gennaro_dkg/
lib.rs

1//! Gennaro's Distributed Key Generation Algorithm.
2//!
3//! The algorithm uses participants with unique identifiers
4//! and each party communicates broadcast data and peer-to-peer
5//! data depending on the round. Round 1 generates secret_participant key shares
6//! which are checked for correctness in round 2. Any secret_participant that fails
7//! in round 2 is dropped from the valid set which is communicated in round 3.
8//! Round 4 communicates only with the remaining valid participants
9//! and computes the secret share and verification key. Round 5 checks that
10//! all participants computed the same verification key.
11//!
12//! The idea is that Rounds 3 and 5 serve as echo broadcasts to check the
13//! state of all valid participants. If an error occurs in any round, then
14//! participants either drop invalid participants or abort.
15//!
16//! The full paper can be found
17//! <https://link.springer.com/content/pdf/10.1007/s00145-006-0347-3.pdf>.
18//!
19//! The interface has been written to work with anything that implements the elliptic-curve::Group
20//! trait.
21//!
22//! An example for generating a secret key on the Secp256k1 curve with 2 out of 3 participants.
23//!
24//! ```
25//! use gennaro_dkg::*;
26//! use k256::{ProjectivePoint, Scalar};
27//! use maplit::btreemap;
28//! use std::{
29//!     collections::BTreeMap,
30//!     num::NonZeroUsize,
31//! };
32//! use vsss_rs::{Share, combine_shares, elliptic_curve::{Group, PrimeField}};
33//!
34//! let parameters = Parameters::new(NonZeroUsize::new(2).unwrap(), NonZeroUsize::new(3).unwrap());
35//!
36//! let mut participant1 = SecretParticipant::<ProjectivePoint>::new(NonZeroUsize::new(1).unwrap(), parameters).unwrap();
37//! let mut participant2 = SecretParticipant::<ProjectivePoint>::new(NonZeroUsize::new(2).unwrap(), parameters).unwrap();
38//! let mut participant3 = SecretParticipant::<ProjectivePoint>::new(NonZeroUsize::new(3).unwrap(), parameters).unwrap();
39//!
40//! // Round 1
41//! let (b1data1, p2p1data) = participant1.round1().unwrap();
42//! let (b2data1, p2p2data) = participant2.round1().unwrap();
43//! let (b3data1, p2p3data) = participant3.round1().unwrap();
44//!
45//! // Can't call the same round twice
46//! assert!(participant1.round1().is_err());
47//! assert!(participant2.round1().is_err());
48//! assert!(participant3.round1().is_err());
49//!
50//! // Send b1data1 to secret_participant 2 and 3
51//! // Send b2data1 to secret_participant 1 and 3
52//! // Send b3data1 to secret_participant 1 and 2
53//!
54//! // Send p2p1data[&2] to secret_participant 2
55//! // Send p2p1data[&3] to secret_participant 3
56//!
57//! // Send p2p2data[&1] to secret_participant 1
58//! // Send p2p2data[&3] to secret_participant 3
59//!
60//! // Send p2p3data[&1] to secret_participant 1
61//! // Send p2p3data[&2] to secret_participant 2
62//!
63//! let p1bdata1 = btreemap! {
64//!     2 => b2data1.clone(),
65//!     3 => b3data1.clone(),
66//! };
67//! let p1pdata = btreemap! {
68//!     2 => p2p2data[&1].clone(),
69//!     3 => p2p3data[&1].clone(),
70//! };
71//! let b1data2 = participant1.round2(p1bdata1, p1pdata).unwrap();
72//!
73//! let p2bdata1 = btreemap! {
74//!     1 => b1data1.clone(),
75//!     3 => b3data1.clone(),
76//! };
77//! let p2pdata = btreemap! {
78//!     1 => p2p1data[&2].clone(),
79//!     3 => p2p3data[&2].clone(),
80//! };
81//! let b2data2 = participant2.round2(p2bdata1, p2pdata).unwrap();
82//!
83//! let p3bdata1 = btreemap! {
84//!     1 => b1data1.clone(),
85//!     2 => b2data1.clone(),
86//! };
87//! let p3pdata = btreemap! {
88//!     1 => p2p1data[&3].clone(),
89//!     2 => p2p2data[&3].clone(),
90//! };
91//! let b3data2 = participant3.round2(p3bdata1, p3pdata).unwrap();
92//!
93//! // Send b1data2 to participants 2 and 3
94//! // Send b2data2 to participants 1 and 3
95//! // Send b3data2 to participants 1 and 2
96//!
97//! // This is an optimization for the example in reality each secret_participant computes this
98//! let bdata2 = btreemap! {
99//!     1 => b1data2,
100//!     2 => b2data2,
101//!     3 => b3data2,
102//! };
103//!
104//! let b1data3 = participant1.round3(&bdata2).unwrap();
105//! let b2data3 = participant2.round3(&bdata2).unwrap();
106//! let b3data3 = participant3.round3(&bdata2).unwrap();
107//!
108//! // Send b1data3 to participants 2 and 3
109//! // Send b2data3 to participants 1 and 3
110//! // Send b3data3 to participants 1 and 2
111//!
112//! // This is an optimization for the example in reality each secret_participant computes this
113//! let bdata3 = btreemap! {
114//!     1 => b1data3,
115//!     2 => b2data3,
116//!     3 => b3data3,
117//! };
118//!
119//! let b1data4 = participant1.round4(&bdata3).unwrap();
120//! let b2data4 = participant2.round4(&bdata3).unwrap();
121//! let b3data4 = participant3.round4(&bdata3).unwrap();
122//!
123//! // Send b1data4 to participants 2 and 3
124//! // Send b2data4 to participants 1 and 3
125//! // Send b3data4 to participants 1 and 2
126//!
127//! // Verify that the same key is computed then done
128//!
129//! // This is an optimization for the example in reality each secret_participant computes this
130//! let bdata4 = btreemap! {
131//!     1 => b1data4,
132//!     2 => b2data4,
133//!     3 => b3data4,
134//! };
135//!
136//! assert!(participant1.round5(&bdata4).is_ok());
137//! assert!(participant2.round5(&bdata4).is_ok());
138//! assert!(participant3.round5(&bdata4).is_ok());
139//!
140//! // Get the verification key
141//! let pk1 = participant1.get_public_key().unwrap();
142//! // Get the secret share
143//! let share1 = participant1.get_secret_share().unwrap();
144//!
145//! assert_eq!(pk1.is_identity().unwrap_u8(), 0u8);
146//! assert_eq!(share1.is_zero().unwrap_u8(), 0u8);
147//!
148//! let pk2 = participant2.get_public_key().unwrap();
149//! let share2 = participant2.get_secret_share().unwrap();
150//!
151//! assert_eq!(pk2.is_identity().unwrap_u8(), 0u8);
152//! assert_eq!(share2.is_zero().unwrap_u8(), 0u8);
153//!
154//! let pk3 = participant3.get_public_key().unwrap();
155//! let share3 = participant3.get_secret_share().unwrap();
156//!
157//! assert_eq!(pk3.is_identity().unwrap_u8(), 0u8);
158//! assert_eq!(share3.is_zero().unwrap_u8(), 0u8);
159//!
160//! // Public keys will be equal
161//! assert_eq!(pk1, pk2);
162//! assert_eq!(pk2, pk3);
163//! // Shares should not be
164//! assert_ne!(share1, share2);
165//! assert_ne!(share1, share3);
166//! assert_ne!(share2, share3);
167//!
168//! // For demonstration purposes, the shares if collected can be combined to recreate
169//! // the computed secret
170//!
171//! let s1 = <Vec<u8> as Share>::from_field_element(1u8, share1).unwrap();
172//! let s2 = <Vec<u8> as Share>::from_field_element(2u8, share2).unwrap();
173//! let s3 = <Vec<u8> as Share>::from_field_element(3u8, share3).unwrap();
174//!
175//! let sk: Scalar = combine_shares(&[s1, s2, s3]).unwrap();
176//! let computed_pk = ProjectivePoint::GENERATOR * sk;
177//! assert_eq!(computed_pk, pk1);
178//! ```
179//!
180//! The output of the DKG is the same as if shamir secret sharing
181//! had been run on the secret and sent to separate parties.
182#![deny(
183    missing_docs,
184    unused_import_braces,
185    unused_qualifications,
186    unused_parens,
187    unused_lifetimes,
188    unconditional_recursion,
189    unused_extern_crates,
190    trivial_casts,
191    trivial_numeric_casts
192)]
193#![cfg_attr(docsrs, feature(doc_cfg))]
194
195pub use rand_core;
196pub use vsss_rs;
197
198mod error;
199mod parameters;
200mod participant;
201mod pedersen_result;
202mod protected;
203mod secret_share;
204
205use rand_core::SeedableRng;
206use serde::{
207    de::{Error as DError, SeqAccess, Unexpected, Visitor},
208    ser::{SerializeSeq, SerializeTuple},
209    Deserialize, Deserializer, Serialize, Serializer,
210};
211use std::{
212    collections::BTreeSet,
213    fmt::{self, Display, Formatter},
214    marker::PhantomData,
215    num::NonZeroUsize,
216};
217use uint_zigzag::Uint;
218use vsss_rs::elliptic_curve::{group::GroupEncoding, Group, PrimeField};
219use zeroize::{Zeroize, ZeroizeOnDrop};
220
221pub use error::*;
222pub use parameters::*;
223pub use participant::*;
224pub use pedersen_result::*;
225
226/// Valid rounds
227#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
228pub enum Round {
229    /// First round
230    One,
231    /// Second round
232    Two,
233    /// Third round
234    Three,
235    /// Four round
236    Four,
237    /// Five round
238    Five,
239}
240
241impl Display for Round {
242    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
243        match self {
244            Self::One => write!(f, "1"),
245            Self::Two => write!(f, "2"),
246            Self::Three => write!(f, "3"),
247            Self::Four => write!(f, "4"),
248            Self::Five => write!(f, "5"),
249        }
250    }
251}
252
253macro_rules! impl_round_to_int {
254    ($ident:ident) => {
255        impl From<Round> for $ident {
256            fn from(value: Round) -> Self {
257                match value {
258                    Round::One => 1,
259                    Round::Two => 2,
260                    Round::Three => 3,
261                    Round::Four => 4,
262                    Round::Five => 5,
263                }
264            }
265        }
266    };
267}
268
269impl_round_to_int!(u8);
270impl_round_to_int!(u16);
271impl_round_to_int!(u32);
272impl_round_to_int!(u64);
273impl_round_to_int!(usize);
274
275/// Broadcast data from round 1 that should be sent to all other participants
276#[derive(Clone, Debug, Serialize, Deserialize)]
277pub struct Round1BroadcastData<G: Group + GroupEncoding + Default> {
278    #[serde(serialize_with = "serialize_g", deserialize_with = "deserialize_g")]
279    message_generator: G,
280    #[serde(serialize_with = "serialize_g", deserialize_with = "deserialize_g")]
281    blinder_generator: G,
282    #[serde(
283        serialize_with = "serialize_g_vec",
284        deserialize_with = "deserialize_g_vec"
285    )]
286    pedersen_commitments: Vec<G>,
287}
288
289#[cfg(test)]
290impl<G: Group + GroupEncoding + Default> serde_encrypt::traits::SerdeEncryptSharedKey
291    for Round1BroadcastData<G>
292{
293    type S = serde_encrypt::serialize::impls::BincodeSerializer<Self>;
294}
295
296/// Echo broadcast data from round 2 that should be sent to all valid participants
297#[derive(Clone, Debug, Serialize, Deserialize)]
298pub struct Round2EchoBroadcastData {
299    valid_participant_ids: BTreeSet<usize>,
300}
301
302#[cfg(test)]
303impl serde_encrypt::traits::SerdeEncryptSharedKey for Round1P2PData {
304    type S = serde_encrypt::serialize::impls::BincodeSerializer<Self>;
305}
306
307/// Broadcast data from round 3 that should be sent to all valid participants
308#[derive(Clone, Debug, Serialize, Deserialize)]
309pub struct Round3BroadcastData<G: Group + GroupEncoding + Default> {
310    #[serde(
311        serialize_with = "serialize_g_vec",
312        deserialize_with = "deserialize_g_vec"
313    )]
314    commitments: Vec<G>,
315}
316
317/// Echo broadcast data from round 4 that should be sent to all valid participants
318#[derive(Copy, Debug, Clone, Serialize, Deserialize)]
319pub struct Round4EchoBroadcastData<G: Group + GroupEncoding + Default> {
320    /// The computed public key
321    #[serde(serialize_with = "serialize_g", deserialize_with = "deserialize_g")]
322    pub public_key: G,
323}
324
325/// Peer data from round 1 that should only be sent to a specific secret_participant
326#[derive(Clone, Debug, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
327pub struct Round1P2PData {
328    secret_share: Vec<u8>,
329    blind_share: Vec<u8>,
330}
331
332pub(crate) fn serialize_scalar<F: PrimeField, S: Serializer>(
333    scalar: &F,
334    s: S,
335) -> Result<S::Ok, S::Error> {
336    let v = scalar.to_repr();
337    let vv = v.as_ref();
338    if s.is_human_readable() {
339        s.serialize_str(&data_encoding::BASE64URL_NOPAD.encode(vv))
340    } else {
341        let len = vv.len();
342        let mut t = s.serialize_tuple(len)?;
343        for vi in vv {
344            t.serialize_element(vi)?;
345        }
346        t.end()
347    }
348}
349
350pub(crate) fn deserialize_scalar<'de, F: PrimeField, D: Deserializer<'de>>(
351    d: D,
352) -> Result<F, D::Error> {
353    struct ScalarVisitor<F: PrimeField> {
354        marker: PhantomData<F>,
355    }
356
357    impl<'de, F: PrimeField> Visitor<'de> for ScalarVisitor<F> {
358        type Value = F;
359
360        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
361            write!(f, "a byte sequence")
362        }
363
364        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
365        where
366            E: DError,
367        {
368            let bytes = data_encoding::BASE64URL_NOPAD
369                .decode(v.as_bytes())
370                .map_err(|_| DError::invalid_value(Unexpected::Str(v), &self))?;
371            let mut repr = F::default().to_repr();
372            repr.as_mut().copy_from_slice(bytes.as_slice());
373            let sc = F::from_repr(repr);
374            if sc.is_some().into() {
375                Ok(sc.unwrap())
376            } else {
377                Err(DError::custom("unable to convert to scalar".to_string()))
378            }
379        }
380
381        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
382        where
383            A: SeqAccess<'de>,
384        {
385            let mut repr = F::default().to_repr();
386            let mut i = 0;
387            let len = repr.as_ref().len();
388            while let Some(b) = seq.next_element()? {
389                repr.as_mut()[i] = b;
390                i += 1;
391                if i == len {
392                    let sc = F::from_repr(repr);
393                    if sc.is_some().into() {
394                        return Ok(sc.unwrap());
395                    }
396                }
397            }
398            Err(DError::custom("unable to convert to scalar".to_string()))
399        }
400    }
401
402    let vis = ScalarVisitor {
403        marker: PhantomData::<F>,
404    };
405    if d.is_human_readable() {
406        d.deserialize_str(vis)
407    } else {
408        let repr = F::default().to_repr();
409        let len = repr.as_ref().len();
410        d.deserialize_tuple(len, vis)
411    }
412}
413
414pub(crate) fn serialize_g<G: Group + GroupEncoding + Default, S: Serializer>(
415    g: &G,
416    s: S,
417) -> Result<S::Ok, S::Error> {
418    let v = g.to_bytes();
419    let vv = v.as_ref();
420    if s.is_human_readable() {
421        s.serialize_str(&data_encoding::BASE64URL_NOPAD.encode(vv))
422    } else {
423        let mut t = s.serialize_tuple(vv.len())?;
424        for b in vv {
425            t.serialize_element(b)?;
426        }
427        t.end()
428    }
429}
430
431pub(crate) fn deserialize_g<'de, G: Group + GroupEncoding + Default, D: Deserializer<'de>>(
432    d: D,
433) -> Result<G, D::Error> {
434    struct GVisitor<G: Group + GroupEncoding + Default> {
435        marker: PhantomData<G>,
436    }
437
438    impl<'de, G: Group + GroupEncoding + Default> Visitor<'de> for GVisitor<G> {
439        type Value = G;
440
441        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
442            write!(f, "a base64 encoded string or tuple of bytes")
443        }
444
445        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
446        where
447            E: DError,
448        {
449            let mut repr = G::Repr::default();
450            let bytes = data_encoding::BASE64URL_NOPAD
451                .decode(v.as_bytes())
452                .map_err(|_| DError::invalid_value(Unexpected::Str(v), &self))?;
453            repr.as_mut().copy_from_slice(bytes.as_slice());
454            let res = G::from_bytes(&repr);
455            if res.is_some().unwrap_u8() == 1u8 {
456                Ok(res.unwrap())
457            } else {
458                Err(DError::invalid_value(Unexpected::Str(v), &self))
459            }
460        }
461
462        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
463        where
464            A: SeqAccess<'de>,
465        {
466            let mut repr = G::Repr::default();
467            let input = repr.as_mut();
468            for i in 0..input.len() {
469                input[i] = seq
470                    .next_element()?
471                    .ok_or_else(|| DError::invalid_length(input.len(), &self))?;
472            }
473            let res = G::from_bytes(&repr);
474            if res.is_some().unwrap_u8() == 1u8 {
475                Ok(res.unwrap())
476            } else {
477                Err(DError::invalid_value(Unexpected::Seq, &self))
478            }
479        }
480    }
481
482    let visitor = GVisitor {
483        marker: PhantomData,
484    };
485    if d.is_human_readable() {
486        d.deserialize_str(visitor)
487    } else {
488        let repr = G::Repr::default();
489        d.deserialize_tuple(repr.as_ref().len(), visitor)
490    }
491}
492
493pub(crate) fn serialize_g_vec<G: Group + GroupEncoding + Default, S: Serializer>(
494    g: &Vec<G>,
495    s: S,
496) -> Result<S::Ok, S::Error> {
497    let v = g.iter().map(|p| p.to_bytes()).collect::<Vec<G::Repr>>();
498    if s.is_human_readable() {
499        let vv = v
500            .iter()
501            .map(|b| data_encoding::BASE64URL_NOPAD.encode(b.as_ref()))
502            .collect::<Vec<String>>();
503        vv.serialize(s)
504    } else {
505        let size = G::Repr::default().as_ref().len();
506        let uint = uint_zigzag::Uint::from(g.len());
507        let length_bytes = uint.to_vec();
508        let mut seq = s.serialize_seq(Some(length_bytes.len() + size * g.len()))?;
509        for b in &length_bytes {
510            seq.serialize_element(b)?;
511        }
512        for c in &v {
513            for b in c.as_ref() {
514                seq.serialize_element(b)?;
515            }
516        }
517        seq.end()
518    }
519}
520
521pub(crate) fn deserialize_g_vec<'de, G: Group + GroupEncoding + Default, D: Deserializer<'de>>(
522    d: D,
523) -> Result<Vec<G>, D::Error> {
524    struct NonReadableVisitor<G: Group + GroupEncoding + Default> {
525        marker: PhantomData<G>,
526    }
527
528    impl<'de, G: Group + GroupEncoding + Default> Visitor<'de> for NonReadableVisitor<G> {
529        type Value = Vec<G>;
530
531        fn expecting(&self, f: &mut Formatter) -> fmt::Result {
532            write!(f, "an array of bytes")
533        }
534
535        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
536        where
537            A: SeqAccess<'de>,
538        {
539            let mut buffer = [0u8; Uint::MAX_BYTES];
540            let mut i = 0;
541            while let Some(b) = seq.next_element()? {
542                buffer[i] = b;
543                i += 1;
544                if i == Uint::MAX_BYTES {
545                    break;
546                }
547            }
548            let bytes_cnt_size = Uint::peek(&buffer)
549                .ok_or_else(|| DError::invalid_value(Unexpected::Bytes(&buffer), &self))?;
550            let points = Uint::try_from(&buffer[..bytes_cnt_size])
551                .map_err(|_| DError::invalid_value(Unexpected::Bytes(&buffer), &self))?;
552
553            i = Uint::MAX_BYTES - bytes_cnt_size;
554            let mut repr = G::Repr::default();
555            {
556                let r = repr.as_mut();
557                r[..i].copy_from_slice(&buffer[bytes_cnt_size..]);
558            }
559            let repr_len = repr.as_ref().len();
560            let mut out = Vec::with_capacity(points.0 as usize);
561            while let Some(b) = seq.next_element()? {
562                repr.as_mut()[i] = b;
563                i += 1;
564                if i == repr_len {
565                    i = 0;
566                    let pt = G::from_bytes(&repr);
567                    if pt.is_none().unwrap_u8() == 1u8 {
568                        return Err(DError::invalid_value(Unexpected::Bytes(&buffer), &self));
569                    }
570                    out.push(pt.unwrap());
571                    if out.len() == points.0 as usize {
572                        break;
573                    }
574                }
575            }
576            if out.len() != points.0 as usize {
577                return Err(DError::invalid_length(out.len(), &self));
578            }
579            Ok(out)
580        }
581    }
582
583    if d.is_human_readable() {
584        let s = Vec::<String>::deserialize(d)?;
585        let mut out = Vec::with_capacity(s.len());
586        for si in &s {
587            let mut repr = G::Repr::default();
588            let bytes = data_encoding::BASE64URL_NOPAD
589                .decode(si.as_bytes())
590                .map_err(|_| DError::custom("unable to decode string to bytes".to_string()))?;
591            repr.as_mut().copy_from_slice(bytes.as_slice());
592            let pt = G::from_bytes(&repr);
593            if pt.is_none().unwrap_u8() == 1u8 {
594                return Err(DError::custom(
595                    "unable to convert string to point".to_string(),
596                ));
597            }
598            out.push(pt.unwrap());
599        }
600        Ok(out)
601    } else {
602        d.deserialize_seq(NonReadableVisitor {
603            marker: PhantomData,
604        })
605    }
606}
607
608#[cfg(test)]
609mod tests {
610    use super::*;
611    use serde_encrypt::traits::SerdeEncryptSharedKey;
612    use std::collections::BTreeMap;
613    use vsss_rs::{combine_shares, Share};
614
615    #[test]
616    fn one_corrupted_party_k256() {
617        one_corrupted_party::<k256::ProjectivePoint>()
618    }
619
620    #[test]
621    fn one_corrupted_party_p256() {
622        one_corrupted_party::<p256::ProjectivePoint>()
623    }
624
625    #[test]
626    fn one_corrupted_party_curve25519() {
627        one_corrupted_party::<vsss_rs::curve25519::WrappedRistretto>();
628        one_corrupted_party::<vsss_rs::curve25519::WrappedEdwards>();
629    }
630
631    #[test]
632    fn one_corrupted_party_bls12_381() {
633        one_corrupted_party::<bls12_381_plus::G1Projective>();
634        one_corrupted_party::<bls12_381_plus::G2Projective>();
635    }
636
637    fn one_corrupted_party<G: Group + GroupEncoding + Default>() {
638        const THRESHOLD: usize = 2;
639        const LIMIT: usize = 4;
640        const BAD_ID: usize = 4;
641
642        let threshold = NonZeroUsize::new(THRESHOLD).unwrap();
643        let limit = NonZeroUsize::new(LIMIT).unwrap();
644        let parameters = Parameters::<G>::new(threshold, limit);
645        let mut participants = [
646            SecretParticipant::<G>::new(NonZeroUsize::new(1).unwrap(), parameters).unwrap(),
647            SecretParticipant::<G>::new(NonZeroUsize::new(2).unwrap(), parameters).unwrap(),
648            SecretParticipant::<G>::new(NonZeroUsize::new(3).unwrap(), parameters).unwrap(),
649            SecretParticipant::<G>::new(NonZeroUsize::new(4).unwrap(), parameters).unwrap(),
650        ];
651
652        let mut r1bdata = Vec::with_capacity(LIMIT);
653        let mut r1p2pdata = Vec::with_capacity(LIMIT);
654        for p in participants.iter_mut() {
655            let (broadcast, p2p) = p.round1().expect("Round 1 should work");
656            r1bdata.push(broadcast);
657            r1p2pdata.push(p2p);
658        }
659        for p in participants.iter_mut() {
660            assert!(p.round1().is_err());
661        }
662
663        // Corrupt bad actor
664        for i in 0..THRESHOLD {
665            r1bdata[BAD_ID - 1].pedersen_commitments[i] = G::identity();
666        }
667
668        let mut r2bdata = BTreeMap::new();
669
670        for i in 0..LIMIT {
671            let mut bdata = BTreeMap::new();
672            let mut p2pdata = BTreeMap::new();
673
674            let my_id = participants[i].get_id();
675            for j in 0..LIMIT {
676                let pp = &participants[j];
677                let id = pp.get_id();
678                if my_id == id {
679                    continue;
680                }
681                bdata.insert(id, r1bdata[id - 1].clone());
682                p2pdata.insert(id, r1p2pdata[id - 1][&my_id].clone());
683            }
684            let p = &mut participants[i];
685            let res = p.round2(bdata, p2pdata);
686            assert!(res.is_ok());
687            if my_id == BAD_ID {
688                continue;
689            }
690            r2bdata.insert(my_id, res.unwrap());
691        }
692
693        let mut r3bdata = BTreeMap::new();
694        for p in participants.iter_mut() {
695            if BAD_ID == p.get_id() {
696                continue;
697            }
698            let res = p.round3(&r2bdata);
699            assert!(res.is_ok());
700            r3bdata.insert(p.get_id(), res.unwrap());
701            assert!(p.round3(&r2bdata).is_err());
702        }
703
704        let mut r4bdata = BTreeMap::new();
705        let mut r4shares = Vec::with_capacity(LIMIT);
706        for p in participants.iter_mut() {
707            if BAD_ID == p.get_id() {
708                continue;
709            }
710            let res = p.round4(&r3bdata);
711            assert!(res.is_ok());
712            let bdata = res.unwrap();
713            let share = p.get_secret_share().unwrap();
714            r4bdata.insert(p.get_id(), bdata);
715            r4shares.push(<Vec<u8> as Share>::from_field_element(p.get_id() as u8, share).unwrap());
716            assert!(p.round4(&r3bdata).is_err());
717        }
718
719        for p in &participants {
720            if BAD_ID == p.get_id() {
721                continue;
722            }
723            assert!(p.round5(&r4bdata).is_ok());
724        }
725
726        let res = combine_shares::<G::Scalar, u8, Vec<u8>>(&r4shares);
727        assert!(res.is_ok());
728        let secret = res.unwrap();
729
730        assert_eq!(r4bdata[&1].public_key, G::generator() * secret);
731    }
732
733    #[test]
734    fn serialization_k256() {
735        serialization_curve::<k256::ProjectivePoint>();
736    }
737
738    #[test]
739    fn serialization_p256() {
740        serialization_curve::<p256::ProjectivePoint>();
741    }
742
743    #[test]
744    fn serialization_bls12_381_g1() {
745        serialization_curve::<bls12_381_plus::G1Projective>();
746    }
747
748    #[test]
749    fn serialization_bls12_381_g2() {
750        serialization_curve::<bls12_381_plus::G2Projective>();
751    }
752
753    #[cfg(feature = "curve25519")]
754    #[test]
755    fn serialization_curve25519() {
756        serialization_curve::<vsss_rs::curve25519::WrappedRistretto>();
757        serialization_curve::<vsss_rs::curve25519::WrappedEdwards>();
758    }
759
760    fn serialization_curve<G: Group + GroupEncoding + Default>() {
761        const THRESHOLD: usize = 2;
762        const LIMIT: usize = 3;
763
764        let threshold = NonZeroUsize::new(THRESHOLD).unwrap();
765        let limit = NonZeroUsize::new(LIMIT).unwrap();
766        let parameters = Parameters::<G>::new(threshold, limit);
767        let mut participants = [
768            SecretParticipant::<G>::new(NonZeroUsize::new(1).unwrap(), parameters).unwrap(),
769            SecretParticipant::<G>::new(NonZeroUsize::new(2).unwrap(), parameters).unwrap(),
770            SecretParticipant::<G>::new(NonZeroUsize::new(3).unwrap(), parameters).unwrap(),
771        ];
772
773        let mut r1bdata = Vec::<Round1BroadcastData<G>>::with_capacity(LIMIT);
774        let mut r1pdata = Vec::<BTreeMap<usize, Round1P2PData>>::with_capacity(LIMIT);
775
776        for participant in participants.iter_mut() {
777            let (bdata, pdata) = participant.round1().unwrap();
778
779            // text serialize test
780            let json = serde_json::to_string(&bdata).unwrap();
781            let res = serde_json::from_str::<Round1BroadcastData<G>>(&json);
782            assert!(res.is_ok());
783            let bdata2 = res.unwrap();
784            assert_eq!(bdata.message_generator, bdata.message_generator);
785            assert_eq!(bdata.blinder_generator, bdata2.blinder_generator);
786            assert_eq!(
787                bdata.pedersen_commitments[0],
788                bdata2.pedersen_commitments[0]
789            );
790            assert_eq!(
791                bdata.pedersen_commitments[1],
792                bdata2.pedersen_commitments[1]
793            );
794
795            let json = serde_json::to_string(&pdata).unwrap();
796            let res = serde_json::from_str::<BTreeMap<usize, Round1P2PData>>(&json);
797            assert!(res.is_ok());
798            let pdata2 = res.unwrap();
799            assert_eq!(pdata.len(), pdata2.len());
800            for (id, val) in &pdata {
801                assert!(pdata2.contains_key(id));
802                assert_eq!(val.secret_share, pdata2[id].secret_share);
803                assert_eq!(val.blind_share, pdata2[id].blind_share);
804            }
805
806            // binary serialize test
807            let bin = serde_bare::to_vec(&bdata).unwrap();
808            let res = serde_bare::from_slice::<Round1BroadcastData<G>>(&bin);
809            assert!(res.is_ok());
810            let bdata2 = res.unwrap();
811            assert_eq!(bdata.message_generator, bdata.message_generator);
812            assert_eq!(bdata.blinder_generator, bdata2.blinder_generator);
813            assert_eq!(
814                bdata.pedersen_commitments[0],
815                bdata2.pedersen_commitments[0]
816            );
817            assert_eq!(
818                bdata.pedersen_commitments[1],
819                bdata2.pedersen_commitments[1]
820            );
821
822            let bin = serde_bare::to_vec(&pdata).unwrap();
823            let res = serde_bare::from_slice::<BTreeMap<usize, Round1P2PData>>(&bin);
824            assert!(res.is_ok());
825            let pdata2 = res.unwrap();
826            assert_eq!(pdata.len(), pdata2.len());
827            for (id, val) in &pdata {
828                assert!(pdata2.contains_key(id));
829                assert_eq!(val.secret_share, pdata2[id].secret_share);
830                assert_eq!(val.blind_share, pdata2[id].blind_share);
831            }
832
833            let shared_key = serde_encrypt::shared_key::SharedKey::new([1u8; 32]);
834            let bin = bdata.encrypt(&shared_key).unwrap();
835            let res = Round1BroadcastData::<G>::decrypt_owned(&bin, &shared_key);
836            assert!(res.is_ok());
837            let bdata2 = res.unwrap();
838            assert_eq!(bdata.message_generator, bdata.message_generator);
839            assert_eq!(bdata.blinder_generator, bdata2.blinder_generator);
840            assert_eq!(
841                bdata.pedersen_commitments[0],
842                bdata2.pedersen_commitments[0]
843            );
844            assert_eq!(
845                bdata.pedersen_commitments[1],
846                bdata2.pedersen_commitments[1]
847            );
848
849            r1bdata.push(bdata);
850            r1pdata.push(pdata);
851        }
852
853        let mut r2bdata = BTreeMap::<usize, Round2EchoBroadcastData>::new();
854        r2bdata.insert(
855            1,
856            participants[0]
857                .round2(
858                    maplit::btreemap! {
859                        2 => r1bdata[1].clone(),
860                        3 => r1bdata[2].clone(),
861                    },
862                    maplit::btreemap! {
863                        2 => r1pdata[1][&1].clone(),
864                        3 => r1pdata[2][&1].clone()
865                    },
866                )
867                .unwrap(),
868        );
869        r2bdata.insert(
870            2,
871            participants[1]
872                .round2(
873                    maplit::btreemap! {
874                        1 => r1bdata[0].clone(),
875                        3 => r1bdata[2].clone(),
876                    },
877                    maplit::btreemap! {
878                        1 => r1pdata[0][&2].clone(),
879                        3 => r1pdata[2][&2].clone(),
880                    },
881                )
882                .unwrap(),
883        );
884        r2bdata.insert(
885            3,
886            participants[2]
887                .round2(
888                    maplit::btreemap! {
889                        1 => r1bdata[0].clone(),
890                        2 => r1bdata[1].clone(),
891                    },
892                    maplit::btreemap! {
893                        1 => r1pdata[0][&3].clone(),
894                        2 => r1pdata[1][&3].clone(),
895                    },
896                )
897                .unwrap(),
898        );
899
900        let json = serde_json::to_string(&r2bdata).unwrap();
901        let res = serde_json::from_str::<BTreeMap<usize, Round2EchoBroadcastData>>(&json);
902        assert!(res.is_ok());
903        let r2bdata2 = res.unwrap();
904        assert_eq!(
905            r2bdata[&1].valid_participant_ids,
906            r2bdata2[&1].valid_participant_ids
907        );
908
909        let bin = serde_bare::to_vec(&r2bdata).unwrap();
910        let res = serde_bare::from_slice::<BTreeMap<usize, Round2EchoBroadcastData>>(&bin);
911        assert!(res.is_ok());
912        let r2bdata2 = res.unwrap();
913        assert_eq!(
914            r2bdata[&1].valid_participant_ids,
915            r2bdata2[&1].valid_participant_ids
916        );
917
918        // We explicitly zeroize the P2P secrets here as we have to assert that it's zeroized.
919        // IRL we don't have to manually zeroize it as it will be automatically dropped as we've implemented the ZeroizeOnDrop trait
920        for i in 0..3 {
921            for j in 1..4 {
922                r1pdata[i].get_mut(&j).map(|val| val.zeroize());
923                if j != i + 1 {
924                    assert!(r1pdata[i].get(&j).unwrap().secret_share.is_empty());
925                    assert!(r1pdata[i].get(&j).unwrap().blind_share.is_empty());
926                }
927            }
928        }
929
930        let mut r3bdata = BTreeMap::<usize, Round3BroadcastData<G>>::new();
931        r3bdata.insert(1, participants[0].round3(&r2bdata).unwrap());
932        r3bdata.insert(2, participants[1].round3(&r2bdata).unwrap());
933        r3bdata.insert(3, participants[2].round3(&r2bdata).unwrap());
934
935        let json = serde_json::to_string(&r3bdata).unwrap();
936        let res = serde_json::from_str::<BTreeMap<usize, Round3BroadcastData<G>>>(&json);
937        assert!(res.is_ok());
938        let r3bdata2 = res.unwrap();
939        assert_eq!(
940            r3bdata.get(&1).unwrap().commitments,
941            r3bdata2.get(&1).unwrap().commitments
942        );
943        assert_eq!(
944            r3bdata.get(&2).unwrap().commitments,
945            r3bdata2.get(&2).unwrap().commitments
946        );
947        assert_eq!(
948            r3bdata.get(&3).unwrap().commitments,
949            r3bdata2.get(&3).unwrap().commitments
950        );
951
952        let bin = serde_bare::to_vec(&r3bdata).unwrap();
953        let res = serde_bare::from_slice::<BTreeMap<usize, Round3BroadcastData<G>>>(&bin);
954        assert!(res.is_ok());
955        let r3bdata2 = res.unwrap();
956        assert_eq!(
957            r3bdata.get(&1).unwrap().commitments,
958            r3bdata2.get(&1).unwrap().commitments
959        );
960        assert_eq!(
961            r3bdata.get(&2).unwrap().commitments,
962            r3bdata2.get(&2).unwrap().commitments
963        );
964        assert_eq!(
965            r3bdata.get(&3).unwrap().commitments,
966            r3bdata2.get(&3).unwrap().commitments
967        );
968
969        let mut r4bdata = BTreeMap::<usize, Round4EchoBroadcastData<G>>::new();
970        r4bdata.insert(1, participants[0].round4(&r3bdata).unwrap());
971        r4bdata.insert(2, participants[1].round4(&r3bdata).unwrap());
972        r4bdata.insert(3, participants[2].round4(&r3bdata).unwrap());
973
974        let json = serde_json::to_string(&r4bdata).unwrap();
975        let res = serde_json::from_str::<BTreeMap<usize, Round4EchoBroadcastData<G>>>(&json);
976        assert!(res.is_ok());
977        let r4bdata2 = res.unwrap();
978        assert_eq!(
979            r4bdata.get(&1).unwrap().public_key,
980            r4bdata2.get(&1).unwrap().public_key
981        );
982        assert_eq!(
983            r4bdata.get(&2).unwrap().public_key,
984            r4bdata2.get(&2).unwrap().public_key
985        );
986        assert_eq!(
987            r4bdata.get(&3).unwrap().public_key,
988            r4bdata2.get(&3).unwrap().public_key
989        );
990
991        let bin = serde_bare::to_vec(&r4bdata).unwrap();
992        let res = serde_bare::from_slice::<BTreeMap<usize, Round4EchoBroadcastData<G>>>(&bin);
993        assert!(res.is_ok());
994        let r4bdata2 = res.unwrap();
995        assert_eq!(
996            r4bdata.get(&1).unwrap().public_key,
997            r4bdata2.get(&1).unwrap().public_key
998        );
999        assert_eq!(
1000            r4bdata.get(&2).unwrap().public_key,
1001            r4bdata2.get(&2).unwrap().public_key
1002        );
1003        assert_eq!(
1004            r4bdata.get(&3).unwrap().public_key,
1005            r4bdata2.get(&3).unwrap().public_key
1006        );
1007    }
1008}