Add dealer key generation crate

This commit is contained in:
Luke Parker
2025-08-18 02:13:12 -04:00
parent cfce2b26e2
commit b6edc94bcd
13 changed files with 170 additions and 53 deletions

View File

@@ -41,6 +41,7 @@ schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5
dkg = { path = "../dkg", version = "0.6", default-features = false, features = ["std"] }
dkg-recovery = { path = "../dkg/recovery", default-features = false, features = ["std"], optional = true }
dkg-dealer = { path = "../dkg/dealer", default-features = false, features = ["std"], optional = true }
[dev-dependencies]
hex = "0.4"
@@ -48,6 +49,7 @@ serde_json = { version = "1", default-features = false, features = ["std"] }
dkg = { path = "../dkg", default-features = false, features = ["std"] }
dkg-recovery = { path = "../dkg/recovery", default-features = false, features = ["std"] }
dkg-dealer = { path = "../dkg/dealer", default-features = false, features = ["std"] }
[features]
ed25519 = ["dalek-ff-group", "ciphersuite/ed25519"]
@@ -58,4 +60,4 @@ p256 = ["ciphersuite/p256"]
ed448 = ["minimal-ed448", "ciphersuite/ed448"]
tests = ["hex", "rand_core/getrandom", "dkg-recovery"]
tests = ["hex", "rand_core/getrandom", "dkg-dealer" ,"dkg-recovery"]

View File

@@ -12,6 +12,10 @@ This library offers ciphersuites compatible with the
[IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version
15 is supported.
A variety of testing utilities are provided under the `tests` feature. These
are provided with no guarantees and may have completely arbitrary behavior,
including panicking for completely well-reasoned input.
This library was
[audited by Cypher Stack in March 2023](https://github.com/serai-dex/serai/raw/e1bb2c191b7123fd260d008e31656d090d559d21/audits/Cypher%20Stack%20crypto%20March%202023/Audit.pdf),
culminating in commit

View File

@@ -1,18 +1,12 @@
use core::ops::Deref;
use std::collections::HashMap;
use zeroize::{Zeroize, Zeroizing};
use rand_core::{RngCore, CryptoRng};
use ciphersuite::{
group::ff::{Field, PrimeField},
Ciphersuite,
};
use dkg::Interpolation;
use ciphersuite::Ciphersuite;
pub use dkg_recovery::recover_key;
use crate::{
Curve, Participant, ThresholdParams, ThresholdKeys, FrostError,
Curve, Participant, ThresholdKeys, FrostError,
algorithm::{Algorithm, Hram, IetfSchnorr},
sign::{Writable, PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine},
};
@@ -37,49 +31,11 @@ pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1;
pub fn key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
rng: &mut R,
) -> HashMap<Participant, ThresholdKeys<C>> {
let coefficients: [_; THRESHOLD as usize] =
core::array::from_fn(|_| Zeroizing::new(C::F::random(&mut *rng)));
fn polynomial<F: PrimeField + Zeroize>(
coefficients: &[Zeroizing<F>],
l: Participant,
) -> Zeroizing<F> {
let l = F::from(u64::from(u16::from(l)));
// This should never be reached since Participant is explicitly non-zero
assert!(l != F::ZERO, "zero participant passed to polynomial");
let mut share = Zeroizing::new(F::ZERO);
for (idx, coefficient) in coefficients.iter().rev().enumerate() {
*share += coefficient.deref();
if idx != (coefficients.len() - 1) {
*share *= l;
}
}
share
}
let group_key = C::generator() * *coefficients[0];
let mut secret_shares = HashMap::with_capacity(PARTICIPANTS as usize);
let mut verification_shares = HashMap::with_capacity(PARTICIPANTS as usize);
for i in 1 ..= PARTICIPANTS {
let i = Participant::new(i).unwrap();
let secret_share = polynomial(&coefficients, i);
secret_shares.insert(i, secret_share.clone());
verification_shares.insert(i, C::generator() * *secret_share);
}
let mut res = HashMap::with_capacity(PARTICIPANTS as usize);
for i in 1 ..= PARTICIPANTS {
let i = Participant::new(i).unwrap();
let keys = ThresholdKeys::new(
ThresholdParams::new(THRESHOLD, PARTICIPANTS, i).unwrap(),
Interpolation::Lagrange,
secret_shares.remove(&i).unwrap(),
verification_shares.clone(),
)
.unwrap();
assert_eq!(keys.group_key(), group_key);
res.insert(i, keys);
}
let res = dkg_dealer::key_gen::<R, C>(rng, THRESHOLD, PARTICIPANTS).unwrap();
assert_eq!(
C::generator() * *recover_key(&res.values().cloned().collect::<Vec<_>>()).unwrap(),
res.values().next().unwrap().group_key()
);
res
}