diff --git a/Cargo.lock b/Cargo.lock index aee48a0e5..af709a0b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,8 +319,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" version = "0.7.0-pre.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ff38607b7ebe30e4715eeb0a0427ff42e3b6b47b2df55a775e767ef2658ccd" +source = "git+https://github.com/RustCrypto/crypto-bigint#08377c5a61d6d891f37b465d5222b645b80e672d" dependencies = [ "hybrid-array", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index b46ebc10f..b0acc0855 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,9 @@ members = [ opt-level = 2 [patch.crates-io] +crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint" } elliptic-curve = { git = "https://github.com/RustCrypto/traits.git" } + hash2curve = { path = "hash2curve" } primefield = { path = "primefield" } primeorder = { path = "primeorder" } diff --git a/primefield/Cargo.toml b/primefield/Cargo.toml index 58033a907..616567d7e 100644 --- a/primefield/Cargo.toml +++ b/primefield/Cargo.toml @@ -14,7 +14,7 @@ edition = "2024" rust-version = "1.85" [dependencies] -bigint = { package = "crypto-bigint", version = "=0.7.0-pre.7", default-features = false } +bigint = { package = "crypto-bigint", version = "=0.7.0-pre.7", default-features = false, features = ["hybrid-array"] } ff = { version = "=0.14.0-pre.0", default-features = false } subtle = { version = "2.6", default-features = false } rand_core = { version = "0.9", default-features = false } diff --git a/primefield/src/dev.rs b/primefield/src/dev.rs index 616a7327c..16ea098f9 100644 --- a/primefield/src/dev.rs +++ b/primefield/src/dev.rs @@ -16,24 +16,11 @@ macro_rules! test_primefield_constants { use $crate::ff::PrimeField as _; /// t = (modulus - 1) >> S - const T: $uint = $uint::from_be_hex($fe::MODULUS) - .wrapping_sub(&$uint::ONE) - .wrapping_shr($fe::S); - - /// Helper function to compute the args to `pow_vartime`. #[cfg(target_pointer_width = "32")] - fn pow_args(n: &$uint) -> [u64; $uint::LIMBS.div_ceil(2)] { - let words = n.as_words(); - core::array::from_fn(|i| { - let hi = words.get((2 * i) + 1).copied().unwrap_or_default(); - let lo = words[2 * i]; - (hi as u64) << 32 | (lo as u64) - }) - } + const T: [u64; $uint::LIMBS.div_ceil(2)] = + $crate::compute_t(&$uint::from_be_hex($fe::MODULUS)); #[cfg(target_pointer_width = "64")] - fn pow_args(n: &$uint) -> [u64; $uint::LIMBS] { - *n.as_words() - } + const T: [u64; $uint::LIMBS] = $crate::compute_t(&$uint::from_be_hex($fe::MODULUS)); #[test] fn two_inv_constant() { @@ -58,7 +45,7 @@ macro_rules! test_primefield_constants { // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY assert_eq!( - $fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&pow_args(&T)), + $fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&T), $fe::ROOT_OF_UNITY ) } @@ -71,7 +58,7 @@ macro_rules! test_primefield_constants { #[test] fn delta_constant() { // DELTA^{t} mod m == 1 - assert_eq!($fe::DELTA.pow_vartime(&pow_args(&T)), $fe::ONE); + assert_eq!($fe::DELTA.pow_vartime(&T), $fe::ONE); } }; } diff --git a/primefield/src/lib.rs b/primefield/src/lib.rs index 915b105b8..ddbe7e417 100644 --- a/primefield/src/lib.rs +++ b/primefield/src/lib.rs @@ -8,14 +8,28 @@ #![warn(missing_docs, rust_2018_idioms, unused_qualifications)] #![doc = include_str!("../README.md")] +mod dev; +mod fiat; +mod monty; + +pub use crate::monty::{MontyFieldElement, MontyFieldParams, compute_t}; +pub use array::typenum::consts; pub use bigint; +pub use bigint::hybrid_array as array; pub use ff; pub use rand_core; pub use subtle; pub use zeroize; -mod dev; -mod fiat; +/// Byte order used when encoding/decoding field elements as bytestrings. +#[derive(Debug)] +pub enum ByteOrder { + /// Big endian. + BigEndian, + + /// Little endian. + LittleEndian, +} /// Implements a field element type whose internal representation is in /// Montgomery form, providing a combination of trait impls and inherent impls @@ -221,12 +235,10 @@ macro_rules! field_element_type { Self::ZERO.ct_eq(self) } - #[must_use] fn square(&self) -> Self { self.square() } - #[must_use] fn double(&self) -> Self { self.double() } diff --git a/primefield/src/monty.rs b/primefield/src/monty.rs new file mode 100644 index 000000000..ec8f6a1b8 --- /dev/null +++ b/primefield/src/monty.rs @@ -0,0 +1,825 @@ +//! Field elements which use an internal Montgomery form representation, implemented using +//! `crypto-bigint`'s [`MontyForm`]. + +use crate::ByteOrder; +use bigint::{ + ArrayEncoding, ByteArray, Integer, Invert, Odd, PrecomputeInverter, Uint, + hybrid_array::{Array, ArraySize, typenum::Unsigned}, + modular::{ + ConstMontyForm as MontyForm, ConstMontyFormInverter, ConstMontyParams, SafeGcdInverter, + }, +}; +use core::fmt::Formatter; +use core::{ + cmp::Ordering, + fmt::{self, Debug}, + iter::{Product, Sum}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use ff::{Field, PrimeField}; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, +}; + +/// Creates a ZST representing the Montgomery parameters for a given field modulus. +/// +/// Accepts the following parameters: +/// +/// - name of the ZST representing the field modulus +/// - hex serialization of the modulus +/// - `crypto-bigint` unsigned integer type (e.g. U256) +/// - number of bytes in an encoded field element +/// - byte order to use when encoding/decoding field elements +/// - documentation string for the field modulus type +/// +/// ``` +/// use primefield::{ByteOrder, bigint::U256, consts::U32}; +/// +/// primefield::monty_field_params!( +/// name: FieldParams, +/// fe_name: "FieldElement", +/// modulus: "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", +/// uint: U256, +/// bytes: U32, +/// byte_order: ByteOrder::BigEndian, +/// doc: "P-256 field modulus", +/// multiplicative_generator: 6 +/// ); +/// ``` +#[macro_export] +macro_rules! monty_field_params { + ( + name: $name:ident, + fe_name: $fe_name:expr, + modulus: $modulus_hex:expr, + uint: $uint_type:ty, + bytes: $byte_size:ty, + byte_order: $byte_order:expr, + doc: $doc:expr, + multiplicative_generator: $multiplicative_generator:expr + ) => { + use $crate::bigint::modular::ConstMontyParams; + + $crate::bigint::const_monty_params!($name, $uint_type, $modulus_hex, $doc); + + impl $crate::MontyFieldParams<{ <$uint_type>::LIMBS }> for $name { + type ByteSize = $byte_size; + const BYTE_ORDER: $crate::ByteOrder = $byte_order; + const FIELD_ELEMENT_NAME: &'static str = $fe_name; + const MODULUS_HEX: &'static str = $modulus_hex; + const MULTIPLICATIVE_GENERATOR: u64 = $multiplicative_generator; + #[cfg(target_pointer_width = "32")] + const T: &'static [u64] = &$crate::compute_t::< + { <$uint_type>::LIMBS.div_ceil(2) }, + { <$uint_type>::LIMBS }, + >($name::PARAMS.modulus().as_ref()); + #[cfg(target_pointer_width = "64")] + const T: &'static [u64] = &$crate::compute_t::< + { <$uint_type>::LIMBS }, + { <$uint_type>::LIMBS }, + >($name::PARAMS.modulus().as_ref()); + } + }; +} + +/// Extension trait for defining additional field parameters beyond the ones provided by +/// [`ConstMontyParams`]. +pub trait MontyFieldParams: ConstMontyParams { + /// Size of a field element when serialized as bytes. + type ByteSize: ArraySize; + + /// Byte order to use when serializing a field element as byte. + const BYTE_ORDER: ByteOrder; + + /// Type name to use in the `Debug` impl on elements of this field. + const FIELD_ELEMENT_NAME: &'static str; + + /// Field modulus as a hexadecimal string. + const MODULUS_HEX: &'static str; + + /// A fixed multiplicative generator of `modulus - 1` order. + /// + /// This element must also be a quadratic nonresidue. + const MULTIPLICATIVE_GENERATOR: u64; + + /// `t = (modulus - 1) >> s`, where `S = (modulus - 1).trailing_zeros()` + const T: &'static [u64]; + + /// Compute modular square root. + // TODO(tarcieri): generic implementations of various algorithms e.g. Tonelli–Shanks + fn sqrt(_: &MontyFieldElement) -> CtOption> { + todo!() + } +} + +/// Field element type which uses an internal Montgomery form representation. +#[derive(Clone, Copy)] +pub struct MontyFieldElement, const LIMBS: usize>( + MontyForm, +); + +impl, const LIMBS: usize> MontyFieldElement { + /// Zero element (additive identity). + pub const ZERO: Self = Self(MontyForm::ZERO); + + /// Multiplicative identity. + pub const ONE: Self = Self(MontyForm::ONE); + + /// Number of limbs used by the internal integer representation. + pub const LIMBS: usize = LIMBS; + + /// Decode field element from a canonical bytestring representation. + pub fn from_bytes(repr: &Array) -> CtOption + where + Uint: ArrayEncoding, + { + debug_assert!(repr.len() <= MOD::ByteSize::USIZE); + let mut byte_array = ByteArray::>::default(); + let offset = MOD::ByteSize::USIZE.saturating_sub(repr.len()); + + let uint = match MOD::BYTE_ORDER { + ByteOrder::BigEndian => { + byte_array[offset..].copy_from_slice(repr); + Uint::from_be_byte_array(byte_array) + } + ByteOrder::LittleEndian => { + byte_array[..offset].copy_from_slice(repr); + Uint::from_le_byte_array(byte_array) + } + }; + + Self::from_uint(&uint) + } + + /// Decode field element from a canonical byte slice. + /// + /// Slice is expected to be zero padded to the expected byte size. + #[inline] + pub fn from_slice(slice: &[u8]) -> Option + where + Uint: ArrayEncoding, + { + let array = Array::try_from(slice).ok()?; + Self::from_bytes(&array).into() + } + + /// Decode a field element from hex-encoded bytes. + /// + /// This is primarily intended for defining constants using hex literals. + /// + /// # Panics + /// + /// - When hex is malformed + /// - When input is the wrong length + pub const fn from_hex_vartime(hex: &str) -> Self { + let uint = match MOD::BYTE_ORDER { + ByteOrder::BigEndian => Uint::from_be_hex(hex), + ByteOrder::LittleEndian => Uint::from_le_hex(hex), + }; + + match uint.cmp_vartime(MOD::PARAMS.modulus().as_ref()) { + Ordering::Less => Self::from_uint_reduced(&uint), + _ => panic!("hex encoded field element overflows modulus"), + } + } + + /// Convert [`Uint`] into [`MontyFieldElement`], first converting it into Montgomery form: + /// + /// ```text + /// w * R^2 * R^-1 mod p = wR mod p + /// ``` + /// + /// Reduces the input modulo `p`. + #[inline] + pub const fn from_uint_reduced(uint: &Uint) -> Self { + Self(MontyForm::new(uint)) + } + + /// Convert [`Uint`] into [`MontyFieldElement`], first converting it into Montgomery form: + /// + /// ```text + /// w * R^2 * R^-1 mod p = wR mod p + /// ``` + /// + /// # Returns + /// + /// The `CtOption` equivalent of `None` if the input overflows the modulus. + #[inline] + pub fn from_uint(uint: &Uint) -> CtOption { + let is_some = uint.ct_lt(MOD::PARAMS.modulus()); + CtOption::new(Self::from_uint_reduced(uint), is_some) + } + + /// Convert a `u64` into a [`MontyFieldElement`]. + /// + /// # Panics + /// + /// If the modulus is 64-bits or smaller. + #[inline] + pub const fn from_u64(w: u64) -> Self { + if MOD::PARAMS.modulus().as_ref().bits() <= 64 { + panic!("modulus is too small to ensure all u64s are in range"); + } + + Self::from_uint_reduced(&Uint::from_u64(w)) + } + + /// Returns the bytestring encoding of this field element. + pub fn to_bytes(self) -> Array + where + Uint: ArrayEncoding, + { + let mut repr = Array::::default(); + debug_assert!(repr.len() <= MOD::ByteSize::USIZE); + + let offset = MOD::ByteSize::USIZE.saturating_sub(repr.len()); + + match MOD::BYTE_ORDER { + ByteOrder::BigEndian => { + let padded = self.0.retrieve().to_be_byte_array(); + repr.copy_from_slice(&padded[offset..]); + } + ByteOrder::LittleEndian => { + let padded = self.0.retrieve().to_le_byte_array(); + repr.copy_from_slice(&padded[..offset]); + } + } + + repr + } + + /// Determine if this field element is odd: `self mod 2 == 1`. + /// + /// # Returns + /// + /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. + #[inline] + pub fn is_odd(&self) -> Choice { + self.0.retrieve().is_odd() + } + + /// Determine if this field element is even: `self mod 2 == 0`. + /// + /// # Returns + /// + /// If even, return `Choice(1)`. Otherwise, return `Choice(0)`. + #[inline] + pub fn is_even(&self) -> Choice { + !self.is_odd() + } + + /// Determine if this field element is zero. + /// + /// # Returns + /// + /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. + #[inline] + pub fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } + + /// Translate field element out of the Montgomery domain, returning a [`Uint`] in canonical form. + #[inline] + pub const fn to_canonical(self) -> Uint { + self.0.retrieve() + } + + /// Add elements. + #[inline] + pub const fn add(&self, rhs: &Self) -> Self { + Self(MontyForm::add(&self.0, &rhs.0)) + } + + /// Double element (add it to itself). + #[inline] + #[must_use] + pub const fn double(&self) -> Self { + self.add(self) + } + + /// Subtract elements. + #[inline] + pub const fn sub(&self, rhs: &Self) -> Self { + Self(MontyForm::sub(&self.0, &rhs.0)) + } + + /// Multiply elements. + #[inline] + pub const fn multiply(&self, rhs: &Self) -> Self { + Self(MontyForm::mul(&self.0, &rhs.0)) + } + + /// Negate element. + #[inline] + pub const fn neg(&self) -> Self { + Self(MontyForm::neg(&self.0)) + } + + /// Compute modular square. + #[inline] + #[must_use] + pub const fn square(&self) -> Self { + self.multiply(self) + } + + /// Compute field inversion: `1 / self`. + #[inline] + pub fn invert(&self) -> CtOption + where + MontyForm: Invert>>, + { + self.0.invert().map(Self) + } + + /// Compute field inversion as a `const fn`. Panics if `self` is zero. + /// + /// This is mainly intended for inverting constants at compile time. + pub const fn const_invert(&self) -> Self + where + Odd>: PrecomputeInverter, Output = Uint>, + { + Self( + ConstMontyFormInverter::::new() + .invert(&self.0) + .expect("input to invert should be non-zero"), + ) + } + + /// Returns `self^exp`, where `exp` is a little-endian integer exponent. + /// + /// **This operation is variable time with respect to the exponent.** + /// + /// If the exponent is fixed, this operation is constant time. + pub const fn pow_vartime(&self, exp: &[u64]) -> Self { + let mut res = Self::ONE; + let mut i = exp.len(); + + while i > 0 { + i -= 1; + + let mut j = 64; + while j > 0 { + j -= 1; + res = res.square(); + + if ((exp[i] >> j) & 1) == 1 { + res = res.multiply(self); + } + } + } + + res + } +} + +// +// `ff` crate trait impls +// + +impl, const LIMBS: usize, const UNSAT_LIMBS: usize> Field + for MontyFieldElement +where + Array: Copy, + Uint: ArrayEncoding, + Odd>: + PrecomputeInverter, Output = Uint>, +{ + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn try_from_rng(rng: &mut R) -> Result { + let mut bytes = Array::::default(); + + loop { + rng.try_fill_bytes(&mut bytes)?; + if let Some(fe) = Self::from_bytes(&bytes).into() { + return Ok(fe); + } + } + } + + fn is_zero(&self) -> Choice { + Self::ZERO.ct_eq(self) + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn invert(&self) -> CtOption { + self.invert() + } + + fn sqrt(&self) -> CtOption { + MOD::sqrt(self) + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + ff::helpers::sqrt_ratio_generic(num, div) + } +} + +impl, const LIMBS: usize, const UNSAT_LIMBS: usize> PrimeField + for MontyFieldElement +where + Array: Copy, + Uint: ArrayEncoding, + Odd>: + PrecomputeInverter, Output = Uint>, +{ + type Repr = Array; + + const MODULUS: &'static str = MOD::MODULUS_HEX; + const NUM_BITS: u32 = MOD::PARAMS.modulus().as_ref().bits(); + const CAPACITY: u32 = Self::NUM_BITS - 1; // TODO(tarcieri): less naive calculation? + const TWO_INV: Self = Self::from_u64(2).const_invert(); + const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(MOD::MULTIPLICATIVE_GENERATOR); + const S: u32 = compute_s(MOD::PARAMS.modulus().as_ref()); + const ROOT_OF_UNITY: Self = Self::MULTIPLICATIVE_GENERATOR.pow_vartime(MOD::T); + const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.const_invert(); + const DELTA: Self = Self::MULTIPLICATIVE_GENERATOR.pow_vartime(&[1 << Self::S]); + + fn from_repr(bytes: Self::Repr) -> CtOption { + Self::from_bytes(&bytes) + } + + fn to_repr(&self) -> Self::Repr { + self.to_bytes() + } + + fn is_odd(&self) -> Choice { + self.is_odd() + } +} + +// +// Arithmetic trait impls +// + +/// Emit a `core::ops` trait wrapper for an inherent method. +macro_rules! monty_field_op { + ($op:tt, $func:ident, $inner_func:ident) => { + impl, const LIMBS: usize> $op + for MontyFieldElement + { + type Output = MontyFieldElement; + + #[inline] + fn $func(self, rhs: MontyFieldElement) -> MontyFieldElement { + >::$inner_func(&self, &rhs) + } + } + + impl, const LIMBS: usize> $op<&MontyFieldElement> + for MontyFieldElement + { + type Output = MontyFieldElement; + + #[inline] + fn $func(self, rhs: &MontyFieldElement) -> MontyFieldElement { + >::$inner_func(&self, rhs) + } + } + + impl, const LIMBS: usize> $op<&MontyFieldElement> + for &MontyFieldElement + { + type Output = MontyFieldElement; + + #[inline] + fn $func(self, rhs: &MontyFieldElement) -> MontyFieldElement { + >::$inner_func(self, rhs) + } + } + }; +} + +monty_field_op!(Add, add, add); +monty_field_op!(Sub, sub, sub); +monty_field_op!(Mul, mul, multiply); + +impl, const LIMBS: usize> AddAssign> + for MontyFieldElement +{ + #[inline] + fn add_assign(&mut self, other: MontyFieldElement) { + *self = *self + other; + } +} + +impl, const LIMBS: usize> AddAssign<&MontyFieldElement> + for MontyFieldElement +{ + #[inline] + fn add_assign(&mut self, other: &MontyFieldElement) { + *self = *self + other; + } +} + +impl, const LIMBS: usize> SubAssign> + for MontyFieldElement +{ + #[inline] + fn sub_assign(&mut self, other: MontyFieldElement) { + *self = *self - other; + } +} + +impl, const LIMBS: usize> SubAssign<&MontyFieldElement> + for MontyFieldElement +{ + #[inline] + fn sub_assign(&mut self, other: &MontyFieldElement) { + *self = *self - other; + } +} + +impl, const LIMBS: usize> MulAssign<&MontyFieldElement> + for MontyFieldElement +{ + #[inline] + fn mul_assign(&mut self, other: &MontyFieldElement) { + *self = *self * other; + } +} + +impl, const LIMBS: usize> MulAssign for MontyFieldElement { + #[inline] + fn mul_assign(&mut self, other: MontyFieldElement) { + *self = *self * other; + } +} + +impl, const LIMBS: usize> Neg for MontyFieldElement { + type Output = MontyFieldElement; + + #[inline] + fn neg(self) -> MontyFieldElement { + >::neg(&self) + } +} + +impl, const LIMBS: usize> Neg for &MontyFieldElement { + type Output = MontyFieldElement; + + #[inline] + fn neg(self) -> MontyFieldElement { + >::neg(self) + } +} + +impl, const LIMBS: usize> Sum for MontyFieldElement { + fn sum>(iter: I) -> Self { + iter.reduce(Add::add).unwrap_or(Self::ZERO) + } +} + +impl<'a, MOD: MontyFieldParams, const LIMBS: usize> Sum<&'a MontyFieldElement> + for MontyFieldElement +{ + fn sum>>(iter: I) -> Self { + iter.copied().sum() + } +} + +impl, const LIMBS: usize> Product for MontyFieldElement { + fn product>(iter: I) -> Self { + iter.reduce(Mul::mul).unwrap_or(Self::ONE) + } +} + +impl<'a, MOD: MontyFieldParams, const LIMBS: usize> + Product<&'a MontyFieldElement> for MontyFieldElement +{ + fn product>(iter: I) -> Self { + iter.copied().product() + } +} + +impl, const LIMBS: usize> Invert for MontyFieldElement +where + MontyForm: Invert>>, +{ + type Output = CtOption; + + fn invert(&self) -> CtOption { + Self::invert(self) + } +} + +// +// `subtle` trait impls +// + +impl, const LIMBS: usize> ConditionallySelectable + for MontyFieldElement +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(MontyForm::conditional_select(&a.0, &b.0, choice)) + } +} + +impl, const LIMBS: usize> ConstantTimeEq + for MontyFieldElement +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl, const LIMBS: usize> ConstantTimeGreater + for MontyFieldElement +{ + fn ct_gt(&self, other: &Self) -> Choice { + // TODO(tarcieri): impl `ConstantTimeGreater` for `ConstMontyForm` + self.0.retrieve().ct_gt(&other.0.retrieve()) + } +} + +impl, const LIMBS: usize> ConstantTimeLess + for MontyFieldElement +{ + fn ct_lt(&self, other: &Self) -> Choice { + // TODO(tarcieri): impl `ConstantTimeLess` for `ConstMontyForm` + self.0.retrieve().ct_lt(&other.0.retrieve()) + } +} + +// +// Miscellaneous trait impls +// + +impl, const LIMBS: usize> Debug for MontyFieldElement { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let canonical = self.to_canonical(); + write!(f, "{}(0x{:X})", MOD::FIELD_ELEMENT_NAME, &canonical) + } +} + +impl, const LIMBS: usize> Default for MontyFieldElement { + fn default() -> Self { + Self::ZERO + } +} + +impl, const LIMBS: usize> Eq for MontyFieldElement {} +impl, const LIMBS: usize> PartialEq for MontyFieldElement { + fn eq(&self, rhs: &Self) -> bool { + self.0.ct_eq(&(rhs.0)).into() + } +} + +impl, const LIMBS: usize> From for MontyFieldElement { + #[inline] + fn from(n: u32) -> MontyFieldElement { + Self::from_uint_reduced(&Uint::from(n)) + } +} + +impl, const LIMBS: usize> From for MontyFieldElement { + #[inline] + fn from(n: u64) -> MontyFieldElement { + Self::from_u64(n) + } +} + +impl, const LIMBS: usize> From + for MontyFieldElement +{ + fn from(n: u128) -> MontyFieldElement { + Self::from_uint_reduced(&Uint::from(n)) + } +} + +impl, const LIMBS: usize> From> + for Array +where + Uint: ArrayEncoding, +{ + fn from(fe: MontyFieldElement) -> Self { + >::from(&fe) + } +} + +impl, const LIMBS: usize> From<&MontyFieldElement> + for Array +where + Uint: ArrayEncoding, +{ + fn from(fe: &MontyFieldElement) -> Self { + fe.to_bytes() + } +} + +impl, const LIMBS: usize> From> + for Uint +{ + fn from(fe: MontyFieldElement) -> Uint { + Uint::from(&fe) + } +} + +impl, const LIMBS: usize> From<&MontyFieldElement> + for Uint +{ + fn from(fe: &MontyFieldElement) -> Uint { + fe.to_canonical() + } +} + +/// Compute `S = (modulus - 1).trailing_zeros()` +const fn compute_s(modulus: &Uint) -> u32 { + modulus.wrapping_sub(&Uint::ONE).trailing_zeros() +} + +/// Compute `t = (modulus - 1) >> S` +pub const fn compute_t(modulus: &Uint) -> [u64; N] { + #[cfg(target_pointer_width = "32")] + assert!( + LIMBS.div_ceil(2) == N, + "t array should have length LIMBS.div_ceil(2) on 32-bit architectures" + ); + #[cfg(target_pointer_width = "64")] + assert!( + LIMBS == N, + "t array should have length LIMBS on 64-bit architectures" + ); + + let s = compute_s(modulus); + let t = modulus.wrapping_sub(&Uint::ONE).wrapping_shr(s); + + let mut ret = [0; N]; + let mut i = 0; + + #[cfg(target_pointer_width = "32")] + while i < N { + let hi_i = (2 * i) + 1; + let hi = if hi_i < LIMBS { t.as_words()[hi_i] } else { 0 }; + let lo = t.as_words()[2 * i]; + ret[i] = (hi as u64) << 32 | (lo as u64); + i += 1; + } + #[cfg(target_pointer_width = "64")] + while i < N { + ret[i] = t.as_words()[i]; + i += 1; + } + + ret +} + +#[cfg(test)] +mod tests { + use crate::{ + ByteOrder, consts::U32, test_field_identity, test_field_invert, test_primefield_constants, + }; + use bigint::U256; + + // Example modulus: P-256 base field. + // p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1 + monty_field_params!( + name: FieldParams, + fe_name: "FieldElement", + modulus: "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + uint: U256, + bytes: U32, + byte_order: ByteOrder::BigEndian, + doc: "P-256 field modulus", + multiplicative_generator: 6 + ); + + /// P-256 field element + type FieldElement = super::MontyFieldElement; + + // TODO(tarcieri): change `test_primefield_constants!` to compute `T` like this: + // /// t = (modulus - 1) >> S + // const T: U256 = FieldParams::PARAMS + // .modulus() + // .as_ref() + // .wrapping_sub(&Uint::ONE) + // .wrapping_shr(FieldElement::S); + + test_primefield_constants!(FieldElement, U256); + test_field_identity!(FieldElement); + test_field_invert!(FieldElement); + + #[test] + fn modulus_bits_constant() { + assert_eq!(FieldElement::NUM_BITS, 256); + } + + #[test] + fn s_constant() { + assert_eq!(FieldElement::S, 1); + } + + #[test] + fn computed_delta_constant() { + assert_eq!(FieldElement::DELTA, FieldElement::from_u64(36)); + } +}