1#![allow(clippy::type_complexity)]
3#![allow(unused_assignments)]
5
6use core::iter;
7
8use alloc::{
9 collections::{BTreeMap, BTreeSet},
10 fmt::{self, Debug},
11 string::ToString,
12 vec::Vec,
13};
14
15use derive_getters::Getters;
16#[cfg(any(test, feature = "test-impl"))]
17use hex::FromHex;
18
19use rand_core::{CryptoRng, RngCore};
20use zeroize::{DefaultIsZeroes, Zeroize, ZeroizeOnDrop};
21
22use crate::{
23 serialization::{SerializableElement, SerializableScalar},
24 Ciphersuite, Element, Error, Field, Group, Header, Identifier, Scalar, SigningKey,
25 VerifyingKey,
26};
27
28#[cfg(feature = "serialization")]
29use crate::serialization::{Deserialize, Serialize};
30
31use super::compute_lagrange_coefficient;
32
33pub mod dkg;
34pub mod refresh;
35pub mod repairable;
36
37#[cfg_attr(feature = "internals", visibility::make(pub))]
40pub(crate) fn sum_commitments<C: Ciphersuite>(
41 commitments: &[&VerifiableSecretSharingCommitment<C>],
42) -> Result<VerifiableSecretSharingCommitment<C>, Error<C>> {
43 let mut group_commitment = vec![
44 CoefficientCommitment::new(<C::Group>::identity());
45 commitments
46 .first()
47 .ok_or(Error::IncorrectNumberOfCommitments)?
48 .0
49 .len()
50 ];
51 for commitment in commitments {
52 for (i, c) in group_commitment.iter_mut().enumerate() {
53 *c = CoefficientCommitment::new(
54 c.value()
55 + commitment
56 .0
57 .get(i)
58 .ok_or(Error::IncorrectNumberOfCommitments)?
59 .value(),
60 );
61 }
62 }
63 Ok(VerifiableSecretSharingCommitment(group_commitment))
64}
65
66pub(crate) fn generate_coefficients<C: Ciphersuite, R: RngCore + CryptoRng>(
68 size: usize,
69 rng: &mut R,
70) -> Vec<Scalar<C>> {
71 iter::repeat_with(|| <<C::Group as Group>::Field>::random(rng))
72 .take(size)
73 .collect()
74}
75
76#[cfg_attr(feature = "internals", visibility::make(pub))]
78pub(crate) fn default_identifiers<C: Ciphersuite>(max_signers: u16) -> Vec<Identifier<C>> {
79 (1..=max_signers)
80 .map(|i| Identifier::<C>::try_from(i).expect("nonzero"))
81 .collect::<Vec<_>>()
82}
83
84#[derive(Clone, Copy, PartialEq, Eq)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
88#[cfg_attr(feature = "serde", serde(transparent))]
89pub struct SigningShare<C: Ciphersuite>(pub(crate) SerializableScalar<C>);
90
91impl<C> SigningShare<C>
92where
93 C: Ciphersuite,
94{
95 #[cfg_attr(feature = "internals", visibility::make(pub))]
97 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
98 pub(crate) fn new(scalar: Scalar<C>) -> Self {
99 Self(SerializableScalar(scalar))
100 }
101
102 #[cfg_attr(feature = "internals", visibility::make(pub))]
104 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
105 pub(crate) fn to_scalar(&self) -> Scalar<C> {
106 self.0 .0
107 }
108
109 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
111 Ok(Self(SerializableScalar::deserialize(bytes)?))
112 }
113
114 pub fn serialize(&self) -> Vec<u8> {
116 self.0.serialize()
117 }
118
119 #[cfg_attr(feature = "internals", visibility::make(pub))]
121 pub(crate) fn from_coefficients(coefficients: &[Scalar<C>], peer: Identifier<C>) -> Self {
122 Self::new(evaluate_polynomial(peer, coefficients))
123 }
124}
125
126impl<C> Debug for SigningShare<C>
127where
128 C: Ciphersuite,
129{
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
131 f.debug_tuple("SigningShare").field(&"<redacted>").finish()
132 }
133}
134
135impl<C> Default for SigningShare<C>
136where
137 C: Ciphersuite,
138{
139 fn default() -> Self {
140 Self::new(<<C::Group as Group>::Field>::zero())
141 }
142}
143
144impl<C> DefaultIsZeroes for SigningShare<C> where C: Ciphersuite {}
146
147#[cfg(any(test, feature = "test-impl"))]
148impl<C> FromHex for SigningShare<C>
149where
150 C: Ciphersuite,
151{
152 type Error = &'static str;
153
154 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
155 let v: Vec<u8> = FromHex::from_hex(hex).map_err(|_| "invalid hex")?;
156 Self::deserialize(&v).map_err(|_| "malformed scalar")
157 }
158}
159
160#[derive(Copy, Clone, PartialEq, Eq)]
162#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
163#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
164#[cfg_attr(feature = "serde", serde(transparent))]
165pub struct VerifyingShare<C>(pub(super) SerializableElement<C>)
166where
167 C: Ciphersuite;
168
169impl<C> VerifyingShare<C>
170where
171 C: Ciphersuite,
172{
173 #[cfg_attr(feature = "internals", visibility::make(pub))]
175 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
176 pub(crate) fn new(element: Element<C>) -> Self {
177 Self(SerializableElement(element))
178 }
179
180 #[cfg_attr(feature = "internals", visibility::make(pub))]
182 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
183 #[allow(dead_code)]
184 pub(crate) fn to_element(&self) -> Element<C> {
185 self.0 .0
186 }
187
188 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
190 Ok(Self(SerializableElement::deserialize(bytes)?))
191 }
192
193 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
195 self.0.serialize()
196 }
197
198 #[cfg_attr(feature = "internals", visibility::make(pub))]
200 pub(crate) fn from_commitment(
201 identifier: Identifier<C>,
202 commitment: &VerifiableSecretSharingCommitment<C>,
203 ) -> VerifyingShare<C> {
204 VerifyingShare::new(evaluate_vss(identifier, commitment))
216 }
217}
218
219impl<C> Debug for VerifyingShare<C>
220where
221 C: Ciphersuite,
222{
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 f.debug_tuple("VerifyingShare")
225 .field(
226 &self
227 .serialize()
228 .map(hex::encode)
229 .unwrap_or("<invalid>".to_string()),
230 )
231 .finish()
232 }
233}
234
235impl<C> From<SigningShare<C>> for VerifyingShare<C>
236where
237 C: Ciphersuite,
238{
239 fn from(secret: SigningShare<C>) -> VerifyingShare<C> {
240 VerifyingShare::new(<C::Group>::generator() * secret.to_scalar())
241 }
242}
243
244#[derive(Clone, Copy, PartialEq, Eq)]
249#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
250#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
251pub struct CoefficientCommitment<C: Ciphersuite>(pub(crate) SerializableElement<C>);
252
253impl<C> CoefficientCommitment<C>
254where
255 C: Ciphersuite,
256{
257 #[cfg_attr(feature = "internals", visibility::make(pub))]
259 pub(crate) fn new(value: Element<C>) -> Self {
260 Self(SerializableElement(value))
261 }
262
263 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
265 Ok(Self(SerializableElement::deserialize(bytes)?))
266 }
267
268 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
270 self.0.serialize()
271 }
272
273 pub fn value(&self) -> Element<C> {
275 self.0 .0
276 }
277}
278
279impl<C> Debug for CoefficientCommitment<C>
280where
281 C: Ciphersuite,
282{
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
284 f.debug_tuple("CoefficientCommitment")
285 .field(
286 &self
287 .serialize()
288 .map(hex::encode)
289 .unwrap_or("<invalid>".to_string()),
290 )
291 .finish()
292 }
293}
294
295#[derive(Clone, Debug, PartialEq, Eq)]
308#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
309#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
310pub struct VerifiableSecretSharingCommitment<C: Ciphersuite>(
311 pub(crate) Vec<CoefficientCommitment<C>>,
312);
313
314impl<C> VerifiableSecretSharingCommitment<C>
315where
316 C: Ciphersuite,
317{
318 #[cfg_attr(feature = "internals", visibility::make(pub))]
320 pub(crate) fn new(coefficients: Vec<CoefficientCommitment<C>>) -> Self {
321 Self(coefficients)
322 }
323
324 pub fn serialize(&self) -> Result<Vec<Vec<u8>>, Error<C>> {
326 self.0
327 .iter()
328 .map(|cc| cc.serialize())
329 .collect::<Result<_, Error<C>>>()
330 }
331
332 pub fn serialize_whole(&self) -> Result<Vec<u8>, Error<C>> {
334 self.serialize().map(|v| v.concat())
335 }
336
337 pub fn deserialize<I, V>(serialized_coefficient_commitments: I) -> Result<Self, Error<C>>
340 where
341 I: IntoIterator<Item = V>,
342 V: AsRef<[u8]>,
343 {
344 let mut coefficient_commitments = Vec::new();
345 for cc in serialized_coefficient_commitments.into_iter() {
346 coefficient_commitments.push(CoefficientCommitment::<C>::deserialize(cc.as_ref())?);
347 }
348
349 Ok(Self::new(coefficient_commitments))
350 }
351
352 pub fn deserialize_whole(bytes: &[u8]) -> Result<Self, Error<C>> {
355 let generator = <C::Group>::generator();
357 let len = <C::Group>::serialize(&generator)
358 .expect("serializing the generator always works")
359 .as_ref()
360 .len();
361
362 let serialized_coefficient_commitments = bytes.chunks_exact(len);
363
364 if !serialized_coefficient_commitments.remainder().is_empty() {
365 return Err(Error::InvalidCoefficient);
366 }
367
368 Self::deserialize(serialized_coefficient_commitments)
369 }
370
371 pub(crate) fn verifying_key(&self) -> Result<VerifyingKey<C>, Error<C>> {
374 Ok(VerifyingKey::new(
375 self.0.first().ok_or(Error::MissingCommitment)?.0 .0,
376 ))
377 }
378
379 #[cfg_attr(feature = "internals", visibility::make(pub))]
381 pub(crate) fn coefficients(&self) -> &[CoefficientCommitment<C>] {
382 &self.0
383 }
384
385 pub(crate) fn min_signers(&self) -> u16 {
387 self.0.len() as u16
388 }
389}
390
391#[derive(Clone, Debug, Zeroize, PartialEq, Eq, Getters, ZeroizeOnDrop)]
403#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
404#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
405#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
406pub struct SecretShare<C: Ciphersuite> {
407 #[getter(skip)]
409 pub(crate) header: Header<C>,
410 #[zeroize(skip)]
412 pub(crate) identifier: Identifier<C>,
413 pub(crate) signing_share: SigningShare<C>,
415 #[zeroize(skip)]
416 pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
418}
419
420impl<C> SecretShare<C>
421where
422 C: Ciphersuite,
423{
424 pub fn new(
426 identifier: Identifier<C>,
427 signing_share: SigningShare<C>,
428 commitment: VerifiableSecretSharingCommitment<C>,
429 ) -> Self {
430 SecretShare {
431 header: Header::default(),
432 identifier,
433 signing_share,
434 commitment,
435 }
436 }
437
438 pub fn verify(&self) -> Result<(VerifyingShare<C>, VerifyingKey<C>), Error<C>> {
453 let f_result = <C::Group>::generator() * self.signing_share.to_scalar();
454 let result = evaluate_vss(self.identifier, &self.commitment);
455
456 if !(f_result == result) {
457 return Err(Error::InvalidSecretShare { culprit: None });
469 }
470
471 Ok((
472 VerifyingShare::new(result),
473 self.commitment.verifying_key()?,
474 ))
475 }
476}
477
478#[cfg(feature = "serialization")]
479impl<C> SecretShare<C>
480where
481 C: Ciphersuite,
482{
483 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
485 Serialize::serialize(&self)
486 }
487
488 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
490 Deserialize::deserialize(bytes)
491 }
492}
493
494pub enum IdentifierList<'a, C: Ciphersuite> {
496 Default,
498 Custom(&'a [Identifier<C>]),
500}
501
502pub fn generate_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
514 max_signers: u16,
515 min_signers: u16,
516 identifiers: IdentifierList<C>,
517 rng: &mut R,
518) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
519 let key = SigningKey::new(rng);
520 split(&key, max_signers, min_signers, identifiers, rng)
521}
522
523pub fn split<C: Ciphersuite, R: RngCore + CryptoRng>(
530 key: &SigningKey<C>,
531 max_signers: u16,
532 min_signers: u16,
533 identifiers: IdentifierList<C>,
534 rng: &mut R,
535) -> Result<(BTreeMap<Identifier<C>, SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
536 validate_num_of_signers(min_signers, max_signers)?;
537
538 if let IdentifierList::Custom(identifiers) = &identifiers {
539 if identifiers.len() != max_signers as usize {
540 return Err(Error::IncorrectNumberOfIdentifiers);
541 }
542 }
543
544 let verifying_key = VerifyingKey::from(key);
545
546 let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, rng);
547
548 let secret_shares = match identifiers {
549 IdentifierList::Default => {
550 let identifiers = default_identifiers(max_signers);
551 generate_secret_shares(key, max_signers, min_signers, coefficients, &identifiers)?
552 }
553 IdentifierList::Custom(identifiers) => {
554 generate_secret_shares(key, max_signers, min_signers, coefficients, identifiers)?
555 }
556 };
557 let mut verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>> = BTreeMap::new();
558 let mut secret_shares_by_id: BTreeMap<Identifier<C>, SecretShare<C>> = BTreeMap::new();
559
560 for secret_share in secret_shares {
561 let signer_public = secret_share.signing_share.into();
562 verifying_shares.insert(secret_share.identifier, signer_public);
563
564 secret_shares_by_id.insert(secret_share.identifier, secret_share);
565 }
566
567 let public_key_package = PublicKeyPackage {
568 header: Header::default(),
569 verifying_shares,
570 verifying_key,
571 min_signers: Some(min_signers),
572 };
573
574 let (processed_secret_shares, processed_public_key_package) =
576 C::post_generate(secret_shares_by_id, public_key_package)?;
577
578 Ok((processed_secret_shares, processed_public_key_package))
579}
580
581fn evaluate_polynomial<C: Ciphersuite>(
588 identifier: Identifier<C>,
589 coefficients: &[Scalar<C>],
590) -> Scalar<C> {
591 let mut value = <<C::Group as Group>::Field>::zero();
592
593 let ell = identifier;
594 for coeff in coefficients.iter().skip(1).rev() {
595 value = value + *coeff;
596 value = value * ell.to_scalar();
597 }
598 value = value
599 + *coefficients
600 .first()
601 .expect("coefficients must have at least one element");
602 value
603}
604
605fn evaluate_vss<C: Ciphersuite>(
611 identifier: Identifier<C>,
612 commitment: &VerifiableSecretSharingCommitment<C>,
613) -> Element<C> {
614 let i = identifier.to_scalar();
615
616 let (_, result) = commitment.0.iter().fold(
617 (<<C::Group as Group>::Field>::one(), <C::Group>::identity()),
618 |(i_to_the_k, sum_so_far), comm_k| {
619 (i * i_to_the_k, sum_so_far + comm_k.value() * i_to_the_k)
620 },
621 );
622 result
623}
624
625#[derive(Clone, Debug, PartialEq, Eq, Getters, Zeroize, ZeroizeOnDrop)]
632#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
633#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
634#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
635pub struct KeyPackage<C: Ciphersuite> {
636 #[getter(skip)]
638 pub(crate) header: Header<C>,
639 #[zeroize(skip)]
641 pub(crate) identifier: Identifier<C>,
642 pub(crate) signing_share: SigningShare<C>,
644 #[zeroize(skip)]
646 pub(crate) verifying_share: VerifyingShare<C>,
647 #[zeroize(skip)]
649 pub(crate) verifying_key: VerifyingKey<C>,
650 pub(crate) min_signers: u16,
651}
652
653impl<C> KeyPackage<C>
654where
655 C: Ciphersuite,
656{
657 pub fn new(
659 identifier: Identifier<C>,
660 signing_share: SigningShare<C>,
661 verifying_share: VerifyingShare<C>,
662 verifying_key: VerifyingKey<C>,
663 min_signers: u16,
664 ) -> Self {
665 Self {
666 header: Header::default(),
667 identifier,
668 signing_share,
669 verifying_share,
670 verifying_key,
671 min_signers,
672 }
673 }
674}
675
676#[cfg(feature = "serialization")]
677impl<C> KeyPackage<C>
678where
679 C: Ciphersuite,
680{
681 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
683 Serialize::serialize(&self)
684 }
685
686 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
688 Deserialize::deserialize(bytes)
689 }
690}
691
692impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
693where
694 C: Ciphersuite,
695{
696 type Error = Error<C>;
697
698 fn try_from(secret_share: SecretShare<C>) -> Result<Self, Error<C>> {
707 let (verifying_share, verifying_key) = secret_share.verify()?;
708
709 Ok(KeyPackage {
710 header: Header::default(),
711 identifier: secret_share.identifier,
712 signing_share: secret_share.signing_share,
713 verifying_share,
714 verifying_key,
715 min_signers: secret_share.commitment.min_signers(),
716 })
717 }
718}
719
720#[derive(Clone, Debug, PartialEq, Eq, Getters)]
725#[cfg_attr(feature = "serde", derive(serde::Serialize))]
726#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
727#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
728pub struct PublicKeyPackage<C: Ciphersuite> {
729 #[getter(skip)]
731 pub(crate) header: Header<C>,
732 pub(crate) verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
735 pub(crate) verifying_key: VerifyingKey<C>,
737 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
740 #[cfg_attr(feature = "serde", serde(default))]
741 #[getter(copy)]
742 pub(crate) min_signers: Option<u16>,
743}
744
745impl<C> PublicKeyPackage<C>
746where
747 C: Ciphersuite,
748{
749 pub fn new(
754 verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
755 verifying_key: VerifyingKey<C>,
756 min_signers: Option<u16>,
757 ) -> Self {
758 Self::new_internal(verifying_shares, verifying_key, min_signers)
759 }
760
761 #[cfg_attr(feature = "internals", visibility::make(pub))]
765 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
766 pub(crate) fn new_internal(
767 verifying_shares: BTreeMap<Identifier<C>, VerifyingShare<C>>,
768 verifying_key: VerifyingKey<C>,
769 min_signers: Option<u16>,
770 ) -> Self {
771 Self {
772 header: Header::default(),
773 verifying_shares,
774 verifying_key,
775 min_signers,
776 }
777 }
778
779 pub fn from_commitment(
784 identifiers: &BTreeSet<Identifier<C>>,
785 commitment: &VerifiableSecretSharingCommitment<C>,
786 ) -> Result<PublicKeyPackage<C>, Error<C>> {
787 let verifying_keys: BTreeMap<_, _> = identifiers
788 .iter()
789 .map(|id| (*id, VerifyingShare::from_commitment(*id, commitment)))
790 .collect();
791 Ok(PublicKeyPackage::new(
792 verifying_keys,
793 VerifyingKey::from_commitment(commitment)?,
794 Some(commitment.min_signers()),
795 ))
796 }
797
798 pub fn from_dkg_commitments(
804 commitments: &BTreeMap<Identifier<C>, &VerifiableSecretSharingCommitment<C>>,
805 ) -> Result<PublicKeyPackage<C>, Error<C>> {
806 let identifiers: BTreeSet<_> = commitments.keys().copied().collect();
807 let commitments: Vec<_> = commitments.values().copied().collect();
808 let group_commitment = sum_commitments(&commitments)?;
809 Self::from_commitment(&identifiers, &group_commitment)
810 }
811
812 pub fn max_signers(&self) -> u16 {
814 self.verifying_shares.len() as u16
815 }
816}
817
818#[cfg(feature = "serialization")]
819impl<C> PublicKeyPackage<C>
820where
821 C: Ciphersuite,
822{
823 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
825 Serialize::serialize(&self)
826 }
827
828 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
830 Deserialize::deserialize(bytes)
831 }
832}
833
834#[cfg_attr(feature = "internals", visibility::make(pub))]
836fn validate_num_of_signers<C: Ciphersuite>(
837 min_signers: u16,
838 max_signers: u16,
839) -> Result<(), Error<C>> {
840 if min_signers < 2 {
841 return Err(Error::InvalidMinSigners);
842 }
843
844 if max_signers < 2 {
845 return Err(Error::InvalidMaxSigners);
846 }
847
848 if min_signers > max_signers {
849 return Err(Error::InvalidMinSigners);
850 }
851
852 Ok(())
853}
854
855pub(crate) fn generate_secret_polynomial<C: Ciphersuite>(
864 secret: &SigningKey<C>,
865 max_signers: u16,
866 min_signers: u16,
867 mut coefficients: Vec<Scalar<C>>,
868) -> Result<(Vec<Scalar<C>>, VerifiableSecretSharingCommitment<C>), Error<C>> {
869 validate_num_of_signers(min_signers, max_signers)?;
870
871 if coefficients.len() != min_signers as usize - 1 {
872 return Err(Error::InvalidCoefficients);
873 }
874
875 coefficients.insert(0, secret.scalar);
877
878 let commitment: Vec<_> = coefficients
880 .iter()
881 .map(|c| CoefficientCommitment::new(<C::Group as Group>::generator() * *c))
882 .collect();
883 let commitment: VerifiableSecretSharingCommitment<C> =
884 VerifiableSecretSharingCommitment(commitment);
885
886 Ok((coefficients, commitment))
887}
888
889pub(crate) fn generate_secret_shares<C: Ciphersuite>(
909 secret: &SigningKey<C>,
910 max_signers: u16,
911 min_signers: u16,
912 coefficients: Vec<Scalar<C>>,
913 identifiers: &[Identifier<C>],
914) -> Result<Vec<SecretShare<C>>, Error<C>> {
915 let mut secret_shares: Vec<SecretShare<C>> = Vec::with_capacity(max_signers as usize);
916
917 let (coefficients, commitment) =
918 generate_secret_polynomial(secret, max_signers, min_signers, coefficients)?;
919
920 let identifiers_set: BTreeSet<_> = identifiers.iter().collect();
921 if identifiers_set.len() != identifiers.len() {
922 return Err(Error::DuplicatedIdentifier);
923 }
924
925 for id in identifiers {
926 let signing_share = SigningShare::from_coefficients(&coefficients, *id);
927
928 secret_shares.push(SecretShare {
929 header: Header::default(),
930 identifier: *id,
931 signing_share,
932 commitment: commitment.clone(),
933 });
934 }
935
936 Ok(secret_shares)
937}
938
939pub fn reconstruct<C: Ciphersuite>(
952 key_packages: &[KeyPackage<C>],
953) -> Result<SigningKey<C>, Error<C>> {
954 if key_packages.is_empty() {
955 return Err(Error::IncorrectNumberOfShares);
956 }
957 let min_signers = key_packages
962 .iter()
963 .map(|k| k.min_signers)
964 .min()
965 .expect("should not be empty since that was just tested");
966 if key_packages.len() < min_signers as usize {
967 return Err(Error::IncorrectNumberOfShares);
968 }
969
970 let mut secret = <<C::Group as Group>::Field>::zero();
971
972 let identifiers: BTreeSet<_> = key_packages
973 .iter()
974 .map(|s| s.identifier())
975 .cloned()
976 .collect();
977
978 if identifiers.len() != key_packages.len() {
979 return Err(Error::DuplicatedIdentifier);
980 }
981
982 for key_package in key_packages.iter() {
984 let lagrange_coefficient =
985 compute_lagrange_coefficient(&identifiers, None, key_package.identifier)?;
986
987 secret = secret + (lagrange_coefficient * key_package.signing_share().to_scalar());
989 }
990
991 Ok(SigningKey { scalar: secret })
992}