diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/primeorder/src/field.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/primeorder/src/field.rs')
-rw-r--r-- | vendor/primeorder/src/field.rs | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/vendor/primeorder/src/field.rs b/vendor/primeorder/src/field.rs new file mode 100644 index 000000000..a347f0bb1 --- /dev/null +++ b/vendor/primeorder/src/field.rs @@ -0,0 +1,641 @@ +/// Implements a field element type whose internal representation is in +/// Montgomery form, providing a combination of trait impls and inherent impls +/// which are `const fn` where possible. +/// +/// Accepts a set of `const fn` arithmetic operation functions as arguments. +/// +/// # Inherent impls +/// - `const ZERO: Self` +/// - `const ONE: Self` (multiplicative identity) +/// - `pub fn from_bytes` +/// - `pub fn from_slice` +/// - `pub fn from_uint` +/// - `fn from_uint_unchecked` +/// - `pub fn to_bytes` +/// - `pub fn to_canonical` +/// - `pub fn is_odd` +/// - `pub fn is_zero` +/// - `pub fn double` +/// +/// NOTE: field implementations must provide their own inherent impls of +/// the following methods in order for the code generated by this macro to +/// compile: +/// +/// - `pub fn invert` +/// - `pub fn sqrt` +/// +/// # Trait impls +/// - `AsRef<$arr>` +/// - `ConditionallySelectable` +/// - `ConstantTimeEq` +/// - `ConstantTimeGreater` +/// - `ConstantTimeLess` +/// - `Default` +/// - `DefaultIsZeroes` +/// - `Eq` +/// - `Field` +/// - `PartialEq` +/// +/// ## Ops +/// - `Add` +/// - `AddAssign` +/// - `Sub` +/// - `SubAssign` +/// - `Mul` +/// - `MulAssign` +/// - `Neg` +#[macro_export] +macro_rules! impl_mont_field_element { + ( + $curve:tt, + $fe:tt, + $bytes:ty, + $uint:ty, + $modulus:expr, + $arr:ty, + $from_mont:ident, + $to_mont:ident, + $add:ident, + $sub:ident, + $mul:ident, + $neg:ident, + $square:ident + ) => { + impl $fe { + /// Zero element. + pub const ZERO: Self = Self(<$uint>::ZERO); + + /// Multiplicative identity. + pub const ONE: Self = Self::from_uint_unchecked(<$uint>::ONE); + + /// Create a [` + #[doc = stringify!($fe)] + /// `] from a canonical big-endian representation. + pub fn from_bytes(repr: &$bytes) -> $crate::elliptic_curve::subtle::CtOption<Self> { + use $crate::elliptic_curve::FieldBytesEncoding; + Self::from_uint(FieldBytesEncoding::<$curve>::decode_field_bytes(repr)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from a big endian byte slice. + pub fn from_slice(slice: &[u8]) -> $crate::elliptic_curve::Result<Self> { + use $crate::elliptic_curve::generic_array::{typenum::Unsigned, GenericArray}; + + if slice.len() != <$curve as $crate::elliptic_curve::Curve>::FieldBytesSize::USIZE { + return Err($crate::elliptic_curve::Error); + } + + Option::from(Self::from_bytes(GenericArray::from_slice(slice))) + .ok_or($crate::elliptic_curve::Error) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] + /// from [` + #[doc = stringify!($uint)] + /// `] converting it into Montgomery form: + /// + /// ```text + /// w * R^2 * R^-1 mod p = wR mod p + /// ``` + pub fn from_uint(uint: $uint) -> $crate::elliptic_curve::subtle::CtOption<Self> { + use $crate::elliptic_curve::subtle::ConstantTimeLess as _; + let is_some = uint.ct_lt(&$modulus); + $crate::elliptic_curve::subtle::CtOption::new( + Self::from_uint_unchecked(uint), + is_some, + ) + } + + /// Parse a [` + #[doc = stringify!($fe)] + /// `] from big endian hex-encoded bytes. + /// + /// Does *not* perform a check that the field element does not overflow the order. + /// + /// This method is primarily intended for defining internal constants. + #[allow(dead_code)] + pub(crate) const fn from_hex(hex: &str) -> Self { + Self::from_uint_unchecked(<$uint>::from_be_hex(hex)) + } + + /// Convert a `u64` into a [` + #[doc = stringify!($fe)] + /// `]. + pub const fn from_u64(w: u64) -> Self { + Self::from_uint_unchecked(<$uint>::from_u64(w)) + } + + /// Decode [` + #[doc = stringify!($fe)] + /// `] from [` + #[doc = stringify!($uint)] + /// `] converting it into Montgomery form. + /// + /// Does *not* perform a check that the field element does not overflow the order. + /// + /// Used incorrectly this can lead to invalid results! + pub(crate) const fn from_uint_unchecked(w: $uint) -> Self { + Self(<$uint>::from_words($to_mont(w.as_words()))) + } + + /// Returns the big-endian encoding of this [` + #[doc = stringify!($fe)] + /// `]. + pub fn to_bytes(self) -> $bytes { + use $crate::elliptic_curve::FieldBytesEncoding; + FieldBytesEncoding::<$curve>::encode_field_bytes(&self.to_canonical()) + } + + /// Translate [` + #[doc = stringify!($fe)] + /// `] out of the Montgomery domain, returning a [` + #[doc = stringify!($uint)] + /// `] in canonical form. + #[inline] + pub const fn to_canonical(self) -> $uint { + <$uint>::from_words($from_mont(self.0.as_words())) + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is odd in the SEC1 sense: `self mod 2 == 1`. + /// + /// # Returns + /// + /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_odd(&self) -> Choice { + use $crate::elliptic_curve::bigint::Integer; + self.to_canonical().is_odd() + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is even in the SEC1 sense: `self mod 2 == 0`. + /// + /// # Returns + /// + /// If even, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_even(&self) -> Choice { + !self.is_odd() + } + + /// Determine if this [` + #[doc = stringify!($fe)] + /// `] is zero. + /// + /// # Returns + /// + /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } + + /// Add elements. + pub const fn add(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($add( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Double element (add it to itself). + #[must_use] + pub const fn double(&self) -> Self { + self.add(self) + } + + /// Subtract elements. + pub const fn sub(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($sub( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Multiply elements. + pub const fn multiply(&self, rhs: &Self) -> Self { + Self(<$uint>::from_words($mul( + self.0.as_words(), + rhs.0.as_words(), + ))) + } + + /// Negate element. + pub const fn neg(&self) -> Self { + Self(<$uint>::from_words($neg(self.0.as_words()))) + } + + /// Compute modular square. + #[must_use] + pub const fn square(&self) -> Self { + Self(<$uint>::from_words($square(self.0.as_words()))) + } + + /// 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 effectively 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 + } + } + + impl AsRef<$arr> for $fe { + fn as_ref(&self) -> &$arr { + self.0.as_ref() + } + } + + impl Default for $fe { + fn default() -> Self { + Self::ZERO + } + } + + impl Eq for $fe {} + impl PartialEq for $fe { + fn eq(&self, rhs: &Self) -> bool { + self.0.ct_eq(&(rhs.0)).into() + } + } + + impl From<u32> for $fe { + fn from(n: u32) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl From<u64> for $fe { + fn from(n: u64) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl From<u128> for $fe { + fn from(n: u128) -> $fe { + Self::from_uint_unchecked(<$uint>::from(n)) + } + } + + impl $crate::elliptic_curve::subtle::ConditionallySelectable for $fe { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self(<$uint>::conditional_select(&a.0, &b.0, choice)) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeEq for $fe { + fn ct_eq(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_eq(&other.0) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeGreater for $fe { + fn ct_gt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_gt(&other.0) + } + } + + impl $crate::elliptic_curve::subtle::ConstantTimeLess for $fe { + fn ct_lt(&self, other: &Self) -> $crate::elliptic_curve::subtle::Choice { + self.0.ct_lt(&other.0) + } + } + + impl $crate::elliptic_curve::zeroize::DefaultIsZeroes for $fe {} + + impl $crate::elliptic_curve::ff::Field for $fe { + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn random(mut rng: impl $crate::elliptic_curve::rand_core::RngCore) -> Self { + // NOTE: can't use ScalarPrimitive::random due to CryptoRng bound + let mut bytes = <$bytes>::default(); + + loop { + rng.fill_bytes(&mut bytes); + if let Some(fe) = Self::from_bytes(&bytes).into() { + return fe; + } + } + } + + fn is_zero(&self) -> Choice { + Self::ZERO.ct_eq(self) + } + + #[must_use] + fn square(&self) -> Self { + self.square() + } + + #[must_use] + fn double(&self) -> Self { + self.double() + } + + fn invert(&self) -> CtOption<Self> { + self.invert() + } + + fn sqrt(&self) -> CtOption<Self> { + self.sqrt() + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + $crate::elliptic_curve::ff::helpers::sqrt_ratio_generic(num, div) + } + } + + $crate::impl_field_op!($fe, Add, add, $add); + $crate::impl_field_op!($fe, Sub, sub, $sub); + $crate::impl_field_op!($fe, Mul, mul, $mul); + + impl AddAssign<$fe> for $fe { + #[inline] + fn add_assign(&mut self, other: $fe) { + *self = *self + other; + } + } + + impl AddAssign<&$fe> for $fe { + #[inline] + fn add_assign(&mut self, other: &$fe) { + *self = *self + other; + } + } + + impl SubAssign<$fe> for $fe { + #[inline] + fn sub_assign(&mut self, other: $fe) { + *self = *self - other; + } + } + + impl SubAssign<&$fe> for $fe { + #[inline] + fn sub_assign(&mut self, other: &$fe) { + *self = *self - other; + } + } + + impl MulAssign<&$fe> for $fe { + #[inline] + fn mul_assign(&mut self, other: &$fe) { + *self = *self * other; + } + } + + impl MulAssign for $fe { + #[inline] + fn mul_assign(&mut self, other: $fe) { + *self = *self * other; + } + } + + impl Neg for $fe { + type Output = $fe; + + #[inline] + fn neg(self) -> $fe { + Self($neg(self.as_ref()).into()) + } + } + + impl Sum for $fe { + fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { + iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO) + } + } + + impl<'a> Sum<&'a $fe> for $fe { + fn sum<I: Iterator<Item = &'a $fe>>(iter: I) -> Self { + iter.copied().sum() + } + } + + impl Product for $fe { + fn product<I: Iterator<Item = Self>>(iter: I) -> Self { + iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE) + } + } + + impl<'a> Product<&'a $fe> for $fe { + fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self { + iter.copied().product() + } + } + }; +} + +/// Emit impls for a `core::ops` trait for all combinations of reference types, +/// which thunk to the given function. +#[macro_export] +macro_rules! impl_field_op { + ($fe:tt, $op:tt, $op_fn:ident, $func:ident) => { + impl ::core::ops::$op for $fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: $fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + + impl ::core::ops::$op<&$fe> for $fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: &$fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + + impl ::core::ops::$op<&$fe> for &$fe { + type Output = $fe; + + #[inline] + fn $op_fn(self, rhs: &$fe) -> $fe { + $fe($func(self.as_ref(), rhs.as_ref()).into()) + } + } + }; +} + +/// Implement Bernstein-Yang field element inversion. +#[macro_export] +macro_rules! impl_bernstein_yang_invert { + ( + $a:expr, + $one:expr, + $d:expr, + $nlimbs:expr, + $word:ty, + $from_montgomery:ident, + $mul:ident, + $neg:ident, + $divstep_precomp:ident, + $divstep:ident, + $msat:ident, + $selectznz:ident, + ) => {{ + // See Bernstein-Yang 2019 p.366 + const ITERATIONS: usize = (49 * $d + 57) / 17; + + let a = $from_montgomery($a); + let mut d = 1; + let mut f = $msat(); + let mut g = [0; $nlimbs + 1]; + let mut v = [0; $nlimbs]; + let mut r = $one; + let mut i = 0; + let mut j = 0; + + while j < $nlimbs { + g[j] = a[j]; + j += 1; + } + + while i < ITERATIONS - ITERATIONS % 2 { + let (out1, out2, out3, out4, out5) = $divstep(d, &f, &g, &v, &r); + let (out1, out2, out3, out4, out5) = $divstep(out1, &out2, &out3, &out4, &out5); + d = out1; + f = out2; + g = out3; + v = out4; + r = out5; + i += 2; + } + + if ITERATIONS % 2 != 0 { + let (_out1, out2, _out3, out4, _out5) = $divstep(d, &f, &g, &v, &r); + v = out4; + f = out2; + } + + let s = ((f[f.len() - 1] >> <$word>::BITS - 1) & 1) as u8; + let v = $selectznz(s, &v, &$neg(&v)); + $mul(&v, &$divstep_precomp()) + }}; +} + +/// Implement field element identity tests. +#[macro_export] +macro_rules! impl_field_identity_tests { + ($fe:tt) => { + #[test] + fn zero_is_additive_identity() { + let zero = $fe::ZERO; + let one = $fe::ONE; + assert_eq!(zero.add(&zero), zero); + assert_eq!(one.add(&zero), one); + } + + #[test] + fn one_is_multiplicative_identity() { + let one = $fe::ONE; + assert_eq!(one.multiply(&one), one); + } + }; +} + +/// Implement field element inversion tests. +#[macro_export] +macro_rules! impl_field_invert_tests { + ($fe:tt) => { + #[test] + fn invert() { + let one = $fe::ONE; + assert_eq!(one.invert().unwrap(), one); + + let three = one + &one + &one; + let inv_three = three.invert().unwrap(); + assert_eq!(three * &inv_three, one); + + let minus_three = -three; + let inv_minus_three = minus_three.invert().unwrap(); + assert_eq!(inv_minus_three, -inv_three); + assert_eq!(three * &inv_minus_three, -one); + } + }; +} + +/// Implement field element square root tests. +#[macro_export] +macro_rules! impl_field_sqrt_tests { + ($fe:tt) => { + #[test] + fn sqrt() { + for &n in &[1u64, 4, 9, 16, 25, 36, 49, 64] { + let fe = $fe::from(n); + let sqrt = fe.sqrt().unwrap(); + assert_eq!(sqrt.square(), fe); + } + } + }; +} + +/// Implement tests for the `PrimeField` trait. +#[macro_export] +macro_rules! impl_primefield_tests { + ($fe:tt, $t:expr) => { + #[test] + fn two_inv_constant() { + assert_eq!($fe::from(2u32) * $fe::TWO_INV, $fe::ONE); + } + + #[test] + fn root_of_unity_constant() { + assert!($fe::S < 128); + let two_to_s = 1u128 << $fe::S; + + // ROOT_OF_UNITY^{2^s} mod m == 1 + assert_eq!( + $fe::ROOT_OF_UNITY.pow_vartime(&[ + (two_to_s & 0xFFFFFFFFFFFFFFFF) as u64, + (two_to_s >> 64) as u64, + 0, + 0 + ]), + $fe::ONE + ); + + // MULTIPLICATIVE_GENERATOR^{t} mod m == ROOT_OF_UNITY + assert_eq!( + $fe::MULTIPLICATIVE_GENERATOR.pow_vartime(&$t), + $fe::ROOT_OF_UNITY + ) + } + + #[test] + fn root_of_unity_inv_constant() { + assert_eq!($fe::ROOT_OF_UNITY * $fe::ROOT_OF_UNITY_INV, $fe::ONE); + } + + #[test] + fn delta_constant() { + // DELTA^{t} mod m == 1 + assert_eq!($fe::DELTA.pow_vartime(&$t), $fe::ONE); + } + }; +} |