use core::fmt; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use byteorder::{ByteOrder, LittleEndian}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use crate::util::{adc, mac, sbb}; /// Represents an element of `GF(r)`. // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. Elements of Fr are always in // Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. #[derive(Clone, Copy, Eq)] pub struct Fr(pub(crate) [u64; 4]); impl fmt::Debug for Fr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let tmp = self.into_bytes(); write!(f, "0x")?; for &b in tmp.iter().rev() { write!(f, "{:02x}", b)?; } Ok(()) } } impl From for Fr { fn from(val: u64) -> Fr { Fr([val, 0, 0, 0]) * R2 } } impl ConstantTimeEq for Fr { 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]) } } impl PartialEq for Fr { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).unwrap_u8() == 1 } } impl ConditionallySelectable for Fr { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Fr([ 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), ]) } } // Constant representing the modulus // r = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7 const MODULUS: Fr = Fr([ 0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x06673b0101343b00, 0x0e7db4ea6533afa9, ]); impl<'a> Neg for &'a Fr { type Output = Fr; #[inline] fn neg(self) -> Fr { // 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, _) = sbb(MODULUS.0[3], self.0[3], 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 = u64::from((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0).wrapping_sub(1); Fr([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) } } impl Neg for Fr { type Output = Fr; #[inline] fn neg(self) -> Fr { -&self } } impl<'a, 'b> Sub<&'b Fr> for &'a Fr { type Output = Fr; #[inline] fn sub(self, rhs: &'b Fr) -> Fr { 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); // 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, _) = adc(d3, MODULUS.0[3] & borrow, carry); Fr([d0, d1, d2, d3]) } } impl<'a, 'b> Add<&'b Fr> for &'a Fr { type Output = Fr; #[inline] fn add(self, rhs: &'b Fr) -> Fr { 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, _) = adc(self.0[3], rhs.0[3], carry); // Attempt to subtract the modulus, to ensure the value // is smaller than the modulus. Fr([d0, d1, d2, d3]) - &MODULUS } } impl<'a, 'b> Mul<&'b Fr> for &'a Fr { type Output = Fr; #[inline] fn mul(self, rhs: &'b Fr) -> Fr { // 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, r4) = mac(0, self.0[0], rhs.0[3], 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, r5) = mac(r4, self.0[1], rhs.0[3], 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, r6) = mac(r5, self.0[2], rhs.0[3], 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, r7) = mac(r6, self.0[3], rhs.0[3], carry); Fr::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) } } impl_binops_additive!(Fr, Fr); impl_binops_multiplicative!(Fr, Fr); /// INV = -(r^{-1} mod 2^64) mod 2^64 const INV: u64 = 0x1ba3a358ef788ef9; /// R = 2^256 mod r const R: Fr = Fr([ 0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, 0x09a6fc6f479155c6, ]); /// R^2 = 2^512 mod r const R2: Fr = Fr([ 0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, 0x04f6547b8d127688, ]); impl Default for Fr { fn default() -> Self { Self::zero() } } impl Fr { pub fn zero() -> Fr { Fr([0, 0, 0, 0]) } pub fn one() -> Fr { R } #[inline] pub fn double(&self) -> Fr { self + self } /// Attempts to convert a little-endian byte representation of /// a field element into an element of `Fr`, failing if the input /// is not canonical (is not smaller than r). /// /// **This operation is variable time.** pub fn from_bytes_vartime(bytes: [u8; 32]) -> Option { let mut tmp = Fr([0, 0, 0, 0]); tmp.0[0] = LittleEndian::read_u64(&bytes[0..8]); tmp.0[1] = LittleEndian::read_u64(&bytes[8..16]); tmp.0[2] = LittleEndian::read_u64(&bytes[16..24]); tmp.0[3] = LittleEndian::read_u64(&bytes[24..32]); // Check if the value is in the field for i in (0..4).rev() { if tmp.0[i] < MODULUS.0[i] { // Convert to Montgomery form by computing // (a.R^{-1} * R^2) / R = a.R tmp.mul_assign(&R2); return Some(tmp); } if tmp.0[i] > MODULUS.0[i] { return None; } } // Value is equal to the modulus None } /// Converts an element of `Fr` into a byte representation in /// little-endian byte order. pub fn into_bytes(&self) -> [u8; 32] { // Turn into canonical form by computing // (a.R) / R = a let tmp = Fr::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); let mut res = [0; 32]; LittleEndian::write_u64(&mut res[0..8], tmp.0[0]); LittleEndian::write_u64(&mut res[8..16], tmp.0[1]); LittleEndian::write_u64(&mut res[16..24], tmp.0[2]); LittleEndian::write_u64(&mut res[24..32], tmp.0[3]); res } /// Squares this element. pub fn square(&self) -> Fr { 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, r4) = mac(0, self.0[0], self.0[3], carry); let (r3, carry) = mac(r3, self.0[1], self.0[2], 0); let (r4, r5) = mac(r4, self.0[1], self.0[3], carry); let (r5, r6) = mac(r5, self.0[2], self.0[3], 0); let r7 = 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, _) = adc(0, r7, carry); Fr::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) } /// Computes the square root of this element, if it exists. /// /// **This operation is variable time.** pub fn sqrt_vartime(&self) -> Option { // Because r = 3 (mod 4) // sqrt can be done with only one exponentiation, // via the computation of self^((r + 1) // 4) (mod r) // a1 = self^((r - 3) // 4) let a1 = self.pow_vartime(&[ 0xb425c397b5bdcb2d, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x039f6d3a994cebea, ]); let a0 = a1 * (a1 * self); if a0 == -Self::one() { None } else { Some(a1 * self) } } /// Exponentiates `self` by `by`, where `by` is a /// little-endian order integer exponent. pub fn pow(&self, by: &[u64; 4]) -> Self { let mut res = Self::one(); for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); let mut tmp = res; tmp.mul_assign(self); res.conditional_assign(&tmp, (((*e >> i) & 0x1) as u8).into()); } } res } /// Exponentiates `self` by `by`, where `by` is a /// little-endian order integer exponent. /// /// **This operation is variable time with respect /// to the exponent.** If the exponent is fixed, /// this operation is effectively constant time. pub fn pow_vartime(&self, by: &[u64; 4]) -> Self { let mut res = Self::one(); for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); if ((*e >> i) & 1) == 1 { res.mul_assign(self); } } } res } /// Exponentiates `self` by r - 2, which has the /// effect of inverting the element if it is /// nonzero. pub fn invert_nonzero(&self) -> Self { #[inline(always)] fn square_assign_multi(n: &mut Fr, num_times: usize) { for _ in 0..num_times { *n = n.square(); } } // found using https://github.com/kwantam/addchain let t10 = *self; let t1 = t10.square(); let t0 = t1.square(); let t3 = t0 * &t1; let t6 = t3 * &t10; let t7 = t6 * &t1; let t12 = t7 * &t3; let t13 = t12 * &t0; let t16 = t12 * &t3; let t2 = t13 * &t3; let t15 = t16 * &t3; let t19 = t2 * &t0; let t9 = t15 * &t3; let t18 = t9 * &t3; let t14 = t18 * &t1; let t4 = t18 * &t0; let t8 = t18 * &t3; let t17 = t14 * &t3; let t11 = t8 * &t3; let t1 = t17 * &t3; let t5 = t11 * &t3; let t3 = t5 * &t0; let mut t0 = t5.square(); square_assign_multi(&mut t0, 5); t0.mul_assign(&t3); square_assign_multi(&mut t0, 6); t0.mul_assign(&t8); square_assign_multi(&mut t0, 7); t0.mul_assign(&t19); square_assign_multi(&mut t0, 6); t0.mul_assign(&t13); square_assign_multi(&mut t0, 8); t0.mul_assign(&t14); square_assign_multi(&mut t0, 6); t0.mul_assign(&t18); square_assign_multi(&mut t0, 7); t0.mul_assign(&t17); square_assign_multi(&mut t0, 5); t0.mul_assign(&t16); square_assign_multi(&mut t0, 3); t0.mul_assign(&t10); square_assign_multi(&mut t0, 11); t0.mul_assign(&t11); square_assign_multi(&mut t0, 8); t0.mul_assign(&t5); square_assign_multi(&mut t0, 5); t0.mul_assign(&t15); square_assign_multi(&mut t0, 8); t0.mul_assign(&t10); square_assign_multi(&mut t0, 12); t0.mul_assign(&t13); square_assign_multi(&mut t0, 7); t0.mul_assign(&t9); square_assign_multi(&mut t0, 5); t0.mul_assign(&t15); square_assign_multi(&mut t0, 14); t0.mul_assign(&t14); square_assign_multi(&mut t0, 5); t0.mul_assign(&t13); square_assign_multi(&mut t0, 2); t0.mul_assign(&t10); square_assign_multi(&mut t0, 6); t0.mul_assign(&t10); square_assign_multi(&mut t0, 9); t0.mul_assign(&t7); square_assign_multi(&mut t0, 6); t0.mul_assign(&t12); square_assign_multi(&mut t0, 8); t0.mul_assign(&t11); square_assign_multi(&mut t0, 3); t0.mul_assign(&t10); square_assign_multi(&mut t0, 12); t0.mul_assign(&t9); square_assign_multi(&mut t0, 11); t0.mul_assign(&t8); square_assign_multi(&mut t0, 8); t0.mul_assign(&t7); square_assign_multi(&mut t0, 4); t0.mul_assign(&t6); square_assign_multi(&mut t0, 10); t0.mul_assign(&t5); square_assign_multi(&mut t0, 7); t0.mul_assign(&t3); square_assign_multi(&mut t0, 6); t0.mul_assign(&t4); square_assign_multi(&mut t0, 7); t0.mul_assign(&t3); square_assign_multi(&mut t0, 5); t0.mul_assign(&t2); square_assign_multi(&mut t0, 6); t0.mul_assign(&t2); square_assign_multi(&mut t0, 7); t0.mul_assign(&t1); t0 } #[inline] fn montgomery_reduce( r0: u64, r1: u64, r2: u64, r3: u64, r4: u64, r5: u64, r6: u64, r7: u64, ) -> Self { // The Montgomery reduction here is based on Algorithm 14.32 in // Handbook of Applied Cryptography // . 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, carry2) = adc(r4, 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, carry2) = adc(r5, 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, carry2) = adc(r6, 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, _) = adc(r7, carry2, carry); let mut tmp = Fr([r4, r5, r6, r7]); // Result may be within MODULUS of the correct value tmp.sub_assign(&MODULUS); tmp } } impl<'a> From<&'a Fr> for [u8; 32] { fn from(value: &'a Fr) -> [u8; 32] { value.into_bytes() } } #[test] fn test_inv() { // Compute -(r^{-1} mod 2^64) mod 2^64 by exponentiating // by totient(2**64) - 1 let mut inv = 1u64; for _ in 0..63 { inv = inv.wrapping_mul(inv); inv = inv.wrapping_mul(MODULUS.0[0]); } inv = inv.wrapping_neg(); assert_eq!(inv, INV); } #[cfg(feature = "std")] #[test] fn test_debug() { assert_eq!( format!("{:?}", Fr::zero()), "0x0000000000000000000000000000000000000000000000000000000000000000" ); assert_eq!( format!("{:?}", Fr::one()), "0x0000000000000000000000000000000000000000000000000000000000000001" ); assert_eq!( format!("{:?}", R2), "0x09a6fc6f479155c6932514eeeb8814f4f315d62f66b6e75025f80bb3b99607d9" ); } #[test] fn test_equality() { assert_eq!(Fr::zero(), Fr::zero()); assert_eq!(Fr::one(), Fr::one()); assert_eq!(R2, R2); assert!(Fr::zero() != Fr::one()); assert!(Fr::one() != R2); } #[test] fn test_into_bytes() { assert_eq!( Fr::zero().into_bytes(), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ); assert_eq!( Fr::one().into_bytes(), [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ); assert_eq!( R2.into_bytes(), [ 217, 7, 150, 185, 179, 11, 248, 37, 80, 231, 182, 102, 47, 214, 21, 243, 244, 20, 136, 235, 238, 20, 37, 147, 198, 85, 145, 71, 111, 252, 166, 9 ] ); assert_eq!( (-&Fr::one()).into_bytes(), [ 182, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14 ] ); } #[test] fn test_from_bytes_vartime() { assert_eq!( Fr::from_bytes_vartime([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]).unwrap(), Fr::zero() ); assert_eq!( Fr::from_bytes_vartime([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]).unwrap(), Fr::one() ); assert_eq!( Fr::from_bytes_vartime([ 217, 7, 150, 185, 179, 11, 248, 37, 80, 231, 182, 102, 47, 214, 21, 243, 244, 20, 136, 235, 238, 20, 37, 147, 198, 85, 145, 71, 111, 252, 166, 9 ]).unwrap(), R2 ); // -1 should work assert!( Fr::from_bytes_vartime([ 182, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14 ]).is_some() ); // modulus is invalid assert!( Fr::from_bytes_vartime([ 183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14 ]).is_none() ); // Anything larger than the modulus is invalid assert!( Fr::from_bytes_vartime([ 184, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14 ]).is_none() ); assert!( Fr::from_bytes_vartime([ 183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 104, 6, 169, 175, 51, 101, 234, 180, 125, 14 ]).is_none() ); assert!( Fr::from_bytes_vartime([ 183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 15 ]).is_none() ); } #[cfg(test)] const LARGEST: Fr = Fr([ 0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x06673b0101343b00, 0x0e7db4ea6533afa9, ]); #[test] fn test_addition() { let mut tmp = LARGEST; tmp += &LARGEST; assert_eq!( tmp, Fr([ 0xd0970e5ed6f72cb5, 0xa6682093ccc81082, 0x06673b0101343b00, 0x0e7db4ea6533afa9 ]) ); let mut tmp = LARGEST; tmp += &Fr([1, 0, 0, 0]); assert_eq!(tmp, Fr::zero()); } #[test] fn test_negation() { let tmp = -&LARGEST; assert_eq!(tmp, Fr([1, 0, 0, 0])); let tmp = -&Fr::zero(); assert_eq!(tmp, Fr::zero()); let tmp = -&Fr([1, 0, 0, 0]); assert_eq!(tmp, LARGEST); } #[test] fn test_subtraction() { let mut tmp = LARGEST; tmp -= &LARGEST; assert_eq!(tmp, Fr::zero()); let mut tmp = Fr::zero(); tmp -= &LARGEST; let mut tmp2 = MODULUS; tmp2 -= &LARGEST; assert_eq!(tmp, tmp2); } #[test] fn test_multiplication() { let mut cur = LARGEST; for _ in 0..100 { let mut tmp = cur; tmp *= &cur; let mut tmp2 = Fr::zero(); for b in cur .into_bytes() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) { let tmp3 = tmp2; tmp2.add_assign(&tmp3); if b { tmp2.add_assign(&cur); } } assert_eq!(tmp, tmp2); cur.add_assign(&LARGEST); } } #[test] fn test_squaring() { let mut cur = LARGEST; for _ in 0..100 { let mut tmp = cur; tmp = tmp.square(); let mut tmp2 = Fr::zero(); for b in cur .into_bytes() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) { let tmp3 = tmp2; tmp2.add_assign(&tmp3); if b { tmp2.add_assign(&cur); } } assert_eq!(tmp, tmp2); cur.add_assign(&LARGEST); } } #[test] fn test_inversion() { assert_eq!(Fr::one().invert_nonzero(), Fr::one()); assert_eq!((-&Fr::one()).invert_nonzero(), -&Fr::one()); let mut tmp = R2; for _ in 0..100 { let mut tmp2 = tmp.invert_nonzero(); tmp2.mul_assign(&tmp); assert_eq!(tmp2, Fr::one()); tmp.add_assign(&R2); } } #[test] fn test_invert_nonzero_is_pow() { let r_minus_2 = [ 0xd0970e5ed6f72cb5, 0xa6682093ccc81082, 0x06673b0101343b00, 0x0e7db4ea6533afa9, ]; let mut r1 = R; let mut r2 = R; let mut r3 = R; for _ in 0..100 { r1 = r1.invert_nonzero(); r2 = r2.pow_vartime(&r_minus_2); r3 = r3.pow(&r_minus_2); assert_eq!(r1, r2); assert_eq!(r2, r3); // Add R so we check something different next time around r1.add_assign(&R); r2 = r1; r3 = r1; } } #[test] fn test_sqrt() { let mut square = Fr([ // r - 2 0xd0970e5ed6f72cb5, 0xa6682093ccc81082, 0x06673b0101343b00, 0x0e7db4ea6533afa9, ]); let mut none_count = 0; for _ in 0..100 { let square_root = square.sqrt_vartime(); if square_root.is_none() { none_count += 1; } else { assert_eq!(square_root.unwrap() * square_root.unwrap(), square); } square -= Fr::one(); } assert_eq!(47, none_count); }