Skip to content

Commit f052cd4

Browse files
authored
Merge pull request #229 from nickfarrow/certpedpop-cleanup
Prepare certpedpop for use
2 parents 35af4a7 + 3f9936f commit f052cd4

File tree

4 files changed

+116
-75
lines changed

4 files changed

+116
-75
lines changed

schnorr_fun/Cargo.toml

Lines changed: 6 additions & 6 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"] }
@@ -40,18 +40,18 @@ required-features = ["libsecp_compat"]
4040

4141
[features]
4242
default = ["std"]
43-
alloc = ["secp256kfun/alloc" ]
44-
std = ["alloc", "secp256kfun/std"]
45-
bincode = [ "dep:bincode", "secp256kfun/bincode"]
46-
serde = ["secp256kfun/serde"]
43+
alloc = ["secp256kfun/alloc"]
44+
std = ["alloc", "secp256kfun/std", "vrf_fun?/std"]
45+
bincode = [ "dep:bincode", "secp256kfun/bincode", "vrf_fun?/bincode"]
46+
serde = ["secp256kfun/serde", "vrf_fun?/serde"]
4747
libsecp_compat = ["libsecp_compat_0_30", "secp256kfun/libsecp_compat"]
4848
libsecp_compat_0_27 = ["secp256kfun/libsecp_compat_0_27"]
4949
libsecp_compat_0_28 = ["secp256kfun/libsecp_compat_0_28"]
5050
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: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use secp256kfun::{KeyPair, hash::Hash32, nonce::NonceGen, prelude::*, rand_core}
2121
/// certifying the aggregated keygen input in certpedpop.
2222
pub trait CertificationScheme {
2323
/// The signature type produced by this scheme
24-
type Signature: Clone + core::fmt::Debug;
24+
type Signature: Clone + core::fmt::Debug + PartialEq;
2525

2626
/// The output produced by successful verification
2727
type Output: Clone + core::fmt::Debug;
@@ -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
@@ -138,14 +146,17 @@ impl<Sig> Default for Certificate<Sig> {
138146
}
139147
}
140148

141-
impl<Sig> Certificate<Sig> {
149+
impl<Sig: PartialEq + core::fmt::Debug> Certificate<Sig> {
142150
/// Create a new empty certificate
143151
pub fn new() -> Self {
144152
Self::default()
145153
}
146154

147155
/// Insert a signature/proof for a public key
148156
pub fn insert(&mut self, key: Point, sig: Sig) {
157+
if let Some(existing) = self.0.get(&key) {
158+
assert_eq!(existing, &sig, "certification should not change");
159+
}
149160
self.0.insert(key, sig);
150161
}
151162

@@ -158,6 +169,17 @@ impl<Sig> Certificate<Sig> {
158169
pub fn iter(&self) -> impl Iterator<Item = (&Point, &Sig)> {
159170
self.0.iter()
160171
}
172+
173+
/// The number of certificates stored
174+
pub fn len(&self) -> usize {
175+
self.0.len()
176+
}
177+
178+
/// Have any certificates been collected
179+
pub fn is_empty(&self) -> bool {
180+
// clippy::len_without_is_empty wanted this method
181+
self.0.is_empty()
182+
}
161183
}
162184

163185
impl Contributor {
@@ -203,12 +225,14 @@ impl Contributor {
203225
}
204226

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

214238
impl<S: CertificationScheme> CertifiedKeygen<S> {
@@ -296,6 +320,7 @@ pub use encpedpop::Coordinator;
296320

297321
/// Stores the state of share recipient who first receives their share and then waits to get
298322
/// signatures from all the certifying parties on the keygeneration before accepting it.
323+
#[derive(Debug, Clone, PartialEq)]
299324
pub struct SecretShareReceiver {
300325
paired_secret_share: PairedSecretShare<Normal, Zero>,
301326
agg_input: AggKeygenInput,
@@ -344,7 +369,9 @@ impl SecretShareReceiver {
344369
.agg_input
345370
.encryption_keys()
346371
.map(|(_, encryption_key)| encryption_key)
347-
.chain(contributor_keys.iter().cloned());
372+
.chain(contributor_keys.iter().cloned())
373+
.collect::<BTreeSet<_>>(); // dedupe as some contributers may have also be receivers
374+
348375
for cert_key in cert_keys {
349376
match certificate.get(&cert_key) {
350377
Some(sig) => match cert_scheme.verify_cert(cert_key, &self.agg_input, sig) {
@@ -378,38 +405,47 @@ pub fn simulate_keygen<H: Hash32, NG: NonceGen, S: CertificationScheme>(
378405
cert_scheme: &S,
379406
threshold: u32,
380407
n_receivers: u32,
381-
n_generators: u32,
408+
n_extra_generators: u32,
382409
fingerprint: Fingerprint,
383410
rng: &mut impl rand_core::RngCore,
384411
) -> (
385412
CertifiedKeygen<S>,
386413
Vec<(PairedSecretShare<Normal>, KeyPair)>,
387414
) {
388-
let share_receivers = (1..=n_receivers)
389-
.map(|i| Scalar::from(i).non_zero().unwrap())
390-
.collect::<BTreeSet<_>>();
391-
392-
let mut receiver_enckeys = share_receivers
393-
.iter()
394-
.cloned()
395-
.map(|party_index| (party_index, KeyPair::new(Scalar::random(rng))))
415+
let mut receiver_enckeys = (1..=n_receivers)
416+
.map(|i| {
417+
let party_index = Scalar::from(i).non_zero().unwrap();
418+
(party_index, KeyPair::new(Scalar::random(rng)))
419+
})
396420
.collect::<BTreeMap<_, _>>();
397421

398422
let public_receiver_enckeys = receiver_enckeys
399423
.iter()
400424
.map(|(party_index, enckeypair)| (*party_index, enckeypair.public_key()))
401425
.collect::<BTreeMap<ShareIndex, Point>>();
402426

427+
// Total number of generators is receivers + extra generators
428+
let n_generators = n_receivers + n_extra_generators;
429+
430+
// Generate keypairs for contributors - receivers will use their existing keypairs
431+
let contributor_keys: Vec<_> = (1..=n_receivers)
432+
.map(|i| {
433+
let party_index = Scalar::from(i).non_zero().unwrap();
434+
receiver_enckeys[&party_index]
435+
})
436+
.chain(core::iter::repeat_n(
437+
KeyPair::new(Scalar::random(rng)),
438+
n_extra_generators as _,
439+
))
440+
.collect();
441+
403442
let (contributors, to_coordinator_messages): (Vec<Contributor>, Vec<KeygenInput>) = (0
404443
..n_generators)
405444
.map(|i| {
406445
Contributor::gen_keygen_input(schnorr, threshold, &public_receiver_enckeys, i, rng)
407446
})
408447
.unzip();
409448

410-
let contributor_keys = (0..n_generators)
411-
.map(|_| KeyPair::new(Scalar::random(rng)))
412-
.collect::<Vec<_>>();
413449
let contributor_public_keys = contributor_keys
414450
.iter()
415451
.map(|kp| kp.public_key())
@@ -526,7 +562,7 @@ mod test {
526562
#[test]
527563
fn certified_run_simulate_keygen(
528564
(n_receivers, threshold) in (1u32..=4).prop_flat_map(|n| (Just(n), 1u32..=n)),
529-
n_generators in 1u32..5,
565+
n_extra_generators in 0u32..=3,
530566
) {
531567
let schnorr = crate::new_with_deterministic_nonces::<sha2::Sha256>();
532568
let mut rng = TestRng::deterministic_rng(RngAlgorithm::ChaCha);
@@ -536,7 +572,7 @@ mod test {
536572
&schnorr,
537573
threshold,
538574
n_receivers,
539-
n_generators,
575+
n_extra_generators,
540576
Fingerprint::none(),
541577
&mut rng
542578
);
@@ -559,14 +595,14 @@ mod test {
559595

560596
let threshold = 2;
561597
let n_receivers = 3;
562-
let n_generators = 2;
598+
let n_extra_generators = 0; // All receivers are also generators
563599

564600
let (certified_keygen, _) = certpedpop::simulate_keygen(
565601
&schnorr,
566602
&vrf_certifier,
567603
threshold,
568604
n_receivers,
569-
n_generators,
605+
n_extra_generators,
570606
Fingerprint::none(),
571607
&mut rng,
572608
);
@@ -581,7 +617,7 @@ mod test {
581617
// Verify we have the expected number of VRF outputs
582618
assert_eq!(
583619
certified_keygen.outputs().len(),
584-
(n_receivers + n_generators) as usize
620+
(n_receivers + n_extra_generators) as usize
585621
);
586622
}
587623
}

vrf_fun/src/vrf.rs

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Generic VRF implementation that can work with different transcript types
22
3-
use core::marker::PhantomData;
43
use secp256kfun::{KeyPair, Scalar, prelude::*};
54
use sigma_fun::{
65
CompactProof, FiatShamir, ProverTranscript, Transcript,
@@ -11,16 +10,27 @@ use sigma_fun::{
1110
};
1211

1312
/// VRF proof structure
14-
#[derive(Clone, Debug)]
13+
#[derive(Clone, Debug, PartialEq)]
1514
#[cfg_attr(
1615
feature = "serde",
1716
derive(serde::Serialize, serde::Deserialize),
18-
serde(bound(serialize = "", deserialize = ""))
17+
serde(bound(
18+
deserialize = "L: ArrayLength<u8>, CompactProof<Scalar<Public, Zero>, L>: serde::Deserialize<'de>",
19+
serialize = "L: ArrayLength<u8>, CompactProof<Scalar<Public, Zero>, L>: serde::Serialize",
20+
))
21+
)]
22+
#[cfg_attr(
23+
feature = "bincode",
24+
derive(bincode::Encode, bincode::Decode),
25+
bincode(
26+
encode_bounds = "L: ArrayLength<u8>, CompactProof<Scalar<Public, Zero>, L>: bincode::Encode",
27+
decode_bounds = "L: ArrayLength<u8>, CompactProof<Scalar<Public, Zero>, L>: bincode::Decode<__Context>",
28+
borrow_decode_bounds = "L: ArrayLength<u8>, CompactProof<Scalar<Public, Zero>, L>: bincode::BorrowDecode<'__de, __Context>"
29+
)
1930
)]
2031
pub struct VrfProof<L = U16>
2132
where
22-
L: ArrayLength<u8> + IsLessOrEqual<U32>,
23-
<L as IsLessOrEqual<U32>>::Output: NonZero,
33+
L: ArrayLength<u8>,
2434
{
2535
/// The VRF output point.
2636
///
@@ -30,51 +40,16 @@ where
3040
pub proof: CompactProof<Scalar<Public, Zero>, L>,
3141
}
3242

33-
#[cfg(feature = "bincode")]
34-
impl<L> bincode::Encode for VrfProof<L>
35-
where
36-
L: ArrayLength<u8> + IsLessOrEqual<U32>,
37-
<L as IsLessOrEqual<U32>>::Output: NonZero,
38-
{
39-
fn encode<E: bincode::enc::Encoder>(
40-
&self,
41-
encoder: &mut E,
42-
) -> Result<(), bincode::error::EncodeError> {
43-
self.gamma.encode(encoder)?;
44-
self.proof.encode(encoder)?;
45-
Ok(())
46-
}
47-
}
48-
49-
#[cfg(feature = "bincode")]
50-
impl<L, Context> bincode::Decode<Context> for VrfProof<L>
51-
where
52-
L: ArrayLength<u8> + IsLessOrEqual<U32>,
53-
<L as IsLessOrEqual<U32>>::Output: NonZero,
54-
{
55-
fn decode<D: bincode::de::Decoder<Context = Context>>(
56-
decoder: &mut D,
57-
) -> Result<Self, bincode::error::DecodeError> {
58-
let gamma = Point::decode(decoder)?;
59-
let proof = CompactProof::<Scalar<Public, Zero>, L>::decode(decoder)?;
60-
Ok(VrfProof { gamma, proof })
61-
}
62-
}
63-
6443
/// Verified random output that ensures gamma has been verified
44+
#[derive(Debug, Clone)]
6545
pub struct VerifiedRandomOutput {
6646
pub gamma: Point,
6747
}
6848

6949
/// Generic VRF implementation
70-
pub struct Vrf<T, ChallengeLength = U16>
71-
where
72-
ChallengeLength: ArrayLength<u8> + IsLessOrEqual<U32>,
73-
<ChallengeLength as IsLessOrEqual<U32>>::Output: NonZero,
74-
{
50+
pub struct Vrf<T, ChallengeLength = U16> {
7551
dleq: crate::VrfDleq<ChallengeLength>,
7652
pub transcript: T,
77-
_phantom: PhantomData<ChallengeLength>,
7853
}
7954

8055
impl<T: Clone, ChallengeLength> Vrf<T, ChallengeLength>
@@ -89,7 +64,6 @@ where
8964
Self {
9065
dleq: Eq::new(DLG::default(), DL::default()),
9166
transcript,
92-
_phantom: PhantomData,
9367
}
9468
}
9569
}

vrf_fun/tests/codec.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use secp256kfun::{KeyPair, prelude::*};
2+
use vrf_fun::VrfProof;
3+
4+
#[cfg(feature = "bincode")]
5+
#[test]
6+
fn test_vrf_proof_bincode_roundtrip() {
7+
let keypair = KeyPair::new(Scalar::random(&mut rand::thread_rng()));
8+
let proof = vrf_fun::rfc9381::sswu::prove::<sha2::Sha256>(&keypair, b"test message");
9+
10+
let encoded = bincode::encode_to_vec(&proof, bincode::config::standard()).unwrap();
11+
let (decoded, _): (VrfProof, _) =
12+
bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
13+
14+
assert_eq!(proof, decoded);
15+
}
16+
17+
#[cfg(all(feature = "bincode", feature = "serde"))]
18+
#[test]
19+
fn test_vrf_proof_serde_roundtrip() {
20+
use bincode::serde::Compat;
21+
22+
let keypair = KeyPair::new(Scalar::random(&mut rand::thread_rng()));
23+
let proof = vrf_fun::rfc9381::sswu::prove::<sha2::Sha256>(&keypair, b"test message");
24+
25+
let compat_proof = Compat(&proof);
26+
let encoded = bincode::encode_to_vec(compat_proof, bincode::config::standard()).unwrap();
27+
let (decoded, _): (Compat<VrfProof>, _) =
28+
bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
29+
30+
assert_eq!(proof, decoded.0);
31+
}

0 commit comments

Comments
 (0)