Skip to content

Commit

Permalink
Merge pull request #98 from zkcrypto/more-trait-changes
Browse files Browse the repository at this point in the history
More trait changes
  • Loading branch information
str4d authored Nov 29, 2022
2 parents c070ffb + 286e908 commit c555625
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 6 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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).
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
40 changes: 37 additions & 3 deletions ff_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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);
Expand All @@ -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,
)
Expand Down Expand Up @@ -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
Expand Down
139 changes: 137 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64> {
/// The prime field can be converted back and forth into this binary
/// representation.
Expand Down Expand Up @@ -241,6 +241,26 @@ pub trait PrimeField: Field + From<u64> {
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).
Expand Down Expand Up @@ -280,6 +300,12 @@ pub trait PrimeField: Field + From<u64> {
!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;

Expand All @@ -288,13 +314,16 @@ pub trait PrimeField: Field + From<u64> {
/// 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;
Expand All @@ -310,6 +339,112 @@ pub trait PrimeField: Field + From<u64> {
/// 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<const N: u8>: 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<const N: usize>: 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.
Expand Down
49 changes: 49 additions & 0 deletions tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down

0 comments on commit c555625

Please sign in to comment.