mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-03 17:40:34 +00:00
Use a non-constant generator in FROST
This commit is contained in:
parent
6f776ff004
commit
885d816309
12 changed files with 29 additions and 24 deletions
|
@ -119,7 +119,7 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
|||
}
|
||||
|
||||
fn nonces(&self) -> Vec<Vec<C::G>> {
|
||||
vec![vec![C::GENERATOR]]
|
||||
vec![vec![C::generator()]]
|
||||
}
|
||||
|
||||
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
||||
|
|
|
@ -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<u8> {
|
||||
Sha512::new()
|
||||
|
|
|
@ -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<u8> {
|
||||
(&Sha256::new().chain($CONTEXT).chain(b"digest").chain(msg).finalize()).to_vec()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,7 +50,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
|
|||
// 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<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),
|
||||
challenge::<C>(context, params.i(), (C::generator() * r).to_bytes().as_ref(), &serialized),
|
||||
)
|
||||
.serialize(),
|
||||
);
|
||||
|
@ -224,7 +224,7 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
|||
// 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<Re: Read, R: RngCore + CryptoRng, C: Curve>(
|
|||
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 })
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ impl<C: Curve> FrostKeys<C> {
|
|||
|
||||
/// 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<C: Curve> FrostKeys<C> {
|
|||
|
||||
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(),
|
||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) fn sign<C: Curve>(
|
|||
mut nonce: C::F,
|
||||
challenge: C::F,
|
||||
) -> SchnorrSignature<C> {
|
||||
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<C: Curve>(
|
|||
challenge: C::F,
|
||||
signature: &SchnorrSignature<C>,
|
||||
) -> bool {
|
||||
(C::GENERATOR * signature.s) == (signature.R + (public_key * challenge))
|
||||
(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>)],
|
||||
) -> 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
|
||||
|
|
|
@ -267,7 +267,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
|||
// 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
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn test_curve<R: RngCore + CryptoRng, C: 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);
|
||||
|
|
|
@ -99,7 +99,7 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
|
|||
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");
|
||||
assert_eq!(C::generator() * group_private, first.group_key(), "failed to recover keys");
|
||||
group_private
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(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>(
|
||||
C::GENERATOR * private_key,
|
||||
C::generator() * private_key,
|
||||
challenge,
|
||||
&schnorr::sign(private_key, nonce, challenge)
|
||||
));
|
||||
|
@ -27,9 +27,9 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
|
|||
// 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::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<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]))
|
||||
.map(|i| (u16::try_from(i + 1).unwrap(), C::generator() * keys[i], challenges[i], sigs[i]))
|
||||
.collect::<Vec<_>>();
|
||||
schnorr::batch_verify(rng, &triplets).unwrap();
|
||||
|
||||
|
@ -111,7 +111,7 @@ fn sign_with_offset<R: RngCore + CryptoRng, C: Curve>(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);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
|
|||
.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 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() {
|
||||
|
@ -71,7 +71,8 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
|||
let keys = vectors_to_multisig_keys::<C>(&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<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
|||
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()],
|
||||
|
|
Loading…
Reference in a new issue