Skip to content

Commit 54c4fe4

Browse files
committed
prepare certpedpop for use
- Remove uneccessary std features from dependencies. - Useful bincode implementations on vrf types. - Add test where contributors are also receivers.
1 parent 35af4a7 commit 54c4fe4

File tree

3 files changed

+148
-10
lines changed

3 files changed

+148
-10
lines changed

schnorr_fun/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ secp256kfun = { path = "../secp256kfun", version = "0.11", default-features = f
1818
bech32 = { version = "0.11", optional = true, default-features = false, features = ["alloc"] }
1919
bincode = { workspace = true, optional = true }
2020
vrf_fun = { path = "../vrf_fun", version = "0.11", optional = true, default-features = false }
21-
sha2 = { version = "0.10", optional = true }
21+
sha2 = { version = "0.10", optional = true, default-features = false }
2222

2323
[dev-dependencies]
2424
secp256kfun = { path = "../secp256kfun", version = "0.11", features = ["proptest", "bincode", "alloc"] }
@@ -51,7 +51,7 @@ libsecp_compat_0_29 = ["secp256kfun/libsecp_compat_0_29"]
5151
libsecp_compat_0_30 = ["secp256kfun/libsecp_compat_0_30"]
5252
proptest = ["secp256kfun/proptest"]
5353
share_backup = ["dep:bech32"]
54-
vrf_cert_keygen = ["dep:vrf_fun", "dep:sha2", "alloc", "secp256kfun/std", "vrf_fun/std"]
54+
vrf_cert_keygen = ["dep:vrf_fun", "dep:sha2"]
5555

5656
[package.metadata.docs.rs]
5757
all-features = true

schnorr_fun/src/frost/chilldkg/certpedpop.rs

Lines changed: 131 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ pub mod vrf_cert {
7474
use vrf_fun::VrfProof;
7575

7676
/// VRF certification scheme using SSWU VRF
77+
#[derive(Clone, Debug, PartialEq)]
7778
pub struct VrfCertifier;
7879

7980
/// The output from VRF verification containing the gamma point
80-
#[derive(Clone, Debug)]
81+
#[derive(Clone, Debug, PartialEq)]
8182
pub struct VrfOutput {
8283
/// The VRF output point (gamma)
8384
pub gamma: Point,
@@ -118,6 +119,7 @@ pub mod vrf_cert {
118119
/// A party that generates secret input to the key generation. You need at least one of these
119120
/// and if at least one of these parties is honest then the final secret key will not be known by an
120121
/// attacker (unless they obtain `t` shares!).
122+
#[derive(Clone, Debug, PartialEq)]
121123
pub struct Contributor {
122124
inner: encpedpop::Contributor,
123125
}
@@ -128,7 +130,13 @@ pub type KeygenInput = encpedpop::KeygenInput;
128130
/// Key generation inputs after being aggregated by the coordinator
129131
pub type AggKeygenInput = encpedpop::AggKeygenInput;
130132
/// A certificate containing signatures or proofs from certifying parties
131-
#[derive(Clone, Debug)]
133+
#[derive(Clone, Debug, PartialEq)]
134+
#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
135+
#[cfg_attr(
136+
feature = "serde",
137+
derive(crate::fun::serde::Deserialize, crate::fun::serde::Serialize),
138+
serde(crate = "crate::fun::serde")
139+
)]
132140
pub struct Certificate<Sig>(BTreeMap<Point, Sig>);
133141

134142
/// A certificate containing signatures or proofs from certifying parties
@@ -158,6 +166,17 @@ impl<Sig> Certificate<Sig> {
158166
pub fn iter(&self) -> impl Iterator<Item = (&Point, &Sig)> {
159167
self.0.iter()
160168
}
169+
170+
/// The number of certificates stored
171+
pub fn len(&self) -> usize {
172+
self.0.len()
173+
}
174+
175+
/// Have any certificates been collected
176+
pub fn is_empty(&self) -> bool {
177+
// clippy::len_without_is_empty wanted this method
178+
self.0.is_empty()
179+
}
161180
}
162181

163182
impl Contributor {
@@ -203,12 +222,14 @@ impl Contributor {
203222
}
204223

205224
/// A key generation session that has been certified by each certifying party (contributors and share receivers).
206-
#[derive(Clone, Debug)]
225+
#[derive(Clone, Debug, PartialEq)]
207226
pub struct CertifiedKeygen<S: CertificationScheme> {
208-
input: AggKeygenInput,
209-
certificate: Certificate<S::Signature>,
227+
/// The aggregated inputs to keygen
228+
pub input: AggKeygenInput,
229+
/// The collected certificates from each party
230+
pub certificate: Certificate<S::Signature>,
210231
/// The outputs from successful verification, indexed by certifying party's public key
211-
outputs: BTreeMap<Point, S::Output>,
232+
pub outputs: BTreeMap<Point, S::Output>,
212233
}
213234

214235
impl<S: CertificationScheme> CertifiedKeygen<S> {
@@ -296,6 +317,7 @@ pub use encpedpop::Coordinator;
296317

297318
/// Stores the state of share recipient who first receives their share and then waits to get
298319
/// signatures from all the certifying parties on the keygeneration before accepting it.
320+
#[derive(Debug, Clone, PartialEq)]
299321
pub struct SecretShareReceiver {
300322
paired_secret_share: PairedSecretShare<Normal, Zero>,
301323
agg_input: AggKeygenInput,
@@ -344,7 +366,9 @@ impl SecretShareReceiver {
344366
.agg_input
345367
.encryption_keys()
346368
.map(|(_, encryption_key)| encryption_key)
347-
.chain(contributor_keys.iter().cloned());
369+
.chain(contributor_keys.iter().cloned())
370+
.collect::<BTreeSet<_>>(); // dedupe as some contributers may have also be receivers
371+
348372
for cert_key in cert_keys {
349373
match certificate.get(&cert_key) {
350374
Some(sig) => match cert_scheme.verify_cert(cert_key, &self.agg_input, sig) {
@@ -584,4 +608,104 @@ mod test {
584608
(n_receivers + n_generators) as usize
585609
);
586610
}
611+
612+
#[test]
613+
fn contributors_are_receivers() {
614+
use proptest::test_runner::{RngAlgorithm, TestRng};
615+
let schnorr = crate::new_with_deterministic_nonces::<sha2::Sha256>();
616+
let mut rng = TestRng::deterministic_rng(RngAlgorithm::ChaCha);
617+
618+
let threshold = 3;
619+
let n_receivers = 5;
620+
let n_contributors = 2; // First 2 receivers will also be contributors
621+
622+
// Create receiver keypairs
623+
let share_receivers = (1..=n_receivers)
624+
.map(|i| Scalar::from(i as u32).non_zero().unwrap())
625+
.collect::<BTreeSet<_>>();
626+
627+
let receiver_enckeys = share_receivers
628+
.iter()
629+
.cloned()
630+
.map(|party_index| (party_index, KeyPair::new(Scalar::random(&mut rng))))
631+
.collect::<BTreeMap<_, _>>();
632+
633+
let public_receiver_enckeys = receiver_enckeys
634+
.iter()
635+
.map(|(party_index, enckeypair)| (*party_index, enckeypair.public_key()))
636+
.collect::<BTreeMap<ShareIndex, Point>>();
637+
638+
// Generate contributors
639+
let (contributors, to_coordinator_messages): (Vec<Contributor>, Vec<KeygenInput>) = (0
640+
..n_contributors)
641+
.map(|i| {
642+
Contributor::gen_keygen_input(
643+
&schnorr,
644+
threshold,
645+
&public_receiver_enckeys,
646+
i,
647+
&mut rng,
648+
)
649+
})
650+
.unzip();
651+
652+
// Contributors use the first n_contributors receiver keypairs
653+
let contributor_keys: Vec<KeyPair> = receiver_enckeys
654+
.values()
655+
.take(n_contributors as usize)
656+
.cloned()
657+
.collect();
658+
659+
let contributor_public_keys = contributor_keys
660+
.iter()
661+
.map(|kp| kp.public_key())
662+
.collect::<Vec<_>>();
663+
664+
// Aggregate inputs
665+
let mut aggregator = Coordinator::new(threshold, n_contributors, &public_receiver_enckeys);
666+
667+
for (i, to_coordinator_message) in to_coordinator_messages.into_iter().enumerate() {
668+
aggregator
669+
.add_input(&schnorr, i as u32, to_coordinator_message)
670+
.unwrap();
671+
}
672+
673+
let agg_input = aggregator.finish().unwrap();
674+
let mut certificate = Certificate::new();
675+
676+
// Contributors certify
677+
for (contributor, keypair) in contributors.into_iter().zip(contributor_keys.iter()) {
678+
let sig = contributor
679+
.verify_agg_input(&schnorr, &agg_input, keypair)
680+
.unwrap();
681+
certificate.insert(keypair.public_key(), sig);
682+
}
683+
684+
// Receivers certify
685+
let mut paired_secret_shares = vec![];
686+
let mut share_receivers = vec![];
687+
for (party_index, enckey) in &receiver_enckeys {
688+
let (share_receiver, cert) = SecretShareReceiver::receive_secret_share(
689+
&schnorr,
690+
&schnorr,
691+
*party_index,
692+
enckey,
693+
&agg_input,
694+
)
695+
.unwrap();
696+
certificate.insert(enckey.public_key(), cert);
697+
share_receivers.push(share_receiver);
698+
}
699+
700+
// Finalize
701+
for share_receiver in share_receivers {
702+
let (_certified_keygen, paired_secret_share) = share_receiver
703+
.finalize(&schnorr, certificate.clone(), &contributor_public_keys)
704+
.unwrap();
705+
paired_secret_shares.push(paired_secret_share.non_zero().unwrap());
706+
}
707+
708+
// Verify we have the expected number of unique shares
709+
assert_eq!(paired_secret_shares.len(), n_receivers as usize);
710+
}
587711
}

vrf_fun/src/vrf.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use sigma_fun::{
1111
};
1212

1313
/// VRF proof structure
14-
#[derive(Clone, Debug)]
14+
#[derive(Clone, Debug, PartialEq)]
1515
#[cfg_attr(
1616
feature = "serde",
1717
derive(serde::Serialize, serde::Deserialize),
@@ -61,7 +61,21 @@ where
6161
}
6262
}
6363

64+
#[cfg(feature = "bincode")]
65+
impl<'a, L, Context> bincode::BorrowDecode<'a, Context> for VrfProof<L>
66+
where
67+
L: ArrayLength<u8> + IsLessOrEqual<U32>,
68+
<L as IsLessOrEqual<U32>>::Output: NonZero,
69+
{
70+
fn borrow_decode<D: bincode::de::BorrowDecoder<'a, Context = Context>>(
71+
decoder: &mut D,
72+
) -> Result<Self, bincode::error::DecodeError> {
73+
<Self as bincode::Decode<Context>>::decode(decoder)
74+
}
75+
}
76+
6477
/// Verified random output that ensures gamma has been verified
78+
#[derive(Debug, Clone)]
6579
pub struct VerifiedRandomOutput {
6680
pub gamma: Point,
6781
}

0 commit comments

Comments
 (0)