mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Apply an initial set of rustfmt rules
This commit is contained in:
@@ -55,12 +55,7 @@ pub trait Algorithm<C: Curve>: Clone {
|
||||
/// Verify a specific share given as a response. Used to determine blame if signature
|
||||
/// verification fails
|
||||
#[must_use]
|
||||
fn verify_share(
|
||||
&self,
|
||||
verification_share: C::G,
|
||||
nonces: &[Vec<C::G>],
|
||||
share: C::F,
|
||||
) -> bool;
|
||||
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool;
|
||||
}
|
||||
|
||||
// Transcript which will create an IETF compliant serialization for the binding factor
|
||||
@@ -88,7 +83,6 @@ impl Transcript for IetfTranscript {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait Hram<C: Curve>: Clone {
|
||||
/// HRAM function to generate a challenge
|
||||
/// H2 from the IETF draft despite having a different argument set (not pre-formatted)
|
||||
@@ -105,11 +99,7 @@ pub struct Schnorr<C: Curve, H: Hram<C>> {
|
||||
|
||||
impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
|
||||
pub fn new() -> Schnorr<C, H> {
|
||||
Schnorr {
|
||||
transcript: IetfTranscript(vec![]),
|
||||
c: None,
|
||||
_hram: PhantomData
|
||||
}
|
||||
Schnorr { transcript: IetfTranscript(vec![]), c: None, _hram: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,16 +156,11 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn verify_share(
|
||||
&self,
|
||||
verification_share: C::G,
|
||||
nonces: &[Vec<C::G>],
|
||||
share: C::F,
|
||||
) -> bool {
|
||||
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool {
|
||||
schnorr::verify::<C>(
|
||||
verification_share,
|
||||
self.c.unwrap(),
|
||||
&SchnorrSignature { R: nonces[0][0], s: share}
|
||||
&SchnorrSignature { R: nonces[0][0], s: share },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ macro_rules! dalek_curve {
|
||||
$Curve::hash_to_F($chal, &[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "ristretto"))]
|
||||
|
||||
@@ -6,7 +6,10 @@ use sha2::{digest::Update, Digest, Sha256};
|
||||
|
||||
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::Curve, algorithm::Hram};
|
||||
|
||||
@@ -36,12 +39,7 @@ macro_rules! kp_curve {
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
(&Sha256::new()
|
||||
.chain($CONTEXT)
|
||||
.chain(b"digest")
|
||||
.chain(msg)
|
||||
.finalize()
|
||||
).to_vec()
|
||||
(&Sha256::new().chain($CONTEXT).chain(b"digest").chain(msg).finalize()).to_vec()
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
@@ -60,19 +58,17 @@ macro_rules! kp_curve {
|
||||
let mut modulus = vec![0; 16];
|
||||
modulus.extend((Self::F::zero() - Self::F::one()).to_bytes());
|
||||
let modulus = U384::from_be_slice(&modulus).wrapping_add(&U384::ONE);
|
||||
Self::read_F(
|
||||
&mut Cursor::new(
|
||||
&U384::from_be_slice(&{
|
||||
let mut bytes = [0; 48];
|
||||
ExpandMsgXmd::<Sha256>::expand_message(
|
||||
&[msg],
|
||||
dst,
|
||||
48
|
||||
).unwrap().fill_bytes(&mut bytes);
|
||||
bytes
|
||||
}).reduce(&modulus).unwrap().to_be_bytes()[16 ..]
|
||||
)
|
||||
).unwrap()
|
||||
Self::read_F(&mut Cursor::new(
|
||||
&U384::from_be_slice(&{
|
||||
let mut bytes = [0; 48];
|
||||
ExpandMsgXmd::<Sha256>::expand_message(&[msg], dst, 48).unwrap().fill_bytes(&mut bytes);
|
||||
bytes
|
||||
})
|
||||
.reduce(&modulus)
|
||||
.unwrap()
|
||||
.to_be_bytes()[16 ..],
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,27 +79,15 @@ macro_rules! kp_curve {
|
||||
fn hram(R: &$lib::ProjectivePoint, A: &$lib::ProjectivePoint, m: &[u8]) -> $lib::Scalar {
|
||||
$Curve::hash_to_F(
|
||||
&[$CONTEXT as &[u8], b"chal"].concat(),
|
||||
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat()
|
||||
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "p256")]
|
||||
kp_curve!(
|
||||
p256,
|
||||
P256,
|
||||
IetfP256Hram,
|
||||
b"P-256",
|
||||
b"FROST-P256-SHA256-v5"
|
||||
);
|
||||
kp_curve!(p256, P256, IetfP256Hram, b"P-256", b"FROST-P256-SHA256-v5");
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
kp_curve!(
|
||||
k256,
|
||||
Secp256k1,
|
||||
NonIetfSecp256k1Hram,
|
||||
b"secp256k1",
|
||||
b"FROST-secp256k1-SHA256-v7"
|
||||
);
|
||||
kp_curve!(k256, Secp256k1, NonIetfSecp256k1Hram, b"secp256k1", b"FROST-secp256k1-SHA256-v7");
|
||||
|
||||
@@ -102,9 +102,8 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
||||
r.read_exact(encoding.as_mut()).map_err(|_| CurveError::InvalidPoint)?;
|
||||
|
||||
let point = Option::<Self::G>::from(
|
||||
Self::G::from_bytes(&encoding)
|
||||
).ok_or(CurveError::InvalidPoint)?;
|
||||
let point =
|
||||
Option::<Self::G>::from(Self::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() != encoding.as_ref()) {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
use std::{marker::PhantomData, io::{Read, Cursor}, collections::HashMap};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
io::{Read, Cursor},
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||
use group::{
|
||||
ff::{Field, PrimeField},
|
||||
GroupEncoding,
|
||||
};
|
||||
|
||||
use multiexp::{multiexp_vartime, BatchVerifier};
|
||||
|
||||
@@ -10,7 +17,7 @@ use crate::{
|
||||
curve::Curve,
|
||||
FrostError, FrostParams, FrostKeys,
|
||||
schnorr::{self, SchnorrSignature},
|
||||
validate_map
|
||||
validate_map,
|
||||
};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -56,13 +63,9 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
||||
// There's no reason to spend the time and effort to make this deterministic besides a
|
||||
// general obsession with canonicity and determinism though
|
||||
r,
|
||||
challenge::<C>(
|
||||
context,
|
||||
params.i(),
|
||||
(C::GENERATOR * r).to_bytes().as_ref(),
|
||||
&serialized
|
||||
)
|
||||
).serialize()
|
||||
challenge::<C>(context, params.i(), (C::GENERATOR * r).to_bytes().as_ref(), &serialized),
|
||||
)
|
||||
.serialize(),
|
||||
);
|
||||
|
||||
// Step 4: Broadcast
|
||||
@@ -114,7 +117,7 @@ fn verify_r1<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
||||
l,
|
||||
these_commitments[0],
|
||||
challenge::<C>(context, l, R.to_bytes().as_ref(), &Am),
|
||||
SchnorrSignature::<C> { R, s }
|
||||
SchnorrSignature::<C> { R, s },
|
||||
));
|
||||
}
|
||||
|
||||
@@ -126,10 +129,7 @@ fn verify_r1<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
||||
Ok(commitments)
|
||||
}
|
||||
|
||||
fn polynomial<F: PrimeField>(
|
||||
coefficients: &[F],
|
||||
l: u16
|
||||
) -> F {
|
||||
fn polynomial<F: PrimeField>(coefficients: &[F], l: u16) -> F {
|
||||
let l = F::from(u64::from(l));
|
||||
let mut share = F::zero();
|
||||
for (idx, coefficient) in coefficients.iter().rev().enumerate() {
|
||||
@@ -207,13 +207,10 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
||||
let exponential = |i: u16, values: &[_]| {
|
||||
let i = C::F::from(i.into());
|
||||
let mut res = Vec::with_capacity(params.t().into());
|
||||
(0 .. usize::from(params.t())).into_iter().fold(
|
||||
C::F::one(),
|
||||
|exp, l| {
|
||||
res.push((exp, values[l]));
|
||||
exp * i
|
||||
}
|
||||
);
|
||||
(0 .. usize::from(params.t())).into_iter().fold(C::F::one(), |exp, l| {
|
||||
res.push((exp, values[l]));
|
||||
exp * i
|
||||
});
|
||||
res
|
||||
};
|
||||
|
||||
@@ -254,15 +251,7 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
||||
|
||||
// TODO: Clear serialized and shares
|
||||
|
||||
Ok(
|
||||
FrostKeys {
|
||||
params,
|
||||
secret_share,
|
||||
group_key: stripes[0],
|
||||
verification_shares,
|
||||
offset: None
|
||||
}
|
||||
)
|
||||
Ok(FrostKeys { params, secret_share, group_key: stripes[0], verification_shares, offset: None })
|
||||
}
|
||||
|
||||
pub struct KeyGenMachine<C: Curve> {
|
||||
@@ -298,11 +287,8 @@ impl<C: Curve> KeyGenMachine<C> {
|
||||
self,
|
||||
rng: &mut R,
|
||||
) -> (SecretShareMachine<C>, Vec<u8>) {
|
||||
let (
|
||||
coefficients,
|
||||
our_commitments,
|
||||
serialized
|
||||
) = generate_key_r1::<_, C>(rng, &self.params, &self.context);
|
||||
let (coefficients, our_commitments, serialized) =
|
||||
generate_key_r1::<_, C>(rng, &self.params, &self.context);
|
||||
|
||||
(
|
||||
SecretShareMachine {
|
||||
|
||||
@@ -3,7 +3,10 @@ use std::{io::Read, collections::HashMap};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||
use group::{
|
||||
ff::{Field, PrimeField},
|
||||
GroupEncoding,
|
||||
};
|
||||
|
||||
mod schnorr;
|
||||
|
||||
@@ -28,11 +31,7 @@ pub struct FrostParams {
|
||||
}
|
||||
|
||||
impl FrostParams {
|
||||
pub fn new(
|
||||
t: u16,
|
||||
n: u16,
|
||||
i: u16
|
||||
) -> Result<FrostParams, FrostError> {
|
||||
pub fn new(t: u16, n: u16, i: u16) -> Result<FrostParams, FrostError> {
|
||||
if (t == 0) || (n == 0) {
|
||||
Err(FrostError::ZeroParameter(t, n))?;
|
||||
}
|
||||
@@ -46,12 +45,18 @@ impl FrostParams {
|
||||
Err(FrostError::InvalidParticipantIndex(n, i))?;
|
||||
}
|
||||
|
||||
Ok(FrostParams{ t, n, i })
|
||||
Ok(FrostParams { t, n, i })
|
||||
}
|
||||
|
||||
pub fn t(&self) -> u16 { self.t }
|
||||
pub fn n(&self) -> u16 { self.n }
|
||||
pub fn i(&self) -> u16 { self.i }
|
||||
pub fn t(&self) -> u16 {
|
||||
self.t
|
||||
}
|
||||
pub fn n(&self) -> u16 {
|
||||
self.n
|
||||
}
|
||||
pub fn i(&self) -> u16 {
|
||||
self.i
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Error, Debug)]
|
||||
@@ -112,10 +117,7 @@ impl<C: Curve> FrostView<C> {
|
||||
}
|
||||
|
||||
/// Calculate the lagrange coefficient for a signing set
|
||||
pub fn lagrange<F: PrimeField>(
|
||||
i: u16,
|
||||
included: &[u16],
|
||||
) -> F {
|
||||
pub fn lagrange<F: PrimeField>(i: u16, included: &[u16]) -> F {
|
||||
let mut num = F::one();
|
||||
let mut denom = F::one();
|
||||
for l in included {
|
||||
@@ -192,12 +194,13 @@ impl<C: Curve> FrostKeys<C> {
|
||||
Ok(FrostView {
|
||||
group_key: self.group_key,
|
||||
secret_share: secret_share + offset_share,
|
||||
verification_shares: self.verification_shares.iter().map(
|
||||
|(l, share)| (
|
||||
*l,
|
||||
(*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR * offset_share)
|
||||
)
|
||||
).collect(),
|
||||
verification_shares: self
|
||||
.verification_shares
|
||||
.iter()
|
||||
.map(|(l, share)| {
|
||||
(*l, (*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR * offset_share))
|
||||
})
|
||||
.collect(),
|
||||
included: included.to_vec(),
|
||||
})
|
||||
}
|
||||
@@ -242,36 +245,35 @@ impl<C: Curve> FrostKeys<C> {
|
||||
let (t, n, i) = {
|
||||
let mut read_u16 = || {
|
||||
let mut value = [0; 2];
|
||||
cursor.read_exact(&mut value).map_err(
|
||||
|_| FrostError::InternalError("missing participant quantities")
|
||||
)?;
|
||||
cursor
|
||||
.read_exact(&mut value)
|
||||
.map_err(|_| FrostError::InternalError("missing participant quantities"))?;
|
||||
Ok(u16::from_be_bytes(value))
|
||||
};
|
||||
(read_u16()?, read_u16()?, read_u16()?)
|
||||
};
|
||||
|
||||
let secret_share = C::read_F(cursor)
|
||||
.map_err(|_| FrostError::InternalError("invalid secret share"))?;
|
||||
let group_key = C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid group key"))?;
|
||||
let secret_share =
|
||||
C::read_F(cursor).map_err(|_| FrostError::InternalError("invalid secret share"))?;
|
||||
let group_key =
|
||||
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid group key"))?;
|
||||
|
||||
let mut verification_shares = HashMap::new();
|
||||
for l in 1 ..= n {
|
||||
verification_shares.insert(
|
||||
l,
|
||||
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid verification share"))?
|
||||
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid verification share"))?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(
|
||||
FrostKeys {
|
||||
params: FrostParams::new(t, n, i)
|
||||
.map_err(|_| FrostError::InternalError("invalid parameters"))?,
|
||||
secret_share,
|
||||
group_key,
|
||||
verification_shares,
|
||||
offset: None
|
||||
}
|
||||
)
|
||||
Ok(FrostKeys {
|
||||
params: FrostParams::new(t, n, i)
|
||||
.map_err(|_| FrostError::InternalError("invalid parameters"))?,
|
||||
secret_share,
|
||||
group_key,
|
||||
verification_shares,
|
||||
offset: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +281,7 @@ impl<C: Curve> FrostKeys<C> {
|
||||
pub(crate) fn validate_map<T>(
|
||||
map: &mut HashMap<u16, T>,
|
||||
included: &[u16],
|
||||
ours: u16
|
||||
ours: u16,
|
||||
) -> Result<(), FrostError> {
|
||||
if (map.len() + 1) != included.len() {
|
||||
Err(FrostError::InvalidParticipantQuantity(included.len(), map.len() + 1))?;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use group::{ff::{Field, PrimeField}, GroupEncoding};
|
||||
use group::{
|
||||
ff::{Field, PrimeField},
|
||||
GroupEncoding,
|
||||
};
|
||||
|
||||
use multiexp::BatchVerifier;
|
||||
|
||||
@@ -25,26 +28,23 @@ impl<C: Curve> SchnorrSignature<C> {
|
||||
pub(crate) fn sign<C: Curve>(
|
||||
private_key: C::F,
|
||||
nonce: C::F,
|
||||
challenge: C::F
|
||||
challenge: C::F,
|
||||
) -> SchnorrSignature<C> {
|
||||
SchnorrSignature {
|
||||
R: C::GENERATOR * nonce,
|
||||
s: nonce + (private_key * challenge)
|
||||
}
|
||||
SchnorrSignature { R: C::GENERATOR * nonce, s: nonce + (private_key * challenge) }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn verify<C: Curve>(
|
||||
public_key: C::G,
|
||||
challenge: C::F,
|
||||
signature: &SchnorrSignature<C>
|
||||
signature: &SchnorrSignature<C>,
|
||||
) -> bool {
|
||||
(C::GENERATOR * signature.s) == (signature.R + (public_key * challenge))
|
||||
}
|
||||
|
||||
pub(crate) fn batch_verify<C: Curve, R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)]
|
||||
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)],
|
||||
) -> Result<(), u16> {
|
||||
let mut values = [(C::F::one(), C::GENERATOR); 3];
|
||||
let mut batch = BatchVerifier::new(triplets.len());
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
use core::fmt;
|
||||
use std::{io::{Read, Cursor}, sync::Arc, collections::HashMap};
|
||||
use std::{
|
||||
io::{Read, Cursor},
|
||||
sync::Arc,
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use transcript::Transcript;
|
||||
|
||||
use group::{ff::{Field, PrimeField}, Group, GroupEncoding};
|
||||
use group::{
|
||||
ff::{Field, PrimeField},
|
||||
Group, GroupEncoding,
|
||||
};
|
||||
use multiexp::multiexp_vartime;
|
||||
|
||||
use dleq::DLEqProof;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
FrostError, FrostParams, FrostKeys, FrostView,
|
||||
algorithm::Algorithm,
|
||||
validate_map
|
||||
curve::Curve, FrostError, FrostParams, FrostKeys, FrostView, algorithm::Algorithm, validate_map,
|
||||
};
|
||||
|
||||
/// Pairing of an Algorithm with a FrostKeys instance and this specific signing set
|
||||
@@ -88,11 +92,14 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
||||
params: &mut Params<C, A>,
|
||||
) -> (PreprocessPackage<C>, Vec<u8>) {
|
||||
let mut serialized = Vec::with_capacity(2 * C::G_len());
|
||||
let (nonces, commitments) = params.algorithm.nonces().iter().map(
|
||||
|generators| {
|
||||
let (nonces, commitments) = params
|
||||
.algorithm
|
||||
.nonces()
|
||||
.iter()
|
||||
.map(|generators| {
|
||||
let nonces = [
|
||||
C::random_nonce(params.view().secret_share(), &mut *rng),
|
||||
C::random_nonce(params.view().secret_share(), &mut *rng)
|
||||
C::random_nonce(params.view().secret_share(), &mut *rng),
|
||||
];
|
||||
|
||||
let commit = |generator: C::G, buf: &mut Vec<u8>| {
|
||||
@@ -116,18 +123,15 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
||||
// This could be further optimized with a multi-nonce proof.
|
||||
// See https://github.com/serai-dex/serai/issues/38
|
||||
for nonce in nonces {
|
||||
DLEqProof::prove(
|
||||
&mut *rng,
|
||||
&mut transcript,
|
||||
&generators,
|
||||
nonce
|
||||
).serialize(&mut serialized).unwrap();
|
||||
DLEqProof::prove(&mut *rng, &mut transcript, &generators, nonce)
|
||||
.serialize(&mut serialized)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
(nonces, commitments)
|
||||
}
|
||||
).unzip();
|
||||
})
|
||||
.unzip();
|
||||
|
||||
let addendum = params.algorithm.preprocess_addendum(rng, ¶ms.view);
|
||||
serialized.extend(&addendum);
|
||||
@@ -139,7 +143,7 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
||||
fn read_D_E<Re: Read, C: Curve>(cursor: &mut Re, l: u16) -> Result<[C::G; 2], FrostError> {
|
||||
Ok([
|
||||
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?,
|
||||
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?
|
||||
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?,
|
||||
])
|
||||
}
|
||||
|
||||
@@ -197,7 +201,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
params.algorithm.process_addendum(
|
||||
¶ms.view,
|
||||
*l,
|
||||
&mut Cursor::new(our_preprocess.addendum.clone())
|
||||
&mut Cursor::new(our_preprocess.addendum.clone()),
|
||||
)?;
|
||||
} else {
|
||||
let mut cursor = commitments.remove(l).unwrap();
|
||||
@@ -213,13 +217,14 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
if nonce_generators.len() >= 2 {
|
||||
let mut transcript = nonce_transcript::<A::Transcript>();
|
||||
for de in 0 .. 2 {
|
||||
DLEqProof::deserialize(
|
||||
&mut cursor
|
||||
).map_err(|_| FrostError::InvalidCommitment(*l))?.verify(
|
||||
&mut transcript,
|
||||
&nonce_generators,
|
||||
&commitments[n].iter().map(|commitments| commitments[de]).collect::<Vec<_>>(),
|
||||
).map_err(|_| FrostError::InvalidCommitment(*l))?;
|
||||
DLEqProof::deserialize(&mut cursor)
|
||||
.map_err(|_| FrostError::InvalidCommitment(*l))?
|
||||
.verify(
|
||||
&mut transcript,
|
||||
&nonce_generators,
|
||||
&commitments[n].iter().map(|commitments| commitments[de]).collect::<Vec<_>>(),
|
||||
)
|
||||
.map_err(|_| FrostError::InvalidCommitment(*l))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,7 +241,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
// protocol
|
||||
rho_transcript.append_message(
|
||||
b"commitments",
|
||||
&C::hash_msg(params.algorithm.transcript().challenge(b"commitments").as_ref())
|
||||
&C::hash_msg(params.algorithm.transcript().challenge(b"commitments").as_ref()),
|
||||
);
|
||||
// Include the offset, if one exists
|
||||
// While this isn't part of the FROST-expected rho transcript, the offset being here coincides
|
||||
@@ -254,10 +259,10 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
|
||||
// Merge the rho transcript back into the global one to ensure its advanced while committing to
|
||||
// everything
|
||||
params.algorithm.transcript().append_message(
|
||||
b"rho_transcript",
|
||||
rho_transcript.challenge(b"merge").as_ref()
|
||||
);
|
||||
params
|
||||
.algorithm
|
||||
.transcript()
|
||||
.append_message(b"rho_transcript", rho_transcript.challenge(b"merge").as_ref());
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -280,10 +285,12 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
let share = params.algorithm.sign_share(
|
||||
¶ms.view,
|
||||
&Rs,
|
||||
&our_preprocess.nonces.iter().map(
|
||||
|nonces| nonces[0] + (nonces[1] * B[¶ms.keys.params.i()].1)
|
||||
).collect::<Vec<_>>(),
|
||||
msg
|
||||
&our_preprocess
|
||||
.nonces
|
||||
.iter()
|
||||
.map(|nonces| nonces[0] + (nonces[1] * B[¶ms.keys.params.i()].1))
|
||||
.collect::<Vec<_>>(),
|
||||
msg,
|
||||
);
|
||||
Ok((Package { B, Rs, share }, share.to_repr().as_ref().to_vec()))
|
||||
}
|
||||
@@ -321,21 +328,21 @@ fn complete<Re: Read, C: Curve, A: Algorithm<C>>(
|
||||
for l in &sign_params.view.included {
|
||||
if !sign_params.algorithm.verify_share(
|
||||
sign_params.view.verification_share(*l),
|
||||
&sign.B[l].0.iter().map(
|
||||
|nonces| nonces.iter().map(
|
||||
|commitments| commitments[0] + (commitments[1] * sign.B[l].1)
|
||||
).collect()
|
||||
).collect::<Vec<_>>(),
|
||||
responses[l]
|
||||
&sign.B[l]
|
||||
.0
|
||||
.iter()
|
||||
.map(|nonces| {
|
||||
nonces.iter().map(|commitments| commitments[0] + (commitments[1] * sign.B[l].1)).collect()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
responses[l],
|
||||
) {
|
||||
Err(FrostError::InvalidShare(*l))?;
|
||||
}
|
||||
}
|
||||
|
||||
// If everyone has a valid share and there were enough participants, this should've worked
|
||||
Err(
|
||||
FrostError::InternalError("everyone had a valid share yet the signature was still invalid")
|
||||
)
|
||||
Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid"))
|
||||
}
|
||||
|
||||
pub trait PreprocessMachine {
|
||||
@@ -345,10 +352,7 @@ pub trait PreprocessMachine {
|
||||
/// Perform the preprocessing round required in order to sign
|
||||
/// Returns a byte vector which must be transmitted to all parties selected for this signing
|
||||
/// process, over an authenticated channel
|
||||
fn preprocess<R: RngCore + CryptoRng>(
|
||||
self,
|
||||
rng: &mut R
|
||||
) -> (Self::SignMachine, Vec<u8>);
|
||||
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>);
|
||||
}
|
||||
|
||||
pub trait SignMachine<S> {
|
||||
@@ -376,7 +380,7 @@ pub trait SignatureMachine<S> {
|
||||
|
||||
/// State machine which manages signing for an arbitrary signature algorithm
|
||||
pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
|
||||
params: Params<C, A>
|
||||
params: Params<C, A>,
|
||||
}
|
||||
|
||||
pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
|
||||
@@ -401,7 +405,7 @@ impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> {
|
||||
|
||||
pub(crate) fn unsafe_override_preprocess(
|
||||
self,
|
||||
preprocess: PreprocessPackage<C>
|
||||
preprocess: PreprocessPackage<C>,
|
||||
) -> AlgorithmSignMachine<C, A> {
|
||||
AlgorithmSignMachine { params: self.params, preprocess }
|
||||
}
|
||||
@@ -411,10 +415,7 @@ impl<C: Curve, A: Algorithm<C>> PreprocessMachine for AlgorithmMachine<C, A> {
|
||||
type Signature = A::Signature;
|
||||
type SignMachine = AlgorithmSignMachine<C, A>;
|
||||
|
||||
fn preprocess<R: RngCore + CryptoRng>(
|
||||
self,
|
||||
rng: &mut R
|
||||
) -> (Self::SignMachine, Vec<u8>) {
|
||||
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>) {
|
||||
let mut params = self.params;
|
||||
let (preprocess, serialized) = preprocess::<R, C, A>(rng, &mut params);
|
||||
(AlgorithmSignMachine { params, preprocess }, serialized)
|
||||
@@ -427,7 +428,7 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachi
|
||||
fn sign<Re: Read>(
|
||||
self,
|
||||
commitments: HashMap<u16, Re>,
|
||||
msg: &[u8]
|
||||
msg: &[u8],
|
||||
) -> Result<(Self::SignatureMachine, Vec<u8>), FrostError> {
|
||||
let mut params = self.params;
|
||||
let (sign, serialized) = sign_with_share(&mut params, self.preprocess, commitments, msg)?;
|
||||
@@ -435,10 +436,7 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachi
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
C: Curve,
|
||||
A: Algorithm<C>
|
||||
> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
|
||||
impl<C: Curve, A: Algorithm<C>> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
|
||||
fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<A::Signature, FrostError> {
|
||||
complete(&self.params, self.sign, shares)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::{curve, tests::vectors::{Vectors, test_with_vectors}};
|
||||
use crate::{
|
||||
curve,
|
||||
tests::vectors::{Vectors, test_with_vectors},
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "ristretto"))]
|
||||
#[test]
|
||||
@@ -12,7 +15,7 @@ fn ristretto_vectors() {
|
||||
shares: &[
|
||||
"5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e",
|
||||
"b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01",
|
||||
"f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04"
|
||||
"f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04",
|
||||
],
|
||||
group_secret: "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
|
||||
group_key: "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
|
||||
@@ -22,20 +25,20 @@ fn ristretto_vectors() {
|
||||
nonces: &[
|
||||
[
|
||||
"eb0dc12ae7b746d36e3f2de46ce3833a05b9d4af5434eeb8cafaefda76906d00",
|
||||
"491e91aa9df514ef598d5e0c7c5cdd088fbde4965b96069d546c0f04f1822b03"
|
||||
"491e91aa9df514ef598d5e0c7c5cdd088fbde4965b96069d546c0f04f1822b03",
|
||||
],
|
||||
[
|
||||
"abd12b8e6f255ee1e540eab029003a6e956567617720f61115f0941615892209",
|
||||
"218e22625f93f262f025bd2d13c46ba722aa29fe585ceed66ff442d98fe4e509"
|
||||
]
|
||||
"218e22625f93f262f025bd2d13c46ba722aa29fe585ceed66ff442d98fe4e509",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"efae3a83437fa8cd96194aacc56a7eb841630c280da99e7764a81d1340323306",
|
||||
"96ddc4582e45eabce46f07b9e9375f8b49d35d1510fd34ac02b1e79d6100a602"
|
||||
"96ddc4582e45eabce46f07b9e9375f8b49d35d1510fd34ac02b1e79d6100a602",
|
||||
],
|
||||
sig: "7ec584cef9a383afb43883b73bcaa6313afe878bd5fe75a608311b866a76ec67".to_owned() +
|
||||
"858cffdb71c4928a7b895165afa2dd438b366a3d1da6d323675905b1a132d908"
|
||||
}
|
||||
"858cffdb71c4928a7b895165afa2dd438b366a3d1da6d323675905b1a132d908",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,7 +52,7 @@ fn ed25519_vectors() {
|
||||
shares: &[
|
||||
"929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509",
|
||||
"a91e66e012e4364ac9aaa405fcafd370402d9859f7b6685c07eed76bf409e80d",
|
||||
"d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02"
|
||||
"d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02",
|
||||
],
|
||||
group_secret: "7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304",
|
||||
group_key: "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673",
|
||||
@@ -59,19 +62,19 @@ fn ed25519_vectors() {
|
||||
nonces: &[
|
||||
[
|
||||
"d9aad97e1a1127bb87702ce8d81d8c07c7cbca89e784868d8e3876ff6b459700",
|
||||
"5063be2774520d08a5ccd7f1213fb1179a5fa292bf13bc91cb28e7bd4d4a690c"
|
||||
"5063be2774520d08a5ccd7f1213fb1179a5fa292bf13bc91cb28e7bd4d4a690c",
|
||||
],
|
||||
[
|
||||
"86961f3a429ac0c5696f49e6d796817ff653f83c07f34e9e1f4d4c8c515b7900",
|
||||
"72225ec11c1315d9f1ea0e78b1160ed95800fadd0191d23fd2f2c90ac96cb307"
|
||||
]
|
||||
"72225ec11c1315d9f1ea0e78b1160ed95800fadd0191d23fd2f2c90ac96cb307",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"caae171b83bff0c2c6f56a1276892918ba228146f6344b85d2ec6efeb6f16d0d",
|
||||
"ea6fdbf61683cf5f1f742e1b91583f0f667f0369efd2e33399b96d5a3ff0300d"
|
||||
"ea6fdbf61683cf5f1f742e1b91583f0f667f0369efd2e33399b96d5a3ff0300d",
|
||||
],
|
||||
sig: "5da10008c13c04dd72328ba8e0f72b63cad43c3bf4b7eaada1c78225afbd977e".to_owned() +
|
||||
"c74afdb47fdfadca0fcda18a28e8891220a284afe5072fb96ba6dc58f6e19e0a"
|
||||
}
|
||||
"c74afdb47fdfadca0fcda18a28e8891220a284afe5072fb96ba6dc58f6e19e0a",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ fn secp256k1_non_ietf() {
|
||||
shares: &[
|
||||
"08f89ffe80ac94dcb920c26f3f46140bfc7f95b493f8310f5fc1ea2b01f4254c",
|
||||
"04f0feac2edcedc6ce1253b7fab8c86b856a797f44d83d82a385554e6e401984",
|
||||
"00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc"
|
||||
"00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc",
|
||||
],
|
||||
group_secret: "0d004150d27c3bf2a42f312683d35fac7394b1e9e318249c1bfe7f0795a83114",
|
||||
group_key: "02f37c34b66ced1fb51c34a90bdae006901f10625cc06c4f64663b0eae87d87b4f",
|
||||
@@ -29,20 +29,20 @@ fn secp256k1_non_ietf() {
|
||||
nonces: &[
|
||||
[
|
||||
"31c3c1b76b76664569859b9251fbabed9d4d432c6f5aaa03ed41f9c231935798",
|
||||
"206f4ffaeb602ccb57cbe50e146ac690e6d7317d4b93377061d9d1b4caf78a26"
|
||||
"206f4ffaeb602ccb57cbe50e146ac690e6d7317d4b93377061d9d1b4caf78a26",
|
||||
],
|
||||
[
|
||||
"0d3945bc1553676a5dd910cb4f14437d99ed421516b2617357b984820fdca520",
|
||||
"635e0fd90caaf40b5e986d0ee0f58778e4d88731bc6ac70350ef702ffe20a21b"
|
||||
]
|
||||
"635e0fd90caaf40b5e986d0ee0f58778e4d88731bc6ac70350ef702ffe20a21b",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"18b71e284c5d008896ed8847b234ec829eda376d6208838ee7faf2ce21b154c1",
|
||||
"a452a49c8116124d0a283f3589a96b704894b43246e47e59d376353bcc638311"
|
||||
"a452a49c8116124d0a283f3589a96b704894b43246e47e59d376353bcc638311",
|
||||
],
|
||||
sig: "03dafb28ee7ad033fd15ed470d07156617260d74a9d76a15d371d7b613d2b111e".to_owned() +
|
||||
"7bd09c2c4cd7312d5a115c77d3bde57f2e76eeb9fa8ed01e8bb712809ee14d7d2"
|
||||
}
|
||||
"7bd09c2c4cd7312d5a115c77d3bde57f2e76eeb9fa8ed01e8bb712809ee14d7d2",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ fn p256_vectors() {
|
||||
shares: &[
|
||||
"0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731",
|
||||
"8d8e787bef0ff6c2f494ca45f4dad198c6bee01212d6c84067159c52e1863ad5",
|
||||
"0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928"
|
||||
"0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928",
|
||||
],
|
||||
group_secret: "8ba9bba2e0fd8c4767154d35a0b7562244a4aaf6f36c8fb8735fa48b301bd8de",
|
||||
group_key: "023a309ad94e9fe8a7ba45dfc58f38bf091959d3c99cfbd02b4dc00585ec45ab70",
|
||||
@@ -66,19 +66,19 @@ fn p256_vectors() {
|
||||
nonces: &[
|
||||
[
|
||||
"33a519cf070a166f9ef41a798d03423743f3e7d0b0efd5d0d963773c4c53205e",
|
||||
"307d208d0c5728f323ae374f1ebd7f14a1a49b77d9d4bc1eab222218a17765ff"
|
||||
"307d208d0c5728f323ae374f1ebd7f14a1a49b77d9d4bc1eab222218a17765ff",
|
||||
],
|
||||
[
|
||||
"a614eadb972dc37b88aeceb6e899903f3104742d13f379a0e014541decbea4a4",
|
||||
"e509791018504c5bb87edaf0f44761cc840888507c4cd80237971d78e65f70f2"
|
||||
]
|
||||
"e509791018504c5bb87edaf0f44761cc840888507c4cd80237971d78e65f70f2",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"61e8b9c474df2e66ad19fd80a6e6cec1c6fe43c0a1cffd2d1c28299e93e1bbdb",
|
||||
"9651d355ca1dea2557ba1f73e38a9f4ff1f1afc565323ef27f88a9d14df8370e"
|
||||
"9651d355ca1dea2557ba1f73e38a9f4ff1f1afc565323ef27f88a9d14df8370e",
|
||||
],
|
||||
sig: "02dfba781e17b830229ae4ed22ebe402873683d9dfd945d01762217fb3172c2a7".to_owned() +
|
||||
"1f83a8d1a3efd188c04d41cf48a716e11b8eff38607023c1f9bb0d36fe1d9f2e9"
|
||||
}
|
||||
"1f83a8d1a3efd188c04d41cf48a716e11b8eff38607023c1f9bb0d36fe1d9f2e9",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,10 @@ use rand_core::{RngCore, CryptoRng};
|
||||
use group::ff::Field;
|
||||
|
||||
use crate::{
|
||||
Curve,
|
||||
FrostParams, FrostKeys,
|
||||
lagrange,
|
||||
Curve, FrostParams, FrostKeys, lagrange,
|
||||
key_gen::KeyGenMachine,
|
||||
algorithm::Algorithm,
|
||||
sign::{PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine}
|
||||
sign::{PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine},
|
||||
};
|
||||
|
||||
// Test suites for public usage
|
||||
@@ -27,22 +25,20 @@ pub const THRESHOLD: u16 = ((PARTICIPANTS / 3) * 2) + 1;
|
||||
|
||||
pub fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>(
|
||||
map: &HashMap<K, V>,
|
||||
without: &K
|
||||
without: &K,
|
||||
) -> HashMap<K, V> {
|
||||
let mut res = map.clone();
|
||||
res.remove(without).unwrap();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(
|
||||
rng: &mut R
|
||||
) -> HashMap<u16, Arc<FrostKeys<C>>> {
|
||||
pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, Arc<FrostKeys<C>>> {
|
||||
let mut machines = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
for i in 1 ..= PARTICIPANTS {
|
||||
let machine = KeyGenMachine::<C>::new(
|
||||
FrostParams::new(THRESHOLD, PARTICIPANTS, i).unwrap(),
|
||||
"FROST Test key_gen".to_string()
|
||||
"FROST Test key_gen".to_string(),
|
||||
);
|
||||
let (machine, these_commitments) = machine.generate_coefficients(rng);
|
||||
machines.insert(i, machine);
|
||||
@@ -50,41 +46,45 @@ pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(
|
||||
}
|
||||
|
||||
let mut secret_shares = HashMap::new();
|
||||
let mut machines = machines.drain().map(|(l, machine)| {
|
||||
let (machine, shares) = machine.generate_secret_shares(
|
||||
rng,
|
||||
clone_without(&commitments, &l)
|
||||
).unwrap();
|
||||
secret_shares.insert(l, shares);
|
||||
(l, machine)
|
||||
}).collect::<HashMap<_, _>>();
|
||||
let mut machines = machines
|
||||
.drain()
|
||||
.map(|(l, machine)| {
|
||||
let (machine, shares) =
|
||||
machine.generate_secret_shares(rng, clone_without(&commitments, &l)).unwrap();
|
||||
secret_shares.insert(l, shares);
|
||||
(l, machine)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut verification_shares = None;
|
||||
let mut group_key = None;
|
||||
machines.drain().map(|(i, machine)| {
|
||||
let mut our_secret_shares = HashMap::new();
|
||||
for (l, shares) in &secret_shares {
|
||||
if i == *l {
|
||||
continue;
|
||||
machines
|
||||
.drain()
|
||||
.map(|(i, machine)| {
|
||||
let mut our_secret_shares = HashMap::new();
|
||||
for (l, shares) in &secret_shares {
|
||||
if i == *l {
|
||||
continue;
|
||||
}
|
||||
our_secret_shares.insert(*l, Cursor::new(shares[&i].clone()));
|
||||
}
|
||||
our_secret_shares.insert(*l, Cursor::new(shares[&i].clone()));
|
||||
}
|
||||
let these_keys = machine.complete(rng, our_secret_shares).unwrap();
|
||||
let these_keys = machine.complete(rng, our_secret_shares).unwrap();
|
||||
|
||||
// Verify the verification_shares are agreed upon
|
||||
if verification_shares.is_none() {
|
||||
verification_shares = Some(these_keys.verification_shares());
|
||||
}
|
||||
assert_eq!(verification_shares.as_ref().unwrap(), &these_keys.verification_shares());
|
||||
// Verify the verification_shares are agreed upon
|
||||
if verification_shares.is_none() {
|
||||
verification_shares = Some(these_keys.verification_shares());
|
||||
}
|
||||
assert_eq!(verification_shares.as_ref().unwrap(), &these_keys.verification_shares());
|
||||
|
||||
// Verify the group keys are agreed upon
|
||||
if group_key.is_none() {
|
||||
group_key = Some(these_keys.group_key());
|
||||
}
|
||||
assert_eq!(group_key.unwrap(), these_keys.group_key());
|
||||
// Verify the group keys are agreed upon
|
||||
if group_key.is_none() {
|
||||
group_key = Some(these_keys.group_key());
|
||||
}
|
||||
assert_eq!(group_key.unwrap(), these_keys.group_key());
|
||||
|
||||
(i, Arc::new(these_keys))
|
||||
}).collect::<HashMap<_, _>>()
|
||||
(i, Arc::new(these_keys))
|
||||
})
|
||||
.collect::<HashMap<_, _>>()
|
||||
}
|
||||
|
||||
pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
|
||||
@@ -92,10 +92,9 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
|
||||
assert!(keys.len() >= first.params().t().into(), "not enough keys provided");
|
||||
let included = keys.keys().cloned().collect::<Vec<_>>();
|
||||
|
||||
let group_private = keys.iter().fold(
|
||||
C::F::zero(),
|
||||
|accum, (i, keys)| accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
|
||||
);
|
||||
let group_private = keys.iter().fold(C::F::zero(), |accum, (i, keys)| {
|
||||
accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
|
||||
});
|
||||
assert_eq!(C::GENERATOR * group_private, first.group_key(), "failed to recover keys");
|
||||
group_private
|
||||
}
|
||||
@@ -114,40 +113,45 @@ pub fn algorithm_machines<R: RngCore, C: Curve, A: Algorithm<C>>(
|
||||
included.push(n);
|
||||
}
|
||||
|
||||
keys.iter().filter_map(
|
||||
|(i, keys)| if included.contains(&i) {
|
||||
Some((
|
||||
*i,
|
||||
AlgorithmMachine::new(
|
||||
algorithm.clone(),
|
||||
keys.clone(),
|
||||
&included.clone()
|
||||
).unwrap()
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
).collect()
|
||||
keys
|
||||
.iter()
|
||||
.filter_map(|(i, keys)| {
|
||||
if included.contains(&i) {
|
||||
Some((
|
||||
*i,
|
||||
AlgorithmMachine::new(algorithm.clone(), keys.clone(), &included.clone()).unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>(
|
||||
rng: &mut R,
|
||||
mut machines: HashMap<u16, M>,
|
||||
msg: &[u8]
|
||||
msg: &[u8],
|
||||
) -> M::Signature {
|
||||
let mut commitments = HashMap::new();
|
||||
let mut machines = machines.drain().map(|(i, machine)| {
|
||||
let (machine, preprocess) = machine.preprocess(rng);
|
||||
commitments.insert(i, Cursor::new(preprocess));
|
||||
(i, machine)
|
||||
}).collect::<HashMap<_, _>>();
|
||||
let mut machines = machines
|
||||
.drain()
|
||||
.map(|(i, machine)| {
|
||||
let (machine, preprocess) = machine.preprocess(rng);
|
||||
commitments.insert(i, Cursor::new(preprocess));
|
||||
(i, machine)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut shares = HashMap::new();
|
||||
let mut machines = machines.drain().map(|(i, machine)| {
|
||||
let (machine, share) = machine.sign(clone_without(&commitments, &i), msg).unwrap();
|
||||
shares.insert(i, Cursor::new(share));
|
||||
(i, machine)
|
||||
}).collect::<HashMap<_, _>>();
|
||||
let mut machines = machines
|
||||
.drain()
|
||||
.map(|(i, machine)| {
|
||||
let (machine, share) = machine.sign(clone_without(&commitments, &i), msg).unwrap();
|
||||
shares.insert(i, Cursor::new(share));
|
||||
(i, machine)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut signature = None;
|
||||
for (i, machine) in machines.drain() {
|
||||
|
||||
@@ -5,34 +5,32 @@ use rand_core::{RngCore, CryptoRng};
|
||||
use group::{ff::Field, GroupEncoding};
|
||||
|
||||
use crate::{
|
||||
Curve, FrostKeys, schnorr::{self, SchnorrSignature}, algorithm::{Hram, Schnorr},
|
||||
tests::{key_gen, algorithm_machines, sign as sign_test}
|
||||
Curve, FrostKeys,
|
||||
schnorr::{self, SchnorrSignature},
|
||||
algorithm::{Hram, Schnorr},
|
||||
tests::{key_gen, algorithm_machines, sign as sign_test},
|
||||
};
|
||||
|
||||
pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
let private_key = C::F::random(&mut *rng);
|
||||
let nonce = C::F::random(&mut *rng);
|
||||
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
|
||||
assert!(
|
||||
schnorr::verify::<C>(
|
||||
C::GENERATOR * private_key,
|
||||
challenge,
|
||||
&schnorr::sign(private_key, nonce, challenge)
|
||||
)
|
||||
);
|
||||
assert!(schnorr::verify::<C>(
|
||||
C::GENERATOR * private_key,
|
||||
challenge,
|
||||
&schnorr::sign(private_key, nonce, challenge)
|
||||
));
|
||||
}
|
||||
|
||||
// The above sign function verifies signing works
|
||||
// This verifies invalid signatures don't pass, using zero signatures, which should effectively be
|
||||
// random
|
||||
pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
assert!(
|
||||
!schnorr::verify::<C>(
|
||||
C::GENERATOR * C::F::random(&mut *rng),
|
||||
C::F::random(rng),
|
||||
&SchnorrSignature { R: C::GENERATOR * C::F::zero(), s: C::F::zero() }
|
||||
)
|
||||
);
|
||||
assert!(!schnorr::verify::<C>(
|
||||
C::GENERATOR * C::F::random(&mut *rng),
|
||||
C::F::random(rng),
|
||||
&SchnorrSignature { R: C::GENERATOR * C::F::zero(), s: C::F::zero() }
|
||||
));
|
||||
}
|
||||
|
||||
pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
@@ -47,9 +45,9 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
}
|
||||
|
||||
// Batch verify
|
||||
let triplets = (0 .. 5).map(
|
||||
|i| (u16::try_from(i + 1).unwrap(), C::GENERATOR * keys[i], challenges[i], sigs[i])
|
||||
).collect::<Vec<_>>();
|
||||
let triplets = (0 .. 5)
|
||||
.map(|i| (u16::try_from(i + 1).unwrap(), C::GENERATOR * keys[i], challenges[i], sigs[i]))
|
||||
.collect::<Vec<_>>();
|
||||
schnorr::batch_verify(rng, &triplets).unwrap();
|
||||
|
||||
// Shift 1 from s from one to another and verify it fails
|
||||
@@ -80,7 +78,7 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
||||
fn sign_core<R: RngCore + CryptoRng, C: Curve>(
|
||||
rng: &mut R,
|
||||
group_key: C::G,
|
||||
keys: &HashMap<u16, Arc<FrostKeys<C>>>
|
||||
keys: &HashMap<u16, Arc<FrostKeys<C>>>,
|
||||
) {
|
||||
const MESSAGE: &'static [u8] = b"Hello, World!";
|
||||
|
||||
@@ -91,7 +89,7 @@ fn sign_core<R: RngCore + CryptoRng, C: Curve>(
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TestHram<C: Curve> {
|
||||
_curve: PhantomData<C>
|
||||
_curve: PhantomData<C>,
|
||||
}
|
||||
impl<C: Curve> Hram<C> for TestHram<C> {
|
||||
#[allow(non_snake_case)]
|
||||
|
||||
@@ -5,10 +5,11 @@ use rand_core::{RngCore, CryptoRng};
|
||||
use group::{ff::PrimeField, GroupEncoding};
|
||||
|
||||
use crate::{
|
||||
curve::Curve, FrostKeys,
|
||||
curve::Curve,
|
||||
FrostKeys,
|
||||
algorithm::{Schnorr, Hram},
|
||||
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
|
||||
tests::{clone_without, curve::test_curve, schnorr::test_schnorr, recover}
|
||||
tests::{clone_without, curve::test_curve, schnorr::test_schnorr, recover},
|
||||
};
|
||||
|
||||
pub struct Vectors {
|
||||
@@ -21,17 +22,17 @@ pub struct Vectors {
|
||||
pub included: &'static [u16],
|
||||
pub nonces: &'static [[&'static str; 2]],
|
||||
pub sig_shares: &'static [&'static str],
|
||||
pub sig: String
|
||||
pub sig: String,
|
||||
}
|
||||
|
||||
// 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>> {
|
||||
let shares = vectors.shares.iter().map(
|
||||
|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap()
|
||||
).collect::<Vec<_>>();
|
||||
let verification_shares = shares.iter().map(
|
||||
|secret| C::GENERATOR * secret
|
||||
).collect::<Vec<_>>();
|
||||
let shares = vectors
|
||||
.shares
|
||||
.iter()
|
||||
.map(|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
let verification_shares = shares.iter().map(|secret| C::GENERATOR * secret).collect::<Vec<_>>();
|
||||
|
||||
let mut keys = HashMap::new();
|
||||
for i in 1 ..= u16::try_from(shares.len()).unwrap() {
|
||||
@@ -59,11 +60,10 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
|
||||
keys
|
||||
}
|
||||
|
||||
pub fn test_with_vectors<
|
||||
R: RngCore + CryptoRng,
|
||||
C: Curve,
|
||||
H: Hram<C>
|
||||
>(rng: &mut R, vectors: Vectors) {
|
||||
pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
||||
rng: &mut R,
|
||||
vectors: Vectors,
|
||||
) {
|
||||
// Do basic tests before trying the vectors
|
||||
test_curve::<_, C>(&mut *rng);
|
||||
test_schnorr::<_, C>(rng);
|
||||
@@ -87,54 +87,59 @@ pub fn test_with_vectors<
|
||||
AlgorithmMachine::new(
|
||||
Schnorr::<C, H>::new(),
|
||||
Arc::new(keys[i].clone()),
|
||||
vectors.included.clone()
|
||||
).unwrap()
|
||||
vectors.included.clone(),
|
||||
)
|
||||
.unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut commitments = HashMap::new();
|
||||
let mut c = 0;
|
||||
let mut machines = machines.drain(..).map(|(i, machine)| {
|
||||
let nonces = [
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][0]).unwrap())).unwrap(),
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][1]).unwrap())).unwrap()
|
||||
];
|
||||
c += 1;
|
||||
let these_commitments = vec![[C::GENERATOR * nonces[0], C::GENERATOR * nonces[1]]];
|
||||
let machine = machine.unsafe_override_preprocess(
|
||||
PreprocessPackage {
|
||||
let mut machines = machines
|
||||
.drain(..)
|
||||
.map(|(i, machine)| {
|
||||
let nonces = [
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][0]).unwrap())).unwrap(),
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][1]).unwrap())).unwrap(),
|
||||
];
|
||||
c += 1;
|
||||
let these_commitments = vec![[C::GENERATOR * nonces[0], C::GENERATOR * nonces[1]]];
|
||||
let machine = machine.unsafe_override_preprocess(PreprocessPackage {
|
||||
nonces: vec![nonces],
|
||||
commitments: vec![these_commitments.clone()],
|
||||
addendum: vec![]
|
||||
}
|
||||
);
|
||||
addendum: vec![],
|
||||
});
|
||||
|
||||
commitments.insert(
|
||||
i,
|
||||
Cursor::new(
|
||||
[
|
||||
these_commitments[0][0].to_bytes().as_ref(),
|
||||
these_commitments[0][1].to_bytes().as_ref()
|
||||
].concat().to_vec()
|
||||
)
|
||||
);
|
||||
(i, machine)
|
||||
}).collect::<Vec<_>>();
|
||||
commitments.insert(
|
||||
i,
|
||||
Cursor::new(
|
||||
[
|
||||
these_commitments[0][0].to_bytes().as_ref(),
|
||||
these_commitments[0][1].to_bytes().as_ref(),
|
||||
]
|
||||
.concat()
|
||||
.to_vec(),
|
||||
),
|
||||
);
|
||||
(i, machine)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut shares = HashMap::new();
|
||||
c = 0;
|
||||
let mut machines = machines.drain(..).map(|(i, machine)| {
|
||||
let (machine, share) = machine.sign(
|
||||
clone_without(&commitments, &i),
|
||||
&hex::decode(vectors.msg).unwrap()
|
||||
).unwrap();
|
||||
let mut machines = machines
|
||||
.drain(..)
|
||||
.map(|(i, machine)| {
|
||||
let (machine, share) =
|
||||
machine.sign(clone_without(&commitments, &i), &hex::decode(vectors.msg).unwrap()).unwrap();
|
||||
|
||||
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
|
||||
c += 1;
|
||||
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
|
||||
c += 1;
|
||||
|
||||
shares.insert(i, Cursor::new(share));
|
||||
(i, machine)
|
||||
}).collect::<HashMap<_, _>>();
|
||||
shares.insert(i, Cursor::new(share));
|
||||
(i, machine)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for (i, machine) in machines.drain() {
|
||||
let sig = machine.complete(clone_without(&shares, &i)).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user