Skip to main content

frost_core/
traits.rs

1//! Traits used to abstract Ciphersuites.
2
3use core::{
4    fmt::Debug,
5    ops::{Add, Mul, Sub},
6};
7
8use alloc::{borrow::Cow, collections::BTreeMap, vec::Vec};
9use rand_core::{CryptoRng, RngCore};
10
11use crate::{
12    challenge,
13    keys::{KeyPackage, PublicKeyPackage, SecretShare, VerifyingShare},
14    random_nonzero,
15    round1::{self, SigningNonces},
16    round2::{self, SignatureShare},
17    BindingFactor, BindingFactorList, Challenge, Error, FieldError, GroupCommitment, GroupError,
18    Identifier, Signature, SigningKey, SigningPackage, VerifyingKey,
19};
20
21/// A prime order finite field GF(q) over which all scalar values for our prime order group can be
22/// multiplied are defined.
23///
24/// This trait does not have to be implemented for a finite field scalar itself, it can be a
25/// pass-through, implemented for a type just for the ciphersuite, and calls through to another
26/// implementation underneath, so that this trait does not have to be implemented for types you
27/// don't own.
28pub trait Field: Copy {
29    /// An element of the scalar field GF(p).
30    /// The Eq/PartialEq implementation MUST be constant-time.
31    type Scalar: Add<Output = Self::Scalar>
32        + Copy
33        + Clone
34        + Eq
35        + Mul<Output = Self::Scalar>
36        + PartialEq
37        + Sub<Output = Self::Scalar>
38        + Send
39        + Sync;
40
41    /// A unique byte array buf of fixed length N.
42    type Serialization: Clone + AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8]> + Debug;
43
44    /// Returns the zero element of the field, the additive identity.
45    fn zero() -> Self::Scalar;
46
47    /// Returns the one element of the field, the multiplicative identity.
48    fn one() -> Self::Scalar;
49
50    /// Computes the multiplicative inverse of an element of the scalar field, failing if the
51    /// element is zero.
52    fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError>;
53
54    /// Generate a random scalar from the entire space [0, l-1]
55    ///
56    /// <https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.6>
57    fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
58
59    /// A member function of a [`Field`] that maps a [`Scalar`] to a unique byte array buf of
60    /// fixed length Ne.
61    ///
62    /// <https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.16>
63    fn serialize(scalar: &Self::Scalar) -> Self::Serialization;
64
65    /// A member function of a [`Field`] that maps a [`Scalar`] to a unique byte array buf of
66    /// fixed length Ne, in little-endian order.
67    ///
68    /// This is used internally.
69    fn little_endian_serialize(scalar: &Self::Scalar) -> Self::Serialization;
70
71    /// A member function of a [`Field`] that attempts to map a byte array `buf` to a [`Scalar`].
72    ///
73    /// Fails if the input is not a valid byte representation of an [`Scalar`] of the
74    /// [`Field`]. This function can raise an [`Error`] if deserialization fails.
75    ///
76    /// <https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.18>
77    fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError>;
78}
79
80/// An element of the [`Ciphersuite`] `C`'s [`Group`]'s scalar [`Field`].
81pub type Scalar<C> = <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar;
82
83/// A prime-order group (or subgroup) that provides everything we need to create and verify Schnorr
84/// signatures.
85///
86/// This trait does not have to be implemented for the curve/element/point itself, it can be a
87/// pass-through, implemented for a type just for the ciphersuite, and calls through to another
88/// implementation underneath, so that this trait does not have to be implemented for types you
89/// don't own.
90pub trait Group: Copy + PartialEq {
91    /// A prime order finite field GF(q) over which all scalar values for our prime order group can
92    /// be multiplied are defined.
93    type Field: Field;
94
95    /// An element of our group that we will be computing over.
96    type Element: Add<Output = Self::Element>
97        + Copy
98        + Clone
99        + Eq
100        + Mul<<Self::Field as Field>::Scalar, Output = Self::Element>
101        + PartialEq
102        + Sub<Output = Self::Element>
103        + Send
104        + Sync;
105
106    /// A unique byte array buf of fixed length N.
107    ///
108    /// Little-endian!
109    type Serialization: Clone + AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8]> + Debug;
110
111    /// The order of the the quotient group when the prime order subgroup divides the order of the
112    /// full curve group.
113    ///
114    /// If using a prime order elliptic curve, the cofactor should be 1 in the scalar field.
115    fn cofactor() -> <Self::Field as Field>::Scalar;
116
117    /// Additive [identity] of the prime order group.
118    ///
119    /// [identity]: https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.4
120    fn identity() -> Self::Element;
121
122    /// The fixed generator element of the prime order group.
123    ///
124    /// The 'base' of ['ScalarBaseMult()'] from the spec.
125    ///
126    /// [`ScalarBaseMult()`]: https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.10
127    fn generator() -> Self::Element;
128
129    /// A member function of a group _G_ that maps an [`Element`] to a unique
130    /// byte array buf of fixed length Ne. This function raises an error if the
131    /// element is the identity element of the group.
132    ///
133    /// <https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.12>
134    fn serialize(element: &Self::Element) -> Result<Self::Serialization, GroupError>;
135
136    /// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
137    ///
138    /// Fails if the input is not a valid byte representation of an [`Element`] of the
139    /// [`Group`]. This function can raise an [`Error`] if deserialization fails or if the
140    /// resulting [`Element`] is the identity element of the group
141    ///
142    /// <https://datatracker.ietf.org/doc/html/rfc9591#section-3.1-4.14>
143    fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError>;
144}
145
146/// An element of the [`Ciphersuite`] `C`'s [`Group`].
147pub type Element<C> = <<C as Ciphersuite>::Group as Group>::Element;
148
149/// A [FROST ciphersuite] specifies the underlying prime-order group details and cryptographic hash
150/// function.
151///
152/// [FROST ciphersuite]: https://datatracker.ietf.org/doc/html/rfc9591#name-ciphersuites
153// See https://github.com/ZcashFoundation/frost/issues/693 for reasoning about the 'static bound.
154pub trait Ciphersuite: Copy + PartialEq + Debug + 'static + Send + Sync {
155    /// The ciphersuite ID string. It should be equal to the contextString in
156    /// the spec. For new ciphersuites, this should be a string that identifies
157    /// the ciphersuite; it's recommended to use a similar format to the
158    /// ciphersuites in the FROST spec, e.g. "FROST-RISTRETTO255-SHA512-v1".
159    const ID: &'static str;
160
161    /// The prime order group (or subgroup) that this ciphersuite operates over.
162    type Group: Group;
163
164    /// A unique byte array of fixed length.
165    type HashOutput: AsRef<[u8]>;
166
167    /// A unique byte array of fixed length that is the `Group::ElementSerialization` +
168    /// `Group::ScalarSerialization`
169    type SignatureSerialization: Clone
170        + AsRef<[u8]>
171        + AsMut<[u8]>
172        + for<'a> TryFrom<&'a [u8]>
173        + Debug;
174
175    /// [H1] for a FROST ciphersuite.
176    ///
177    /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field.
178    ///
179    /// [H1]: https://datatracker.ietf.org/doc/html/rfc9591#name-cryptographic-hash-function
180    fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
181
182    /// [H2] for a FROST ciphersuite.
183    ///
184    /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field.
185    ///
186    /// [H2]: https://datatracker.ietf.org/doc/html/rfc9591#name-cryptographic-hash-function
187    fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
188
189    /// [H3] for a FROST ciphersuite.
190    ///
191    /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field.
192    ///
193    /// [H3]: https://datatracker.ietf.org/doc/html/rfc9591#name-cryptographic-hash-function
194    fn H3(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
195
196    /// [H4] for a FROST ciphersuite.
197    ///
198    /// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied.
199    ///
200    /// [H4]: https://datatracker.ietf.org/doc/html/rfc9591#name-cryptographic-hash-function
201    fn H4(m: &[u8]) -> Self::HashOutput;
202
203    /// [H5] for a FROST ciphersuite.
204    ///
205    /// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied.
206    ///
207    /// [H5]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
208    fn H5(m: &[u8]) -> Self::HashOutput;
209
210    /// Hash function for a FROST ciphersuite, used for the DKG.
211    ///
212    /// The DKG it not part of the specification, thus this is optional.
213    /// It can return None if DKG is not supported by the Ciphersuite. This is
214    /// the default implementation.
215    ///
216    /// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field.
217    fn HDKG(_m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
218        None
219    }
220
221    /// Hash function for a FROST ciphersuite, used for deriving identifiers from strings.
222    ///
223    /// This feature is not part of the specification and is just a convenient
224    /// way of creating identifiers. Therefore it can return None if this is not supported by the
225    /// Ciphersuite. This is the default implementation.
226    ///
227    /// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field.
228    fn HID(_m: &[u8]) -> Option<<<Self::Group as Group>::Field as Field>::Scalar> {
229        None
230    }
231
232    // The following are optional methods that allow customizing steps of the
233    // protocol if required.
234
235    /// Optional. Do regular (non-FROST) signing with a [`SigningKey`]. Called
236    /// by [`SigningKey::sign()`]. This is not used by FROST. Can be overridden
237    /// if required which is useful if FROST signing has been changed by the
238    /// other Ciphersuite trait methods and regular signing should be changed
239    /// accordingly to match.
240    fn single_sign<R: RngCore + CryptoRng>(
241        signing_key: &SigningKey<Self>,
242        rng: R,
243        message: &[u8],
244    ) -> Signature<Self> {
245        signing_key.default_sign(rng, message)
246    }
247
248    /// Optional. Verify a signature for this ciphersuite. Called by
249    /// [`VerifyingKey::verify()`]. The default implementation uses the
250    /// "cofactored" equation (it multiplies by the cofactor returned by
251    /// [`Group::cofactor()`]).
252    ///
253    /// # Cryptographic Safety
254    ///
255    /// You may override this to provide a tailored implementation, but if the
256    /// ciphersuite defines it, it must also multiply by the cofactor to comply
257    /// with the RFC. Note that batch verification (see
258    /// [`crate::batch::Verifier`]) also uses the default implementation
259    /// regardless whether a tailored implementation was provided.
260    fn verify_signature(
261        message: &[u8],
262        signature: &Signature<Self>,
263        public_key: &VerifyingKey<Self>,
264    ) -> Result<(), Error<Self>> {
265        let (message, signature, public_key) = <Self>::pre_verify(message, signature, public_key)?;
266
267        let c = <Self>::challenge(&signature.R, &public_key, &message)?;
268
269        public_key.verify_prehashed(c, &signature)
270    }
271
272    /// Optional. Pre-process [`round2::sign()`] inputs. The default
273    /// implementation returns them as-is. [`Cow`] is used so implementations
274    /// can choose to return the same passed reference or a modified clone.
275    #[allow(clippy::type_complexity)]
276    fn pre_sign<'a>(
277        signing_package: &'a SigningPackage<Self>,
278        signer_nonces: &'a round1::SigningNonces<Self>,
279        key_package: &'a KeyPackage<Self>,
280    ) -> Result<
281        (
282            Cow<'a, SigningPackage<Self>>,
283            Cow<'a, round1::SigningNonces<Self>>,
284            Cow<'a, KeyPackage<Self>>,
285        ),
286        Error<Self>,
287    > {
288        Ok((
289            Cow::Borrowed(signing_package),
290            Cow::Borrowed(signer_nonces),
291            Cow::Borrowed(key_package),
292        ))
293    }
294
295    /// Optional. Pre-process [`crate::aggregate()`] and
296    /// [`crate::verify_signature_share()`] inputs. In the latter case, "dummy"
297    /// container BTreeMap and PublicKeyPackage are passed with the relevant
298    /// values (PublicKeyPackage.min_signers will be None). The default
299    /// implementation returns them as-is. [`Cow`] is used so implementations
300    /// can choose to return the same passed reference or a modified clone.
301    #[allow(clippy::type_complexity)]
302    fn pre_aggregate<'a>(
303        signing_package: &'a SigningPackage<Self>,
304        signature_shares: &'a BTreeMap<Identifier<Self>, round2::SignatureShare<Self>>,
305        public_key_package: &'a PublicKeyPackage<Self>,
306    ) -> Result<
307        (
308            Cow<'a, SigningPackage<Self>>,
309            Cow<'a, BTreeMap<Identifier<Self>, round2::SignatureShare<Self>>>,
310            Cow<'a, PublicKeyPackage<Self>>,
311        ),
312        Error<Self>,
313    > {
314        Ok((
315            Cow::Borrowed(signing_package),
316            Cow::Borrowed(signature_shares),
317            Cow::Borrowed(public_key_package),
318        ))
319    }
320
321    /// Optional. Pre-process [`VerifyingKey::verify()`] inputs. The default
322    /// implementation returns them as-is. [`Cow`] is used so implementations
323    /// can choose to return the same passed reference or a modified clone.
324    #[allow(clippy::type_complexity)]
325    fn pre_verify<'a>(
326        msg: &'a [u8],
327        signature: &'a Signature<Self>,
328        public_key: &'a VerifyingKey<Self>,
329    ) -> Result<
330        (
331            Cow<'a, [u8]>,
332            Cow<'a, Signature<Self>>,
333            Cow<'a, VerifyingKey<Self>>,
334        ),
335        Error<Self>,
336    > {
337        Ok((
338            Cow::Borrowed(msg),
339            Cow::Borrowed(signature),
340            Cow::Borrowed(public_key),
341        ))
342    }
343
344    /// Optional. Pre-process [`crate::compute_group_commitment()`] inputs in
345    /// [`round2::sign()`].
346    #[allow(clippy::type_complexity)]
347    fn pre_commitment_sign<'a>(
348        signing_package: &'a SigningPackage<Self>,
349        signing_nonces: &'a SigningNonces<Self>,
350        _binding_factor_list: &'a BindingFactorList<Self>,
351    ) -> Result<(Cow<'a, SigningPackage<Self>>, Cow<'a, SigningNonces<Self>>), Error<Self>> {
352        Ok((
353            Cow::Borrowed(signing_package),
354            Cow::Borrowed(signing_nonces),
355        ))
356    }
357
358    /// Optional. Pre-process [`crate::compute_group_commitment()`] inputs in
359    /// [`crate::aggregate()`].
360    fn pre_commitment_aggregate<'a>(
361        signing_package: &'a SigningPackage<Self>,
362        _binding_factor_list: &'a BindingFactorList<Self>,
363    ) -> Result<Cow<'a, SigningPackage<Self>>, Error<Self>> {
364        Ok(Cow::Borrowed(signing_package))
365    }
366
367    /// Optional. Generate a nonce and a commitment to it. Used by
368    /// [`SigningKey`] for regular (non-FROST) signing and internally by the DKG
369    /// to generate proof-of-knowledge signatures.
370    fn generate_nonce<R: RngCore + CryptoRng>(
371        rng: &mut R,
372    ) -> (
373        <<Self::Group as Group>::Field as Field>::Scalar,
374        <Self::Group as Group>::Element,
375    ) {
376        let k = random_nonzero::<Self, R>(rng);
377        let R = <Self::Group>::generator() * k;
378        (k, R)
379    }
380
381    /// Optional. Generates the challenge as is required for Schnorr signatures.
382    /// Called by [`round2::sign()`] and [`crate::aggregate()`].
383    fn challenge(
384        R: &Element<Self>,
385        verifying_key: &VerifyingKey<Self>,
386        message: &[u8],
387    ) -> Result<Challenge<Self>, Error<Self>> {
388        challenge(R, verifying_key, message)
389    }
390
391    /// Optional. Compute the signature share for a particular signer on a given
392    /// challenge. Called by [`round2::sign()`].
393    fn compute_signature_share(
394        _group_commitment: &GroupCommitment<Self>,
395        signer_nonces: &round1::SigningNonces<Self>,
396        binding_factor: BindingFactor<Self>,
397        lambda_i: <<Self::Group as Group>::Field as Field>::Scalar,
398        key_package: &KeyPackage<Self>,
399        challenge: Challenge<Self>,
400    ) -> round2::SignatureShare<Self> {
401        round2::compute_signature_share(
402            signer_nonces,
403            binding_factor,
404            lambda_i,
405            key_package,
406            challenge,
407        )
408    }
409
410    /// Optional. Verify a signing share. Called by [`crate::aggregate()`] if
411    /// cheater detection is enabled.
412    fn verify_share(
413        _group_commitment: &GroupCommitment<Self>,
414        signature_share: &SignatureShare<Self>,
415        identifier: Identifier<Self>,
416        group_commitment_share: &round1::GroupCommitmentShare<Self>,
417        verifying_share: &VerifyingShare<Self>,
418        lambda_i: Scalar<Self>,
419        challenge: &Challenge<Self>,
420    ) -> Result<(), Error<Self>> {
421        signature_share.verify(
422            identifier,
423            group_commitment_share,
424            verifying_share,
425            lambda_i,
426            challenge,
427        )
428    }
429
430    /// Optional. Converts a signature to its
431    /// [`Ciphersuite::SignatureSerialization`] in bytes.
432    ///
433    /// The default implementation serializes a signature by serializing its `R`
434    /// point and `z` component independently, and then concatenating them.
435    fn serialize_signature(signature: &Signature<Self>) -> Result<Vec<u8>, Error<Self>> {
436        signature.default_serialize()
437    }
438
439    /// Optional. Converts bytes as [`Ciphersuite::SignatureSerialization`] into
440    /// a `Signature<C>`.
441    ///
442    /// The default implementation assumes the serialization is a serialized `R`
443    /// point followed by a serialized `z` component with no padding or extra
444    /// fields.
445    fn deserialize_signature(bytes: &[u8]) -> Result<Signature<Self>, Error<Self>> {
446        Signature::<Self>::default_deserialize(bytes)
447    }
448
449    /// Post-process the output of the DKG for a given participant.
450    fn post_dkg(
451        key_package: KeyPackage<Self>,
452        public_key_package: PublicKeyPackage<Self>,
453    ) -> Result<(KeyPackage<Self>, PublicKeyPackage<Self>), Error<Self>> {
454        Ok((key_package, public_key_package))
455    }
456
457    /// Post-process the output of the key generation for a participant.
458    #[allow(clippy::type_complexity)]
459    fn post_generate(
460        secret_shares: BTreeMap<Identifier<Self>, SecretShare<Self>>,
461        public_key_package: PublicKeyPackage<Self>,
462    ) -> Result<
463        (
464            BTreeMap<Identifier<Self>, SecretShare<Self>>,
465            PublicKeyPackage<Self>,
466        ),
467        Error<Self>,
468    > {
469        Ok((secret_shares, public_key_package))
470    }
471}