1#![allow(clippy::type_complexity)]
3
4use core::iter;
5
6use alloc::{
7 collections::{BTreeMap, BTreeSet},
8 fmt::{self, Debug},
9 string::ToString,
10 vec::Vec,
11};
12
13use derive_getters::Getters;
14#[cfg(any(test, feature = "test-impl"))]
15use hex::FromHex;
16
17use rand_core::{CryptoRng, RngCore};
18use zeroize::{DefaultIsZeroes, Zeroize};
19
20use crate::{
21 serialization::{SerializableElement, SerializableScalar},
22 Ciphersuite, Element, Error, Field, Group, Header, Identifier, Scalar, SigningKey,
23 VerifyingKey,
24};
25
26#[cfg(feature = "serialization")]
27use crate::serialization::{Deserialize, Serialize};
28
29use super::compute_lagrange_coefficient;
30
31pub mod dkg;
32pub mod refresh;
33pub mod repairable;
34
35#[cfg_attr(feature = "internals", visibility::make(pub))]
38pub(crate) fn sum_commitments<C: Ciphersuite>(
39 commitments: &[&VerifiableSecretSharingCommitment<C>],
40) -> Result<VerifiableSecretSharingCommitment<C>, Error<C>> {
41 let mut group_commitment = vec![
42 CoefficientCommitment::new(<C::Group>::identity());
43 commitments
44 .first()
45 .ok_or(Error::IncorrectNumberOfCommitments)?
46 .0
47 .len()
48 ];
49 for commitment in commitments {
50 for (i, c) in group_commitment.iter_mut().enumerate() {
51 *c = CoefficientCommitment::new(
52 c.value()
53 + commitment
54 .0
55 .get(i)
56 .ok_or(Error::IncorrectNumberOfCommitments)?
57 .value(),
58 );
59 }
60 }
61 Ok(VerifiableSecretSharingCommitment(group_commitment))
62}
63
64pub(crate) fn generate_coefficients<C: Ciphersuite, R: RngCore + CryptoRng>(
66 size: usize,
67 rng: &mut R,
68) -> Vec<Scalar<C>> {
69 iter::repeat_with(|| <<C::Group as Group>::Field>::random(rng))
70 .take(size)
71 .collect()
72}
73
74#[cfg_attr(feature = "internals", visibility::make(pub))]
76pub(crate) fn default_identifiers<C: Ciphersuite>(max_signers: u16) -> Vec<Identifier<C>> {
77 (1..=max_signers)
78 .map(|i| Identifier::<C>::try_from(i).expect("nonzero"))
79 .collect::<Vec<_>>()
80}
81
82#[derive(Clone, Copy, PartialEq, Eq)]
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
86#[cfg_attr(feature = "serde", serde(transparent))]
87pub struct SigningShare<C: Ciphersuite>(pub(crate) SerializableScalar<C>);
88
89impl<C> SigningShare<C>
90where
91 C: Ciphersuite,
92{
93 #[cfg_attr(feature = "internals", visibility::make(pub))]
95 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
96 pub(crate) fn new(scalar: Scalar<C>) -> Self {
97 Self(SerializableScalar(scalar))
98 }
99
100 #[cfg_attr(feature = "internals", visibility::make(pub))]
102 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
103 pub(crate) fn to_scalar(&self) -> Scalar<C> {
104 self.0 .0
105 }
106
107 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
109 Ok(Self(SerializableScalar::deserialize(bytes)?))
110 }
111
112 pub fn serialize(&self) -> Vec<u8> {
114 self.0.serialize()
115 }
116
117 #[cfg_attr(feature = "internals", visibility::make(pub))]
119 pub(crate) fn from_coefficients(coefficients: &[Scalar<C>], peer: Identifier<C>) -> Self {
120 Self::new(evaluate_polynomial(peer, coefficients))
121 }
122}
123
124impl<C> Debug for SigningShare<C>
125where
126 C: Ciphersuite,
127{
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
129 f.debug_tuple("SigningShare").field(&"<redacted>").finish()
130 }
131}
132
133impl<C> Default for SigningShare<C>
134where
135 C: Ciphersuite,
136{
137 fn default() -> Self {
138 Self::new(<<C::Group as Group>::Field>::zero())
139 }
140}
141
142impl<C> DefaultIsZeroes for SigningShare<C> where C: Ciphersuite {}
144
145#[cfg(any(test, feature = "test-impl"))]
146impl<C> FromHex for SigningShare<C>
147where
148 C: Ciphersuite,
149{
150 type Error = &'static str;
151
152 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
153 let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
154 Self::deserialize(&v).map_err(|_| "malformed scalar")
155 }
156}
157
158#[derive(Copy, Clone, PartialEq, Eq)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
162#[cfg_attr(feature = "serde", serde(transparent))]
163pub struct VerifyingShare<C>(pub(super) SerializableElement<C>)
164where
165 C: Ciphersuite;
166
167impl<C> VerifyingShare<C>
168where
169 C: Ciphersuite,
170{
171 #[cfg_attr(feature = "internals", visibility::make(pub))]
173 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
174 pub(crate) fn new(element: Element<C>) -> Self {
175 Self(SerializableElement(element))
176 }
177
178 #[cfg_attr(feature = "internals", visibility::make(pub))]
180 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
181 #[allow(dead_code)]
182 pub(crate) fn to_element(&self) -> Element<C> {
183 self.0 .0
184 }
185
186 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
188 Ok(Self(SerializableElement::deserialize(bytes)?))
189 }
190
191 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
193 self.0.serialize()
194 }
195
196 #[cfg_attr(feature = "internals", visibility::make(pub))]
198 pub(crate) fn from_commitment(
199 identifier: Identifier<C>,
200 commitment: &VerifiableSecretSharingCommitment<C>,
201 ) -> VerifyingShare<C> {
202 VerifyingShare::new(evaluate_vss(identifier, commitment))
214 }
215}
216
217impl<C> Debug for VerifyingShare<C>
218where
219 C: Ciphersuite,
220{
221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222 f.debug_tuple("VerifyingShare")
223 .field(
224 &self
225 .serialize()
226 .map(hex::encode)
227 .unwrap_or("<invalid>".to_string()),
228 )
229 .finish()
230 }
231}
232
233impl<C> From<SigningShare<C>> for VerifyingShare<C>
234where
235 C: Ciphersuite,
236{
237 fn from(secret: SigningShare<C>) -> VerifyingShare<C> {
238 VerifyingShare::new(<C::Group>::generator() * secret.to_scalar())
239 }
240}
241
242#[derive(Clone, Copy, PartialEq, Eq)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
249pub struct CoefficientCommitment<C: Ciphersuite>(pub(crate) SerializableElement<C>);
250
251impl<C> CoefficientCommitment<C>
252where
253 C: Ciphersuite,
254{
255 #[cfg_attr(feature = "internals", visibility::make(pub))]
257 pub(crate) fn new(value: Element<C>) -> Self {
258 Self(SerializableElement(value))
259 }
260
261 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
263 Ok(Self(SerializableElement::deserialize(bytes)?))
264 }
265
266 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
268 self.0.serialize()
269 }
270
271 pub fn value(&self) -> Element<C> {
273 self.0 .0
274 }
275}
276
277impl<C> Debug for CoefficientCommitment<C>
278where
279 C: Ciphersuite,
280{
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
282 f.debug_tuple("CoefficientCommitment")
283 .field(
284 &self
285 .serialize()
286 .map(hex::encode)
287 .unwrap_or("<invalid>".to_string()),
288 )
289 .finish()
290 }
291}
292
293#[derive(Clone, Debug, PartialEq, Eq)]
306#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
307#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
308pub struct VerifiableSecretSharingCommitment<C: Ciphersuite>(
309 pub(crate) Vec<CoefficientCommitment<C>>,
310);
311
312impl<C> VerifiableSecretSharingCommitment<C>
313where
314 C: Ciphersuite,
315{
316 #[cfg_attr(feature = "internals", visibility::make(pub))]
318 pub(crate) fn new(coefficients: Vec<CoefficientCommitment<C>>) -> Self {
319 Self(coefficients)
320 }
321
322 pub fn serialize(&self) -> Result<Vec<Vec<u8>>, Error<C>> {
324 self.0
325 .iter()
326 .map(|cc| cc.serialize())
327 .collect::<Result<_, Error<C>>>()
328 }
329
330 pub fn serialize_whole(&self) -> Result<Vec<u8>, Error<C>> {
332 self.serialize().map(|v| v.concat())
333 }
334
335 pub fn deserialize<I, V>(serialized_coefficient_commitments: I) -> Result<Self, Error<C>>
338 where
339 I: IntoIterator<Item = V>,
340 V: AsRef<[u8]>,
341 {
342 let mut coefficient_commitments = Vec::new();
343 for cc in serialized_coefficient_commitments.into_iter() {
344 coefficient_commitments.push(CoefficientCommitment::<C>::deserialize(cc.as_ref())?);
345 }
346
347 Ok(Self::new(coefficient_commitments))
348 }
349
350 pub fn deserialize_whole(bytes: &[u8]) -> Result<Self, Error<C>> {
353 let generator = <C::Group>::generator();
355 let len = <C::Group>::serialize(&generator)
356 .expect("serializing the generator always works")
357 .as_ref()
358 .len();
359
360 let serialized_coefficient_commitments = bytes.chunks_exact(len);
361
362 if !serialized_coefficient_commitments.remainder().is_empty() {
363 return Err(Error::InvalidCoefficient);
364 }
365
366 Self::deserialize(serialized_coefficient_commitments)
367 }
368
369 pub(crate) fn verifying_key(&self) -> Result<VerifyingKey<C>, Error<C>> {
372 Ok(VerifyingKey::new(
373 self.0.first().ok_or(Error::MissingCommitment)?.0 .0,
374 ))
375 }
376
377 #[cfg_attr(feature = "internals", visibility::make(pub))]
379 pub(crate) fn coefficients(&self) -> &[CoefficientCommitment<C>] {
380 &self.0
381 }
382}
383
384#[derive(Clone, Debug, Zeroize, PartialEq, Eq, Getters)]
396#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
397#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
398#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
399pub struct SecretShare<C: Ciphersuite> {
400 #[getter(skip)]
402 pub(crate) header: Header<C>,
403 #[zeroize(skip)]
405 pub(crate) identifier: Identifier<C>,
406 pub(crate) signing_share: SigningShare<C>,
408 #[zeroize(skip)]
409 pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
411}
412
413impl<C> SecretShare<C>
414where
415 C: Ciphersuite,
416{
417 pub fn new(
419 identifier: Identifier<C>,
420 signing_share: SigningShare<C>,
421 commitment: VerifiableSecretSharingCommitment<C>,
422 ) -> Self {
423 SecretShare {
424 header: Header::default(),
425 identifier,
426 signing_share,
427 commitment,
428 }
429 }
430
431 pub fn verify(&self) -> Result<(VerifyingShare<C>, VerifyingKey<C>), Error<C>> {
446 let f_result = <C::Group>::generator() * self.signing_share.to_scalar();
447 let result = evaluate_vss(self.identifier, &self.commitment);
448
449 if !(f_result == result) {
450 return Err(Error::InvalidSecretShare { culprit: None });
462 }
463
464 Ok((
465 VerifyingShare::new(result),
466 self.commitment.verifying_key()?,
467 ))
468 }
469}
470
471#[cfg(feature = "serialization")]
472impl<C> SecretShare<C>
473where
474 C: Ciphersuite,
475{
476 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
478 Serialize::serialize(&self)
479 }
480
481 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
483 Deserialize::deserialize(bytes)
484 }
485}
486
487pub enum IdentifierList<'a, C: Ciphersuite> {
489 Default,
491 Custom(&'a [Identifier<C>]),
493}
494
495pub fn generate_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
507 max_signers: u16,
508 min_signers: u16,
509 identifiers: IdentifierList<C>,
510 rng: &mut R,
511) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
512 let key = SigningKey::new(rng);
513 split(&key, max_signers, min_signers, identifiers, rng)
514}
515
516pub fn split<C: Ciphersuite, R: RngCore + CryptoRng>(
523 key: &SigningKey<C>,
524 max_signers: u16,
525 min_signers: u16,
526 identifiers: IdentifierList<C>,
527 rng: &mut R,
528) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
529 validate_num_of_signers(min_signers, max_signers)?;
530
531 if let IdentifierList::Custom(identifiers) = &identifiers {
532 if identifiers.len() != max_signers as usize {
533 return Err(Error::IncorrectNumberOfIdentifiers);
534 }
535 }
536
537 let verifying_key = VerifyingKey::from(key);
538
539 let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, rng);
540
541 let secret_shares = match identifiers {
542 IdentifierList::Default => {
543 let identifiers = default_identifiers(max_signers);
544 generate_secret_shares(key, max_signers, min_signers, coefficients, &identifiers)?
545 }
546 IdentifierList::Custom(identifiers) => {
547 generate_secret_shares(key, max_signers, min_signers, coefficients, identifiers)?
548 }
549 };
550 let mut verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>> = BTreeMap::new();
551 let mut secret_shares_by_id: BTreeMap<Identifier<C>, SecretShare<C>> = BTreeMap::new();
552
553 for secret_share in secret_shares {
554 let signer_public = secret_share.signing_share.into();
555 verifying_shares.insert(secret_share.identifier, signer_public);
556
557 secret_shares_by_id.insert(secret_share.identifier, secret_share);
558 }
559
560 let public_key_package = PublicKeyPackage {
561 header: Header::default(),
562 verifying_shares,
563 verifying_key,
564 };
565
566 let (processed_secret_shares, processed_public_key_package) =
568 C::post_generate(secret_shares_by_id, public_key_package)?;
569
570 Ok((processed_secret_shares, processed_public_key_package))
571}
572
573fn evaluate_polynomial<C: Ciphersuite>(
580 identifier: Identifier<C>,
581 coefficients: &[Scalar<C>],
582) -> Scalar<C> {
583 let mut value = <<C::Group as Group>::Field>::zero();
584
585 let ell = identifier;
586 for coeff in coefficients.iter().skip(1).rev() {
587 value = value + *coeff;
588 value = value * ell.to_scalar();
589 }
590 value = value
591 + *coefficients
592 .first()
593 .expect("coefficients must have at least one element");
594 value
595}
596
597fn evaluate_vss<C: Ciphersuite>(
603 identifier: Identifier<C>,
604 commitment: &VerifiableSecretSharingCommitment<C>,
605) -> Element<C> {
606 let i = identifier.to_scalar();
607
608 let (_, result) = commitment.0.iter().fold(
609 (<<C::Group as Group>::Field>::one(), <C::Group>::identity()),
610 |(i_to_the_k, sum_so_far), comm_k| {
611 (i * i_to_the_k, sum_so_far + comm_k.value() * i_to_the_k)
612 },
613 );
614 result
615}
616
617#[derive(Clone, Debug, PartialEq, Eq, Getters, Zeroize)]
624#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
625#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
626#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
627pub struct KeyPackage<C: Ciphersuite> {
628 #[getter(skip)]
630 pub(crate) header: Header<C>,
631 #[zeroize(skip)]
633 pub(crate) identifier: Identifier<C>,
634 pub(crate) signing_share: SigningShare<C>,
636 #[zeroize(skip)]
638 pub(crate) verifying_share: VerifyingShare<C>,
639 #[zeroize(skip)]
641 pub(crate) verifying_key: VerifyingKey<C>,
642 pub(crate) min_signers: u16,
643}
644
645impl<C> KeyPackage<C>
646where
647 C: Ciphersuite,
648{
649 pub fn new(
651 identifier: Identifier<C>,
652 signing_share: SigningShare<C>,
653 verifying_share: VerifyingShare<C>,
654 verifying_key: VerifyingKey<C>,
655 min_signers: u16,
656 ) -> Self {
657 Self {
658 header: Header::default(),
659 identifier,
660 signing_share,
661 verifying_share,
662 verifying_key,
663 min_signers,
664 }
665 }
666}
667
668#[cfg(feature = "serialization")]
669impl<C> KeyPackage<C>
670where
671 C: Ciphersuite,
672{
673 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
675 Serialize::serialize(&self)
676 }
677
678 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
680 Deserialize::deserialize(bytes)
681 }
682}
683
684impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
685where
686 C: Ciphersuite,
687{
688 type Error = Error<C>;
689
690 fn try_from(secret_share: SecretShare<C>) -> Result<Self, Error<C>> {
699 let (verifying_share, verifying_key) = secret_share.verify()?;
700
701 Ok(KeyPackage {
702 header: Header::default(),
703 identifier: secret_share.identifier,
704 signing_share: secret_share.signing_share,
705 verifying_share,
706 verifying_key,
707 min_signers: secret_share.commitment.0.len() as u16,
708 })
709 }
710}
711
712#[derive(Clone, Debug, PartialEq, Eq, Getters)]
717#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
718#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
719#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
720pub struct PublicKeyPackage<C: Ciphersuite> {
721 #[getter(skip)]
723 pub(crate) header: Header<C>,
724 pub(crate) verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
727 pub(crate) verifying_key: VerifyingKey<C>,
729}
730
731impl<C> PublicKeyPackage<C>
732where
733 C: Ciphersuite,
734{
735 pub fn new(
737 verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
738 verifying_key: VerifyingKey<C>,
739 ) -> Self {
740 Self {
741 header: Header::default(),
742 verifying_shares,
743 verifying_key,
744 }
745 }
746
747 pub fn from_commitment(
752 identifiers: &BTreeSet<Identifier<C>>,
753 commitment: &VerifiableSecretSharingCommitment<C>,
754 ) -> Result<PublicKeyPackage<C>, Error<C>> {
755 let verifying_keys: BTreeMap<_, _> = identifiers
756 .iter()
757 .map(|id| (*id, VerifyingShare::from_commitment(*id, commitment)))
758 .collect();
759 Ok(PublicKeyPackage::new(
760 verifying_keys,
761 VerifyingKey::from_commitment(commitment)?,
762 ))
763 }
764
765 pub fn from_dkg_commitments(
771 commitments: &BTreeMap<Identifier<C>, &VerifiableSecretSharingCommitment<C>>,
772 ) -> Result<PublicKeyPackage<C>, Error<C>> {
773 let identifiers: BTreeSet<_> = commitments.keys().copied().collect();
774 let commitments: Vec<_> = commitments.values().copied().collect();
775 let group_commitment = sum_commitments(&commitments)?;
776 Self::from_commitment(&identifiers, &group_commitment)
777 }
778}
779
780#[cfg(feature = "serialization")]
781impl<C> PublicKeyPackage<C>
782where
783 C: Ciphersuite,
784{
785 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
787 Serialize::serialize(&self)
788 }
789
790 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
792 Deserialize::deserialize(bytes)
793 }
794}
795
796#[cfg_attr(feature = "internals", visibility::make(pub))]
798fn validate_num_of_signers<C: Ciphersuite>(
799 min_signers: u16,
800 max_signers: u16,
801) -> Result<(), Error<C>> {
802 if min_signers < 2 {
803 return Err(Error::InvalidMinSigners);
804 }
805
806 if max_signers < 2 {
807 return Err(Error::InvalidMaxSigners);
808 }
809
810 if min_signers > max_signers {
811 return Err(Error::InvalidMinSigners);
812 }
813
814 Ok(())
815}
816
817pub(crate) fn generate_secret_polynomial<C: Ciphersuite>(
826 secret: &SigningKey<C>,
827 max_signers: u16,
828 min_signers: u16,
829 mut coefficients: Vec<Scalar<C>>,
830) -> Result<(Vec<Scalar<C>>, VerifiableSecretSharingCommitment<C>), Error<C>> {
831 validate_num_of_signers(min_signers, max_signers)?;
832
833 if coefficients.len() != min_signers as usize - 1 {
834 return Err(Error::InvalidCoefficients);
835 }
836
837 coefficients.insert(0, secret.scalar);
839
840 let commitment: Vec<_> = coefficients
842 .iter()
843 .map(|c| CoefficientCommitment::new(<C::Group as Group>::generator() * *c))
844 .collect();
845 let commitment: VerifiableSecretSharingCommitment<C> =
846 VerifiableSecretSharingCommitment(commitment);
847
848 Ok((coefficients, commitment))
849}
850
851pub(crate) fn generate_secret_shares<C: Ciphersuite>(
871 secret: &SigningKey<C>,
872 max_signers: u16,
873 min_signers: u16,
874 coefficients: Vec<Scalar<C>>,
875 identifiers: &[Identifier<C>],
876) -> Result<Vec<SecretShare<C>>, Error<C>> {
877 let mut secret_shares: Vec<SecretShare<C>> = Vec::with_capacity(max_signers as usize);
878
879 let (coefficients, commitment) =
880 generate_secret_polynomial(secret, max_signers, min_signers, coefficients)?;
881
882 let identifiers_set: BTreeSet<_> = identifiers.iter().collect();
883 if identifiers_set.len() != identifiers.len() {
884 return Err(Error::DuplicatedIdentifier);
885 }
886
887 for id in identifiers {
888 let signing_share = SigningShare::from_coefficients(&coefficients, *id);
889
890 secret_shares.push(SecretShare {
891 header: Header::default(),
892 identifier: *id,
893 signing_share,
894 commitment: commitment.clone(),
895 });
896 }
897
898 Ok(secret_shares)
899}
900
901pub fn reconstruct<C: Ciphersuite>(
914 key_packages: &[KeyPackage<C>],
915) -> Result<SigningKey<C>, Error<C>> {
916 if key_packages.is_empty() {
917 return Err(Error::IncorrectNumberOfShares);
918 }
919 let min_signers = key_packages
924 .iter()
925 .map(|k| k.min_signers)
926 .min()
927 .expect("should not be empty since that was just tested");
928 if key_packages.len() < min_signers as usize {
929 return Err(Error::IncorrectNumberOfShares);
930 }
931
932 let mut secret = <<C::Group as Group>::Field>::zero();
933
934 let identifiers: BTreeSet<_> = key_packages
935 .iter()
936 .map(|s| s.identifier())
937 .cloned()
938 .collect();
939
940 if identifiers.len() != key_packages.len() {
941 return Err(Error::DuplicatedIdentifier);
942 }
943
944 for key_package in key_packages.iter() {
946 let lagrange_coefficient =
947 compute_lagrange_coefficient(&identifiers, None, key_package.identifier)?;
948
949 secret = secret + (lagrange_coefficient * key_package.signing_share().to_scalar());
951 }
952
953 Ok(SigningKey { scalar: secret })
954}