#![allow(non_snake_case)] #![deny(missing_docs)] #![doc = include_str!("../README.md")] #![forbid(unsafe_code)] use std::{ default::Default, fmt::Debug, ops::{Add, Mul, Sub}, }; use hex::FromHex; use rand_core::{CryptoRng, RngCore}; // pub mod batch; mod error; pub mod frost; // mod scalar_mul; mod signature; mod signing_key; mod verifying_key; pub use error::Error; 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). type Scalar: Add + Copy + Clone + Eq + Mul + PartialEq + Sub; /// A unique byte array buf of fixed length N. /// /// Little-endian! type Serialization: AsRef<[u8]> + AsMut<[u8]> + Debug + Default + FromHex + 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; /// Generate a random scalar from the entire space [1, l-1] /// /// fn random_nonzero(rng: &mut R) -> Self::Scalar; /// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of /// fixed length Ne. /// /// fn serialize(scalar: &Self::Scalar) -> 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 a [`DeserializeError`] 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`]'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 { /// 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]> + AsMut<[u8]> + Default + FromHex + TryFrom>; /// Outputs the order of G (i.e. p) /// /// fn order() -> ::Scalar; /// 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-04.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-04.html#section-3.1 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 a [`DeserializeError`] 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-04.html#name-ciphersuites pub trait Ciphersuite: Copy + Clone { /// 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]> + FromHex + TryFrom>; /// [H1] for a FROST ciphersuite. /// /// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field. /// /// [H1]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash fn H1(m: &[u8]) -> <::Field as Field>::Scalar; /// [H2] for a FROST ciphersuite. /// /// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field. /// /// [H2]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash fn H2(m: &[u8]) -> <::Field as Field>::Scalar; /// H3 for a FROST ciphersuite. /// /// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied. /// /// [spec]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash fn H3(m: &[u8]) -> Self::HashOutput; } /// A type refinement for the scalar field element representing the per-message _[challenge]_. /// /// [challenge]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-signature-challenge-computa #[derive(Clone)] pub struct Challenge( pub(crate) <<::Group as Group>::Field as Field>::Scalar, ); 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( <<::Group as Group>::Field as 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-04.html#section-4.6 /// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.2 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[..])) }