mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-05 10:29:40 +00:00
Use GroupEncoding instead of Curve's from_slice/to_bytes
Increases usage of standardization while expanding dalek_ff_group. Closes https://github.com/serai-dex/serai/issues/26 by moving dfg::EdwardsPoint to only be for the prime subgroup.
This commit is contained in:
parent
ac17645fc8
commit
3de7a76051
14 changed files with 141 additions and 178 deletions
|
@ -3,6 +3,8 @@ use core::convert::TryInto;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
|
use group::GroupEncoding;
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
constants::ED25519_BASEPOINT_TABLE as DTable,
|
constants::ED25519_BASEPOINT_TABLE as DTable,
|
||||||
scalar::Scalar as DScalar,
|
scalar::Scalar as DScalar,
|
||||||
|
@ -10,7 +12,6 @@ use curve25519_dalek::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
use frost::curve::{Curve, Ed25519};
|
|
||||||
use dalek_ff_group as dfg;
|
use dalek_ff_group as dfg;
|
||||||
|
|
||||||
use crate::random_scalar;
|
use crate::random_scalar;
|
||||||
|
@ -118,18 +119,26 @@ impl DLEqProof {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn read_dleq(
|
pub(crate) fn read_dleq(
|
||||||
serialized: &[u8],
|
serialized: &[u8],
|
||||||
start: usize,
|
start: usize,
|
||||||
H: &DPoint,
|
H: &DPoint,
|
||||||
l: u16,
|
l: u16,
|
||||||
xG: &DPoint
|
xG: &DPoint
|
||||||
) -> Result<dfg::EdwardsPoint, MultisigError> {
|
) -> Result<dfg::EdwardsPoint, MultisigError> {
|
||||||
// Not using G_from_slice here would enable non-canonical points and break blame
|
if serialized.len() < start + 96 {
|
||||||
// This does also ban identity points, yet those should never be a concern
|
Err(MultisigError::InvalidDLEqProof(l))?;
|
||||||
let other = <Ed25519 as Curve>::G_from_slice(
|
}
|
||||||
&serialized[(start + 0) .. (start + 32)]
|
|
||||||
).map_err(|_| MultisigError::InvalidDLEqProof(l))?;
|
let bytes = (&serialized[(start + 0) .. (start + 32)]).try_into().unwrap();
|
||||||
|
// dfg ensures the point is torsion free
|
||||||
|
let other = Option::<dfg::EdwardsPoint>::from(
|
||||||
|
dfg::EdwardsPoint::from_bytes(&bytes)).ok_or(MultisigError::InvalidDLEqProof(l)
|
||||||
|
)?;
|
||||||
|
// Ensure this is a canonical point
|
||||||
|
if other.to_bytes() != bytes {
|
||||||
|
Err(MultisigError::InvalidDLEqProof(l))?;
|
||||||
|
}
|
||||||
|
|
||||||
DLEqProof::deserialize(&serialized[(start + 32) .. (start + 96)])
|
DLEqProof::deserialize(&serialized[(start + 32) .. (start + 96)])
|
||||||
.ok_or(MultisigError::InvalidDLEqProof(l))?
|
.ok_or(MultisigError::InvalidDLEqProof(l))?
|
||||||
|
|
|
@ -226,6 +226,11 @@ impl SignMachine<Transaction> for TransactionSignMachine {
|
||||||
|
|
||||||
// FROST commitments, image, H commitments, and their proofs
|
// FROST commitments, image, H commitments, and their proofs
|
||||||
let clsag_len = 64 + ClsagMultisig::serialized_len();
|
let clsag_len = 64 + ClsagMultisig::serialized_len();
|
||||||
|
for (l, commitments) in &commitments {
|
||||||
|
if commitments.len() != (self.clsags.len() * clsag_len) {
|
||||||
|
Err(FrostError::InvalidCommitment(*l))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the unified commitments to a Vec of the individual commitments
|
// Convert the unified commitments to a Vec of the individual commitments
|
||||||
let mut commitments = (0 .. self.clsags.len()).map(|_| commitments.iter_mut().map(
|
let mut commitments = (0 .. self.clsags.len()).map(|_| commitments.iter_mut().map(
|
||||||
|
|
|
@ -27,7 +27,7 @@ use dalek::{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
use group::{ff::{Field, PrimeField}, Group};
|
use group::{ff::{Field, PrimeField}, Group, GroupEncoding, prime::PrimeGroup};
|
||||||
|
|
||||||
macro_rules! deref_borrow {
|
macro_rules! deref_borrow {
|
||||||
($Source: ident, $Target: ident) => {
|
($Source: ident, $Target: ident) => {
|
||||||
|
@ -192,6 +192,7 @@ macro_rules! dalek_group {
|
||||||
(
|
(
|
||||||
$Point: ident,
|
$Point: ident,
|
||||||
$DPoint: ident,
|
$DPoint: ident,
|
||||||
|
$torsion_free: expr,
|
||||||
|
|
||||||
$Table: ident,
|
$Table: ident,
|
||||||
$DTable: ident,
|
$DTable: ident,
|
||||||
|
@ -225,6 +226,29 @@ macro_rules! dalek_group {
|
||||||
fn double(&self) -> Self { *self + self }
|
fn double(&self) -> Self { *self + self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GroupEncoding for $Point {
|
||||||
|
type Repr = [u8; 32];
|
||||||
|
|
||||||
|
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
if let Some(point) = $DCompressed(*bytes).decompress() {
|
||||||
|
if $torsion_free(point) {
|
||||||
|
return CtOption::new($Point(point), Choice::from(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CtOption::new($Point::identity(), Choice::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
||||||
|
$Point::from_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self) -> Self::Repr {
|
||||||
|
self.0.compress().to_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimeGroup for $Point {}
|
||||||
|
|
||||||
pub struct $Compressed(pub $DCompressed);
|
pub struct $Compressed(pub $DCompressed);
|
||||||
deref_borrow!($Compressed, $DCompressed);
|
deref_borrow!($Compressed, $DCompressed);
|
||||||
impl $Compressed {
|
impl $Compressed {
|
||||||
|
@ -261,6 +285,7 @@ macro_rules! dalek_group {
|
||||||
dalek_group!(
|
dalek_group!(
|
||||||
EdwardsPoint,
|
EdwardsPoint,
|
||||||
DEdwardsPoint,
|
DEdwardsPoint,
|
||||||
|
|point: DEdwardsPoint| point.is_torsion_free(),
|
||||||
|
|
||||||
EdwardsBasepointTable,
|
EdwardsBasepointTable,
|
||||||
DEdwardsBasepointTable,
|
DEdwardsBasepointTable,
|
||||||
|
@ -272,15 +297,10 @@ dalek_group!(
|
||||||
ED25519_BASEPOINT_TABLE
|
ED25519_BASEPOINT_TABLE
|
||||||
);
|
);
|
||||||
|
|
||||||
impl EdwardsPoint {
|
|
||||||
pub fn is_torsion_free(&self) -> bool {
|
|
||||||
self.0.is_torsion_free()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dalek_group!(
|
dalek_group!(
|
||||||
RistrettoPoint,
|
RistrettoPoint,
|
||||||
DRistrettoPoint,
|
DRistrettoPoint,
|
||||||
|
|_| true,
|
||||||
|
|
||||||
RistrettoBasepointTable,
|
RistrettoBasepointTable,
|
||||||
DRistrettoBasepointTable,
|
DRistrettoBasepointTable,
|
||||||
|
|
|
@ -1,34 +1,27 @@
|
||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use sha2::{Digest, Sha512};
|
use sha2::{Digest, Sha512};
|
||||||
|
|
||||||
use group::{ff::PrimeField, Group};
|
|
||||||
|
|
||||||
use dalek_ff_group::Scalar;
|
use dalek_ff_group::Scalar;
|
||||||
|
|
||||||
use crate::{curve::{CurveError, Curve}, algorithm::Hram};
|
use crate::{curve::Curve, algorithm::Hram};
|
||||||
|
|
||||||
macro_rules! dalek_curve {
|
macro_rules! dalek_curve {
|
||||||
(
|
(
|
||||||
$Curve: ident,
|
$Curve: ident,
|
||||||
$Hram: ident,
|
$Hram: ident,
|
||||||
$Point: ident,
|
$Point: ident,
|
||||||
$Compressed: ident,
|
|
||||||
$Table: ident,
|
$Table: ident,
|
||||||
|
|
||||||
$POINT: ident,
|
$POINT: ident,
|
||||||
$TABLE: ident,
|
$TABLE: ident,
|
||||||
|
|
||||||
$torsioned: expr,
|
|
||||||
|
|
||||||
$ID: literal,
|
$ID: literal,
|
||||||
$CONTEXT: literal,
|
$CONTEXT: literal,
|
||||||
$chal: literal,
|
$chal: literal,
|
||||||
$digest: literal,
|
$digest: literal,
|
||||||
) => {
|
) => {
|
||||||
use dalek_ff_group::{$Point, $Compressed, $Table, $POINT, $TABLE};
|
use dalek_ff_group::{$Point, $Table, $POINT, $TABLE};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct $Curve;
|
pub struct $Curve;
|
||||||
|
@ -75,43 +68,6 @@ macro_rules! dalek_curve {
|
||||||
fn G_len() -> usize {
|
fn G_len() -> usize {
|
||||||
32
|
32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn F_from_slice(slice: &[u8]) -> Result<Self::F, CurveError> {
|
|
||||||
let scalar = Self::F::from_repr(
|
|
||||||
slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?
|
|
||||||
);
|
|
||||||
if !bool::from(scalar.is_some()) {
|
|
||||||
Err(CurveError::InvalidScalar)?;
|
|
||||||
}
|
|
||||||
Ok(scalar.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn G_from_slice(slice: &[u8]) -> Result<Self::G, CurveError> {
|
|
||||||
let bytes = slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?;
|
|
||||||
let point = $Compressed::new(bytes).decompress().ok_or(CurveError::InvalidPoint)?;
|
|
||||||
|
|
||||||
// Ban identity
|
|
||||||
if point.is_identity().into() {
|
|
||||||
Err(CurveError::InvalidPoint)?;
|
|
||||||
}
|
|
||||||
// Ban torsioned points to meet the prime order group requirement
|
|
||||||
if $torsioned(point) {
|
|
||||||
Err(CurveError::InvalidPoint)?;
|
|
||||||
}
|
|
||||||
// Ban points which weren't canonically encoded
|
|
||||||
if point.compress().to_bytes() != bytes {
|
|
||||||
Err(CurveError::InvalidPoint)?;
|
|
||||||
}
|
|
||||||
Ok(point)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn F_to_bytes(f: &Self::F) -> Vec<u8> {
|
|
||||||
f.to_repr().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn G_to_bytes(g: &Self::G) -> Vec<u8> {
|
|
||||||
g.compress().to_bytes().to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -130,11 +86,9 @@ dalek_curve!(
|
||||||
Ristretto,
|
Ristretto,
|
||||||
IetfRistrettoHram,
|
IetfRistrettoHram,
|
||||||
RistrettoPoint,
|
RistrettoPoint,
|
||||||
CompressedRistretto,
|
|
||||||
RistrettoBasepointTable,
|
RistrettoBasepointTable,
|
||||||
RISTRETTO_BASEPOINT_POINT,
|
RISTRETTO_BASEPOINT_POINT,
|
||||||
RISTRETTO_BASEPOINT_TABLE,
|
RISTRETTO_BASEPOINT_TABLE,
|
||||||
|_| false,
|
|
||||||
b"ristretto",
|
b"ristretto",
|
||||||
b"FROST-RISTRETTO255-SHA512-v5",
|
b"FROST-RISTRETTO255-SHA512-v5",
|
||||||
b"chal",
|
b"chal",
|
||||||
|
@ -146,11 +100,9 @@ dalek_curve!(
|
||||||
Ed25519,
|
Ed25519,
|
||||||
IetfEd25519Hram,
|
IetfEd25519Hram,
|
||||||
EdwardsPoint,
|
EdwardsPoint,
|
||||||
CompressedEdwardsY,
|
|
||||||
EdwardsBasepointTable,
|
EdwardsBasepointTable,
|
||||||
ED25519_BASEPOINT_POINT,
|
ED25519_BASEPOINT_POINT,
|
||||||
ED25519_BASEPOINT_TABLE,
|
ED25519_BASEPOINT_TABLE,
|
||||||
|point: EdwardsPoint| !bool::from(point.is_torsion_free()),
|
|
||||||
b"edwards25519",
|
b"edwards25519",
|
||||||
b"",
|
b"",
|
||||||
b"",
|
b"",
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use sha2::{digest::Update, Digest, Sha256};
|
use sha2::{digest::Update, Digest, Sha256};
|
||||||
|
|
||||||
use group::{ff::{Field, PrimeField}, Group, GroupEncoding};
|
use group::{ff::Field, GroupEncoding};
|
||||||
|
|
||||||
use elliptic_curve::{bigint::{Encoding, U384}, hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}};
|
use elliptic_curve::{bigint::{Encoding, U384}, hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}};
|
||||||
|
|
||||||
use crate::{curve::{CurveError, Curve}, algorithm::Hram};
|
use crate::{curve::{Curve, F_from_slice}, algorithm::Hram};
|
||||||
|
|
||||||
macro_rules! kp_curve {
|
macro_rules! kp_curve {
|
||||||
(
|
(
|
||||||
|
@ -65,7 +63,7 @@ macro_rules! kp_curve {
|
||||||
let mut modulus = vec![0; 16];
|
let mut modulus = vec![0; 16];
|
||||||
modulus.extend((Self::F::zero() - Self::F::one()).to_bytes());
|
modulus.extend((Self::F::zero() - Self::F::one()).to_bytes());
|
||||||
let modulus = U384::from_be_slice(&modulus).wrapping_add(&U384::ONE);
|
let modulus = U384::from_be_slice(&modulus).wrapping_add(&U384::ONE);
|
||||||
Self::F_from_slice(
|
F_from_slice::<Self::F>(
|
||||||
&U384::from_be_slice(&{
|
&U384::from_be_slice(&{
|
||||||
let mut bytes = [0; 48];
|
let mut bytes = [0; 48];
|
||||||
ExpandMsgXmd::<Sha256>::expand_message(
|
ExpandMsgXmd::<Sha256>::expand_message(
|
||||||
|
@ -85,38 +83,6 @@ macro_rules! kp_curve {
|
||||||
fn G_len() -> usize {
|
fn G_len() -> usize {
|
||||||
33
|
33
|
||||||
}
|
}
|
||||||
|
|
||||||
fn F_from_slice(slice: &[u8]) -> Result<Self::F, CurveError> {
|
|
||||||
let bytes: [u8; 32] = slice.try_into()
|
|
||||||
.map_err(|_| CurveError::InvalidLength(32, slice.len()))?;
|
|
||||||
|
|
||||||
let scalar = Self::F::from_repr(bytes.into());
|
|
||||||
if scalar.is_none().into() {
|
|
||||||
Err(CurveError::InvalidScalar)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(scalar.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn G_from_slice(slice: &[u8]) -> Result<Self::G, CurveError> {
|
|
||||||
let bytes: [u8; 33] = slice.try_into()
|
|
||||||
.map_err(|_| CurveError::InvalidLength(33, slice.len()))?;
|
|
||||||
|
|
||||||
let point = Self::G::from_bytes(&bytes.into());
|
|
||||||
if point.is_none().into() || point.unwrap().is_identity().into() {
|
|
||||||
Err(CurveError::InvalidPoint)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(point.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn F_to_bytes(f: &Self::F) -> Vec<u8> {
|
|
||||||
f.to_bytes().to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn G_to_bytes(g: &Self::G) -> Vec<u8> {
|
|
||||||
g.to_bytes().to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -126,7 +92,7 @@ macro_rules! kp_curve {
|
||||||
fn hram(R: &$lib::ProjectivePoint, A: &$lib::ProjectivePoint, m: &[u8]) -> $lib::Scalar {
|
fn hram(R: &$lib::ProjectivePoint, A: &$lib::ProjectivePoint, m: &[u8]) -> $lib::Scalar {
|
||||||
$Curve::hash_to_F(
|
$Curve::hash_to_F(
|
||||||
&[$CONTEXT as &[u8], b"chal"].concat(),
|
&[$CONTEXT as &[u8], b"chal"].concat(),
|
||||||
&[&$Curve::G_to_bytes(R), &$Curve::G_to_bytes(A), m].concat()
|
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use group::{ff::PrimeField, Group, GroupOps};
|
use group::{ff::PrimeField, Group, GroupOps, prime::PrimeGroup};
|
||||||
|
|
||||||
#[cfg(any(test, feature = "dalek"))]
|
#[cfg(any(test, feature = "dalek"))]
|
||||||
mod dalek;
|
mod dalek;
|
||||||
|
@ -42,7 +42,7 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||||
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
|
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
|
||||||
type F: PrimeField;
|
type F: PrimeField;
|
||||||
/// Group element type
|
/// Group element type
|
||||||
type G: Group<Scalar = Self::F> + GroupOps;
|
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup;
|
||||||
/// Precomputed table type
|
/// Precomputed table type
|
||||||
type T: Mul<Self::F, Output = Self::G>;
|
type T: Mul<Self::F, Output = Self::G>;
|
||||||
|
|
||||||
|
@ -99,23 +99,31 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||||
// that is on them
|
// that is on them
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn G_len() -> usize;
|
fn G_len() -> usize;
|
||||||
|
}
|
||||||
/// Field element from slice. Preferred to be canonical yet does not have to be
|
|
||||||
// Required due to the lack of standardized encoding functions provided by ff/group
|
/// Field element from slice
|
||||||
// While they do technically exist, their usage of Self::Repr breaks all potential library usage
|
#[allow(non_snake_case)]
|
||||||
// without helper functions like this
|
pub(crate) fn F_from_slice<F: PrimeField>(slice: &[u8]) -> Result<F, CurveError> {
|
||||||
#[allow(non_snake_case)]
|
let mut encoding = F::Repr::default();
|
||||||
fn F_from_slice(slice: &[u8]) -> Result<Self::F, CurveError>;
|
encoding.as_mut().copy_from_slice(slice);
|
||||||
|
|
||||||
/// Group element from slice. Must require canonicity or risks differing binding factors
|
let point = Option::<F>::from(F::from_repr(encoding)).ok_or(CurveError::InvalidScalar)?;
|
||||||
#[allow(non_snake_case)]
|
if point.to_repr().as_ref() != slice {
|
||||||
fn G_from_slice(slice: &[u8]) -> Result<Self::G, CurveError>;
|
Err(CurveError::InvalidScalar)?;
|
||||||
|
}
|
||||||
/// Obtain a vector of the byte encoding of F
|
Ok(point)
|
||||||
#[allow(non_snake_case)]
|
}
|
||||||
fn F_to_bytes(f: &Self::F) -> Vec<u8>;
|
|
||||||
|
/// Group element from slice
|
||||||
/// Obtain a vector of the byte encoding of G
|
#[allow(non_snake_case)]
|
||||||
#[allow(non_snake_case)]
|
pub(crate) fn G_from_slice<G: PrimeGroup>(slice: &[u8]) -> Result<G, CurveError> {
|
||||||
fn G_to_bytes(g: &Self::G) -> Vec<u8>;
|
let mut encoding = G::Repr::default();
|
||||||
|
encoding.as_mut().copy_from_slice(slice);
|
||||||
|
|
||||||
|
let point = Option::<G>::from(G::from_bytes(&encoding)).ok_or(CurveError::InvalidPoint)?;
|
||||||
|
// Ban the identity, per the FROST spec, and non-canonical points
|
||||||
|
if (point.is_identity().into()) || (point.to_bytes().as_ref() != slice) {
|
||||||
|
Err(CurveError::InvalidPoint)?;
|
||||||
|
}
|
||||||
|
Ok(point)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ use std::{marker::PhantomData, collections::HashMap};
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use group::ff::{Field, PrimeField};
|
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||||
|
|
||||||
use multiexp::{multiexp_vartime, BatchVerifier};
|
use multiexp::{multiexp_vartime, BatchVerifier};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
curve::Curve,
|
curve::{Curve, F_from_slice, G_from_slice},
|
||||||
FrostError, FrostParams, FrostKeys,
|
FrostError, FrostParams, FrostKeys,
|
||||||
schnorr::{self, SchnorrSignature},
|
schnorr::{self, SchnorrSignature},
|
||||||
validate_map
|
validate_map
|
||||||
|
@ -43,7 +43,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
||||||
// Step 3: Generate public commitments
|
// Step 3: Generate public commitments
|
||||||
commitments.push(C::GENERATOR_TABLE * coefficients[i]);
|
commitments.push(C::GENERATOR_TABLE * coefficients[i]);
|
||||||
// Serialize them for publication
|
// Serialize them for publication
|
||||||
serialized.extend(&C::G_to_bytes(&commitments[i]));
|
serialized.extend(commitments[i].to_bytes().as_ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Provide a proof of knowledge
|
// Step 2: Provide a proof of knowledge
|
||||||
|
@ -59,7 +59,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
||||||
challenge::<C>(
|
challenge::<C>(
|
||||||
context,
|
context,
|
||||||
params.i(),
|
params.i(),
|
||||||
&C::G_to_bytes(&(C::GENERATOR_TABLE * r)),
|
(C::GENERATOR_TABLE * r).to_bytes().as_ref(),
|
||||||
&serialized
|
&serialized
|
||||||
)
|
)
|
||||||
).serialize()
|
).serialize()
|
||||||
|
@ -90,11 +90,11 @@ fn verify_r1<R: RngCore + CryptoRng, C: Curve>(
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let R_bytes = |l| &serialized[&l][commitments_len .. commitments_len + C::G_len()];
|
let R_bytes = |l| &serialized[&l][commitments_len .. commitments_len + C::G_len()];
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let R = |l| C::G_from_slice(R_bytes(l)).map_err(|_| FrostError::InvalidProofOfKnowledge(l));
|
let R = |l| G_from_slice::<C::G>(R_bytes(l)).map_err(|_| FrostError::InvalidProofOfKnowledge(l));
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let Am = |l| &serialized[&l][0 .. commitments_len];
|
let Am = |l| &serialized[&l][0 .. commitments_len];
|
||||||
|
|
||||||
let s = |l| C::F_from_slice(
|
let s = |l| F_from_slice::<C::F>(
|
||||||
&serialized[&l][commitments_len + C::G_len() ..]
|
&serialized[&l][commitments_len + C::G_len() ..]
|
||||||
).map_err(|_| FrostError::InvalidProofOfKnowledge(l));
|
).map_err(|_| FrostError::InvalidProofOfKnowledge(l));
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ fn verify_r1<R: RngCore + CryptoRng, C: Curve>(
|
||||||
let mut these_commitments = vec![];
|
let mut these_commitments = vec![];
|
||||||
for c in 0 .. usize::from(params.t()) {
|
for c in 0 .. usize::from(params.t()) {
|
||||||
these_commitments.push(
|
these_commitments.push(
|
||||||
C::G_from_slice(
|
G_from_slice::<C::G>(
|
||||||
&serialized[&l][(c * C::G_len()) .. ((c + 1) * C::G_len())]
|
&serialized[&l][(c * C::G_len()) .. ((c + 1) * C::G_len())]
|
||||||
).map_err(|_| FrostError::InvalidCommitment(l.try_into().unwrap()))?
|
).map_err(|_| FrostError::InvalidCommitment(l.try_into().unwrap()))?
|
||||||
);
|
);
|
||||||
|
@ -166,7 +166,7 @@ fn generate_key_r2<R: RngCore + CryptoRng, C: Curve>(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.insert(l, C::F_to_bytes(&polynomial(&coefficients, l)));
|
res.insert(l, polynomial(&coefficients, l).to_repr().as_ref().to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate our own share
|
// Calculate our own share
|
||||||
|
@ -199,13 +199,13 @@ fn complete_r2<R: RngCore + CryptoRng, C: Curve>(
|
||||||
validate_map(
|
validate_map(
|
||||||
&mut serialized,
|
&mut serialized,
|
||||||
&(1 ..= params.n()).into_iter().collect::<Vec<_>>(),
|
&(1 ..= params.n()).into_iter().collect::<Vec<_>>(),
|
||||||
(params.i(), C::F_to_bytes(&secret_share))
|
(params.i(), secret_share.to_repr().as_ref().to_vec())
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Step 2. Verify each share
|
// Step 2. Verify each share
|
||||||
let mut shares = HashMap::new();
|
let mut shares = HashMap::new();
|
||||||
for (l, share) in serialized {
|
for (l, share) in serialized {
|
||||||
shares.insert(l, C::F_from_slice(&share).map_err(|_| FrostError::InvalidShare(l))?);
|
shares.insert(l, F_from_slice::<C::F>(&share).map_err(|_| FrostError::InvalidShare(l))?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the exponent for a given participant and apply it to a series of commitments
|
// Calculate the exponent for a given participant and apply it to a series of commitments
|
||||||
|
|
|
@ -3,12 +3,12 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use group::ff::{Field, PrimeField};
|
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||||
|
|
||||||
mod schnorr;
|
mod schnorr;
|
||||||
|
|
||||||
pub mod curve;
|
pub mod curve;
|
||||||
use curve::Curve;
|
use curve::{Curve, F_from_slice, G_from_slice};
|
||||||
pub mod key_gen;
|
pub mod key_gen;
|
||||||
pub mod algorithm;
|
pub mod algorithm;
|
||||||
pub mod sign;
|
pub mod sign;
|
||||||
|
@ -213,10 +213,10 @@ impl<C: Curve> FrostKeys<C> {
|
||||||
serialized.extend(&self.params.t.to_be_bytes());
|
serialized.extend(&self.params.t.to_be_bytes());
|
||||||
serialized.extend(&self.params.n.to_be_bytes());
|
serialized.extend(&self.params.n.to_be_bytes());
|
||||||
serialized.extend(&self.params.i.to_be_bytes());
|
serialized.extend(&self.params.i.to_be_bytes());
|
||||||
serialized.extend(&C::F_to_bytes(&self.secret_share));
|
serialized.extend(self.secret_share.to_repr().as_ref());
|
||||||
serialized.extend(&C::G_to_bytes(&self.group_key));
|
serialized.extend(self.group_key.to_bytes().as_ref());
|
||||||
for l in 1 ..= self.params.n.into() {
|
for l in 1 ..= self.params.n.into() {
|
||||||
serialized.extend(&C::G_to_bytes(&self.verification_shares[&l]));
|
serialized.extend(self.verification_shares[&l].to_bytes().as_ref());
|
||||||
}
|
}
|
||||||
serialized
|
serialized
|
||||||
}
|
}
|
||||||
|
@ -253,10 +253,10 @@ impl<C: Curve> FrostKeys<C> {
|
||||||
let i = u16::from_be_bytes(serialized[cursor .. (cursor + 2)].try_into().unwrap());
|
let i = u16::from_be_bytes(serialized[cursor .. (cursor + 2)].try_into().unwrap());
|
||||||
cursor += 2;
|
cursor += 2;
|
||||||
|
|
||||||
let secret_share = C::F_from_slice(&serialized[cursor .. (cursor + C::F_len())])
|
let secret_share = F_from_slice::<C::F>(&serialized[cursor .. (cursor + C::F_len())])
|
||||||
.map_err(|_| FrostError::InternalError("invalid secret share".to_string()))?;
|
.map_err(|_| FrostError::InternalError("invalid secret share".to_string()))?;
|
||||||
cursor += C::F_len();
|
cursor += C::F_len();
|
||||||
let group_key = C::G_from_slice(&serialized[cursor .. (cursor + C::G_len())])
|
let group_key = G_from_slice::<C::G>(&serialized[cursor .. (cursor + C::G_len())])
|
||||||
.map_err(|_| FrostError::InternalError("invalid group key".to_string()))?;
|
.map_err(|_| FrostError::InternalError("invalid group key".to_string()))?;
|
||||||
cursor += C::G_len();
|
cursor += C::G_len();
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ impl<C: Curve> FrostKeys<C> {
|
||||||
for l in 1 ..= n {
|
for l in 1 ..= n {
|
||||||
verification_shares.insert(
|
verification_shares.insert(
|
||||||
l,
|
l,
|
||||||
C::G_from_slice(&serialized[cursor .. (cursor + C::G_len())])
|
G_from_slice::<C::G>(&serialized[cursor .. (cursor + C::G_len())])
|
||||||
.map_err(|_| FrostError::InternalError("invalid verification share".to_string()))?
|
.map_err(|_| FrostError::InternalError("invalid verification share".to_string()))?
|
||||||
);
|
);
|
||||||
cursor += C::G_len();
|
cursor += C::G_len();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use group::ff::Field;
|
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||||
|
|
||||||
use multiexp::BatchVerifier;
|
use multiexp::BatchVerifier;
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ pub struct SchnorrSignature<C: Curve> {
|
||||||
impl<C: Curve> SchnorrSignature<C> {
|
impl<C: Curve> SchnorrSignature<C> {
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
let mut res = Vec::with_capacity(C::G_len() + C::F_len());
|
let mut res = Vec::with_capacity(C::G_len() + C::F_len());
|
||||||
res.extend(C::G_to_bytes(&self.R));
|
res.extend(self.R.to_bytes().as_ref());
|
||||||
res.extend(C::F_to_bytes(&self.s));
|
res.extend(self.s.to_repr().as_ref());
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,12 @@ use std::{sync::Arc, collections::HashMap};
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use group::ff::Field;
|
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||||
|
|
||||||
use transcript::Transcript;
|
use transcript::Transcript;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
curve::Curve,
|
curve::{Curve, F_from_slice, G_from_slice},
|
||||||
FrostError,
|
FrostError,
|
||||||
FrostParams, FrostKeys, FrostView,
|
FrostParams, FrostKeys, FrostView,
|
||||||
algorithm::Algorithm,
|
algorithm::Algorithm,
|
||||||
|
@ -85,8 +85,8 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
||||||
C::random_nonce(params.view().secret_share(), &mut *rng)
|
C::random_nonce(params.view().secret_share(), &mut *rng)
|
||||||
];
|
];
|
||||||
let commitments = [C::GENERATOR_TABLE * nonces[0], C::GENERATOR_TABLE * nonces[1]];
|
let commitments = [C::GENERATOR_TABLE * nonces[0], C::GENERATOR_TABLE * nonces[1]];
|
||||||
let mut serialized = C::G_to_bytes(&commitments[0]);
|
let mut serialized = commitments[0].to_bytes().as_ref().to_vec();
|
||||||
serialized.extend(&C::G_to_bytes(&commitments[1]));
|
serialized.extend(commitments[1].to_bytes().as_ref());
|
||||||
|
|
||||||
serialized.extend(
|
serialized.extend(
|
||||||
¶ms.algorithm.preprocess_addendum(
|
¶ms.algorithm.preprocess_addendum(
|
||||||
|
@ -129,7 +129,7 @@ fn sign_with_share<C: Curve, A: Algorithm<C>>(
|
||||||
transcript.domain_separate(b"FROST");
|
transcript.domain_separate(b"FROST");
|
||||||
// Include the offset, if one exists
|
// Include the offset, if one exists
|
||||||
if let Some(offset) = params.keys.offset {
|
if let Some(offset) = params.keys.offset {
|
||||||
transcript.append_message(b"offset", &C::F_to_bytes(&offset));
|
transcript.append_message(b"offset", offset.to_repr().as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ fn sign_with_share<C: Curve, A: Algorithm<C>>(
|
||||||
let mut read_commitment = |c, label| {
|
let mut read_commitment = |c, label| {
|
||||||
let commitment = &commitments[c .. (c + C::G_len())];
|
let commitment = &commitments[c .. (c + C::G_len())];
|
||||||
transcript.append_message(label, commitment);
|
transcript.append_message(label, commitment);
|
||||||
C::G_from_slice(commitment).map_err(|_| FrostError::InvalidCommitment(*l))
|
G_from_slice::<C::G>(commitment).map_err(|_| FrostError::InvalidCommitment(*l))
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -176,15 +176,13 @@ fn sign_with_share<C: Curve, A: Algorithm<C>>(
|
||||||
let R = {
|
let R = {
|
||||||
B.values().map(|B| B[0]).sum::<C::G>() + (B.values().map(|B| B[1]).sum::<C::G>() * binding)
|
B.values().map(|B| B[0]).sum::<C::G>() + (B.values().map(|B| B[1]).sum::<C::G>() * binding)
|
||||||
};
|
};
|
||||||
let share = C::F_to_bytes(
|
let share = params.algorithm.sign_share(
|
||||||
¶ms.algorithm.sign_share(
|
¶ms.view,
|
||||||
¶ms.view,
|
R,
|
||||||
R,
|
binding,
|
||||||
binding,
|
our_preprocess.nonces[0] + (our_preprocess.nonces[1] * binding),
|
||||||
our_preprocess.nonces[0] + (our_preprocess.nonces[1] * binding),
|
msg
|
||||||
msg
|
).to_repr().as_ref().to_vec();
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((Package { B, binding, R, share: share.clone() }, share))
|
Ok((Package { B, binding, R, share: share.clone() }, share))
|
||||||
}
|
}
|
||||||
|
@ -203,7 +201,7 @@ fn complete<C: Curve, A: Algorithm<C>>(
|
||||||
let mut responses = HashMap::new();
|
let mut responses = HashMap::new();
|
||||||
let mut sum = C::F::zero();
|
let mut sum = C::F::zero();
|
||||||
for l in &sign_params.view.included {
|
for l in &sign_params.view.included {
|
||||||
let part = C::F_from_slice(&shares[l]).map_err(|_| FrostError::InvalidShare(*l))?;
|
let part = F_from_slice::<C::F>(&shares[l]).map_err(|_| FrostError::InvalidShare(*l))?;
|
||||||
sum += part;
|
sum += part;
|
||||||
responses.insert(*l, part);
|
responses.insert(*l, part);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{marker::PhantomData, sync::Arc, collections::HashMap};
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use group::ff::Field;
|
use group::{ff::Field, GroupEncoding};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Curve, FrostKeys, schnorr::{self, SchnorrSignature}, algorithm::{Hram, Schnorr},
|
Curve, FrostKeys, schnorr::{self, SchnorrSignature}, algorithm::{Hram, Schnorr},
|
||||||
|
@ -96,7 +96,7 @@ pub struct TestHram<C: Curve> {
|
||||||
impl<C: Curve> Hram<C> for TestHram<C> {
|
impl<C: Curve> Hram<C> for TestHram<C> {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F {
|
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F {
|
||||||
C::hash_to_F(b"challenge", &[&C::G_to_bytes(R), &C::G_to_bytes(A), m].concat())
|
C::hash_to_F(b"challenge", &[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ use std::{sync::Arc, collections::HashMap};
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
|
use group::{ff::PrimeField, GroupEncoding};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Curve, FrostKeys,
|
curve::{Curve, F_from_slice, G_from_slice}, FrostKeys,
|
||||||
algorithm::{Schnorr, Hram},
|
algorithm::{Schnorr, Hram},
|
||||||
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
|
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
|
||||||
tests::{curve::test_curve, schnorr::test_schnorr, recover}
|
tests::{curve::test_curve, schnorr::test_schnorr, recover}
|
||||||
|
@ -25,7 +27,7 @@ pub struct Vectors {
|
||||||
// Load these vectors into FrostKeys using a custom serialization it'll deserialize
|
// Load these vectors into FrostKeys using a custom serialization it'll deserialize
|
||||||
fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKeys<C>> {
|
fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKeys<C>> {
|
||||||
let shares = vectors.shares.iter().map(
|
let shares = vectors.shares.iter().map(
|
||||||
|secret| C::F_from_slice(&hex::decode(secret).unwrap()).unwrap()
|
|secret| F_from_slice::<C::F>(&hex::decode(secret).unwrap()).unwrap()
|
||||||
).collect::<Vec<_>>();
|
).collect::<Vec<_>>();
|
||||||
let verification_shares = shares.iter().map(
|
let verification_shares = shares.iter().map(
|
||||||
|secret| C::GENERATOR * secret
|
|secret| C::GENERATOR * secret
|
||||||
|
@ -39,10 +41,10 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
|
||||||
serialized.extend(vectors.threshold.to_be_bytes());
|
serialized.extend(vectors.threshold.to_be_bytes());
|
||||||
serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes());
|
serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes());
|
||||||
serialized.extend(i.to_be_bytes());
|
serialized.extend(i.to_be_bytes());
|
||||||
serialized.extend(C::F_to_bytes(&shares[usize::from(i) - 1]));
|
serialized.extend(shares[usize::from(i) - 1].to_repr().as_ref());
|
||||||
serialized.extend(&hex::decode(vectors.group_key).unwrap());
|
serialized.extend(&hex::decode(vectors.group_key).unwrap());
|
||||||
for share in &verification_shares {
|
for share in &verification_shares {
|
||||||
serialized.extend(&C::G_to_bytes(share));
|
serialized.extend(share.to_bytes().as_ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
let these_keys = FrostKeys::<C>::deserialize(&serialized).unwrap();
|
let these_keys = FrostKeys::<C>::deserialize(&serialized).unwrap();
|
||||||
|
@ -50,7 +52,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
|
||||||
assert_eq!(usize::from(these_keys.params().n()), shares.len());
|
assert_eq!(usize::from(these_keys.params().n()), shares.len());
|
||||||
assert_eq!(these_keys.params().i(), i);
|
assert_eq!(these_keys.params().i(), i);
|
||||||
assert_eq!(these_keys.secret_share(), shares[usize::from(i - 1)]);
|
assert_eq!(these_keys.secret_share(), shares[usize::from(i - 1)]);
|
||||||
assert_eq!(&hex::encode(&C::G_to_bytes(&these_keys.group_key())), vectors.group_key);
|
assert_eq!(&hex::encode(these_keys.group_key().to_bytes().as_ref()), vectors.group_key);
|
||||||
keys.insert(i, these_keys);
|
keys.insert(i, these_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +70,14 @@ pub fn test_with_vectors<
|
||||||
|
|
||||||
// Test against the vectors
|
// Test against the vectors
|
||||||
let keys = vectors_to_multisig_keys::<C>(&vectors);
|
let keys = vectors_to_multisig_keys::<C>(&vectors);
|
||||||
let group_key = C::G_from_slice(&hex::decode(vectors.group_key).unwrap()).unwrap();
|
let group_key = G_from_slice::<C::G>(&hex::decode(vectors.group_key).unwrap()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
C::GENERATOR * C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap(),
|
C::GENERATOR * F_from_slice::<C::F>(&hex::decode(vectors.group_secret).unwrap()).unwrap(),
|
||||||
group_key
|
group_key
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
recover(&keys),
|
recover(&keys),
|
||||||
C::F_from_slice(&hex::decode(vectors.group_secret).unwrap()).unwrap()
|
F_from_slice::<C::F>(&hex::decode(vectors.group_secret).unwrap()).unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut machines = vec![];
|
let mut machines = vec![];
|
||||||
|
@ -94,13 +96,13 @@ pub fn test_with_vectors<
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
let mut machines = machines.drain(..).map(|(i, machine)| {
|
let mut machines = machines.drain(..).map(|(i, machine)| {
|
||||||
let nonces = [
|
let nonces = [
|
||||||
C::F_from_slice(&hex::decode(vectors.nonces[c][0]).unwrap()).unwrap(),
|
F_from_slice::<C::F>(&hex::decode(vectors.nonces[c][0]).unwrap()).unwrap(),
|
||||||
C::F_from_slice(&hex::decode(vectors.nonces[c][1]).unwrap()).unwrap()
|
F_from_slice::<C::F>(&hex::decode(vectors.nonces[c][1]).unwrap()).unwrap()
|
||||||
];
|
];
|
||||||
c += 1;
|
c += 1;
|
||||||
|
|
||||||
let mut serialized = C::G_to_bytes(&(C::GENERATOR * nonces[0]));
|
let mut serialized = (C::GENERATOR * nonces[0]).to_bytes().as_ref().to_vec();
|
||||||
serialized.extend(&C::G_to_bytes(&(C::GENERATOR * nonces[1])));
|
serialized.extend((C::GENERATOR * nonces[1]).to_bytes().as_ref());
|
||||||
|
|
||||||
let (machine, serialized) = machine.unsafe_override_preprocess(
|
let (machine, serialized) = machine.unsafe_override_preprocess(
|
||||||
PreprocessPackage { nonces, serialized: serialized.clone() }
|
PreprocessPackage { nonces, serialized: serialized.clone() }
|
||||||
|
@ -127,8 +129,8 @@ pub fn test_with_vectors<
|
||||||
|
|
||||||
for (_, machine) in machines.drain() {
|
for (_, machine) in machines.drain() {
|
||||||
let sig = machine.complete(shares.clone()).unwrap();
|
let sig = machine.complete(shares.clone()).unwrap();
|
||||||
let mut serialized = C::G_to_bytes(&sig.R);
|
let mut serialized = sig.R.to_bytes().as_ref().to_vec();
|
||||||
serialized.extend(C::F_to_bytes(&sig.s));
|
serialized.extend(sig.s.to_repr().as_ref());
|
||||||
assert_eq!(hex::encode(serialized), vectors.sig);
|
assert_eq!(hex::encode(serialized), vectors.sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ serde_json = "1.0"
|
||||||
curve25519-dalek = { version = "3", features = ["std"] }
|
curve25519-dalek = { version = "3", features = ["std"] }
|
||||||
blake2 = "0.10"
|
blake2 = "0.10"
|
||||||
|
|
||||||
|
group = "0.12"
|
||||||
|
|
||||||
transcript = { package = "flexible-transcript", path = "../crypto/transcript", features = ["recommended"] }
|
transcript = { package = "flexible-transcript", path = "../crypto/transcript", features = ["recommended"] }
|
||||||
dalek-ff-group = { path = "../crypto/dalek-ff-group" }
|
dalek-ff-group = { path = "../crypto/dalek-ff-group" }
|
||||||
frost = { package = "modular-frost", path = "../crypto/frost" }
|
frost = { package = "modular-frost", path = "../crypto/frost" }
|
||||||
|
|
|
@ -2,8 +2,9 @@ use std::{sync::Arc, collections::HashMap};
|
||||||
|
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use transcript::{Transcript, RecommendedTranscript};
|
use group::GroupEncoding;
|
||||||
|
|
||||||
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
use frost::{curve::Curve, FrostKeys, sign::{PreprocessMachine, SignMachine, SignatureMachine}};
|
use frost::{curve::Curve, FrostKeys, sign::{PreprocessMachine, SignMachine, SignatureMachine}};
|
||||||
|
|
||||||
use crate::{coin::{CoinError, Output, Coin}, SignError, Network};
|
use crate::{coin::{CoinError, Output, Coin}, SignError, Network};
|
||||||
|
@ -31,7 +32,7 @@ impl<C: Curve> WalletKeys<C> {
|
||||||
let mut transcript = RecommendedTranscript::new(DST);
|
let mut transcript = RecommendedTranscript::new(DST);
|
||||||
transcript.append_message(b"chain", chain);
|
transcript.append_message(b"chain", chain);
|
||||||
transcript.append_message(b"curve", C::ID);
|
transcript.append_message(b"curve", C::ID);
|
||||||
transcript.append_message(b"group_key", &C::G_to_bytes(&self.keys.group_key()));
|
transcript.append_message(b"group_key", self.keys.group_key().to_bytes().as_ref());
|
||||||
self.keys.offset(C::hash_to_F(DST, &transcript.challenge(b"offset")))
|
self.keys.offset(C::hash_to_F(DST, &transcript.challenge(b"offset")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue