commonware_cryptography/bls12381/dkg/
mod.rs

1//! Distributed Key Generation (DKG) and Resharing protocol for the BLS12-381 curve.
2//!
3//! This crate implements an interactive Distributed Key Generation (DKG) and Resharing protocol
4//! for the BLS12-381 curve. Unlike other constructions, this construction does not require encrypted
5//! shares to be publicly broadcast to complete a DKG/Reshare. Shares, instead, are sent directly
6//! between dealers and players over an encrypted channel (which can be instantiated
7//! with [commonware-p2p](https://docs.rs/commonware-p2p)).
8//!
9//! The DKG is based on the "Joint-Feldman" construction from "Secure Distributed Key
10//! Generation for Discrete-Log Based Cryptosystems" (GJKR99) and Resharing is based
11//! on the construction described in "Redistributing secret shares to new access structures
12//! and its applications" (Desmedt97).
13//!
14//! # Overview
15//!
16//! The protocol has three types of participants: arbiters, dealers, and players. The arbiter
17//! serves as an orchestrator that collects commitments, acknowledgements, and reveals from
18//! dealers/players and replicates them to all dealers/players. The arbiter can be implemented as
19//! a standalone process or by some consensus protocol. Dealers generate commitments/shares and collect
20//! acknowledgements from players. Players receive shares from dealers, validate them, and send acknowledgements
21//! back to dealers. It is possible to be both a dealer and a player in the protocol.
22//!
23//! Whether or not the protocol succeeds, the dealers that did not post valid commitments/acks/reveals are
24//! identified and returned. If the protocol succeeds, any dealers that did not post valid commitments/acks/reveals
25//! are identified (and still returned). It is expected that the set of participants would punish/exclude
26//! "bad" dealers prior to a future round (to eventually make progress).
27//!
28//! # Specification
29//!
30//! ## Assumptions
31//!
32//! * Let `t` be the maximum amount of time it takes for a message to be sent between any two participants.
33//! * Each participant has an encrypted channel to every other participant.
34//! * There exist `3f + 1` participants and at most `f` static Byzantine faults.
35//!
36//! ## [Arbiter] Step 0: Start Round
37//!
38//! Send a message to all participants to start a round. If this is a reshare, include the group polynomial from
39//! the last successful round.
40//!
41//! ## [Dealer] Step 1: Generate Commitment and Dealings
42//!
43//! Upon receiving start message from arbiter, generate commitment and dealings. If it is a DKG, the commitment is
44//! a random polynomial of degree `2f`. If it is a reshare, the commitment must be consistent with the
45//! previous group polynomial.
46//!
47//! ## [Dealer] Step 2: Distribute Commitment and Dealings
48//!
49//! Distribute generated commitment and corresponding dealings to each player over an encrypted channel.
50//!
51//! ## [Player] Step 3: Verify Dealing and Send Acknowledgement
52//!
53//! Verify incoming dealing against provided commitment (additionally comparing the commitment to the previous group
54//! polynomial, if reshare). If the dealing is valid, send an acknowledgement back to the dealer.
55//!
56//! To protect against a dealer sending different commitments to different players, players must sign this
57//! acknowledgement over `(dealer, commitment)`.
58//!
59//! ## [Dealer] Step 4: Collect Acknowledgements and Send to Arbiter
60//!
61//! Collect acknowledgements from players. After `2t` has elapsed since Step 1 (up to `3t` from Step 0), check to
62//! see if at least `2f + 1` acknowledgements have been received (including self, if a player as well). If so, send the
63//! commitment, acknowledgements, and unencrypted dealings of players that did not send an acknowledgement to the
64//! arbiter. If not, exit.
65//!
66//! ## [Arbiter] Step 5: Select Commitments and Forward Reveals
67//!
68//! Select the first `2f + 1` commitments with at most `f` reveals. Forward these `2f + 1` commitments
69//! (and any reveals associated with each) to all players. If there do not exist `2f + 1` commitments with
70//! at most `f` reveals by time `4t`, exit.
71//!
72//! ## [Player] Step 6: Recover Group Polynomial and Derive Share
73//!
74//! If the round is successful, each player will receive `2f + 1` commitments and any dealings associated with said
75//! commitments they did not acknowledge (or that the dealer said they didn't acknowledge). With this, they can recover
76//! the new group polynomial and derive their share of the secret. If this distribution is not received by time `5t`, exit.
77//!
78//! # Synchrony Assumption
79//!
80//! Under synchrony (where `t` is the maximum amount of time it takes for a message to be sent between any two participants),
81//! this construction can be used to maintain a shared secret where at least `f + 1` honest players must participate to
82//! recover the shared secret (`2f + 1` threshold where at most `f` players are Byzantine). To see how this is true,
83//! first consider that in any successful round there must exist `2f + 1` commitments with at most `f` reveals. This implies
84//! that all players must have acknowledged or have access to a reveal for each of the `2f + 1` selected commitments (allowing
85//! them to derive their share). Next, consider that when the network is synchronous that all `2f + 1` honest players send
86//! acknowledgements to honest dealers before `2t`. Because `2f + 1` commitments must be chosen, at least `f + 1` commitments
87//! must be from honest dealers (where no honest player dealing is revealed). Even if the remaining `f` commitments are from
88//! Byzantine dealers, there will not be enough dealings to recover the derived share of any honest player (at most `f` of
89//! `2f + 1` dealings publicly revealed). Given all `2f + 1` honest players have access to their shares and it is not possible
90//! for a Byzantine player to derive any honest player's share, this claim holds.
91//!
92//! If the network is not synchronous, however, Byzantine players can collude to recover a shared secret with the
93//! participation of a single honest player (rather than `f + 1`) and `f + 1` honest players will each be able to derive
94//! the shared secret (if the Byzantine players reveal their shares). To see how this could be, consider a network where
95//! `f` honest participants are in one partition and (`f + 1` honest and `f` Byzantine participants) are in another. All
96//! `f` Byzantine players acknowledge dealings from the `f + 1` honest dealers. Participants in the second partition will
97//! complete a round and all the reveals will belong to the same set of `f` honest players (that are in the first partition).
98//! A colluding Byzantine adversary will then have access to their acknowledged `f` shares and the revealed `f` shares
99//! (requiring only the participation of a single honest player that was in their partition to recover the shared secret).
100//! If the Byzantine adversary reveals all of their (still private) shares at this time, each of the `f + 1` honest players
101//! that were in the second partition will be able to derive the shared secret without collusion (using their private share
102//! and the `2f` public shares). It will not be possible for any external observer, however, to recover the shared secret.
103//!
104//! ## Future Work: Dropping the Synchrony Assumption?
105//!
106//! It is possible to design a DKG/Resharing scheme that maintains a shared secret where at least `f + 1` honest players
107//! must participate to recover the shared secret that doesn't require a synchrony assumption (`2f + 1` threshold
108//! where at most `f` players are Byzantine). However, known constructions that satisfy this requirement require both
109//! broadcasting encrypted dealings publicly and employing Zero-Knowledge Proofs (ZKPs) to attest that encrypted dealings
110//! were generated correctly ([Groth21](https://eprint.iacr.org/2021/339), [Kate23](https://eprint.iacr.org/2023/451)).
111//!
112//! As of January 2025, these constructions are still considered novel (2-3 years in production), require stronger
113//! cryptographic assumptions, don't scale to hundreds of participants (unless dealers have powerful hardware), and provide
114//! observers the opportunity to brute force decrypt shares (even if honest players are online).
115//!
116//! # Tracking Complaints
117//!
118//! This crate does not provide an integrated mechanism for tracking complaints from players (of malicious dealers). However, it is
119//! possible to implement your own mechanism and to manually disqualify dealers from a given round in the arbiter. This decision was made
120//! because the mechanism for communicating commitments/shares/acknowledgements is highly dependent on the context in which this
121//! construction is used.
122//!
123//! # Example
124//!
125//! For a complete example of how to instantiate this crate, check out [commonware-vrf](https://docs.rs/commonware-vrf).
126
127pub mod arbiter;
128pub use arbiter::Arbiter;
129pub mod dealer;
130pub use dealer::Dealer;
131pub mod ops;
132pub mod player;
133pub use player::Player;
134
135use thiserror::Error;
136
137#[derive(Error, Debug)]
138pub enum Error {
139    #[error("unexpected polynomial")]
140    UnexpectedPolynomial,
141    #[error("commitment has wrong degree")]
142    CommitmentWrongDegree,
143    #[error("misdirected share")]
144    MisdirectedShare,
145    #[error("share does not on commitment")]
146    ShareWrongCommitment,
147    #[error("insufficient dealings")]
148    InsufficientDealings,
149    #[error("reshare mismatch")]
150    ReshareMismatch,
151    #[error("share interpolation failed")]
152    ShareInterpolationFailed,
153    #[error("public key interpolation failed")]
154    PublicKeyInterpolationFailed,
155    #[error("dealer is invalid")]
156    DealerInvalid,
157    #[error("player invalid")]
158    PlayerInvalid,
159    #[error("missing share")]
160    MissingShare,
161    #[error("missing commitment")]
162    MissingCommitment,
163    #[error("too many commitments")]
164    TooManyCommitments,
165    #[error("duplicate commitment")]
166    DuplicateCommitment,
167    #[error("duplicate share")]
168    DuplicateShare,
169    #[error("duplicate ack")]
170    DuplicateAck,
171    #[error("mismatched commitment")]
172    MismatchedCommitment,
173    #[error("mismatched share")]
174    MismatchedShare,
175    #[error("too many reveals")]
176    TooManyReveals,
177    #[error("incorrect active")]
178    IncorrectActive,
179    #[error("already active")]
180    AlreadyActive,
181    #[error("invalid commitments")]
182    InvalidCommitments,
183    #[error("dealer disqualified")]
184    DealerDisqualified,
185}
186
187#[cfg(test)]
188mod tests {
189    use super::*;
190    use crate::bls12381::primitives::ops::{
191        partial_sign_proof_of_possession, threshold_signature_recover, verify_proof_of_possession,
192    };
193    use crate::bls12381::primitives::poly::public;
194    use crate::bls12381::primitives::variant::{MinPk, MinSig, Variant};
195    use crate::{Ed25519, Signer};
196    use arbiter::Output;
197    use commonware_utils::quorum;
198    use rand::rngs::StdRng;
199    use rand::SeedableRng;
200    use std::collections::HashMap;
201
202    fn run_dkg_and_reshare<V: Variant>(
203        n_0: u32,
204        dealers_0: u32,
205        n_1: u32,
206        dealers_1: u32,
207        concurrency: usize,
208    ) {
209        // Create shared RNG (for reproducibility)
210        let mut rng = StdRng::seed_from_u64(0);
211
212        // Create contributors (must be in sorted order)
213        let mut contributors = Vec::new();
214        for i in 0..n_0 {
215            let signer = Ed25519::from_seed(i as u64).public_key();
216            contributors.push(signer);
217        }
218        contributors.sort();
219
220        // Create dealers
221        let mut dealer_shares = HashMap::new();
222        let mut dealers = HashMap::new();
223        for con in contributors.iter().take(dealers_0 as usize) {
224            let (dealer, commitment, shares) =
225                Dealer::<_, V>::new(&mut rng, None, contributors.clone());
226            dealer_shares.insert(con.clone(), (commitment, shares));
227            dealers.insert(con.clone(), dealer);
228        }
229
230        // Create players
231        let mut players = HashMap::new();
232        for con in &contributors {
233            let player = Player::<_, V>::new(
234                con.clone(),
235                None,
236                contributors.clone(),
237                contributors.clone(),
238                concurrency,
239            );
240            players.insert(con.clone(), player);
241        }
242
243        // Create arbiter
244        let mut arb = Arbiter::<_, V>::new(
245            None,
246            contributors.clone(),
247            contributors.clone(),
248            concurrency,
249        );
250
251        // Check ready
252        assert!(!arb.ready());
253
254        // Send commitments and shares to players
255        for (dealer, mut dealer_obj) in dealers {
256            // Distribute shares to players
257            let (commitment, shares) = dealer_shares.get(&dealer).unwrap().clone();
258            for (player_idx, player) in contributors.iter().enumerate() {
259                // Process share
260                let player_obj = players.get_mut(player).unwrap();
261                player_obj
262                    .share(
263                        dealer.clone(),
264                        commitment.clone(),
265                        shares[player_idx].clone(),
266                    )
267                    .unwrap();
268
269                // Collect ack
270                dealer_obj.ack(player.clone()).unwrap();
271            }
272
273            // Finalize dealer
274            let output = dealer_obj.finalize().unwrap();
275
276            // Ensure no reveals required
277            assert!(output.inactive.is_empty());
278
279            // Send commitment and acks to arbiter
280            arb.commitment(dealer, commitment, output.active, Vec::new())
281                .unwrap();
282        }
283
284        // Check ready
285        assert!(arb.ready());
286
287        // Finalize arbiter
288        let (result, disqualified) = arb.finalize();
289
290        // Verify disqualifications are empty (only occurs if invalid commitment or missing)
291        assert_eq!(disqualified.len(), (n_0 - dealers_0) as usize);
292
293        // Verify result
294        let output: Output<V> = result.unwrap();
295
296        // Ensure right number of commitments picked
297        let expected_commitments = quorum(n_0) as usize;
298        assert_eq!(output.commitments.len(), expected_commitments);
299
300        // Ensure no reveals required
301        assert!(output.reveals.is_empty());
302
303        // Distribute commitments to players and recover public key
304        let mut outputs = HashMap::new();
305        for player in contributors.iter() {
306            let result = players
307                .remove(player)
308                .unwrap()
309                .finalize(output.commitments.clone(), HashMap::new())
310                .unwrap();
311            outputs.insert(player.clone(), result);
312        }
313
314        // Test that can generate proof-of-possession
315        let t = quorum(n_0);
316        let partials = outputs
317            .values()
318            .map(|s| partial_sign_proof_of_possession::<V>(&s.public, &s.share))
319            .collect::<Vec<_>>();
320        let signature =
321            threshold_signature_recover::<V, _>(t, &partials).expect("unable to recover signature");
322        let public_key = public::<V>(&outputs.iter().next().unwrap().1.public);
323        verify_proof_of_possession::<V>(public_key, &signature)
324            .expect("invalid proof of possession");
325
326        // Create reshare players (assume no overlap)
327        let mut reshare_players = Vec::new();
328        for i in 0..n_1 {
329            let player = Ed25519::from_seed((i + n_0) as u64).public_key();
330            reshare_players.push(player);
331        }
332        reshare_players.sort();
333
334        // Create reshare dealers
335        let mut reshare_shares = HashMap::new();
336        let mut reshare_dealers = HashMap::new();
337        for con in contributors.iter().take(dealers_1 as usize) {
338            let output = outputs.get(con).unwrap();
339            let (dealer, commitment, shares) = Dealer::<_, V>::new(
340                &mut rng,
341                Some(output.share.clone()),
342                reshare_players.clone(),
343            );
344            reshare_shares.insert(con.clone(), (commitment, shares));
345            reshare_dealers.insert(con.clone(), dealer);
346        }
347
348        // Create reshare player objects
349        let mut reshare_player_objs = HashMap::new();
350        for con in &reshare_players {
351            let player = Player::<_, V>::new(
352                con.clone(),
353                Some(output.public.clone()),
354                contributors.clone(),
355                reshare_players.clone(),
356                concurrency,
357            );
358            reshare_player_objs.insert(con.clone(), player);
359        }
360
361        // Create arbiter
362        let mut arb = Arbiter::<_, V>::new(
363            Some(output.public),
364            contributors.clone(),
365            reshare_players.clone(),
366            concurrency,
367        );
368
369        // Check ready
370        assert!(!arb.ready());
371
372        // Send commitments and shares to players
373        for (dealer, mut dealer_obj) in reshare_dealers {
374            // Distribute shares to players
375            let (commitment, shares) = reshare_shares.get(&dealer).unwrap().clone();
376            for (player_idx, player) in reshare_players.iter().enumerate() {
377                // Process share
378                let player_obj = reshare_player_objs.get_mut(player).unwrap();
379                player_obj
380                    .share(
381                        dealer.clone(),
382                        commitment.clone(),
383                        shares[player_idx].clone(),
384                    )
385                    .unwrap();
386
387                // Collect ack
388                dealer_obj.ack(player.clone()).unwrap();
389            }
390
391            // Finalize dealer
392            let output = dealer_obj.finalize().unwrap();
393
394            // Ensure no reveals required
395            assert!(output.inactive.is_empty());
396
397            // Send commitment and acks to arbiter
398            arb.commitment(dealer, commitment, output.active, Vec::new())
399                .unwrap();
400        }
401
402        // Check ready
403        assert!(arb.ready());
404
405        // Finalize arbiter
406        let (result, disqualified) = arb.finalize();
407
408        // Verify disqualifications are empty (only occurs if invalid commitment)
409        assert_eq!(disqualified.len(), (n_0 - dealers_1) as usize);
410
411        // Verify result
412        let output: Output<V> = result.unwrap();
413
414        // Ensure right number of commitments picked
415        let expected_commitments = quorum(n_0) as usize;
416        assert_eq!(output.commitments.len(), expected_commitments);
417
418        // Ensure no reveals required
419        assert!(output.reveals.is_empty());
420
421        // Distribute commitments to players and recover public key
422        let mut outputs = Vec::new();
423        for player in reshare_players.iter() {
424            let result = reshare_player_objs
425                .remove(player)
426                .unwrap()
427                .finalize(output.commitments.clone(), HashMap::new())
428                .unwrap();
429            assert_eq!(result.public, output.public);
430            outputs.push(result);
431        }
432
433        // Test that can generate proof-of-possession
434        let t = quorum(n_1);
435        let partials = outputs
436            .iter()
437            .map(|s| partial_sign_proof_of_possession::<V>(&s.public, &s.share))
438            .collect::<Vec<_>>();
439        let signature =
440            threshold_signature_recover::<V, _>(t, &partials).expect("unable to recover signature");
441        let public_key = public::<V>(&outputs[0].public);
442        verify_proof_of_possession::<V>(public_key, &signature)
443            .expect("invalid proof of possession");
444    }
445
446    #[test]
447    fn test_dkg_and_reshare_all_active() {
448        run_dkg_and_reshare::<MinPk>(5, 5, 10, 5, 4);
449        run_dkg_and_reshare::<MinSig>(5, 5, 10, 5, 4);
450    }
451
452    #[test]
453    fn test_dkg_and_reshare_min_active() {
454        run_dkg_and_reshare::<MinPk>(4, 3, 4, 3, 4);
455        run_dkg_and_reshare::<MinSig>(4, 3, 4, 3, 4);
456    }
457
458    #[test]
459    fn test_dkg_and_reshare_min_active_different_sizes() {
460        run_dkg_and_reshare::<MinPk>(5, 4, 10, 4, 4);
461        run_dkg_and_reshare::<MinSig>(5, 4, 10, 4, 4);
462    }
463
464    #[test]
465    fn test_dkg_and_reshare_min_active_large() {
466        run_dkg_and_reshare::<MinPk>(20, 14, 100, 14, 4);
467        run_dkg_and_reshare::<MinSig>(20, 14, 100, 14, 4);
468    }
469
470    #[test]
471    #[should_panic]
472    fn test_dkg_and_reshare_insufficient_active() {
473        run_dkg_and_reshare::<MinPk>(5, 3, 10, 2, 4);
474        run_dkg_and_reshare::<MinSig>(5, 3, 10, 2, 4);
475    }
476
477    #[test]
478    fn test_invalid_commitment() {
479        // Initialize test
480        let n = 5;
481        let mut rng = StdRng::seed_from_u64(0);
482
483        // Create contributors (must be in sorted order)
484        let mut contributors = Vec::new();
485        for i in 0..n {
486            let signer = Ed25519::from_seed(i as u64).public_key();
487            contributors.push(signer);
488        }
489        contributors.sort();
490
491        // Create dealer
492        let (_, _, shares) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
493
494        // Create unrelated commitment of correct degree
495        let t = quorum(n);
496        let (public, _) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
497
498        // Create player
499        let mut player = Player::<_, MinSig>::new(
500            contributors[0].clone(),
501            None,
502            contributors.clone(),
503            contributors.clone(),
504            1,
505        );
506
507        // Send invalid commitment to player
508        let result = player.share(contributors[0].clone(), public, shares[0].clone());
509        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
510    }
511
512    #[test]
513    fn test_mismatched_commitment() {
514        // Initialize test
515        let n = 5;
516        let mut rng = StdRng::seed_from_u64(0);
517
518        // Create contributors (must be in sorted order)
519        let mut contributors = Vec::new();
520        for i in 0..n {
521            let signer = Ed25519::from_seed(i as u64).public_key();
522            contributors.push(signer);
523        }
524        contributors.sort();
525
526        // Create dealer
527        let (_, commitment, shares) =
528            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
529
530        // Create unrelated commitment of correct degree
531        let t = quorum(n);
532        let (other_commitment, _) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
533
534        // Create player
535        let mut player = Player::<_, MinSig>::new(
536            contributors[0].clone(),
537            None,
538            contributors.clone(),
539            contributors.clone(),
540            1,
541        );
542
543        // Send valid commitment to player
544        player
545            .share(contributors[0].clone(), commitment, shares[0].clone())
546            .unwrap();
547
548        // Send alternative commitment to player
549        let result = player.share(contributors[0].clone(), other_commitment, shares[0].clone());
550        assert!(matches!(result, Err(Error::MismatchedCommitment)));
551    }
552
553    #[test]
554    fn test_mismatched_share() {
555        // Initialize test
556        let n = 5;
557        let mut rng = StdRng::seed_from_u64(0);
558
559        // Create contributors (must be in sorted order)
560        let mut contributors = Vec::new();
561        for i in 0..n {
562            let signer = Ed25519::from_seed(i as u64).public_key();
563            contributors.push(signer);
564        }
565        contributors.sort();
566
567        // Create dealer
568        let (_, commitment, shares) =
569            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
570
571        // Create unrelated commitment of correct degree
572        let t = quorum(n);
573        let (_, other_shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
574
575        // Create player
576        let mut player = Player::<_, MinSig>::new(
577            contributors[0].clone(),
578            None,
579            contributors.clone(),
580            contributors.clone(),
581            1,
582        );
583
584        // Send valid share to player
585        player
586            .share(
587                contributors[0].clone(),
588                commitment.clone(),
589                shares[0].clone(),
590            )
591            .unwrap();
592
593        // Send alternative share to player
594        let result = player.share(contributors[0].clone(), commitment, other_shares[0].clone());
595        assert!(matches!(result, Err(Error::MismatchedShare)));
596    }
597
598    #[test]
599    fn test_duplicate_share() {
600        // Initialize test
601        let n = 5;
602        let mut rng = StdRng::seed_from_u64(0);
603
604        // Create contributors (must be in sorted order)
605        let mut contributors = Vec::new();
606        for i in 0..n {
607            let signer = Ed25519::from_seed(i as u64).public_key();
608            contributors.push(signer);
609        }
610        contributors.sort();
611
612        // Create dealer
613        let (_, commitment, shares) =
614            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
615
616        // Create player
617        let mut player = Player::<_, MinSig>::new(
618            contributors[0].clone(),
619            None,
620            contributors.clone(),
621            contributors.clone(),
622            1,
623        );
624
625        // Send valid share to player
626        player
627            .share(
628                contributors[0].clone(),
629                commitment.clone(),
630                shares[0].clone(),
631            )
632            .unwrap();
633
634        // Send alternative share to player
635        let result = player.share(contributors[0].clone(), commitment, shares[0].clone());
636        assert!(matches!(result, Err(Error::DuplicateShare)));
637    }
638
639    #[test]
640    fn test_misdirected_share() {
641        // Initialize test
642        let n = 5;
643        let mut rng = StdRng::seed_from_u64(0);
644
645        // Create contributors (must be in sorted order)
646        let mut contributors = Vec::new();
647        for i in 0..n {
648            let signer = Ed25519::from_seed(i as u64).public_key();
649            contributors.push(signer);
650        }
651        contributors.sort();
652
653        // Create dealer
654        let (_, commitment, shares) =
655            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
656
657        // Create player
658        let mut player = Player::<_, MinSig>::new(
659            contributors[0].clone(),
660            None,
661            contributors.clone(),
662            contributors.clone(),
663            1,
664        );
665
666        // Send misdirected share to player
667        let result = player.share(
668            contributors[0].clone(),
669            commitment.clone(),
670            shares[1].clone(),
671        );
672        assert!(matches!(result, Err(Error::MisdirectedShare)));
673    }
674
675    #[test]
676    fn test_invalid_dealer() {
677        // Initialize test
678        let n = 5;
679        let mut rng = StdRng::seed_from_u64(0);
680
681        // Create contributors (must be in sorted order)
682        let mut contributors = Vec::new();
683        for i in 0..n {
684            let signer = Ed25519::from_seed(i as u64).public_key();
685            contributors.push(signer);
686        }
687        contributors.sort();
688
689        // Create dealer
690        let (_, commitment, shares) =
691            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
692
693        // Create player
694        let mut player = Player::<_, MinSig>::new(
695            contributors[0].clone(),
696            None,
697            contributors.clone(),
698            contributors.clone(),
699            1,
700        );
701
702        // Send share from invalid dealer
703        let dealer = Ed25519::from_seed(n as u64).public_key();
704        let result = player.share(dealer.clone(), commitment.clone(), shares[0].clone());
705        assert!(matches!(result, Err(Error::DealerInvalid)));
706
707        // Create arbiter
708        let mut arb =
709            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
710
711        // Send commitment from invalid dealer
712        let result = arb.commitment(dealer, commitment, vec![0, 1, 2, 3], Vec::new());
713        assert!(matches!(result, Err(Error::DealerInvalid)));
714    }
715
716    #[test]
717    fn test_invalid_commitment_degree() {
718        // Initialize test
719        let n = 5;
720        let mut rng = StdRng::seed_from_u64(0);
721
722        // Create contributors (must be in sorted order)
723        let mut contributors = Vec::new();
724        for i in 0..n {
725            let signer = Ed25519::from_seed(i as u64).public_key();
726            contributors.push(signer);
727        }
728        contributors.sort();
729
730        // Create dealer
731        let (_, _, shares) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
732
733        // Create invalid commitment
734        let (public, _) = ops::generate_shares::<_, MinSig>(&mut rng, None, n * 2, 1);
735
736        // Create player
737        let mut player = Player::<_, MinSig>::new(
738            contributors[0].clone(),
739            None,
740            contributors.clone(),
741            contributors.clone(),
742            1,
743        );
744
745        // Send invalid commitment to player
746        let result = player.share(contributors[0].clone(), public.clone(), shares[0].clone());
747        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
748
749        // Create arbiter
750        let mut arb =
751            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
752
753        // Send invalid commitment to arbiter
754        let result = arb.commitment(
755            contributors[0].clone(),
756            public,
757            vec![0, 1, 2, 3, 4],
758            Vec::new(),
759        );
760        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
761    }
762
763    #[test]
764    fn test_reveal() {
765        // Initialize test
766        let n = 5;
767        let mut rng = StdRng::seed_from_u64(0);
768
769        // Create contributors (must be in sorted order)
770        let mut contributors = Vec::new();
771        for i in 0..n {
772            let signer = Ed25519::from_seed(i as u64).public_key();
773            contributors.push(signer);
774        }
775        contributors.sort();
776
777        // Create dealer
778        let (_, commitment, shares) =
779            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
780
781        // Create arbiter
782        let mut arb =
783            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
784
785        // Add commitment to arbiter
786        arb.commitment(
787            contributors[0].clone(),
788            commitment,
789            vec![0, 1, 2, 3],
790            vec![shares[4].clone()],
791        )
792        .unwrap();
793    }
794
795    #[test]
796    fn test_arbiter_reveals() {
797        // Initialize test
798        let n = 11;
799        let q = quorum(n as u32) as usize;
800        let mut rng = StdRng::seed_from_u64(0);
801
802        // Create contributors (must be in sorted order)
803        let mut contributors = Vec::new();
804        for i in 0..n {
805            let signer = Ed25519::from_seed(i as u64).public_key();
806            contributors.push(signer);
807        }
808        contributors.sort();
809
810        // Create arbiter
811        let mut arb =
812            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
813
814        // Create dealers
815        let mut commitments = Vec::with_capacity(n);
816        let mut reveals = Vec::with_capacity(n);
817        for con in &contributors {
818            // Create dealer
819            let (_, commitment, shares) =
820                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
821            commitments.push(commitment.clone());
822            reveals.push(shares[q].clone());
823
824            // Add commitment to arbiter
825            let acks: Vec<u32> = (0..q as u32).collect();
826            let reveals = shares[q..n].to_vec();
827            arb.commitment(con.clone(), commitment, acks, reveals)
828                .unwrap();
829        }
830
831        // Finalize arbiter
832        let (result, _) = arb.finalize();
833        let output = result.unwrap();
834
835        // Ensure commitments and reveals are correct
836        assert_eq!(output.commitments.len(), q);
837        for (dealer_idx, commitment) in commitments.iter().enumerate().take(q) {
838            let dealer_idx = dealer_idx as u32;
839            assert_eq!(output.commitments.get(&dealer_idx).unwrap(), commitment);
840            assert_eq!(
841                output.reveals.get(&dealer_idx).unwrap()[0],
842                reveals[dealer_idx as usize]
843            );
844        }
845    }
846
847    #[test]
848    fn test_arbiter_best() {}
849
850    #[test]
851    fn test_duplicate_commitment() {
852        // Initialize test
853        let n = 5;
854        let mut rng = StdRng::seed_from_u64(0);
855
856        // Create contributors (must be in sorted order)
857        let mut contributors = Vec::new();
858        for i in 0..n {
859            let signer = Ed25519::from_seed(i as u64).public_key();
860            contributors.push(signer);
861        }
862        contributors.sort();
863
864        // Create dealer
865        let (_, commitment, shares) =
866            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
867
868        // Create arbiter
869        let mut arb =
870            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
871
872        // Add commitment to arbiter
873        arb.commitment(
874            contributors[0].clone(),
875            commitment.clone(),
876            vec![0, 1, 2, 3],
877            vec![shares[4].clone()],
878        )
879        .unwrap();
880
881        // Add commitment to arbiter (again)
882        let result = arb.commitment(
883            contributors[0].clone(),
884            commitment,
885            vec![0, 1, 2, 3],
886            vec![shares[4].clone()],
887        );
888        assert!(matches!(result, Err(Error::DuplicateCommitment)));
889    }
890
891    #[test]
892    fn test_reveal_duplicate_player() {
893        // Initialize test
894        let n = 5;
895        let mut rng = StdRng::seed_from_u64(0);
896
897        // Create contributors (must be in sorted order)
898        let mut contributors = Vec::new();
899        for i in 0..n {
900            let signer = Ed25519::from_seed(i as u64).public_key();
901            contributors.push(signer);
902        }
903        contributors.sort();
904
905        // Create dealer
906        let (_, commitment, shares) =
907            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
908
909        // Create arbiter
910        let mut arb =
911            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
912
913        // Add commitment to arbiter
914        let result = arb.commitment(
915            contributors[0].clone(),
916            commitment,
917            vec![0, 1, 2, 3],
918            vec![shares[3].clone()],
919        );
920        assert!(matches!(result, Err(Error::AlreadyActive)));
921    }
922
923    #[test]
924    fn test_insufficient_active() {
925        // Initialize test
926        let n = 5;
927        let mut rng = StdRng::seed_from_u64(0);
928
929        // Create contributors (must be in sorted order)
930        let mut contributors = Vec::new();
931        for i in 0..n {
932            let signer = Ed25519::from_seed(i as u64).public_key();
933            contributors.push(signer);
934        }
935        contributors.sort();
936
937        // Create dealer
938        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
939
940        // Create arbiter
941        let mut arb =
942            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
943
944        // Add commitment to arbiter
945        let result = arb.commitment(
946            contributors[0].clone(),
947            commitment.clone(),
948            vec![0, 1, 2, 3],
949            Vec::new(),
950        );
951        assert!(matches!(result, Err(Error::IncorrectActive)));
952
953        // Add valid commitment to arbiter after disqualified
954        let result = arb.commitment(
955            contributors[0].clone(),
956            commitment,
957            vec![0, 1, 2, 3, 4],
958            Vec::new(),
959        );
960        assert!(matches!(result, Err(Error::DealerDisqualified)));
961    }
962
963    #[test]
964    fn test_manual_disqualify() {
965        // Initialize test
966        let n = 5;
967        let mut rng = StdRng::seed_from_u64(0);
968
969        // Create contributors (must be in sorted order)
970        let mut contributors = Vec::new();
971        for i in 0..n {
972            let signer = Ed25519::from_seed(i as u64).public_key();
973            contributors.push(signer);
974        }
975        contributors.sort();
976
977        // Create dealer
978        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
979
980        // Create arbiter
981        let mut arb =
982            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
983
984        // Disqualify dealer
985        arb.disqualify(contributors[0].clone());
986
987        // Add valid commitment to arbiter after disqualified
988        let result = arb.commitment(
989            contributors[0].clone(),
990            commitment,
991            vec![0, 1, 2, 3, 4],
992            Vec::new(),
993        );
994        assert!(matches!(result, Err(Error::DealerDisqualified)));
995    }
996
997    #[test]
998    fn test_too_many_reveals() {
999        // Initialize test
1000        let n = 5;
1001        let mut rng = StdRng::seed_from_u64(0);
1002
1003        // Create contributors (must be in sorted order)
1004        let mut contributors = Vec::new();
1005        for i in 0..n {
1006            let signer = Ed25519::from_seed(i as u64).public_key();
1007            contributors.push(signer);
1008        }
1009        contributors.sort();
1010
1011        // Create dealer
1012        let (_, commitment, shares) =
1013            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1014
1015        // Create arbiter
1016        let mut arb =
1017            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1018
1019        // Add commitment to arbiter
1020        let result = arb.commitment(
1021            contributors[0].clone(),
1022            commitment,
1023            vec![0, 1, 2],
1024            vec![shares[3].clone(), shares[4].clone()],
1025        );
1026        assert!(matches!(result, Err(Error::TooManyReveals)));
1027    }
1028
1029    #[test]
1030    fn test_incorrect_reveal() {
1031        // Initialize test
1032        let n = 5;
1033        let mut rng = StdRng::seed_from_u64(0);
1034
1035        // Create contributors (must be in sorted order)
1036        let mut contributors = Vec::new();
1037        for i in 0..n {
1038            let signer = Ed25519::from_seed(i as u64).public_key();
1039            contributors.push(signer);
1040        }
1041        contributors.sort();
1042
1043        // Create dealer
1044        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1045
1046        // Create invalid shares
1047        let t = quorum(n);
1048        let (_, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
1049
1050        // Create arbiter
1051        let mut arb =
1052            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1053
1054        // Add commitment to arbiter
1055        let result = arb.commitment(
1056            contributors[0].clone(),
1057            commitment,
1058            vec![0, 1, 2, 3],
1059            vec![shares[4].clone()],
1060        );
1061        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1062    }
1063
1064    #[test]
1065    fn test_reveal_corrupt_share() {
1066        // Initialize test
1067        let n = 5;
1068        let mut rng = StdRng::seed_from_u64(0);
1069
1070        // Create contributors (must be in sorted order)
1071        let mut contributors = Vec::new();
1072        for i in 0..n {
1073            let signer = Ed25519::from_seed(i as u64).public_key();
1074            contributors.push(signer);
1075        }
1076        contributors.sort();
1077
1078        // Create dealer
1079        let (_, commitment, shares) =
1080            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1081
1082        // Create arbiter
1083        let mut arb =
1084            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1085
1086        // Swap share value
1087        let mut share = shares[3].clone();
1088        share.index = 4;
1089
1090        // Add commitment to arbiter
1091        let result = arb.commitment(
1092            contributors[0].clone(),
1093            commitment,
1094            vec![0, 1, 2, 3],
1095            vec![share],
1096        );
1097        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1098    }
1099
1100    #[test]
1101    fn test_reveal_duplicate_ack() {
1102        // Initialize test
1103        let n = 5;
1104        let mut rng = StdRng::seed_from_u64(0);
1105
1106        // Create contributors (must be in sorted order)
1107        let mut contributors = Vec::new();
1108        for i in 0..n {
1109            let signer = Ed25519::from_seed(i as u64).public_key();
1110            contributors.push(signer);
1111        }
1112        contributors.sort();
1113
1114        // Create dealer
1115        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1116
1117        // Create arbiter
1118        let mut arb =
1119            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1120
1121        // Add commitment to arbiter
1122        let result = arb.commitment(
1123            contributors[0].clone(),
1124            commitment,
1125            vec![0, 1, 2, 2],
1126            Vec::new(),
1127        );
1128        assert!(matches!(result, Err(Error::AlreadyActive)));
1129    }
1130
1131    #[test]
1132    fn test_reveal_invalid_ack() {
1133        // Initialize test
1134        let n = 5;
1135        let mut rng = StdRng::seed_from_u64(0);
1136
1137        // Create contributors (must be in sorted order)
1138        let mut contributors = Vec::new();
1139        for i in 0..n {
1140            let signer = Ed25519::from_seed(i as u64).public_key();
1141            contributors.push(signer);
1142        }
1143        contributors.sort();
1144
1145        // Create dealer
1146        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1147
1148        // Create arbiter
1149        let mut arb =
1150            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1151
1152        // Add commitment to arbiter
1153        let result = arb.commitment(
1154            contributors[0].clone(),
1155            commitment,
1156            vec![0, 1, 2, 10],
1157            Vec::new(),
1158        );
1159        assert!(matches!(result, Err(Error::PlayerInvalid)));
1160    }
1161
1162    #[test]
1163    fn test_reveal_invalid_share() {
1164        // Initialize test
1165        let n = 5;
1166        let mut rng = StdRng::seed_from_u64(0);
1167
1168        // Create contributors (must be in sorted order)
1169        let mut contributors = Vec::new();
1170        for i in 0..n {
1171            let signer = Ed25519::from_seed(i as u64).public_key();
1172            contributors.push(signer);
1173        }
1174        contributors.sort();
1175
1176        // Create dealer
1177        let (_, commitment, shares) =
1178            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1179
1180        // Create arbiter
1181        let mut arb =
1182            Arbiter::<_, MinSig>::new(None, contributors.clone(), contributors.clone(), 1);
1183
1184        // Swap share value
1185        let mut share = shares[3].clone();
1186        share.index = 10;
1187
1188        // Add commitment to arbiter
1189        let result = arb.commitment(
1190            contributors[0].clone(),
1191            commitment,
1192            vec![0, 1, 2, 3],
1193            vec![share],
1194        );
1195        assert!(matches!(result, Err(Error::PlayerInvalid)));
1196    }
1197
1198    #[test]
1199    fn test_dealer_acks() {
1200        // Initialize test
1201        let n = 5;
1202        let mut rng = StdRng::seed_from_u64(0);
1203
1204        // Create contributors (must be in sorted order)
1205        let mut contributors = Vec::new();
1206        for i in 0..n {
1207            let signer = Ed25519::from_seed(i as u64).public_key();
1208            contributors.push(signer);
1209        }
1210        contributors.sort();
1211
1212        // Create dealer
1213        let (mut dealer, _, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1214
1215        // Ack all players
1216        for player in &contributors {
1217            dealer.ack(player.clone()).unwrap();
1218        }
1219
1220        // Finalize dealer
1221        let output = dealer.finalize().unwrap();
1222        assert_eq!(output.active, vec![0, 1, 2, 3, 4]);
1223        assert!(output.inactive.is_empty());
1224    }
1225
1226    #[test]
1227    fn test_dealer_inactive() {
1228        // Initialize test
1229        let n = 5;
1230        let mut rng = StdRng::seed_from_u64(0);
1231
1232        // Create contributors (must be in sorted order)
1233        let mut contributors = Vec::new();
1234        for i in 0..n {
1235            let signer = Ed25519::from_seed(i as u64).public_key();
1236            contributors.push(signer);
1237        }
1238        contributors.sort();
1239
1240        // Create dealer
1241        let (mut dealer, _, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1242
1243        // Ack all players
1244        for player in contributors.iter().take(4) {
1245            dealer.ack(player.clone()).unwrap();
1246        }
1247
1248        // Finalize dealer
1249        let output = dealer.finalize().unwrap();
1250        assert_eq!(output.active, vec![0, 1, 2, 3]);
1251        assert_eq!(output.inactive, vec![4]);
1252    }
1253
1254    #[test]
1255    fn test_dealer_insufficient() {
1256        // Initialize test
1257        let n = 5;
1258        let mut rng = StdRng::seed_from_u64(0);
1259
1260        // Create contributors (must be in sorted order)
1261        let mut contributors = Vec::new();
1262        for i in 0..n {
1263            let signer = Ed25519::from_seed(i as u64).public_key();
1264            contributors.push(signer);
1265        }
1266        contributors.sort();
1267
1268        // Create dealer
1269        let (mut dealer, _, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1270
1271        // Ack all players
1272        for player in contributors.iter().take(2) {
1273            dealer.ack(player.clone()).unwrap();
1274        }
1275
1276        // Finalize dealer
1277        assert!(dealer.finalize().is_none());
1278    }
1279
1280    #[test]
1281    fn test_dealer_duplicate_ack() {
1282        // Initialize test
1283        let n = 5;
1284        let mut rng = StdRng::seed_from_u64(0);
1285
1286        // Create contributors (must be in sorted order)
1287        let mut contributors = Vec::new();
1288        for i in 0..n {
1289            let signer = Ed25519::from_seed(i as u64).public_key();
1290            contributors.push(signer);
1291        }
1292        contributors.sort();
1293
1294        // Create dealer
1295        let (mut dealer, _, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1296
1297        // Ack player
1298        let player = contributors[0].clone();
1299        dealer.ack(player.clone()).unwrap();
1300
1301        // Ack player (again)
1302        let result = dealer.ack(player);
1303        assert!(matches!(result, Err(Error::DuplicateAck)));
1304    }
1305
1306    #[test]
1307    fn test_dealer_invalid_player() {
1308        // Initialize test
1309        let n = 5;
1310        let mut rng = StdRng::seed_from_u64(0);
1311
1312        // Create contributors (must be in sorted order)
1313        let mut contributors = Vec::new();
1314        for i in 0..n {
1315            let signer = Ed25519::from_seed(i as u64).public_key();
1316            contributors.push(signer);
1317        }
1318        contributors.sort();
1319
1320        // Create dealer
1321        let (mut dealer, _, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1322
1323        // Ack invalid player
1324        let player = Ed25519::from_seed(n as u64).public_key();
1325        let result = dealer.ack(player);
1326        assert!(matches!(result, Err(Error::PlayerInvalid)));
1327    }
1328
1329    #[test]
1330    fn test_player_reveals() {
1331        // Initialize test
1332        let n = 11;
1333        let q = quorum(n as u32) as usize;
1334        let mut rng = StdRng::seed_from_u64(0);
1335
1336        // Create contributors (must be in sorted order)
1337        let mut contributors = Vec::new();
1338        for i in 0..n {
1339            let signer = Ed25519::from_seed(i as u64).public_key();
1340            contributors.push(signer);
1341        }
1342        contributors.sort();
1343
1344        // Create player
1345        let mut player = Player::<_, MinSig>::new(
1346            contributors[0].clone(),
1347            None,
1348            contributors.clone(),
1349            contributors.clone(),
1350            1,
1351        );
1352
1353        // Send shares to player
1354        let mut commitments = HashMap::new();
1355        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1356            let (_, commitment, shares) =
1357                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1358            player
1359                .share(con.clone(), commitment.clone(), shares[0].clone())
1360                .unwrap();
1361            commitments.insert(i as u32, commitment);
1362        }
1363
1364        // Finalize player with reveal
1365        let last = (q - 1) as u32;
1366        let (_, commitment, shares) =
1367            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1368        commitments.insert(last, commitment);
1369        let mut reveals = HashMap::new();
1370        reveals.insert(last, shares[0].clone());
1371        player.finalize(commitments, reveals).unwrap();
1372    }
1373
1374    #[test]
1375    fn test_player_missing_reveal() {
1376        // Initialize test
1377        let n = 11;
1378        let q = quorum(n as u32) as usize;
1379        let mut rng = StdRng::seed_from_u64(0);
1380
1381        // Create contributors (must be in sorted order)
1382        let mut contributors = Vec::new();
1383        for i in 0..n {
1384            let signer = Ed25519::from_seed(i as u64).public_key();
1385            contributors.push(signer);
1386        }
1387        contributors.sort();
1388
1389        // Create player
1390        let mut player = Player::<_, MinSig>::new(
1391            contributors[0].clone(),
1392            None,
1393            contributors.clone(),
1394            contributors.clone(),
1395            1,
1396        );
1397
1398        // Send shares to player
1399        let mut commitments = HashMap::new();
1400        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1401            let (_, commitment, shares) =
1402                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1403            player
1404                .share(con.clone(), commitment.clone(), shares[0].clone())
1405                .unwrap();
1406            commitments.insert(i as u32, commitment);
1407        }
1408
1409        // Finalize player with reveal
1410        let last = (q - 1) as u32;
1411        let (_, commitment, _) = Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1412        commitments.insert(last, commitment);
1413        let result = player.finalize(commitments, HashMap::new());
1414        assert!(matches!(result, Err(Error::MissingShare)));
1415    }
1416
1417    #[test]
1418    fn test_player_insufficient_commitments() {
1419        // Initialize test
1420        let n = 5;
1421        let mut rng = StdRng::seed_from_u64(0);
1422
1423        // Create contributors (must be in sorted order)
1424        let mut contributors = Vec::new();
1425        for i in 0..n {
1426            let signer = Ed25519::from_seed(i as u64).public_key();
1427            contributors.push(signer);
1428        }
1429        contributors.sort();
1430
1431        // Create player
1432        let mut player = Player::<_, MinSig>::new(
1433            contributors[0].clone(),
1434            None,
1435            contributors.clone(),
1436            contributors.clone(),
1437            1,
1438        );
1439
1440        // Send shares to player
1441        let mut commitments = HashMap::new();
1442        for (i, con) in contributors.iter().enumerate().take(2) {
1443            let (_, commitment, shares) =
1444                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1445            player
1446                .share(con.clone(), commitment.clone(), shares[0].clone())
1447                .unwrap();
1448            commitments.insert(i as u32, commitment);
1449        }
1450
1451        // Finalize player with reveal
1452        let result = player.finalize(commitments, HashMap::new());
1453        assert!(matches!(result, Err(Error::InvalidCommitments)));
1454    }
1455
1456    #[test]
1457    fn test_player_misdirected_reveal() {
1458        // Initialize test
1459        let n = 11;
1460        let q = quorum(n as u32) as usize;
1461        let mut rng = StdRng::seed_from_u64(0);
1462
1463        // Create contributors (must be in sorted order)
1464        let mut contributors = Vec::new();
1465        for i in 0..n {
1466            let signer = Ed25519::from_seed(i as u64).public_key();
1467            contributors.push(signer);
1468        }
1469        contributors.sort();
1470
1471        // Create player
1472        let mut player = Player::<_, MinSig>::new(
1473            contributors[0].clone(),
1474            None,
1475            contributors.clone(),
1476            contributors.clone(),
1477            1,
1478        );
1479
1480        // Send shares to player
1481        let mut commitments = HashMap::new();
1482        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1483            let (_, commitment, shares) =
1484                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1485            player
1486                .share(con.clone(), commitment.clone(), shares[0].clone())
1487                .unwrap();
1488            commitments.insert(i as u32, commitment);
1489        }
1490
1491        // Finalize player with reveal
1492        let last = (q - 1) as u32;
1493        let (_, commitment, shares) =
1494            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1495        commitments.insert(last, commitment);
1496        let mut reveals = HashMap::new();
1497        reveals.insert(last, shares[1].clone());
1498        let result = player.finalize(commitments, reveals);
1499        assert!(matches!(result, Err(Error::MisdirectedShare)));
1500    }
1501
1502    #[test]
1503    fn test_player_invalid_commitment() {
1504        // Initialize test
1505        let n = 11;
1506        let q = quorum(n as u32) as usize;
1507        let mut rng = StdRng::seed_from_u64(0);
1508
1509        // Create contributors (must be in sorted order)
1510        let mut contributors = Vec::new();
1511        for i in 0..n {
1512            let signer = Ed25519::from_seed(i as u64).public_key();
1513            contributors.push(signer);
1514        }
1515        contributors.sort();
1516
1517        // Create player
1518        let mut player = Player::<_, MinSig>::new(
1519            contributors[0].clone(),
1520            None,
1521            contributors.clone(),
1522            contributors.clone(),
1523            1,
1524        );
1525
1526        // Send shares to player
1527        let mut commitments = HashMap::new();
1528        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1529            let (_, commitment, shares) =
1530                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1531            player
1532                .share(con.clone(), commitment.clone(), shares[0].clone())
1533                .unwrap();
1534            commitments.insert(i as u32, commitment);
1535        }
1536
1537        // Finalize player with reveal
1538        let last = (q - 1) as u32;
1539        let (commitment, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n as u32, 1);
1540        commitments.insert(last, commitment);
1541        let mut reveals = HashMap::new();
1542        reveals.insert(last, shares[0].clone());
1543        let result = player.finalize(commitments, reveals);
1544        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
1545    }
1546
1547    #[test]
1548    fn test_player_invalid_reveal() {
1549        // Initialize test
1550        let n = 11;
1551        let q = quorum(n as u32) as usize;
1552        let mut rng = StdRng::seed_from_u64(0);
1553
1554        // Create contributors (must be in sorted order)
1555        let mut contributors = Vec::new();
1556        for i in 0..n {
1557            let signer = Ed25519::from_seed(i as u64).public_key();
1558            contributors.push(signer);
1559        }
1560        contributors.sort();
1561
1562        // Create player
1563        let mut player = Player::<_, MinSig>::new(
1564            contributors[0].clone(),
1565            None,
1566            contributors.clone(),
1567            contributors.clone(),
1568            1,
1569        );
1570
1571        // Send shares to player
1572        let mut commitments = HashMap::new();
1573        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1574            let (_, commitment, shares) =
1575                Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1576            player
1577                .share(con.clone(), commitment.clone(), shares[0].clone())
1578                .unwrap();
1579            commitments.insert(i as u32, commitment);
1580        }
1581
1582        // Finalize player with reveal
1583        let last = (q - 1) as u32;
1584        let (_, commitment, shares) =
1585            Dealer::<_, MinSig>::new(&mut rng, None, contributors.clone());
1586        commitments.insert(last, commitment);
1587        let mut reveals = HashMap::new();
1588        let mut share = shares[1].clone();
1589        share.index = 0;
1590        reveals.insert(last, share);
1591        let result = player.finalize(commitments, reveals);
1592        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1593    }
1594}