From 885d8163094e4a36742c10c74b92e977e76a64cc Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 13 Aug 2022 05:07:07 -0400 Subject: [PATCH] Use a non-constant generator in FROST --- crypto/frost/src/algorithm.rs | 2 +- crypto/frost/src/curve/dalek.rs | 4 +++- crypto/frost/src/curve/kp256.rs | 4 +++- crypto/frost/src/curve/mod.rs | 2 +- crypto/frost/src/key_gen.rs | 8 ++++---- crypto/frost/src/lib.rs | 4 ++-- crypto/frost/src/schnorr.rs | 6 +++--- crypto/frost/src/sign.rs | 2 +- crypto/frost/src/tests/curve.rs | 2 +- crypto/frost/src/tests/mod.rs | 2 +- crypto/frost/src/tests/schnorr.rs | 10 +++++----- crypto/frost/src/tests/vectors.rs | 7 ++++--- 12 files changed, 29 insertions(+), 24 deletions(-) diff --git a/crypto/frost/src/algorithm.rs b/crypto/frost/src/algorithm.rs index 8641ef4a..39f558f6 100644 --- a/crypto/frost/src/algorithm.rs +++ b/crypto/frost/src/algorithm.rs @@ -119,7 +119,7 @@ impl> Algorithm for Schnorr { } fn nonces(&self) -> Vec> { - vec![vec![C::GENERATOR]] + vec![vec![C::generator()]] } fn preprocess_addendum( diff --git a/crypto/frost/src/curve/dalek.rs b/crypto/frost/src/curve/dalek.rs index 8968cbd9..6e329aa9 100644 --- a/crypto/frost/src/curve/dalek.rs +++ b/crypto/frost/src/curve/dalek.rs @@ -28,7 +28,9 @@ macro_rules! dalek_curve { type G = $Point; const ID: &'static [u8] = $ID; - const GENERATOR: Self::G = $POINT; + fn generator() -> Self::G { + $POINT + } fn hash_msg(msg: &[u8]) -> Vec { Sha512::new() diff --git a/crypto/frost/src/curve/kp256.rs b/crypto/frost/src/curve/kp256.rs index a26fc334..41d1e35c 100644 --- a/crypto/frost/src/curve/kp256.rs +++ b/crypto/frost/src/curve/kp256.rs @@ -31,7 +31,9 @@ macro_rules! kp_curve { type G = $lib::ProjectivePoint; const ID: &'static [u8] = $ID; - const GENERATOR: Self::G = $lib::ProjectivePoint::GENERATOR; + fn generator() -> Self::G { + $lib::ProjectivePoint::GENERATOR + } fn hash_msg(msg: &[u8]) -> Vec { (&Sha256::new().chain($CONTEXT).chain(b"digest").chain(msg).finalize()).to_vec() diff --git a/crypto/frost/src/curve/mod.rs b/crypto/frost/src/curve/mod.rs index 0ba0ac6a..99351963 100644 --- a/crypto/frost/src/curve/mod.rs +++ b/crypto/frost/src/curve/mod.rs @@ -53,7 +53,7 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize { /// Generator for the group // While group does provide this in its API, privacy coins may want to use a custom basepoint - const GENERATOR: Self::G; + fn generator() -> Self::G; /// Hash the message for the binding factor. H3 from the IETF draft // This doesn't actually need to be part of Curve as it does nothing with the curve diff --git a/crypto/frost/src/key_gen.rs b/crypto/frost/src/key_gen.rs index c56a5d42..802e8961 100644 --- a/crypto/frost/src/key_gen.rs +++ b/crypto/frost/src/key_gen.rs @@ -50,7 +50,7 @@ fn generate_key_r1( // Step 1: Generate t random values to form a polynomial with coefficients.push(C::F::random(&mut *rng)); // Step 3: Generate public commitments - commitments.push(C::GENERATOR * coefficients[i]); + commitments.push(C::generator() * coefficients[i]); // Serialize them for publication serialized.extend(commitments[i].to_bytes().as_ref()); } @@ -65,7 +65,7 @@ fn generate_key_r1( // 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::(context, params.i(), (C::GENERATOR * r).to_bytes().as_ref(), &serialized), + challenge::(context, params.i(), (C::generator() * r).to_bytes().as_ref(), &serialized), ) .serialize(), ); @@ -224,7 +224,7 @@ fn complete_r2( // ensure that malleability isn't present is to use this n * t algorithm, which runs // per sender and not as an aggregate of all senders, which also enables blame let mut values = exponential(params.i, &commitments[l]); - values.push((-*share, C::GENERATOR)); + values.push((-*share, C::generator())); share.zeroize(); batch.queue(rng, *l, values); @@ -246,7 +246,7 @@ fn complete_r2( verification_shares.insert(i, multiexp_vartime(&exponential(i, &stripes))); } // Removing this check would enable optimizing the above from t + (n * t) to t + ((n - 1) * t) - debug_assert_eq!(C::GENERATOR * secret_share, verification_shares[¶ms.i()]); + debug_assert_eq!(C::generator() * secret_share, verification_shares[¶ms.i()]); Ok(FrostCore { params, secret_share, group_key: stripes[0], verification_shares }) } diff --git a/crypto/frost/src/lib.rs b/crypto/frost/src/lib.rs index bb1a16b0..57a567ca 100644 --- a/crypto/frost/src/lib.rs +++ b/crypto/frost/src/lib.rs @@ -330,7 +330,7 @@ impl FrostKeys { /// Returns the group key with any offset applied pub fn group_key(&self) -> C::G { - self.core.group_key + (C::GENERATOR * self.offset.unwrap_or_else(C::F::zero)) + self.core.group_key + (C::generator() * self.offset.unwrap_or_else(C::F::zero)) } /// Returns all participants' verification shares without any offsetting @@ -354,7 +354,7 @@ impl FrostKeys { let offset_share = self.offset.unwrap_or_else(C::F::zero) * C::F::from(included.len().try_into().unwrap()).invert().unwrap(); - let offset_verification_share = C::GENERATOR * offset_share; + let offset_verification_share = C::generator() * offset_share; Ok(FrostView { group_key: self.group_key(), diff --git a/crypto/frost/src/schnorr.rs b/crypto/frost/src/schnorr.rs index 2174a062..b47b4370 100644 --- a/crypto/frost/src/schnorr.rs +++ b/crypto/frost/src/schnorr.rs @@ -32,7 +32,7 @@ pub(crate) fn sign( mut nonce: C::F, challenge: C::F, ) -> SchnorrSignature { - let res = SchnorrSignature { R: C::GENERATOR * nonce, s: nonce + (private_key * challenge) }; + let res = SchnorrSignature { R: C::generator() * nonce, s: nonce + (private_key * challenge) }; private_key.zeroize(); nonce.zeroize(); res @@ -44,14 +44,14 @@ pub(crate) fn verify( challenge: C::F, signature: &SchnorrSignature, ) -> bool { - (C::GENERATOR * signature.s) == (signature.R + (public_key * challenge)) + (C::generator() * signature.s) == (signature.R + (public_key * challenge)) } pub(crate) fn batch_verify( rng: &mut R, triplets: &[(u16, C::G, C::F, SchnorrSignature)], ) -> Result<(), u16> { - let mut values = [(C::F::one(), C::GENERATOR); 3]; + let mut values = [(C::F::one(), C::generator()); 3]; let mut batch = BatchVerifier::new(triplets.len()); for triple in triplets { // s = r + ca diff --git a/crypto/frost/src/sign.rs b/crypto/frost/src/sign.rs index 37744efe..aff1e438 100644 --- a/crypto/frost/src/sign.rs +++ b/crypto/frost/src/sign.rs @@ -267,7 +267,7 @@ fn sign_with_share>( // While further code edits would still be required for such a model (having the offset // communicated as a point along with only a single party applying the offset), this means it // wouldn't require a transcript change as well - rho_transcript.append_message(b"offset", (C::GENERATOR * offset).to_bytes().as_ref()); + rho_transcript.append_message(b"offset", (C::generator() * offset).to_bytes().as_ref()); } // Generate the per-signer binding factors diff --git a/crypto/frost/src/tests/curve.rs b/crypto/frost/src/tests/curve.rs index ed6a37d1..c57b0568 100644 --- a/crypto/frost/src/tests/curve.rs +++ b/crypto/frost/src/tests/curve.rs @@ -30,7 +30,7 @@ pub fn test_curve(rng: &mut R) { let mut sum = C::G::identity(); for _ in 0 .. 10 { for _ in 0 .. 100 { - pairs.push((C::F::random(&mut *rng), C::GENERATOR * C::F::random(&mut *rng))); + pairs.push((C::F::random(&mut *rng), C::generator() * C::F::random(&mut *rng))); sum += pairs[pairs.len() - 1].1 * pairs[pairs.len() - 1].0; } assert_eq!(multiexp::multiexp(&pairs), sum); diff --git a/crypto/frost/src/tests/mod.rs b/crypto/frost/src/tests/mod.rs index b82af65c..fcbc2ccf 100644 --- a/crypto/frost/src/tests/mod.rs +++ b/crypto/frost/src/tests/mod.rs @@ -99,7 +99,7 @@ pub fn recover(keys: &HashMap>) -> C::F { let group_private = keys.iter().fold(C::F::zero(), |accum, (i, keys)| { accum + (keys.secret_share() * lagrange::(*i, &included)) }); - assert_eq!(C::GENERATOR * group_private, first.group_key(), "failed to recover keys"); + assert_eq!(C::generator() * group_private, first.group_key(), "failed to recover keys"); group_private } diff --git a/crypto/frost/src/tests/schnorr.rs b/crypto/frost/src/tests/schnorr.rs index 4767621a..460261a5 100644 --- a/crypto/frost/src/tests/schnorr.rs +++ b/crypto/frost/src/tests/schnorr.rs @@ -16,7 +16,7 @@ pub(crate) fn core_sign(rng: &mut R) { let nonce = C::F::random(&mut *rng); let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM assert!(schnorr::verify::( - C::GENERATOR * private_key, + C::generator() * private_key, challenge, &schnorr::sign(private_key, nonce, challenge) )); @@ -27,9 +27,9 @@ pub(crate) fn core_sign(rng: &mut R) { // random pub(crate) fn core_verify(rng: &mut R) { assert!(!schnorr::verify::( - C::GENERATOR * C::F::random(&mut *rng), + C::generator() * C::F::random(&mut *rng), C::F::random(rng), - &SchnorrSignature { R: C::GENERATOR * C::F::zero(), s: C::F::zero() } + &SchnorrSignature { R: C::identity(), s: C::F::zero() } )); } @@ -46,7 +46,7 @@ pub(crate) fn core_batch_verify(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])) + .map(|i| (u16::try_from(i + 1).unwrap(), C::generator() * keys[i], challenges[i], sigs[i])) .collect::>(); schnorr::batch_verify(rng, &triplets).unwrap(); @@ -111,7 +111,7 @@ fn sign_with_offset(rng: &mut R) { for i in 1 ..= u16::try_from(keys.len()).unwrap() { keys.insert(i, keys[&i].offset(offset)); } - let offset_key = group_key + (C::GENERATOR * offset); + let offset_key = group_key + (C::generator() * offset); sign_core(rng, offset_key, &keys); } diff --git a/crypto/frost/src/tests/vectors.rs b/crypto/frost/src/tests/vectors.rs index 0c792a26..d286ec76 100644 --- a/crypto/frost/src/tests/vectors.rs +++ b/crypto/frost/src/tests/vectors.rs @@ -32,7 +32,7 @@ fn vectors_to_multisig_keys(vectors: &Vectors) -> HashMap>(); - let verification_shares = shares.iter().map(|secret| C::GENERATOR * secret).collect::>(); + let verification_shares = shares.iter().map(|secret| C::generator() * secret).collect::>(); let mut keys = HashMap::new(); for i in 1 ..= u16::try_from(shares.len()).unwrap() { @@ -71,7 +71,8 @@ pub fn test_with_vectors>( let keys = vectors_to_multisig_keys::(&vectors); let group_key = C::read_G(&mut Cursor::new(hex::decode(vectors.group_key).unwrap())).unwrap(); assert_eq!( - C::GENERATOR * C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap(), + C::generator() * + C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap(), group_key ); assert_eq!( @@ -102,7 +103,7 @@ pub fn test_with_vectors>( 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 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()],