frost/frost-core/src/lib.rs

241 lines
9.2 KiB
Rust

#![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<Output = Self::Scalar>
+ Copy
+ Clone
+ Eq
+ Mul<Output = Self::Scalar>
+ PartialEq
+ Sub<Output = Self::Scalar>;
/// A unique byte array buf of fixed length N.
///
/// Little-endian!
type Serialization: AsRef<[u8]> + AsMut<[u8]> + Debug + Default + FromHex + TryFrom<Vec<u8>>;
/// 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<Self::Scalar, Error>;
/// Generate a random scalar from the entire space [0, l-1]
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.3>
fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
/// Generate a random scalar from the entire space [1, l-1]
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.4>
fn random_nonzero<R: RngCore + CryptoRng>(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.
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
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
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error>;
}
/// An element of the [`Ciphersuite`] `C`'s [`Group`]'s scalar [`Field`].
pub type Scalar<C> = <<<C as Ciphersuite>::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<Output = Self::Element>
+ Copy
+ Clone
+ Eq
+ Mul<<Self::Field as Field>::Scalar, Output = Self::Element>
+ PartialEq
+ Sub<Output = Self::Element>;
/// A unique byte array buf of fixed length N.
///
/// Little-endian!
type Serialization: AsRef<[u8]> + AsMut<[u8]> + Default + FromHex + TryFrom<Vec<u8>>;
/// Outputs the order of G (i.e. p)
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.1>
fn order() -> <Self::Field as Field>::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.
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-4.1-3>
fn cofactor() -> <Self::Field as Field>::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.
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
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
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error>;
}
/// An element of the [`Ciphersuite`] `C`'s [`Group`].
pub type Element<C> = <<C as Ciphersuite>::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<Vec<u8>>;
/// [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]) -> <<Self::Group as Group>::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]) -> <<Self::Group as Group>::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<C: Ciphersuite>(
pub(crate) <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
);
impl<C> Debug for Challenge<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secret")
.field(&hex::encode(
<<<C as Ciphersuite>::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<C>(
R: &<C::Group as Group>::Element,
verifying_key: &<C::Group as Group>::Element,
msg: &[u8],
) -> Challenge<C>
where
C: Ciphersuite,
{
let mut preimage = vec![];
preimage.extend_from_slice(<C::Group as Group>::serialize(R).as_ref());
preimage.extend_from_slice(<C::Group as Group>::serialize(verifying_key).as_ref());
preimage.extend_from_slice(msg);
Challenge(C::H2(&preimage[..]))
}