1mod round1;
2mod round2;
3mod round3;
4
5use super::*;
6use elliptic_curve::group::GroupEncoding;
7use elliptic_curve::subtle::ConditionallySelectable;
8use elliptic_curve::{Field, Group};
9use elliptic_curve_tools::{SumOfProducts, group, prime_field, prime_field_vec};
10use rand_core::CryptoRng;
11use serde::{Deserialize, Serialize};
12use std::collections::HashSet;
13use std::fmt::{self, Debug, Formatter};
14use std::marker::PhantomData;
15use vsss_rs::{
16 DefaultShare, IdentifierPrimeField, ShareElement, ShareVerifierGroup, ValueGroup,
17 ValuePrimeField, subtle::ConstantTimeEq,
18};
19
20pub type SecretParticipant<G> = Participant<SecretParticipantImpl<G>, G>;
22
23pub type RefreshParticipant<G> = Participant<RefreshParticipantImpl<G>, G>;
25
26pub type SecretShare<F> = DefaultShare<IdentifierPrimeField<F>, IdentifierPrimeField<F>>;
28
29pub type FeldmanShareVerifier<G> = ShareVerifierGroup<G>;
31
32#[derive(Copy, Clone, Debug)]
34pub struct ReconstructionSet<'a, F: ScalarHash> {
35 identifiers: &'a [IdentifierPrimeField<F>],
36}
37
38impl<'a, F: ScalarHash> ReconstructionSet<'a, F> {
39 pub fn new(identifiers: &'a [IdentifierPrimeField<F>]) -> DkgResult<Self> {
41 if identifiers.len() < 2 {
42 return Err(Error::Initialization(
43 "A reconstruction set requires at least 2 participant identifiers".to_string(),
44 ));
45 }
46 if identifiers.iter().any(|id| bool::from(id.is_zero())) {
47 return Err(Error::Initialization(
48 "Reconstruction participant identifiers cannot be zero".to_string(),
49 ));
50 }
51 let unique_identifiers = identifiers.iter().copied().collect::<HashSet<_>>();
52 if unique_identifiers.len() != identifiers.len() {
53 return Err(Error::Initialization(
54 "Reconstruction participant identifiers must be unique".to_string(),
55 ));
56 }
57 Ok(Self { identifiers })
58 }
59
60 pub fn identifiers(&self) -> &[IdentifierPrimeField<F>] {
62 self.identifiers
63 }
64
65 fn contains(&self, identifier: &IdentifierPrimeField<F>) -> bool {
66 self.identifiers.contains(identifier)
67 }
68}
69
70pub trait ParticipantImpl<G>
72where
73 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
74 G::Scalar: ScalarHash,
75{
76 fn get_type(&self) -> ParticipantType;
78 fn random_value(rng: impl CryptoRng) -> G::Scalar;
80 fn check_feldman_verifier(verifier: G) -> bool;
85}
86
87#[derive(Serialize, Deserialize)]
94pub struct Participant<I, G>
95where
96 I: ParticipantImpl<G> + Default,
97 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
98 G::Scalar: ScalarHash,
99{
100 pub(crate) ordinal: usize,
101 #[serde(bound(
102 serialize = "IdentifierPrimeField<G::Scalar>: Serialize",
103 deserialize = "IdentifierPrimeField<G::Scalar>: Deserialize<'de>"
104 ))]
105 pub(crate) id: IdentifierPrimeField<G::Scalar>,
106 pub(crate) threshold: usize,
107 pub(crate) limit: usize,
108 pub(crate) round: Round,
109 pub(crate) completed: bool,
110 #[serde(bound(
111 serialize = "SecretShare<G::Scalar>: Serialize",
112 deserialize = "SecretShare<G::Scalar>: Deserialize<'de>"
113 ))]
114 pub(crate) secret_shares: Vec<SecretShare<G::Scalar>>,
115 #[serde(bound(
116 serialize = "ValueGroup<G>: Serialize",
117 deserialize = "ValueGroup<G>: Deserialize<'de>"
118 ))]
119 pub(crate) feldman_verifiers: Vec<ValueGroup<G>>,
120 #[serde(with = "prime_field")]
121 pub(crate) original_secret: G::Scalar,
122 #[serde(with = "group")]
123 pub(crate) verifying_share: G,
124 #[serde(bound(
125 serialize = "SecretShare<G::Scalar>: Serialize",
126 deserialize = "SecretShare<G::Scalar>: Deserialize<'de>"
127 ))]
128 pub(crate) secret_share: SecretShare<G::Scalar>,
129 #[serde(with = "group")]
130 pub(crate) message_generator: G,
131 #[serde(bound(
132 serialize = "ValueGroup<G>: Serialize",
133 deserialize = "ValueGroup<G>: Deserialize<'de>"
134 ))]
135 pub(crate) public_key: ValueGroup<G>,
136 #[serde(with = "prime_field_vec")]
137 pub(crate) powers_of_i: Vec<G::Scalar>,
138 #[serde(bound(
139 serialize = "Round1Data<G>: Serialize",
140 deserialize = "Round1Data<G>: Deserialize<'de>"
141 ))]
142 pub(crate) received_round1_data: Vec<Option<Round1Data<G>>>,
143 #[serde(bound(
144 serialize = "Round2Data<G::Scalar>: Serialize",
145 deserialize = "Round2Data<G::Scalar>: Deserialize<'de>"
146 ))]
147 pub(crate) received_round2_data: Vec<Option<Round2Data<G::Scalar>>>,
148 #[serde(bound(
149 serialize = "IdentifierPrimeField<G::Scalar>: Serialize",
150 deserialize = "IdentifierPrimeField<G::Scalar>: Deserialize<'de>"
151 ))]
152 pub(crate) all_participant_ids: Vec<IdentifierPrimeField<G::Scalar>>,
153 #[serde(bound(
154 serialize = "IdentifierPrimeField<G::Scalar>: Serialize",
155 deserialize = "IdentifierPrimeField<G::Scalar>: Deserialize<'de>"
156 ))]
157 pub(crate) valid_participant_ids: Vec<Option<IdentifierPrimeField<G::Scalar>>>,
158 pub(crate) participant_impl: I,
159}
160
161impl<I, G> Debug for Participant<I, G>
162where
163 I: ParticipantImpl<G> + Default,
164 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
165 G::Scalar: ScalarHash,
166{
167 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
168 f.debug_struct("Participant")
169 .field("ordinal", &self.ordinal)
170 .field("id", &self.id)
171 .field("threshold", &self.threshold)
172 .field("limit", &self.limit)
173 .field("round", &self.round)
174 .field("completed", &self.completed)
175 .field("feldman_verifiers", &self.feldman_verifiers)
176 .field("public_key", &self.public_key)
177 .field("powers_of_i", &self.powers_of_i)
178 .finish()
179 }
180}
181
182impl<G> Participant<SecretParticipantImpl<G>, G>
183where
184 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
185 G::Scalar: ScalarHash,
186{
187 pub fn new_secret(
189 id: IdentifierPrimeField<G::Scalar>,
190 parameters: &Parameters<G>,
191 ) -> DkgResult<Self> {
192 let rng = rand::rng();
193 let secret = SecretParticipantImpl::<G>::random_value(rng);
194 Self::initialize(id, parameters, IdentifierPrimeField(secret), None)
195 }
196
197 pub fn with_secret(
201 new_identifier: IdentifierPrimeField<G::Scalar>,
202 old_share: &SecretShare<G::Scalar>,
203 parameters: &Parameters<G>,
204 reconstruction_set: &ReconstructionSet<'_, G::Scalar>,
205 ) -> DkgResult<Self> {
206 if !reconstruction_set.contains(&old_share.identifier) {
207 return Err(Error::Initialization(
208 "The old share is not included in the reconstruction set".to_string(),
209 ));
210 }
211 let secret = *old_share.value * *Self::lagrange(old_share, reconstruction_set);
212 Self::initialize(
213 new_identifier,
214 parameters,
215 IdentifierPrimeField(secret),
216 None,
217 )
218 }
219}
220
221impl<G> Participant<RefreshParticipantImpl<G>, G>
222where
223 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
224 G::Scalar: ScalarHash,
225{
226 pub fn new_refresh(
231 id: IdentifierPrimeField<G::Scalar>,
232 existing_share: Option<&SecretShare<G::Scalar>>,
233 parameters: &Parameters<G>,
234 ) -> DkgResult<Self> {
235 if existing_share.is_some_and(|share| share.identifier != id) {
236 return Err(Error::Initialization(
237 "The existing share identifier does not match the refresh participant".to_string(),
238 ));
239 }
240 let secret = existing_share
241 .map(|share| share.value.0)
242 .unwrap_or_else(|| G::Scalar::random(&mut rand::rng()));
243 Self::initialize(
244 id,
245 parameters,
246 IdentifierPrimeField(secret),
247 Some(parameters.message_generator * secret),
248 )
249 }
250}
251
252impl<I, G> Participant<I, G>
253where
254 I: ParticipantImpl<G> + Default,
255 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
256 G::Scalar: ScalarHash,
257{
258 fn initialize(
259 id: IdentifierPrimeField<G::Scalar>,
260 parameters: &Parameters<G>,
261 secret: ValuePrimeField<G::Scalar>,
262 verifying_share: Option<G>,
263 ) -> DkgResult<Self> {
264 let rng = rand::rng();
265
266 let mut powers_of_i = vec![G::Scalar::ONE; parameters.threshold];
267 powers_of_i[1] = *id;
268 for i in 2..parameters.threshold {
269 powers_of_i[i] = powers_of_i[i - 1] * *id;
270 }
271
272 let participant_type = I::default().get_type();
273 let secret_to_split = match participant_type {
274 ParticipantType::Secret => secret,
275 ParticipantType::Refresh => IdentifierPrimeField(G::Scalar::ZERO),
276 };
277
278 let (shares, verifiers) = vsss_rs::feldman::split_secret_with_participant_generators::<
279 SecretShare<G::Scalar>,
280 ShareVerifierGroup<G>,
281 >(
282 parameters.threshold,
283 parameters.limit,
284 &secret_to_split,
285 Some(ValueGroup(parameters.message_generator)),
286 rng,
287 ¶meters.participant_number_generators,
288 )?;
289 let verifiers = verifiers.iter().skip(1).copied().collect::<Vec<_>>();
290
291 let verifying_share = match participant_type {
292 ParticipantType::Secret => verifiers[0].0,
293 ParticipantType::Refresh => verifying_share.ok_or(Error::Initialization(
294 "Verifying share is required for refresh".to_string(),
295 ))?,
296 };
297
298 if verifiers.iter().skip(1).any(|c| c.is_identity().into())
299 || !I::check_feldman_verifier(*verifiers[0])
300 {
301 return Err(Error::Initialization(
302 "Invalid Feldman verifier".to_string(),
303 ));
304 }
305
306 let ordinal = shares
307 .iter()
308 .position(|s| s.identifier == id)
309 .ok_or_else(|| {
310 Error::Initialization(format!(
311 "Invalid participant ID '{id}'; it is not in the generated set of shares"
312 ))
313 })?;
314
315 let all_participant_ids = shares.iter().map(|share| share.identifier).collect();
316 Ok(Self {
317 ordinal,
318 id,
319 threshold: parameters.threshold,
320 limit: parameters.limit,
321 completed: false,
322 round: Round::One,
323 original_secret: secret.0,
324 verifying_share,
325 secret_shares: shares,
326 feldman_verifiers: verifiers,
327 secret_share: SecretShare::<G::Scalar>::default(),
328 message_generator: parameters.message_generator,
329 public_key: ValueGroup::<G>::identity(),
330 powers_of_i,
331 received_round1_data: std::iter::repeat_with(|| None)
332 .take(parameters.limit)
333 .collect(),
334 received_round2_data: std::iter::repeat_with(|| None)
335 .take(parameters.limit)
336 .collect(),
337 all_participant_ids,
338 valid_participant_ids: vec![None; parameters.limit],
339 participant_impl: Default::default(),
340 })
341 }
342
343 pub fn ordinal(&self) -> usize {
345 self.ordinal
346 }
347
348 pub fn id(&self) -> IdentifierPrimeField<G::Scalar> {
350 self.id
351 }
352
353 pub fn completed(&self) -> bool {
355 self.completed
356 }
357
358 pub fn round(&self) -> Round {
360 self.round
361 }
362
363 pub fn threshold(&self) -> usize {
365 self.threshold
366 }
367
368 pub fn limit(&self) -> usize {
370 self.limit
371 }
372
373 pub fn secret_share(&self) -> Option<SecretShare<G::Scalar>> {
377 if self.completed {
378 Some(self.secret_share)
379 } else {
380 None
381 }
382 }
383
384 pub fn public_key(&self) -> Option<G> {
389 if self.completed {
390 Some(*self.public_key)
391 } else {
392 None
393 }
394 }
395
396 pub fn all_participant_ids(&self) -> &[IdentifierPrimeField<G::Scalar>] {
398 &self.all_participant_ids
399 }
400
401 pub fn valid_participant_ids(&self) -> &[Option<IdentifierPrimeField<G::Scalar>>] {
403 &self.valid_participant_ids
404 }
405
406 pub fn feldman_verifiers(&self) -> &[ShareVerifierGroup<G>] {
408 &self.feldman_verifiers
409 }
410
411 pub fn received_round1_data(&self) -> &[Option<Round1Data<G>>] {
413 &self.received_round1_data
414 }
415
416 pub fn received_round2_data(&self) -> &[Option<Round2Data<G::Scalar>>] {
418 &self.received_round2_data
419 }
420
421 pub fn verifying_share(&self) -> G {
423 self.verifying_share
424 }
425
426 pub fn final_transcript_hash(&self) -> [u8; 32] {
428 get_final_transcript_hash(&self.received_round1_data, &self.received_round2_data)
429 }
430
431 pub fn into_output(self) -> DkgResult<DkgOutput<G>> {
435 if !self.completed {
436 return Err(Error::Round(
437 "Protocol is not complete; no output is available".to_string(),
438 ));
439 }
440
441 let transcript_hash =
442 get_final_transcript_hash(&self.received_round1_data, &self.received_round2_data);
443 Ok(DkgOutput {
444 secret_share: self.secret_share,
445 public_key: self.public_key.0,
446 feldman_verifiers: self.feldman_verifiers,
447 participant_ids: self.valid_participant_ids,
448 transcript_hash,
449 })
450 }
451
452 #[deprecated(since = "0.6.0", note = "use `ordinal` instead")]
454 pub fn get_ordinal(&self) -> usize {
455 self.ordinal()
456 }
457
458 #[deprecated(since = "0.6.0", note = "use `id` instead")]
460 pub fn get_id(&self) -> IdentifierPrimeField<G::Scalar> {
461 self.id()
462 }
463
464 #[deprecated(since = "0.6.0", note = "use `round` instead")]
466 pub fn get_round(&self) -> Round {
467 self.round()
468 }
469
470 #[deprecated(since = "0.6.0", note = "use `threshold` instead")]
472 pub fn get_threshold(&self) -> usize {
473 self.threshold()
474 }
475
476 #[deprecated(since = "0.6.0", note = "use `limit` instead")]
478 pub fn get_limit(&self) -> usize {
479 self.limit()
480 }
481
482 #[deprecated(since = "0.6.0", note = "use `secret_share` instead")]
484 pub fn get_secret_share(&self) -> Option<SecretShare<G::Scalar>> {
485 self.secret_share()
486 }
487
488 #[deprecated(since = "0.6.0", note = "use `public_key` instead")]
490 pub fn get_public_key(&self) -> Option<G> {
491 self.public_key()
492 }
493
494 #[deprecated(since = "0.6.0", note = "use `all_participant_ids` instead")]
496 pub fn get_all_participant_ids(&self) -> &[IdentifierPrimeField<G::Scalar>] {
497 self.all_participant_ids()
498 }
499
500 #[deprecated(since = "0.6.0", note = "use `valid_participant_ids` instead")]
502 pub fn get_valid_participant_ids(&self) -> &[Option<IdentifierPrimeField<G::Scalar>>] {
503 self.valid_participant_ids()
504 }
505
506 #[deprecated(since = "0.6.0", note = "use `feldman_verifiers` instead")]
508 pub fn get_feldman_verifiers(&self) -> Vec<ShareVerifierGroup<G>> {
509 self.feldman_verifiers().to_vec()
510 }
511
512 #[deprecated(since = "0.6.0", note = "use `received_round1_data` instead")]
514 pub fn get_received_round1_data(&self) -> &[Option<Round1Data<G>>] {
515 self.received_round1_data()
516 }
517
518 #[deprecated(since = "0.6.0", note = "use `received_round2_data` instead")]
520 pub fn get_received_round2_data(&self) -> &[Option<Round2Data<G::Scalar>>] {
521 self.received_round2_data()
522 }
523
524 pub fn receive(&mut self, data: &[u8]) -> DkgResult<()> {
526 let (&round, payload) = data
527 .split_first()
528 .ok_or_else(|| Error::InvalidMessage("message is empty".to_string()))?;
529 let round = Round::try_from(round).map_err(Error::InvalidMessage)?;
530 match round {
531 Round::One => {
532 let round1_payload = postcard::from_bytes::<Round1Data<G>>(payload)?;
533 self.receive_round1data(round1_payload)
534 }
535 Round::Two => {
536 let round2_payload = postcard::from_bytes::<Round2Data<G::Scalar>>(payload)?;
537 self.receive_round2data(round2_payload)
538 }
539 _ => Err(Error::Round("Protocol is complete".to_string())),
540 }
541 }
542
543 pub fn run(&mut self) -> DkgResult<RoundOutputGenerator<G>> {
545 match self.round {
546 Round::One => self.round1(),
547 Round::Two => self.round2(),
548 Round::Three => self.round3(),
549 Round::Four => Err(Error::Round("Protocol is complete".to_string())),
550 }
551 }
552
553 pub fn advance(&mut self) -> DkgResult<AdvanceResult<G::Scalar>> {
558 match self.run()? {
559 RoundOutputGenerator::Round3 => Ok(AdvanceResult::Complete),
560 output => Ok(AdvanceResult::Messages(output.into_messages()?)),
561 }
562 }
563
564 pub(crate) fn check_sending_participant_id(
565 &self,
566 round: Round,
567 sender_ordinal: usize,
568 sender_id: IdentifierPrimeField<G::Scalar>,
569 ) -> DkgResult<()> {
570 let id = self
571 .all_participant_ids
572 .get(sender_ordinal)
573 .ok_or_else(|| {
574 Error::Round(format!(
575 "Round {round}: Unknown sender ordinal, {sender_ordinal}"
576 ))
577 })?;
578 if *id != sender_id {
579 return Err(Error::Round(format!(
580 "Round {round}: Sender id mismatch, expected '{id}', got '{sender_id}'"
581 )));
582 }
583 if sender_id.is_zero().into() {
584 return Err(Error::Round(format!("Round {round}: Sender id is zero")));
585 }
586 if self.id.ct_eq(&sender_id).into() {
587 return Err(Error::Round(format!(
588 "Round {round}: Sender id is equal to our id",
589 )));
590 }
591 Ok(())
592 }
593
594 pub(crate) fn lagrange(
595 share: &SecretShare<G::Scalar>,
596 reconstruction_set: &ReconstructionSet<'_, G::Scalar>,
597 ) -> ValuePrimeField<G::Scalar> {
598 let mut num = G::Scalar::ONE;
599 let mut den = G::Scalar::ONE;
600 for &x_j in reconstruction_set.identifiers() {
601 if x_j == share.identifier {
602 continue;
603 }
604 num *= *x_j;
605 den *= *x_j - *share.identifier;
606 }
607
608 let den_inverse = den.invert().unwrap_or(G::Scalar::ZERO);
611 IdentifierPrimeField(num * den_inverse)
612 }
613}
614
615#[derive(Default, Clone, Debug, Serialize, Deserialize)]
617pub struct SecretParticipantImpl<G>(PhantomData<G>);
618
619impl<G> ParticipantImpl<G> for SecretParticipantImpl<G>
620where
621 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
622 G::Scalar: ScalarHash,
623{
624 fn get_type(&self) -> ParticipantType {
625 ParticipantType::Secret
626 }
627
628 fn random_value(mut rng: impl CryptoRng) -> <G as Group>::Scalar {
629 G::Scalar::random(&mut rng)
630 }
631
632 fn check_feldman_verifier(verifier: G) -> bool {
633 verifier.is_identity().unwrap_u8() == 0u8
634 }
635}
636
637#[derive(Default, Clone, Debug, Serialize, Deserialize)]
639pub struct RefreshParticipantImpl<G>(PhantomData<G>);
640
641impl<G> ParticipantImpl<G> for RefreshParticipantImpl<G>
642where
643 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
644 G::Scalar: ScalarHash,
645{
646 fn get_type(&self) -> ParticipantType {
647 ParticipantType::Refresh
648 }
649
650 fn random_value(_rng: impl CryptoRng) -> <G as Group>::Scalar {
651 G::Scalar::ZERO
652 }
653
654 fn check_feldman_verifier(verifier: G) -> bool {
655 verifier.is_identity().into()
656 }
657}
658
659pub trait AnyParticipant<G>: Send + Sync + Debug
661where
662 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
663 G::Scalar: ScalarHash,
664{
665 fn ordinal(&self) -> usize;
667 fn id(&self) -> IdentifierPrimeField<G::Scalar>;
669 fn threshold(&self) -> usize;
671 fn limit(&self) -> usize;
673 fn round(&self) -> Round;
675 fn secret_share(&self) -> Option<SecretShare<G::Scalar>>;
677 fn public_key(&self) -> Option<G>;
679 fn valid_participant_ids(&self) -> &[Option<IdentifierPrimeField<G::Scalar>>];
681 fn all_participant_ids(&self) -> &[IdentifierPrimeField<G::Scalar>];
683 fn feldman_verifiers(&self) -> &[ShareVerifierGroup<G>];
685 fn received_round1_data(&self) -> &[Option<Round1Data<G>>];
687 fn received_round2_data(&self) -> &[Option<Round2Data<G::Scalar>>];
689 fn verifying_share(&self) -> G;
691 fn final_transcript_hash(&self) -> [u8; 32];
693 fn completed(&self) -> bool;
695 fn receive(&mut self, data: &[u8]) -> DkgResult<()>;
697 fn run(&mut self) -> DkgResult<RoundOutputGenerator<G>>;
699 fn advance(&mut self) -> DkgResult<AdvanceResult<G::Scalar>>;
701 fn into_output(self: Box<Self>) -> DkgResult<DkgOutput<G>>;
703
704 #[deprecated(since = "0.6.0", note = "use `ordinal` instead")]
706 fn get_ordinal(&self) -> usize {
707 self.ordinal()
708 }
709
710 #[deprecated(since = "0.6.0", note = "use `id` instead")]
712 fn get_id(&self) -> IdentifierPrimeField<G::Scalar> {
713 self.id()
714 }
715
716 #[deprecated(since = "0.6.0", note = "use `threshold` instead")]
718 fn get_threshold(&self) -> usize {
719 self.threshold()
720 }
721
722 #[deprecated(since = "0.6.0", note = "use `limit` instead")]
724 fn get_limit(&self) -> usize {
725 self.limit()
726 }
727
728 #[deprecated(since = "0.6.0", note = "use `round` instead")]
730 fn get_round(&self) -> Round {
731 self.round()
732 }
733
734 #[deprecated(since = "0.6.0", note = "use `secret_share` instead")]
736 fn get_secret_share(&self) -> Option<SecretShare<G::Scalar>> {
737 self.secret_share()
738 }
739
740 #[deprecated(since = "0.6.0", note = "use `public_key` instead")]
742 fn get_public_key(&self) -> Option<G> {
743 self.public_key()
744 }
745
746 #[deprecated(since = "0.6.0", note = "use `valid_participant_ids` instead")]
748 fn get_valid_participant_ids(&self) -> &[Option<IdentifierPrimeField<G::Scalar>>] {
749 self.valid_participant_ids()
750 }
751
752 #[deprecated(since = "0.6.0", note = "use `all_participant_ids` instead")]
754 fn get_all_participant_ids(&self) -> &[IdentifierPrimeField<G::Scalar>] {
755 self.all_participant_ids()
756 }
757
758 #[deprecated(since = "0.6.0", note = "use `feldman_verifiers` instead")]
760 fn get_feldman_verifiers(&self) -> Vec<ShareVerifierGroup<G>> {
761 self.feldman_verifiers().to_vec()
762 }
763
764 #[deprecated(since = "0.6.0", note = "use `received_round1_data` instead")]
766 fn get_received_round1_data(&self) -> &[Option<Round1Data<G>>] {
767 self.received_round1_data()
768 }
769
770 #[deprecated(since = "0.6.0", note = "use `received_round2_data` instead")]
772 fn get_received_round2_data(&self) -> &[Option<Round2Data<G::Scalar>>] {
773 self.received_round2_data()
774 }
775
776 #[deprecated(since = "0.6.0", note = "use `verifying_share` instead")]
778 fn get_verifying_share(&self) -> G {
779 self.verifying_share()
780 }
781
782 #[deprecated(since = "0.6.0", note = "use `final_transcript_hash` instead")]
784 fn get_final_transcript_hash(&self) -> [u8; 32] {
785 self.final_transcript_hash()
786 }
787}
788
789impl<I, G> AnyParticipant<G> for Participant<I, G>
790where
791 I: ParticipantImpl<G> + Default + Send + Sync,
792 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
793 G::Scalar: ScalarHash,
794{
795 fn ordinal(&self) -> usize {
796 self.ordinal
797 }
798
799 fn id(&self) -> IdentifierPrimeField<G::Scalar> {
800 self.id
801 }
802
803 fn threshold(&self) -> usize {
804 self.threshold
805 }
806
807 fn limit(&self) -> usize {
808 self.limit
809 }
810
811 fn round(&self) -> Round {
812 self.round
813 }
814
815 fn secret_share(&self) -> Option<SecretShare<G::Scalar>> {
816 self.secret_share()
817 }
818
819 fn public_key(&self) -> Option<G> {
820 self.public_key()
821 }
822
823 fn valid_participant_ids(&self) -> &[Option<IdentifierPrimeField<G::Scalar>>] {
824 &self.valid_participant_ids
825 }
826
827 fn all_participant_ids(&self) -> &[IdentifierPrimeField<G::Scalar>] {
828 &self.all_participant_ids
829 }
830
831 fn feldman_verifiers(&self) -> &[ShareVerifierGroup<G>] {
832 &self.feldman_verifiers
833 }
834
835 fn received_round1_data(&self) -> &[Option<Round1Data<G>>] {
836 &self.received_round1_data
837 }
838
839 fn received_round2_data(&self) -> &[Option<Round2Data<G::Scalar>>] {
840 &self.received_round2_data
841 }
842
843 fn verifying_share(&self) -> G {
844 self.verifying_share
845 }
846
847 fn final_transcript_hash(&self) -> [u8; 32] {
848 get_final_transcript_hash(&self.received_round1_data, &self.received_round2_data)
849 }
850
851 fn completed(&self) -> bool {
852 self.completed()
853 }
854
855 fn receive(&mut self, data: &[u8]) -> DkgResult<()> {
856 self.receive(data)
857 }
858
859 fn run(&mut self) -> DkgResult<RoundOutputGenerator<G>> {
860 self.run()
861 }
862
863 fn advance(&mut self) -> DkgResult<AdvanceResult<G::Scalar>> {
864 self.advance()
865 }
866
867 fn into_output(self: Box<Self>) -> DkgResult<DkgOutput<G>> {
868 (*self).into_output()
869 }
870}
871
872fn get_final_transcript_hash<G>(
873 received_round1_data: &[Option<Round1Data<G>>],
874 received_round2_data: &[Option<Round2Data<G::Scalar>>],
875) -> [u8; 32]
876where
877 G: SumOfProducts + GroupEncoding + Default + ConditionallySelectable,
878 G::Scalar: ScalarHash,
879{
880 let mut transcript = merlin::Transcript::new(b"Frost DKG - Final Transcript");
881 for round1data in received_round1_data.iter().flatten() {
882 round1data.add_to_transcript(&mut transcript);
883 }
884 for round2data in received_round2_data.iter().flatten() {
885 round2data.add_to_transcript(&mut transcript);
886 }
887 let mut transcript_hash = [0u8; 32];
888 transcript.challenge_bytes(b"final result", &mut transcript_hash);
889 transcript_hash
890}
891
892#[cfg(test)]
893mod tests {
894 use super::*;
895 use k256::{ProjectivePoint, Scalar};
896 use std::num::NonZeroUsize;
897 use vsss_rs::Share;
898
899 #[test]
900 fn receive_rejects_empty_message() {
901 let parameters = Parameters::new(
902 NonZeroUsize::new(2).expect("threshold is non-zero"),
903 NonZeroUsize::new(2).expect("limit is non-zero"),
904 )
905 .expect("valid parameters");
906 let mut participant = SecretParticipant::<ProjectivePoint>::new_secret(
907 IdentifierPrimeField::ONE,
908 ¶meters,
909 )
910 .expect("create participant");
911
912 let result = participant.receive(&[]);
913
914 assert!(
915 matches!(result, Err(Error::InvalidMessage(message)) if message == "message is empty")
916 );
917 }
918
919 #[test]
920 fn debug_redacts_secret_state() {
921 let parameters = Parameters::new(
922 NonZeroUsize::new(2).expect("threshold is non-zero"),
923 NonZeroUsize::new(2).expect("limit is non-zero"),
924 )
925 .expect("valid parameters");
926 let participant = SecretParticipant::<ProjectivePoint>::new_secret(
927 IdentifierPrimeField::ONE,
928 ¶meters,
929 )
930 .expect("create participant");
931
932 assert_eq!(participant.feldman_verifiers().len(), 2);
933 let debug = format!("{participant:?}");
934
935 assert!(!debug.contains("original_secret"));
936 assert!(!debug.contains("secret_share"));
937 assert!(!debug.contains("secret_shares"));
938 assert!(!debug.contains("received_round2_data"));
939 }
940
941 #[test]
942 fn output_is_unavailable_before_completion() {
943 let parameters = Parameters::new(
944 NonZeroUsize::new(2).expect("threshold is non-zero"),
945 NonZeroUsize::new(2).expect("limit is non-zero"),
946 )
947 .expect("valid parameters");
948 let participant = SecretParticipant::<ProjectivePoint>::new_secret(
949 IdentifierPrimeField::ONE,
950 ¶meters,
951 )
952 .expect("create participant");
953
954 let result = participant.into_output();
955
956 assert!(matches!(result, Err(Error::Round(message)) if message.contains("not complete")));
957 }
958
959 #[test]
960 fn reconstruction_set_rejects_duplicate_identifiers() {
961 let identifier = IdentifierPrimeField(Scalar::ONE);
962 let identifiers = [identifier, identifier];
963
964 let result = ReconstructionSet::new(&identifiers);
965
966 assert!(matches!(result, Err(Error::Initialization(_))));
967 }
968
969 #[test]
970 fn refresh_rejects_a_share_with_a_different_identifier() {
971 let parameters = Parameters::new(
972 NonZeroUsize::new(2).expect("threshold is non-zero"),
973 NonZeroUsize::new(2).expect("limit is non-zero"),
974 )
975 .expect("valid parameters");
976 let share = SecretShare::with_identifier_and_value(
977 IdentifierPrimeField(Scalar::ONE),
978 IdentifierPrimeField(Scalar::ONE),
979 );
980
981 let result = RefreshParticipant::<ProjectivePoint>::new_refresh(
982 IdentifierPrimeField(Scalar::from(2u64)),
983 Some(&share),
984 ¶meters,
985 );
986
987 assert!(
988 matches!(result, Err(Error::Initialization(message)) if message.contains("does not match"))
989 );
990 }
991
992 #[test]
993 fn resharing_rejects_a_share_missing_from_the_reconstruction_set() {
994 let parameters = Parameters::new(
995 NonZeroUsize::new(2).expect("threshold is non-zero"),
996 NonZeroUsize::new(3).expect("limit is non-zero"),
997 )
998 .expect("valid parameters");
999 let share = SecretShare::with_identifier_and_value(
1000 IdentifierPrimeField(Scalar::ONE),
1001 IdentifierPrimeField(Scalar::ONE),
1002 );
1003 let identifiers = [
1004 IdentifierPrimeField(Scalar::from(2u64)),
1005 IdentifierPrimeField(Scalar::from(3u64)),
1006 ];
1007 let reconstruction_set =
1008 ReconstructionSet::new(&identifiers).expect("valid reconstruction set");
1009
1010 let result = SecretParticipant::<ProjectivePoint>::with_secret(
1011 IdentifierPrimeField::ONE,
1012 &share,
1013 ¶meters,
1014 &reconstruction_set,
1015 );
1016
1017 assert!(
1018 matches!(result, Err(Error::Initialization(message)) if message.contains("not included"))
1019 );
1020 }
1021}