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::{Ed25519, Signer};
195    use commonware_utils::quorum;
196    use rand::rngs::StdRng;
197    use rand::SeedableRng;
198    use std::collections::HashMap;
199
200    fn run_dkg_and_reshare(n_0: u32, dealers_0: u32, n_1: u32, dealers_1: u32, concurrency: usize) {
201        // Create shared RNG (for reproducibility)
202        let mut rng = StdRng::seed_from_u64(0);
203
204        // Create contributors (must be in sorted order)
205        let mut contributors = Vec::new();
206        for i in 0..n_0 {
207            let signer = Ed25519::from_seed(i as u64).public_key();
208            contributors.push(signer);
209        }
210        contributors.sort();
211
212        // Create dealers
213        let mut dealer_shares = HashMap::new();
214        let mut dealers = HashMap::new();
215        for con in contributors.iter().take(dealers_0 as usize) {
216            let (dealer, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
217            dealer_shares.insert(con.clone(), (commitment, shares));
218            dealers.insert(con.clone(), dealer);
219        }
220
221        // Create players
222        let mut players = HashMap::new();
223        for con in &contributors {
224            let player = Player::new(
225                con.clone(),
226                None,
227                contributors.clone(),
228                contributors.clone(),
229                concurrency,
230            );
231            players.insert(con.clone(), player);
232        }
233
234        // Create arbiter
235        let mut arb = Arbiter::new(
236            None,
237            contributors.clone(),
238            contributors.clone(),
239            concurrency,
240        );
241
242        // Check ready
243        assert!(!arb.ready());
244
245        // Send commitments and shares to players
246        for (dealer, mut dealer_obj) in dealers {
247            // Distribute shares to players
248            let (commitment, shares) = dealer_shares.get(&dealer).unwrap().clone();
249            for (player_idx, player) in contributors.iter().enumerate() {
250                // Process share
251                let player_obj = players.get_mut(player).unwrap();
252                player_obj
253                    .share(dealer.clone(), commitment.clone(), shares[player_idx])
254                    .unwrap();
255
256                // Collect ack
257                dealer_obj.ack(player.clone()).unwrap();
258            }
259
260            // Finalize dealer
261            let output = dealer_obj.finalize().unwrap();
262
263            // Ensure no reveals required
264            assert!(output.inactive.is_empty());
265
266            // Send commitment and acks to arbiter
267            arb.commitment(dealer, commitment, output.active, Vec::new())
268                .unwrap();
269        }
270
271        // Check ready
272        assert!(arb.ready());
273
274        // Finalize arbiter
275        let (result, disqualified) = arb.finalize();
276
277        // Verify disqualifications are empty (only occurs if invalid commitment or missing)
278        assert_eq!(disqualified.len(), (n_0 - dealers_0) as usize);
279
280        // Verify result
281        let output = result.unwrap();
282
283        // Ensure right number of commitments picked
284        let expected_commitments = quorum(n_0) as usize;
285        assert_eq!(output.commitments.len(), expected_commitments);
286
287        // Ensure no reveals required
288        assert!(output.reveals.is_empty());
289
290        // Distribute commitments to players and recover public key
291        let mut outputs = HashMap::new();
292        for player in contributors.iter() {
293            let result = players
294                .remove(player)
295                .unwrap()
296                .finalize(output.commitments.clone(), HashMap::new())
297                .unwrap();
298            outputs.insert(player.clone(), result);
299        }
300
301        // Test that can generate proof-of-possession
302        let t = quorum(n_0);
303        let partials = outputs
304            .values()
305            .map(|s| partial_sign_proof_of_possession(&s.public, &s.share))
306            .collect::<Vec<_>>();
307        let signature =
308            threshold_signature_recover(t, &partials).expect("unable to recover signature");
309        let public_key = public(&outputs.iter().next().unwrap().1.public);
310        verify_proof_of_possession(public_key, &signature).expect("invalid proof of possession");
311
312        // Create reshare players (assume no overlap)
313        let mut reshare_players = Vec::new();
314        for i in 0..n_1 {
315            let player = Ed25519::from_seed((i + n_0) as u64).public_key();
316            reshare_players.push(player);
317        }
318        reshare_players.sort();
319
320        // Create reshare dealers
321        let mut reshare_shares = HashMap::new();
322        let mut reshare_dealers = HashMap::new();
323        for con in contributors.iter().take(dealers_1 as usize) {
324            let output = outputs.get(con).unwrap();
325            let (dealer, commitment, shares) =
326                Dealer::new(&mut rng, Some(output.share), reshare_players.clone());
327            reshare_shares.insert(con.clone(), (commitment, shares));
328            reshare_dealers.insert(con.clone(), dealer);
329        }
330
331        // Create reshare player objects
332        let mut reshare_player_objs = HashMap::new();
333        for con in &reshare_players {
334            let player = Player::new(
335                con.clone(),
336                Some(output.public.clone()),
337                contributors.clone(),
338                reshare_players.clone(),
339                concurrency,
340            );
341            reshare_player_objs.insert(con.clone(), player);
342        }
343
344        // Create arbiter
345        let mut arb = Arbiter::new(
346            Some(output.public),
347            contributors.clone(),
348            reshare_players.clone(),
349            concurrency,
350        );
351
352        // Check ready
353        assert!(!arb.ready());
354
355        // Send commitments and shares to players
356        for (dealer, mut dealer_obj) in reshare_dealers {
357            // Distribute shares to players
358            let (commitment, shares) = reshare_shares.get(&dealer).unwrap().clone();
359            for (player_idx, player) in reshare_players.iter().enumerate() {
360                // Process share
361                let player_obj = reshare_player_objs.get_mut(player).unwrap();
362                player_obj
363                    .share(dealer.clone(), commitment.clone(), shares[player_idx])
364                    .unwrap();
365
366                // Collect ack
367                dealer_obj.ack(player.clone()).unwrap();
368            }
369
370            // Finalize dealer
371            let output = dealer_obj.finalize().unwrap();
372
373            // Ensure no reveals required
374            assert!(output.inactive.is_empty());
375
376            // Send commitment and acks to arbiter
377            arb.commitment(dealer, commitment, output.active, Vec::new())
378                .unwrap();
379        }
380
381        // Check ready
382        assert!(arb.ready());
383
384        // Finalize arbiter
385        let (result, disqualified) = arb.finalize();
386
387        // Verify disqualifications are empty (only occurs if invalid commitment)
388        assert_eq!(disqualified.len(), (n_0 - dealers_1) as usize);
389
390        // Verify result
391        let output = result.unwrap();
392
393        // Ensure right number of commitments picked
394        let expected_commitments = quorum(n_0) as usize;
395        assert_eq!(output.commitments.len(), expected_commitments);
396
397        // Ensure no reveals required
398        assert!(output.reveals.is_empty());
399
400        // Distribute commitments to players and recover public key
401        let mut outputs = Vec::new();
402        for player in reshare_players.iter() {
403            let result = reshare_player_objs
404                .remove(player)
405                .unwrap()
406                .finalize(output.commitments.clone(), HashMap::new())
407                .unwrap();
408            assert_eq!(result.public, output.public);
409            outputs.push(result);
410        }
411
412        // Test that can generate proof-of-possession
413        let t = quorum(n_1);
414        let partials = outputs
415            .iter()
416            .map(|s| partial_sign_proof_of_possession(&s.public, &s.share))
417            .collect::<Vec<_>>();
418        let signature =
419            threshold_signature_recover(t, &partials).expect("unable to recover signature");
420        let public_key = public(&outputs[0].public);
421        verify_proof_of_possession(public_key, &signature).expect("invalid proof of possession");
422    }
423
424    #[test]
425    fn test_dkg_and_reshare_all_active() {
426        run_dkg_and_reshare(5, 5, 10, 5, 4);
427    }
428
429    #[test]
430    fn test_dkg_and_reshare_min_active() {
431        run_dkg_and_reshare(4, 3, 4, 3, 4);
432    }
433
434    #[test]
435    fn test_dkg_and_reshare_min_active_different_sizes() {
436        run_dkg_and_reshare(5, 4, 10, 4, 4);
437    }
438
439    #[test]
440    fn test_dkg_and_reshare_min_active_large() {
441        run_dkg_and_reshare(20, 14, 100, 14, 4);
442    }
443
444    #[test]
445    #[should_panic]
446    fn test_dkg_and_reshare_insufficient_active() {
447        run_dkg_and_reshare(5, 3, 10, 2, 4);
448    }
449
450    #[test]
451    fn test_invalid_commitment() {
452        // Initialize test
453        let n = 5;
454        let mut rng = StdRng::seed_from_u64(0);
455
456        // Create contributors (must be in sorted order)
457        let mut contributors = Vec::new();
458        for i in 0..n {
459            let signer = Ed25519::from_seed(i as u64).public_key();
460            contributors.push(signer);
461        }
462        contributors.sort();
463
464        // Create dealer
465        let (_, _, shares) = Dealer::new(&mut rng, None, contributors.clone());
466
467        // Create unrelated commitment of correct degree
468        let t = quorum(n);
469        let (public, _) = ops::generate_shares(&mut rng, None, n, t);
470
471        // Create player
472        let mut player = Player::new(
473            contributors[0].clone(),
474            None,
475            contributors.clone(),
476            contributors.clone(),
477            1,
478        );
479
480        // Send invalid commitment to player
481        let result = player.share(contributors[0].clone(), public, shares[0]);
482        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
483    }
484
485    #[test]
486    fn test_mismatched_commitment() {
487        // Initialize test
488        let n = 5;
489        let mut rng = StdRng::seed_from_u64(0);
490
491        // Create contributors (must be in sorted order)
492        let mut contributors = Vec::new();
493        for i in 0..n {
494            let signer = Ed25519::from_seed(i as u64).public_key();
495            contributors.push(signer);
496        }
497        contributors.sort();
498
499        // Create dealer
500        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
501
502        // Create unrelated commitment of correct degree
503        let t = quorum(n);
504        let (other_commitment, _) = ops::generate_shares(&mut rng, None, n, t);
505
506        // Create player
507        let mut player = Player::new(
508            contributors[0].clone(),
509            None,
510            contributors.clone(),
511            contributors.clone(),
512            1,
513        );
514
515        // Send valid commitment to player
516        player
517            .share(contributors[0].clone(), commitment, shares[0])
518            .unwrap();
519
520        // Send alternative commitment to player
521        let result = player.share(contributors[0].clone(), other_commitment, shares[0]);
522        assert!(matches!(result, Err(Error::MismatchedCommitment)));
523    }
524
525    #[test]
526    fn test_mismatched_share() {
527        // Initialize test
528        let n = 5;
529        let mut rng = StdRng::seed_from_u64(0);
530
531        // Create contributors (must be in sorted order)
532        let mut contributors = Vec::new();
533        for i in 0..n {
534            let signer = Ed25519::from_seed(i as u64).public_key();
535            contributors.push(signer);
536        }
537        contributors.sort();
538
539        // Create dealer
540        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
541
542        // Create unrelated commitment of correct degree
543        let t = quorum(n);
544        let (_, other_shares) = ops::generate_shares(&mut rng, None, n, t);
545
546        // Create player
547        let mut player = Player::new(
548            contributors[0].clone(),
549            None,
550            contributors.clone(),
551            contributors.clone(),
552            1,
553        );
554
555        // Send valid share to player
556        player
557            .share(contributors[0].clone(), commitment.clone(), shares[0])
558            .unwrap();
559
560        // Send alternative share to player
561        let result = player.share(contributors[0].clone(), commitment, other_shares[0]);
562        assert!(matches!(result, Err(Error::MismatchedShare)));
563    }
564
565    #[test]
566    fn test_duplicate_share() {
567        // Initialize test
568        let n = 5;
569        let mut rng = StdRng::seed_from_u64(0);
570
571        // Create contributors (must be in sorted order)
572        let mut contributors = Vec::new();
573        for i in 0..n {
574            let signer = Ed25519::from_seed(i as u64).public_key();
575            contributors.push(signer);
576        }
577        contributors.sort();
578
579        // Create dealer
580        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
581
582        // Create player
583        let mut player = Player::new(
584            contributors[0].clone(),
585            None,
586            contributors.clone(),
587            contributors.clone(),
588            1,
589        );
590
591        // Send valid share to player
592        player
593            .share(contributors[0].clone(), commitment.clone(), shares[0])
594            .unwrap();
595
596        // Send alternative share to player
597        let result = player.share(contributors[0].clone(), commitment, shares[0]);
598        assert!(matches!(result, Err(Error::DuplicateShare)));
599    }
600
601    #[test]
602    fn test_misdirected_share() {
603        // Initialize test
604        let n = 5;
605        let mut rng = StdRng::seed_from_u64(0);
606
607        // Create contributors (must be in sorted order)
608        let mut contributors = Vec::new();
609        for i in 0..n {
610            let signer = Ed25519::from_seed(i as u64).public_key();
611            contributors.push(signer);
612        }
613        contributors.sort();
614
615        // Create dealer
616        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
617
618        // Create player
619        let mut player = Player::new(
620            contributors[0].clone(),
621            None,
622            contributors.clone(),
623            contributors.clone(),
624            1,
625        );
626
627        // Send misdirected share to player
628        let result = player.share(contributors[0].clone(), commitment.clone(), shares[1]);
629        assert!(matches!(result, Err(Error::MisdirectedShare)));
630    }
631
632    #[test]
633    fn test_invalid_dealer() {
634        // Initialize test
635        let n = 5;
636        let mut rng = StdRng::seed_from_u64(0);
637
638        // Create contributors (must be in sorted order)
639        let mut contributors = Vec::new();
640        for i in 0..n {
641            let signer = Ed25519::from_seed(i as u64).public_key();
642            contributors.push(signer);
643        }
644        contributors.sort();
645
646        // Create dealer
647        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
648
649        // Create player
650        let mut player = Player::new(
651            contributors[0].clone(),
652            None,
653            contributors.clone(),
654            contributors.clone(),
655            1,
656        );
657
658        // Send share from invalid dealer
659        let dealer = Ed25519::from_seed(n as u64).public_key();
660        let result = player.share(dealer.clone(), commitment.clone(), shares[0]);
661        assert!(matches!(result, Err(Error::DealerInvalid)));
662
663        // Create arbiter
664        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
665
666        // Send commitment from invalid dealer
667        let result = arb.commitment(dealer, commitment, vec![0, 1, 2, 3], Vec::new());
668        assert!(matches!(result, Err(Error::DealerInvalid)));
669    }
670
671    #[test]
672    fn test_invalid_commitment_degree() {
673        // Initialize test
674        let n = 5;
675        let mut rng = StdRng::seed_from_u64(0);
676
677        // Create contributors (must be in sorted order)
678        let mut contributors = Vec::new();
679        for i in 0..n {
680            let signer = Ed25519::from_seed(i as u64).public_key();
681            contributors.push(signer);
682        }
683        contributors.sort();
684
685        // Create dealer
686        let (_, _, shares) = Dealer::new(&mut rng, None, contributors.clone());
687
688        // Create invalid commitment
689        let (public, _) = ops::generate_shares(&mut rng, None, n * 2, 1);
690
691        // Create player
692        let mut player = Player::new(
693            contributors[0].clone(),
694            None,
695            contributors.clone(),
696            contributors.clone(),
697            1,
698        );
699
700        // Send invalid commitment to player
701        let result = player.share(contributors[0].clone(), public.clone(), shares[0]);
702        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
703
704        // Create arbiter
705        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
706
707        // Send invalid commitment to arbiter
708        let result = arb.commitment(
709            contributors[0].clone(),
710            public,
711            vec![0, 1, 2, 3, 4],
712            Vec::new(),
713        );
714        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
715    }
716
717    #[test]
718    fn test_reveal() {
719        // Initialize test
720        let n = 5;
721        let mut rng = StdRng::seed_from_u64(0);
722
723        // Create contributors (must be in sorted order)
724        let mut contributors = Vec::new();
725        for i in 0..n {
726            let signer = Ed25519::from_seed(i as u64).public_key();
727            contributors.push(signer);
728        }
729        contributors.sort();
730
731        // Create dealer
732        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
733
734        // Create arbiter
735        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
736
737        // Add commitment to arbiter
738        arb.commitment(
739            contributors[0].clone(),
740            commitment,
741            vec![0, 1, 2, 3],
742            vec![shares[4]],
743        )
744        .unwrap();
745    }
746
747    #[test]
748    fn test_arbiter_reveals() {
749        // Initialize test
750        let n = 11;
751        let q = quorum(n as u32) as usize;
752        let mut rng = StdRng::seed_from_u64(0);
753
754        // Create contributors (must be in sorted order)
755        let mut contributors = Vec::new();
756        for i in 0..n {
757            let signer = Ed25519::from_seed(i as u64).public_key();
758            contributors.push(signer);
759        }
760        contributors.sort();
761
762        // Create arbiter
763        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
764
765        // Create dealers
766        let mut commitments = Vec::with_capacity(n);
767        let mut reveals = Vec::with_capacity(n);
768        for con in &contributors {
769            // Create dealer
770            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
771            commitments.push(commitment.clone());
772            reveals.push(shares[q]);
773
774            // Add commitment to arbiter
775            let acks: Vec<u32> = (0..q as u32).collect();
776            let reveals = shares[q..n].to_vec();
777            arb.commitment(con.clone(), commitment, acks, reveals)
778                .unwrap();
779        }
780
781        // Finalize arbiter
782        let (result, _) = arb.finalize();
783        let output = result.unwrap();
784
785        // Ensure commitments and reveals are correct
786        assert_eq!(output.commitments.len(), q);
787        for (dealer_idx, commitment) in commitments.iter().enumerate().take(q) {
788            let dealer_idx = dealer_idx as u32;
789            assert_eq!(output.commitments.get(&dealer_idx).unwrap(), commitment);
790            assert_eq!(
791                output.reveals.get(&dealer_idx).unwrap()[0],
792                reveals[dealer_idx as usize]
793            );
794        }
795    }
796
797    #[test]
798    fn test_arbiter_best() {}
799
800    #[test]
801    fn test_duplicate_commitment() {
802        // Initialize test
803        let n = 5;
804        let mut rng = StdRng::seed_from_u64(0);
805
806        // Create contributors (must be in sorted order)
807        let mut contributors = Vec::new();
808        for i in 0..n {
809            let signer = Ed25519::from_seed(i as u64).public_key();
810            contributors.push(signer);
811        }
812        contributors.sort();
813
814        // Create dealer
815        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
816
817        // Create arbiter
818        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
819
820        // Add commitment to arbiter
821        arb.commitment(
822            contributors[0].clone(),
823            commitment.clone(),
824            vec![0, 1, 2, 3],
825            vec![shares[4]],
826        )
827        .unwrap();
828
829        // Add commitment to arbiter (again)
830        let result = arb.commitment(
831            contributors[0].clone(),
832            commitment,
833            vec![0, 1, 2, 3],
834            vec![shares[4]],
835        );
836        assert!(matches!(result, Err(Error::DuplicateCommitment)));
837    }
838
839    #[test]
840    fn test_reveal_duplicate_player() {
841        // Initialize test
842        let n = 5;
843        let mut rng = StdRng::seed_from_u64(0);
844
845        // Create contributors (must be in sorted order)
846        let mut contributors = Vec::new();
847        for i in 0..n {
848            let signer = Ed25519::from_seed(i as u64).public_key();
849            contributors.push(signer);
850        }
851        contributors.sort();
852
853        // Create dealer
854        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
855
856        // Create arbiter
857        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
858
859        // Add commitment to arbiter
860        let result = arb.commitment(
861            contributors[0].clone(),
862            commitment,
863            vec![0, 1, 2, 3],
864            vec![shares[3]],
865        );
866        assert!(matches!(result, Err(Error::AlreadyActive)));
867    }
868
869    #[test]
870    fn test_insufficient_active() {
871        // Initialize test
872        let n = 5;
873        let mut rng = StdRng::seed_from_u64(0);
874
875        // Create contributors (must be in sorted order)
876        let mut contributors = Vec::new();
877        for i in 0..n {
878            let signer = Ed25519::from_seed(i as u64).public_key();
879            contributors.push(signer);
880        }
881        contributors.sort();
882
883        // Create dealer
884        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
885
886        // Create arbiter
887        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
888
889        // Add commitment to arbiter
890        let result = arb.commitment(
891            contributors[0].clone(),
892            commitment.clone(),
893            vec![0, 1, 2, 3],
894            Vec::new(),
895        );
896        assert!(matches!(result, Err(Error::IncorrectActive)));
897
898        // Add valid commitment to arbiter after disqualified
899        let result = arb.commitment(
900            contributors[0].clone(),
901            commitment,
902            vec![0, 1, 2, 3, 4],
903            Vec::new(),
904        );
905        assert!(matches!(result, Err(Error::DealerDisqualified)));
906    }
907
908    #[test]
909    fn test_manual_disqualify() {
910        // Initialize test
911        let n = 5;
912        let mut rng = StdRng::seed_from_u64(0);
913
914        // Create contributors (must be in sorted order)
915        let mut contributors = Vec::new();
916        for i in 0..n {
917            let signer = Ed25519::from_seed(i as u64).public_key();
918            contributors.push(signer);
919        }
920        contributors.sort();
921
922        // Create dealer
923        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
924
925        // Create arbiter
926        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
927
928        // Disqualify dealer
929        arb.disqualify(contributors[0].clone());
930
931        // Add valid commitment to arbiter after disqualified
932        let result = arb.commitment(
933            contributors[0].clone(),
934            commitment,
935            vec![0, 1, 2, 3, 4],
936            Vec::new(),
937        );
938        assert!(matches!(result, Err(Error::DealerDisqualified)));
939    }
940
941    #[test]
942    fn test_too_many_reveals() {
943        // Initialize test
944        let n = 5;
945        let mut rng = StdRng::seed_from_u64(0);
946
947        // Create contributors (must be in sorted order)
948        let mut contributors = Vec::new();
949        for i in 0..n {
950            let signer = Ed25519::from_seed(i as u64).public_key();
951            contributors.push(signer);
952        }
953        contributors.sort();
954
955        // Create dealer
956        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
957
958        // Create arbiter
959        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
960
961        // Add commitment to arbiter
962        let result = arb.commitment(
963            contributors[0].clone(),
964            commitment,
965            vec![0, 1, 2],
966            vec![shares[3], shares[4]],
967        );
968        assert!(matches!(result, Err(Error::TooManyReveals)));
969    }
970
971    #[test]
972    fn test_incorrect_reveal() {
973        // Initialize test
974        let n = 5;
975        let mut rng = StdRng::seed_from_u64(0);
976
977        // Create contributors (must be in sorted order)
978        let mut contributors = Vec::new();
979        for i in 0..n {
980            let signer = Ed25519::from_seed(i as u64).public_key();
981            contributors.push(signer);
982        }
983        contributors.sort();
984
985        // Create dealer
986        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
987
988        // Create invalid shares
989        let t = quorum(n);
990        let (_, shares) = ops::generate_shares(&mut rng, None, n, t);
991
992        // Create arbiter
993        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
994
995        // Add commitment to arbiter
996        let result = arb.commitment(
997            contributors[0].clone(),
998            commitment,
999            vec![0, 1, 2, 3],
1000            vec![shares[4]],
1001        );
1002        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1003    }
1004
1005    #[test]
1006    fn test_reveal_corrupt_share() {
1007        // Initialize test
1008        let n = 5;
1009        let mut rng = StdRng::seed_from_u64(0);
1010
1011        // Create contributors (must be in sorted order)
1012        let mut contributors = Vec::new();
1013        for i in 0..n {
1014            let signer = Ed25519::from_seed(i as u64).public_key();
1015            contributors.push(signer);
1016        }
1017        contributors.sort();
1018
1019        // Create dealer
1020        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1021
1022        // Create arbiter
1023        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1024
1025        // Swap share value
1026        let mut share = shares[3];
1027        share.index = 4;
1028
1029        // Add commitment to arbiter
1030        let result = arb.commitment(
1031            contributors[0].clone(),
1032            commitment,
1033            vec![0, 1, 2, 3],
1034            vec![share],
1035        );
1036        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1037    }
1038
1039    #[test]
1040    fn test_reveal_duplicate_ack() {
1041        // Initialize test
1042        let n = 5;
1043        let mut rng = StdRng::seed_from_u64(0);
1044
1045        // Create contributors (must be in sorted order)
1046        let mut contributors = Vec::new();
1047        for i in 0..n {
1048            let signer = Ed25519::from_seed(i as u64).public_key();
1049            contributors.push(signer);
1050        }
1051        contributors.sort();
1052
1053        // Create dealer
1054        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1055
1056        // Create arbiter
1057        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1058
1059        // Add commitment to arbiter
1060        let result = arb.commitment(
1061            contributors[0].clone(),
1062            commitment,
1063            vec![0, 1, 2, 2],
1064            Vec::new(),
1065        );
1066        assert!(matches!(result, Err(Error::AlreadyActive)));
1067    }
1068
1069    #[test]
1070    fn test_reveal_invalid_ack() {
1071        // Initialize test
1072        let n = 5;
1073        let mut rng = StdRng::seed_from_u64(0);
1074
1075        // Create contributors (must be in sorted order)
1076        let mut contributors = Vec::new();
1077        for i in 0..n {
1078            let signer = Ed25519::from_seed(i as u64).public_key();
1079            contributors.push(signer);
1080        }
1081        contributors.sort();
1082
1083        // Create dealer
1084        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1085
1086        // Create arbiter
1087        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1088
1089        // Add commitment to arbiter
1090        let result = arb.commitment(
1091            contributors[0].clone(),
1092            commitment,
1093            vec![0, 1, 2, 10],
1094            Vec::new(),
1095        );
1096        assert!(matches!(result, Err(Error::PlayerInvalid)));
1097    }
1098
1099    #[test]
1100    fn test_reveal_invalid_share() {
1101        // Initialize test
1102        let n = 5;
1103        let mut rng = StdRng::seed_from_u64(0);
1104
1105        // Create contributors (must be in sorted order)
1106        let mut contributors = Vec::new();
1107        for i in 0..n {
1108            let signer = Ed25519::from_seed(i as u64).public_key();
1109            contributors.push(signer);
1110        }
1111        contributors.sort();
1112
1113        // Create dealer
1114        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1115
1116        // Create arbiter
1117        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1118
1119        // Swap share value
1120        let mut share = shares[3];
1121        share.index = 10;
1122
1123        // Add commitment to arbiter
1124        let result = arb.commitment(
1125            contributors[0].clone(),
1126            commitment,
1127            vec![0, 1, 2, 3],
1128            vec![share],
1129        );
1130        assert!(matches!(result, Err(Error::PlayerInvalid)));
1131    }
1132
1133    #[test]
1134    fn test_dealer_acks() {
1135        // Initialize test
1136        let n = 5;
1137        let mut rng = StdRng::seed_from_u64(0);
1138
1139        // Create contributors (must be in sorted order)
1140        let mut contributors = Vec::new();
1141        for i in 0..n {
1142            let signer = Ed25519::from_seed(i as u64).public_key();
1143            contributors.push(signer);
1144        }
1145        contributors.sort();
1146
1147        // Create dealer
1148        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1149
1150        // Ack all players
1151        for player in &contributors {
1152            dealer.ack(player.clone()).unwrap();
1153        }
1154
1155        // Finalize dealer
1156        let output = dealer.finalize().unwrap();
1157        assert_eq!(output.active, vec![0, 1, 2, 3, 4]);
1158        assert!(output.inactive.is_empty());
1159    }
1160
1161    #[test]
1162    fn test_dealer_inactive() {
1163        // Initialize test
1164        let n = 5;
1165        let mut rng = StdRng::seed_from_u64(0);
1166
1167        // Create contributors (must be in sorted order)
1168        let mut contributors = Vec::new();
1169        for i in 0..n {
1170            let signer = Ed25519::from_seed(i as u64).public_key();
1171            contributors.push(signer);
1172        }
1173        contributors.sort();
1174
1175        // Create dealer
1176        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1177
1178        // Ack all players
1179        for player in contributors.iter().take(4) {
1180            dealer.ack(player.clone()).unwrap();
1181        }
1182
1183        // Finalize dealer
1184        let output = dealer.finalize().unwrap();
1185        assert_eq!(output.active, vec![0, 1, 2, 3]);
1186        assert_eq!(output.inactive, vec![4]);
1187    }
1188
1189    #[test]
1190    fn test_dealer_insufficient() {
1191        // Initialize test
1192        let n = 5;
1193        let mut rng = StdRng::seed_from_u64(0);
1194
1195        // Create contributors (must be in sorted order)
1196        let mut contributors = Vec::new();
1197        for i in 0..n {
1198            let signer = Ed25519::from_seed(i as u64).public_key();
1199            contributors.push(signer);
1200        }
1201        contributors.sort();
1202
1203        // Create dealer
1204        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1205
1206        // Ack all players
1207        for player in contributors.iter().take(2) {
1208            dealer.ack(player.clone()).unwrap();
1209        }
1210
1211        // Finalize dealer
1212        assert!(dealer.finalize().is_none());
1213    }
1214
1215    #[test]
1216    fn test_dealer_duplicate_ack() {
1217        // Initialize test
1218        let n = 5;
1219        let mut rng = StdRng::seed_from_u64(0);
1220
1221        // Create contributors (must be in sorted order)
1222        let mut contributors = Vec::new();
1223        for i in 0..n {
1224            let signer = Ed25519::from_seed(i as u64).public_key();
1225            contributors.push(signer);
1226        }
1227        contributors.sort();
1228
1229        // Create dealer
1230        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1231
1232        // Ack player
1233        let player = contributors[0].clone();
1234        dealer.ack(player.clone()).unwrap();
1235
1236        // Ack player (again)
1237        let result = dealer.ack(player);
1238        assert!(matches!(result, Err(Error::DuplicateAck)));
1239    }
1240
1241    #[test]
1242    fn test_dealer_invalid_player() {
1243        // Initialize test
1244        let n = 5;
1245        let mut rng = StdRng::seed_from_u64(0);
1246
1247        // Create contributors (must be in sorted order)
1248        let mut contributors = Vec::new();
1249        for i in 0..n {
1250            let signer = Ed25519::from_seed(i as u64).public_key();
1251            contributors.push(signer);
1252        }
1253        contributors.sort();
1254
1255        // Create dealer
1256        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1257
1258        // Ack invalid player
1259        let player = Ed25519::from_seed(n as u64).public_key();
1260        let result = dealer.ack(player);
1261        assert!(matches!(result, Err(Error::PlayerInvalid)));
1262    }
1263
1264    #[test]
1265    fn test_player_reveals() {
1266        // Initialize test
1267        let n = 11;
1268        let q = quorum(n as u32) as usize;
1269        let mut rng = StdRng::seed_from_u64(0);
1270
1271        // Create contributors (must be in sorted order)
1272        let mut contributors = Vec::new();
1273        for i in 0..n {
1274            let signer = Ed25519::from_seed(i as u64).public_key();
1275            contributors.push(signer);
1276        }
1277        contributors.sort();
1278
1279        // Create player
1280        let mut player = Player::new(
1281            contributors[0].clone(),
1282            None,
1283            contributors.clone(),
1284            contributors.clone(),
1285            1,
1286        );
1287
1288        // Send shares to player
1289        let mut commitments = HashMap::new();
1290        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1291            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1292            player
1293                .share(con.clone(), commitment.clone(), shares[0])
1294                .unwrap();
1295            commitments.insert(i as u32, commitment);
1296        }
1297
1298        // Finalize player with reveal
1299        let last = (q - 1) as u32;
1300        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1301        commitments.insert(last, commitment);
1302        let mut reveals = HashMap::new();
1303        reveals.insert(last, shares[0]);
1304        player.finalize(commitments, reveals).unwrap();
1305    }
1306
1307    #[test]
1308    fn test_player_missing_reveal() {
1309        // Initialize test
1310        let n = 11;
1311        let q = quorum(n as u32) as usize;
1312        let mut rng = StdRng::seed_from_u64(0);
1313
1314        // Create contributors (must be in sorted order)
1315        let mut contributors = Vec::new();
1316        for i in 0..n {
1317            let signer = Ed25519::from_seed(i as u64).public_key();
1318            contributors.push(signer);
1319        }
1320        contributors.sort();
1321
1322        // Create player
1323        let mut player = Player::new(
1324            contributors[0].clone(),
1325            None,
1326            contributors.clone(),
1327            contributors.clone(),
1328            1,
1329        );
1330
1331        // Send shares to player
1332        let mut commitments = HashMap::new();
1333        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1334            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1335            player
1336                .share(con.clone(), commitment.clone(), shares[0])
1337                .unwrap();
1338            commitments.insert(i as u32, commitment);
1339        }
1340
1341        // Finalize player with reveal
1342        let last = (q - 1) as u32;
1343        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1344        commitments.insert(last, commitment);
1345        let result = player.finalize(commitments, HashMap::new());
1346        assert!(matches!(result, Err(Error::MissingShare)));
1347    }
1348
1349    #[test]
1350    fn test_player_insufficient_commitments() {
1351        // Initialize test
1352        let n = 5;
1353        let mut rng = StdRng::seed_from_u64(0);
1354
1355        // Create contributors (must be in sorted order)
1356        let mut contributors = Vec::new();
1357        for i in 0..n {
1358            let signer = Ed25519::from_seed(i as u64).public_key();
1359            contributors.push(signer);
1360        }
1361        contributors.sort();
1362
1363        // Create player
1364        let mut player = Player::new(
1365            contributors[0].clone(),
1366            None,
1367            contributors.clone(),
1368            contributors.clone(),
1369            1,
1370        );
1371
1372        // Send shares to player
1373        let mut commitments = HashMap::new();
1374        for (i, con) in contributors.iter().enumerate().take(2) {
1375            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1376            player
1377                .share(con.clone(), commitment.clone(), shares[0])
1378                .unwrap();
1379            commitments.insert(i as u32, commitment);
1380        }
1381
1382        // Finalize player with reveal
1383        let result = player.finalize(commitments, HashMap::new());
1384        assert!(matches!(result, Err(Error::InvalidCommitments)));
1385    }
1386
1387    #[test]
1388    fn test_player_misdirected_reveal() {
1389        // Initialize test
1390        let n = 11;
1391        let q = quorum(n as u32) as usize;
1392        let mut rng = StdRng::seed_from_u64(0);
1393
1394        // Create contributors (must be in sorted order)
1395        let mut contributors = Vec::new();
1396        for i in 0..n {
1397            let signer = Ed25519::from_seed(i as u64).public_key();
1398            contributors.push(signer);
1399        }
1400        contributors.sort();
1401
1402        // Create player
1403        let mut player = Player::new(
1404            contributors[0].clone(),
1405            None,
1406            contributors.clone(),
1407            contributors.clone(),
1408            1,
1409        );
1410
1411        // Send shares to player
1412        let mut commitments = HashMap::new();
1413        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1414            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1415            player
1416                .share(con.clone(), commitment.clone(), shares[0])
1417                .unwrap();
1418            commitments.insert(i as u32, commitment);
1419        }
1420
1421        // Finalize player with reveal
1422        let last = (q - 1) as u32;
1423        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1424        commitments.insert(last, commitment);
1425        let mut reveals = HashMap::new();
1426        reveals.insert(last, shares[1]);
1427        let result = player.finalize(commitments, reveals);
1428        assert!(matches!(result, Err(Error::MisdirectedShare)));
1429    }
1430
1431    #[test]
1432    fn test_player_invalid_commitment() {
1433        // Initialize test
1434        let n = 11;
1435        let q = quorum(n as u32) as usize;
1436        let mut rng = StdRng::seed_from_u64(0);
1437
1438        // Create contributors (must be in sorted order)
1439        let mut contributors = Vec::new();
1440        for i in 0..n {
1441            let signer = Ed25519::from_seed(i as u64).public_key();
1442            contributors.push(signer);
1443        }
1444        contributors.sort();
1445
1446        // Create player
1447        let mut player = Player::new(
1448            contributors[0].clone(),
1449            None,
1450            contributors.clone(),
1451            contributors.clone(),
1452            1,
1453        );
1454
1455        // Send shares to player
1456        let mut commitments = HashMap::new();
1457        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1458            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1459            player
1460                .share(con.clone(), commitment.clone(), shares[0])
1461                .unwrap();
1462            commitments.insert(i as u32, commitment);
1463        }
1464
1465        // Finalize player with reveal
1466        let last = (q - 1) as u32;
1467        let (commitment, shares) = ops::generate_shares(&mut rng, None, n as u32, 1);
1468        commitments.insert(last, commitment);
1469        let mut reveals = HashMap::new();
1470        reveals.insert(last, shares[0]);
1471        let result = player.finalize(commitments, reveals);
1472        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
1473    }
1474
1475    #[test]
1476    fn test_player_invalid_reveal() {
1477        // Initialize test
1478        let n = 11;
1479        let q = quorum(n as u32) as usize;
1480        let mut rng = StdRng::seed_from_u64(0);
1481
1482        // Create contributors (must be in sorted order)
1483        let mut contributors = Vec::new();
1484        for i in 0..n {
1485            let signer = Ed25519::from_seed(i as u64).public_key();
1486            contributors.push(signer);
1487        }
1488        contributors.sort();
1489
1490        // Create player
1491        let mut player = Player::new(
1492            contributors[0].clone(),
1493            None,
1494            contributors.clone(),
1495            contributors.clone(),
1496            1,
1497        );
1498
1499        // Send shares to player
1500        let mut commitments = HashMap::new();
1501        for (i, con) in contributors.iter().enumerate().take(q - 1) {
1502            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1503            player
1504                .share(con.clone(), commitment.clone(), shares[0])
1505                .unwrap();
1506            commitments.insert(i as u32, commitment);
1507        }
1508
1509        // Finalize player with reveal
1510        let last = (q - 1) as u32;
1511        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1512        commitments.insert(last, commitment);
1513        let mut reveals = HashMap::new();
1514        let mut share = shares[1];
1515        share.index = 0;
1516        reveals.insert(last, share);
1517        let result = player.finalize(commitments, reveals);
1518        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1519    }
1520}