From 84edae1b4f7eb56ee0c21988bfac0e70fbc46aef Mon Sep 17 00:00:00 2001 From: kilic Date: Tue, 14 May 2024 01:47:36 +0300 Subject: [PATCH] remove 7 limb specific impls --- src/pluto_eris/fields/fp.rs | 415 ----------------- src/pluto_eris/fields/fp2.rs | 649 --------------------------- src/pluto_eris/fields/fq.rs | 406 ----------------- src/pluto_eris/fields/mod.rs | 843 ----------------------------------- 4 files changed, 2313 deletions(-) delete mode 100644 src/pluto_eris/fields/fp.rs delete mode 100644 src/pluto_eris/fields/fp2.rs delete mode 100644 src/pluto_eris/fields/fq.rs delete mode 100644 src/pluto_eris/fields/mod.rs diff --git a/src/pluto_eris/fields/fp.rs b/src/pluto_eris/fields/fp.rs deleted file mode 100644 index 646ef7e8..00000000 --- a/src/pluto_eris/fields/fp.rs +++ /dev/null @@ -1,415 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_p$ where -/// -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001` -/// -/// is the base field of the Pluto curve. -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fp` values are always in Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fp(pub(crate) [u64; 7]); - -/// Size of `Fp` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001 -const MODULUS: Fp = Fp([ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x9ffffcd3, 0x0006b945, 0xa2a7e8c3, 0x8fadffd6, 0xe4a7a5fe, 0xda8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -// pub const NEGATIVE_ONE: Fp = Fp([]); - -pub(crate) const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd300000001"; - -/// INV = -r^{-1} mod 2^64 -/// `0x9ffffcd2ffffffff` -const INV: u64 = 0x9ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod p` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c7760637089cbf6a760a123e01218d68a2aaffd0ef18a000163afffffff9` -const R: Fp = Fp([ - 0xa000163afffffff9, - 0x8d68a2aaffd0ef18, - 0xbf6a760a123e0121, - 0x2242c7760637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x03ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod p` -/// `0x1a4b16581f66e3cc8bcb0f20758aec8520b6db3d7481a84c734fd363b575c23e7a42067a8ccd154b4b20c07277ae01f1d9702c6d54dc0598` -const R2: Fp = Fp([ - 0xd9702c6d54dc0598, - 0x4b20c07277ae01f1, - 0x7a42067a8ccd154b, - 0x734fd363b575c23e, - 0x20b6db3d7481a84c, - 0x8bcb0f20758aec85, - 0x1a4b16581f66e3cc, -]); - -/// `R^3 = 2^1792 mod p` -/// `0x1f51e40a048ddc1789010189f4df0ae1f3bc57efac4b3280b25aa8b46a40b225e5446680e4c4ea0449937d6b40e58f05c67afa3fe916dd69` -const R3: Fp = Fp([ - 0xc67afa3fe916dd69, - 0x49937d6b40e58f05, - 0xe5446680e4c4ea04, - 0xb25aa8b46a40b225, - 0xf3bc57efac4b3280, - 0x89010189f4df0ae1, - 0x1f51e40a048ddc17, -]); - -/// `GENERATOR = 10 mod p` is a generator of the `p - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fp = Fp::from_raw([0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -const S: u32 = 32; - -/// GENERATOR^t where t * 2^s + 1 = p -/// with t odd. In other words, this -/// is a 2^s root of unity. -/// `0x2d39f8c5f9adb3f35fe3f4222db17451ddd9602a013af5276bdbe3903ec85fc889232f5c8bc6857060c75e6f399661d6c7b82d31d563091` -const ROOT_OF_UNITY: Fp = Fp::from_raw([ - 0x6c7b82d31d563091, - 0x060c75e6f399661d, - 0x889232f5c8bc6857, - 0x76bdbe3903ec85fc, - 0x1ddd9602a013af52, - 0x35fe3f4222db1745, - 0x02d39f8c5f9adb3f, -]); - -/// 1 / ROOT_OF_UNITY mod p -/// `0x17725d635b00cda4153eb10c7105919d012822bd86c08691803272fbc5c9f8378055eb56ae2d55f9272bf208aad57f666deaead2c693ff66` -const ROOT_OF_UNITY_INV: Fp = Fp::from_raw([ - 0x6deaead2c693ff66, - 0x272bf208aad57f66, - 0x8055eb56ae2d55f9, - 0x803272fbc5c9f837, - 0x012822bd86c08691, - 0x153eb10c7105919d, - 0x17725d635b00cda4, -]); - -/// 1 / 2 mod p -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e6d45363df253d2ff47d6ffeb5153f46180035ca2cffffe6980000001` -pub(crate) const TWO_INV: Fp = Fp::from_raw([ - 0xcffffe6980000001, - 0x5153f46180035ca2, - 0xf253d2ff47d6ffeb, - 0xa21fcd2e6d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); -/// GENERATOR^{2^s} where t * 2^s + 1 = r with t odd. In other words, this is a t root of unity. -/// `0xeacefc6504d028d42ed23fc8766d5a5f195b456887e1e0021fb760c53233e9170c23749b459b95cc6cbb5faf3754a1e1916b2007775db04` -const DELTA: Fp = Fp::from_raw([ - 0x1916b2007775db04, - 0xc6cbb5faf3754a1e, - 0x70c23749b459b95c, - 0x21fb760c53233e91, - 0xf195b456887e1e00, - 0x42ed23fc8766d5a5, - 0x0eacefc6504d028d, -]); - -/// `ZETA^3 = 1 mod p` where `ZETA^2 != 1 mod p` -/// `0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe` -const ZETA: Fp = Fp::from_raw([ - 0x100004c37ffffffe, - 0xc8ad8b38dffaf50c, - 0xc956d01c903d720d, - 0x50000d7ee0e4a803, - 0x00000000360001c9, - 0x0000000000004800, - 0x0000000000000000, -]); - -/// NEG_ONE ; -1 mod p -pub(crate) const NEG_ONE: Fp = Fp::from_raw([ - 0x9ffffcd300000000, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -impl_binops_additive!(Fp, Fp); -impl_binops_multiplicative!(Fp, Fp); -field_common_7_limbs!( - Fp, - FpRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fp); -impl_from_u64_7_limbs!(Fp, R2); -field_arithmetic_7_limbs!(Fp, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fp, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fp, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fp); - -impl Fp { - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fp { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(p - 2) - let tmp = self.pow([ - 0x9ffffcd2ffffffff, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0x80035ca2cffffe69, - 0x47d6ffeb5153f461, - 0x6d45363df253d2ff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fp` element. -pub struct FpRepr { - pub repr: [u8; SIZE], -} - -impl FpRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FpRepr { - fn default() -> Self { - FpRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FpRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FpRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FpRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fp { - type Repr = FpRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - res[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fp { - /// Converts a 512-bit little endian integer into - /// an `Fp` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fp { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fp, "field_arithmetic"); - crate::field_testing_suite!(Fp, "conversion"); - crate::field_testing_suite!(Fp, "serialization"); - crate::field_testing_suite!(Fp, "quadratic_residue"); - crate::field_testing_suite!(Fp, "bits"); - crate::field_testing_suite!(Fp, "serialization_check"); - crate::field_testing_suite!(Fp, "constants", MODULUS_STR); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!(Fp, "from_uniform_bytes", 64); -} diff --git a/src/pluto_eris/fields/fp2.rs b/src/pluto_eris/fields/fp2.rs deleted file mode 100644 index 1246b654..00000000 --- a/src/pluto_eris/fields/fp2.rs +++ /dev/null @@ -1,649 +0,0 @@ -use super::fp::{Fp, MODULUS_STR}; -use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::ff_ext::Legendre; -use core::convert::TryInto; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::cmp::Ordering; -use std::ops::MulAssign; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// -ALPHA is a quadratic non-residue in Fp. Fp2 = Fp[X]/(X^2 + ALPHA) -/// We introduce the variable u such that u^2 = -ALPHA - -/// U_SQUARE = -5 -/// 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5cda8a6c7be4a7a5fe8fadffd6a2a7e8c30006b9459ffffcd2fffffffc -const U_SQUARE: Fp = Fp::from_raw([ - 0x9ffffcd2fffffffc, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -const NEG_ONE: Fp2 = Fp2 { - c0: super::fp::NEG_ONE, - c1: Fp::ZERO, -}; - -/// An element of Fp2, represented by c0 + c1 * u. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fp2 { - pub c0: Fp, - pub c1: Fp, -} - -/// `Fp2` elements are ordered lexicographically. -impl Ord for Fp2 { - #[inline(always)] - fn cmp(&self, other: &Fp2) -> Ordering { - match self.c1.cmp(&other.c1) { - Ordering::Greater => Ordering::Greater, - Ordering::Less => Ordering::Less, - Ordering::Equal => self.c0.cmp(&other.c0), - } - } -} - -impl PartialOrd for Fp2 { - #[inline(always)] - fn partial_cmp(&self, other: &Fp2) -> Option { - Some(self.cmp(other)) - } -} - -impl ConditionallySelectable for Fp2 { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fp2 { - c0: Fp::conditional_select(&a.c0, &b.c0, choice), - c1: Fp::conditional_select(&a.c1, &b.c1, choice), - } - } -} - -impl ConstantTimeEq for Fp2 { - fn ct_eq(&self, other: &Self) -> Choice { - self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) - } -} - -impl Default for Fp2 { - #[inline] - fn default() -> Self { - Self::ZERO - } -} - -impl From for [u8; 112] { - fn from(value: Fp2) -> [u8; 112] { - value.to_bytes() - } -} - -impl<'a> From<&'a Fp2> for [u8; 112] { - fn from(value: &'a Fp2) -> [u8; 112] { - value.to_bytes() - } -} - -impl Neg for Fp2 { - type Output = Fp2; - - #[inline] - fn neg(self) -> Fp2 { - -&self - } -} - -impl<'a> Neg for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn neg(self) -> Fp2 { - self.neg() - } -} - -impl<'a, 'b> Sub<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn sub(self, rhs: &'b Fp2) -> Fp2 { - self.sub(rhs) - } -} - -impl<'a, 'b> Add<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn add(self, rhs: &'b Fp2) -> Fp2 { - self.add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 { - type Output = Fp2; - - #[inline] - fn mul(self, rhs: &'b Fp2) -> Fp2 { - self.mul(rhs) - } -} - -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -impl_binops_additive!(Fp2, Fp2); -impl_binops_multiplicative!(Fp2, Fp2); -impl_sum_prod!(Fp2); - -/// Size in bytes of a `Fp2` element. -const SIZE: usize = 112; -/// Size in bytes of a each coefficient of `Fp2`. -const COEF_SIZE: usize = 56; - -impl Fp2 { - /// Returns the zero element. - #[inline] - pub const fn zero() -> Fp2 { - Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - } - } - - /// Returns the unit. - #[inline] - pub const fn one() -> Fp2 { - Fp2 { - c0: Fp::one(), - c1: Fp::zero(), - } - } - - /// Given its `Fp` coefficients c0, c1. Returns the element of `Fp2`: c0 + c1 * u. - pub const fn new(c0: Fp, c1: Fp) -> Self { - Fp2 { c0, c1 } - } - - /// Returns the size in bytes of a `Fp2` element. - pub const fn size() -> usize { - SIZE - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fp`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; SIZE]) -> CtOption { - let c0 = Fp::from_bytes(bytes[0..COEF_SIZE].try_into().unwrap()); - let c1 = Fp::from_bytes(bytes[COEF_SIZE..SIZE].try_into().unwrap()); - CtOption::new( - Fp2 { - c0: c0.unwrap(), - c1: c1.unwrap(), - }, - c0.is_some() & c1.is_some(), - ) - } - - /// Converts an element of `Fp` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(self) -> [u8; SIZE] { - let mut res = [0u8; SIZE]; - let c0_bytes = self.c0.to_bytes(); - let c1_bytes = self.c1.to_bytes(); - res[0..COEF_SIZE].copy_from_slice(&c0_bytes[..]); - res[COEF_SIZE..SIZE].copy_from_slice(&c1_bytes[..]); - res - } - - // TODO: This is a naive method using 4 multiplications - pub fn mul_assign(&mut self, other: &Self) { - // r0 = s0 * s0 + U_SQUARE * s1 * o1 - // r1 = s0 * o1 - s1 * o0 - - let t0 = self.c0 * other.c0; - let t1 = self.c0 * other.c1; - let t2 = self.c1 * other.c0; - let t3 = self.c1 * other.c1; - - self.c0 = t0 + U_SQUARE * t3; - self.c1 = t1 + t2 - } - - // TODO: This is a naive method using 3 multiplications - pub fn square_assign(&mut self) { - // r0 = s0^2 + U_SQUARE * s1^2 - // r1 = 2* s0s1 - - let ab = self.c0 * self.c1; - let a2 = self.c0 * self.c0; - let b2 = self.c1 * self.c1; - - self.c1 = ab.double(); - self.c0 = a2 + U_SQUARE * b2; - } - - pub fn double(&self) -> Self { - Self { - c0: self.c0.double(), - c1: self.c1.double(), - } - } - - pub fn double_assign(&mut self) { - self.c0 = self.c0.double(); - self.c1 = self.c1.double(); - } - - pub fn add(&self, other: &Self) -> Self { - Self { - c0: self.c0.add(&other.c0), - c1: self.c1.add(&other.c1), - } - } - - pub fn sub(&self, other: &Self) -> Self { - Self { - c0: self.c0.sub(&other.c0), - c1: self.c1.sub(&other.c1), - } - } - - pub fn mul(&self, other: &Self) -> Self { - let mut t = *other; - t.mul_assign(self); - t - } - - pub fn square(&self) -> Self { - let mut t = *self; - t.square_assign(); - t - } - - pub fn neg(&self) -> Self { - Self { - c0: self.c0.neg(), - c1: self.c1.neg(), - } - } - - // conjucate by negating c1 - pub fn conjugate(&mut self) { - self.c1 = -self.c1; - } - - pub fn frobenius_map(&mut self, power: usize) { - //TODO Replace with constant time version if needed - if power % 2 != 0 { - self.conjugate() - } - } - - /// Multiply this element by cubic nonresidue: V_CUBE = 57/(u+3) - pub fn mul_by_nonresidue(&mut self) { - // (x + y * u) * 57/(u + 3) - self.mul_assign(&super::fp6::V_CUBE) - } - - pub fn invert(&self) -> CtOption { - let mut t1 = self.c1; - t1 = t1.square(); - t1 *= U_SQUARE; - let mut t0 = self.c0; - t0 = t0.square(); - //t0 = c0^2 - U_SQUARE c1^2 - t0 -= &t1; - t0.invert().map(|t| { - let mut tmp = Fp2 { - c0: self.c0, - c1: self.c1, - }; - tmp.c0 *= &t; - tmp.c1 *= &t; - tmp.c1 = -tmp.c1; - - tmp - }) - } - - /// Norm of Fp2 as extension field in u over Fp - fn norm(&self) -> Fp { - // norm = self * self.conjugate() - let t0 = self.c0.square(); - let t1 = self.c1.square() * U_SQUARE; - t1 - t0 - } -} - -impl Legendre for Fp2 { - fn legendre(&self) -> i64 { - self.norm().legendre() - } -} - -impl Field for Fp2 { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Fp2 { - c0: Fp::random(&mut rng), - c1: Fp::random(&mut rng), - } - } - - fn is_zero(&self) -> Choice { - self.c0.is_zero() & self.c1.is_zero() - } - - fn square(&self) -> Self { - self.square() - } - - fn double(&self) -> Self { - self.double() - } - - fn sqrt(&self) -> CtOption { - // Algorithm 10, https://eprint.iacr.org/2012/685.pdf - - // Aux elements. Described in PRECOMPUTATION of Algorithm 10. - // As element of Fp2: E = 0 + U * - // 0x13e275a1fa6a13af7a82a3d83bc9e63a667c70cf991a36e603b21f15823a404a021848271d63f0875d232408689b4c6c67153f9701e19938 - const E: Fp2 = Fp2 { - c0: Fp::ZERO, - c1: Fp::from_raw([ - 0x67153f9701e19938, - 0x5d232408689b4c6c, - 0x021848271d63f087, - 0x03b21f15823a404a, - 0x667c70cf991a36e6, - 0x7a82a3d83bc9e63a, - 0x13e275a1fa6a13af, - ]), - }; - - // As element of Fp2: f = 5 + 0 * U - // 0x5 - const F: Fp2 = Fp2 { - c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), - c1: Fp::ZERO, - }; - - // Algorithm (not constant time) - let b = self.pow_vartime([ - // (p-1)/4 = - // 0x900000000000900004c3800035fdc392a00f29dbd0e499bd10fe69736a29b1ef929e97fa3eb7ff5a8a9fa30c001ae5167ffff34c0000000 - 0x67ffff34c0000000, - 0xa8a9fa30c001ae51, - 0xf929e97fa3eb7ff5, - 0xd10fe69736a29b1e, - 0x2a00f29dbd0e499b, - 0x004c3800035fdc39, - 0x0900000000000900, - ]); - - let b_2 = b.square(); - let mut b_2_q = b_2; - b_2_q.frobenius_map(1); - - let a0 = b_2_q * b_2; - if a0 == NEG_ONE { - CtOption::new(a0, Choice::from(0)) - } else { - let mut x = b; - x.frobenius_map(1); - if x * b == Fp2::ONE { - let x0 = (b_2 * self).c0.sqrt().unwrap(); - x.c0.mul_assign(x0); - x.c1.mul_assign(x0); - CtOption::new(x, Choice::from(1)) - } else { - let x0 = (self * b_2 * F).sqrt().unwrap(); - x *= x0 * E; - CtOption::new(x, Choice::from(1)) - } - } - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } - - fn invert(&self) -> CtOption { - self.invert() - } -} - -impl From for Fp2 { - fn from(bit: bool) -> Fp2 { - if bit { - Fp2::ONE - } else { - Fp2::ZERO - } - } -} - -impl From for Fp2 { - fn from(val: u64) -> Self { - Fp2 { - c0: Fp::from(val), - c1: Fp::zero(), - } - } -} - -// This trait is only implemented to satisfy the requirement of CurveExt -impl PrimeField for Fp2 { - type Repr = Fp2Bytes; - - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = Fp2 { - c0: Fp::MULTIPLICATIVE_GENERATOR, - c1: Fp::ZERO, - }; - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const S: u32 = 0; - - // TODO: Check that we can just 0 this and forget. - const ROOT_OF_UNITY: Self = Fp2::zero(); - const ROOT_OF_UNITY_INV: Self = Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }; - const DELTA: Self = Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }; - const TWO_INV: Self = Fp2 { - c0: Fp::TWO_INV, - c1: Fp::zero(), - }; - - fn from_repr(repr: Self::Repr) -> CtOption { - let c0 = Fp::from_bytes(&repr.0[..COEF_SIZE].try_into().unwrap()); - let c1 = Fp::from_bytes(&repr.0[COEF_SIZE..].try_into().unwrap()); - // Disallow overflow representation - CtOption::new(Fp2::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) - } - - fn to_repr(&self) -> Self::Repr { - Fp2Bytes(self.to_bytes()) - } - - fn is_odd(&self) -> Choice { - self.c0.is_odd() | (self.c0.is_zero() & self.c1.is_odd()) - } -} - -impl FromUniformBytes<64> for Fp2 { - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::new(Fp::from_uniform_bytes(bytes), Fp::zero()) - } -} -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fp2` element. -/// First half of the bytes represent `c0`, the second half represent `c1`. -pub struct Fp2Bytes([u8; SIZE]); - -impl Default for Fp2Bytes { - fn default() -> Self { - Self([0u8; SIZE]) - } -} - -impl AsMut<[u8]> for Fp2Bytes { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } -} - -impl AsRef<[u8]> for Fp2Bytes { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl crate::serde::SerdeObject for Fp2 { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 112); - let [c0, c1] = [0, 56].map(|i| Fp::from_raw_bytes_unchecked(&bytes[i..i + 56])); - Self { c0, c1 } - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != SIZE { - return None; - } - let [c0, c1] = [0, COEF_SIZE].map(|i| Fp::from_raw_bytes(&bytes[i..i + COEF_SIZE])); - c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(SIZE); - for limb in self.c0.0.iter().chain(self.c1.0.iter()) { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let [c0, c1] = [(); 2].map(|_| Fp::read_raw_unchecked(reader)); - Self { c0, c1 } - } - fn read_raw(reader: &mut R) -> std::io::Result { - let c0 = Fp::read_raw(reader)?; - let c1 = Fp::read_raw(reader)?; - Ok(Self { c0, c1 }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - self.c0.write_raw(writer)?; - self.c1.write_raw(writer) - } -} - -impl WithSmallOrderMulGroup<3> for Fp2 { - const ZETA: Self = Fp2 { - // 0x24000000000024000130e0000d7f28e4a803ca76be3924a5f43f8cddf9a5c4781b50d5e1ff708dc8d9fa5d8a200bc4398ffff80f80000002 - c0: Fp::from_raw([ - 0x8ffff80f80000002, - 0xd9fa5d8a200bc439, - 0x1b50d5e1ff708dc8, - 0xf43f8cddf9a5c478, - 0xa803ca76be3924a5, - 0x0130e0000d7f28e4, - 0x2400000000002400, - ]), - c1: Fp::zero(), - }; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fp2, "field_arithmetic"); - crate::field_testing_suite!(Fp2, "conversion"); - crate::field_testing_suite!(Fp2, "serialization"); - crate::field_testing_suite!(Fp2, "quadratic_residue"); - crate::field_testing_suite!(Fp2, "sqrt"); - crate::field_testing_suite!(Fp2, "zeta", Fp); - // extension field-specific - crate::field_testing_suite!(Fp2, "f2_tests", Fp); - crate::field_testing_suite!( - Fp2, - "frobenius", - // Frobenius endomorphism power parameter for extension field - // ϕ: E → E - // (x, y) ↦ (x^p, y^p) - // p: modulus of base field (Here, Fp::MODULUS) - [ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ] - ); - - #[test] - fn test_fp2_squaring() { - // u + 1 - let mut a = Fp2 { - c0: Fp::one(), - c1: Fp::one(), - }; - // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u - a.square_assign(); - let minus_4 = -Fp::from(4u64); - assert_eq!( - a, - Fp2 { - c0: minus_4, - c1: Fp::one() + Fp::one(), - } - ); - - // u - let mut a = Fp2 { - c0: Fp::zero(), - c1: Fp::one(), - }; - // u^2 - a.square_assign(); - assert_eq!( - a, - Fp2 { - c0: U_SQUARE, - c1: Fp::zero(), - } - ); - } - - #[test] - fn test_fp2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let nqr = crate::pluto_eris::fields::fp6::V_CUBE; - for _ in 0..1000 { - let mut a = Fp2::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } - } -} diff --git a/src/pluto_eris/fields/fq.rs b/src/pluto_eris/fields/fq.rs deleted file mode 100644 index 45d0f542..00000000 --- a/src/pluto_eris/fields/fq.rs +++ /dev/null @@ -1,406 +0,0 @@ -use crate::arithmetic::{adc, mac, sbb}; -use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::{ - extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, - impl_from_u64_7_limbs, -}; -use crate::{ - impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, - impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, - impl_sum_prod, -}; -use core::convert::TryInto; -use core::fmt; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use std::slice::Iter; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -/// This represents an element of $\mathbb{F}_q$ where -/// -/// `q = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -/// -/// is the scalar field of the Pluto curve (and the base field of the Eris curve). -/// The internal representation of this type is seven 64-bit unsigned -/// integers in little-endian order which account for the 446 bits required to be represented. -/// `Fq` values are always in Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^448. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] -pub struct Fq(pub(crate) [u64; 7]); - -/// Size of `Fq` element in bytes -const SIZE: usize = 56; - -/// Constant representing the modulus -/// `p = 0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001` -const MODULUS: Fq = Fq([ - 0x1ffffcd300000001, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, -]); - -/// The modulus as u32 limbs. -#[cfg(not(target_pointer_width = "64"))] -const MODULUS_LIMBS_32: [u32; 14] = [ - 0x00000001, 0x1ffffcd3, 0x60050af4, 0x9ca7e85d, 0x8e177fd6, 0xe4a775fe, 0x7a8a6c7b, 0x443f9a5c, - 0xf439266f, 0xa803ca76, 0x0d7f70e4, 0x0130e000, 0x00002400, 0x24000000, -]; - -const MODULUS_STR: &str = "0x24000000000024000130e0000d7f70e4a803ca76f439266f443f9a5c7a8a6c7be4a775fe8e177fd69ca7e85d60050af41ffffcd300000001"; - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -/// `0x1ffffcd2ffffffff` -const INV: u64 = 0x1ffffcd2ffffffff; - -/// Let M be the power of `2^64` nearest to `Self::MODULUS_BITS`. Then `R = M % Self::MODULUS`. -/// `R = 2^448 mod q` -/// `0x3ffffffffff03fff7a9dfffa183e9bf67e576bf526ff2f52242c778a637089cbf6bc60a1d5b8121b768a5725fdcb3532000163afffffff9` -const R: Fq = Fq([ - 0x2000163afffffff9, - 0xb768a5725fdcb353, - 0xbf6bc60a1d5b8121, - 0x2242c778a637089c, - 0x67e576bf526ff2f5, - 0xf7a9dfffa183e9bf, - 0x3ffffffffff03ff, -]); - -/// `R^2 = 2^896 mod q` -/// `0x50d7c998f46144ee436895a5a630ff544d51e923f64695651da4da1c97f716419bd905e6e4ff6c2bc64e865fe4552ad740808c831022522` -const R2: Fq = Fq([ - 0x740808c831022522, - 0xbc64e865fe4552ad, - 0x19bd905e6e4ff6c2, - 0x51da4da1c97f7164, - 0x44d51e923f646956, - 0xe436895a5a630ff5, - 0x050d7c998f46144e, -]); - -/// `R^3 = 2^1792 mod q` -/// `0x2f2c41fb476072baa10b8225e69f7de3b2c1031e6d01279e65191fab1f6ce25295c3c8bd6945406c89b51b218477a6f7252704d7495b38a` -const R3: Fq = Fq([ - 0x7252704d7495b38a, - 0xc89b51b218477a6f, - 0x295c3c8bd6945406, - 0xe65191fab1f6ce25, - 0x3b2c1031e6d01279, - 0xaa10b8225e69f7de, - 0x02f2c41fb476072b, -]); - -/// `GENERATOR = 7 mod q` is a generator of the `q - 1` order multiplicative -/// subgroup, or in other words a primitive root of the field. -const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// Size of the 2-adic sub-group of the field. -const S: u32 = 32; - -/// GENERATOR^t where t * 2^s + 1 = q -/// with t odd. In other words, this is a 2^s root of unity. -/// `0x0a5e6f78289fd24b1c64c90821c44cdce9ba1b3e90f2e88957f869667f6dfdbdbce6bb9ed38a8c2382fa11e3d3810fcc3c7bb406ec7bce04` - -const ROOT_OF_UNITY: Fq = Fq::from_raw([ - 0x3c7bb406ec7bce04, - 0x82fa11e3d3810fcc, - 0xbce6bb9ed38a8c23, - 0x57f869667f6dfdbd, - 0xe9ba1b3e90f2e889, - 0x1c64c90821c44cdc, - 0x0a5e6f78289fd24b, -]); - -/// 1 / ROOT_OF_UNITY mod q -/// `0x1a8c636e293fe9928f85aa6ec68f950ebb57e3f0502dd05667c990c1c2f57128c77768be1824fd3f60869f410287a1879ec16a35ca69b6fb` - -const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ - 0x9ec16a35ca69b6fb, - 0x60869f410287a187, - 0xc77768be1824fd3f, - 0x67c990c1c2f57128, - 0xbb57e3f0502dd056, - 0x8f85aa6ec68f950e, - 0x1a8c636e293fe992, -]); - -/// 1 / 2 mod q -/// `0x12000000000012000098700006bfb8725401e53b7a1c9337a21fcd2e3d45363df253baff470bbfeb4e53f42eb002857a0ffffe6980000001` -const TWO_INV: Fq = Fq::from_raw([ - 0x0ffffe6980000001, - 0x4e53f42eb002857a, - 0xf253baff470bbfeb, - 0xa21fcd2e3d45363d, - 0x5401e53b7a1c9337, - 0x0098700006bfb872, - 0x1200000000001200, -]); - -/// GENERATOR^{2^s} where t * 2^s + 1 = q with t odd. In other words, this is a t root of unity. -/// 0x657946fe07116ceca983fe28713a2b257ab7a7866c95121e727f3776c3e84cb0a14f6a7f83f8cdaeadb479c657bdf2de4589640faf72e67 -const DELTA: Fq = Fq::from_raw([ - 0xe4589640faf72e67, - 0xeadb479c657bdf2d, - 0x0a14f6a7f83f8cda, - 0xe727f3776c3e84cb, - 0x57ab7a7866c95121, - 0xca983fe28713a2b2, - 0x657946fe07116ce, -]); - -/// `ZETA^3 = 1 mod q` where `ZETA^2 != 1 mod q` -/// `0x9000000000006c000392a0001afee1c9500792ae3039253e641ba35817a29ffaf50be000032cfffffffe` - -const ZETA: Fq = Fq::from_raw([ - 0xe000032cfffffffe, - 0xa35817a29ffaf50b, - 0x92ae3039253e641b, - 0xa0001afee1c95007, - 0x000000006c000392, - 0x0000000000009000, - 0x0000000000000000, -]); - -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); -field_common_7_limbs!( - Fq, - FqRepr, - MODULUS, - INV, - MODULUS_STR, - TWO_INV, - ROOT_OF_UNITY_INV, - DELTA, - ZETA, - R, - R2, - R3 -); -impl_sum_prod!(Fq); -impl_from_u64_7_limbs!(Fq, R2); -field_arithmetic_7_limbs!(Fq, MODULUS, INV, sparse); - -#[cfg(target_pointer_width = "64")] -field_bits_7_limbs!(Fq, MODULUS); -#[cfg(not(target_pointer_width = "64"))] -field_bits_7_limbs!(Fq, MODULUS, MODULUS_LIMBS_32); - -extend_field_legendre!(Fq); - -impl Fq { - /// Return field element size in bytes. - pub const fn size() -> usize { - SIZE - } -} - -impl ff::Field for Fq { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); - - fn random(mut rng: impl RngCore) -> Self { - Self::from_u512([ - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - rng.next_u64(), - ]) - } - - fn double(&self) -> Self { - self.double() - } - - #[inline(always)] - fn square(&self) -> Self { - self.square() - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - fn invert(&self) -> CtOption { - // self^(q - 2) - let tmp = self.pow_vartime([ - 0x1ffffcd2ffffffff, - 0x9ca7e85d60050af4, - 0xe4a775fe8e177fd6, - 0x443f9a5c7a8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - - CtOption::new(tmp, !self.ct_eq(&Self::zero())) - } - - fn sqrt(&self) -> CtOption { - /// `(t - 1) // 2` where t * 2^s + 1 = q with t odd. - const T_MINUS1_OVER2: [u64; 7] = [ - 0xb002857a0ffffe69, - 0x470bbfeb4e53f42e, - 0x3d45363df253baff, - 0x7a1c9337a21fcd2e, - 0x06bfb8725401e53b, - 0x0000120000987000, - 0x0000000012000000, - ]; - ff::helpers::sqrt_tonelli_shanks(self, T_MINUS1_OVER2) - } - - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - ff::helpers::sqrt_ratio_generic(num, div) - } -} - -#[derive(Clone, Copy, Debug)] -/// Canonical little-endian representation of a `Fq` element. -pub struct FqRepr { - pub repr: [u8; SIZE], -} - -impl FqRepr { - /// Returns an iterator over the bytes of the canonical representation of the element. - pub fn iter(&self) -> Iter<'_, u8> { - self.repr.iter() - } -} - -impl Default for FqRepr { - fn default() -> Self { - FqRepr { repr: [0u8; SIZE] } - } -} - -impl AsRef<[u8]> for FqRepr { - fn as_ref(&self) -> &[u8] { - self.repr.as_ref() - } -} - -impl AsMut<[u8]> for FqRepr { - fn as_mut(&mut self) -> &mut [u8] { - self.repr.as_mut() - } -} -impl From<[u8; SIZE]> for FqRepr { - fn from(repr: [u8; SIZE]) -> Self { - Self { repr } - } -} - -impl ff::PrimeField for Fq { - type Repr = FqRepr; - - const NUM_BITS: u32 = 446; - const CAPACITY: u32 = 445; - const MODULUS: &'static str = MODULUS_STR; - const MULTIPLICATIVE_GENERATOR: Self = GENERATOR; - const ROOT_OF_UNITY: Self = ROOT_OF_UNITY; - const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV; - const TWO_INV: Self = TWO_INV; - const DELTA: Self = DELTA; - const S: u32 = S; - - fn from_repr(repr: Self::Repr) -> CtOption { - let mut tmp = Self([0, 0, 0, 0, 0, 0, 0]); - let repr = repr.repr; - - tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); - tmp.0[4] = u64::from_le_bytes(repr[32..40].try_into().unwrap()); - tmp.0[5] = u64::from_le_bytes(repr[40..48].try_into().unwrap()); - tmp.0[6] = u64::from_le_bytes(repr[48..56].try_into().unwrap()); - - // Try to subtract the modulus - let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0); - let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); - let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); - let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); - let (_, borrow) = sbb(tmp.0[4], MODULUS.0[4], borrow); - let (_, borrow) = sbb(tmp.0[5], MODULUS.0[5], borrow); - let (_, borrow) = sbb(tmp.0[6], MODULUS.0[6], borrow); - - // If the element is smaller than MODULUS then the - // subtraction will underflow, producing a borrow value - // of 0xffff...ffff. Otherwise, it'll be zero. - let is_some = (borrow as u8) & 1; - - // Convert to Montgomery form by computing - // (a.R^0 * R^2) / R = a.R - tmp *= &R2; - - CtOption::new(tmp, Choice::from(is_some)) - } - - fn to_repr(&self) -> Self::Repr { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Self::montgomery_reduce(&[ - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], 0, 0, 0, - 0, 0, 0, 0, - ]); - - let mut res = [0; SIZE]; - res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); - res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); - res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); - res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); - res[32..40].copy_from_slice(&tmp.0[4].to_le_bytes()); - res[40..48].copy_from_slice(&tmp.0[5].to_le_bytes()); - res[48..56].copy_from_slice(&tmp.0[6].to_le_bytes()); - res.into() - } - - fn is_odd(&self) -> Choice { - Choice::from(self.to_repr().repr[0] & 1) - } -} - -impl FromUniformBytes<64> for Fq { - /// Converts a 512-bit little endian integer into - /// an `Fq` by reducing by the modulus. - fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { - Self::from_u512([ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - u64::from_le_bytes(bytes[56..64].try_into().unwrap()), - ]) - } -} - -impl WithSmallOrderMulGroup<3> for Fq { - const ZETA: Self = ZETA; -} - -#[cfg(test)] -mod test { - use super::*; - crate::field_testing_suite!(Fq, "field_arithmetic"); - crate::field_testing_suite!(Fq, "conversion"); - crate::field_testing_suite!(Fq, "serialization"); - crate::field_testing_suite!(Fq, "quadratic_residue"); - crate::field_testing_suite!(Fq, "bits"); - crate::field_testing_suite!(Fq, "serialization_check"); - crate::field_testing_suite!(Fq, "constants", MODULUS_STR); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64); -} diff --git a/src/pluto_eris/fields/mod.rs b/src/pluto_eris/fields/mod.rs deleted file mode 100644 index 307f92d3..00000000 --- a/src/pluto_eris/fields/mod.rs +++ /dev/null @@ -1,843 +0,0 @@ -pub mod fp; -pub mod fp12; -pub mod fp2; -pub mod fp6; -pub mod fq; - -#[macro_export] -macro_rules! impl_from_u64_7_limbs { - ($field:ident, $r2:ident) => { - impl From for $field { - fn from(val: u64) -> $field { - $field([val, 0, 0, 0, 0, 0, 0]) * $r2 - } - } - }; -} - -#[macro_export] -macro_rules! field_common_7_limbs { - ( - $field:ident, - $field_repr:ident, - $modulus:ident, - $inv:ident, - $modulus_str:ident, - $two_inv:ident, - $root_of_unity_inv:ident, - $delta:ident, - $zeta:ident, - $r:ident, - $r2:ident, - $r3:ident - ) => { - impl $field { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> $field { - $field([0, 0, 0, 0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> $field { - $r - } - - // Returns the Jacobi symbol, where the numerator and denominator - // are the element and the characteristic of the field, respectively. - // The Jacobi symbol is applicable to odd moduli - // while the Legendre symbol is applicable to prime moduli. - // They are equivalent for prime moduli. - #[inline(always)] - pub fn jacobi(&self) -> i64 { - $crate::ff_ext::jacobi::jacobi::<8>(&self.0, &$modulus.0) - } - - fn from_u512(limbs: [u64; 8]) -> $field { - let d0 = $field([ - limbs[0], limbs[1], limbs[2], limbs[3], limbs[4], limbs[5], limbs[6], - ]); - let d1 = $field([limbs[7], 0, 0, 0, 0, 0, 0]); - - d0 * $r2 + d1 * $r3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) `$field` representation. - pub const fn from_raw(val: [u64; 7]) -> Self { - #[cfg(feature = "asm")] - { - let (r0, carry) = mac(0, val[0], $r2.0[0], 0); - let (r1, carry) = mac(0, val[0], $r2.0[1], carry); - let (r2, carry) = mac(0, val[0], $r2.0[2], carry); - let (r3, carry) = mac(0, val[0], $r2.0[3], carry); - let (r4, carry) = mac(0, val[0], $r2.0[4], carry); - let (r5, carry) = mac(0, val[0], $r2.0[5], carry); - let (r6, r7) = mac(0, val[0], $r2.0[6], carry); - - let (r1, carry) = mac(r1, val[1], $r2.0[0], 0); - let (r2, carry) = mac(r2, val[1], $r2.0[1], carry); - let (r3, carry) = mac(r3, val[1], $r2.0[2], carry); - let (r4, carry) = mac(r4, val[1], $r2.0[3], carry); - let (r5, carry) = mac(r5, val[1], $r2.0[4], carry); - let (r6, carry) = mac(r6, val[1], $r2.0[5], carry); - let (r7, r8) = mac(r7, val[1], $r2.0[6], carry); - - let (r2, carry) = mac(r2, val[2], $r2.0[0], 0); - let (r3, carry) = mac(r3, val[2], $r2.0[1], carry); - let (r4, carry) = mac(r4, val[2], $r2.0[2], carry); - let (r5, carry) = mac(r5, val[2], $r2.0[3], carry); - let (r6, carry) = mac(r6, val[2], $r2.0[4], carry); - let (r7, carry) = mac(r7, val[2], $r2.0[5], carry); - let (r8, r9) = mac(r8, val[2], $r2.0[6], carry); - - let (r3, carry) = mac(r3, val[3], $r2.0[0], 0); - let (r4, carry) = mac(r4, val[3], $r2.0[1], carry); - let (r5, carry) = mac(r5, val[3], $r2.0[2], carry); - let (r6, carry) = mac(r6, val[3], $r2.0[3], carry); - let (r7, carry) = mac(r7, val[3], $r2.0[4], carry); - let (r8, carry) = mac(r8, val[3], $r2.0[5], carry); - let (r9, r10) = mac(r9, val[3], $r2.0[6], carry); - - let (r4, carry) = mac(r4, val[4], $r2.0[0], 0); - let (r5, carry) = mac(r5, val[4], $r2.0[1], carry); - let (r6, carry) = mac(r6, val[4], $r2.0[2], carry); - let (r7, carry) = mac(r7, val[4], $r2.0[3], carry); - let (r8, carry) = mac(r8, val[4], $r2.0[4], carry); - let (r9, carry) = mac(r9, val[4], $r2.0[5], carry); - let (r10, r11) = mac(r10, val[4], $r2.0[6], carry); - - let (r5, carry) = mac(r5, val[5], $r2.0[0], 0); - let (r6, carry) = mac(r6, val[5], $r2.0[1], carry); - let (r7, carry) = mac(r7, val[5], $r2.0[2], carry); - let (r8, carry) = mac(r8, val[5], $r2.0[3], carry); - let (r9, carry) = mac(r9, val[5], $r2.0[4], carry); - let (r10, carry) = mac(r10, val[5], $r2.0[5], carry); - let (r11, r12) = mac(r11, val[5], $r2.0[6], carry); - - let (r6, carry) = mac(r6, val[6], $r2.0[0], 0); - let (r7, carry) = mac(r7, val[6], $r2.0[1], carry); - let (r8, carry) = mac(r8, val[6], $r2.0[2], carry); - let (r9, carry) = mac(r9, val[6], $r2.0[3], carry); - let (r10, carry) = mac(r10, val[6], $r2.0[4], carry); - let (r11, carry) = mac(r11, val[6], $r2.0[5], carry); - let (r12, r13) = mac(r12, val[6], $r2.0[6], carry); - - // Montgomery reduction - let k = r0.wrapping_mul($inv); - let (_, carry) = mac(r0, k, $modulus.0[0], 0); - let (r1, carry) = mac(r1, k, $modulus.0[1], carry); - let (r2, carry) = mac(r2, k, $modulus.0[2], carry); - let (r3, carry) = mac(r3, k, $modulus.0[3], carry); - let (r4, carry) = mac(r4, k, $modulus.0[4], carry); - let (r5, carry) = mac(r5, k, $modulus.0[5], carry); - let (r6, carry) = mac(r6, k, $modulus.0[6], carry); - let (r7, carry2) = adc(r7, 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r8, carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r9, carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r10, carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r11, carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r12, carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, carry2) = adc(r13, carry2, carry); - - // Result may be within MODULUS of the correct value - let (d0, borrow) = sbb(r7, $modulus.0[0], 0); - let (d1, borrow) = sbb(r8, $modulus.0[1], borrow); - let (d2, borrow) = sbb(r9, $modulus.0[2], borrow); - let (d3, borrow) = sbb(r10, $modulus.0[3], borrow); - let (d4, borrow) = sbb(r11, $modulus.0[4], borrow); - let (d5, borrow) = sbb(r12, $modulus.0[5], borrow); - let (d6, borrow) = sbb(r13, $modulus.0[6], borrow); - let (_, borrow) = sbb(carry2, 0, borrow); - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - #[cfg(not(feature = "asm"))] - { - (&$field(val)).mul(&$r2) - } - } - - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fr`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 56]) -> CtOption<$field> { - ::from_repr($field_repr { repr: *bytes }) - } - - /// Converts an element of `Fr` into a byte representation in - /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 56] { - ::to_repr(self).repr - } - - /// Lexicographic comparison of Montgomery forms. - #[inline(always)] - const fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool { - let (_, borrow) = sbb(x[0], y[0], 0); - let (_, borrow) = sbb(x[1], y[1], borrow); - let (_, borrow) = sbb(x[2], y[2], borrow); - let (_, borrow) = sbb(x[3], y[3], borrow); - let (_, borrow) = sbb(x[4], y[4], borrow); - let (_, borrow) = sbb(x[5], y[5], borrow); - let (_, borrow) = sbb(x[6], y[6], borrow); - borrow >> 63 == 1 - } - } - - impl fmt::Debug for $field { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_repr(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } - } - - impl Default for $field { - #[inline] - fn default() -> Self { - Self::zero() - } - } - - impl From for $field { - fn from(bit: bool) -> $field { - if bit { - $field::one() - } else { - $field::zero() - } - } - } - - impl ConstantTimeEq for $field { - fn ct_eq(&self, other: &Self) -> Choice { - self.0[0].ct_eq(&other.0[0]) - & self.0[1].ct_eq(&other.0[1]) - & self.0[2].ct_eq(&other.0[2]) - & self.0[3].ct_eq(&other.0[3]) - & self.0[4].ct_eq(&other.0[4]) - & self.0[5].ct_eq(&other.0[5]) - & self.0[6].ct_eq(&other.0[6]) - } - } - - impl core::cmp::Ord for $field { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let left = self.to_repr(); - let right = other.to_repr(); - left.iter() - .zip(right.iter()) - .rev() - .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { - core::cmp::Ordering::Equal => None, - res => Some(res), - }) - .unwrap_or(core::cmp::Ordering::Equal) - } - } - - impl core::cmp::PartialOrd for $field { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - impl ConditionallySelectable for $field { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - $field([ - u64::conditional_select(&a.0[0], &b.0[0], choice), - u64::conditional_select(&a.0[1], &b.0[1], choice), - u64::conditional_select(&a.0[2], &b.0[2], choice), - u64::conditional_select(&a.0[3], &b.0[3], choice), - u64::conditional_select(&a.0[4], &b.0[4], choice), - u64::conditional_select(&a.0[5], &b.0[5], choice), - u64::conditional_select(&a.0[6], &b.0[6], choice), - ]) - } - } - - impl<'a> Neg for &'a $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - self.neg() - } - } - - impl Neg for $field { - type Output = $field; - - #[inline] - fn neg(self) -> $field { - -&self - } - } - - impl<'a, 'b> Sub<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn sub(self, rhs: &'b $field) -> $field { - self.sub(rhs) - } - } - - impl<'a, 'b> Add<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn add(self, rhs: &'b $field) -> $field { - self.add(rhs) - } - } - - impl<'a, 'b> Mul<&'b $field> for &'a $field { - type Output = $field; - - #[inline] - fn mul(self, rhs: &'b $field) -> $field { - self.mul(rhs) - } - } - - impl From<$field> for [u8; 56] { - fn from(value: $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl<'a> From<&'a $field> for [u8; 56] { - fn from(value: &'a $field) -> [u8; 56] { - value.to_repr().repr - } - } - - impl $crate::serde::SerdeObject for $field { - fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { - debug_assert_eq!(bytes.len(), 56); - let inner = [0, 8, 16, 24, 32, 40, 48] - .map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); - Self(inner) - } - fn from_raw_bytes(bytes: &[u8]) -> Option { - if bytes.len() != 56 { - return None; - } - let elt = Self::from_raw_bytes_unchecked(bytes); - Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) - } - fn to_raw_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(56); - for limb in self.0.iter() { - res.extend_from_slice(&limb.to_le_bytes()); - } - res - } - fn read_raw_unchecked(reader: &mut R) -> Self { - let inner = [(); 7].map(|_| { - let mut buf = [0; 8]; - reader.read_exact(&mut buf).unwrap(); - u64::from_le_bytes(buf) - }); - Self(inner) - } - fn read_raw(reader: &mut R) -> std::io::Result { - let mut inner = [0u64; 7]; - for limb in inner.iter_mut() { - let mut buf = [0; 8]; - reader.read_exact(&mut buf)?; - *limb = u64::from_le_bytes(buf); - } - let elt = Self(inner); - Self::is_less_than(&elt.0, &$modulus.0) - .then(|| elt) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - "input number is not less than field modulus", - ) - }) - } - fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { - for limb in self.0.iter() { - writer.write_all(&limb.to_le_bytes())?; - } - Ok(()) - } - } - }; -} - -#[macro_export] -macro_rules! field_arithmetic_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { - $crate::field_specific_7_limbs!($field, $modulus, $inv, $field_type); - impl $field { - /// Doubles this field element. - #[inline] - pub const fn double(&self) -> $field { - self.add(self) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> $field { - let (r1, carry) = mac(0, self.0[0], self.0[1], 0); - let (r2, carry) = mac(0, self.0[0], self.0[2], carry); - let (r3, carry) = mac(0, self.0[0], self.0[3], carry); - let (r4, carry) = mac(0, self.0[0], self.0[4], carry); - let (r5, carry) = mac(0, self.0[0], self.0[5], carry); - let (r6, r7) = mac(0, self.0[0], self.0[6], carry); - - let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); - let (r4, carry) = mac(r4, self.0[1], self.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], self.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], self.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], self.0[6], carry); - - let (r5, carry) = mac(r5, self.0[2], self.0[3], 0); - let (r6, carry) = mac(r6, self.0[2], self.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], self.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], self.0[6], carry); - - let (r7, carry) = mac(r7, self.0[3], self.0[4], 0); - let (r8, carry) = mac(r8, self.0[3], self.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], self.0[6], carry); - - let (r9, carry) = mac(r9, self.0[4], self.0[5], 0); - let (r10, r11) = mac(r10, self.0[4], self.0[6], carry); - - let (r11, r12) = mac(r11, self.0[5], self.0[6], 0); - - let r13 = r12 >> 63; - let r12 = (r12 << 1) | (r11 >> 63); - let r11 = (r11 << 1) | (r10 >> 63); - let r10 = (r10 << 1) | (r9 >> 63); - let r9 = (r9 << 1) | (r8 >> 63); - let r8 = (r8 << 1) | (r7 >> 63); - let r7 = (r7 << 1) | (r6 >> 63); - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let (r0, carry) = mac(0, self.0[0], self.0[0], 0); - let (r1, carry) = adc(0, r1, carry); - let (r2, carry) = mac(r2, self.0[1], self.0[1], carry); - let (r3, carry) = adc(0, r3, carry); - let (r4, carry) = mac(r4, self.0[2], self.0[2], carry); - let (r5, carry) = adc(0, r5, carry); - let (r6, carry) = mac(r6, self.0[3], self.0[3], carry); - let (r7, carry) = adc(0, r7, carry); - let (r8, carry) = mac(r8, self.0[4], self.0[4], carry); - let (r9, carry) = adc(0, r9, carry); - let (r10, carry) = mac(r10, self.0[5], self.0[5], carry); - let (r11, carry) = adc(0, r11, carry); - let (r12, carry) = mac(r12, self.0[6], self.0[6], carry); - let (r13, _) = adc(0, r13, carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// Multiplies `rhs` by `self`, returning the result. - #[inline] - pub const fn mul(&self, rhs: &Self) -> $field { - // Schoolbook multiplication - let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); - let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); - let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); - let (r3, carry) = mac(0, self.0[0], rhs.0[3], carry); - let (r4, carry) = mac(0, self.0[0], rhs.0[4], carry); - let (r5, carry) = mac(0, self.0[0], rhs.0[5], carry); - let (r6, r7) = mac(0, self.0[0], rhs.0[6], carry); - - let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); - let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); - let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); - let (r4, carry) = mac(r4, self.0[1], rhs.0[3], carry); - let (r5, carry) = mac(r5, self.0[1], rhs.0[4], carry); - let (r6, carry) = mac(r6, self.0[1], rhs.0[5], carry); - let (r7, r8) = mac(r7, self.0[1], rhs.0[6], carry); - - let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); - let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); - let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); - let (r5, carry) = mac(r5, self.0[2], rhs.0[3], carry); - let (r6, carry) = mac(r6, self.0[2], rhs.0[4], carry); - let (r7, carry) = mac(r7, self.0[2], rhs.0[5], carry); - let (r8, r9) = mac(r8, self.0[2], rhs.0[6], carry); - - let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); - let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); - let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); - let (r6, carry) = mac(r6, self.0[3], rhs.0[3], carry); - let (r7, carry) = mac(r7, self.0[3], rhs.0[4], carry); - let (r8, carry) = mac(r8, self.0[3], rhs.0[5], carry); - let (r9, r10) = mac(r9, self.0[3], rhs.0[6], carry); - - let (r4, carry) = mac(r4, self.0[4], rhs.0[0], 0); - let (r5, carry) = mac(r5, self.0[4], rhs.0[1], carry); - let (r6, carry) = mac(r6, self.0[4], rhs.0[2], carry); - let (r7, carry) = mac(r7, self.0[4], rhs.0[3], carry); - let (r8, carry) = mac(r8, self.0[4], rhs.0[4], carry); - let (r9, carry) = mac(r9, self.0[4], rhs.0[5], carry); - let (r10, r11) = mac(r10, self.0[4], rhs.0[6], carry); - - let (r5, carry) = mac(r5, self.0[5], rhs.0[0], 0); - let (r6, carry) = mac(r6, self.0[5], rhs.0[1], carry); - let (r7, carry) = mac(r7, self.0[5], rhs.0[2], carry); - let (r8, carry) = mac(r8, self.0[5], rhs.0[3], carry); - let (r9, carry) = mac(r9, self.0[5], rhs.0[4], carry); - let (r10, carry) = mac(r10, self.0[5], rhs.0[5], carry); - let (r11, r12) = mac(r11, self.0[5], rhs.0[6], carry); - - let (r6, carry) = mac(r6, self.0[6], rhs.0[0], 0); - let (r7, carry) = mac(r7, self.0[6], rhs.0[1], carry); - let (r8, carry) = mac(r8, self.0[6], rhs.0[2], carry); - let (r9, carry) = mac(r9, self.0[6], rhs.0[3], carry); - let (r10, carry) = mac(r10, self.0[6], rhs.0[4], carry); - let (r11, carry) = mac(r11, self.0[6], rhs.0[5], carry); - let (r12, r13) = mac(r12, self.0[6], rhs.0[6], carry); - - $field::montgomery_reduce(&[ - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, - ]) - } - - /// Subtracts `rhs` from `self`, returning the result. - #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - let (d4, borrow) = sbb(self.0[4], rhs.0[4], borrow); - let (d5, borrow) = sbb(self.0[5], rhs.0[5], borrow); - let (d6, borrow) = sbb(self.0[6], rhs.0[6], borrow); - - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - - /// Negates `self`. - #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb($modulus.0[0], self.0[0], 0); - let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow); - let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow); - let (d3, borrow) = sbb($modulus.0[3], self.0[3], borrow); - let (d4, borrow) = sbb($modulus.0[4], self.0[4], borrow); - let (d5, borrow) = sbb($modulus.0[5], self.0[5], borrow); - let (d6, _) = sbb($modulus.0[6], self.0[6], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = (((self.0[0] - | self.0[1] - | self.0[2] - | self.0[3] - | self.0[4] - | self.0[5] - | self.0[6]) - == 0) as u64) - .wrapping_sub(1); - - $field([ - d0 & mask, - d1 & mask, - d2 & mask, - d3 & mask, - d4 & mask, - d5 & mask, - d6 & mask, - ]) - } - } - }; -} - -#[macro_export] -macro_rules! field_specific_7_limbs { - ($field:ident, $modulus:ident, $inv:ident, sparse) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, _) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - (&$field([d0, d1, d2, d3, d4, d5, d6])).sub(&$modulus) - } - - #[inline(always)] - pub(crate) const fn montgomery_reduce(r: &[u64; 14]) -> $field { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r[0].wrapping_mul($inv); - let (_, carry) = mac(r[0], k, $modulus.0[0], 0); - let (r1, carry) = mac(r[1], k, $modulus.0[1], carry); - let (r2, carry) = mac(r[2], k, $modulus.0[2], carry); - let (r3, carry) = mac(r[3], k, $modulus.0[3], carry); - let (r4, carry) = mac(r[4], k, $modulus.0[4], carry); - let (r5, carry) = mac(r[5], k, $modulus.0[5], carry); - let (r6, carry) = mac(r[6], k, $modulus.0[6], carry); - let (r7, carry2) = adc(r[7], 0, carry); - - let k = r1.wrapping_mul($inv); - let (_, carry) = mac(r1, k, $modulus.0[0], 0); - let (r2, carry) = mac(r2, k, $modulus.0[1], carry); - let (r3, carry) = mac(r3, k, $modulus.0[2], carry); - let (r4, carry) = mac(r4, k, $modulus.0[3], carry); - let (r5, carry) = mac(r5, k, $modulus.0[4], carry); - let (r6, carry) = mac(r6, k, $modulus.0[5], carry); - let (r7, carry) = mac(r7, k, $modulus.0[6], carry); - let (r8, carry2) = adc(r[8], carry2, carry); - - let k = r2.wrapping_mul($inv); - let (_, carry) = mac(r2, k, $modulus.0[0], 0); - let (r3, carry) = mac(r3, k, $modulus.0[1], carry); - let (r4, carry) = mac(r4, k, $modulus.0[2], carry); - let (r5, carry) = mac(r5, k, $modulus.0[3], carry); - let (r6, carry) = mac(r6, k, $modulus.0[4], carry); - let (r7, carry) = mac(r7, k, $modulus.0[5], carry); - let (r8, carry) = mac(r8, k, $modulus.0[6], carry); - let (r9, carry2) = adc(r[9], carry2, carry); - - let k = r3.wrapping_mul($inv); - let (_, carry) = mac(r3, k, $modulus.0[0], 0); - let (r4, carry) = mac(r4, k, $modulus.0[1], carry); - let (r5, carry) = mac(r5, k, $modulus.0[2], carry); - let (r6, carry) = mac(r6, k, $modulus.0[3], carry); - let (r7, carry) = mac(r7, k, $modulus.0[4], carry); - let (r8, carry) = mac(r8, k, $modulus.0[5], carry); - let (r9, carry) = mac(r9, k, $modulus.0[6], carry); - let (r10, carry2) = adc(r[10], carry2, carry); - - let k = r4.wrapping_mul($inv); - let (_, carry) = mac(r4, k, $modulus.0[0], 0); - let (r5, carry) = mac(r5, k, $modulus.0[1], carry); - let (r6, carry) = mac(r6, k, $modulus.0[2], carry); - let (r7, carry) = mac(r7, k, $modulus.0[3], carry); - let (r8, carry) = mac(r8, k, $modulus.0[4], carry); - let (r9, carry) = mac(r9, k, $modulus.0[5], carry); - let (r10, carry) = mac(r10, k, $modulus.0[6], carry); - let (r11, carry2) = adc(r[11], carry2, carry); - - let k = r5.wrapping_mul($inv); - let (_, carry) = mac(r5, k, $modulus.0[0], 0); - let (r6, carry) = mac(r6, k, $modulus.0[1], carry); - let (r7, carry) = mac(r7, k, $modulus.0[2], carry); - let (r8, carry) = mac(r8, k, $modulus.0[3], carry); - let (r9, carry) = mac(r9, k, $modulus.0[4], carry); - let (r10, carry) = mac(r10, k, $modulus.0[5], carry); - let (r11, carry) = mac(r11, k, $modulus.0[6], carry); - let (r12, carry2) = adc(r[12], carry2, carry); - - let k = r6.wrapping_mul($inv); - let (_, carry) = mac(r6, k, $modulus.0[0], 0); - let (r7, carry) = mac(r7, k, $modulus.0[1], carry); - let (r8, carry) = mac(r8, k, $modulus.0[2], carry); - let (r9, carry) = mac(r9, k, $modulus.0[3], carry); - let (r10, carry) = mac(r10, k, $modulus.0[4], carry); - let (r11, carry) = mac(r11, k, $modulus.0[5], carry); - let (r12, carry) = mac(r12, k, $modulus.0[6], carry); - let (r13, _) = adc(r[13], carry2, carry); - // Result may be within MODULUS of the correct value - (&$field([r7, r8, r9, r10, r11, r12, r13])).sub(&$modulus) - } - } - }; - ($field:ident, $modulus:ident, $inv:ident, dense) => { - impl $field { - /// Adds `rhs` to `self`, returning the result. - #[inline] - pub const fn add(&self, rhs: &Self) -> Self { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, carry) = adc(self.0[3], rhs.0[3], carry); - let (d4, carry) = adc(self.0[4], rhs.0[4], carry); - let (d5, carry) = adc(self.0[5], rhs.0[5], carry); - let (d6, carry) = adc(self.0[6], rhs.0[6], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - let (d0, borrow) = sbb(d0, $modulus.0[0], 0); - let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); - let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); - let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); - let (d4, borrow) = sbb(d4, $modulus.0[4], borrow); - let (d5, borrow) = sbb(d5, $modulus.0[5], borrow); - let (_, borrow) = sbb(carry, 0, borrow); - - let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); - let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); - let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); - let (d3, carry) = adc(d3, $modulus.0[3] & borrow, carry); - let (d4, carry) = adc(d4, $modulus.0[4] & borrow, carry); - let (d5, carry) = adc(d5, $modulus.0[5] & borrow, carry); - let (d6, _) = adc(d6, $modulus.0[6] & borrow, carry); - - $field([d0, d1, d2, d3, d4, d5, d6]) - } - } - }; -} - -#[macro_export] -macro_rules! field_bits_7_limbs { - // For #[cfg(target_pointer_width = "64")] - ($field:ident, $modulus:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u64; 7]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - let limbs = [ - u64::from_le_bytes(bytes[0..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..16].try_into().unwrap()), - u64::from_le_bytes(bytes[16..24].try_into().unwrap()), - u64::from_le_bytes(bytes[24..32].try_into().unwrap()), - u64::from_le_bytes(bytes[32..40].try_into().unwrap()), - u64::from_le_bytes(bytes[40..48].try_into().unwrap()), - u64::from_le_bytes(bytes[48..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus.0) - } - } - }; - // For #[cfg(not(target_pointer_width = "64"))] - ($field:ident, $modulus:ident, $modulus_limbs_32:ident) => { - #[cfg(feature = "bits")] - #[cfg_attr(docsrs, doc(cfg(feature = "bits")))] - impl ::ff::PrimeFieldBits for $field { - type ReprBits = [u32; 14]; - - fn to_le_bits(&self) -> ::ff::FieldBits { - let bytes = self.to_repr().repr; - - let limbs = [ - u32::from_le_bytes(bytes[0..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..16].try_into().unwrap()), - u32::from_le_bytes(bytes[16..20].try_into().unwrap()), - u32::from_le_bytes(bytes[20..24].try_into().unwrap()), - u32::from_le_bytes(bytes[24..28].try_into().unwrap()), - u32::from_le_bytes(bytes[28..32].try_into().unwrap()), - u32::from_le_bytes(bytes[32..36].try_into().unwrap()), - u32::from_le_bytes(bytes[36..40].try_into().unwrap()), - u32::from_le_bytes(bytes[40..44].try_into().unwrap()), - u32::from_le_bytes(bytes[44..48].try_into().unwrap()), - u32::from_le_bytes(bytes[48..52].try_into().unwrap()), - u32::from_le_bytes(bytes[52..56].try_into().unwrap()), - ]; - - ::ff::FieldBits::new(limbs) - } - - fn char_le_bits() -> ::ff::FieldBits { - ::ff::FieldBits::new($modulus_limbs_32) - } - } - }; -}