1#![deny(
34 unsafe_code,
35 missing_docs,
36 missing_debug_implementations,
37 unused_qualifications,
38 unused_import_braces,
39 clippy::unwrap_used
40)]
41#![warn(
42 clippy::cast_precision_loss,
43 clippy::checked_conversions,
44 clippy::implicit_saturating_sub,
45 clippy::mod_module_files,
46 clippy::panic,
47 clippy::panic_in_result_fn,
48 rust_2018_idioms,
49 unused_lifetimes
50)]
51
52#[macro_use]
53mod macros;
54mod error;
55mod identifier;
56#[cfg(not(feature = "verify_only"))]
57mod key_package;
58mod signature;
59mod signature_share;
60mod signing_commitments;
61mod signing_nonces;
62#[cfg(not(feature = "verify_only"))]
63mod signing_share;
64mod verifying_key;
65mod verifying_share;
66
67use lit_rust_crypto::*;
68pub use lit_rust_crypto::{
69 self, curve25519_dalek, decaf377, ed448_goldilocks, jubjub, k256, p256, p384, vsss_rs,
70};
71
72pub use ed25519_dalek;
73pub use schnorrkel;
74
75pub use error::*;
76pub use identifier::Identifier;
77#[cfg(not(feature = "verify_only"))]
78pub use key_package::KeyPackage;
79pub use signature::Signature;
80pub use signature_share::SignatureShare;
81pub use signing_commitments::SigningCommitments;
82pub use signing_nonces::SigningNonces;
83#[cfg(not(feature = "verify_only"))]
84pub use signing_share::SigningShare;
85pub use verifying_key::VerifyingKey;
86pub use verifying_share::VerifyingShare;
87
88#[cfg(not(feature = "verify_only"))]
89use core::num::NonZeroU8;
90use frost_core::Ciphersuite;
91#[cfg(not(feature = "verify_only"))]
92use rand_core::{CryptoRng, RngCore};
93use serde::{Deserialize, Deserializer, Serialize, Serializer};
94use sha2::{Digest, Sha256};
95use std::{
96 collections::BTreeMap,
97 fmt::{self, Debug, Display, Formatter},
98 str::FromStr,
99};
100
101#[cfg(not(feature = "verify_only"))]
102pub fn red_jubjub_generator() -> jubjub::SubgroupPoint {
104 <frost_redjubjub::JubjubGroup as frost_core::Group>::generator()
105}
106
107
108#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, Default)]
110#[repr(u8)]
111pub enum Scheme {
112 #[default]
113 Ed25519Sha512 = 1,
115 Ed448Shake256 = 2,
117 Ristretto25519Sha512 = 3,
119 K256Sha256 = 4,
121 P256Sha256 = 5,
123 P384Sha384 = 6,
125 RedJubjubBlake2b512 = 7,
127 K256Taproot = 8,
129 RedDecaf377Blake2b512 = 9,
131 SchnorrkelSubstrate = 10,
134 RedPallasBlake2b512 = 11,
136}
137
138impl Display for Scheme {
139 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
140 write!(f, "{}", self.as_str())
141 }
142}
143
144impl FromStr for Scheme {
145 type Err = Error;
146
147 fn from_str(s: &str) -> Result<Self, Self::Err> {
148 match s {
149 "Ed25519Sha512" | "FROST-ED25519-SHA512-v1" => Ok(Self::Ed25519Sha512),
150 "Ed448Shake256" | "FROST-ED448-SHAKE256-v1" => Ok(Self::Ed448Shake256),
151 "Ristretto25519Sha512" | "FROST-RISTRETTO255-SHA512-v1" => {
152 Ok(Self::Ristretto25519Sha512)
153 }
154 "K256Sha256" | "FROST-secp256k1-SHA256-v1" => Ok(Self::K256Sha256),
155 "P256Sha256" | "FROST-P256-SHA256-v1" => Ok(Self::P256Sha256),
156 "P384Sha384" | "FROST-P384-SHA384-v1" => Ok(Self::P384Sha384),
157 "RedJubjubBlake2b512" | "FROST-RedJubjub-BLAKE2b-512-v1" => {
158 Ok(Self::RedJubjubBlake2b512)
159 }
160 "K256Taproot" | "FROST-secp256k1-Taproot-v1" => Ok(Self::K256Taproot),
161 "RedDecaf377Blake2b512" | "FROST-Decaf377-BLAKE2b-512-v1" => {
162 Ok(Self::RedDecaf377Blake2b512)
163 }
164 "SchnorrkelSubstrate" | "FROST-Schnorrkel-Merlin-Strobe128-v1" => {
165 Ok(Self::SchnorrkelSubstrate)
166 }
167 "RedPallasBlake2b512" | "FROST(Pallas, BLAKE2b-512)" => Ok(Self::RedPallasBlake2b512),
168 _ => Err(Error::General(format!("Unknown scheme: {}", s))),
169 }
170 }
171}
172
173impl TryFrom<u8> for Scheme {
174 type Error = Error;
175
176 fn try_from(value: u8) -> Result<Self, Self::Error> {
177 match value {
178 1 => Ok(Self::Ed25519Sha512),
179 2 => Ok(Self::Ed448Shake256),
180 3 => Ok(Self::Ristretto25519Sha512),
181 4 => Ok(Self::K256Sha256),
182 5 => Ok(Self::P256Sha256),
183 6 => Ok(Self::P384Sha384),
184 7 => Ok(Self::RedJubjubBlake2b512),
185 8 => Ok(Self::K256Taproot),
186 9 => Ok(Self::RedDecaf377Blake2b512),
187 10 => Ok(Self::SchnorrkelSubstrate),
188 11 => Ok(Self::RedPallasBlake2b512),
189 _ => Err(Error::General(format!("Unknown scheme: {}", value))),
190 }
191 }
192}
193
194impl Serialize for Scheme {
195 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
196 if s.is_human_readable() {
197 s.serialize_str(&self.to_string())
198 } else {
199 s.serialize_u8(*self as u8)
200 }
201 }
202}
203
204impl<'de> Deserialize<'de> for Scheme {
205 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
206 if d.is_human_readable() {
207 let s = String::deserialize(d)?;
208 Self::from_str(&s).map_err(serde::de::Error::custom)
209 } else {
210 let u = u8::deserialize(d)?;
211 Self::try_from(u).map_err(serde::de::Error::custom)
212 }
213 }
214}
215
216impl Scheme {
217 #[cfg(not(feature = "verify_only"))]
218 pub fn pregenerate_signing_nonces<R: CryptoRng + RngCore>(
222 &self,
223 count: NonZeroU8,
224 secret_share: &SigningShare,
225 rng: &mut R,
226 ) -> FrostResult<(Vec<SigningNonces>, Vec<SigningCommitments>)> {
227 match self {
228 Self::Ed25519Sha512 => {
229 preprocess::<frost_ed25519::Ed25519Sha512, R>(count, secret_share, rng)
230 }
231 Self::Ed448Shake256 => {
232 preprocess::<frost_ed448::Ed448Shake256, R>(count, secret_share, rng)
233 }
234 Self::Ristretto25519Sha512 => {
235 preprocess::<frost_ristretto255::Ristretto255Sha512, R>(count, secret_share, rng)
236 }
237 Self::K256Sha256 => {
238 preprocess::<frost_secp256k1::Secp256K1Sha256, R>(count, secret_share, rng)
239 }
240 Self::P256Sha256 => preprocess::<frost_p256::P256Sha256, R>(count, secret_share, rng),
241 Self::P384Sha384 => preprocess::<frost_p384::P384Sha384, R>(count, secret_share, rng),
242 Self::RedJubjubBlake2b512 => {
243 preprocess::<frost_redjubjub::JubjubBlake2b512, R>(count, secret_share, rng)
244 }
245 Self::K256Taproot => {
246 preprocess::<frost_taproot::Secp256K1Taproot, R>(count, secret_share, rng)
247 }
248 Self::RedDecaf377Blake2b512 => {
249 preprocess::<frost_decaf377::Decaf377Blake2b512, R>(count, secret_share, rng)
250 }
251 Self::SchnorrkelSubstrate => preprocess::<
252 frost_schnorrkel25519::Schnorrkel25519Merlin,
253 R,
254 >(count, secret_share, rng),
255 Self::RedPallasBlake2b512 => {
256 preprocess::<frost_redpallas::PallasBlake2b512, R>(count, secret_share, rng)
257 }
258 }
259 }
260
261 #[cfg(not(feature = "verify_only"))]
262 pub fn signing_round1<R: CryptoRng + RngCore>(
264 &self,
265 secret_share: &SigningShare,
266 rng: &mut R,
267 ) -> FrostResult<(SigningNonces, SigningCommitments)> {
268 if secret_share.scheme != *self {
269 return Err(Error::General(format!(
270 "mismatched schemes for secret_share: expected {}, found {}",
271 self, secret_share.scheme
272 )));
273 }
274 match self {
275 Self::Ed25519Sha512 => round1::<frost_ed25519::Ed25519Sha512, R>(secret_share, rng),
276 Self::Ed448Shake256 => round1::<frost_ed448::Ed448Shake256, R>(secret_share, rng),
277 Self::Ristretto25519Sha512 => {
278 round1::<frost_ristretto255::Ristretto255Sha512, R>(secret_share, rng)
279 }
280 Self::K256Sha256 => round1::<frost_secp256k1::Secp256K1Sha256, R>(secret_share, rng),
281 Self::P256Sha256 => round1::<frost_p256::P256Sha256, R>(secret_share, rng),
282 Self::P384Sha384 => round1::<frost_p384::P384Sha384, R>(secret_share, rng),
283 Self::RedJubjubBlake2b512 => {
284 round1::<frost_redjubjub::JubjubBlake2b512, R>(secret_share, rng)
285 }
286 Self::K256Taproot => round1::<frost_taproot::Secp256K1Taproot, R>(secret_share, rng),
287 Self::RedDecaf377Blake2b512 => {
288 round1::<frost_decaf377::Decaf377Blake2b512, R>(secret_share, rng)
289 }
290 Self::SchnorrkelSubstrate => {
291 round1::<frost_schnorrkel25519::Schnorrkel25519Merlin, R>(secret_share, rng)
292 }
293 Self::RedPallasBlake2b512 => {
294 round1::<frost_redpallas::PallasBlake2b512, R>(secret_share, rng)
295 }
296 }
297 }
298
299 #[cfg(not(feature = "verify_only"))]
300 pub fn signing_round2(
302 &self,
303 message: &[u8],
304 signing_commitments: &[(Identifier, SigningCommitments)],
305 signing_nonce: &SigningNonces,
306 key_package: &KeyPackage,
307 ) -> FrostResult<SignatureShare> {
308 if key_package.identifier.scheme != *self {
309 return Err(Error::General(format!(
310 "mismatched schemes for key_package: expected {}, found {}",
311 self, key_package.identifier.scheme
312 )));
313 }
314 if signing_nonce.scheme != *self {
315 return Err(Error::General(format!(
316 "mismatched schemes for signing_nonce: expected {}, found {}",
317 self, signing_nonce.scheme
318 )));
319 }
320 if signing_commitments
321 .iter()
322 .any(|(id, c)| id.scheme != *self || c.scheme != *self)
323 {
324 return Err(Error::General(
325 "mismatched schemes for signing_commitments".to_string(),
326 ));
327 }
328 match self {
329 Self::Ed25519Sha512 => round2::<frost_ed25519::Ed25519Sha512>(
330 message,
331 signing_commitments,
332 signing_nonce,
333 key_package,
334 ),
335 Self::Ed448Shake256 => round2::<frost_ed448::Ed448Shake256>(
336 message,
337 signing_commitments,
338 signing_nonce,
339 key_package,
340 ),
341 Self::Ristretto25519Sha512 => round2::<frost_ristretto255::Ristretto255Sha512>(
342 message,
343 signing_commitments,
344 signing_nonce,
345 key_package,
346 ),
347 Self::K256Sha256 => round2::<frost_secp256k1::Secp256K1Sha256>(
348 message,
349 signing_commitments,
350 signing_nonce,
351 key_package,
352 ),
353 Self::P256Sha256 => round2::<frost_p256::P256Sha256>(
354 message,
355 signing_commitments,
356 signing_nonce,
357 key_package,
358 ),
359 Self::P384Sha384 => round2::<frost_p384::P384Sha384>(
360 message,
361 signing_commitments,
362 signing_nonce,
363 key_package,
364 ),
365 Self::RedJubjubBlake2b512 => round2::<frost_redjubjub::JubjubBlake2b512>(
366 message,
367 signing_commitments,
368 signing_nonce,
369 key_package,
370 ),
371 Self::K256Taproot => round2::<frost_taproot::Secp256K1Taproot>(
372 Sha256::digest(message).as_slice(),
373 signing_commitments,
374 signing_nonce,
375 key_package,
376 ),
377 Self::RedDecaf377Blake2b512 => round2::<frost_decaf377::Decaf377Blake2b512>(
378 message,
379 signing_commitments,
380 signing_nonce,
381 key_package,
382 ),
383 Self::SchnorrkelSubstrate => round2::<frost_schnorrkel25519::Schnorrkel25519Merlin>(
384 message,
385 signing_commitments,
386 signing_nonce,
387 key_package,
388 ),
389 Self::RedPallasBlake2b512 => round2::<frost_redpallas::PallasBlake2b512>(
390 message,
391 signing_commitments,
392 signing_nonce,
393 key_package,
394 ),
395 }
396 }
397
398 pub fn aggregate(
400 &self,
401 message: &[u8],
402 signing_commitments: &[(Identifier, SigningCommitments)],
403 signature_shares: &[(Identifier, SignatureShare)],
404 signer_pubkeys: &[(Identifier, VerifyingShare)],
405 verifying_key: &VerifyingKey,
406 ) -> FrostResult<Signature> {
407 if signer_pubkeys
408 .iter()
409 .any(|(id, v)| id.scheme != *self || v.scheme != *self)
410 {
411 return Err(Error::General(
412 "mismatched schemes for signer_pubkeys".to_string(),
413 ));
414 }
415 if signing_commitments
416 .iter()
417 .any(|(id, c)| id.scheme != *self || c.scheme != *self)
418 {
419 return Err(Error::General(
420 "mismatched schemes for signing_commitments".to_string(),
421 ));
422 }
423 if signature_shares
424 .iter()
425 .any(|(id, s)| id.scheme != *self || s.scheme != *self)
426 {
427 return Err(Error::General(
428 "mismatched schemes for signature_shares".to_string(),
429 ));
430 }
431 if verifying_key.scheme != *self {
432 return Err(Error::General(format!(
433 "mismatched schemes for verifying_key: expected {}, found {}",
434 self, verifying_key.scheme
435 )));
436 }
437 match self {
438 Self::Ed25519Sha512 => aggregate::<frost_ed25519::Ed25519Sha512>(
439 message,
440 signing_commitments,
441 signature_shares,
442 signer_pubkeys,
443 verifying_key,
444 ),
445 Self::Ed448Shake256 => aggregate::<frost_ed448::Ed448Shake256>(
446 message,
447 signing_commitments,
448 signature_shares,
449 signer_pubkeys,
450 verifying_key,
451 ),
452 Self::Ristretto25519Sha512 => aggregate::<frost_ristretto255::Ristretto255Sha512>(
453 message,
454 signing_commitments,
455 signature_shares,
456 signer_pubkeys,
457 verifying_key,
458 ),
459 Self::K256Sha256 => aggregate::<frost_secp256k1::Secp256K1Sha256>(
460 message,
461 signing_commitments,
462 signature_shares,
463 signer_pubkeys,
464 verifying_key,
465 ),
466 Self::P256Sha256 => aggregate::<frost_p256::P256Sha256>(
467 message,
468 signing_commitments,
469 signature_shares,
470 signer_pubkeys,
471 verifying_key,
472 ),
473 Self::P384Sha384 => aggregate::<frost_p384::P384Sha384>(
474 message,
475 signing_commitments,
476 signature_shares,
477 signer_pubkeys,
478 verifying_key,
479 ),
480 Self::RedJubjubBlake2b512 => aggregate::<frost_redjubjub::JubjubBlake2b512>(
481 message,
482 signing_commitments,
483 signature_shares,
484 signer_pubkeys,
485 verifying_key,
486 ),
487 Self::K256Taproot => {
488 let signature = aggregate::<frost_taproot::Secp256K1Taproot>(
489 Sha256::digest(message).as_slice(),
490 signing_commitments,
491 signature_shares,
492 signer_pubkeys,
493 verifying_key,
494 )?;
495 let sig: k256::schnorr::Signature = signature.try_into()?;
498 Ok(sig.into())
500 }
501 Self::RedDecaf377Blake2b512 => aggregate::<frost_decaf377::Decaf377Blake2b512>(
502 message,
503 signing_commitments,
504 signature_shares,
505 signer_pubkeys,
506 verifying_key,
507 ),
508 Self::SchnorrkelSubstrate => {
509 let signature = aggregate::<frost_schnorrkel25519::Schnorrkel25519Merlin>(
510 message,
511 signing_commitments,
512 signature_shares,
513 signer_pubkeys,
514 verifying_key,
515 )?;
516 let sig: schnorrkel::Signature = signature.try_into()?;
520 Ok(sig.into())
522 }
523 Self::RedPallasBlake2b512 => aggregate::<frost_redpallas::PallasBlake2b512>(
524 message,
525 signing_commitments,
526 signature_shares,
527 signer_pubkeys,
528 verifying_key,
529 ),
530 }
531 }
532
533 pub fn verify(
535 &self,
536 message: &[u8],
537 verifying_key: &VerifyingKey,
538 signature: &Signature,
539 ) -> FrostResult<()> {
540 if verifying_key.scheme != *self {
541 return Err(Error::General(format!(
542 "mismatched schemes for verifying_key: expected {}, found {}",
543 self, verifying_key.scheme
544 )));
545 }
546 if signature.scheme != *self {
547 return Err(Error::General(format!(
548 "mismatched schemes for signature: expected {}, found {}",
549 self, signature.scheme
550 )));
551 }
552 match self {
553 Self::Ed25519Sha512 => {
554 verify::<frost_ed25519::Ed25519Sha512>(message, verifying_key, signature)
555 }
556 Self::Ed448Shake256 => {
557 verify::<frost_ed448::Ed448Shake256>(message, verifying_key, signature)
558 }
559 Self::Ristretto25519Sha512 => {
560 verify::<frost_ristretto255::Ristretto255Sha512>(message, verifying_key, signature)
561 }
562 Self::K256Sha256 => {
563 verify::<frost_secp256k1::Secp256K1Sha256>(message, verifying_key, signature)
564 }
565 Self::P256Sha256 => verify::<frost_p256::P256Sha256>(message, verifying_key, signature),
566 Self::P384Sha384 => verify::<frost_p384::P384Sha384>(message, verifying_key, signature),
567 Self::RedJubjubBlake2b512 => {
568 verify::<frost_redjubjub::JubjubBlake2b512>(message, verifying_key, signature)
569 }
570 Self::K256Taproot => verify::<frost_taproot::Secp256K1Taproot>(
571 Sha256::digest(message).as_slice(),
572 verifying_key,
573 signature,
574 ),
575 Self::RedDecaf377Blake2b512 => {
576 verify::<frost_decaf377::Decaf377Blake2b512>(message, verifying_key, signature)
577 }
578 Self::SchnorrkelSubstrate => verify::<frost_schnorrkel25519::Schnorrkel25519Merlin>(
579 message,
580 verifying_key,
581 signature,
582 ),
583 Self::RedPallasBlake2b512 => {
584 verify::<frost_redpallas::PallasBlake2b512>(message, verifying_key, signature)
585 }
586 }
587 }
588
589 #[cfg(not(feature = "verify_only"))]
590 pub fn verifying_share(&self, signing_share: &SigningShare) -> FrostResult<VerifyingShare> {
592 if signing_share.scheme != *self {
593 return Err(Error::General(format!(
594 "mismatched schemes for signing_share: expected {}, found {}",
595 self, signing_share.scheme
596 )));
597 }
598 match self {
599 Self::Ed25519Sha512 => verifying_share::<frost_ed25519::Ed25519Sha512>(signing_share),
600 Self::Ed448Shake256 => verifying_share::<frost_ed448::Ed448Shake256>(signing_share),
601 Self::Ristretto25519Sha512 => {
602 verifying_share::<frost_ristretto255::Ristretto255Sha512>(signing_share)
603 }
604 Self::K256Sha256 => verifying_share::<frost_secp256k1::Secp256K1Sha256>(signing_share),
605 Self::P256Sha256 => verifying_share::<frost_p256::P256Sha256>(signing_share),
606 Self::P384Sha384 => verifying_share::<frost_p384::P384Sha384>(signing_share),
607 Self::RedJubjubBlake2b512 => {
608 verifying_share::<frost_redjubjub::JubjubBlake2b512>(signing_share)
609 }
610 Self::K256Taproot => verifying_share::<frost_taproot::Secp256K1Taproot>(signing_share),
611 Self::RedDecaf377Blake2b512 => {
612 verifying_share::<frost_decaf377::Decaf377Blake2b512>(signing_share)
613 }
614 Self::SchnorrkelSubstrate => {
615 verifying_share::<frost_schnorrkel25519::Schnorrkel25519Merlin>(signing_share)
616 }
617 Self::RedPallasBlake2b512 => {
618 verifying_share::<frost_redpallas::PallasBlake2b512>(signing_share)
619 }
620 }
621 }
622
623 pub(crate) const fn scalar_len(&self) -> FrostResult<usize> {
624 match self {
625 Self::Ed25519Sha512 => Ok(32),
626 Self::Ed448Shake256 => Ok(57),
627 Self::Ristretto25519Sha512 => Ok(32),
628 Self::K256Sha256 => Ok(32),
629 Self::P256Sha256 => Ok(32),
630 Self::P384Sha384 => Ok(48),
631 Self::RedJubjubBlake2b512 => Ok(32),
632 Self::K256Taproot => Ok(32),
633 Self::RedDecaf377Blake2b512 => Ok(32),
634 Self::SchnorrkelSubstrate => Ok(32),
635 Self::RedPallasBlake2b512 => Ok(32),
636 }
637 }
638
639 pub(crate) const fn byte_order(&self) -> FrostResult<ByteOrder> {
640 match self {
641 Self::Ed25519Sha512
642 | Self::Ristretto25519Sha512
643 | Self::Ed448Shake256
644 | Self::RedJubjubBlake2b512
645 | Self::RedDecaf377Blake2b512
646 | Self::SchnorrkelSubstrate
647 | Self::RedPallasBlake2b512 => Ok(ByteOrder::LittleEndian),
648 Self::P256Sha256 | Self::K256Sha256 | Self::K256Taproot | Self::P384Sha384 => {
649 Ok(ByteOrder::BigEndian)
650 }
651 }
652 }
653
654 pub(crate) const fn compressed_point_len(&self) -> FrostResult<usize> {
655 match self {
656 Self::Ed25519Sha512 => Ok(32),
657 Self::Ed448Shake256 => Ok(57),
658 Self::Ristretto25519Sha512 => Ok(32),
659 Self::K256Sha256 => Ok(33),
660 Self::P256Sha256 => Ok(33),
661 Self::P384Sha384 => Ok(49),
662 Self::RedJubjubBlake2b512 => Ok(32),
663 Self::K256Taproot => Ok(33),
664 Self::RedDecaf377Blake2b512 => Ok(32),
665 Self::SchnorrkelSubstrate => Ok(32),
666 Self::RedPallasBlake2b512 => Ok(32),
667 }
668 }
669
670 pub(crate) const fn commitment_len(&self) -> FrostResult<usize> {
671 match self {
672 Self::Ed25519Sha512 => Ok(69),
673 Self::Ed448Shake256 => Ok(119),
674 Self::Ristretto25519Sha512 => Ok(69),
675 Self::K256Sha256 => Ok(71),
676 Self::P256Sha256 => Ok(71),
677 Self::P384Sha384 => Ok(103),
678 Self::RedJubjubBlake2b512 => Ok(69),
679 Self::K256Taproot => Ok(71),
680 Self::RedDecaf377Blake2b512 => Ok(69),
681 Self::SchnorrkelSubstrate => Ok(69),
682 Self::RedPallasBlake2b512 => Ok(69),
683 }
684 }
685
686 pub(crate) const fn signature_len(&self) -> FrostResult<usize> {
687 match self {
688 Self::Ed25519Sha512 => Ok(64),
689 Self::Ed448Shake256 => Ok(114),
690 Self::Ristretto25519Sha512 => Ok(64),
691 Self::K256Sha256 => Ok(65),
692 Self::P256Sha256 => Ok(65),
693 Self::P384Sha384 => Ok(97),
694 Self::RedJubjubBlake2b512 => Ok(64),
695 Self::K256Taproot => Ok(65),
696 Self::RedDecaf377Blake2b512 => Ok(64),
697 Self::SchnorrkelSubstrate => Ok(64),
698 Self::RedPallasBlake2b512 => Ok(64),
699 }
700 }
701
702 #[cfg(not(feature = "verify_only"))]
703 pub fn generate_with_trusted_dealer<R: CryptoRng + RngCore>(
705 &self,
706 min_signers: u16,
707 max_signers: u16,
708 rng: &mut R,
709 ) -> FrostResult<(BTreeMap<Identifier, SigningShare>, VerifyingKey)> {
710 match self {
711 Self::Ed25519Sha512 => generate_with_trusted_dealer::<frost_ed25519::Ed25519Sha512, R>(
712 min_signers,
713 max_signers,
714 rng,
715 ),
716 Self::Ed448Shake256 => generate_with_trusted_dealer::<frost_ed448::Ed448Shake256, R>(
717 min_signers,
718 max_signers,
719 rng,
720 ),
721 Self::Ristretto25519Sha512 => generate_with_trusted_dealer::<
722 frost_ristretto255::Ristretto255Sha512,
723 R,
724 >(min_signers, max_signers, rng),
725 Self::K256Sha256 => {
726 generate_with_trusted_dealer::<frost_secp256k1::Secp256K1Sha256, R>(
727 min_signers,
728 max_signers,
729 rng,
730 )
731 }
732 Self::P256Sha256 => generate_with_trusted_dealer::<frost_p256::P256Sha256, R>(
733 min_signers,
734 max_signers,
735 rng,
736 ),
737 Self::P384Sha384 => generate_with_trusted_dealer::<frost_p384::P384Sha384, R>(
738 min_signers,
739 max_signers,
740 rng,
741 ),
742 Self::RedJubjubBlake2b512 => generate_with_trusted_dealer::<
743 frost_redjubjub::JubjubBlake2b512,
744 R,
745 >(min_signers, max_signers, rng),
746 Self::K256Taproot => {
747 generate_with_trusted_dealer::<frost_taproot::Secp256K1Taproot, R>(
748 min_signers,
749 max_signers,
750 rng,
751 )
752 }
753 Self::RedDecaf377Blake2b512 => generate_with_trusted_dealer::<
754 frost_decaf377::Decaf377Blake2b512,
755 R,
756 >(min_signers, max_signers, rng),
757 Self::SchnorrkelSubstrate => generate_with_trusted_dealer::<
758 frost_schnorrkel25519::Schnorrkel25519Merlin,
759 R,
760 >(min_signers, max_signers, rng),
761 Self::RedPallasBlake2b512 => generate_with_trusted_dealer::<
762 frost_redpallas::PallasBlake2b512,
763 R,
764 >(min_signers, max_signers, rng),
765 }
766 }
767
768 pub const fn as_str(&self) -> &'static str {
770 match self {
771 Self::Ed25519Sha512 => "Ed25519Sha512",
772 Self::Ed448Shake256 => "Ed448Shake256",
773 Self::Ristretto25519Sha512 => "Ristretto25519Sha512",
774 Self::K256Sha256 => "K256Sha256",
775 Self::P256Sha256 => "P256Sha256",
776 Self::P384Sha384 => "P384Sha384",
777 Self::RedJubjubBlake2b512 => "RedJubjubBlake2b512",
778 Self::K256Taproot => "K256Taproot",
779 Self::RedDecaf377Blake2b512 => "RedDecaf377Blake2b512",
780 Self::SchnorrkelSubstrate => "SchnorrkelSubstrate",
781 Self::RedPallasBlake2b512 => "RedPallasBlake2b512",
782 }
783 }
784}
785
786#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)]
788pub enum ByteOrder {
789 #[default]
791 BigEndian,
792 LittleEndian,
794}
795
796fn verify<C: Ciphersuite>(
797 message: &[u8],
798 verifying_key: &VerifyingKey,
799 signature: &Signature,
800) -> FrostResult<()> {
801 let verifying_key: frost_core::VerifyingKey<C> = verifying_key.try_into()?;
802 let signature: frost_core::Signature<C> = signature.try_into()?;
803 if !verifying_key.is_valid() || !signature.is_valid() {
804 return Err(Error::General("Error verifying signature".to_string()));
805 }
806 verifying_key
807 .verify(message, &signature)
808 .map_err(|_| Error::General("Error verifying signature".to_string()))
809}
810
811#[cfg(not(feature = "verify_only"))]
812fn verifying_share<C: Ciphersuite>(signing_share: &SigningShare) -> FrostResult<VerifyingShare> {
813 let signing_share: frost_core::keys::SigningShare<C> = signing_share.try_into()?;
814 let verifying_share = frost_core::keys::VerifyingShare::<C>::from(signing_share);
815 Ok(verifying_share.into())
816}
817
818fn aggregate<C: Ciphersuite>(
819 message: &[u8],
820 signing_commitments: &[(Identifier, SigningCommitments)],
821 signature_shares: &[(Identifier, SignatureShare)],
822 signer_pubkeys: &[(Identifier, VerifyingShare)],
823 verifying_key: &VerifyingKey,
824) -> FrostResult<Signature> {
825 let signing_commitment_map =
826 create_frost_signing_commitments_from_bytes::<C>(signing_commitments)?;
827 if signing_commitment_map
828 .iter()
829 .any(|(i, c)| !i.is_valid() && !c.is_valid())
830 {
831 return Err(Error::General("Error aggregating signature".to_string()));
832 }
833 let signature_shares_map = create_frost_signing_shares_from_bytes::<C>(signature_shares)?;
834 if signature_shares_map
835 .iter()
836 .any(|(i, s)| !i.is_valid() && !s.is_valid())
837 {
838 return Err(Error::General("Error aggregating signature".to_string()));
839 }
840 let mut signer_pubkeys_map = BTreeMap::new();
841 for (index, pubkey) in signer_pubkeys {
842 let index: frost_core::Identifier<C> = index.try_into()?;
843 let pubkey: frost_core::keys::VerifyingShare<C> = pubkey.try_into()?;
844 if !index.is_valid() && !pubkey.is_valid() {
845 return Err(Error::General("Error aggregating signature".to_string()));
846 }
847 signer_pubkeys_map.insert(index, pubkey);
848 }
849 let verifying_key: frost_core::VerifyingKey<C> = verifying_key.try_into()?;
850 if !verifying_key.is_valid() {
851 return Err(Error::General("Error aggregating signature".to_string()));
852 }
853 let pubkey_package =
854 frost_core::keys::PublicKeyPackage::<C>::new(signer_pubkeys_map, verifying_key);
855 if !pubkey_package.is_valid() {
856 return Err(Error::General("Error aggregating signature".to_string()));
857 }
858 let signing_package = frost_core::SigningPackage::<C>::new(signing_commitment_map, message);
859 if !signing_package.is_valid() {
860 return Err(Error::General("Error aggregating signature".to_string()));
861 }
862
863 let signature =
864 frost_core::aggregate::<C>(&signing_package, &signature_shares_map, &pubkey_package)
865 .map_err(|e| match e {
866 frost_core::Error::InvalidSignatureShare { culprit } => {
867 Error::Cheaters(vec![culprit.into()])
868 }
869 ee => ee.into(),
870 })?;
871 Ok(signature.into())
872}
873
874#[cfg(not(feature = "verify_only"))]
875fn round2<C: Ciphersuite>(
876 message: &[u8],
877 signing_commitments: &[(Identifier, SigningCommitments)],
878 signing_nonce: &SigningNonces,
879 key_package: &KeyPackage,
880) -> FrostResult<SignatureShare> {
881 let key_package: frost_core::keys::KeyPackage<C> = key_package.try_into()?;
882 if !key_package.is_valid() {
883 return Err(Error::General("Error signing, bad inputs".to_string()));
884 }
885 let signing_nonces: frost_core::round1::SigningNonces<C> = signing_nonce.try_into()?;
886 if !signing_nonces.is_valid() {
887 return Err(Error::General("Error signing, bad inputs".to_string()));
888 }
889 let signing_commitments_map =
890 create_frost_signing_commitments_from_bytes::<C>(signing_commitments)?;
891 if signing_commitments_map
892 .iter()
893 .any(|(i, c)| !i.is_valid() && !c.is_valid())
894 {
895 return Err(Error::General("Error signing, bad inputs".to_string()));
896 }
897 let signing_package = frost_core::SigningPackage::<C>::new(signing_commitments_map, message);
898 let signature = frost_core::round2::sign::<C>(&signing_package, &signing_nonces, &key_package)
899 .map_err(|_| Error::General("Error signing".to_string()))?;
900 Ok(signature.into())
901}
902
903#[cfg(not(feature = "verify_only"))]
904fn round1<C: Ciphersuite, R: CryptoRng + RngCore>(
905 secret: &SigningShare,
906 rng: &mut R,
907) -> FrostResult<(SigningNonces, SigningCommitments)> {
908 let signing_share: frost_core::keys::SigningShare<C> = secret.try_into()?;
909 if !signing_share.is_valid() {
910 return Err(Error::General(
911 "Error: signing share is invalid".to_string(),
912 ));
913 }
914 let (signing_nonces, signing_commitments) =
915 frost_core::round1::commit::<C, R>(&signing_share, rng);
916 Ok((signing_nonces.into(), signing_commitments.into()))
917}
918
919#[cfg(not(feature = "verify_only"))]
920fn preprocess<C: Ciphersuite, R: CryptoRng + RngCore>(
921 count: NonZeroU8,
922 secret: &SigningShare,
923 rng: &mut R,
924) -> FrostResult<(Vec<SigningNonces>, Vec<SigningCommitments>)> {
925 let signing_share: frost_core::keys::SigningShare<C> = secret.try_into()?;
926 if !signing_share.is_valid() {
927 return Err(Error::General(
928 "Error: signing share is invalid".to_string(),
929 ));
930 }
931 let (signing_nonces, signing_commitments) =
932 frost_core::round1::preprocess::<C, R>(count.get(), &signing_share, rng);
933 Ok((
934 signing_nonces.iter().map(SigningNonces::from).collect(),
935 signing_commitments
936 .iter()
937 .map(SigningCommitments::from)
938 .collect(),
939 ))
940}
941
942#[cfg(not(feature = "verify_only"))]
943fn generate_with_trusted_dealer<C: Ciphersuite, R: CryptoRng + RngCore>(
945 min_signers: u16,
946 max_signers: u16,
947 rng: &mut R,
948) -> FrostResult<(BTreeMap<Identifier, SigningShare>, VerifyingKey)> {
949 let (shares, public_package) = frost_core::keys::generate_with_dealer::<C, R>(
950 max_signers,
951 min_signers,
952 frost_core::keys::IdentifierList::<C>::Default,
953 rng,
954 )
955 .map_err(|_| Error::General("Error generating keys".to_string()))?;
956 let shares = shares
957 .iter()
958 .map(|(id, share)| (id.into(), share.signing_share().into()))
959 .collect();
960 Ok((shares, public_package.verifying_key().into()))
961}
962
963fn create_frost_signing_commitments_from_bytes<C: Ciphersuite>(
964 signing_commitments: &[(Identifier, SigningCommitments)],
965) -> FrostResult<BTreeMap<frost_core::Identifier<C>, frost_core::round1::SigningCommitments<C>>> {
966 let mut signing_commitments_map = BTreeMap::new();
967 for (index, commitment) in signing_commitments {
968 signing_commitments_map.insert(index.try_into()?, commitment.try_into()?);
969 }
970 Ok(signing_commitments_map)
971}
972
973fn create_frost_signing_shares_from_bytes<C: Ciphersuite>(
974 signing_shares: &[(Identifier, SignatureShare)],
975) -> FrostResult<BTreeMap<frost_core::Identifier<C>, frost_core::round2::SignatureShare<C>>> {
976 let mut signing_commitments_map = BTreeMap::new();
977 for (index, share) in signing_shares {
978 signing_commitments_map.insert(index.try_into()?, share.try_into()?);
979 }
980 Ok(signing_commitments_map)
981}
982
983pub(crate) fn is_zero(value: &[u8]) -> subtle::Choice {
984 let mut result = 0i8;
985 for b in value {
986 result |= *b as i8;
987 }
988 let result = ((result | -result) >> 7) + 1;
989 subtle::Choice::from(result as u8)
990}
991
992#[cfg(test)]
993mod tests {
994 use super::*;
995 use frost_core::Group as _;
996 use frost_dkg::elliptic_curve_tools::SumOfProducts;
997 use frost_dkg::{DkgResult, Parameters, Round, ScalarHash, SecretParticipant};
998 use group::{Group, GroupEncoding};
999 use rand_core::SeedableRng;
1000 use rstest::*;
1001 use std::num::{NonZeroU16, NonZeroUsize};
1002 use vsss_rs::IdentifierPrimeField;
1003 use vsss_rs::elliptic_curve::PrimeField;
1004
1005 const DKG_MSG: &[u8] = b"test";
1006
1007 #[test]
1008 fn sign_with_cheaters() {
1009 const THRESHOLD: u16 = 3;
1010 let scheme = Scheme::Ed25519Sha512;
1011 let mut rng = rand::rngs::OsRng;
1012 let (secret_shares, verifying_key) = scheme
1013 .generate_with_trusted_dealer(THRESHOLD, 5, &mut rng)
1014 .unwrap();
1015 let mut signing_package = BTreeMap::new();
1016 let mut signing_commitments = Vec::new();
1017
1018 for (id, secret_share) in &secret_shares {
1019 let res = scheme.signing_round1(secret_share, &mut rng);
1020 assert!(res.is_ok());
1021 let (nonces, commitments) = res.unwrap();
1022 signing_package.insert(id.clone(), (nonces, secret_share));
1023 signing_commitments.push((id.clone(), commitments));
1024 }
1025
1026 let mut verifying_shares = Vec::new();
1027 let mut signature_shares = Vec::new();
1028 for (i, (id, (nonces, secret_share))) in signing_package.iter().enumerate() {
1029 let res = scheme.signing_round2(
1030 DKG_MSG,
1031 &signing_commitments,
1032 &nonces,
1033 &KeyPackage {
1034 identifier: id.clone(),
1035 secret_share: (*secret_share).clone(),
1036 verifying_key: verifying_key.clone(),
1037 threshold: NonZeroU16::new(THRESHOLD).unwrap(),
1038 },
1039 );
1040 let mut signature = res.unwrap();
1041 if i & 1 == 1 {
1042 signature.value.iter_mut().for_each(|b| *b = 1);
1043 }
1044 signature_shares.push((id.clone(), signature));
1045 verifying_shares.push((id.clone(), scheme.verifying_share(&secret_share).unwrap()));
1046 }
1047
1048 let res = scheme.aggregate(
1049 DKG_MSG,
1050 &signing_commitments,
1051 &signature_shares,
1052 &verifying_shares,
1053 &verifying_key,
1054 );
1055 assert!(res.is_err());
1056 match res.unwrap_err() {
1057 Error::Cheaters(cheaters) => {
1058 assert_eq!(cheaters.len(), 1);
1060 }
1061 e => assert!(false, "Unexpected error: {:?}", e),
1062 }
1063 }
1064
1065 #[rstest]
1066 #[case::ed25519(Scheme::Ed25519Sha512, 32)]
1067 #[case::ed448(Scheme::Ed448Shake256, 57)]
1068 #[case::ristretto25519(Scheme::Ristretto25519Sha512, 32)]
1069 #[case::k256(Scheme::K256Sha256, 32)]
1070 #[case::p256(Scheme::P256Sha256, 32)]
1071 #[case::p384(Scheme::P384Sha384, 48)]
1072 #[case::redjubjub(Scheme::RedJubjubBlake2b512, 32)]
1073 #[case::taproot(Scheme::K256Taproot, 32)]
1074 #[case::reddecaf377(Scheme::RedDecaf377Blake2b512, 32)]
1075 #[case::redpallas(Scheme::RedPallasBlake2b512, 32)]
1076 #[case::schnorrkel(Scheme::SchnorrkelSubstrate, 32)]
1077 fn pregenerate(#[case] scheme: Scheme, #[case] length: usize) {
1078 let mut rng = rand::rngs::OsRng;
1079 let mut secret = SigningShare {
1080 scheme,
1081 value: vec![1u8; length],
1082 };
1083 secret.value[length - 1] = 0;
1085 secret.value[length - 2] = 0;
1086 let (signing_nonces, signing_commitments) = scheme
1087 .pregenerate_signing_nonces(NonZeroU8::new(200).unwrap(), &secret, &mut rng)
1088 .unwrap();
1089 assert_eq!(signing_nonces.len(), 200);
1090 assert_eq!(signing_commitments.len(), 200);
1091 }
1092
1093 #[rstest]
1094 #[case::ed25519(Scheme::Ed25519Sha512)]
1095 #[case::ed448(Scheme::Ed448Shake256)]
1096 #[case::ristretto25519(Scheme::Ristretto25519Sha512)]
1097 #[case::k256(Scheme::K256Sha256)]
1098 #[case::p256(Scheme::P256Sha256)]
1099 #[case::p384(Scheme::P384Sha384)]
1100 #[case::redjubjub(Scheme::RedJubjubBlake2b512)]
1101 #[case::taproot(Scheme::K256Taproot)]
1102 #[case::reddecaf377(Scheme::RedDecaf377Blake2b512)]
1103 #[case::redpallas(Scheme::RedPallasBlake2b512)]
1104 #[case::schnorrkel(Scheme::SchnorrkelSubstrate)]
1105 fn rounds(#[case] scheme: Scheme) {
1106 const MSG: &[u8] = b"test";
1107 const THRESHOLD: u16 = 3;
1108 let mut rng = rand::rngs::OsRng;
1109 let (secret_shares, verifying_key) = scheme
1110 .generate_with_trusted_dealer(THRESHOLD, 5, &mut rng)
1111 .unwrap();
1112
1113 let mut signing_package = BTreeMap::new();
1114 let mut signing_commitments = Vec::new();
1115
1116 for (id, secret_share) in &secret_shares {
1117 let res = scheme.signing_round1(&secret_share, &mut rng);
1118 assert!(res.is_ok());
1119 let (nonces, commitments) = res.unwrap();
1120 signing_package.insert(id.clone(), (nonces, secret_share));
1121 signing_commitments.push((id.clone(), commitments));
1122 }
1123
1124 let mut verifying_shares = Vec::new();
1125 let mut signature_shares = Vec::new();
1126 for (id, (nonces, secret_share)) in signing_package {
1127 let res = scheme.signing_round2(
1128 MSG,
1129 &signing_commitments,
1130 &nonces,
1131 &KeyPackage {
1132 identifier: id.clone(),
1133 secret_share: secret_share.clone(),
1134 verifying_key: verifying_key.clone(),
1135 threshold: NonZeroU16::new(THRESHOLD).unwrap(),
1136 },
1137 );
1138 let signature = res.unwrap();
1139 signature_shares.push((id.clone(), signature));
1140 verifying_shares.push((id.clone(), scheme.verifying_share(&secret_share).unwrap()));
1141 }
1142
1143 let res = scheme.aggregate(
1144 MSG,
1145 &signing_commitments,
1146 &signature_shares,
1147 &verifying_shares,
1148 &verifying_key,
1149 );
1150 assert!(res.is_ok());
1151 }
1152
1153 #[rstest]
1154 #[case::ed25519(Scheme::Ed25519Sha512)]
1155 #[case::ed448(Scheme::Ed448Shake256)]
1156 #[case::ristretto25519(Scheme::Ristretto25519Sha512)]
1157 #[case::k256(Scheme::K256Sha256)]
1158 #[case::p256(Scheme::P256Sha256)]
1159 #[case::p384(Scheme::P384Sha384)]
1160 #[case::redjubjub(Scheme::RedJubjubBlake2b512)]
1161 #[case::taproot(Scheme::K256Taproot)]
1162 #[case::reddecaf377(Scheme::RedDecaf377Blake2b512)]
1163 #[case::redpallas(Scheme::RedPallasBlake2b512)]
1164 #[case::schnorrkel(Scheme::SchnorrkelSubstrate)]
1165 fn full(#[case] scheme: Scheme) {
1166 const MSG: &[u8] = b"test";
1167 const THRESHOLD: u16 = 3;
1168 let mut rng = rand::rngs::OsRng;
1169 let (secret_shares, verifying_key) = scheme
1170 .generate_with_trusted_dealer(THRESHOLD, 5, &mut rng)
1171 .unwrap();
1172
1173 let mut signing_package = Vec::new();
1174 for (id, secret_share) in secret_shares {
1175 let res = scheme.pregenerate_signing_nonces(
1176 NonZeroU8::new(20).unwrap(),
1177 &secret_share,
1178 &mut rng,
1179 );
1180 assert!(res.is_ok());
1181 let (nonces, commitments) = res.unwrap();
1182 signing_package.push((id, secret_share, nonces, commitments));
1183 }
1184
1185 while signing_package[0].2.len() > 0 {
1186 let mut signing_commitments = Vec::new();
1187 let mut new_signing_package = Vec::new();
1188 for i in 0..signing_package.len() {
1189 signing_commitments.push((
1190 signing_package[i].0.clone(),
1191 signing_package[i].3.pop().unwrap(),
1192 ));
1193 new_signing_package.push((
1194 signing_package[i].0.clone(),
1195 signing_package[i].2.pop().unwrap(),
1196 signing_package[i].1.clone(),
1197 ));
1198 }
1199
1200 let mut verifying_shares = Vec::new();
1201 let mut signature_shares = Vec::new();
1202 for (id, nonces, secret_share) in new_signing_package {
1203 let res = scheme.signing_round2(
1204 MSG,
1205 &signing_commitments,
1206 &nonces,
1207 &KeyPackage {
1208 identifier: id.clone(),
1209 secret_share: secret_share.clone(),
1210 verifying_key: verifying_key.clone(),
1211 threshold: NonZeroU16::new(THRESHOLD).unwrap(),
1212 },
1213 );
1214 assert!(res.is_ok());
1215 let signature = res.unwrap();
1216 signature_shares.push((id.clone(), signature));
1217 verifying_shares.push((id.clone(), scheme.verifying_share(&secret_share).unwrap()));
1218 }
1219
1220 let res = scheme.aggregate(
1221 MSG,
1222 &signing_commitments,
1223 &signature_shares,
1224 &verifying_shares,
1225 &verifying_key,
1226 );
1227 assert!(res.is_ok());
1228 }
1229 }
1230
1231 #[rstest]
1233 #[case::ed25519(Scheme::Ed25519Sha512)]
1234 #[case::ed448(Scheme::Ed448Shake256)]
1235 #[case::ristretto25519(Scheme::Ristretto25519Sha512)]
1236 #[case::k256(Scheme::K256Sha256)]
1237 #[case::p256(Scheme::P256Sha256)]
1238 #[case::p384(Scheme::P384Sha384)]
1239 #[case::redjubjub(Scheme::RedJubjubBlake2b512)]
1240 #[case::taproot(Scheme::K256Taproot)]
1241 #[case::reddecaf377(Scheme::RedDecaf377Blake2b512)]
1242 #[case::redpallas(Scheme::RedPallasBlake2b512)]
1243 #[case::schnorrkel(Scheme::SchnorrkelSubstrate)]
1244 fn min_threshold(#[case] scheme: Scheme) {
1245 const MSG: &[u8] = b"test";
1246 const THRESHOLD: u16 = 2;
1247 let mut rng = rand::rngs::OsRng;
1248 let (secret_shares, verifying_key) = scheme
1249 .generate_with_trusted_dealer(THRESHOLD, 2, &mut rng)
1250 .unwrap();
1251
1252 let mut signing_package = BTreeMap::new();
1253 let mut signing_commitments = Vec::new();
1254
1255 for (id, secret_share) in &secret_shares {
1256 let res = scheme.signing_round1(&secret_share, &mut rng);
1257 assert!(res.is_ok());
1258 let (nonces, commitments) = res.unwrap();
1259 signing_package.insert(id.clone(), (nonces, secret_share));
1260 signing_commitments.push((id.clone(), commitments));
1261 }
1262
1263 let mut verifying_shares = Vec::new();
1264 let mut signature_shares = Vec::new();
1265 for (id, (nonces, secret_share)) in signing_package {
1266 let res = scheme.signing_round2(
1267 MSG,
1268 &signing_commitments,
1269 &nonces,
1270 &KeyPackage {
1271 identifier: id.clone(),
1272 secret_share: secret_share.clone(),
1273 verifying_key: verifying_key.clone(),
1274 threshold: NonZeroU16::new(THRESHOLD).unwrap(),
1275 },
1276 );
1277 let signature = res.unwrap();
1278 signature_shares.push((id.clone(), signature));
1279 verifying_shares.push((id.clone(), scheme.verifying_share(&secret_share).unwrap()));
1280 }
1281
1282 let res = scheme.aggregate(
1283 MSG,
1284 &signing_commitments,
1285 &signature_shares,
1286 &verifying_shares,
1287 &verifying_key,
1288 );
1289 assert!(res.is_ok());
1290 }
1291
1292 fn dkg_core<G>(scheme: Scheme, generator: Option<G>) -> (VerifyingKey, Signature)
1293 where
1294 G: GroupEncoding + Group + Default + SumOfProducts,
1295 G::Scalar: ScalarHash,
1296 {
1297 let threshold: usize = 2;
1298 let limit: usize = 3;
1299
1300 let mut rng = rand_chacha::ChaCha8Rng::from_seed([0u8; 32]);
1301
1302 let params = Parameters::<G>::new(
1303 NonZeroUsize::new(threshold).unwrap(),
1304 NonZeroUsize::new(limit).unwrap(),
1305 generator,
1306 None,
1307 );
1308 let mut secret_participants = [
1309 SecretParticipant::new_secret(IdentifierPrimeField(G::Scalar::from(1u64)), ¶ms)
1310 .unwrap(),
1311 SecretParticipant::new_secret(IdentifierPrimeField(G::Scalar::from(2u64)), ¶ms)
1312 .unwrap(),
1313 SecretParticipant::new_secret(IdentifierPrimeField(G::Scalar::from(3u64)), ¶ms)
1314 .unwrap(),
1315 ];
1316
1317 fn next_round<G>(participants: &mut [SecretParticipant<G>]) -> DkgResult<()>
1318 where
1319 G: GroupEncoding + Group + Default + SumOfProducts,
1320 G::Scalar: ScalarHash,
1321 {
1322 let mut round_generators = Vec::with_capacity(participants.len());
1323
1324 for p in participants.iter_mut() {
1325 let round_generator = p.run()?;
1326 round_generators.push(round_generator);
1327 }
1328
1329 for generator in &round_generators {
1330 for data in generator.iter() {
1331 let p = &mut participants[data.dst_ordinal];
1332 assert_eq!(data.dst_ordinal, p.get_ordinal());
1333 assert_eq!(data.dst_id, p.get_id());
1334 assert!(p.receive(data.data.as_slice()).is_ok());
1335 }
1336 }
1337 Ok(())
1338 }
1339
1340 for _ in [Round::One, Round::Two, Round::Three] {
1341 let res = next_round(&mut secret_participants);
1342 assert!(res.is_ok());
1343 }
1344
1345 let id1 = Identifier::from((scheme, 1u8));
1346 let id2 = Identifier::from((scheme, 2u8));
1347 let id3 = Identifier::from((scheme, 3u8));
1348
1349 let pk = secret_participants[0].get_public_key().unwrap();
1350
1351 let verifying_key = VerifyingKey {
1352 scheme,
1353 value: pk.to_bytes().as_ref().to_vec(),
1354 };
1355 let mut secret_shares = BTreeMap::new();
1356
1357 secret_shares.insert(
1358 id1,
1359 SigningShare {
1360 scheme,
1361 value: secret_participants[0]
1362 .get_secret_share()
1363 .unwrap()
1364 .value
1365 .0
1366 .to_repr()
1367 .as_ref()
1368 .to_vec(),
1369 },
1370 );
1371 secret_shares.insert(
1372 id2,
1373 SigningShare {
1374 scheme,
1375 value: secret_participants[1]
1376 .get_secret_share()
1377 .unwrap()
1378 .value
1379 .0
1380 .to_repr()
1381 .as_ref()
1382 .to_vec(),
1383 },
1384 );
1385 secret_shares.insert(
1386 id3,
1387 SigningShare {
1388 scheme,
1389 value: secret_participants[2]
1390 .get_secret_share()
1391 .unwrap()
1392 .value
1393 .0
1394 .to_repr()
1395 .as_ref()
1396 .to_vec(),
1397 },
1398 );
1399
1400 let mut signing_package = BTreeMap::new();
1401 let mut signing_commitments = Vec::new();
1402
1403 for (id, secret_share) in &secret_shares {
1404 let res = scheme.signing_round1(&secret_share, &mut rng);
1405 assert!(res.is_ok());
1406 let (nonces, commitments) = res.unwrap();
1407 signing_package.insert(id.clone(), (nonces, secret_share));
1408 signing_commitments.push((id.clone(), commitments));
1409 }
1410
1411 let mut verifying_shares = Vec::new();
1412 let mut signature_shares = Vec::new();
1413 for (id, (nonces, secret_share)) in signing_package {
1414 let res = scheme.signing_round2(
1415 DKG_MSG,
1416 &signing_commitments,
1417 &nonces,
1418 &KeyPackage {
1419 identifier: id.clone(),
1420 secret_share: secret_share.clone(),
1421 verifying_key: verifying_key.clone(),
1422 threshold: NonZeroU16::new(threshold as u16).unwrap(),
1423 },
1424 );
1425 let signature = res.unwrap();
1426 signature_shares.push((id.clone(), signature));
1427 verifying_shares.push((id.clone(), scheme.verifying_share(&secret_share).unwrap()));
1428 }
1429
1430 let res = scheme.aggregate(
1431 DKG_MSG,
1432 &signing_commitments,
1433 &signature_shares,
1434 &verifying_shares,
1435 &verifying_key,
1436 );
1437 assert!(res.is_ok());
1438 let signature = res.unwrap();
1439 (verifying_key, signature)
1440 }
1441
1442 #[test]
1443 fn dkg_k256_taproot() {
1444 let (verifying_key, signature) =
1445 dkg_core::<k256::ProjectivePoint>(Scheme::K256Taproot, None);
1446
1447 let res = Scheme::K256Taproot.verify(DKG_MSG, &verifying_key, &signature);
1448 assert!(res.is_ok());
1449 let verifying_key: k256::schnorr::VerifyingKey = verifying_key.try_into().unwrap();
1450 let signature: k256::schnorr::Signature = signature.try_into().unwrap();
1451 let msg = Sha256::digest(DKG_MSG);
1452 assert!(verifying_key.verify_raw(&msg, &signature).is_ok());
1453 }
1454
1455 #[test]
1456 fn dkg_jubjub() {
1457 let (verifying_key, signature) = dkg_core::<jubjub::SubgroupPoint>(
1458 Scheme::RedJubjubBlake2b512,
1459 Some(frost_redjubjub::JubjubGroup::generator()),
1460 );
1461
1462 let verifying_key: reddsa::VerificationKey<reddsa::sapling::SpendAuth> =
1464 verifying_key.try_into().unwrap();
1465 let signature: reddsa::Signature<reddsa::sapling::SpendAuth> =
1466 signature.try_into().unwrap();
1467 assert!(verifying_key.verify(DKG_MSG, &signature).is_ok());
1468 }
1469
1470 #[test]
1471 fn dkg_pallas() {
1472 let (verifying_key, signature) = dkg_core::<pallas::Point>(
1473 Scheme::RedPallasBlake2b512,
1474 Some(frost_redpallas::PallasGroup::generator()),
1475 );
1476
1477 let verifying_key: reddsa::VerificationKey<reddsa::orchard::SpendAuth> =
1479 verifying_key.try_into().unwrap();
1480 let signature: reddsa::Signature<reddsa::orchard::SpendAuth> =
1481 signature.try_into().unwrap();
1482 assert!(verifying_key.verify(DKG_MSG, &signature).is_ok());
1483 }
1484
1485 #[test]
1486 fn dkg_decaf377() {
1487 let (verifying_key, signature) =
1488 dkg_core::<decaf377::Element>(Scheme::RedDecaf377Blake2b512, None);
1489
1490 let pk: decaf377_rdsa::VerificationKey<decaf377_rdsa::SpendAuth> =
1491 verifying_key.try_into().unwrap();
1492 let sg: decaf377_rdsa::Signature<decaf377_rdsa::SpendAuth> = signature.try_into().unwrap();
1493 assert!(pk.verify(DKG_MSG, &sg).is_ok());
1494 }
1495
1496 #[test]
1497 fn dkg_schnorrkel() {
1498 let (verifying_key, signature) =
1499 dkg_core::<curve25519::WrappedRistretto>(Scheme::SchnorrkelSubstrate, None);
1500
1501 let res = Scheme::SchnorrkelSubstrate.verify(DKG_MSG, &verifying_key, &signature);
1502 assert!(res.is_ok());
1503 let pk: schnorrkel::PublicKey = verifying_key.try_into().unwrap();
1504 let sg: schnorrkel::Signature = signature.try_into().unwrap();
1505 assert!(pk.verify_simple(b"substrate", DKG_MSG, &sg).is_ok());
1506 }
1507}