diff --git a/src/fields/fp.rs b/src/fields/fp.rs index eb943b0..065a453 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -466,10 +466,16 @@ impl Group for Fp { impl ff::Field for Fp { fn random(mut rng: impl RngCore) -> Self { - let mut random_bytes = [0; 64]; - rng.fill_bytes(&mut random_bytes[..]); - - Self::from_bytes_wide(&random_bytes) + 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 zero() -> Self { @@ -491,7 +497,7 @@ impl ff::Field for Fp { /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { - let (is_square, res) = self.sqrt_alt(); + let (is_square, res) = FP_TABLES.sqrt_alt(self); CtOption::new(res, is_square) } @@ -535,15 +541,47 @@ impl ff::PrimeField for Fp { const S: u32 = S; fn from_repr(repr: Self::Repr) -> CtOption { - Self::from_bytes(&repr) + let mut tmp = Fp([0, 0, 0, 0]); + + 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()); + + // 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); + + // 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 { - self.to_bytes() + // Turn into canonical form by computing + // (a.R) / R = a + let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + + let mut res = [0; 32]; + 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 } fn is_odd(&self) -> Choice { - Choice::from(self.to_bytes()[0] & 1) + Choice::from(self.to_repr()[0] & 1) } fn multiplicative_generator() -> Self { @@ -551,7 +589,7 @@ impl ff::PrimeField for Fp { } fn root_of_unity() -> Self { - Self::ROOT_OF_UNITY + ROOT_OF_UNITY } } @@ -660,48 +698,12 @@ impl FieldExt for Fp { Fp::from_raw([v as u64, (v >> 64) as u64, 0, 0]) } - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fp`, failing if the input is not canonical. fn from_bytes(bytes: &[u8; 32]) -> CtOption { - let mut tmp = Fp([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(bytes[24..32].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); - - // 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)) + ::from_repr(*bytes) } - /// Converts an element of `Fp` into a byte representation in - /// little-endian byte order. fn to_bytes(&self) -> [u8; 32] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Fp::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); - - let mut res = [0; 32]; - 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 + ::to_repr(self) } /// Converts a 512-bit little endian integer into diff --git a/src/fields/fq.rs b/src/fields/fq.rs index b624a67..c8be606 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -466,10 +466,16 @@ impl Group for Fq { impl ff::Field for Fq { fn random(mut rng: impl RngCore) -> Self { - let mut random_bytes = [0; 64]; - rng.fill_bytes(&mut random_bytes[..]); - - Self::from_bytes_wide(&random_bytes) + 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 zero() -> Self { @@ -491,7 +497,7 @@ impl ff::Field for Fq { /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { - let (is_square, res) = self.sqrt_alt(); + let (is_square, res) = FQ_TABLES.sqrt_alt(self); CtOption::new(res, is_square) } @@ -535,15 +541,47 @@ impl ff::PrimeField for Fq { const S: u32 = S; fn from_repr(repr: Self::Repr) -> CtOption { - Self::from_bytes(&repr) + let mut tmp = Fq([0, 0, 0, 0]); + + 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()); + + // 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); + + // 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 { - self.to_bytes() + // Turn into canonical form by computing + // (a.R) / R = a + let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); + + let mut res = [0; 32]; + 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 } fn is_odd(&self) -> Choice { - Choice::from(self.to_bytes()[0] & 1) + Choice::from(self.to_repr()[0] & 1) } fn multiplicative_generator() -> Self { @@ -551,7 +589,7 @@ impl ff::PrimeField for Fq { } fn root_of_unity() -> Self { - Self::ROOT_OF_UNITY + ROOT_OF_UNITY } } @@ -660,48 +698,12 @@ impl FieldExt for Fq { Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0]) } - /// Attempts to convert a little-endian byte representation of - /// a scalar into a `Fq`, failing if the input is not canonical. fn from_bytes(bytes: &[u8; 32]) -> CtOption { - let mut tmp = Fq([0, 0, 0, 0]); - - tmp.0[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap()); - tmp.0[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap()); - tmp.0[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap()); - tmp.0[3] = u64::from_le_bytes(bytes[24..32].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); - - // 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)) + ::from_repr(*bytes) } - /// Converts an element of `Fq` into a byte representation in - /// little-endian byte order. fn to_bytes(&self) -> [u8; 32] { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Fq::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); - - let mut res = [0; 32]; - 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 + ::to_repr(self) } /// Converts a 512-bit little endian integer into