diff --git a/consensus/src/simplex/scheme/bls12381_threshold/vrf.rs b/consensus/src/simplex/scheme/bls12381_threshold/vrf.rs index c775876cafb..c71ba41afd8 100644 --- a/consensus/src/simplex/scheme/bls12381_threshold/vrf.rs +++ b/consensus/src/simplex/scheme/bls12381_threshold/vrf.rs @@ -883,7 +883,7 @@ mod tests { use commonware_codec::{Decode, Encode}; use commonware_cryptography::{ bls12381::{ - dkg::{self, deal_anonymous}, + dkg::feldman_desmedt as dkg, primitives::{ group::Scalar, ops::threshold, @@ -952,7 +952,7 @@ mod tests { let mut rng = test_rng(); let participants = ed25519_participants(&mut rng, 5); let (polynomial, shares) = - deal_anonymous::(&mut rng, Default::default(), NZU32!(4)); + dkg::deal_anonymous::(&mut rng, Default::default(), NZU32!(4)); Scheme::::signer( NAMESPACE, participants.keys().clone(), @@ -976,7 +976,8 @@ mod tests { fn verifier_polynomial_threshold_must_equal_quorum() { let mut rng = test_rng(); let participants = ed25519_participants(&mut rng, 5); - let (polynomial, _) = deal_anonymous::(&mut rng, Default::default(), NZU32!(4)); + let (polynomial, _) = + dkg::deal_anonymous::(&mut rng, Default::default(), NZU32!(4)); Scheme::::verifier(NAMESPACE, participants.keys().clone(), polynomial); } diff --git a/cryptography/conformance.toml b/cryptography/conformance.toml index a8891b609c1..e7c2b7143dd 100644 --- a/cryptography/conformance.toml +++ b/cryptography/conformance.toml @@ -18,35 +18,35 @@ hash = "ad245f64a57c96036599647eaf509937173e9de01503a9e6494f29571191ade1" n_cases = 65536 hash = "ba2d888e6d1050e6a361aa79430c1bb03d90eb8e74b9715b1d7d01c35a495e1d" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "97c266fb7821326e6333be0859025c774220c8d010e488d2fd13a743e4135f64" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "ef8d69a3cbafc5e3f8f98755337acacc6609e92d3fdee0e4576481190cb421b4" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance"] n_cases = 65536 hash = "2d443ed310b383cab74abec888d0637ab81435779e274ed7be84adc7b10e2f86" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "0a15ca78d654be68bb78cf58cfd1da568f8f1585878f081735939f02da161b22" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "1a05e4e910dd186bd81189d79eaf1b4c211012d07f534ddaa38ab9705d80fa62" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "b31f32f62da530fb4861e8a46e5068e0c36ed1b509ee5bc758b6ca90a2568ad7" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "0cbb8c8644dffe0be78d1307fb5034dd804921d66799c1aaec3d335b44e9616c" -["commonware_cryptography::bls12381::dkg::test::conformance::CodecConformance>"] +["commonware_cryptography::bls12381::dkg::feldman_desmedt::test::conformance::CodecConformance>"] n_cases = 65536 hash = "fca94fb3b0df54a6a34edfbb8aeef28490262daf97870e12f869aee6cf7f7e67" diff --git a/cryptography/fuzz/Cargo.toml b/cryptography/fuzz/Cargo.toml index 07b75058b19..01130c340ac 100644 --- a/cryptography/fuzz/Cargo.toml +++ b/cryptography/fuzz/Cargo.toml @@ -133,15 +133,15 @@ doc = false bench = false [[bin]] -name = "bls12381_dkg" -path = "fuzz_targets/bls12381_dkg.rs" +name = "bls12381_dkg_feldman_desmedt" +path = "fuzz_targets/bls12381_dkg_feldman_desmedt.rs" test = false doc = false bench = false [[bin]] -name = "bls12381_golden_dkg" -path = "fuzz_targets/bls12381_golden_dkg.rs" +name = "bls12381_dkg_golden" +path = "fuzz_targets/bls12381_dkg_golden.rs" test = false doc = false bench = false diff --git a/cryptography/fuzz/fuzz_targets/bls12381_dkg.rs b/cryptography/fuzz/fuzz_targets/bls12381_dkg_feldman_desmedt.rs similarity index 94% rename from cryptography/fuzz/fuzz_targets/bls12381_dkg.rs rename to cryptography/fuzz/fuzz_targets/bls12381_dkg_feldman_desmedt.rs index 094ff6fa649..59f169f10d6 100644 --- a/cryptography/fuzz/fuzz_targets/bls12381_dkg.rs +++ b/cryptography/fuzz/fuzz_targets/bls12381_dkg_feldman_desmedt.rs @@ -2,7 +2,7 @@ use arbitrary::Arbitrary; use commonware_cryptography::bls12381::{ - dkg::FuzzPlan, + dkg::feldman_desmedt::FuzzPlan, primitives::variant::{MinPk, MinSig}, }; use libfuzzer_sys::fuzz_target; diff --git a/cryptography/fuzz/fuzz_targets/bls12381_golden_dkg.rs b/cryptography/fuzz/fuzz_targets/bls12381_dkg_golden.rs similarity index 90% rename from cryptography/fuzz/fuzz_targets/bls12381_golden_dkg.rs rename to cryptography/fuzz/fuzz_targets/bls12381_dkg_golden.rs index bcbbd3ee6cb..b2324aea0df 100644 --- a/cryptography/fuzz/fuzz_targets/bls12381_golden_dkg.rs +++ b/cryptography/fuzz/fuzz_targets/bls12381_dkg_golden.rs @@ -1,7 +1,7 @@ #![no_main] use arbitrary::Arbitrary; -use commonware_cryptography::bls12381::golden_dkg::{FuzzPlan, Setup}; +use commonware_cryptography::bls12381::dkg::golden::{FuzzPlan, Setup}; use commonware_parallel::Sequential; use libfuzzer_sys::fuzz_target; use std::{num::NonZeroU32, sync::LazyLock}; diff --git a/cryptography/src/bls12381/benches/bench.rs b/cryptography/src/bls12381/benches/bench.rs index e8cc5c9d232..f0d07e69a0c 100644 --- a/cryptography/src/bls12381/benches/bench.rs +++ b/cryptography/src/bls12381/benches/bench.rs @@ -8,7 +8,6 @@ mod combine_public_keys; mod combine_signatures; mod dkg; mod evaluate_point; -mod golden_dkg; mod hash_to_curve; mod msm; mod scheme_batch_verify_same_message; @@ -24,8 +23,8 @@ mod tle_encrypt; criterion_main!( batch_to_affine::benches, - dkg::benches, - golden_dkg::benches, + dkg::golden::benches, + dkg::feldman_desmedt::benches, hash_to_curve::benches, threshold_recover::benches, combine_public_keys::benches, diff --git a/cryptography/src/bls12381/benches/dkg.rs b/cryptography/src/bls12381/benches/dkg.rs index 0d43a91c81a..be97491f7ca 100644 --- a/cryptography/src/bls12381/benches/dkg.rs +++ b/cryptography/src/bls12381/benches/dkg.rs @@ -1,182 +1,2 @@ -use commonware_cryptography::{ - bls12381::{ - dkg::{deal, Dealer, Info, Logs, Player}, - primitives::variant::MinSig, - }, - ed25519::{Batch, PrivateKey, PublicKey}, - Signer as _, -}; -use commonware_math::algebra::Random; -use commonware_parallel::{Rayon, Sequential}; -use commonware_utils::{ordered::Set, Faults, N3f1, NZUsize, TryCollect}; -use criterion::{criterion_group, BatchSize, Criterion}; -use rand::{rngs::StdRng, SeedableRng}; -use rand_core::CryptoRngCore; -use std::{collections::BTreeMap, hint::black_box}; - -type V = MinSig; - -struct Bench { - info: Info, - me: PrivateKey, - logs: Logs, -} - -impl Bench { - fn new(mut rng: impl CryptoRngCore, reshare: bool, n: u32) -> Self { - let private_keys = (0..n) - .map(|_| PrivateKey::random(&mut rng)) - .collect::>(); - let me = private_keys.first().unwrap().clone(); - let me_pk = me.public_key(); - let dealers = private_keys - .iter() - .map(|sk| sk.public_key()) - .try_collect::>() - .unwrap(); - - let (output, shares) = if reshare { - let (o, s) = - deal::(&mut rng, Default::default(), dealers.clone()).unwrap(); - (Some(o), Some(s)) - } else { - (None, None) - }; - let players = dealers.clone(); - let info = Info::new::( - b"_COMMONWARE_CRYPTOGRAPHY_BLS12381_DKG_BENCH", - 0, - output, - Default::default(), - dealers, - players, - ) - .unwrap(); - - // Create player state for every participant - let mut player_states = private_keys - .iter() - .filter_map(|sk| { - let pk = sk.public_key(); - if pk == me_pk { - return None; - } - Some(( - pk, - Player::::new(info.clone(), sk.clone()).unwrap(), - )) - }) - .collect::>(); - - let mut logs = Logs::::new(info.clone()); - for sk in private_keys { - let pk = sk.public_key(); - let (mut dealer, pub_msg, priv_msgs) = Dealer::start::( - &mut rng, - info.clone(), - sk, - shares - .as_ref() - .and_then(|shares| shares.get_value(&pk).cloned()), - ) - .unwrap(); - for (target_pk, priv_msg) in priv_msgs { - // The only missing player should be ourselves. - if let Some(player) = player_states.get_mut(&target_pk) { - if let Some(ack) = - player.dealer_message::(pk.clone(), pub_msg.clone(), priv_msg) - { - dealer.receive_player_ack(target_pk.clone(), ack).unwrap(); - } - } - } - logs.record(pk, dealer.finalize::().check(&info).unwrap().1); - } - - Self { info, me, logs } - } - - fn pre_finalize(&self) -> (Player, Logs) { - ( - Player::::new(self.info.clone(), self.me.clone()).unwrap(), - self.logs.clone(), - ) - } -} - -// Configure contributors based on context -cfg_if::cfg_if! { - if #[cfg(full_bench)] { - const CONTRIBUTORS: &[u32] = &[5, 10, 20, 50, 100, 250, 500]; - const CONCURRENCY: &[usize] = &[1, 4, 8]; - } else { - const CONTRIBUTORS: &[u32] = &[5, 10, 20, 50]; - const CONCURRENCY: &[usize] = &[1]; - } -} - -fn bench_dkg(c: &mut Criterion, reshare: bool) { - let suffix = if reshare { - "_reshare_recovery" - } else { - "_recovery" - }; - let mut rng = StdRng::seed_from_u64(0); - for &n in CONTRIBUTORS { - let t = N3f1::quorum(n); - let bench = Bench::new(&mut rng, reshare, n); - for &concurrency in CONCURRENCY { - let strategy = Rayon::new(NZUsize!(concurrency)).unwrap(); - c.bench_function( - &format!( - "{}{}/n={} t={} conc={}", - module_path!(), - suffix, - n, - t, - concurrency, - ), - |b| { - b.iter_batched( - || bench.pre_finalize(), - |(player, logs)| { - let mut finalize_rng = StdRng::seed_from_u64(0); - if concurrency > 1 { - black_box( - player - .finalize::(&mut finalize_rng, logs, &strategy) - .unwrap(), - ); - } else { - black_box( - player - .finalize::( - &mut finalize_rng, - logs, - &Sequential, - ) - .unwrap(), - ); - } - }, - BatchSize::SmallInput, - ); - }, - ); - } - } -} - -fn bench_dkg_recovery(c: &mut Criterion) { - bench_dkg(c, false); -} - -fn bench_dkg_reshare_recovery(c: &mut Criterion) { - bench_dkg(c, true); -} - -criterion_group! { - name = benches; - config = Criterion::default().sample_size(10); - targets = bench_dkg_recovery, bench_dkg_reshare_recovery -} +pub mod feldman_desmedt; +pub mod golden; diff --git a/cryptography/src/bls12381/benches/dkg/feldman_desmedt.rs b/cryptography/src/bls12381/benches/dkg/feldman_desmedt.rs new file mode 100644 index 00000000000..e451ef31e85 --- /dev/null +++ b/cryptography/src/bls12381/benches/dkg/feldman_desmedt.rs @@ -0,0 +1,182 @@ +use commonware_cryptography::{ + bls12381::{ + dkg::feldman_desmedt::{deal, Dealer, Info, Logs, Player}, + primitives::variant::MinSig, + }, + ed25519::{Batch, PrivateKey, PublicKey}, + Signer as _, +}; +use commonware_math::algebra::Random; +use commonware_parallel::{Rayon, Sequential}; +use commonware_utils::{ordered::Set, Faults, N3f1, NZUsize, TryCollect}; +use criterion::{criterion_group, BatchSize, Criterion}; +use rand::{rngs::StdRng, SeedableRng}; +use rand_core::CryptoRngCore; +use std::{collections::BTreeMap, hint::black_box}; + +type V = MinSig; + +struct Bench { + info: Info, + me: PrivateKey, + logs: Logs, +} + +impl Bench { + fn new(mut rng: impl CryptoRngCore, reshare: bool, n: u32) -> Self { + let private_keys = (0..n) + .map(|_| PrivateKey::random(&mut rng)) + .collect::>(); + let me = private_keys.first().unwrap().clone(); + let me_pk = me.public_key(); + let dealers = private_keys + .iter() + .map(|sk| sk.public_key()) + .try_collect::>() + .unwrap(); + + let (output, shares) = if reshare { + let (o, s) = + deal::(&mut rng, Default::default(), dealers.clone()).unwrap(); + (Some(o), Some(s)) + } else { + (None, None) + }; + let players = dealers.clone(); + let info = Info::new::( + b"_COMMONWARE_CRYPTOGRAPHY_BLS12381_DKG_BENCH", + 0, + output, + Default::default(), + dealers, + players, + ) + .unwrap(); + + // Create player state for every participant + let mut player_states = private_keys + .iter() + .filter_map(|sk| { + let pk = sk.public_key(); + if pk == me_pk { + return None; + } + Some(( + pk, + Player::::new(info.clone(), sk.clone()).unwrap(), + )) + }) + .collect::>(); + + let mut logs = Logs::::new(info.clone()); + for sk in private_keys { + let pk = sk.public_key(); + let (mut dealer, pub_msg, priv_msgs) = Dealer::start::( + &mut rng, + info.clone(), + sk, + shares + .as_ref() + .and_then(|shares| shares.get_value(&pk).cloned()), + ) + .unwrap(); + for (target_pk, priv_msg) in priv_msgs { + // The only missing player should be ourselves. + if let Some(player) = player_states.get_mut(&target_pk) { + if let Some(ack) = + player.dealer_message::(pk.clone(), pub_msg.clone(), priv_msg) + { + dealer.receive_player_ack(target_pk.clone(), ack).unwrap(); + } + } + } + logs.record(pk, dealer.finalize::().check(&info).unwrap().1); + } + + Self { info, me, logs } + } + + fn pre_finalize(&self) -> (Player, Logs) { + ( + Player::::new(self.info.clone(), self.me.clone()).unwrap(), + self.logs.clone(), + ) + } +} + +// Configure contributors based on context +cfg_if::cfg_if! { + if #[cfg(full_bench)] { + const CONTRIBUTORS: &[u32] = &[5, 10, 20, 50, 100, 250, 500]; + const CONCURRENCY: &[usize] = &[1, 4, 8]; + } else { + const CONTRIBUTORS: &[u32] = &[5, 10, 20, 50]; + const CONCURRENCY: &[usize] = &[1]; + } +} + +fn bench_dkg(c: &mut Criterion, reshare: bool) { + let suffix = if reshare { + "_reshare_recovery" + } else { + "_recovery" + }; + let mut rng = StdRng::seed_from_u64(0); + for &n in CONTRIBUTORS { + let t = N3f1::quorum(n); + let bench = Bench::new(&mut rng, reshare, n); + for &concurrency in CONCURRENCY { + let strategy = Rayon::new(NZUsize!(concurrency)).unwrap(); + c.bench_function( + &format!( + "{}{}/n={} t={} conc={}", + module_path!(), + suffix, + n, + t, + concurrency, + ), + |b| { + b.iter_batched( + || bench.pre_finalize(), + |(player, logs)| { + let mut finalize_rng = StdRng::seed_from_u64(0); + if concurrency > 1 { + black_box( + player + .finalize::(&mut finalize_rng, logs, &strategy) + .unwrap(), + ); + } else { + black_box( + player + .finalize::( + &mut finalize_rng, + logs, + &Sequential, + ) + .unwrap(), + ); + } + }, + BatchSize::SmallInput, + ); + }, + ); + } + } +} + +fn bench_dkg_recovery(c: &mut Criterion) { + bench_dkg(c, false); +} + +fn bench_dkg_reshare_recovery(c: &mut Criterion) { + bench_dkg(c, true); +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(10); + targets = bench_dkg_recovery, bench_dkg_reshare_recovery +} diff --git a/cryptography/src/bls12381/benches/golden_dkg.rs b/cryptography/src/bls12381/benches/dkg/golden.rs similarity index 85% rename from cryptography/src/bls12381/benches/golden_dkg.rs rename to cryptography/src/bls12381/benches/dkg/golden.rs index 384e82991e8..7c2afbec5b0 100644 --- a/cryptography/src/bls12381/benches/golden_dkg.rs +++ b/cryptography/src/bls12381/benches/dkg/golden.rs @@ -1,5 +1,5 @@ use commonware_codec::EncodeSize as _; -use commonware_cryptography::bls12381::golden_dkg::{ +use commonware_cryptography::bls12381::dkg::golden::{ self, DealerLog, Info, PrivateKey, PublicKey, Setup, SignedDealerLog, }; use commonware_math::algebra::Random; @@ -48,13 +48,13 @@ impl Bench { } fn deal(&self, rng: &mut impl CryptoRngCore) -> SignedDealerLog { - golden_dkg::deal(rng, &SETUP, &self.info, &self.me, None, &Sequential) + golden::deal(rng, &SETUP, &self.info, &self.me, None, &Sequential) .expect("honest deal should succeed") } } /// Time for a dealer to produce a [`SignedDealerLog`] addressed to `n` receivers. -fn bench_golden_dkg_deal(c: &mut Criterion) { +fn bench_deal(c: &mut Criterion) { let mut rng = StdRng::seed_from_u64(0); for &n in RECEIVERS { let bench = Bench::new(&mut rng, n); @@ -69,7 +69,7 @@ fn bench_golden_dkg_deal(c: &mut Criterion) { }, |(info, me, mut rng)| { black_box( - golden_dkg::deal(&mut rng, &SETUP, &info, &me, None, &Sequential).unwrap(), + golden::deal(&mut rng, &SETUP, &info, &me, None, &Sequential).unwrap(), ); }, BatchSize::SmallInput, @@ -82,8 +82,8 @@ fn bench_golden_dkg_deal(c: &mut Criterion) { /// /// Performs the full verification a real receiver does: the signature check /// via `SignedDealerLog::identify`, plus the eVRF batch check and per-dealing -/// linear check via `golden_dkg::observe`. -fn bench_golden_dkg_verify(c: &mut Criterion) { +/// linear check via `golden::observe`. +fn bench_verify(c: &mut Criterion) { let mut rng = StdRng::seed_from_u64(0); for &n in RECEIVERS { let bench = Bench::new(&mut rng, n); @@ -95,9 +95,7 @@ fn bench_golden_dkg_verify(c: &mut Criterion) { let (pk, log) = signed.identify(&info).expect("honest log should identify"); let mut logs = BTreeMap::::new(); logs.insert(pk, log); - black_box( - golden_dkg::observe(&mut rng, &SETUP, &info, logs, &Sequential).unwrap(), - ); + black_box(golden::observe(&mut rng, &SETUP, &info, logs, &Sequential).unwrap()); }, BatchSize::SmallInput, ); @@ -109,7 +107,7 @@ fn bench_golden_dkg_verify(c: &mut Criterion) { /// /// Reported via stdout (no measured timing) in the same style as /// `coding/src/benches/bench_size.rs`. -fn bench_golden_dkg_dealing_size(_c: &mut Criterion) { +fn bench_dealing_size(_c: &mut Criterion) { let mut rng = StdRng::seed_from_u64(0); for &n in RECEIVERS { let bench = Bench::new(&mut rng, n); @@ -127,7 +125,7 @@ criterion_group! { name = benches; config = Criterion::default().sample_size(10); targets = - bench_golden_dkg_deal, - bench_golden_dkg_verify, - bench_golden_dkg_dealing_size, + bench_deal, + bench_verify, + bench_dealing_size, } diff --git a/cryptography/src/bls12381/benches/threshold_batch_verify_same_message.rs b/cryptography/src/bls12381/benches/threshold_batch_verify_same_message.rs index 5e803ad4a3c..7f7cb1a29e6 100644 --- a/cryptography/src/bls12381/benches/threshold_batch_verify_same_message.rs +++ b/cryptography/src/bls12381/benches/threshold_batch_verify_same_message.rs @@ -1,6 +1,6 @@ use commonware_cryptography::{ bls12381::{ - dkg::deal, + dkg::feldman_desmedt::deal, primitives::{self, sharing::Mode, variant::MinSig}, }, ed25519::PrivateKey, diff --git a/cryptography/src/bls12381/benches/threshold_batch_verify_same_message_pre.rs b/cryptography/src/bls12381/benches/threshold_batch_verify_same_message_pre.rs index 565c1bf3458..c918cbd46c7 100644 --- a/cryptography/src/bls12381/benches/threshold_batch_verify_same_message_pre.rs +++ b/cryptography/src/bls12381/benches/threshold_batch_verify_same_message_pre.rs @@ -1,6 +1,6 @@ use commonware_cryptography::{ bls12381::{ - dkg::deal, + dkg::feldman_desmedt::deal, primitives::{self, sharing::Mode, variant::MinSig}, }, ed25519::PrivateKey, diff --git a/cryptography/src/bls12381/benches/threshold_batch_verify_same_signer.rs b/cryptography/src/bls12381/benches/threshold_batch_verify_same_signer.rs index f5ef32e9e1a..a25807e3e26 100644 --- a/cryptography/src/bls12381/benches/threshold_batch_verify_same_signer.rs +++ b/cryptography/src/bls12381/benches/threshold_batch_verify_same_signer.rs @@ -1,6 +1,6 @@ use commonware_cryptography::{ bls12381::{ - dkg::deal, + dkg::feldman_desmedt::deal, primitives::{self, sharing::Mode, variant::MinSig}, }, ed25519::PrivateKey, diff --git a/cryptography/src/bls12381/benches/threshold_recover.rs b/cryptography/src/bls12381/benches/threshold_recover.rs index 9181246612e..2d755f67361 100644 --- a/cryptography/src/bls12381/benches/threshold_recover.rs +++ b/cryptography/src/bls12381/benches/threshold_recover.rs @@ -1,6 +1,6 @@ use commonware_cryptography::{ bls12381::{ - dkg::deal, + dkg::feldman_desmedt::deal, primitives::{self, sharing::Mode, variant::MinSig}, }, ed25519::PrivateKey, diff --git a/cryptography/src/bls12381/certificate/threshold/mocks.rs b/cryptography/src/bls12381/certificate/threshold/mocks.rs index 4367e2c02f3..8cca68c6fc3 100644 --- a/cryptography/src/bls12381/certificate/threshold/mocks.rs +++ b/cryptography/src/bls12381/certificate/threshold/mocks.rs @@ -2,7 +2,7 @@ use crate::{ bls12381::{ - dkg::deal, + dkg::feldman_desmedt::deal, primitives::{group::Share, sharing::Sharing, variant::Variant}, }, certificate::{mocks::Fixture, Scheme}, diff --git a/cryptography/src/bls12381/certificate/threshold/mod.rs b/cryptography/src/bls12381/certificate/threshold/mod.rs index ff8cd0aaea0..e6e8026b827 100644 --- a/cryptography/src/bls12381/certificate/threshold/mod.rs +++ b/cryptography/src/bls12381/certificate/threshold/mod.rs @@ -713,7 +713,7 @@ mod tests { use super::*; use crate::{ bls12381::{ - dkg, + dkg::feldman_desmedt as dkg, primitives::{ ops::threshold::sign_message, variant::{MinPk, MinSig, Variant}, diff --git a/cryptography/src/bls12381/dkg.rs b/cryptography/src/bls12381/dkg/feldman_desmedt.rs similarity index 98% rename from cryptography/src/bls12381/dkg.rs rename to cryptography/src/bls12381/dkg/feldman_desmedt.rs index 584ae769076..b4ee77a462e 100644 --- a/cryptography/src/bls12381/dkg.rs +++ b/cryptography/src/bls12381/dkg/feldman_desmedt.rs @@ -1,10 +1,10 @@ -//! Distributed Key Generation (DKG) and Resharing protocol for the BLS12-381 curve. +//! Feldman/Desmedt Distributed Key Generation (DKG) and Resharing for BLS12-381. //! -//! This module implements an interactive Distributed Key Generation (DKG) and Resharing protocol -//! for the BLS12-381 curve. Unlike other constructions, this construction does not require encrypted -//! shares to be publicly broadcast to complete a DKG/Reshare. Shares, instead, are sent directly -//! between dealers and players over an encrypted channel (which can be instantiated -//! with [commonware-p2p](https://docs.rs/commonware-p2p)). +//! This module implements a Feldman/Desmedt-style DKG and Resharing protocol. Unlike other +//! constructions, this construction does not require encrypted shares to be publicly broadcast to +//! complete a DKG/Reshare. Shares, instead, are sent directly between dealers and players over an +//! encrypted channel (which can be instantiated with +//! [commonware-p2p](https://docs.rs/commonware-p2p)). //! //! The DKG is based on the "Joint-Feldman" construction from "Secure Distributed Key //! Generation for Discrete-Log Based Cryptosystems" (GJKR99) and Resharing is based @@ -157,17 +157,12 @@ //! honest players and another block `B_2` to `f + 1` other honest players. Normally, it would only be possible to create one quorum of `2f + 1` (for `B_2`), //! however, with `h` other shares revealed another quorum of `2f + h` can be formed for `B_1`. //! -//! #### Future Work: Dropping the Synchrony Assumption for `f` Bounded Reveals? +//! #### Dropping the Synchrony Assumption for `f` Bounded Reveals? //! //! It is possible to design a DKG/Resharing scheme that maintains a shared secret where at least `f + 1` honest players //! must participate to recover the shared secret that doesn't require a synchrony assumption (`2f + 1` threshold -//! where at most `f` players are Byzantine). However, known constructions that satisfy this requirement require both -//! broadcasting encrypted dealings publicly and employing Zero-Knowledge Proofs (ZKPs) to attest that encrypted dealings -//! were generated correctly ([Groth21](https://eprint.iacr.org/2021/339), [Kate23](https://eprint.iacr.org/2023/451)). -//! -//! As of January 2025, these constructions are still considered novel (2-3 years in production), require stronger -//! cryptographic assumptions, don't scale to hundreds of participants (unless dealers have powerful hardware), and provide -//! observers the opportunity to brute force decrypt shares (even if honest players are online). +//! where at most `f` players are Byzantine) by combining encryption and ZK Proofs. We have an implementation of one +//! such protocol, [Golden](https://eprint.iacr.org/2025/1924), in [`crate::bls12381::dkg::golden`]. //! //! ## Handling Complaints //! @@ -200,7 +195,7 @@ //! //! ``` //! use commonware_cryptography::bls12381::{ -//! dkg::{Dealer, Info, Logs, Player, SignedDealerLog, observe}, +//! dkg::feldman_desmedt::{Dealer, Info, Logs, Player, SignedDealerLog, observe}, //! primitives::{variant::MinSig, sharing::Mode}, //! }; //! use commonware_cryptography::{ed25519, Signer}; @@ -302,10 +297,9 @@ //! //! For a complete example with resharing, see [commonware-reshare](https://docs.rs/commonware-reshare). -use super::primitives::group::{Private, Share}; use crate::{ bls12381::primitives::{ - group::Scalar, + group::{Private, Scalar, Share}, sharing::{Mode, ModeVersion, Sharing}, variant::Variant, }, diff --git a/cryptography/src/bls12381/golden_dkg/evrf/bandersnatch.rs b/cryptography/src/bls12381/dkg/golden/evrf/bandersnatch.rs similarity index 100% rename from cryptography/src/bls12381/golden_dkg/evrf/bandersnatch.rs rename to cryptography/src/bls12381/dkg/golden/evrf/bandersnatch.rs diff --git a/cryptography/src/bls12381/golden_dkg/evrf/mod.rs b/cryptography/src/bls12381/dkg/golden/evrf/mod.rs similarity index 99% rename from cryptography/src/bls12381/golden_dkg/evrf/mod.rs rename to cryptography/src/bls12381/dkg/golden/evrf/mod.rs index 9ae0b5f4454..7eef8391481 100644 --- a/cryptography/src/bls12381/golden_dkg/evrf/mod.rs +++ b/cryptography/src/bls12381/dkg/golden/evrf/mod.rs @@ -1,10 +1,7 @@ mod bandersnatch; use crate::{ - bls12381::{ - golden_dkg::evrf::bandersnatch::{vrf_batch_checked, vrf_batch_checked_circuit, vrf_recv}, - primitives::group::{Scalar, G1}, - }, + bls12381::primitives::group::{Scalar, G1}, transcript::{Summary, Transcript}, zk::{ bulletproofs::circuit::{self, prove, verify}, @@ -12,7 +9,7 @@ use crate::{ }, Secret, }; -use bandersnatch::{F, G}; +use bandersnatch::{vrf_batch_checked, vrf_batch_checked_circuit, vrf_recv, F, G}; use bytes::{Buf, BufMut, Bytes}; use commonware_codec::{ Encode, EncodeFixed, EncodeSize, Error as CodecError, FixedSize, Read, ReadExt, Write, @@ -786,7 +783,7 @@ mod tests { let msg = Bytes::copy_from_slice(nonce.as_ref()); // The outer transcript both sides agree on. The prover forks it the - // same way `golden_dkg::deal` does, and `check_batch` re-forks it + // same way `golden::deal` does, and `check_batch` re-forks it // internally per sender. let outer_transcript = Transcript::new(b"vrf-batch-checked-test"); diff --git a/cryptography/src/bls12381/golden_dkg.rs b/cryptography/src/bls12381/dkg/golden/mod.rs similarity index 99% rename from cryptography/src/bls12381/golden_dkg.rs rename to cryptography/src/bls12381/dkg/golden/mod.rs index 84afe1e774a..87f1bc1eafe 100644 --- a/cryptography/src/bls12381/golden_dkg.rs +++ b/cryptography/src/bls12381/dkg/golden/mod.rs @@ -1,7 +1,7 @@ //! Non-interactive Distributed Key Generation (DKG) and Resharing for BLS12-381. //! //! This module implements a non-interactive DKG and Resharing protocol for the BLS12-381 -//! curve. Unlike the interactive [`super::dkg`] protocol, this construction requires no +//! curve. Unlike the interactive [`super::feldman_desmedt`] protocol, this construction requires no //! back-and-forth between dealers and players. Each dealer publishes a single message, //! and any observer can verify correctness and compute the public output without private //! key material. @@ -94,7 +94,7 @@ //! # Example //! //! ```rust,ignore -//! use commonware_cryptography::bls12381::golden_dkg::*; +//! use commonware_cryptography::bls12381::dkg::golden::*; //! use std::num::NonZeroU32; //! //! // Build the eVRF [`Setup`] once. This is expensive but only needs to be done @@ -127,13 +127,10 @@ mod evrf; use crate::{ - bls12381::{ - golden_dkg::evrf::{Signature, VrfCommitments}, - primitives::{ - group::{Private, Scalar, Share, SmallScalar, G1}, - sharing::{Mode, ModeVersion, Sharing}, - variant::MinPk, - }, + bls12381::primitives::{ + group::{Private, Scalar, Share, SmallScalar, G1}, + sharing::{Mode, ModeVersion, Sharing}, + variant::MinPk, }, transcript::{Summary, Transcript}, Signer as _, Verifier as _, @@ -150,6 +147,7 @@ use commonware_utils::{ Faults, Participant, TryCollect as _, NZU32, }; pub use evrf::{PrivateKey, PublicKey, Setup}; +use evrf::{Signature, VrfCommitments}; use rand_core::CryptoRngCore; use std::{borrow::Cow, collections::BTreeMap, num::NonZeroU32}; @@ -1317,7 +1315,7 @@ mod test_plan { // // Manually construct a dealing with a wrong-degree poly // evaluated at the correct player scalars. Because - // golden_dkg has no explicit degree check, this dealing + // Golden has no explicit degree check, this dealing // passes Dealing::check() and gets selected -- the test // verifies this by NOT considering shift_degree dealers // as "bad". diff --git a/cryptography/src/bls12381/dkg/mod.rs b/cryptography/src/bls12381/dkg/mod.rs new file mode 100644 index 00000000000..c38882ae906 --- /dev/null +++ b/cryptography/src/bls12381/dkg/mod.rs @@ -0,0 +1,19 @@ +//! Distributed Key Generation (DKG) and Resharing protocols for BLS12-381. +//! +//! This module provides two constructions: +//! +//! - [`feldman_desmedt`]: a synchronous, two-round protocol with direct dealer-player messages, +//! - [`golden`]: an asynchronous, one-round protocol using encryption and zero-knowledge proofs. +//! +//! [`feldman_desmedt`] is simpler and cheaper, but relies on synchrony to bound +//! revealed shares. [`golden`] removes that assumption at higher computational cost. + +pub mod feldman_desmedt; +#[cfg(not(any( + commonware_stability_BETA, + commonware_stability_GAMMA, + commonware_stability_DELTA, + commonware_stability_EPSILON, + commonware_stability_RESERVED +)))] // ALPHA +pub mod golden; diff --git a/cryptography/src/bls12381/mod.rs b/cryptography/src/bls12381/mod.rs index 491f21d3e4f..48cb3d8eae2 100644 --- a/cryptography/src/bls12381/mod.rs +++ b/cryptography/src/bls12381/mod.rs @@ -9,17 +9,6 @@ pub mod certificate; #[cfg(feature = "std")] pub mod dkg; -#[cfg(all( - feature = "std", - not(any( - commonware_stability_BETA, - commonware_stability_GAMMA, - commonware_stability_DELTA, - commonware_stability_EPSILON, - commonware_stability_RESERVED - )) -))] // ALPHA -pub mod golden_dkg; pub mod primitives; mod scheme; pub mod tle; diff --git a/cryptography/src/bls12381/primitives/mod.rs b/cryptography/src/bls12381/primitives/mod.rs index 552933f4390..71e8a3f0f80 100644 --- a/cryptography/src/bls12381/primitives/mod.rs +++ b/cryptography/src/bls12381/primitives/mod.rs @@ -14,8 +14,8 @@ //! //! ```rust //! use commonware_cryptography::bls12381::{ +//! dkg::feldman_desmedt as dkg, //! primitives::{ops::{self, threshold}, variant::MinSig, sharing::Mode}, -//! dkg, //! }; //! use commonware_utils::{NZU32, N3f1}; //! use rand::rngs::OsRng; diff --git a/cryptography/src/bls12381/primitives/ops/threshold.rs b/cryptography/src/bls12381/primitives/ops/threshold.rs index 099686be30f..6c935bac2e7 100644 --- a/cryptography/src/bls12381/primitives/ops/threshold.rs +++ b/cryptography/src/bls12381/primitives/ops/threshold.rs @@ -347,7 +347,7 @@ where mod tests { use super::*; use crate::bls12381::{ - dkg, + dkg::feldman_desmedt as dkg, primitives::{ group::{Private, Scalar, G1_MESSAGE, G2_MESSAGE}, ops::{self, hash_with_namespace}, diff --git a/docs/blogs/commonware-cryptography.html b/docs/blogs/commonware-cryptography.html index 8664c89e7d2..ce4613728c2 100644 --- a/docs/blogs/commonware-cryptography.html +++ b/docs/blogs/commonware-cryptography.html @@ -97,7 +97,7 @@

commonware-cryptography: Unlocking Seeds, Links, and Views

Today, we're excited to share how @commonwarexyz is answering these questions with commonware-cryptography (now in ALPHA).

commonware-cryptography is an open (Apache-2 and MIT) implementation of BLS12-381 Distributed Key Generation (DKG), Resharing, and Threshold Signatures in Rust. Unlike most implementations, our construction does not employ a "board" for share distribution (that requires dealers to broadcast encrypted shares over a public channel). Rather, dealers distribute shares over encrypted connections directly with each player and players broadcast an acknowledgement when they receive a correct share (no share material posted).

-

With an eye towards consensus integration (natively emitting Threshold Signatures during finalization), this interactive DKG/Resharing construction requires 2f + 1 players (of 3f + 1 players where any f are Byzantine) to generate a valid threshold signature. Resharing can be run to introduce/remove contributors and/or proactively on a regular interval to bound the age of any shares. You can read more about this construction here.

+

With an eye towards consensus integration (natively emitting Threshold Signatures during finalization), this interactive DKG/Resharing construction requires 2f + 1 players (of 3f + 1 players where any f are Byzantine) to generate a valid threshold signature. Resharing can be run to introduce/remove contributors and/or proactively on a regular interval to bound the age of any shares. You can read more about this construction here.

So, how does this answer any of a developer's questions?

  • @@ -119,4 +119,4 @@

    commonware-cryptography: Unlocking Seeds, Links, and Views

    - \ No newline at end of file + diff --git a/docs/blogs/golden.html b/docs/blogs/golden.html index 0513409dcb8..2d681dd93fa 100644 --- a/docs/blogs/golden.html +++ b/docs/blogs/golden.html @@ -535,7 +535,7 @@

    A small ZK stack

    Performance

    Here are the current performance numbers we have from our initial implementation. Measured values are taken from - bls12381::golden_dkg::{deal, verify, dealing_size} + bls12381::dkg::golden::{deal, verify, dealing_size} for n \in \{2, 4, 8\}; values for n \in \{16, 32, 64\} are projected linearly (shown in gray) since the underlying cost is diff --git a/docs/blogs/golden.md b/docs/blogs/golden.md index 65752ebfad5..d5d58cae383 100644 --- a/docs/blogs/golden.md +++ b/docs/blogs/golden.md @@ -415,7 +415,7 @@ of a single dealer, which is quite nice. # Performance Here are the current performance numbers we have from our initial implementation. -Measured values are taken from `bls12381::golden_dkg::{deal, verify, dealing_size}` +Measured values are taken from `bls12381::dkg::golden::{deal, verify, dealing_size}` for $n \in \{2, 4, 8\}$; values for $n \in \{16, 32, 64\}$ are projected linearly (shown in gray) since the underlying cost is dominated by $O(n)$ work. diff --git a/docs/blogs/reshare.html b/docs/blogs/reshare.html index 09ef164e630..5d5d0f3fc6a 100644 --- a/docs/blogs/reshare.html +++ b/docs/blogs/reshare.html @@ -126,7 +126,7 @@

    Resharing: Piggybacking on Consensus

    Our new commonware-reshare example - marries the DKG implementation from commonware-cryptography::bls12381::dkg with + marries the DKG implementation from commonware-cryptography::bls12381::dkg::feldman_desmedt with threshold commonware-consensus::simplex's (implicit) replicated log. Validators proactively refresh their key material every epoch, a configurable interval of blocks, and derive new shares for incoming participants.

    @@ -158,7 +158,7 @@

    Generating a Threshold Secret

    The trusted path is great for local testing and CI: the setup tool deterministically samples the group key, splits it into shares, and writes configs for each validator. The DKG ceremony is more complex but should be used for any production deployment (recall whoever has the shared secret can trivially undermine threshold commonware-consensus::simplex). - A bootstrap committee uses the non-threshold dialect of commonware-consensus::simplex (powered by commonware-cryptography::ed25519) to agree on the transcript produced by commonware-cryptography::bls12381::dkg, and the generated shares + A bootstrap committee uses the non-threshold dialect of commonware-consensus::simplex (powered by commonware-cryptography::ed25519) to agree on the transcript produced by commonware-cryptography::bls12381::dkg::feldman_desmedt, and the generated shares are used by the initial participants in the first epoch. From there, the built-in resharing mechanism handles all future key material updates.

    @@ -192,4 +192,4 @@

    Trying It Locally

    - \ No newline at end of file + diff --git a/examples/bridge/src/bin/dealer.rs b/examples/bridge/src/bin/dealer.rs index f8d6d5f1dc3..8bbc7738963 100644 --- a/examples/bridge/src/bin/dealer.rs +++ b/examples/bridge/src/bin/dealer.rs @@ -1,7 +1,7 @@ use clap::{value_parser, Arg, Command}; use commonware_codec::Encode; use commonware_cryptography::{ - bls12381::{dkg::deal_anonymous, primitives::variant::MinSig}, + bls12381::{dkg::feldman_desmedt::deal_anonymous, primitives::variant::MinSig}, ed25519, Signer as _, }; use commonware_formatting::hex; diff --git a/examples/reshare/src/application/scheme.rs b/examples/reshare/src/application/scheme.rs index 733c8954ee5..afef787cb34 100644 --- a/examples/reshare/src/application/scheme.rs +++ b/examples/reshare/src/application/scheme.rs @@ -5,7 +5,7 @@ use crate::orchestrator::EpochTransition; use commonware_consensus::{simplex, types::Epoch}; use commonware_cryptography::{ bls12381::{ - dkg, + dkg::feldman_desmedt as dkg, primitives::variant::{MinSig, Variant}, }, certificate::{self, Scheme}, diff --git a/examples/reshare/src/application/types.rs b/examples/reshare/src/application/types.rs index 99d00dcd4fc..49689a539d2 100644 --- a/examples/reshare/src/application/types.rs +++ b/examples/reshare/src/application/types.rs @@ -6,7 +6,7 @@ use commonware_consensus::{ Block as ConsensusBlock, CertifiableBlock, Heightable, }; use commonware_cryptography::{ - bls12381::{dkg::SignedDealerLog, primitives::variant::Variant}, + bls12381::{dkg::feldman_desmedt::SignedDealerLog, primitives::variant::Variant}, Committable, Digest, Digestible, Hasher, Signer, }; use commonware_runtime::{Buf, BufMut}; diff --git a/examples/reshare/src/dkg/actor.rs b/examples/reshare/src/dkg/actor.rs index b70c6cfc283..e903917b2fd 100644 --- a/examples/reshare/src/dkg/actor.rs +++ b/examples/reshare/src/dkg/actor.rs @@ -13,7 +13,9 @@ use commonware_codec::{Encode, EncodeSize, Error as CodecError, Read, ReadExt, W use commonware_consensus::types::{Epoch, EpochPhase, Epocher, FixedEpocher}; use commonware_cryptography::{ bls12381::{ - dkg::{observe, DealerPrivMsg, DealerPubMsg, Info, Logs, Output, PlayerAck}, + dkg::feldman_desmedt::{ + observe, DealerPrivMsg, DealerPubMsg, Info, Logs, Output, PlayerAck, + }, primitives::{ group::Share, sharing::{Mode, ModeVersion}, @@ -643,7 +645,7 @@ mod tests { use crate::{dkg::ContinueOnUpdate, orchestrator::Message, setup::PeerConfig}; use commonware_actor::Feedback; use commonware_cryptography::{ - bls12381::{dkg::deal, primitives::variant::MinSig}, + bls12381::{dkg::feldman_desmedt::deal, primitives::variant::MinSig}, ed25519::{PrivateKey, PublicKey as Ed25519PublicKey}, transcript::Summary, Sha256, Signer, diff --git a/examples/reshare/src/dkg/egress.rs b/examples/reshare/src/dkg/egress.rs index 809e4b252c7..303745be970 100644 --- a/examples/reshare/src/dkg/egress.rs +++ b/examples/reshare/src/dkg/egress.rs @@ -1,6 +1,6 @@ use commonware_consensus::types::Epoch; use commonware_cryptography::bls12381::{ - dkg::Output, + dkg::feldman_desmedt::Output, primitives::{group::Share, variant::Variant}, }; use std::{future::Future, pin::Pin}; diff --git a/examples/reshare/src/dkg/ingress.rs b/examples/reshare/src/dkg/ingress.rs index 516898fb1e6..b78d0d84d06 100644 --- a/examples/reshare/src/dkg/ingress.rs +++ b/examples/reshare/src/dkg/ingress.rs @@ -9,7 +9,7 @@ use commonware_actor::{ }; use commonware_consensus::{marshal::Update, Reporter}; use commonware_cryptography::{ - bls12381::{dkg::SignedDealerLog, primitives::variant::Variant}, + bls12381::{dkg::feldman_desmedt::SignedDealerLog, primitives::variant::Variant}, Hasher, Signer, }; use commonware_utils::{acknowledgement::Exact, channel::oneshot, Acknowledgement}; diff --git a/examples/reshare/src/dkg/state.rs b/examples/reshare/src/dkg/state.rs index 15f3fb7ec65..189c94458f0 100644 --- a/examples/reshare/src/dkg/state.rs +++ b/examples/reshare/src/dkg/state.rs @@ -16,7 +16,7 @@ use commonware_codec::{EncodeSize, Read, ReadExt, Write}; use commonware_consensus::types::Epoch as EpochNum; use commonware_cryptography::{ bls12381::{ - dkg::{ + dkg::feldman_desmedt::{ Dealer as CryptoDealer, DealerLog, DealerPrivMsg, DealerPubMsg, Info, Logs, Output, Player as CryptoPlayer, PlayerAck, SignedDealerLog, }, @@ -656,8 +656,10 @@ impl Player { rng: &mut impl CryptoRngCore, logs: Logs, strategy: &impl Strategy, - ) -> Result<(Output, Share), commonware_cryptography::bls12381::dkg::Error> - { + ) -> Result< + (Output, Share), + commonware_cryptography::bls12381::dkg::feldman_desmedt::Error, + > { self.player.finalize::(rng, logs, strategy) } } @@ -669,7 +671,7 @@ mod tests { use commonware_consensus::types::Epoch; use commonware_cryptography::{ bls12381::{ - dkg::Info, + dkg::feldman_desmedt::Info, primitives::{group::Scalar, sharing::Mode, variant::MinPk}, }, ed25519, Signer, diff --git a/examples/reshare/src/engine.rs b/examples/reshare/src/engine.rs index cfb25d97fe3..efb985ef2c0 100644 --- a/examples/reshare/src/engine.rs +++ b/examples/reshare/src/engine.rs @@ -20,7 +20,7 @@ use commonware_consensus::{ }; use commonware_cryptography::{ bls12381::{ - dkg::Output, + dkg::feldman_desmedt::Output, primitives::{group, variant::Variant}, }, ed25519::Batch, diff --git a/examples/reshare/src/setup.rs b/examples/reshare/src/setup.rs index 4be7af19db4..501c820672f 100644 --- a/examples/reshare/src/setup.rs +++ b/examples/reshare/src/setup.rs @@ -3,7 +3,7 @@ use crate::dkg::MAX_SUPPORTED_MODE; use commonware_codec::{Decode, Encode}; use commonware_cryptography::{ bls12381::{ - dkg::{deal, Output}, + dkg::feldman_desmedt::{deal, Output}, primitives::{group::Share, variant::MinSig}, }, ed25519::{PrivateKey, PublicKey}, diff --git a/examples/reshare/src/validator.rs b/examples/reshare/src/validator.rs index 9ed6826c61f..ae8244c5c10 100644 --- a/examples/reshare/src/validator.rs +++ b/examples/reshare/src/validator.rs @@ -164,7 +164,7 @@ mod test { }; use commonware_cryptography::{ bls12381::{ - dkg::{deal, Output}, + dkg::feldman_desmedt::{deal, Output}, primitives::{group::Share, variant::MinSig}, }, ed25519::{PrivateKey, PublicKey},