frost_secp256k1_tr/
lib.rs

1#![no_std]
2#![allow(non_snake_case)]
3#![deny(missing_docs)]
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![doc = include_str!("../README.md")]
7#![doc = document_features::document_features!()]
8
9extern crate alloc;
10
11use alloc::vec;
12use alloc::{borrow::Cow, collections::BTreeMap, vec::Vec};
13
14use frost_rerandomized::RandomizedCiphersuite;
15use k256::elliptic_curve::ops::Reduce;
16use k256::{
17    elliptic_curve::{
18        bigint::U256,
19        group::prime::PrimeCurveAffine,
20        hash2curve::{hash_to_field, ExpandMsgXmd},
21        point::AffineCoordinates,
22        sec1::{FromEncodedPoint, ToEncodedPoint},
23        Field as FFField, PrimeField,
24    },
25    AffinePoint, ProjectivePoint, Scalar,
26};
27use rand_core::{CryptoRng, RngCore};
28use sha2::{Digest, Sha256};
29
30use frost_core::{self as frost, random_nonzero};
31
32use keys::EvenY;
33use keys::Tweak;
34
35#[cfg(test)]
36mod tests;
37
38// Re-exports in our public API
39#[cfg(feature = "serde")]
40pub use frost_core::serde;
41pub use frost_core::{
42    Challenge, Ciphersuite, Element, Field, FieldError, Group, GroupCommitment, GroupError,
43};
44pub use rand_core;
45
46/// An error.
47pub type Error = frost_core::Error<Secp256K1Sha256TR>;
48
49/// An implementation of the FROST(secp256k1, SHA-256) ciphersuite scalar field.
50#[derive(Clone, Copy)]
51pub struct Secp256K1ScalarField;
52
53impl Field for Secp256K1ScalarField {
54    type Scalar = Scalar;
55
56    type Serialization = [u8; 32];
57
58    fn zero() -> Self::Scalar {
59        Scalar::ZERO
60    }
61
62    fn one() -> Self::Scalar {
63        Scalar::ONE
64    }
65
66    fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError> {
67        // [`Scalar`]'s Eq/PartialEq does a constant-time comparison
68        if *scalar == <Self as Field>::zero() {
69            Err(FieldError::InvalidZeroScalar)
70        } else {
71            Ok(scalar.invert().unwrap())
72        }
73    }
74
75    fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
76        Scalar::random(rng)
77    }
78
79    fn serialize(scalar: &Self::Scalar) -> Self::Serialization {
80        scalar.to_bytes().into()
81    }
82
83    fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError> {
84        let field_bytes: &k256::FieldBytes = buf.into();
85        match Scalar::from_repr(*field_bytes).into() {
86            Some(s) => Ok(s),
87            None => Err(FieldError::MalformedScalar),
88        }
89    }
90
91    fn little_endian_serialize(scalar: &Self::Scalar) -> Self::Serialization {
92        let mut array = Self::serialize(scalar);
93        array.reverse();
94        array
95    }
96}
97
98/// An implementation of the FROST(secp256k1, SHA-256) ciphersuite group.
99#[derive(Clone, Copy, PartialEq, Eq)]
100pub struct Secp256K1Group;
101
102impl Group for Secp256K1Group {
103    type Field = Secp256K1ScalarField;
104
105    type Element = ProjectivePoint;
106
107    /// [SEC 1][1] serialization of a compressed point in secp256k1 takes 33 bytes
108    /// (1-byte prefix and 32 bytes for the coordinate).
109    ///
110    /// Note that, in the SEC 1 spec, the identity is encoded as a single null byte;
111    /// but here we pad with zeroes. This is acceptable as the identity _should_ never
112    /// be serialized in FROST, else we error.
113    ///
114    /// [1]: https://secg.org/sec1-v2.pdf
115    type Serialization = [u8; 33];
116
117    fn cofactor() -> <Self::Field as Field>::Scalar {
118        Scalar::ONE
119    }
120
121    fn identity() -> Self::Element {
122        ProjectivePoint::IDENTITY
123    }
124
125    fn generator() -> Self::Element {
126        ProjectivePoint::GENERATOR
127    }
128
129    fn serialize(element: &Self::Element) -> Result<Self::Serialization, GroupError> {
130        if *element == Self::identity() {
131            return Err(GroupError::InvalidIdentityElement);
132        }
133        let mut fixed_serialized = [0; 33];
134        let serialized_point = element.to_affine().to_encoded_point(true);
135        let serialized = serialized_point.as_bytes();
136        fixed_serialized.copy_from_slice(serialized);
137        Ok(fixed_serialized)
138    }
139
140    fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
141        let encoded_point =
142            k256::EncodedPoint::from_bytes(buf).map_err(|_| GroupError::MalformedElement)?;
143
144        match Option::<AffinePoint>::from(AffinePoint::from_encoded_point(&encoded_point)) {
145            Some(point) => {
146                if point.is_identity().into() {
147                    // This is actually impossible since the identity is encoded a a single byte
148                    // which will never happen since we receive a 33-byte buffer.
149                    // We leave the check for consistency.
150                    Err(GroupError::InvalidIdentityElement)
151                } else {
152                    Ok(ProjectivePoint::from(point))
153                }
154            }
155            None => Err(GroupError::MalformedElement),
156        }
157    }
158}
159
160fn hash_to_array(inputs: &[&[u8]]) -> [u8; 32] {
161    let mut h = Sha256::new();
162    for i in inputs {
163        h.update(i);
164    }
165    let mut output = [0u8; 32];
166    output.copy_from_slice(h.finalize().as_slice());
167    output
168}
169
170fn hash_to_scalar(domain: &[&[u8]], msg: &[u8]) -> Scalar {
171    let mut u = [Secp256K1ScalarField::zero()];
172    hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&[msg], domain, &mut u)
173        .expect("should never return error according to error cases described in ExpandMsgXmd");
174    u[0]
175}
176
177/// Context string from the ciphersuite in the [spec].
178///
179/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-1
180const CONTEXT_STRING: &str = "FROST-secp256k1-SHA256-TR-v1";
181
182/// An implementation of the FROST(secp256k1, SHA-256) ciphersuite.
183#[derive(Clone, Copy, PartialEq, Eq, Debug)]
184pub struct Secp256K1Sha256TR;
185
186/// Digest the hasher to a Scalar
187fn hasher_to_scalar(hasher: Sha256) -> Scalar {
188    // This is acceptable because secp256k1 curve order is close to 2^256,
189    // and the input is uniformly random since it is a hash output, therefore
190    // the bias is negligibly small.
191    Scalar::reduce(U256::from_be_slice(&hasher.finalize()))
192}
193
194/// Create a BIP340 compliant tagged hash
195fn tagged_hash(tag: &str) -> Sha256 {
196    let mut hasher = Sha256::new();
197    let mut tag_hasher = Sha256::new();
198    tag_hasher.update(tag.as_bytes());
199    let tag_hash = tag_hasher.finalize();
200    hasher.update(tag_hash);
201    hasher.update(tag_hash);
202    hasher
203}
204
205/// Create a BIP341 compliant taproot tweak
206fn tweak<T: AsRef<[u8]>>(
207    public_key: &<<Secp256K1Sha256TR as Ciphersuite>::Group as Group>::Element,
208    merkle_root: Option<T>,
209) -> Scalar {
210    match merkle_root {
211        None => {
212            let mut hasher = tagged_hash("TapTweak");
213            hasher.update(public_key.to_affine().x());
214            hasher_to_scalar(hasher)
215        }
216        Some(root) => {
217            let mut hasher = tagged_hash("TapTweak");
218            hasher.update(public_key.to_affine().x());
219            hasher.update(root.as_ref());
220            hasher_to_scalar(hasher)
221        }
222    }
223}
224
225// Negate a Nonce
226fn negate_nonce(nonce: &frost_core::round1::Nonce<S>) -> frost_core::round1::Nonce<S> {
227    frost_core::round1::Nonce::<S>::from_scalar(-nonce.to_scalar())
228}
229
230// Negate a SigningNonces
231fn negate_nonces(signing_nonces: &round1::SigningNonces) -> round1::SigningNonces {
232    // TODO: this recomputes commitments which is expensive, and not needed.
233    // Create an `internals` SigningNonces::from_nonces_and_commitments or
234    // something similar.
235    round1::SigningNonces::from_nonces(
236        negate_nonce(signing_nonces.hiding()),
237        negate_nonce(signing_nonces.binding()),
238    )
239}
240
241impl Ciphersuite for Secp256K1Sha256TR {
242    const ID: &'static str = CONTEXT_STRING;
243
244    type Group = Secp256K1Group;
245
246    type HashOutput = [u8; 32];
247
248    type SignatureSerialization = [u8; 64];
249
250    /// H1 for FROST(secp256k1, SHA-256)
251    ///
252    /// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-2.2.2.1
253    fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
254        hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"rho"], m)
255    }
256
257    /// H2 for FROST(secp256k1, SHA-256)
258    ///
259    /// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-2.2.2.2
260    fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
261        let mut hasher = tagged_hash("BIP0340/challenge");
262        hasher.update(m);
263        hasher_to_scalar(hasher)
264    }
265
266    /// H3 for FROST(secp256k1, SHA-256)
267    ///
268    /// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-2.2.2.3
269    fn H3(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
270        hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"nonce"], m)
271    }
272
273    /// H4 for FROST(secp256k1, SHA-256)
274    ///
275    /// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-2.2.2.4
276    fn H4(m: &[u8]) -> Self::HashOutput {
277        hash_to_array(&[CONTEXT_STRING.as_bytes(), b"msg", m])
278    }
279
280    /// H5 for FROST(secp256k1, SHA-256)
281    ///
282    /// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-14.html#section-6.5-2.2.2.5
283    fn H5(m: &[u8]) -> Self::HashOutput {
284        hash_to_array(&[CONTEXT_STRING.as_bytes(), b"com", m])
285    }
286
287    /// HDKG for FROST(secp256k1, SHA-256)
288    fn HDKG(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
289        Some(hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"dkg"], m))
290    }
291
292    /// HID for FROST(secp256k1, SHA-256)
293    fn HID(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
294        Some(hash_to_scalar(&[CONTEXT_STRING.as_bytes(), b"id"], m))
295    }
296
297    // Sign, negating the key if required by BIP-340.
298    fn single_sign<R: RngCore + CryptoRng>(
299        signing_key: &SigningKey,
300        rng: R,
301        message: &[u8],
302    ) -> Signature {
303        let signing_key = signing_key.into_even_y(None);
304        signing_key.default_sign(rng, message)
305    }
306
307    // Preprocess sign inputs, negating the keys in the KeyPackage if required
308    // by BIP-340.
309    fn pre_sign<'a>(
310        signing_package: &'a SigningPackage,
311        signer_nonces: &'a round1::SigningNonces,
312        key_package: &'a keys::KeyPackage,
313    ) -> Result<
314        (
315            Cow<'a, SigningPackage>,
316            Cow<'a, round1::SigningNonces>,
317            Cow<'a, keys::KeyPackage>,
318        ),
319        Error,
320    > {
321        Ok((
322            Cow::Borrowed(signing_package),
323            Cow::Borrowed(signer_nonces),
324            Cow::Owned(key_package.clone().into_even_y(None)),
325        ))
326    }
327
328    // Preprocess sign inputs, negating the keys in the PublicKeyPackage if
329    // required by BIP-340.
330    fn pre_aggregate<'a>(
331        signing_package: &'a SigningPackage,
332        signature_shares: &'a BTreeMap<Identifier, round2::SignatureShare>,
333        public_key_package: &'a keys::PublicKeyPackage,
334    ) -> Result<
335        (
336            Cow<'a, SigningPackage>,
337            Cow<'a, BTreeMap<Identifier, round2::SignatureShare>>,
338            Cow<'a, keys::PublicKeyPackage>,
339        ),
340        Error,
341    > {
342        Ok((
343            Cow::Borrowed(signing_package),
344            Cow::Borrowed(signature_shares),
345            Cow::Owned(public_key_package.clone().into_even_y(None)),
346        ))
347    }
348
349    // Preprocess verify inputs, negating the VerifyingKey and `signature.R` if required by
350    // BIP-340.
351    fn pre_verify<'a>(
352        message: &'a [u8],
353        signature: &'a Signature,
354        public_key: &'a VerifyingKey,
355    ) -> Result<(Cow<'a, [u8]>, Cow<'a, Signature>, Cow<'a, VerifyingKey>), Error> {
356        let public_key = public_key.into_even_y(None);
357        let signature = signature.into_even_y(None);
358        Ok((
359            Cow::Borrowed(message),
360            Cow::Owned(signature),
361            Cow::Owned(public_key),
362        ))
363    }
364
365    // Generate a nonce, negating it if required by BIP-340.
366    fn generate_nonce<R: RngCore + CryptoRng>(
367        rng: &mut R,
368    ) -> (
369        <<Self::Group as Group>::Field as Field>::Scalar,
370        <Self::Group as Group>::Element,
371    ) {
372        let k = random_nonzero::<Self, R>(rng);
373        let R = <Self::Group>::generator() * k;
374        if R.to_affine().y_is_odd().into() {
375            (-k, -R)
376        } else {
377            (k, R)
378        }
379    }
380
381    // Compute the challenge. Per BIP-340, only the X coordinate of R and
382    // verifying_key are hashed, unlike vanilla FROST.
383    fn challenge(
384        R: &Element<S>,
385        verifying_key: &VerifyingKey,
386        message: &[u8],
387    ) -> Result<Challenge<S>, Error> {
388        let mut preimage = vec![];
389        preimage.extend_from_slice(&R.to_affine().x());
390        preimage.extend_from_slice(&verifying_key.to_element().to_affine().x());
391        preimage.extend_from_slice(message);
392        Ok(Challenge::from_scalar(S::H2(&preimage[..])))
393    }
394
395    /// Compute a signature share, negating the nonces if required by BIP-340.
396    fn compute_signature_share(
397        group_commitment: &GroupCommitment<S>,
398        signer_nonces: &round1::SigningNonces,
399        binding_factor: frost::BindingFactor<S>,
400        lambda_i: <<Self::Group as Group>::Field as Field>::Scalar,
401        key_package: &frost::keys::KeyPackage<S>,
402        challenge: Challenge<S>,
403    ) -> round2::SignatureShare {
404        let signer_nonces = if !group_commitment.has_even_y() {
405            negate_nonces(signer_nonces)
406        } else {
407            signer_nonces.clone()
408        };
409
410        frost::round2::compute_signature_share(
411            &signer_nonces,
412            binding_factor,
413            lambda_i,
414            key_package,
415            challenge,
416        )
417    }
418
419    /// Verify a signature share, negating the group commitment share if
420    /// required by BIP-340.
421    fn verify_share(
422        group_commitment: &GroupCommitment<S>,
423        signature_share: &frost_core::round2::SignatureShare<S>,
424        identifier: Identifier,
425        group_commitment_share: &frost_core::round1::GroupCommitmentShare<S>,
426        verifying_share: &frost_core::keys::VerifyingShare<S>,
427        lambda_i: Scalar,
428        challenge: &Challenge<S>,
429    ) -> Result<(), Error> {
430        let group_commitment_share = if !group_commitment.has_even_y() {
431            frost_core::round1::GroupCommitmentShare::from_element(
432                -group_commitment_share.to_element(),
433            )
434        } else {
435            *group_commitment_share
436        };
437        signature_share.verify(
438            identifier,
439            &group_commitment_share,
440            verifying_share,
441            lambda_i,
442            challenge,
443        )
444    }
445
446    /// Serialize a signature in compact BIP340 format, with an x-only R point.
447    fn serialize_signature(signature: &Signature) -> Result<Vec<u8>, Error> {
448        let R_bytes = Self::Group::serialize(signature.R())?;
449        let z_bytes = <Self::Group as Group>::Field::serialize(signature.z());
450
451        let mut bytes = vec![0u8; 64];
452        bytes[..32].copy_from_slice(&R_bytes[1..]);
453        bytes[32..].copy_from_slice(&z_bytes);
454        Ok(bytes)
455    }
456
457    /// Deserialize a signature in compact BIP340 format, with an x-only R point.
458    fn deserialize_signature(bytes: &[u8]) -> Result<Signature, Error> {
459        if bytes.len() != 64 {
460            return Err(Error::MalformedSignature);
461        }
462
463        let mut R_bytes = [0u8; 33];
464        R_bytes[0] = 0x02; // taproot signatures always have an even R point
465        R_bytes[1..].copy_from_slice(&bytes[..32]);
466
467        let mut z_bytes = [0u8; 32];
468        z_bytes.copy_from_slice(&bytes[32..]);
469
470        let R = Self::Group::deserialize(&R_bytes)?;
471        let z = <Self::Group as Group>::Field::deserialize(&z_bytes)?;
472
473        Ok(Signature::new(R, z))
474    }
475
476    /// Post-process the DKG output. We add an unusable taproot tweak to the
477    /// group key computed by a DKG run, to prevent peers from inserting rogue
478    /// tapscript tweaks into the group's joint public key.
479    fn post_dkg(
480        key_package: keys::KeyPackage,
481        public_key_package: keys::PublicKeyPackage,
482    ) -> Result<(keys::KeyPackage, keys::PublicKeyPackage), Error> {
483        // From BIP-341:
484        // > If the spending conditions do not require a script path, the output
485        // > key should commit to an unspendable script path instead of having
486        // > no script path. This can be achieved by computing the output key
487        // > point as Q = P + int(hashTapTweak(bytes(P)))G.
488        Ok((
489            key_package.tweak::<&[u8]>(None),
490            public_key_package.tweak::<&[u8]>(None),
491        ))
492    }
493}
494
495impl RandomizedCiphersuite for Secp256K1Sha256TR {
496    fn hash_randomizer(m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
497        Some(hash_to_scalar(
498            &[CONTEXT_STRING.as_bytes(), b"randomizer"],
499            m,
500        ))
501    }
502}
503
504type S = Secp256K1Sha256TR;
505
506/// A FROST(secp256k1, SHA-256) participant identifier.
507pub type Identifier = frost::Identifier<S>;
508
509/// FROST(secp256k1, SHA-256) keys, key generation, key shares.
510pub mod keys {
511    use super::*;
512
513    /// The identifier list to use when generating key shares.
514    pub type IdentifierList<'a> = frost::keys::IdentifierList<'a, S>;
515
516    /// Allows all participants' keys to be generated using a central, trusted
517    /// dealer.
518    pub fn generate_with_dealer<RNG: RngCore + CryptoRng>(
519        max_signers: u16,
520        min_signers: u16,
521        identifiers: IdentifierList,
522        mut rng: RNG,
523    ) -> Result<(BTreeMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
524        frost::keys::generate_with_dealer(max_signers, min_signers, identifiers, &mut rng)
525    }
526
527    /// Splits an existing key into FROST shares.
528    ///
529    /// This is identical to [`generate_with_dealer`] but receives an existing key
530    /// instead of generating a fresh one. This is useful in scenarios where
531    /// the key needs to be generated externally or must be derived from e.g. a
532    /// seed phrase.
533    pub fn split<R: RngCore + CryptoRng>(
534        secret: &SigningKey,
535        max_signers: u16,
536        min_signers: u16,
537        identifiers: IdentifierList,
538        rng: &mut R,
539    ) -> Result<(BTreeMap<Identifier, SecretShare>, PublicKeyPackage), Error> {
540        frost::keys::split(secret, max_signers, min_signers, identifiers, rng)
541    }
542
543    /// Recompute the secret from t-of-n secret shares using Lagrange interpolation.
544    ///
545    /// This can be used if for some reason the original key must be restored; e.g.
546    /// if threshold signing is not required anymore.
547    ///
548    /// This is NOT required to sign with FROST; the whole point of FROST is being
549    /// able to generate signatures only using the shares, without having to
550    /// reconstruct the original key.
551    ///
552    /// The caller is responsible for providing at least `min_signers` shares;
553    /// if less than that is provided, a different key will be returned.
554    pub fn reconstruct(secret_shares: &[KeyPackage]) -> Result<SigningKey, Error> {
555        frost::keys::reconstruct(secret_shares)
556    }
557
558    /// Secret and public key material generated by a dealer performing
559    /// [`generate_with_dealer`].
560    ///
561    /// # Security
562    ///
563    /// To derive a FROST(secp256k1, SHA-256) keypair, the receiver of the [`SecretShare`] *must* call
564    /// .into(), which under the hood also performs validation.
565    pub type SecretShare = frost::keys::SecretShare<S>;
566
567    /// A secret scalar value representing a signer's share of the group secret.
568    pub type SigningShare = frost::keys::SigningShare<S>;
569
570    /// A public group element that represents a single signer's public verification share.
571    pub type VerifyingShare = frost::keys::VerifyingShare<S>;
572
573    /// A FROST(secp256k1, SHA-256) keypair, which can be generated either by a trusted dealer or using
574    /// a DKG.
575    ///
576    /// When using a central dealer, [`SecretShare`]s are distributed to
577    /// participants, who then perform verification, before deriving
578    /// [`KeyPackage`]s, which they store to later use during signing.
579    pub type KeyPackage = frost::keys::KeyPackage<S>;
580
581    /// Public data that contains all the signers' public keys as well as the
582    /// group public key.
583    ///
584    /// Used for verification purposes before publishing a signature.
585    pub type PublicKeyPackage = frost::keys::PublicKeyPackage<S>;
586
587    /// Contains the commitments to the coefficients for our secret polynomial _f_,
588    /// used to generate participants' key shares.
589    ///
590    /// [`VerifiableSecretSharingCommitment`] contains a set of commitments to the coefficients (which
591    /// themselves are scalars) for a secret polynomial f, where f is used to
592    /// generate each ith participant's key share f(i). Participants use this set of
593    /// commitments to perform verifiable secret sharing.
594    ///
595    /// Note that participants MUST be assured that they have the *same*
596    /// [`VerifiableSecretSharingCommitment`], either by performing pairwise comparison, or by using
597    /// some agreed-upon public location for publication, where each participant can
598    /// ensure that they received the correct (and same) value.
599    pub type VerifiableSecretSharingCommitment = frost::keys::VerifiableSecretSharingCommitment<S>;
600
601    /// Trait for ensuring the group public key has an even Y coordinate.
602    ///
603    /// In BIP-340, public keys are encoded with only the X coordinate, which
604    /// means that two Y coordinates are possible. The specification says that
605    /// the coordinate which is even must be used. Alternatively, something
606    /// equivalent can be accomplished by simply converting any existing
607    /// (non-encoded) public key to have an even Y coordinate.
608    ///
609    /// This trait is used to enable this procedure, by changing the private and
610    /// public keys to ensure that the public key has a even Y coordinate. This
611    /// is done by simply negating both keys if Y is even (in a field, negating
612    /// is equivalent to computing p - x where p is the prime modulus. Since p
613    /// is odd, if x is odd then the result will be even). Fortunately this
614    /// works even after Shamir secret sharing, in the individual signing and
615    /// verifying shares, since it's linear.
616    pub trait EvenY {
617        /// Return if the given type has a group public key with an even Y
618        /// coordinate.
619        fn has_even_y(&self) -> bool;
620
621        /// Convert the given type to make sure the group public key has an even
622        /// Y coordinate. `is_even` can be specified if evenness was already
623        /// determined beforehand.
624        fn into_even_y(self, is_even: Option<bool>) -> Self;
625    }
626
627    impl EvenY for PublicKeyPackage {
628        fn has_even_y(&self) -> bool {
629            let verifying_key = self.verifying_key();
630            (!verifying_key.to_element().to_affine().y_is_odd()).into()
631        }
632
633        fn into_even_y(self, is_even: Option<bool>) -> Self {
634            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
635            if !is_even {
636                // Negate verifying key
637                let verifying_key = VerifyingKey::new(-self.verifying_key().to_element());
638                // Recreate verifying share map with negated VerifyingShares
639                // values.
640                let verifying_shares: BTreeMap<_, _> = self
641                    .verifying_shares()
642                    .iter()
643                    .map(|(i, vs)| {
644                        let vs = VerifyingShare::new(-vs.to_element());
645                        (*i, vs)
646                    })
647                    .collect();
648                PublicKeyPackage::new(verifying_shares, verifying_key)
649            } else {
650                self
651            }
652        }
653    }
654
655    impl EvenY for KeyPackage {
656        fn has_even_y(&self) -> bool {
657            let verifying_key = self.verifying_key();
658            (!verifying_key.to_element().to_affine().y_is_odd()).into()
659        }
660
661        fn into_even_y(self, is_even: Option<bool>) -> Self {
662            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
663            if !is_even {
664                // Negate all components
665                let verifying_key = VerifyingKey::new(-self.verifying_key().to_element());
666                let signing_share = SigningShare::new(-self.signing_share().to_scalar());
667                let verifying_share = VerifyingShare::new(-self.verifying_share().to_element());
668                KeyPackage::new(
669                    *self.identifier(),
670                    signing_share,
671                    verifying_share,
672                    verifying_key,
673                    *self.min_signers(),
674                )
675            } else {
676                self
677            }
678        }
679    }
680
681    impl EvenY for VerifyingKey {
682        fn has_even_y(&self) -> bool {
683            (!self.to_element().to_affine().y_is_odd()).into()
684        }
685
686        fn into_even_y(self, is_even: Option<bool>) -> Self {
687            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
688            if !is_even {
689                VerifyingKey::new(-self.to_element())
690            } else {
691                self
692            }
693        }
694    }
695
696    impl EvenY for GroupCommitment<S> {
697        fn has_even_y(&self) -> bool {
698            (!self.clone().to_element().to_affine().y_is_odd()).into()
699        }
700
701        fn into_even_y(self, is_even: Option<bool>) -> Self {
702            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
703            if !is_even {
704                Self::from_element(-self.to_element())
705            } else {
706                self
707            }
708        }
709    }
710
711    impl EvenY for Signature {
712        fn has_even_y(&self) -> bool {
713            (!self.R().to_affine().y_is_odd()).into()
714        }
715
716        fn into_even_y(self, is_even: Option<bool>) -> Self {
717            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
718            if !is_even {
719                Self::new(-*self.R(), *self.z())
720            } else {
721                self
722            }
723        }
724    }
725
726    impl EvenY for SigningKey {
727        fn has_even_y(&self) -> bool {
728            (!Into::<VerifyingKey>::into(self)
729                .to_element()
730                .to_affine()
731                .y_is_odd())
732            .into()
733        }
734
735        fn into_even_y(self, is_even: Option<bool>) -> Self {
736            let is_even = is_even.unwrap_or_else(|| self.has_even_y());
737            if !is_even {
738                SigningKey::from_scalar(-self.to_scalar())
739                    .expect("the original SigningKey must be nonzero")
740            } else {
741                self
742            }
743        }
744    }
745
746    /// Trait for tweaking a key component following BIP-341
747    pub trait Tweak: EvenY {
748        /// Convert the given type to add a tweak.
749        fn tweak<T: AsRef<[u8]>>(self, merkle_root: Option<T>) -> Self;
750    }
751
752    impl Tweak for PublicKeyPackage {
753        fn tweak<T: AsRef<[u8]>>(self, merkle_root: Option<T>) -> Self {
754            let t = tweak(&self.verifying_key().to_element(), merkle_root);
755            let tp = ProjectivePoint::GENERATOR * t;
756            let public_key_package = self.into_even_y(None);
757            let verifying_key =
758                VerifyingKey::new(public_key_package.verifying_key().to_element() + tp);
759            // Recreate verifying share map with negated VerifyingShares
760            // values.
761            let verifying_shares: BTreeMap<_, _> = public_key_package
762                .verifying_shares()
763                .iter()
764                .map(|(i, vs)| {
765                    let vs = VerifyingShare::new(vs.to_element() + tp);
766                    (*i, vs)
767                })
768                .collect();
769            PublicKeyPackage::new(verifying_shares, verifying_key)
770        }
771    }
772
773    impl Tweak for KeyPackage {
774        fn tweak<T: AsRef<[u8]>>(self, merkle_root: Option<T>) -> Self {
775            let t = tweak(&self.verifying_key().to_element(), merkle_root);
776            let tp = ProjectivePoint::GENERATOR * t;
777            let key_package = self.into_even_y(None);
778            let verifying_key = VerifyingKey::new(key_package.verifying_key().to_element() + tp);
779            let signing_share = SigningShare::new(key_package.signing_share().to_scalar() + t);
780            let verifying_share =
781                VerifyingShare::new(key_package.verifying_share().to_element() + tp);
782            KeyPackage::new(
783                *key_package.identifier(),
784                signing_share,
785                verifying_share,
786                verifying_key,
787                *key_package.min_signers(),
788            )
789        }
790    }
791
792    pub mod dkg;
793    pub mod refresh;
794    pub mod repairable;
795}
796
797/// FROST(secp256k1, SHA-256) Round 1 functionality and types.
798pub mod round1 {
799    use crate::keys::SigningShare;
800
801    use super::*;
802
803    /// Comprised of FROST(secp256k1, SHA-256) hiding and binding nonces.
804    ///
805    /// Note that [`SigningNonces`] must be used *only once* for a signing
806    /// operation; re-using nonces will result in leakage of a signer's long-lived
807    /// signing key.
808    pub type SigningNonces = frost::round1::SigningNonces<S>;
809
810    /// Published by each participant in the first round of the signing protocol.
811    ///
812    /// This step can be batched if desired by the implementation. Each
813    /// SigningCommitment can be used for exactly *one* signature.
814    pub type SigningCommitments = frost::round1::SigningCommitments<S>;
815
816    /// A commitment to a signing nonce share.
817    pub type NonceCommitment = frost::round1::NonceCommitment<S>;
818
819    /// Performed once by each participant selected for the signing operation.
820    ///
821    /// Generates the signing nonces and commitments to be used in the signing
822    /// operation.
823    pub fn commit<RNG>(secret: &SigningShare, rng: &mut RNG) -> (SigningNonces, SigningCommitments)
824    where
825        RNG: CryptoRng + RngCore,
826    {
827        frost::round1::commit::<S, RNG>(secret, rng)
828    }
829}
830
831/// Generated by the coordinator of the signing operation and distributed to
832/// each signing party.
833pub type SigningPackage = frost::SigningPackage<S>;
834
835/// FROST(secp256k1, SHA-256) Round 2 functionality and types, for signature share generation.
836pub mod round2 {
837    use keys::Tweak;
838
839    use super::*;
840
841    /// A FROST(secp256k1, SHA-256) participant's signature share, which the Coordinator will aggregate with all other signer's
842    /// shares into the joint signature.
843    pub type SignatureShare = frost::round2::SignatureShare<S>;
844
845    /// Performed once by each participant selected for the signing operation.
846    ///
847    /// Receives the message to be signed and a set of signing commitments and a set
848    /// of randomizing commitments to be used in that signing operation, including
849    /// that for this participant.
850    ///
851    /// Assumes the participant has already determined which nonce corresponds with
852    /// the commitment that was assigned by the coordinator in the SigningPackage.
853    pub fn sign(
854        signing_package: &SigningPackage,
855        signer_nonces: &round1::SigningNonces,
856        key_package: &keys::KeyPackage,
857    ) -> Result<SignatureShare, Error> {
858        frost::round2::sign(signing_package, signer_nonces, key_package)
859    }
860
861    /// Same as [`sign()`], but using a Taproot tweak as specified in BIP-341.
862    pub fn sign_with_tweak(
863        signing_package: &SigningPackage,
864        signer_nonces: &round1::SigningNonces,
865        key_package: &keys::KeyPackage,
866        merkle_root: Option<&[u8]>,
867    ) -> Result<SignatureShare, Error> {
868        let key_package = key_package.clone().tweak(merkle_root);
869        frost::round2::sign(signing_package, signer_nonces, &key_package)
870    }
871}
872
873/// A Schnorr signature on FROST(secp256k1, SHA-256).
874pub type Signature = frost_core::Signature<S>;
875
876/// Verifies each FROST(secp256k1, SHA-256) participant's signature share, and if all are valid,
877/// aggregates the shares into a signature to publish.
878///
879/// Resulting signature is compatible with verification of a plain Schnorr
880/// signature.
881///
882/// This operation is performed by a coordinator that can communicate with all
883/// the signing participants before publishing the final signature. The
884/// coordinator can be one of the participants or a semi-trusted third party
885/// (who is trusted to not perform denial of service attacks, but does not learn
886/// any secret information). Note that because the coordinator is trusted to
887/// report misbehaving parties in order to avoid publishing an invalid
888/// signature, if the coordinator themselves is a signer and misbehaves, they
889/// can avoid that step. However, at worst, this results in a denial of
890/// service attack due to publishing an invalid signature.
891pub fn aggregate(
892    signing_package: &SigningPackage,
893    signature_shares: &BTreeMap<Identifier, round2::SignatureShare>,
894    public_key_package: &keys::PublicKeyPackage,
895) -> Result<Signature, Error> {
896    frost::aggregate(signing_package, signature_shares, public_key_package)
897}
898
899/// Same as [`aggregate()`], but using a Taproot tweak as specified in BIP-341.
900pub fn aggregate_with_tweak(
901    signing_package: &SigningPackage,
902    signature_shares: &BTreeMap<Identifier, round2::SignatureShare>,
903    public_key_package: &keys::PublicKeyPackage,
904    merkle_root: Option<&[u8]>,
905) -> Result<Signature, Error> {
906    let public_key_package = public_key_package.clone().tweak(merkle_root);
907    frost::aggregate(signing_package, signature_shares, &public_key_package)
908}
909
910/// A signing key for a Schnorr signature on FROST(secp256k1, SHA-256).
911pub type SigningKey = frost_core::SigningKey<S>;
912
913/// A valid verifying key for Schnorr signatures on FROST(secp256k1, SHA-256).
914pub type VerifyingKey = frost_core::VerifyingKey<S>;