#![allow(non_snake_case)] // It's emitting false positives; see https://github.com/rust-lang/rust-clippy/issues/9413 #![allow(clippy::derive_partial_eq_without_eq)] #![deny(missing_docs)] #![doc = include_str!("../README.md")] #![forbid(unsafe_code)] use std::{ default::Default, fmt::Debug, ops::{Add, Mul, Sub}, }; use rand_core::{CryptoRng, RngCore}; pub mod batch; #[cfg(any(test, feature = "test-impl"))] pub mod benches; mod error; pub mod frost; mod scalar_mul; mod signature; mod signing_key; #[cfg(any(test, feature = "test-impl"))] pub mod tests; mod verifying_key; pub use error::{Error, FieldError, GroupError}; pub use signature::Signature; pub use signing_key::SigningKey; pub use verifying_key::VerifyingKey; /// A prime order finite field GF(q) over which all scalar values for our prime order group can be /// multiplied are defined. /// /// This trait does not have to be implemented for a finite field scalar itself, it can be a /// pass-through, implemented for a type just for the ciphersuite, and calls through to another /// implementation underneath, so that this trait does not have to be implemented for types you /// don't own. pub trait Field: Copy + Clone { /// An element of the scalar field GF(p). /// The Eq/PartialEq implementation MUST be constant-time. type Scalar: Add + Copy + Clone + Eq + Mul + PartialEq + Sub; /// A unique byte array buf of fixed length N. type Serialization: AsRef<[u8]> + Debug + TryFrom>; /// Returns the zero element of the field, the additive identity. fn zero() -> Self::Scalar; /// Returns the one element of the field, the multiplicative identity. fn one() -> Self::Scalar; /// Computes the multiplicative inverse of an element of the scalar field, failing if the /// element is zero. fn invert(scalar: &Self::Scalar) -> Result; /// Generate a random scalar from the entire space [0, l-1] /// /// fn random(rng: &mut R) -> Self::Scalar; /// A member function of a [`Field`] that maps a [`Scalar`] to a unique byte array buf of /// fixed length Ne. /// /// fn serialize(scalar: &Self::Scalar) -> Self::Serialization; /// A member function of a [`Field`] that maps a [`Scalar`] to a unique byte array buf of /// fixed length Ne, in little-endian order. /// /// This is used internally. fn little_endian_serialize(scalar: &Self::Scalar) -> Self::Serialization; /// A member function of a [`Field`] that attempts to map a byte array `buf` to a [`Scalar`]. /// /// Fails if the input is not a valid byte representation of an [`Scalar`] of the /// [`Field`]. This function can raise an [`Error`] if deserialization fails or if the /// resulting [`Scalar`] is zero /// /// fn deserialize(buf: &Self::Serialization) -> Result; } /// An element of the [`Ciphersuite`] `C`'s [`Group`]'s scalar [`Field`]. pub type Scalar = <<::Group as Group>::Field as Field>::Scalar; /// A prime-order group (or subgroup) that provides everything we need to create and verify Schnorr /// signatures. /// /// This trait does not have to be implemented for the curve/element/point itself, it can be a /// pass-through, implemented for a type just for the ciphersuite, and calls through to another /// implementation underneath, so that this trait does not have to be implemented for types you /// don't own. pub trait Group: Copy + Clone + PartialEq { /// A prime order finite field GF(q) over which all scalar values for our prime order group can /// be multiplied are defined. type Field: Field; /// An element of our group that we will be computing over. type Element: Add + Copy + Clone + Eq + Mul<::Scalar, Output = Self::Element> + PartialEq + Sub; /// A unique byte array buf of fixed length N. /// /// Little-endian! type Serialization: AsRef<[u8]> + Debug + TryFrom>; /// The order of the the quotient group when the prime order subgroup divides the order of the /// full curve group. /// /// If using a prime order elliptic curve, the cofactor should be 1 in the scalar field. fn cofactor() -> ::Scalar; /// Additive [identity] of the prime order group. /// /// [identity]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.1-3.2 fn identity() -> Self::Element; /// The fixed generator element of the prime order group. /// /// The 'base' of ['ScalarBaseMult()'] from the spec. /// /// [`ScalarBaseMult()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.1-3.5 fn generator() -> Self::Element; /// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of /// fixed length Ne. /// /// fn serialize(element: &Self::Element) -> Self::Serialization; /// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`]. /// /// Fails if the input is not a valid byte representation of an [`Element`] of the /// [`Group`]. This function can raise an [`Error`] if deserialization fails or if the /// resulting [`Element`] is the identity element of the group /// /// fn deserialize(buf: &Self::Serialization) -> Result; } /// An element of the [`Ciphersuite`] `C`'s [`Group`]. pub type Element = <::Group as Group>::Element; /// A [FROST ciphersuite] specifies the underlying prime-order group details and cryptographic hash /// function. /// /// [FROST ciphersuite]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-ciphersuites pub trait Ciphersuite: Copy + Clone + PartialEq + Debug { /// The prime order group (or subgroup) that this ciphersuite operates over. type Group: Group; /// A unique byte array of fixed length. type HashOutput: AsRef<[u8]>; /// A unique byte array of fixed length that is the `Group::ElementSerialization` + /// `Group::ScalarSerialization` type SignatureSerialization: AsRef<[u8]> + TryFrom>; /// [H1] for a FROST ciphersuite. /// /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field. /// /// [H1]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-cryptographic-hash-function fn H1(m: &[u8]) -> <::Field as Field>::Scalar; /// [H2] for a FROST ciphersuite. /// /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field. /// /// [H2]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-cryptographic-hash-function fn H2(m: &[u8]) -> <::Field as Field>::Scalar; /// [H3] for a FROST ciphersuite. /// /// Maps arbitrary inputs to `Self::Scalar` elements of the prime-order group scalar field. /// /// [H3]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-cryptographic-hash-function fn H3(m: &[u8]) -> <::Field as Field>::Scalar; /// [H4] for a FROST ciphersuite. /// /// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied. /// /// [H4]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-cryptographic-hash-function fn H4(m: &[u8]) -> Self::HashOutput; /// [H5] for a FROST ciphersuite. /// /// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied. /// /// [H5]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash fn H5(m: &[u8]) -> Self::HashOutput; /// Hash function for a FROST ciphersuite, used for the DKG. /// /// The DKG it not part of the specification, thus this is optional. /// It can return None if DKG is not supported by the Ciphersuite. This is /// the default implementation. /// /// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field. fn HDKG(_m: &[u8]) -> Option<<::Field as Field>::Scalar> { None } /// Verify a signature for this ciphersuite. The default implementation uses the "cofactored" /// equation (it multiplies by the cofactor returned by [`Group::cofactor()`]). /// /// # Cryptographic Safety /// /// You may override this to provide a tailored implementation, but if the ciphersuite defines it, /// it must also multiply by the cofactor to comply with the RFC. Note that batch verification /// (see [`crate::batch::Verifier`]) also uses the default implementation regardless whether a /// tailored implementation was provided. fn verify_signature( msg: &[u8], signature: &Signature, public_key: &VerifyingKey, ) -> Result<(), Error> { let c = crate::challenge::(&signature.R, &public_key.element, msg); public_key.verify_prehashed(c, signature) } } /// A type refinement for the scalar field element representing the per-message _[challenge]_. /// /// [challenge]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-challenge-computa #[derive(Clone)] pub struct Challenge(pub(crate) <::Field as Field>::Scalar); impl Challenge where C: Ciphersuite, { /// Return the underlying scalar. #[cfg(feature = "internals")] pub fn to_scalar(self) -> <<::Group as Group>::Field as Field>::Scalar { self.0 } } impl Debug for Challenge where C: Ciphersuite, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Secret") .field(&hex::encode(<::Field>::serialize( &self.0, ))) .finish() } } /// Generates the challenge as is required for Schnorr signatures. /// /// Deals in bytes, so that [FROST] and singleton signing and verification can use it with different /// types. /// /// This is the only invocation of the H2 hash function from the [RFC]. /// /// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-challenge-computa /// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.2 #[cfg_attr(feature = "internals", visibility::make(pub))] fn challenge(R: &Element, verifying_key: &Element, msg: &[u8]) -> Challenge where C: Ciphersuite, { let mut preimage = vec![]; preimage.extend_from_slice(::serialize(R).as_ref()); preimage.extend_from_slice(::serialize(verifying_key).as_ref()); preimage.extend_from_slice(msg); Challenge(C::H2(&preimage[..])) } /// Generates a random nonzero scalar. /// /// It assumes that the Scalar Eq/PartialEq implementation is constant-time. pub(crate) fn random_nonzero(rng: &mut R) -> Scalar { loop { let scalar = <::Field>::random(rng); if scalar != <::Field>::zero() { return scalar; } } }