diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 444846e..5d0efb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.33.0 + toolchain: 1.36.0 override: true # Ensure all code has been formatted with rustfmt @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.33.0 + toolchain: 1.36.0 override: true - name: cargo fetch uses: actions-rs/cargo@v1 @@ -58,7 +58,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.33.0 + toolchain: 1.36.0 override: true - run: rustup target add thumbv6m-none-eabi - name: cargo fetch diff --git a/Cargo.toml b/Cargo.toml index 29da017..2acf948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,10 @@ repository = "https://github.com/zkcrypto/jubjub" version = "0.2.0" edition = "2018" +[dependencies.bls12_381] +version = "0.1" +default-features = false + [dependencies.byteorder] version = "1" default-features = false diff --git a/README.md b/README.md index 7b8e0f8..ea9b446 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is a pure Rust implementation of the Jubjub elliptic curve group and its associated fields. * **This implementation has not been reviewed or audited. Use at your own risk.** -* This implementation targets Rust `1.33` or later. +* This implementation targets Rust `1.36` or later. * All operations are constant time unless explicitly noted. ## Features diff --git a/src/fq.rs b/src/fq.rs deleted file mode 100644 index 96bd30d..0000000 --- a/src/fq.rs +++ /dev/null @@ -1,1053 +0,0 @@ -use core::fmt; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - -use byteorder::{ByteOrder, LittleEndian}; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - -use crate::util::{adc, mac, sbb}; - -/// Represents an element of `GF(q)`. -// The internal representation of this type is four 64-bit unsigned -// integers in little-endian order. Elements of Fq are always in -// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, Eq)] -pub struct Fq(pub(crate) [u64; 4]); - -impl fmt::Debug for Fq { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_bytes(); - write!(f, "0x")?; - for &b in tmp.iter().rev() { - write!(f, "{:02x}", b)?; - } - Ok(()) - } -} - -impl From for Fq { - fn from(val: u64) -> Fq { - Fq([val, 0, 0, 0]) * R2 - } -} - -impl ConstantTimeEq for Fq { - 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 Fq { - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).unwrap_u8() == 1 - } -} - -impl ConditionallySelectable for Fq { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Fq([ - 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 -/// q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 -const MODULUS: Fq = Fq([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, -]); - -impl<'a> Neg for &'a Fq { - type Output = Fq; - - #[inline] - fn neg(self) -> Fq { - // 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); - - Fq([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) - } -} - -impl Neg for Fq { - type Output = Fq; - - #[inline] - fn neg(self) -> Fq { - -&self - } -} - -impl<'a, 'b> Sub<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn sub(self, rhs: &'b Fq) -> Fq { - self.subtract(rhs) - } -} - -impl<'a, 'b> Add<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn add(self, rhs: &'b Fq) -> Fq { - self.field_add(rhs) - } -} - -impl<'a, 'b> Mul<&'b Fq> for &'a Fq { - type Output = Fq; - - #[inline] - fn mul(self, rhs: &'b Fq) -> Fq { - self.multiply(rhs) - } -} - -impl_binops_additive!(Fq, Fq); -impl_binops_multiplicative!(Fq, Fq); - -/// INV = -(q^{-1} mod 2^64) mod 2^64 -const INV: u64 = 0xfffffffeffffffff; - -/// R = 2^256 mod q -const R: Fq = Fq([ - 0x00000001fffffffe, - 0x5884b7fa00034802, - 0x998c4fefecbc4ff5, - 0x1824b159acc5056f, -]); - -/// R^2 = 2^512 mod q -const R2: Fq = Fq([ - 0xc999e990f3f29c6d, - 0x2b6cedcb87925c23, - 0x05d314967254398f, - 0x0748d9d99f59ff11, -]); - -/// R^3 = 2^768 mod q -const R3: Fq = Fq([ - 0xc62c1807439b73af, - 0x1b3e0d188cf06990, - 0x73d13c71c7b5f418, - 0x6e2a5bb9c8db33e9, -]); - -// /// 7*R mod q -// const GENERATOR: Fq = Fq([ -// 0x0000000efffffff1, -// 0x17e363d300189c0f, -// 0xff9c57876f8457b0, -// 0x351332208fc5a8c4, -// ]); - -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. -const ROOT_OF_UNITY: Fq = Fq([ - 0xb9b58d8c5f0e466a, - 0x5b1b4c801819d7ec, - 0x0af53ae352a31e64, - 0x5bf3adda19e9b27b, -]); - -impl Default for Fq { - fn default() -> Self { - Self::zero() - } -} - -impl Fq { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> Fq { - Fq([0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> Fq { - R - } - - /// Doubles this field element. - #[inline] - pub fn double(&self) -> Fq { - self + self - } - - /// Attempts to convert a little-endian byte representation of - /// a field element into an element of `Fq`, failing if the input - /// is not canonical (is not smaller than q). - pub fn from_bytes(bytes: &[u8; 32]) -> CtOption { - let mut tmp = Fq([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]); - - // 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)) - } - - /// Converts an element of `Fq` into a byte representation in - /// little-endian byte order. - pub 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]; - 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 - } - - /// Converts a 512-bit little endian integer into - /// an element of Fq by reducing modulo q. - pub fn from_bytes_wide(bytes: &[u8; 64]) -> Fq { - Fq::from_u512([ - LittleEndian::read_u64(&bytes[0..8]), - LittleEndian::read_u64(&bytes[8..16]), - LittleEndian::read_u64(&bytes[16..24]), - LittleEndian::read_u64(&bytes[24..32]), - LittleEndian::read_u64(&bytes[32..40]), - LittleEndian::read_u64(&bytes[40..48]), - LittleEndian::read_u64(&bytes[48..56]), - LittleEndian::read_u64(&bytes[56..64]), - ]) - } - - fn from_u512(limbs: [u64; 8]) -> Fq { - // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits - // with the higher bits multiplied by 2^256. Thus, we perform two reductions - // - // 1. the lower bits are multiplied by R^2, as normal - // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 - // - // and computing their sum in the field. It remains to see that arbitrary 256-bit - // numbers can be placed into Montgomery form safely using the reduction. The - // reduction works so long as the product is less than R=2^256 multipled by - // the modulus. This holds because for any `c` smaller than the modulus, we have - // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the - // reduction always works so long as `c` is in the field; in this case it is either the - // constant `R2` or `R3`. - let d0 = Fq([limbs[0], limbs[1], limbs[2], limbs[3]]); - let d1 = Fq([limbs[4], limbs[5], limbs[6], limbs[7]]); - // Convert to Montgomery form - d0 * R2 + d1 * R3 - } - - /// Converts from an integer represented in little endian - /// into its (congruent) representation in Fq. - pub const fn from_raw(val: [u64; 4]) -> Self { - Fq(val).multiply(&R2) - } - - /// Squares this element. - #[inline] - pub const fn square(&self) -> Fq { - 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); - - Fq::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - /// Computes the square root of this element, if it exists. - pub fn sqrt(&self) -> CtOption { - // Tonelli-Shank's algorithm for q mod 16 = 1 - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - - // w = self^((t - 1) // 2) - // = self^6104339283789297388802252303364915521546564123189034618274734669823 - let w = self.pow_vartime(&[ - 0x7fff2dff7fffffff, - 0x04d0ec02a9ded201, - 0x94cebea4199cec04, - 0x0000000039f6d3a9, - ]); - - let mut v = S; - let mut x = self * &w; - let mut b = &x * &w; - - // Initialize z as the 2^S root of unity. - let mut z = ROOT_OF_UNITY; - - for max_v in (1..=S).rev() { - let mut k = 1; - let mut tmp = b.square(); - let mut j_less_than_v: Choice = 1.into(); - - for j in 2..max_v { - let tmp_is_one = tmp.ct_eq(&Fq::one()); - let squared = Fq::conditional_select(&tmp, &z, tmp_is_one).square(); - tmp = Fq::conditional_select(&squared, &tmp, tmp_is_one); - let new_z = Fq::conditional_select(&z, &squared, tmp_is_one); - j_less_than_v &= !j.ct_eq(&v); - k = u32::conditional_select(&j, &k, tmp_is_one); - z = Fq::conditional_select(&z, &new_z, j_less_than_v); - } - - let result = &x * &z; - x = Fq::conditional_select(&result, &x, b.ct_eq(&Fq::one())); - z = z.square(); - b = &b * &z; - v = k; - } - - CtOption::new( - x, - (&x * &x).ct_eq(self), // Only return Some if it's the square root. - ) - } - - /// 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 - } - - /// Computes the multiplicative inverse of this element, - /// failing if the element is zero. - pub fn invert(&self) -> CtOption { - #[inline(always)] - fn square_assign_multi(n: &mut Fq, num_times: usize) { - for _ in 0..num_times { - *n = n.square(); - } - } - // found using https://github.com/kwantam/addchain - let mut t0 = self.square(); - let mut t1 = t0 * self; - let mut t16 = t0.square(); - let mut t6 = t16.square(); - let mut t5 = t6 * &t0; - t0 = t6 * &t16; - let mut t12 = t5 * &t16; - let mut t2 = t6.square(); - let mut t7 = t5 * &t6; - let mut t15 = t0 * &t5; - let mut t17 = t12.square(); - t1.mul_assign(&t17); - let mut t3 = t7 * &t2; - let t8 = t1 * &t17; - let t4 = t8 * &t2; - let t9 = t8 * &t7; - t7 = t4 * &t5; - let t11 = t4 * &t17; - t5 = t9 * &t17; - let t14 = t7 * &t15; - let t13 = t11 * &t12; - t12 = t11 * &t17; - t15.mul_assign(&t12); - t16.mul_assign(&t15); - t3.mul_assign(&t16); - t17.mul_assign(&t3); - t0.mul_assign(&t17); - t6.mul_assign(&t0); - t2.mul_assign(&t6); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t17); - square_assign_multi(&mut t0, 9); - t0.mul_assign(&t16); - square_assign_multi(&mut t0, 9); - t0.mul_assign(&t15); - square_assign_multi(&mut t0, 9); - t0.mul_assign(&t15); - square_assign_multi(&mut t0, 7); - t0.mul_assign(&t14); - square_assign_multi(&mut t0, 7); - t0.mul_assign(&t13); - square_assign_multi(&mut t0, 10); - t0.mul_assign(&t12); - square_assign_multi(&mut t0, 9); - t0.mul_assign(&t11); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t8); - square_assign_multi(&mut t0, 8); - t0.mul_assign(self); - square_assign_multi(&mut t0, 14); - t0.mul_assign(&t9); - square_assign_multi(&mut t0, 10); - t0.mul_assign(&t8); - square_assign_multi(&mut t0, 15); - t0.mul_assign(&t7); - square_assign_multi(&mut t0, 10); - t0.mul_assign(&t6); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t5); - square_assign_multi(&mut t0, 16); - t0.mul_assign(&t3); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 7); - t0.mul_assign(&t4); - square_assign_multi(&mut t0, 9); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t3); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t3); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 8); - t0.mul_assign(&t2); - square_assign_multi(&mut t0, 5); - t0.mul_assign(&t1); - square_assign_multi(&mut t0, 5); - t0.mul_assign(&t1); - - CtOption::new(t0, !self.ct_eq(&Self::zero())) - } - - #[inline] - const 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); - - // Result may be within MODULUS of the correct value - Fq([r4, r5, r6, r7]).subtract(&MODULUS) - } - - #[inline] - pub(crate) const fn multiply(&self, rhs: &Self) -> Self { - // 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); - - Fq::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) - } - - #[inline] - pub(crate) const fn subtract(&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); - - // 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); - - Fq([d0, d1, d2, d3]) - } - - #[inline] - pub(crate) const fn field_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, _) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - Fq([d0, d1, d2, d3]).subtract(&MODULUS) - } -} - -impl<'a> From<&'a Fq> for [u8; 32] { - fn from(value: &'a Fq) -> [u8; 32] { - value.to_bytes() - } -} - -#[test] -fn test_inv() { - // Compute -(q^{-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!("{:?}", Fq::zero()), - "0x0000000000000000000000000000000000000000000000000000000000000000" - ); - assert_eq!( - format!("{:?}", Fq::one()), - "0x0000000000000000000000000000000000000000000000000000000000000001" - ); - assert_eq!( - format!("{:?}", R2), - "0x1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe" - ); -} - -#[test] -fn test_equality() { - assert_eq!(Fq::zero(), Fq::zero()); - assert_eq!(Fq::one(), Fq::one()); - assert_eq!(R2, R2); - - assert!(Fq::zero() != Fq::one()); - assert!(Fq::one() != R2); -} - -#[test] -fn test_to_bytes() { - assert_eq!( - Fq::zero().to_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!( - Fq::one().to_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.to_bytes(), - [ - 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, - 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 - ] - ); - - assert_eq!( - (-&Fq::one()).to_bytes(), - [ - 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 - ] - ); -} - -#[test] -fn test_from_bytes() { - assert_eq!( - Fq::from_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 - ]) - .unwrap(), - Fq::zero() - ); - - assert_eq!( - Fq::from_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 - ]) - .unwrap(), - Fq::one() - ); - - assert_eq!( - Fq::from_bytes(&[ - 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, - 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 - ]) - .unwrap(), - R2 - ); - - // -1 should work - assert!( - Fq::from_bytes(&[ - 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 - ]) - .is_some() - .unwrap_u8() - == 1 - ); - - // modulus is invalid - assert!( - Fq::from_bytes(&[ - 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 - ]) - .is_none() - .unwrap_u8() - == 1 - ); - - // Anything larger than the modulus is invalid - assert!( - Fq::from_bytes(&[ - 2, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 - ]) - .is_none() - .unwrap_u8() - == 1 - ); - assert!( - Fq::from_bytes(&[ - 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 58, 51, 72, 125, 157, 41, 83, 167, 237, 115 - ]) - .is_none() - .unwrap_u8() - == 1 - ); - assert!( - Fq::from_bytes(&[ - 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 116 - ]) - .is_none() - .unwrap_u8() - == 1 - ); -} - -#[test] -fn test_from_u512_zero() { - assert_eq!( - Fq::zero(), - Fq::from_u512([ - MODULUS.0[0], - MODULUS.0[1], - MODULUS.0[2], - MODULUS.0[3], - 0, - 0, - 0, - 0 - ]) - ); -} - -#[test] -fn test_from_u512_r() { - assert_eq!(R, Fq::from_u512([1, 0, 0, 0, 0, 0, 0, 0])); -} - -#[test] -fn test_from_u512_r2() { - assert_eq!(R2, Fq::from_u512([0, 0, 0, 0, 1, 0, 0, 0])); -} - -#[test] -fn test_from_u512_max() { - let max_u64 = 0xffffffffffffffff; - assert_eq!( - R3 - R, - Fq::from_u512([max_u64, max_u64, max_u64, max_u64, max_u64, max_u64, max_u64, max_u64]) - ); -} - -#[test] -fn test_from_bytes_wide_r2() { - assert_eq!( - R2, - Fq::from_bytes_wide(&[ - 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, - 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24, 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, - ]) - ); -} - -#[test] -fn test_from_bytes_wide_negative_one() { - assert_eq!( - -&Fq::one(), - Fq::from_bytes_wide(&[ - 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, - 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115, 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, - ]) - ); -} - -#[test] -fn test_from_bytes_wide_maximum() { - assert_eq!( - Fq([ - 0xc62c1805439b73b1, - 0xc2b9551e8ced218e, - 0xda44ec81daf9a422, - 0x5605aa601c162e79 - ]), - Fq::from_bytes_wide(&[0xff; 64]) - ); -} - -#[test] -fn test_zero() { - assert_eq!(Fq::zero(), -&Fq::zero()); - assert_eq!(Fq::zero(), Fq::zero() + Fq::zero()); - assert_eq!(Fq::zero(), Fq::zero() - Fq::zero()); - assert_eq!(Fq::zero(), Fq::zero() * Fq::zero()); -} - -#[cfg(test)] -const LARGEST: Fq = Fq([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, -]); - -#[test] -fn test_addition() { - let mut tmp = LARGEST; - tmp += &LARGEST; - - assert_eq!( - tmp, - Fq([ - 0xfffffffeffffffff, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ]) - ); - - let mut tmp = LARGEST; - tmp += &Fq([1, 0, 0, 0]); - - assert_eq!(tmp, Fq::zero()); -} - -#[test] -fn test_negation() { - let tmp = -&LARGEST; - - assert_eq!(tmp, Fq([1, 0, 0, 0])); - - let tmp = -&Fq::zero(); - assert_eq!(tmp, Fq::zero()); - let tmp = -&Fq([1, 0, 0, 0]); - assert_eq!(tmp, LARGEST); -} - -#[test] -fn test_subtraction() { - let mut tmp = LARGEST; - tmp -= &LARGEST; - - assert_eq!(tmp, Fq::zero()); - - let mut tmp = Fq::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 = Fq::zero(); - for b in cur - .to_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 = Fq::zero(); - for b in cur - .to_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!(Fq::zero().invert().is_none().unwrap_u8(), 1); - assert_eq!(Fq::one().invert().unwrap(), Fq::one()); - assert_eq!((-&Fq::one()).invert().unwrap(), -&Fq::one()); - - let mut tmp = R2; - - for _ in 0..100 { - let mut tmp2 = tmp.invert().unwrap(); - tmp2.mul_assign(&tmp); - - assert_eq!(tmp2, Fq::one()); - - tmp.add_assign(&R2); - } -} - -#[test] -fn test_invert_is_pow() { - let q_minus_2 = [ - 0xfffffffeffffffff, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]; - - let mut r1 = R; - let mut r2 = R; - let mut r3 = R; - - for _ in 0..100 { - r1 = r1.invert().unwrap(); - r2 = r2.pow_vartime(&q_minus_2); - r3 = r3.pow(&q_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() { - { - assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); - } - - let mut square = Fq([ - 0x46cd85a5f273077e, - 0x1d30c47dd68fc735, - 0x77f656f60beca0eb, - 0x494aa01bdf32468d, - ]); - - let mut none_count = 0; - - for _ in 0..100 { - let square_root = square.sqrt(); - if square_root.is_none().unwrap_u8() == 1 { - none_count += 1; - } else { - assert_eq!(square_root.unwrap() * square_root.unwrap(), square); - } - square -= Fq::one(); - } - - assert_eq!(49, none_count); -} - -#[test] -fn test_from_raw() { - assert_eq!( - Fq::from_raw([ - 0x1fffffffd, - 0x5884b7fa00034802, - 0x998c4fefecbc4ff5, - 0x1824b159acc5056f - ]), - Fq::from_raw([0xffffffffffffffff; 4]) - ); - - assert_eq!(Fq::from_raw(MODULUS.0), Fq::zero()); - - assert_eq!(Fq::from_raw([1, 0, 0, 0]), R); -} diff --git a/src/lib.rs b/src/lib.rs index da1cf93..bea1137 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,9 +43,8 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[macro_use] mod util; -mod fq; mod fr; -pub use fq::Fq; +pub use bls12_381::Scalar as Fq; pub use fr::Fr; const FR_MODULUS_BYTES: [u8; 32] = [ @@ -463,9 +462,9 @@ impl AffinePoint { /// for use in multiple additions. pub const fn to_niels(&self) -> AffineNielsPoint { AffineNielsPoint { - v_plus_u: self.v.field_add(&self.u), - v_minus_u: self.v.subtract(&self.u), - t2d: self.u.multiply(&self.v).multiply(&EDWARDS_D2), + v_plus_u: Fq::add(&self.v, &self.u), + v_minus_u: Fq::sub(&self.v, &self.u), + t2d: Fq::mul(&Fq::mul(&self.u, &self.v), &EDWARDS_D2), } } @@ -953,17 +952,17 @@ fn test_extended_niels_point_identity() { #[test] fn test_assoc() { let p = ExtendedPoint::from(AffinePoint { - u: Fq([ - 0xc0115cb656ae4839, - 0x623dc3ff81d64c26, - 0x5868e739b5794f2c, - 0x23bd4fbb18d39c9c, + u: Fq::from_raw([ + 0x81c571e5d883cfb0, + 0x049f7a686f147029, + 0xf539c860bc3ea21f, + 0x4284715b7ccc8162, ]), - v: Fq([ - 0x7588ee6d6dd40deb, - 0x9d6d7a23ebdb7c4c, - 0x46462e26d4edb8c7, - 0x10b4c1517ca82e9b, + v: Fq::from_raw([ + 0xbf096275684bb8ca, + 0xc7ba245890af256d, + 0x59119f3e86380eb0, + 0x3793de182f9fb1d2, ]), }) .mul_by_cofactor(); @@ -979,17 +978,17 @@ fn test_assoc() { #[test] fn test_batch_normalize() { let mut p = ExtendedPoint::from(AffinePoint { - u: Fq([ - 0xc0115cb656ae4839, - 0x623dc3ff81d64c26, - 0x5868e739b5794f2c, - 0x23bd4fbb18d39c9c, + u: Fq::from_raw([ + 0x81c571e5d883cfb0, + 0x049f7a686f147029, + 0xf539c860bc3ea21f, + 0x4284715b7ccc8162, ]), - v: Fq([ - 0x7588ee6d6dd40deb, - 0x9d6d7a23ebdb7c4c, - 0x46462e26d4edb8c7, - 0x10b4c1517ca82e9b, + v: Fq::from_raw([ + 0xbf096275684bb8ca, + 0xc7ba245890af256d, + 0x59119f3e86380eb0, + 0x3793de182f9fb1d2, ]), }) .mul_by_cofactor(); @@ -1214,17 +1213,17 @@ fn test_mul_consistency() { ]); assert_eq!(a * b, c); let p = ExtendedPoint::from(AffinePoint { - u: Fq([ - 0xc0115cb656ae4839, - 0x623dc3ff81d64c26, - 0x5868e739b5794f2c, - 0x23bd4fbb18d39c9c, + u: Fq::from_raw([ + 0x81c571e5d883cfb0, + 0x049f7a686f147029, + 0xf539c860bc3ea21f, + 0x4284715b7ccc8162, ]), - v: Fq([ - 0x7588ee6d6dd40deb, - 0x9d6d7a23ebdb7c4c, - 0x46462e26d4edb8c7, - 0x10b4c1517ca82e9b, + v: Fq::from_raw([ + 0xbf096275684bb8ca, + 0xc7ba245890af256d, + 0x59119f3e86380eb0, + 0x3793de182f9fb1d2, ]), }) .mul_by_cofactor();