lit_frost/
lib.rs

1//! FROST is a threshold signature scheme that allows a group of signers to
2//! produce a single signature on a message. The signature is valid if and only
3//! if at least `threshold` of the signers have signed the message.
4//! FROST is based on the [FROST paper](https://eprint.iacr.org/2020/852.pdf)
5//! and the [FROST RFC](https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/).
6//!
7//! This crate centers around picking a signature scheme and generating the
8//! necessary keys to use FROST. The signature scheme is defined by the
9//! [`Scheme`] enum. All other types in this crate are data objects that support
10//! the signature schemes.
11//!
12//! FROST requires 2 rounds to complete a signature. The first round is
13//! performed by the signers to generate [`SigningNonces`] and
14//! [`SigningCommitments`]. Signers can either generate these values
15//! in advance using [`Scheme::pregenerate_signing_nonces`] or generate them
16//! on the fly using [`Scheme::signing_round1`]. [`Scheme::signing_round1`] only generates
17//! one nonce and commitment to will be used immediately.
18//!
19//! The second round is performed by the signers to generate a
20//! [`SignatureShare`]. [`Scheme::signing_round2`] performs the second round of the
21//! signing protocol and generates a [`SignatureShare`].
22//!
23//! The [`SignatureShare`]s can then be aggregated into a single
24//! [`Signature`] using [`Scheme::aggregate`] by the signature recipient.
25//! The [`Signature`] can then be verified using [`Scheme::verify`] by anyone.
26//!
27//! [`SigningShare`]s are generated using distributed key generation (DKG) and
28//! help privately by each signer. [`SigningNonces`] must also be treated as
29//! secret values known by the signers and used only once per signing operation.
30//!
31//! [`SigningShare`]s can be converted from the most popular libraries using
32//! the [`From`] trait.
33#![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"))]
102/// Export the RedJubJub Generator point
103pub fn red_jubjub_generator() -> jubjub::SubgroupPoint {
104    <frost_redjubjub::JubjubGroup as frost_core::Group>::generator()
105}
106
107
108/// The FROST supported signature schemes
109#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, Default)]
110#[repr(u8)]
111pub enum Scheme {
112    #[default]
113    /// Compute the Ed25519 signature using the SHA-512 hash function
114    Ed25519Sha512 = 1,
115    /// Compute the Ed448 signature using the SHAKE-256 hash function
116    Ed448Shake256 = 2,
117    /// Compute the Ristretto25519 signature using the SHA-512 hash function
118    Ristretto25519Sha512 = 3,
119    /// Compute the Secp256k1 schnorr signature using the SHA-256 hash function
120    K256Sha256 = 4,
121    /// Compute the NistP256 schnorr signature using the SHA-256 hash function
122    P256Sha256 = 5,
123    /// Compute the NistP384 schnorr signature using the SHA-384 hash function
124    P384Sha384 = 6,
125    /// Compute the RedJubjub schnorr signature using the Blake2b-512 hash function
126    RedJubjubBlake2b512 = 7,
127    /// Compute the Secp256k1 schnorr signature using the taproot hash function
128    K256Taproot = 8,
129    /// Compute the RedDecaf377 schnorr signature using the Blake2b-512 hash function
130    RedDecaf377Blake2b512 = 9,
131    /// Compute the Schnorrkel signature using the Merlin-Strobe128 hash function
132    /// for the Polkadot substrate chain
133    SchnorrkelSubstrate = 10,
134    /// Compute the RedPallas schnorr signature using the Blake2b-512 hash function
135    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    /// Pregenerate a `count` of signing nonces and commitments that can be used
219    /// later to sign a message. These nonce MUST only be used once, otherwise
220    /// the long-lived signing key will be leaked.
221    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    /// Compute the first round of the signing protocol if no pregenerated nonces and commitments are available.
263    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    /// Compute the second round of the signing protocol and generate a signature.
301    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    /// Combine the signature shares into a single signature.
399    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                // The Taproot signature requires only 64 bytes
496                // which is correctly handled here for dropping the correct bytes
497                let sig: k256::schnorr::Signature = signature.try_into()?;
498                // Now convert it back in the correct form
499                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                // The Schnorrkel signature requires some bits set
517                // to indicate the signature is a Schnorrkel signature
518                // Handle that here since the default frost signature does not.
519                let sig: schnorrkel::Signature = signature.try_into()?;
520                // Now convert it back with the correct bits set
521                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    /// Verify a purported signature over message made by this verification key.
534    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    /// Get the [`VerifyingShare`] from a [`SigningShare`]
591    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    /// Perform a key generation with a trusted dealer.
704    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    /// Return the user-friendly name of the ciphersuite
769    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/// The byte order for the ciphersuite
787#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)]
788pub enum ByteOrder {
789    /// Big endian byte order
790    #[default]
791    BigEndian,
792    /// Little endian byte order
793    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"))]
943// #[cfg(test)]
944fn 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                // The new frost_core API only reports one culprit at a time
1059                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        // Clear the high bits
1084        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    // verify that the threshold of 2 is enough to sign a message
1232    #[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)), &params)
1310                .unwrap(),
1311            SecretParticipant::new_secret(IdentifierPrimeField(G::Scalar::from(2u64)), &params)
1312                .unwrap(),
1313            SecretParticipant::new_secret(IdentifierPrimeField(G::Scalar::from(3u64)), &params)
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        // Orchard uses the pasta curves not jubjub
1463        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        // Orchard uses the pasta curves not jubjub
1478        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}