1use core::iter;
38
39use alloc::collections::BTreeMap;
40
41use rand_core::{CryptoRng, RngCore};
42
43use crate::{
44 Challenge, Ciphersuite, Element, Error, Field, Group, Header, Identifier, Scalar, Signature,
45 SigningKey, VerifyingKey,
46};
47
48#[cfg(feature = "serialization")]
49use crate::serialization::{Deserialize, Serialize};
50
51use super::{
52 evaluate_polynomial, generate_coefficients, generate_secret_polynomial,
53 validate_num_of_signers, KeyPackage, PublicKeyPackage, SecretShare, SigningShare,
54 VerifiableSecretSharingCommitment,
55};
56
57pub mod round1 {
59 use alloc::vec::Vec;
60 use derive_getters::Getters;
61 use zeroize::{Zeroize, ZeroizeOnDrop};
62
63 use super::*;
64
65 use crate::serialization::SerializableScalar;
66 #[cfg(feature = "serialization")]
67 use crate::serialization::{Deserialize, Serialize};
68
69 #[derive(Clone, Debug, PartialEq, Eq, Getters)]
72 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73 #[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
74 #[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
75 pub struct Package<C: Ciphersuite> {
76 #[getter(skip)]
78 pub(crate) header: Header<C>,
79 pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
81 pub(crate) proof_of_knowledge: Signature<C>,
83 }
84
85 impl<C> Package<C>
86 where
87 C: Ciphersuite,
88 {
89 pub fn new(
91 commitment: VerifiableSecretSharingCommitment<C>,
92 proof_of_knowledge: Signature<C>,
93 ) -> Self {
94 Self {
95 header: Header::default(),
96 commitment,
97 proof_of_knowledge,
98 }
99 }
100 }
101
102 #[cfg(feature = "serialization")]
103 impl<C> Package<C>
104 where
105 C: Ciphersuite,
106 {
107 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
109 Serialize::serialize(&self)
110 }
111
112 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
114 Deserialize::deserialize(bytes)
115 }
116 }
117
118 #[derive(Clone, PartialEq, Eq, Getters, Zeroize, ZeroizeOnDrop)]
125 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126 #[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
127 #[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
128 pub struct SecretPackage<C: Ciphersuite> {
129 #[zeroize(skip)]
131 pub(crate) identifier: Identifier<C>,
132 #[getter(skip)]
135 pub(crate) coefficients: Vec<SerializableScalar<C>>,
136 #[zeroize(skip)]
138 pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
139 pub(crate) min_signers: u16,
141 pub(crate) max_signers: u16,
143 }
144
145 impl<C> SecretPackage<C>
146 where
147 C: Ciphersuite,
148 {
149 pub fn new(
153 identifier: Identifier<C>,
154 coefficients: Vec<Scalar<C>>,
155 commitment: VerifiableSecretSharingCommitment<C>,
156 min_signers: u16,
157 max_signers: u16,
158 ) -> Self {
159 Self {
160 identifier,
161 coefficients: coefficients.into_iter().map(SerializableScalar).collect(),
162 commitment,
163 min_signers,
164 max_signers,
165 }
166 }
167
168 #[cfg_attr(feature = "internals", visibility::make(pub))]
170 pub(crate) fn coefficients(&self) -> Vec<Scalar<C>> {
171 self.coefficients.iter().map(|s| s.0).collect()
172 }
173 }
174
175 #[cfg(feature = "serialization")]
176 impl<C> SecretPackage<C>
177 where
178 C: Ciphersuite,
179 {
180 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
182 Serialize::serialize(&self)
183 }
184
185 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
187 Deserialize::deserialize(bytes)
188 }
189 }
190
191 impl<C> core::fmt::Debug for SecretPackage<C>
192 where
193 C: Ciphersuite,
194 {
195 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
196 f.debug_struct("SecretPackage")
197 .field("identifier", &self.identifier)
198 .field("coefficients", &"<redacted>")
199 .field("commitment", &self.commitment)
200 .field("min_signers", &self.min_signers)
201 .field("max_signers", &self.max_signers)
202 .finish()
203 }
204 }
205}
206
207pub mod round2 {
209 use derive_getters::Getters;
210 use zeroize::{Zeroize, ZeroizeOnDrop};
211
212 #[cfg(feature = "serialization")]
213 use alloc::vec::Vec;
214
215 use crate::serialization::SerializableScalar;
216
217 use super::*;
218
219 #[derive(Clone, Debug, PartialEq, Eq, Getters, Zeroize, ZeroizeOnDrop)]
227 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
228 #[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
229 #[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
230 pub struct Package<C: Ciphersuite> {
231 #[getter(skip)]
233 pub(crate) header: Header<C>,
234 pub(crate) signing_share: SigningShare<C>,
236 }
237
238 impl<C> Package<C>
239 where
240 C: Ciphersuite,
241 {
242 pub fn new(signing_share: SigningShare<C>) -> Self {
244 Self {
245 header: Header::default(),
246 signing_share,
247 }
248 }
249 }
250
251 #[cfg(feature = "serialization")]
252 impl<C> Package<C>
253 where
254 C: Ciphersuite,
255 {
256 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
258 Serialize::serialize(&self)
259 }
260
261 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
263 Deserialize::deserialize(bytes)
264 }
265 }
266
267 #[derive(Clone, PartialEq, Eq, Getters, Zeroize, ZeroizeOnDrop)]
274 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
275 #[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
276 #[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
277 pub struct SecretPackage<C: Ciphersuite> {
278 #[zeroize(skip)]
280 pub(crate) identifier: Identifier<C>,
281 #[zeroize(skip)]
283 pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
284 #[getter(skip)]
286 pub(crate) secret_share: SerializableScalar<C>,
287 pub(crate) min_signers: u16,
289 pub(crate) max_signers: u16,
291 }
292
293 impl<C> SecretPackage<C>
294 where
295 C: Ciphersuite,
296 {
297 pub fn new(
300 identifier: Identifier<C>,
301 commitment: VerifiableSecretSharingCommitment<C>,
302 secret_share: Scalar<C>,
303 min_signers: u16,
304 max_signers: u16,
305 ) -> Self {
306 Self {
307 identifier,
308 commitment,
309 secret_share: SerializableScalar(secret_share),
310 min_signers,
311 max_signers,
312 }
313 }
314
315 pub fn secret_share(&self) -> Scalar<C> {
317 self.secret_share.0
318 }
319 }
320
321 #[cfg(feature = "serialization")]
322 impl<C> SecretPackage<C>
323 where
324 C: Ciphersuite,
325 {
326 pub fn serialize(&self) -> Result<Vec<u8>, Error<C>> {
328 Serialize::serialize(&self)
329 }
330
331 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
333 Deserialize::deserialize(bytes)
334 }
335 }
336
337 impl<C> core::fmt::Debug for SecretPackage<C>
338 where
339 C: Ciphersuite,
340 {
341 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
342 f.debug_struct("SecretPackage")
343 .field("identifier", &self.identifier)
344 .field("commitment", &self.commitment)
345 .field("secret_share", &"<redacted>")
346 .field("min_signers", &self.min_signers)
347 .field("max_signers", &self.max_signers)
348 .finish()
349 }
350 }
351}
352
353pub fn part1<C: Ciphersuite, R: RngCore + CryptoRng>(
360 identifier: Identifier<C>,
361 max_signers: u16,
362 min_signers: u16,
363 mut rng: R,
364) -> Result<(round1::SecretPackage<C>, round1::Package<C>), Error<C>> {
365 validate_num_of_signers::<C>(min_signers, max_signers)?;
366
367 let secret: SigningKey<C> = SigningKey::new(&mut rng);
368
369 let coefficients = generate_coefficients::<C, R>(min_signers as usize - 1, &mut rng);
378
379 let (coefficients, commitment) =
380 generate_secret_polynomial(&secret, max_signers, min_signers, coefficients)?;
381 let proof_of_knowledge =
382 compute_proof_of_knowledge(identifier, &coefficients, &commitment, &mut rng)?;
383
384 let secret_package = round1::SecretPackage::new(
385 identifier,
386 coefficients,
387 commitment.clone(),
388 min_signers,
389 max_signers,
390 );
391 let package = round1::Package {
392 header: Header::default(),
393 commitment,
394 proof_of_knowledge,
395 };
396
397 Ok((secret_package, package))
398}
399
400fn challenge<C>(
402 identifier: Identifier<C>,
403 verifying_key: &VerifyingKey<C>,
404 R: &Element<C>,
405) -> Result<Challenge<C>, Error<C>>
406where
407 C: Ciphersuite,
408{
409 let mut preimage = vec![];
410
411 preimage.extend_from_slice(identifier.serialize().as_ref());
412 preimage.extend_from_slice(<C::Group>::serialize(&verifying_key.to_element())?.as_ref());
413 preimage.extend_from_slice(<C::Group>::serialize(R)?.as_ref());
414
415 Ok(Challenge(
416 C::HDKG(&preimage[..]).ok_or(Error::DKGNotSupported)?,
417 ))
418}
419
420#[cfg_attr(feature = "internals", visibility::make(pub))]
423pub(crate) fn compute_proof_of_knowledge<C: Ciphersuite, R: RngCore + CryptoRng>(
424 identifier: Identifier<C>,
425 coefficients: &[Scalar<C>],
426 commitment: &VerifiableSecretSharingCommitment<C>,
427 mut rng: R,
428) -> Result<Signature<C>, Error<C>> {
429 let (k, R_i) = <C>::generate_nonce(&mut rng);
436 let c_i = challenge::<C>(identifier, &commitment.verifying_key()?, &R_i)?;
437 let a_i0 = *coefficients.first().ok_or(Error::InvalidCoefficients)?;
438 let mu_i = k + a_i0 * c_i.0;
439 Ok(Signature { R: R_i, z: mu_i })
440}
441
442#[cfg_attr(feature = "internals", visibility::make(pub))]
445pub(crate) fn verify_proof_of_knowledge<C: Ciphersuite>(
446 identifier: Identifier<C>,
447 commitment: &VerifiableSecretSharingCommitment<C>,
448 proof_of_knowledge: &Signature<C>,
449) -> Result<(), Error<C>> {
450 let ell = identifier;
456 let R_ell = proof_of_knowledge.R;
457 let mu_ell = proof_of_knowledge.z;
458 let phi_ell0 = commitment.verifying_key()?;
459 let c_ell = challenge::<C>(ell, &phi_ell0, &R_ell)?;
460 if R_ell != <C::Group>::generator() * mu_ell - phi_ell0.to_element() * c_ell.0 {
461 return Err(Error::InvalidProofOfKnowledge { culprit: ell });
462 }
463 Ok(())
464}
465
466pub fn part2<C: Ciphersuite>(
482 secret_package: round1::SecretPackage<C>,
483 round1_packages: &BTreeMap<Identifier<C>, round1::Package<C>>,
484) -> Result<
485 (
486 round2::SecretPackage<C>,
487 BTreeMap<Identifier<C>, round2::Package<C>>,
488 ),
489 Error<C>,
490> {
491 if round1_packages.len() != (secret_package.max_signers - 1) as usize {
492 return Err(Error::IncorrectNumberOfPackages);
493 }
494
495 if round1_packages.contains_key(&secret_package.identifier) {
496 return Err(Error::UnknownIdentifier);
497 }
498
499 for package in round1_packages.values() {
500 if package.commitment.min_signers() != secret_package.min_signers {
501 return Err(Error::IncorrectNumberOfCommitments);
502 }
503 }
504
505 let mut round2_packages = BTreeMap::new();
506
507 for (sender_identifier, round1_package) in round1_packages {
508 let ell = *sender_identifier;
509 verify_proof_of_knowledge(
511 ell,
512 &round1_package.commitment,
513 &round1_package.proof_of_knowledge,
514 )?;
515
516 let signing_share = SigningShare::from_coefficients(&secret_package.coefficients(), ell);
522
523 round2_packages.insert(
524 ell,
525 round2::Package {
526 header: Header::default(),
527 signing_share,
528 },
529 );
530 }
531 let fii = evaluate_polynomial(secret_package.identifier, &secret_package.coefficients());
532 Ok((
533 round2::SecretPackage::new(
534 secret_package.identifier,
535 secret_package.commitment.clone(),
536 fii,
537 secret_package.min_signers,
538 secret_package.max_signers,
539 ),
540 round2_packages,
541 ))
542}
543
544pub fn part3<C: Ciphersuite>(
562 round2_secret_package: &round2::SecretPackage<C>,
563 round1_packages: &BTreeMap<Identifier<C>, round1::Package<C>>,
564 round2_packages: &BTreeMap<Identifier<C>, round2::Package<C>>,
565) -> Result<(KeyPackage<C>, PublicKeyPackage<C>), Error<C>> {
566 if round1_packages.len() != (round2_secret_package.max_signers - 1) as usize {
567 return Err(Error::IncorrectNumberOfPackages);
568 }
569 if round1_packages.contains_key(&round2_secret_package.identifier) {
570 return Err(Error::UnknownIdentifier);
571 }
572 if round2_packages.contains_key(&round2_secret_package.identifier) {
573 return Err(Error::UnknownIdentifier);
574 }
575 if round1_packages.len() != round2_packages.len() {
576 return Err(Error::IncorrectNumberOfPackages);
577 }
578 if round1_packages
579 .keys()
580 .any(|id| !round2_packages.contains_key(id))
581 {
582 return Err(Error::IncorrectPackage);
583 }
584
585 let mut signing_share = <<C::Group as Group>::Field>::zero();
586
587 for (sender_identifier, round2_package) in round2_packages {
588 let ell = *sender_identifier;
594 let f_ell_i = round2_package.signing_share;
595
596 let commitment = &round1_packages
597 .get(&ell)
598 .ok_or(Error::PackageNotFound)?
599 .commitment;
600
601 let secret_share = SecretShare {
605 header: Header::default(),
606 identifier: round2_secret_package.identifier,
607 signing_share: f_ell_i,
608 commitment: commitment.clone(),
609 };
610
611 let _ = secret_share.verify().map_err(|e| {
614 if let Error::InvalidSecretShare { .. } = e {
615 Error::InvalidSecretShare {
616 culprit: Some(*sender_identifier),
617 }
618 } else {
619 e
620 }
621 })?;
622
623 signing_share = signing_share + f_ell_i.to_scalar();
628 }
629
630 signing_share = signing_share + round2_secret_package.secret_share();
631 let signing_share = SigningShare::new(signing_share);
632
633 let verifying_share = signing_share.into();
637
638 let commitments: BTreeMap<_, _> = round1_packages
639 .iter()
640 .map(|(id, package)| (*id, &package.commitment))
641 .chain(iter::once((
642 round2_secret_package.identifier,
643 &round2_secret_package.commitment,
644 )))
645 .collect();
646 let public_key_package = PublicKeyPackage::from_dkg_commitments(&commitments)?;
647
648 let key_package = KeyPackage {
649 header: Header::default(),
650 identifier: round2_secret_package.identifier,
651 signing_share,
652 verifying_share,
653 verifying_key: public_key_package.verifying_key,
654 min_signers: round2_secret_package.min_signers,
655 };
656
657 C::post_dkg(key_package, public_key_package)
658}