|
|
@ -1,69 +1,5 @@ |
|
|
|
use super::fq2::Fq2; |
|
|
|
use std::cmp::Ordering; |
|
|
|
use {Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField}; |
|
|
|
|
|
|
|
// q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
|
|
|
|
const MODULUS: FqRepr = FqRepr([ |
|
|
|
0xb9feffffffffaaab, |
|
|
|
0x1eabfffeb153ffff, |
|
|
|
0x6730d2a0f6b0f624, |
|
|
|
0x64774b84f38512bf, |
|
|
|
0x4b1ba7b6434bacd7, |
|
|
|
0x1a0111ea397fe69a, |
|
|
|
]); |
|
|
|
|
|
|
|
// The number of bits needed to represent the modulus.
|
|
|
|
const MODULUS_BITS: u32 = 381; |
|
|
|
|
|
|
|
// The number of bits that must be shaved from the beginning of
|
|
|
|
// the representation when randomly sampling.
|
|
|
|
const REPR_SHAVE_BITS: u32 = 3; |
|
|
|
|
|
|
|
// R = 2**384 % q
|
|
|
|
const R: FqRepr = FqRepr([ |
|
|
|
0x760900000002fffd, |
|
|
|
0xebf4000bc40c0002, |
|
|
|
0x5f48985753c758ba, |
|
|
|
0x77ce585370525745, |
|
|
|
0x5c071a97a256ec6d, |
|
|
|
0x15f65ec3fa80e493, |
|
|
|
]); |
|
|
|
|
|
|
|
// R2 = R^2 % q
|
|
|
|
const R2: FqRepr = FqRepr([ |
|
|
|
0xf4df1f341c341746, |
|
|
|
0xa76e6a609d104f1, |
|
|
|
0x8de5476c4c95b6d5, |
|
|
|
0x67eb88a9939d83c0, |
|
|
|
0x9a793e85b519952d, |
|
|
|
0x11988fe592cae3aa, |
|
|
|
]); |
|
|
|
|
|
|
|
// INV = -(q^{-1} mod 2^64) mod 2^64
|
|
|
|
const INV: u64 = 0x89f3fffcfffcfffd; |
|
|
|
|
|
|
|
// GENERATOR = 2 (multiplicative generator of q-1 order, that is also quadratic nonresidue)
|
|
|
|
const GENERATOR: FqRepr = FqRepr([ |
|
|
|
0x321300000006554f, |
|
|
|
0xb93c0018d6c40005, |
|
|
|
0x57605e0db0ddbb51, |
|
|
|
0x8b256521ed1f9bcb, |
|
|
|
0x6cf28d7901622c03, |
|
|
|
0x11ebab9dbb81e28c, |
|
|
|
]); |
|
|
|
|
|
|
|
// 2^s * t = MODULUS - 1 with t odd
|
|
|
|
const S: u32 = 1; |
|
|
|
|
|
|
|
// 2^s root of unity computed by GENERATOR^t
|
|
|
|
const ROOT_OF_UNITY: FqRepr = FqRepr([ |
|
|
|
0x43f5fffffffcaaae, |
|
|
|
0x32b7fff2ed47fffd, |
|
|
|
0x7e83a49a2e99d69, |
|
|
|
0xeca8f3318332bb7a, |
|
|
|
0xef148d1ea0f4c069, |
|
|
|
0x40ab3263eff0206, |
|
|
|
]); |
|
|
|
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; |
|
|
|
|
|
|
|
// B coefficient of BLS12-381 curve, 4.
|
|
|
|
pub const B_COEFF: Fq = Fq(FqRepr([ |
|
|
@ -507,669 +443,11 @@ pub const NEGATIVE_ONE: Fq = Fq(FqRepr([ |
|
|
|
0x40ab3263eff0206, |
|
|
|
])); |
|
|
|
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] |
|
|
|
pub struct FqRepr(pub [u64; 6]); |
|
|
|
|
|
|
|
impl ::rand::Rand for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self { |
|
|
|
FqRepr(rng.gen()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl ::std::fmt::Display for FqRepr { |
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { |
|
|
|
try!(write!(f, "0x")); |
|
|
|
for i in self.0.iter().rev() { |
|
|
|
try!(write!(f, "{:016x}", *i)); |
|
|
|
} |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl AsRef<[u64]> for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn as_ref(&self) -> &[u64] { |
|
|
|
&self.0 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl AsMut<[u64]> for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn as_mut(&mut self) -> &mut [u64] { |
|
|
|
&mut self.0 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl From<u64> for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn from(val: u64) -> FqRepr { |
|
|
|
let mut repr = Self::default(); |
|
|
|
repr.0[0] = val; |
|
|
|
repr |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Ord for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn cmp(&self, other: &FqRepr) -> Ordering { |
|
|
|
for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { |
|
|
|
if a < b { |
|
|
|
return Ordering::Less; |
|
|
|
} else if a > b { |
|
|
|
return Ordering::Greater; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Ordering::Equal |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl PartialOrd for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn partial_cmp(&self, other: &FqRepr) -> Option<Ordering> { |
|
|
|
Some(self.cmp(other)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl PrimeFieldRepr for FqRepr { |
|
|
|
#[inline(always)] |
|
|
|
fn is_odd(&self) -> bool { |
|
|
|
self.0[0] & 1 == 1 |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn is_even(&self) -> bool { |
|
|
|
!self.is_odd() |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn is_zero(&self) -> bool { |
|
|
|
self.0.iter().all(|&e| e == 0) |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn shr(&mut self, mut n: u32) { |
|
|
|
if n >= 64 * 6 { |
|
|
|
*self = Self::from(0); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
while n >= 64 { |
|
|
|
let mut t = 0; |
|
|
|
for i in self.0.iter_mut().rev() { |
|
|
|
::std::mem::swap(&mut t, i); |
|
|
|
} |
|
|
|
n -= 64; |
|
|
|
} |
|
|
|
|
|
|
|
if n > 0 { |
|
|
|
let mut t = 0; |
|
|
|
for i in self.0.iter_mut().rev() { |
|
|
|
let t2 = *i << (64 - n); |
|
|
|
*i >>= n; |
|
|
|
*i |= t; |
|
|
|
t = t2; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn div2(&mut self) { |
|
|
|
let mut t = 0; |
|
|
|
for i in self.0.iter_mut().rev() { |
|
|
|
let t2 = *i << 63; |
|
|
|
*i >>= 1; |
|
|
|
*i |= t; |
|
|
|
t = t2; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn mul2(&mut self) { |
|
|
|
let mut last = 0; |
|
|
|
for i in &mut self.0 { |
|
|
|
let tmp = *i >> 63; |
|
|
|
*i <<= 1; |
|
|
|
*i |= last; |
|
|
|
last = tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn shl(&mut self, mut n: u32) { |
|
|
|
if n >= 64 * 6 { |
|
|
|
*self = Self::from(0); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
while n >= 64 { |
|
|
|
let mut t = 0; |
|
|
|
for i in &mut self.0 { |
|
|
|
::std::mem::swap(&mut t, i); |
|
|
|
} |
|
|
|
n -= 64; |
|
|
|
} |
|
|
|
|
|
|
|
if n > 0 { |
|
|
|
let mut t = 0; |
|
|
|
for i in &mut self.0 { |
|
|
|
let t2 = *i >> (64 - n); |
|
|
|
*i <<= n; |
|
|
|
*i |= t; |
|
|
|
t = t2; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn num_bits(&self) -> u32 { |
|
|
|
let mut ret = (6 as u32) * 64; |
|
|
|
for i in self.0.iter().rev() { |
|
|
|
let leading = i.leading_zeros(); |
|
|
|
ret -= leading; |
|
|
|
if leading != 64 { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ret |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn add_nocarry(&mut self, other: &FqRepr) { |
|
|
|
let mut carry = 0; |
|
|
|
|
|
|
|
for (a, b) in self.0.iter_mut().zip(other.0.iter()) { |
|
|
|
*a = ::adc(*a, *b, &mut carry); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn sub_noborrow(&mut self, other: &FqRepr) { |
|
|
|
let mut borrow = 0; |
|
|
|
|
|
|
|
for (a, b) in self.0.iter_mut().zip(other.0.iter()) { |
|
|
|
*a = ::sbb(*a, *b, &mut borrow); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)] |
|
|
|
#[derive(PrimeField)] |
|
|
|
#[PrimeFieldModulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"] |
|
|
|
#[PrimeFieldGenerator = "2"] |
|
|
|
pub struct Fq(FqRepr); |
|
|
|
|
|
|
|
/// `Fq` elements are ordered lexicographically.
|
|
|
|
impl Ord for Fq { |
|
|
|
#[inline(always)] |
|
|
|
fn cmp(&self, other: &Fq) -> Ordering { |
|
|
|
self.into_repr().cmp(&other.into_repr()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl PartialOrd for Fq { |
|
|
|
#[inline(always)] |
|
|
|
fn partial_cmp(&self, other: &Fq) -> Option<Ordering> { |
|
|
|
Some(self.cmp(other)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl ::std::fmt::Display for Fq { |
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { |
|
|
|
write!(f, "Fq({})", self.into_repr()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl ::rand::Rand for Fq { |
|
|
|
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self { |
|
|
|
loop { |
|
|
|
let mut tmp = Fq(FqRepr::rand(rng)); |
|
|
|
|
|
|
|
// Mask away the unused bits at the beginning.
|
|
|
|
tmp.0.as_mut()[5] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; |
|
|
|
|
|
|
|
if tmp.is_valid() { |
|
|
|
return tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl From<Fq> for FqRepr { |
|
|
|
fn from(e: Fq) -> FqRepr { |
|
|
|
e.into_repr() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl PrimeField for Fq { |
|
|
|
type Repr = FqRepr; |
|
|
|
|
|
|
|
fn from_repr(r: FqRepr) -> Result<Fq, PrimeFieldDecodingError> { |
|
|
|
let mut r = Fq(r); |
|
|
|
if r.is_valid() { |
|
|
|
r.mul_assign(&Fq(R2)); |
|
|
|
|
|
|
|
Ok(r) |
|
|
|
} else { |
|
|
|
Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn into_repr(&self) -> FqRepr { |
|
|
|
let mut r = *self; |
|
|
|
r.mont_reduce( |
|
|
|
(self.0).0[0], |
|
|
|
(self.0).0[1], |
|
|
|
(self.0).0[2], |
|
|
|
(self.0).0[3], |
|
|
|
(self.0).0[4], |
|
|
|
(self.0).0[5], |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
); |
|
|
|
r.0 |
|
|
|
} |
|
|
|
|
|
|
|
fn char() -> FqRepr { |
|
|
|
MODULUS |
|
|
|
} |
|
|
|
|
|
|
|
const NUM_BITS: u32 = MODULUS_BITS; |
|
|
|
|
|
|
|
const CAPACITY: u32 = Self::NUM_BITS - 1; |
|
|
|
|
|
|
|
fn multiplicative_generator() -> Self { |
|
|
|
Fq(GENERATOR) |
|
|
|
} |
|
|
|
|
|
|
|
const S: u32 = S; |
|
|
|
|
|
|
|
fn root_of_unity() -> Self { |
|
|
|
Fq(ROOT_OF_UNITY) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Field for Fq { |
|
|
|
#[inline] |
|
|
|
fn zero() -> Self { |
|
|
|
Fq(FqRepr::from(0)) |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn one() -> Self { |
|
|
|
Fq(R) |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn is_zero(&self) -> bool { |
|
|
|
self.0.is_zero() |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn add_assign(&mut self, other: &Fq) { |
|
|
|
// This cannot exceed the backing capacity.
|
|
|
|
self.0.add_nocarry(&other.0); |
|
|
|
|
|
|
|
// However, it may need to be reduced.
|
|
|
|
self.reduce(); |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn double(&mut self) { |
|
|
|
// This cannot exceed the backing capacity.
|
|
|
|
self.0.mul2(); |
|
|
|
|
|
|
|
// However, it may need to be reduced.
|
|
|
|
self.reduce(); |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn sub_assign(&mut self, other: &Fq) { |
|
|
|
// If `other` is larger than `self`, we'll need to add the modulus to self first.
|
|
|
|
if other.0 > self.0 { |
|
|
|
self.0.add_nocarry(&MODULUS); |
|
|
|
} |
|
|
|
|
|
|
|
self.0.sub_noborrow(&other.0); |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn negate(&mut self) { |
|
|
|
if !self.is_zero() { |
|
|
|
let mut tmp = MODULUS; |
|
|
|
tmp.sub_noborrow(&self.0); |
|
|
|
self.0 = tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn inverse(&self) -> Option<Self> { |
|
|
|
if self.is_zero() { |
|
|
|
None |
|
|
|
} else { |
|
|
|
// Guajardo Kumar Paar Pelzl
|
|
|
|
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
|
|
|
// Algorithm 16 (BEA for Inversion in Fp)
|
|
|
|
|
|
|
|
let one = FqRepr::from(1); |
|
|
|
|
|
|
|
let mut u = self.0; |
|
|
|
let mut v = MODULUS; |
|
|
|
let mut b = Fq(R2); // Avoids unnecessary reduction step.
|
|
|
|
let mut c = Self::zero(); |
|
|
|
|
|
|
|
while u != one && v != one { |
|
|
|
while u.is_even() { |
|
|
|
u.div2(); |
|
|
|
|
|
|
|
if b.0.is_even() { |
|
|
|
b.0.div2(); |
|
|
|
} else { |
|
|
|
b.0.add_nocarry(&MODULUS); |
|
|
|
b.0.div2(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
while v.is_even() { |
|
|
|
v.div2(); |
|
|
|
|
|
|
|
if c.0.is_even() { |
|
|
|
c.0.div2(); |
|
|
|
} else { |
|
|
|
c.0.add_nocarry(&MODULUS); |
|
|
|
c.0.div2(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if v < u { |
|
|
|
u.sub_noborrow(&v); |
|
|
|
b.sub_assign(&c); |
|
|
|
} else { |
|
|
|
v.sub_noborrow(&u); |
|
|
|
c.sub_assign(&b); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if u == one { |
|
|
|
Some(b) |
|
|
|
} else { |
|
|
|
Some(c) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn frobenius_map(&mut self, _: usize) { |
|
|
|
// This has no effect in a prime field.
|
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn mul_assign(&mut self, other: &Fq) { |
|
|
|
let mut carry = 0; |
|
|
|
let r0 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry); |
|
|
|
let r1 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry); |
|
|
|
let r2 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry); |
|
|
|
let r3 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[4], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(0, (self.0).0[0], (other.0).0[5], &mut carry); |
|
|
|
let r6 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r1 = ::mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry); |
|
|
|
let r2 = ::mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry); |
|
|
|
let r3 = ::mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[1], (other.0).0[4], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[1], (other.0).0[5], &mut carry); |
|
|
|
let r7 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r2 = ::mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry); |
|
|
|
let r3 = ::mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[2], (other.0).0[4], &mut carry); |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[2], (other.0).0[5], &mut carry); |
|
|
|
let r8 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r3 = ::mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry); |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[3], (other.0).0[4], &mut carry); |
|
|
|
let r8 = ::mac_with_carry(r8, (self.0).0[3], (other.0).0[5], &mut carry); |
|
|
|
let r9 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[4], (other.0).0[0], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[4], (other.0).0[1], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[4], (other.0).0[2], &mut carry); |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[4], (other.0).0[3], &mut carry); |
|
|
|
let r8 = ::mac_with_carry(r8, (self.0).0[4], (other.0).0[4], &mut carry); |
|
|
|
let r9 = ::mac_with_carry(r9, (self.0).0[4], (other.0).0[5], &mut carry); |
|
|
|
let r10 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[5], (other.0).0[0], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[5], (other.0).0[1], &mut carry); |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[5], (other.0).0[2], &mut carry); |
|
|
|
let r8 = ::mac_with_carry(r8, (self.0).0[5], (other.0).0[3], &mut carry); |
|
|
|
let r9 = ::mac_with_carry(r9, (self.0).0[5], (other.0).0[4], &mut carry); |
|
|
|
let r10 = ::mac_with_carry(r10, (self.0).0[5], (other.0).0[5], &mut carry); |
|
|
|
let r11 = carry; |
|
|
|
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11); |
|
|
|
} |
|
|
|
|
|
|
|
#[inline] |
|
|
|
fn square(&mut self) { |
|
|
|
let mut carry = 0; |
|
|
|
let r1 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry); |
|
|
|
let r2 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry); |
|
|
|
let r3 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[4], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[5], &mut carry); |
|
|
|
let r6 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r3 = ::mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry); |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry); |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[1], (self.0).0[4], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[1], (self.0).0[5], &mut carry); |
|
|
|
let r7 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r5 = ::mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[2], (self.0).0[4], &mut carry); |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[2], (self.0).0[5], &mut carry); |
|
|
|
let r8 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r7 = ::mac_with_carry(r7, (self.0).0[3], (self.0).0[4], &mut carry); |
|
|
|
let r8 = ::mac_with_carry(r8, (self.0).0[3], (self.0).0[5], &mut carry); |
|
|
|
let r9 = carry; |
|
|
|
let mut carry = 0; |
|
|
|
let r9 = ::mac_with_carry(r9, (self.0).0[4], (self.0).0[5], &mut carry); |
|
|
|
let r10 = carry; |
|
|
|
|
|
|
|
let r11 = 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 mut carry = 0; |
|
|
|
let r0 = ::mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry); |
|
|
|
let r1 = ::adc(r1, 0, &mut carry); |
|
|
|
let r2 = ::mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry); |
|
|
|
let r3 = ::adc(r3, 0, &mut carry); |
|
|
|
let r4 = ::mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry); |
|
|
|
let r5 = ::adc(r5, 0, &mut carry); |
|
|
|
let r6 = ::mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry); |
|
|
|
let r7 = ::adc(r7, 0, &mut carry); |
|
|
|
let r8 = ::mac_with_carry(r8, (self.0).0[4], (self.0).0[4], &mut carry); |
|
|
|
let r9 = ::adc(r9, 0, &mut carry); |
|
|
|
let r10 = ::mac_with_carry(r10, (self.0).0[5], (self.0).0[5], &mut carry); |
|
|
|
let r11 = ::adc(r11, 0, &mut carry); |
|
|
|
self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Fq { |
|
|
|
/// Determines if the element is really in the field. This is only used
|
|
|
|
/// internally.
|
|
|
|
#[inline(always)] |
|
|
|
fn is_valid(&self) -> bool { |
|
|
|
self.0 < MODULUS |
|
|
|
} |
|
|
|
|
|
|
|
/// Subtracts the modulus from this element if this element is not in the
|
|
|
|
/// field. Only used internally.
|
|
|
|
#[inline(always)] |
|
|
|
fn reduce(&mut self) { |
|
|
|
if !self.is_valid() { |
|
|
|
self.0.sub_noborrow(&MODULUS); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[inline(always)] |
|
|
|
fn mont_reduce( |
|
|
|
&mut self, |
|
|
|
r0: u64, |
|
|
|
mut r1: u64, |
|
|
|
mut r2: u64, |
|
|
|
mut r3: u64, |
|
|
|
mut r4: u64, |
|
|
|
mut r5: u64, |
|
|
|
mut r6: u64, |
|
|
|
mut r7: u64, |
|
|
|
mut r8: u64, |
|
|
|
mut r9: u64, |
|
|
|
mut r10: u64, |
|
|
|
mut r11: u64, |
|
|
|
) { |
|
|
|
// The Montgomery reduction here is based on Algorithm 14.32 in
|
|
|
|
// Handbook of Applied Cryptography
|
|
|
|
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
|
|
|
|
|
|
|
|
let k = r0.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r0, k, MODULUS.0[0], &mut carry); |
|
|
|
r1 = ::mac_with_carry(r1, k, MODULUS.0[1], &mut carry); |
|
|
|
r2 = ::mac_with_carry(r2, k, MODULUS.0[2], &mut carry); |
|
|
|
r3 = ::mac_with_carry(r3, k, MODULUS.0[3], &mut carry); |
|
|
|
r4 = ::mac_with_carry(r4, k, MODULUS.0[4], &mut carry); |
|
|
|
r5 = ::mac_with_carry(r5, k, MODULUS.0[5], &mut carry); |
|
|
|
r6 = ::adc(r6, 0, &mut carry); |
|
|
|
let carry2 = carry; |
|
|
|
let k = r1.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r1, k, MODULUS.0[0], &mut carry); |
|
|
|
r2 = ::mac_with_carry(r2, k, MODULUS.0[1], &mut carry); |
|
|
|
r3 = ::mac_with_carry(r3, k, MODULUS.0[2], &mut carry); |
|
|
|
r4 = ::mac_with_carry(r4, k, MODULUS.0[3], &mut carry); |
|
|
|
r5 = ::mac_with_carry(r5, k, MODULUS.0[4], &mut carry); |
|
|
|
r6 = ::mac_with_carry(r6, k, MODULUS.0[5], &mut carry); |
|
|
|
r7 = ::adc(r7, carry2, &mut carry); |
|
|
|
let carry2 = carry; |
|
|
|
let k = r2.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r2, k, MODULUS.0[0], &mut carry); |
|
|
|
r3 = ::mac_with_carry(r3, k, MODULUS.0[1], &mut carry); |
|
|
|
r4 = ::mac_with_carry(r4, k, MODULUS.0[2], &mut carry); |
|
|
|
r5 = ::mac_with_carry(r5, k, MODULUS.0[3], &mut carry); |
|
|
|
r6 = ::mac_with_carry(r6, k, MODULUS.0[4], &mut carry); |
|
|
|
r7 = ::mac_with_carry(r7, k, MODULUS.0[5], &mut carry); |
|
|
|
r8 = ::adc(r8, carry2, &mut carry); |
|
|
|
let carry2 = carry; |
|
|
|
let k = r3.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r3, k, MODULUS.0[0], &mut carry); |
|
|
|
r4 = ::mac_with_carry(r4, k, MODULUS.0[1], &mut carry); |
|
|
|
r5 = ::mac_with_carry(r5, k, MODULUS.0[2], &mut carry); |
|
|
|
r6 = ::mac_with_carry(r6, k, MODULUS.0[3], &mut carry); |
|
|
|
r7 = ::mac_with_carry(r7, k, MODULUS.0[4], &mut carry); |
|
|
|
r8 = ::mac_with_carry(r8, k, MODULUS.0[5], &mut carry); |
|
|
|
r9 = ::adc(r9, carry2, &mut carry); |
|
|
|
let carry2 = carry; |
|
|
|
let k = r4.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r4, k, MODULUS.0[0], &mut carry); |
|
|
|
r5 = ::mac_with_carry(r5, k, MODULUS.0[1], &mut carry); |
|
|
|
r6 = ::mac_with_carry(r6, k, MODULUS.0[2], &mut carry); |
|
|
|
r7 = ::mac_with_carry(r7, k, MODULUS.0[3], &mut carry); |
|
|
|
r8 = ::mac_with_carry(r8, k, MODULUS.0[4], &mut carry); |
|
|
|
r9 = ::mac_with_carry(r9, k, MODULUS.0[5], &mut carry); |
|
|
|
r10 = ::adc(r10, carry2, &mut carry); |
|
|
|
let carry2 = carry; |
|
|
|
let k = r5.wrapping_mul(INV); |
|
|
|
let mut carry = 0; |
|
|
|
::mac_with_carry(r5, k, MODULUS.0[0], &mut carry); |
|
|
|
r6 = ::mac_with_carry(r6, k, MODULUS.0[1], &mut carry); |
|
|
|
r7 = ::mac_with_carry(r7, k, MODULUS.0[2], &mut carry); |
|
|
|
r8 = ::mac_with_carry(r8, k, MODULUS.0[3], &mut carry); |
|
|
|
r9 = ::mac_with_carry(r9, k, MODULUS.0[4], &mut carry); |
|
|
|
r10 = ::mac_with_carry(r10, k, MODULUS.0[5], &mut carry); |
|
|
|
r11 = ::adc(r11, carry2, &mut carry); |
|
|
|
(self.0).0[0] = r6; |
|
|
|
(self.0).0[1] = r7; |
|
|
|
(self.0).0[2] = r8; |
|
|
|
(self.0).0[3] = r9; |
|
|
|
(self.0).0[4] = r10; |
|
|
|
(self.0).0[5] = r11; |
|
|
|
self.reduce(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl SqrtField for Fq { |
|
|
|
fn legendre(&self) -> ::LegendreSymbol { |
|
|
|
use LegendreSymbol::*; |
|
|
|
|
|
|
|
// s = self^((q - 1) // 2)
|
|
|
|
let s = self.pow([ |
|
|
|
0xdcff7fffffffd555, |
|
|
|
0xf55ffff58a9ffff, |
|
|
|
0xb39869507b587b12, |
|
|
|
0xb23ba5c279c2895f, |
|
|
|
0x258dd3db21a5d66b, |
|
|
|
0xd0088f51cbff34d, |
|
|
|
]); |
|
|
|
if s == Fq::zero() { |
|
|
|
Zero |
|
|
|
} else if s == Fq::one() { |
|
|
|
QuadraticResidue |
|
|
|
} else { |
|
|
|
QuadraticNonResidue |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn sqrt(&self) -> Option<Self> { |
|
|
|
// Shank's algorithm for q mod 4 = 3
|
|
|
|
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
|
|
|
|
|
|
|
|
// a1 = self^((q - 3) // 4)
|
|
|
|
let mut a1 = self.pow([ |
|
|
|
0xee7fbfffffffeaaa, |
|
|
|
0x7aaffffac54ffff, |
|
|
|
0xd9cc34a83dac3d89, |
|
|
|
0xd91dd2e13ce144af, |
|
|
|
0x92c6e9ed90d2eb35, |
|
|
|
0x680447a8e5ff9a6, |
|
|
|
]); |
|
|
|
let mut a0 = a1; |
|
|
|
a0.square(); |
|
|
|
a0.mul_assign(self); |
|
|
|
|
|
|
|
if a0 == NEGATIVE_ONE { |
|
|
|
None |
|
|
|
} else { |
|
|
|
a1.mul_assign(self); |
|
|
|
Some(a1) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_b_coeff() { |
|
|
|
assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF); |
|
|
@ -1899,6 +1177,8 @@ use rand::{Rand, SeedableRng, XorShiftRng}; |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_fq_repr_ordering() { |
|
|
|
use std::cmp::Ordering; |
|
|
|
|
|
|
|
fn assert_equality(a: FqRepr, b: FqRepr) { |
|
|
|
assert_eq!(a, b); |
|
|
|
assert!(a.cmp(&b) == Ordering::Equal); |
|
|
@ -2304,14 +1584,16 @@ fn test_fq_is_valid() { |
|
|
|
0x17c8be1800b9f059 |
|
|
|
])).is_valid() |
|
|
|
); |
|
|
|
assert!(!Fq(FqRepr([ |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff |
|
|
|
])).is_valid()); |
|
|
|
assert!( |
|
|
|
!Fq(FqRepr([ |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff, |
|
|
|
0xffffffffffffffff |
|
|
|
])).is_valid() |
|
|
|
); |
|
|
|
|
|
|
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); |
|
|
|
|
|
|
@ -2745,6 +2027,8 @@ fn test_fq_pow() { |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_fq_sqrt() { |
|
|
|
use ff::SqrtField; |
|
|
|
|
|
|
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); |
|
|
|
|
|
|
|
assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); |
|
|
@ -2878,6 +2162,8 @@ fn test_fq_num_bits() { |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_fq_root_of_unity() { |
|
|
|
use ff::SqrtField; |
|
|
|
|
|
|
|
assert_eq!(Fq::S, 1); |
|
|
|
assert_eq!( |
|
|
|
Fq::multiplicative_generator(), |
|
|
@ -2924,7 +2210,8 @@ fn fq_repr_tests() { |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_fq_legendre() { |
|
|
|
use LegendreSymbol::*; |
|
|
|
use ff::LegendreSymbol::*; |
|
|
|
use ff::SqrtField; |
|
|
|
|
|
|
|
assert_eq!(QuadraticResidue, Fq::one().legendre()); |
|
|
|
assert_eq!(Zero, Fq::zero().legendre()); |
|
|
|