diff --git a/CHANGELOG.md b/CHANGELOG.md index a70b8bb..5b6c4f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,14 @@ and this library adheres to Rust's notion of - `ff::Field::pow` - `ff::Field::{sqrt_ratio, sqrt_alt}` - `core::iter::{Sum, Product}` bounds on `ff::Field` -- `ff::PrimeField::{MULTIPLICATIVE_GENERATOR, ROOT_OF_UNITY}` +- `ff::PrimeField::from_u128` +- `ff::PrimeField::{MODULUS, TWO_INV}` +- Constants related to multiplicative generators: + - `ff::PrimeField::MULTIPLICATIVE_GENERATOR` + - `ff::PrimeField::{ROOT_OF_UNITY, ROOT_OF_UNITY_INV}` + - `ff::PrimeField::DELTA` +- `ff::WithSmallOrderMulGroup` +- `ff::FromUniformBytes` - `ff::helpers`: - `sqrt_tonelli_shanks` - `sqrt_ratio_generic` @@ -23,6 +30,9 @@ and this library adheres to Rust's notion of if it is more efficient in practice, or they can keep their own implementation of `Field::sqrt` and implement `Field::sqrt_ratio` in terms of that implementation using the `ff::helpers::sqrt_ratio_generic` helper function. +- `ff::PrimeField` is now documented as representing a non-binary field (i.e. + its prime is not 2). This was always the intention, but is now a concrete + requirement in order for `PrimeField::TWO_INV` to exist. ### Removed - `ff::Field::{zero, one}` (use `ff::Field::{ZERO, ONE}` instead). diff --git a/Cargo.toml b/Cargo.toml index dc8a273..c67e78a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ rand_core = { version = "0.6", default-features = false } subtle = { version = "2.2.1", default-features = false, features = ["i128"] } [dev-dependencies] +blake2b_simd = "1" rand = "0.8" [features] diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index 84148d5..5e7ebb6 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -479,6 +479,14 @@ fn prime_field_constants_and_sqrt( // Compute R = 2**(64 * limbs) mod m let r = (BigUint::one() << (limbs * 64)) % modulus; + let to_mont = |v| (v * &r) % modulus; + + let two = BigUint::from_str("2").unwrap(); + let p_minus_2 = modulus - &two; + let invert = |v| exp(v, &p_minus_2, &modulus); + + // 2^-1 mod m + let two_inv = biguint_to_u64_vec(to_mont(invert(two)), limbs); // modulus - 1 = 2^s * t let mut s: u32 = 0; @@ -489,9 +497,14 @@ fn prime_field_constants_and_sqrt( } // Compute 2^s root of unity given the generator - let root_of_unity = - biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); - let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); + let root_of_unity = exp(generator.clone(), &t, &modulus); + let root_of_unity_inv = biguint_to_u64_vec(to_mont(invert(root_of_unity.clone())), limbs); + let root_of_unity = biguint_to_u64_vec(to_mont(root_of_unity), limbs); + let delta = biguint_to_u64_vec( + to_mont(exp(generator.clone(), &(BigUint::one() << s), &modulus)), + limbs, + ); + let generator = biguint_to_u64_vec(to_mont(generator), limbs); let sqrt_impl = if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { @@ -581,6 +594,7 @@ fn prime_field_constants_and_sqrt( let r = biguint_to_u64_vec(r, limbs); let modulus_le_bytes = ReprEndianness::Little.modulus_repr(modulus, limbs * 8); + let modulus_str = format!("0x{}", modulus.to_str_radix(16)); let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 @@ -602,6 +616,9 @@ fn prime_field_constants_and_sqrt( /// This is the modulus m of the prime field in limb form const MODULUS_LIMBS: #name = #name([#(#modulus,)*]); + /// This is the modulus m of the prime field in hex string form + const MODULUS_STR: &'static str = #modulus_str; + /// The number of bits needed to represent the modulus. const MODULUS_BITS: u32 = #modulus_num_bits; @@ -618,6 +635,9 @@ fn prime_field_constants_and_sqrt( /// -(m^{-1} mod m) mod m const INV: u64 = #inv; + /// 2^{-1} mod m + const TWO_INV: #name = #name(#two_inv); + /// Multiplicative generator of `MODULUS` - 1 order, also quadratic /// nonresidue. const GENERATOR: #name = #name(#generator); @@ -627,6 +647,12 @@ fn prime_field_constants_and_sqrt( /// 2^s root of unity computed by GENERATOR^t const ROOT_OF_UNITY: #name = #name(#root_of_unity); + + /// (2^s)^{-1} mod m + const ROOT_OF_UNITY_INV: #name = #name(#root_of_unity_inv); + + /// GENERATOR^{2^s} + const DELTA: #name = #name(#delta); }, sqrt_impl, ) @@ -1215,15 +1241,23 @@ fn prime_field_impl( ::ff::derive::subtle::Choice::from((r.0[0] & 1) as u8) } + const MODULUS: &'static str = MODULUS_STR; + const NUM_BITS: u32 = MODULUS_BITS; const CAPACITY: u32 = Self::NUM_BITS - 1; + const TWO_INV: Self = TWO_INV; + const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; const S: u32 = S; const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; + + const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; + + const DELTA: Self = DELTA; } #prime_field_bits_impl diff --git a/src/lib.rs b/src/lib.rs index 666f925..96bd3e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,7 +191,7 @@ pub trait Field: } } -/// This represents an element of a prime field. +/// This represents an element of a non-binary prime field. pub trait PrimeField: Field + From { /// The prime field can be converted back and forth into this binary /// representation. @@ -241,6 +241,26 @@ pub trait PrimeField: Field + From { Some(res) } + /// Obtains a field element congruent to the integer `v`. + /// + /// For fields where `Self::CAPACITY >= 128`, this is injective and will produce a + /// unique field element. + /// + /// For fields where `Self::CAPACITY < 128`, this is surjective; some field elements + /// will be produced by multiple values of `v`. + /// + /// If you want to deterministically sample a field element representing a value, use + /// [`FromUniformBytes`] instead. + fn from_u128(v: u128) -> Self { + let lower = v as u64; + let upper = (v >> 64) as u64; + let mut tmp = Self::from(upper); + for _ in 0..64 { + tmp = tmp.double(); + } + tmp + Self::from(lower) + } + /// Attempts to convert a byte representation of a field element into an element of /// this prime field, failing if the input is not canonical (is not smaller than the /// field's modulus). @@ -280,6 +300,12 @@ pub trait PrimeField: Field + From { !self.is_odd() } + /// Modulus of the field written as a string for debugging purposes. + /// + /// The encoding of the modulus is implementation-specific. Generic users of the + /// `PrimeField` trait should treat this string as opaque. + const MODULUS: &'static str; + /// How many bits are needed to represent an element of this field. const NUM_BITS: u32; @@ -288,13 +314,16 @@ pub trait PrimeField: Field + From { /// This is usually `Self::NUM_BITS - 1`. const CAPACITY: u32; + /// Inverse of $2$ in the field. + const TWO_INV: Self; + /// A fixed multiplicative generator of `modulus - 1` order. This element must also be /// a quadratic nonresidue. /// /// It can be calculated using [SageMath] as `GF(modulus).primitive_element()`. /// /// Implementations of this trait MUST ensure that this is the generator used to - /// derive `Self::root_of_unity`. + /// derive `Self::ROOT_OF_UNITY`. /// /// [SageMath]: https://www.sagemath.org/ const MULTIPLICATIVE_GENERATOR: Self; @@ -310,6 +339,112 @@ pub trait PrimeField: Field + From { /// It can be calculated by exponentiating `Self::MULTIPLICATIVE_GENERATOR` by `t`, /// where `t = (modulus - 1) >> Self::S`. const ROOT_OF_UNITY: Self; + + /// Inverse of [`Self::ROOT_OF_UNITY`]. + const ROOT_OF_UNITY_INV: Self; + + /// Generator of the `t-order` multiplicative subgroup. + /// + /// It can be calculated by exponentiating [`Self::MULTIPLICATIVE_GENERATOR`] by `2^s`, + /// where `s` is [`Self::S`]. + const DELTA: Self; +} + +/// The subset of prime-order fields such that `(modulus - 1)` is divisible by `N`. +/// +/// If `N` is prime, there will be `N - 1` valid choices of [`Self::ZETA`]. Similarly to +/// [`PrimeField::MULTIPLICATIVE_GENERATOR`], the specific choice does not matter, as long +/// as the choice is consistent across all uses of the field. +pub trait WithSmallOrderMulGroup: PrimeField { + /// A field element of small multiplicative order $N$. + /// + /// The presense of this element allows you to perform (certain types of) + /// endomorphisms on some elliptic curves. + /// + /// It can be calculated using [SageMath] as + /// `GF(modulus).primitive_element() ^ ((modulus - 1) // N)`. + /// Choosing the element of order $N$ that is smallest, when considered + /// as an integer, may help to ensure consistency. + /// + /// [SageMath]: https://www.sagemath.org/ + const ZETA: Self; +} + +/// Trait for constructing a [`PrimeField`] element from a fixed-length uniform byte +/// array. +/// +/// "Uniform" means that the byte array's contents must be indistinguishable from the +/// [discrete uniform distribution]. Suitable byte arrays can be obtained: +/// - from a cryptographically-secure randomness source (which makes this constructor +/// equivalent to [`Field::random`]). +/// - from a cryptographic hash function output, which enables a "random" field element to +/// be selected deterministically. This is the primary use case for `FromUniformBytes`. +/// +/// The length `N` of the byte array is chosen by the trait implementer such that the loss +/// of uniformity in the mapping from byte arrays to field elements is cryptographically +/// negligible. +/// +/// [discrete uniform distribution]: https://en.wikipedia.org/wiki/Discrete_uniform_distribution +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "derive")] { +/// # // Fake this so we don't actually need a dev-dependency on bls12_381. +/// # mod bls12_381 { +/// # use ff::{Field, PrimeField}; +/// # +/// # #[derive(PrimeField)] +/// # #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] +/// # #[PrimeFieldGenerator = "7"] +/// # #[PrimeFieldReprEndianness = "little"] +/// # pub struct Scalar([u64; 4]); +/// # +/// # impl ff::FromUniformBytes<64> for Scalar { +/// # fn from_uniform_bytes(_bytes: &[u8; 64]) -> Self { +/// # // Fake impl for doctest +/// # Scalar::ONE +/// # } +/// # } +/// # } +/// # +/// use blake2b_simd::blake2b; +/// use bls12_381::Scalar; +/// use ff::FromUniformBytes; +/// +/// // `bls12_381::Scalar` implements `FromUniformBytes<64>`, and BLAKE2b (by default) +/// // produces a 64-byte hash. +/// let hash = blake2b(b"Some message"); +/// let val = Scalar::from_uniform_bytes(hash.as_array()); +/// # } +/// ``` +/// +/// # Implementing `FromUniformBytes` +/// +/// [`Self::from_uniform_bytes`] should always be implemented by interpreting the provided +/// byte array as the little endian unsigned encoding of an integer, and then reducing that +/// integer modulo the field modulus. +/// +/// For security, `N` must be chosen so that `N * 8 >= Self::NUM_BITS + 128`. A larger +/// value of `N` may be chosen for convenience; for example, for a field with a 255-bit +/// modulus, `N = 64` is convenient as it matches the output length of several common +/// cryptographic hash functions (such as SHA-512 and BLAKE2b). +/// +/// ## Trait design +/// +/// This trait exists because `PrimeField::from_uniform_bytes([u8; N])` cannot currently +/// exist (trait methods cannot use associated constants in the const positions of their +/// type signature, and we do not want `PrimeField` to require a generic const parameter). +/// However, this has the side-effect that `FromUniformBytes` can be implemented multiple +/// times for different values of `N`. Most implementations of [`PrimeField`] should only +/// need to implement `FromUniformBytes` trait for one value of `N` (chosen following the +/// above considerations); if you find yourself needing to implement it multiple times, +/// please [let us know about your use case](https://github.com/zkcrypto/ff/issues/new) so +/// we can take it into consideration for future evolutions of the `ff` traits. +pub trait FromUniformBytes: PrimeField { + /// Returns a field element that is congruent to the provided little endian unsigned + /// byte representation of an integer. + fn from_uniform_bytes(bytes: &[u8; N]) -> Self; } /// This represents the bits of an element of a prime field. diff --git a/tests/derive.rs b/tests/derive.rs index b20bb4e..fa6ee20 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -37,6 +37,55 @@ mod full_limbs { } } +#[test] +fn constants() { + use ff::{Field, PrimeField}; + + assert_eq!( + Bls381K12Scalar::MODULUS, + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", + ); + + assert_eq!( + Bls381K12Scalar::from(2) * Bls381K12Scalar::TWO_INV, + Bls381K12Scalar::ONE, + ); + + assert_eq!( + Bls381K12Scalar::ROOT_OF_UNITY * Bls381K12Scalar::ROOT_OF_UNITY_INV, + Bls381K12Scalar::ONE, + ); + + // ROOT_OF_UNITY^{2^s} mod m == 1 + assert_eq!( + Bls381K12Scalar::ROOT_OF_UNITY.pow(&[1u64 << Bls381K12Scalar::S, 0, 0, 0]), + Bls381K12Scalar::ONE, + ); + + // DELTA^{t} mod m == 1 + assert_eq!( + Bls381K12Scalar::DELTA.pow(&[ + 0xfffe5bfeffffffff, + 0x09a1d80553bda402, + 0x299d7d483339d808, + 0x73eda753, + ]), + Bls381K12Scalar::ONE, + ); +} + +#[test] +fn from_u128() { + use ff::{Field, PrimeField}; + + assert_eq!(Bls381K12Scalar::from_u128(1), Bls381K12Scalar::ONE); + assert_eq!(Bls381K12Scalar::from_u128(2), Bls381K12Scalar::from(2)); + assert_eq!( + Bls381K12Scalar::from_u128(u128::MAX), + Bls381K12Scalar::from_str_vartime("340282366920938463463374607431768211455").unwrap(), + ); +} + #[test] fn batch_inversion() { use ff::{BatchInverter, Field};