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, Scheme};
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).unwrap() 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).unwrap();
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).unwrap() 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).unwrap();
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, 3, 10, 3, 4);
437    }
438
439    #[test]
440    fn test_dkg_and_reshare_min_active_large() {
441        run_dkg_and_reshare(20, 13, 100, 13, 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).unwrap();
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).unwrap();
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).unwrap();
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 = 5;
751        let mut rng = StdRng::seed_from_u64(0);
752
753        // Create contributors (must be in sorted order)
754        let mut contributors = Vec::new();
755        for i in 0..n {
756            let signer = Ed25519::from_seed(i as u64).public_key();
757            contributors.push(signer);
758        }
759        contributors.sort();
760
761        // Create arbiter
762        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
763
764        // Create dealers
765        let mut commitments = Vec::with_capacity(n);
766        let mut reveals = Vec::with_capacity(n);
767        for con in &contributors {
768            // Create dealer
769            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
770            commitments.push(commitment.clone());
771            reveals.push(shares[4]);
772
773            // Add commitment to arbiter
774            arb.commitment(con.clone(), commitment, vec![0, 1, 2, 3], vec![shares[4]])
775                .unwrap();
776        }
777
778        // Finalize arbiter
779        let (result, _) = arb.finalize();
780        let output = result.unwrap();
781
782        // Ensure commitments and reveals are correct
783        assert_eq!(output.commitments.len(), 3);
784        for (dealer_idx, commitment) in commitments.iter().enumerate().take(3) {
785            let dealer_idx = dealer_idx as u32;
786            assert_eq!(output.commitments.get(&dealer_idx).unwrap(), commitment);
787            assert_eq!(
788                output.reveals.get(&dealer_idx).unwrap()[0],
789                reveals[dealer_idx as usize]
790            );
791        }
792    }
793
794    #[test]
795    fn test_arbiter_best() {}
796
797    #[test]
798    fn test_duplicate_commitment() {
799        // Initialize test
800        let n = 5;
801        let mut rng = StdRng::seed_from_u64(0);
802
803        // Create contributors (must be in sorted order)
804        let mut contributors = Vec::new();
805        for i in 0..n {
806            let signer = Ed25519::from_seed(i as u64).public_key();
807            contributors.push(signer);
808        }
809        contributors.sort();
810
811        // Create dealer
812        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
813
814        // Create arbiter
815        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
816
817        // Add commitment to arbiter
818        arb.commitment(
819            contributors[0].clone(),
820            commitment.clone(),
821            vec![0, 1, 2, 3],
822            vec![shares[4]],
823        )
824        .unwrap();
825
826        // Add commitment to arbiter (again)
827        let result = arb.commitment(
828            contributors[0].clone(),
829            commitment,
830            vec![0, 1, 2, 3],
831            vec![shares[4]],
832        );
833        assert!(matches!(result, Err(Error::DuplicateCommitment)));
834    }
835
836    #[test]
837    fn test_reveal_duplicate_player() {
838        // Initialize test
839        let n = 5;
840        let mut rng = StdRng::seed_from_u64(0);
841
842        // Create contributors (must be in sorted order)
843        let mut contributors = Vec::new();
844        for i in 0..n {
845            let signer = Ed25519::from_seed(i as u64).public_key();
846            contributors.push(signer);
847        }
848        contributors.sort();
849
850        // Create dealer
851        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
852
853        // Create arbiter
854        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
855
856        // Add commitment to arbiter
857        let result = arb.commitment(
858            contributors[0].clone(),
859            commitment,
860            vec![0, 1, 2, 3],
861            vec![shares[3]],
862        );
863        assert!(matches!(result, Err(Error::AlreadyActive)));
864    }
865
866    #[test]
867    fn test_insufficient_active() {
868        // Initialize test
869        let n = 5;
870        let mut rng = StdRng::seed_from_u64(0);
871
872        // Create contributors (must be in sorted order)
873        let mut contributors = Vec::new();
874        for i in 0..n {
875            let signer = Ed25519::from_seed(i as u64).public_key();
876            contributors.push(signer);
877        }
878        contributors.sort();
879
880        // Create dealer
881        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
882
883        // Create arbiter
884        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
885
886        // Add commitment to arbiter
887        let result = arb.commitment(
888            contributors[0].clone(),
889            commitment.clone(),
890            vec![0, 1, 2, 3],
891            Vec::new(),
892        );
893        assert!(matches!(result, Err(Error::IncorrectActive)));
894
895        // Add valid commitment to arbiter after disqualified
896        let result = arb.commitment(
897            contributors[0].clone(),
898            commitment,
899            vec![0, 1, 2, 3, 4],
900            Vec::new(),
901        );
902        assert!(matches!(result, Err(Error::DealerDisqualified)));
903    }
904
905    #[test]
906    fn test_manual_disqualify() {
907        // Initialize test
908        let n = 5;
909        let mut rng = StdRng::seed_from_u64(0);
910
911        // Create contributors (must be in sorted order)
912        let mut contributors = Vec::new();
913        for i in 0..n {
914            let signer = Ed25519::from_seed(i as u64).public_key();
915            contributors.push(signer);
916        }
917        contributors.sort();
918
919        // Create dealer
920        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
921
922        // Create arbiter
923        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
924
925        // Disqualify dealer
926        arb.disqualify(contributors[0].clone());
927
928        // Add valid commitment to arbiter after disqualified
929        let result = arb.commitment(
930            contributors[0].clone(),
931            commitment,
932            vec![0, 1, 2, 3, 4],
933            Vec::new(),
934        );
935        assert!(matches!(result, Err(Error::DealerDisqualified)));
936    }
937
938    #[test]
939    fn test_too_many_reveals() {
940        // Initialize test
941        let n = 5;
942        let mut rng = StdRng::seed_from_u64(0);
943
944        // Create contributors (must be in sorted order)
945        let mut contributors = Vec::new();
946        for i in 0..n {
947            let signer = Ed25519::from_seed(i as u64).public_key();
948            contributors.push(signer);
949        }
950        contributors.sort();
951
952        // Create dealer
953        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
954
955        // Create arbiter
956        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
957
958        // Add commitment to arbiter
959        let result = arb.commitment(
960            contributors[0].clone(),
961            commitment,
962            vec![0, 1, 2],
963            vec![shares[3], shares[4]],
964        );
965        assert!(matches!(result, Err(Error::TooManyReveals)));
966    }
967
968    #[test]
969    fn test_incorrect_reveal() {
970        // Initialize test
971        let n = 5;
972        let mut rng = StdRng::seed_from_u64(0);
973
974        // Create contributors (must be in sorted order)
975        let mut contributors = Vec::new();
976        for i in 0..n {
977            let signer = Ed25519::from_seed(i as u64).public_key();
978            contributors.push(signer);
979        }
980        contributors.sort();
981
982        // Create dealer
983        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
984
985        // Create invalid shares
986        let t = quorum(n).unwrap();
987        let (_, shares) = ops::generate_shares(&mut rng, None, n, t);
988
989        // Create arbiter
990        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
991
992        // Add commitment to arbiter
993        let result = arb.commitment(
994            contributors[0].clone(),
995            commitment,
996            vec![0, 1, 2, 3],
997            vec![shares[4]],
998        );
999        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1000    }
1001
1002    #[test]
1003    fn test_reveal_corrupt_share() {
1004        // Initialize test
1005        let n = 5;
1006        let mut rng = StdRng::seed_from_u64(0);
1007
1008        // Create contributors (must be in sorted order)
1009        let mut contributors = Vec::new();
1010        for i in 0..n {
1011            let signer = Ed25519::from_seed(i as u64).public_key();
1012            contributors.push(signer);
1013        }
1014        contributors.sort();
1015
1016        // Create dealer
1017        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1018
1019        // Create arbiter
1020        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1021
1022        // Swap share value
1023        let mut share = shares[3];
1024        share.index = 4;
1025
1026        // Add commitment to arbiter
1027        let result = arb.commitment(
1028            contributors[0].clone(),
1029            commitment,
1030            vec![0, 1, 2, 3],
1031            vec![share],
1032        );
1033        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1034    }
1035
1036    #[test]
1037    fn test_reveal_duplicate_ack() {
1038        // Initialize test
1039        let n = 5;
1040        let mut rng = StdRng::seed_from_u64(0);
1041
1042        // Create contributors (must be in sorted order)
1043        let mut contributors = Vec::new();
1044        for i in 0..n {
1045            let signer = Ed25519::from_seed(i as u64).public_key();
1046            contributors.push(signer);
1047        }
1048        contributors.sort();
1049
1050        // Create dealer
1051        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1052
1053        // Create arbiter
1054        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1055
1056        // Add commitment to arbiter
1057        let result = arb.commitment(
1058            contributors[0].clone(),
1059            commitment,
1060            vec![0, 1, 2, 2],
1061            Vec::new(),
1062        );
1063        assert!(matches!(result, Err(Error::AlreadyActive)));
1064    }
1065
1066    #[test]
1067    fn test_reveal_invalid_ack() {
1068        // Initialize test
1069        let n = 5;
1070        let mut rng = StdRng::seed_from_u64(0);
1071
1072        // Create contributors (must be in sorted order)
1073        let mut contributors = Vec::new();
1074        for i in 0..n {
1075            let signer = Ed25519::from_seed(i as u64).public_key();
1076            contributors.push(signer);
1077        }
1078        contributors.sort();
1079
1080        // Create dealer
1081        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1082
1083        // Create arbiter
1084        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1085
1086        // Add commitment to arbiter
1087        let result = arb.commitment(
1088            contributors[0].clone(),
1089            commitment,
1090            vec![0, 1, 2, 10],
1091            Vec::new(),
1092        );
1093        assert!(matches!(result, Err(Error::PlayerInvalid)));
1094    }
1095
1096    #[test]
1097    fn test_reveal_invalid_share() {
1098        // Initialize test
1099        let n = 5;
1100        let mut rng = StdRng::seed_from_u64(0);
1101
1102        // Create contributors (must be in sorted order)
1103        let mut contributors = Vec::new();
1104        for i in 0..n {
1105            let signer = Ed25519::from_seed(i as u64).public_key();
1106            contributors.push(signer);
1107        }
1108        contributors.sort();
1109
1110        // Create dealer
1111        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1112
1113        // Create arbiter
1114        let mut arb = Arbiter::new(None, contributors.clone(), contributors.clone(), 1);
1115
1116        // Swap share value
1117        let mut share = shares[3];
1118        share.index = 10;
1119
1120        // Add commitment to arbiter
1121        let result = arb.commitment(
1122            contributors[0].clone(),
1123            commitment,
1124            vec![0, 1, 2, 3],
1125            vec![share],
1126        );
1127        assert!(matches!(result, Err(Error::PlayerInvalid)));
1128    }
1129
1130    #[test]
1131    fn test_dealer_acks() {
1132        // Initialize test
1133        let n = 5;
1134        let mut rng = StdRng::seed_from_u64(0);
1135
1136        // Create contributors (must be in sorted order)
1137        let mut contributors = Vec::new();
1138        for i in 0..n {
1139            let signer = Ed25519::from_seed(i as u64).public_key();
1140            contributors.push(signer);
1141        }
1142        contributors.sort();
1143
1144        // Create dealer
1145        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1146
1147        // Ack all players
1148        for player in &contributors {
1149            dealer.ack(player.clone()).unwrap();
1150        }
1151
1152        // Finalize dealer
1153        let output = dealer.finalize().unwrap();
1154        assert_eq!(output.active, vec![0, 1, 2, 3, 4]);
1155        assert!(output.inactive.is_empty());
1156    }
1157
1158    #[test]
1159    fn test_dealer_inactive() {
1160        // Initialize test
1161        let n = 5;
1162        let mut rng = StdRng::seed_from_u64(0);
1163
1164        // Create contributors (must be in sorted order)
1165        let mut contributors = Vec::new();
1166        for i in 0..n {
1167            let signer = Ed25519::from_seed(i as u64).public_key();
1168            contributors.push(signer);
1169        }
1170        contributors.sort();
1171
1172        // Create dealer
1173        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1174
1175        // Ack all players
1176        for player in contributors.iter().take(4) {
1177            dealer.ack(player.clone()).unwrap();
1178        }
1179
1180        // Finalize dealer
1181        let output = dealer.finalize().unwrap();
1182        assert_eq!(output.active, vec![0, 1, 2, 3]);
1183        assert_eq!(output.inactive, vec![4]);
1184    }
1185
1186    #[test]
1187    fn test_dealer_insufficient() {
1188        // Initialize test
1189        let n = 5;
1190        let mut rng = StdRng::seed_from_u64(0);
1191
1192        // Create contributors (must be in sorted order)
1193        let mut contributors = Vec::new();
1194        for i in 0..n {
1195            let signer = Ed25519::from_seed(i as u64).public_key();
1196            contributors.push(signer);
1197        }
1198        contributors.sort();
1199
1200        // Create dealer
1201        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1202
1203        // Ack all players
1204        for player in contributors.iter().take(2) {
1205            dealer.ack(player.clone()).unwrap();
1206        }
1207
1208        // Finalize dealer
1209        assert!(dealer.finalize().is_none());
1210    }
1211
1212    #[test]
1213    fn test_dealer_duplicate_ack() {
1214        // Initialize test
1215        let n = 5;
1216        let mut rng = StdRng::seed_from_u64(0);
1217
1218        // Create contributors (must be in sorted order)
1219        let mut contributors = Vec::new();
1220        for i in 0..n {
1221            let signer = Ed25519::from_seed(i as u64).public_key();
1222            contributors.push(signer);
1223        }
1224        contributors.sort();
1225
1226        // Create dealer
1227        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1228
1229        // Ack player
1230        let player = contributors[0].clone();
1231        dealer.ack(player.clone()).unwrap();
1232
1233        // Ack player (again)
1234        let result = dealer.ack(player);
1235        assert!(matches!(result, Err(Error::DuplicateAck)));
1236    }
1237
1238    #[test]
1239    fn test_dealer_invalid_player() {
1240        // Initialize test
1241        let n = 5;
1242        let mut rng = StdRng::seed_from_u64(0);
1243
1244        // Create contributors (must be in sorted order)
1245        let mut contributors = Vec::new();
1246        for i in 0..n {
1247            let signer = Ed25519::from_seed(i as u64).public_key();
1248            contributors.push(signer);
1249        }
1250        contributors.sort();
1251
1252        // Create dealer
1253        let (mut dealer, _, _) = Dealer::new(&mut rng, None, contributors.clone());
1254
1255        // Ack invalid player
1256        let player = Ed25519::from_seed(n as u64).public_key();
1257        let result = dealer.ack(player);
1258        assert!(matches!(result, Err(Error::PlayerInvalid)));
1259    }
1260
1261    #[test]
1262    fn test_player_reveals() {
1263        // Initialize test
1264        let n = 5;
1265        let mut rng = StdRng::seed_from_u64(0);
1266
1267        // Create contributors (must be in sorted order)
1268        let mut contributors = Vec::new();
1269        for i in 0..n {
1270            let signer = Ed25519::from_seed(i as u64).public_key();
1271            contributors.push(signer);
1272        }
1273        contributors.sort();
1274
1275        // Create player
1276        let mut player = Player::new(
1277            contributors[0].clone(),
1278            None,
1279            contributors.clone(),
1280            contributors.clone(),
1281            1,
1282        );
1283
1284        // Send shares to player
1285        let mut commitments = HashMap::new();
1286        for (i, con) in contributors.iter().enumerate().take(2) {
1287            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1288            player
1289                .share(con.clone(), commitment.clone(), shares[0])
1290                .unwrap();
1291            commitments.insert(i as u32, commitment);
1292        }
1293
1294        // Finalize player with reveal
1295        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1296        commitments.insert(2, commitment);
1297        let mut reveals = HashMap::new();
1298        reveals.insert(2, shares[0]);
1299        player.finalize(commitments, reveals).unwrap();
1300    }
1301
1302    #[test]
1303    fn test_player_missing_reveal() {
1304        // Initialize test
1305        let n = 5;
1306        let mut rng = StdRng::seed_from_u64(0);
1307
1308        // Create contributors (must be in sorted order)
1309        let mut contributors = Vec::new();
1310        for i in 0..n {
1311            let signer = Ed25519::from_seed(i as u64).public_key();
1312            contributors.push(signer);
1313        }
1314        contributors.sort();
1315
1316        // Create player
1317        let mut player = Player::new(
1318            contributors[0].clone(),
1319            None,
1320            contributors.clone(),
1321            contributors.clone(),
1322            1,
1323        );
1324
1325        // Send shares to player
1326        let mut commitments = HashMap::new();
1327        for (i, con) in contributors.iter().enumerate().take(2) {
1328            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1329            player
1330                .share(con.clone(), commitment.clone(), shares[0])
1331                .unwrap();
1332            commitments.insert(i as u32, commitment);
1333        }
1334
1335        // Finalize player with reveal
1336        let (_, commitment, _) = Dealer::new(&mut rng, None, contributors.clone());
1337        commitments.insert(2, commitment);
1338        let result = player.finalize(commitments, HashMap::new());
1339        assert!(matches!(result, Err(Error::MissingShare)));
1340    }
1341
1342    #[test]
1343    fn test_player_insufficient_commitments() {
1344        // Initialize test
1345        let n = 5;
1346        let mut rng = StdRng::seed_from_u64(0);
1347
1348        // Create contributors (must be in sorted order)
1349        let mut contributors = Vec::new();
1350        for i in 0..n {
1351            let signer = Ed25519::from_seed(i as u64).public_key();
1352            contributors.push(signer);
1353        }
1354        contributors.sort();
1355
1356        // Create player
1357        let mut player = Player::new(
1358            contributors[0].clone(),
1359            None,
1360            contributors.clone(),
1361            contributors.clone(),
1362            1,
1363        );
1364
1365        // Send shares to player
1366        let mut commitments = HashMap::new();
1367        for (i, con) in contributors.iter().enumerate().take(2) {
1368            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1369            player
1370                .share(con.clone(), commitment.clone(), shares[0])
1371                .unwrap();
1372            commitments.insert(i as u32, commitment);
1373        }
1374
1375        // Finalize player with reveal
1376        let result = player.finalize(commitments, HashMap::new());
1377        assert!(matches!(result, Err(Error::InvalidCommitments)));
1378    }
1379
1380    #[test]
1381    fn test_player_misdirected_reveal() {
1382        // Initialize test
1383        let n = 5;
1384        let mut rng = StdRng::seed_from_u64(0);
1385
1386        // Create contributors (must be in sorted order)
1387        let mut contributors = Vec::new();
1388        for i in 0..n {
1389            let signer = Ed25519::from_seed(i as u64).public_key();
1390            contributors.push(signer);
1391        }
1392        contributors.sort();
1393
1394        // Create player
1395        let mut player = Player::new(
1396            contributors[0].clone(),
1397            None,
1398            contributors.clone(),
1399            contributors.clone(),
1400            1,
1401        );
1402
1403        // Send shares to player
1404        let mut commitments = HashMap::new();
1405        for (i, con) in contributors.iter().enumerate().take(2) {
1406            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1407            player
1408                .share(con.clone(), commitment.clone(), shares[0])
1409                .unwrap();
1410            commitments.insert(i as u32, commitment);
1411        }
1412
1413        // Finalize player with reveal
1414        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1415        commitments.insert(2, commitment);
1416        let mut reveals = HashMap::new();
1417        reveals.insert(2, shares[1]);
1418        let result = player.finalize(commitments, reveals);
1419        assert!(matches!(result, Err(Error::MisdirectedShare)));
1420    }
1421
1422    #[test]
1423    fn test_player_invalid_commitment() {
1424        // Initialize test
1425        let n = 5;
1426        let mut rng = StdRng::seed_from_u64(0);
1427
1428        // Create contributors (must be in sorted order)
1429        let mut contributors = Vec::new();
1430        for i in 0..n {
1431            let signer = Ed25519::from_seed(i as u64).public_key();
1432            contributors.push(signer);
1433        }
1434        contributors.sort();
1435
1436        // Create player
1437        let mut player = Player::new(
1438            contributors[0].clone(),
1439            None,
1440            contributors.clone(),
1441            contributors.clone(),
1442            1,
1443        );
1444
1445        // Send shares to player
1446        let mut commitments = HashMap::new();
1447        for (i, con) in contributors.iter().enumerate().take(2) {
1448            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1449            player
1450                .share(con.clone(), commitment.clone(), shares[0])
1451                .unwrap();
1452            commitments.insert(i as u32, commitment);
1453        }
1454
1455        // Finalize player with reveal
1456        let (commitment, shares) = ops::generate_shares(&mut rng, None, n, 1);
1457        commitments.insert(2, commitment);
1458        let mut reveals = HashMap::new();
1459        reveals.insert(2, shares[0]);
1460        let result = player.finalize(commitments, reveals);
1461        assert!(matches!(result, Err(Error::CommitmentWrongDegree)));
1462    }
1463
1464    #[test]
1465    fn test_player_invalid_reveal() {
1466        // Initialize test
1467        let n = 5;
1468        let mut rng = StdRng::seed_from_u64(0);
1469
1470        // Create contributors (must be in sorted order)
1471        let mut contributors = Vec::new();
1472        for i in 0..n {
1473            let signer = Ed25519::from_seed(i as u64).public_key();
1474            contributors.push(signer);
1475        }
1476        contributors.sort();
1477
1478        // Create player
1479        let mut player = Player::new(
1480            contributors[0].clone(),
1481            None,
1482            contributors.clone(),
1483            contributors.clone(),
1484            1,
1485        );
1486
1487        // Send shares to player
1488        let mut commitments = HashMap::new();
1489        for (i, con) in contributors.iter().enumerate().take(2) {
1490            let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1491            player
1492                .share(con.clone(), commitment.clone(), shares[0])
1493                .unwrap();
1494            commitments.insert(i as u32, commitment);
1495        }
1496
1497        // Finalize player with reveal
1498        let (_, commitment, shares) = Dealer::new(&mut rng, None, contributors.clone());
1499        commitments.insert(2, commitment);
1500        let mut reveals = HashMap::new();
1501        let mut share = shares[1];
1502        share.index = 0;
1503        reveals.insert(2, share);
1504        let result = player.finalize(commitments, reveals);
1505        assert!(matches!(result, Err(Error::ShareWrongCommitment)));
1506    }
1507}