From 51f2fc0ebeec8bca9d3169830ff719f9f5089aaf Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 27 Nov 2020 00:19:19 -0800 Subject: [PATCH] Improve field macro Compile time Montgomery multiplication! --- Cargo.toml | 1 + ff-macros/Cargo.toml | 22 ++ ff-macros/LICENSE-APACHE | 1 + ff-macros/LICENSE-MIT | 1 + ff-macros/src/lib.rs | 88 ++++++++ ff/Cargo.toml | 2 +- ff/src/biginteger/arithmetic.rs | 106 ++++++++++ ff/src/biginteger/macros.rs | 4 +- ff/src/biginteger/mod.rs | 108 +--------- ff/src/fields/arithmetic.rs | 37 ++-- ff/src/fields/macros.rs | 112 +++++++++++ ff/src/fields/mod.rs | 19 +- ff/src/lib.rs | 7 +- ff/src/test_field/mod.rs | 345 +++++++++++++++++++++++--------- test-curves/src/bls12_381/fq.rs | 4 +- test-curves/src/bls12_381/g1.rs | 41 +--- test-curves/src/mnt4_753/fr.rs | 2 +- test-curves/src/mnt4_753/g1.rs | 63 +----- 18 files changed, 632 insertions(+), 331 deletions(-) create mode 100644 ff-macros/Cargo.toml create mode 120000 ff-macros/LICENSE-APACHE create mode 120000 ff-macros/LICENSE-MIT create mode 100644 ff-macros/src/lib.rs create mode 100644 ff/src/biginteger/arithmetic.rs diff --git a/Cargo.toml b/Cargo.toml index a7692672d..b2624cbbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "serialize", "serialize-derive", + "ff-macros", "ff-asm", "ff", diff --git a/ff-macros/Cargo.toml b/ff-macros/Cargo.toml new file mode 100644 index 000000000..0b74ac241 --- /dev/null +++ b/ff-macros/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ark-ff-macros" +version = "0.1.0" +authors = [ "arkworks contributors" ] +description = "A library for generating x86-64 assembly for finite field multiplication" +homepage = "https://arworks.rs" +repository = "https://github.com/arkworks/algebra" +documentation = "https://docs.rs/ark-ff-asm/" +keywords = ["cryptography", "finite fields", "assembly" ] +categories = ["cryptography"] +include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +quote = "1.0.0" +syn = { version = "1.0.0", features = ["full", "parsing", "extra-traits"]} +num-bigint = { version = "0.3", default-features = false } +num-traits = { version = "0.2", default-features = false } + +[lib] +proc-macro = true diff --git a/ff-macros/LICENSE-APACHE b/ff-macros/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/ff-macros/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/ff-macros/LICENSE-MIT b/ff-macros/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/ff-macros/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/ff-macros/src/lib.rs b/ff-macros/src/lib.rs new file mode 100644 index 000000000..9d0aa22d6 --- /dev/null +++ b/ff-macros/src/lib.rs @@ -0,0 +1,88 @@ +#![deny( + warnings, + unused, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +#![forbid(unsafe_code)] +#![recursion_limit = "128"] + +use num_bigint::{BigInt, Sign}; +use proc_macro::TokenStream; +use std::str::FromStr; +use syn::{Expr, Lit}; + +fn parse_string(input: TokenStream) -> Option { + let input: Expr = syn::parse(input).unwrap(); + let input = if let Expr::Group(syn::ExprGroup { expr, .. }) = input { + expr + } else { + panic!("could not parse"); + }; + match *input { + Expr::Lit(expr_lit) => match expr_lit.lit { + Lit::Str(s) => Some(s.value()), + _ => None, + }, + _ => None, + } +} + +fn str_to_limbs(num: &str) -> (bool, Vec) { + let (sign, digits) = BigInt::from_str(num) + .expect("could not parse to bigint") + .to_radix_le(16); + let limbs = digits + .chunks(16) + .map(|chunk| { + let mut this = 0u64; + for (i, hexit) in chunk.iter().enumerate() { + this += (*hexit as u64) << (4 * i); + } + format!("{}u64", this) + }) + .collect::>(); + + let sign_is_positive = sign != Sign::Minus; + (sign_is_positive, limbs) +} + +#[proc_macro] +pub fn to_sign_and_limbs(input: TokenStream) -> TokenStream { + let num = parse_string(input).expect("expected decimal string"); + let (is_positive, limbs) = str_to_limbs(&num); + + let limbs: String = limbs.join(", "); + let limbs_and_sign = format!("({}", is_positive) + ", [" + &limbs + "])"; + let tuple: Expr = syn::parse_str(&limbs_and_sign).unwrap(); + quote::quote!(#tuple).into() +} + +#[test] +fn test_str_to_limbs() { + let (is_positive, limbs) = str_to_limbs("-5"); + assert!(!is_positive); + assert_eq!(&limbs, &["5u64".to_string()]); + + let (is_positive, limbs) = str_to_limbs("100"); + assert!(is_positive); + assert_eq!(&limbs, &["100u64".to_string()]); + + let large_num = -((1i128 << 64) + 101234001234i128); + let (is_positive, limbs) = str_to_limbs(&large_num.to_string()); + assert!(!is_positive); + assert_eq!(&limbs, &["101234001234u64".to_string(), "1u64".to_string()]); + + let num = "80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946"; + let (is_positive, limbs) = str_to_limbs(&num.to_string()); + assert!(is_positive); + let expected_limbs = [ + format!("{}u64", 0x8508c00000000002u64), + format!("{}u64", 0x452217cc90000000u64), + format!("{}u64", 0xc5ed1347970dec00u64), + format!("{}u64", 0x619aaf7d34594aabu64), + format!("{}u64", 0x9b3af05dd14f6ecu64), + ]; + assert_eq!(&limbs, &expected_limbs); +} diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 0b2b1fbf1..9f5fede28 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -15,6 +15,7 @@ build = "build.rs" [dependencies] ark-ff-asm = { path = "../ff-asm" } +ark-ff-macros = { path = "../ff-macros" } ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } ark-serialize = { path = "../serialize", default-features = false } derivative = { version = "2", features = ["use_core"] } @@ -27,7 +28,6 @@ rustc_version = "0.3" [dev-dependencies] rand_xorshift = "0.2" -ark-test-curves = { path = "../test-curves", default-features = false, features = [ "bls12_381_curve"] } [features] default = [] diff --git a/ff/src/biginteger/arithmetic.rs b/ff/src/biginteger/arithmetic.rs new file mode 100644 index 000000000..4d64e4ffe --- /dev/null +++ b/ff/src/biginteger/arithmetic.rs @@ -0,0 +1,106 @@ +use ark_std::vec::Vec; + +/// Calculate a + b + carry, returning the sum and modifying the +/// carry value. +macro_rules! adc { + ($a:expr, $b:expr, &mut $carry:expr$(,)?) => {{ + let tmp = ($a as u128) + ($b as u128) + ($carry as u128); + + $carry = (tmp >> 64) as u64; + + tmp as u64 + }}; +} + +/// Calculate a + (b * c) + carry, returning the least significant digit +/// and setting carry to the most significant digit. +macro_rules! mac_with_carry { + ($a:expr, $b:expr, $c:expr, &mut $carry:expr$(,)?) => {{ + let tmp = ($a as u128) + ($b as u128 * $c as u128) + ($carry as u128); + + $carry = (tmp >> 64) as u64; + + tmp as u64 + }}; +} + +/// Calculate a - b - borrow, returning the result and modifying +/// the borrow value. +macro_rules! sbb { + ($a:expr, $b:expr, &mut $borrow:expr$(,)?) => {{ + let tmp = (1u128 << 64) + ($a as u128) - ($b as u128) - ($borrow as u128); + + $borrow = if tmp >> 64 == 0 { 1 } else { 0 }; + + tmp as u64 + }}; +} + +#[inline(always)] +pub(crate) fn mac(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { + let tmp = (u128::from(a)) + u128::from(b) * u128::from(c); + + *carry = (tmp >> 64) as u64; + + tmp as u64 +} + +#[inline(always)] +pub(crate) fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) { + let tmp = (u128::from(a)) + u128::from(b) * u128::from(c); + + *carry = (tmp >> 64) as u64; +} + +pub fn find_wnaf(num: &[u64]) -> Vec { + let is_zero = |num: &[u64]| num.iter().all(|x| *x == 0u64); + let is_odd = |num: &[u64]| num[0] & 1 == 1; + let sub_noborrow = |num: &mut [u64], z: u64| { + let mut other = vec![0u64; num.len()]; + other[0] = z; + let mut borrow = 0; + + for (a, b) in num.iter_mut().zip(other) { + *a = sbb!(*a, b, &mut borrow); + } + }; + let add_nocarry = |num: &mut [u64], z: u64| { + let mut other = vec![0u64; num.len()]; + other[0] = z; + let mut carry = 0; + + for (a, b) in num.iter_mut().zip(other) { + *a = adc!(*a, b, &mut carry); + } + }; + let div2 = |num: &mut [u64]| { + let mut t = 0; + for i in num.iter_mut().rev() { + let t2 = *i << 63; + *i >>= 1; + *i |= t; + t = t2; + } + }; + + let mut num = num.to_vec(); + let mut res = vec![]; + + while !is_zero(&num) { + let z: i64; + if is_odd(&num) { + z = 2 - (num[0] % 4) as i64; + if z >= 0 { + sub_noborrow(&mut num, z as u64) + } else { + add_nocarry(&mut num, (-z) as u64) + } + } else { + z = 0; + } + res.push(z); + div2(&mut num); + } + + res +} diff --git a/ff/src/biginteger/macros.rs b/ff/src/biginteger/macros.rs index ab02df3f1..08b7f90ca 100644 --- a/ff/src/biginteger/macros.rs +++ b/ff/src/biginteger/macros.rs @@ -17,7 +17,7 @@ macro_rules! bigint_impl { let mut carry = 0; for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = arithmetic::adc(*a, *b, &mut carry); + *a = adc!(*a, *b, &mut carry); } carry != 0 @@ -28,7 +28,7 @@ macro_rules! bigint_impl { let mut borrow = 0; for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = arithmetic::sbb(*a, *b, &mut borrow); + *a = sbb!(*a, *b, &mut borrow); } borrow != 0 diff --git a/ff/src/biginteger/mod.rs b/ff/src/biginteger/mod.rs index c02f60388..d8eb3520a 100644 --- a/ff/src/biginteger/mod.rs +++ b/ff/src/biginteger/mod.rs @@ -15,7 +15,8 @@ use rand::{ distributions::{Distribution, Standard}, Rng, }; - +#[macro_use] +pub mod arithmetic; #[macro_use] mod macros; @@ -117,108 +118,3 @@ pub trait BigInteger: Ok(()) } } - -pub mod arithmetic { - use ark_std::vec::Vec; - pub fn find_wnaf(num: &[u64]) -> Vec { - let is_zero = |num: &[u64]| num.iter().all(|x| *x == 0u64); - let is_odd = |num: &[u64]| num[0] & 1 == 1; - let sub_noborrow = |num: &mut [u64], z: u64| { - let mut other = vec![0u64; num.len()]; - other[0] = z; - let mut borrow = 0; - - for (a, b) in num.iter_mut().zip(other) { - *a = sbb(*a, b, &mut borrow); - } - }; - let add_nocarry = |num: &mut [u64], z: u64| { - let mut other = vec![0u64; num.len()]; - other[0] = z; - let mut carry = 0; - - for (a, b) in num.iter_mut().zip(other) { - *a = adc(*a, b, &mut carry); - } - }; - let div2 = |num: &mut [u64]| { - let mut t = 0; - for i in num.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - }; - - let mut num = num.to_vec(); - let mut res = vec![]; - - while !is_zero(&num) { - let z: i64; - if is_odd(&num) { - z = 2 - (num[0] % 4) as i64; - if z >= 0 { - sub_noborrow(&mut num, z as u64) - } else { - add_nocarry(&mut num, (-z) as u64) - } - } else { - z = 0; - } - res.push(z); - div2(&mut num); - } - - res - } - - /// Calculate a + b + carry, returning the sum and modifying the - /// carry value. - #[inline(always)] - pub(crate) fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { - let tmp = u128::from(a) + u128::from(b) + u128::from(*carry); - - *carry = (tmp >> 64) as u64; - - tmp as u64 - } - - /// Calculate a - b - borrow, returning the result and modifying - /// the borrow value. - #[inline(always)] - pub(crate) fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { - let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow); - - *borrow = if tmp >> 64 == 0 { 1 } else { 0 }; - - tmp as u64 - } - - /// Calculate a + (b * c) + carry, returning the least significant digit - /// and setting carry to the most significant digit. - #[inline(always)] - pub(crate) fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { - let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry); - - *carry = (tmp >> 64) as u64; - - tmp as u64 - } - - #[inline(always)] - pub(crate) fn mac(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { - let tmp = (u128::from(a)) + u128::from(b) * u128::from(c); - - *carry = (tmp >> 64) as u64; - - tmp as u64 - } - - #[inline(always)] - pub(crate) fn mac_discard(a: u64, b: u64, c: u64, carry: &mut u64) { - let tmp = (u128::from(a)) + u128::from(b) * u128::from(c); - - *carry = (tmp >> 64) as u64; - } -} diff --git a/ff/src/fields/arithmetic.rs b/ff/src/fields/arithmetic.rs index 3526a3a46..db80b8e43 100644 --- a/ff/src/fields/arithmetic.rs +++ b/ff/src/fields/arithmetic.rs @@ -38,8 +38,8 @@ macro_rules! impl_field_mul_assign { let k = r[0].wrapping_mul(P::INV); fa::mac_discard(r[0], k, P::MODULUS.0[0], &mut carry2); for j in 1..$limbs { - r[j] = fa::mac_with_carry(r[j], (self.0).0[j], (other.0).0[i], &mut carry1); - r[j - 1] = fa::mac_with_carry(r[j], k, P::MODULUS.0[j], &mut carry2); + r[j] = mac_with_carry!(r[j], (self.0).0[j], (other.0).0[i], &mut carry1); + r[j - 1] = mac_with_carry!(r[j], k, P::MODULUS.0[j], &mut carry2); } r[$limbs - 1] = carry1 + carry2; } @@ -53,7 +53,7 @@ macro_rules! impl_field_mul_assign { let mut carry = 0; for j in 0..$limbs { r[j + i] = - fa::mac_with_carry(r[j + i], (self.0).0[i], (other.0).0[j], &mut carry); + mac_with_carry!(r[j + i], (self.0).0[i], (other.0).0[j], &mut carry); } r[$limbs + i] = carry; } @@ -62,11 +62,11 @@ macro_rules! impl_field_mul_assign { for i in 0..$limbs { let k = r[i].wrapping_mul(P::INV); let mut carry = 0; - fa::mac_with_carry(r[i], k, P::MODULUS.0[0], &mut carry); + mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); for j in 1..$limbs { - r[j + i] = fa::mac_with_carry(r[j + i], k, P::MODULUS.0[j], &mut carry); + r[j + i] = mac_with_carry!(r[j + i], k, P::MODULUS.0[j], &mut carry); } - r[$limbs + i] = fa::adc(r[$limbs + i], _carry2, &mut carry); + r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); _carry2 = carry; } (self.0).0.copy_from_slice(&r[$limbs..]); @@ -88,10 +88,10 @@ macro_rules! impl_field_into_repr { let k = r[i].wrapping_mul(P::INV); let mut carry = 0; - fa::mac_with_carry(r[i], k, P::MODULUS.0[0], &mut carry); + mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); for j in 1..$limbs { r[(j + i) % $limbs] = - fa::mac_with_carry(r[(j + i) % $limbs], k, P::MODULUS.0[j], &mut carry); + mac_with_carry!(r[(j + i) % $limbs], k, P::MODULUS.0[j], &mut carry); } r[i % $limbs] = carry; } @@ -132,12 +132,8 @@ macro_rules! impl_field_square_in_place { if i < $limbs - 1 { for j in 0..$limbs { if j > i { - r[i + j] = fa::mac_with_carry( - r[i + j], - (self.0).0[i], - (self.0).0[j], - &mut carry, - ); + r[i + j] = + mac_with_carry!(r[i + j], (self.0).0[i], (self.0).0[j], &mut carry); } } r[$limbs + i] = carry; @@ -155,19 +151,22 @@ macro_rules! impl_field_square_in_place { r[1] <<= 1; for i in 0..$limbs { - r[2 * i] = fa::mac_with_carry(r[2 * i], (self.0).0[i], (self.0).0[i], &mut carry); - r[2 * i + 1] = fa::adc(r[2 * i + 1], 0, &mut carry); + r[2 * i] = mac_with_carry!(r[2 * i], (self.0).0[i], (self.0).0[i], &mut carry); + #[allow(unused_assignments)] + { + r[2 * i + 1] = adc!(r[2 * i + 1], 0, &mut carry); + } } // Montgomery reduction let mut _carry2 = 0; for i in 0..$limbs { let k = r[i].wrapping_mul(P::INV); let mut carry = 0; - fa::mac_with_carry(r[i], k, P::MODULUS.0[0], &mut carry); + mac_with_carry!(r[i], k, P::MODULUS.0[0], &mut carry); for j in 1..$limbs { - r[j + i] = fa::mac_with_carry(r[j + i], k, P::MODULUS.0[j], &mut carry); + r[j + i] = mac_with_carry!(r[j + i], k, P::MODULUS.0[j], &mut carry); } - r[$limbs + i] = fa::adc(r[$limbs + i], _carry2, &mut carry); + r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); _carry2 = carry; } (self.0).0.copy_from_slice(&r[$limbs..]); diff --git a/ff/src/fields/macros.rs b/ff/src/fields/macros.rs index 517682fff..a37ecd0ed 100644 --- a/ff/src/fields/macros.rs +++ b/ff/src/fields/macros.rs @@ -89,6 +89,7 @@ macro_rules! impl_prime_field_serializer { } }; } + macro_rules! impl_Fp { ($Fp:ident, $FpParameters:ident, $BigInteger:ident, $BigIntegerType:ty, $limbs:expr) => { pub trait $FpParameters: FpParameters {} @@ -115,6 +116,117 @@ macro_rules! impl_Fp { pub const fn new(element: $BigIntegerType) -> Self { Self(element, PhantomData) } + + #[ark_ff_asm::unroll_for_loops] + const fn const_is_zero(&self) -> bool { + let mut is_zero = true; + for i in 0..$limbs { + is_zero &= (self.0).0[i] == 0; + } + is_zero + } + + const fn const_neg(self, modulus: $BigIntegerType) -> Self { + if !self.const_is_zero() { + Self::new(Self::sub_noborrow(&modulus, &self.0)) + } else { + self + } + } + + /// Interpret a string of decimal numbers as a prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// For *internal* use only; please use the `field_new` macro instead + /// of this method + #[doc(hidden)] + pub const fn const_from_str(limbs: &[u64], is_positive: bool, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { + let mut repr = $BigInteger([0; $limbs]); + let mut i = 0; + while i < limbs.len() { + repr.0[i] = limbs[i]; + i += 1; + } + let res = Self::const_from_repr(repr, r2, modulus, inv); + if is_positive { + res + } else { + res.const_neg(modulus) + } + } + + #[inline] + pub(crate) const fn const_from_repr(repr: $BigIntegerType, r2: $BigIntegerType, modulus: $BigIntegerType, inv: u64) -> Self { + let mut r = Self::new(repr); + if r.const_is_zero() { + r + } else { + r = r.const_mul(&$Fp(r2, PhantomData), modulus, inv); + r + } + } + + #[ark_ff_asm::unroll_for_loops] + const fn const_mul(mut self, other: &Self, modulus: $BigIntegerType, inv: u64) -> Self { + let mut r = [0u64; $limbs * 2]; + + for i in 0..$limbs { + let mut carry = 0; + for j in 0..$limbs { + r[j + i] = mac_with_carry!(r[j + i], (self.0).0[i], (other.0).0[j], &mut carry); + } + r[$limbs + i] = carry; + } + // Montgomery reduction + let mut _carry2 = 0; + for i in 0..$limbs { + let k = r[i].wrapping_mul(inv); + let mut carry = 0; + mac_with_carry!(r[i], k, modulus.0[0], &mut carry); + for j in 1..$limbs { + r[j + i] = mac_with_carry!(r[j + i], k, modulus.0[j], &mut carry); + } + r[$limbs + i] = adc!(r[$limbs + i], _carry2, &mut carry); + _carry2 = carry; + } + + for i in 0..$limbs { + (self.0).0[i] = r[$limbs + i]; + } + + self.const_reduce(modulus) + } + + + #[ark_ff_asm::unroll_for_loops] + const fn const_is_valid(&self, modulus: $BigIntegerType) -> bool { + for i in 0..$limbs { + if (self.0).0[($limbs - i - 1)] < modulus.0[($limbs - i - 1)] { + return true + } else if (self.0).0[($limbs - i - 1)] > modulus.0[($limbs - i - 1)] { + return false + } + } + false + } + + #[inline] + const fn const_reduce(mut self, modulus: $BigIntegerType) -> Self { + if !self.const_is_valid(modulus) { + self.0 = Self::sub_noborrow(&self.0, &modulus); + } + self + } + + #[ark_ff_asm::unroll_for_loops] + #[allow(unused_assignments)] + const fn sub_noborrow(a: &$BigIntegerType, b: &$BigIntegerType) -> $BigInteger { + let mut a = *a; + let mut borrow = 0; + for i in 0..$limbs { + a.0[i] = sbb!(a.0[i], b.0[i], &mut borrow); + } + a + } } impl $Fp

{ diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 83a76a896..53238ac84 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -16,6 +16,7 @@ use ark_std::{ vec::Vec, }; +pub use ark_ff_macros; use num_traits::{One, Zero}; #[macro_use] @@ -30,12 +31,18 @@ pub use self::models::*; #[macro_export] macro_rules! field_new { - ($name:ident, $c0:expr) => { - $name { - 0: $c0, - 1: core::marker::PhantomData, - } - }; + ($name:ident, $c0:expr) => {{ + use $crate::FpParameters; + type Params = <$name as $crate::PrimeField>::Params; + let (is_positive, limbs) = $crate::ark_ff_macros::to_sign_and_limbs!($c0); + $name::const_from_str( + &limbs, + is_positive, + Params::R2, + Params::MODULUS, + Params::INV, + ) + }}; ($name:ident, $c0:expr, $c1:expr $(,)?) => { $name { c0: $c0, diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 2fe6360c9..f0ceec6c3 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -21,6 +21,10 @@ extern crate derivative; pub mod bytes; pub use self::bytes::*; +#[macro_use] +pub mod biginteger; +pub use self::biginteger::*; + #[macro_use] pub mod fields; pub use self::fields::*; @@ -29,9 +33,6 @@ pub use self::fields::*; #[cfg(test)] mod test_field; -pub mod biginteger; -pub use self::biginteger::*; - mod rand; pub use self::rand::*; diff --git a/ff/src/test_field/mod.rs b/ff/src/test_field/mod.rs index 9c6ddd153..49677733a 100644 --- a/ff/src/test_field/mod.rs +++ b/ff/src/test_field/mod.rs @@ -1,102 +1,249 @@ -/// Copy of BLS12-381's Fr -use crate::{ - biginteger::BigInteger256 as BigInteger, - fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, -}; - #[allow(unused)] -pub type Fr = Fp256; - -pub struct FrParameters; - -impl Fp256Parameters for FrParameters {} -impl FftParameters for FrParameters { - type BigInt = BigInteger; - - const TWO_ADICITY: u32 = 32; - - #[rustfmt::skip] - const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ - 0xb9b58d8c5f0e466a, - 0x5b1b4c801819d7ec, - 0xaf53ae352a31e64, - 0x5bf3adda19e9b27b, - ]); +pub(crate) use fq::*; +pub(crate) use fr::*; + +pub(crate) mod fr { + /// Copy of BLS12-381's Fr + use crate::{ + biginteger::BigInteger256 as BigInteger, + fields::{FftParameters, Fp256, Fp256Parameters, FpParameters}, + }; + + #[allow(unused)] + pub type Fr = Fp256; + + pub struct FrParameters; + + impl Fp256Parameters for FrParameters {} + impl FftParameters for FrParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 32; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 0xb9b58d8c5f0e466a, + 0x5b1b4c801819d7ec, + 0xaf53ae352a31e64, + 0x5bf3adda19e9b27b, + ]); + } + impl FpParameters for FrParameters { + /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0xffffffff00000001, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48, + ]); + + const MODULUS_BITS: u32 = 255; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 1; + + /// R = 10920338887063814464675503992315976177888879664585288394250266608035967270910 + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 0x1fffffffe, + 0x5884b7fa00034802, + 0x998c4fefecbc4ff5, + 0x1824b159acc5056f, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xc999e990f3f29c6d, + 0x2b6cedcb87925c23, + 0x5d314967254398f, + 0x748d9d99f59ff11, + ]); + + const INV: u64 = 0xfffffffeffffffff; + + /// GENERATOR = 7 + /// Encoded in Montgomery form, so the value here is + /// 7 * R % q = 24006497034320510773280787438025867407531605151569380937148207556313189711857 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0xefffffff1, + 0x17e363d300189c0f, + 0xff9c57876f8457b0, + 0x351332208fc5a8c4, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x7fffffff80000000, + 0xa9ded2017fff2dff, + 0x199cec0404d0ec02, + 0x39f6d3a994cebea4, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + // For T coprime to 2 + + // T = (MODULUS - 1) / 2^S = + // 12208678567578594777604504606729831043093128246378069236549469339647 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0xfffe5bfeffffffff, + 0x9a1d80553bda402, + 0x299d7d483339d808, + 0x73eda753, + ]); + + // (T - 1) / 2 = + // 6104339283789297388802252303364915521546564123189034618274734669823 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x7fff2dff7fffffff, + 0x4d0ec02a9ded201, + 0x94cebea4199cec04, + 0x39f6d3a9, + ]); + } } -impl FpParameters for FrParameters { - /// MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 - #[rustfmt::skip] - const MODULUS: BigInteger = BigInteger([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]); - - const MODULUS_BITS: u32 = 255; - - const CAPACITY: u32 = Self::MODULUS_BITS - 1; - - const REPR_SHAVE_BITS: u32 = 1; - - /// R = 10920338887063814464675503992315976177888879664585288394250266608035967270910 - #[rustfmt::skip] - const R: BigInteger = BigInteger([ - 0x1fffffffe, - 0x5884b7fa00034802, - 0x998c4fefecbc4ff5, - 0x1824b159acc5056f, - ]); - - #[rustfmt::skip] - const R2: BigInteger = BigInteger([ - 0xc999e990f3f29c6d, - 0x2b6cedcb87925c23, - 0x5d314967254398f, - 0x748d9d99f59ff11, - ]); - - const INV: u64 = 0xfffffffeffffffff; - - /// GENERATOR = 7 - /// Encoded in Montgomery form, so the value here is - /// 7 * R % q = 24006497034320510773280787438025867407531605151569380937148207556313189711857 - #[rustfmt::skip] - const GENERATOR: BigInteger = BigInteger([ - 0xefffffff1, - 0x17e363d300189c0f, - 0xff9c57876f8457b0, - 0x351332208fc5a8c4, - ]); - - #[rustfmt::skip] - const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ - 0x7fffffff80000000, - 0xa9ded2017fff2dff, - 0x199cec0404d0ec02, - 0x39f6d3a994cebea4, - ]); - - // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T - // For T coprime to 2 - - // T = (MODULUS - 1) / 2^S = - // 12208678567578594777604504606729831043093128246378069236549469339647 - #[rustfmt::skip] - const T: BigInteger = BigInteger([ - 0xfffe5bfeffffffff, - 0x9a1d80553bda402, - 0x299d7d483339d808, - 0x73eda753, - ]); - - // (T - 1) / 2 = - // 6104339283789297388802252303364915521546564123189034618274734669823 - #[rustfmt::skip] - const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ - 0x7fff2dff7fffffff, - 0x4d0ec02a9ded201, - 0x94cebea4199cec04, - 0x39f6d3a9, - ]); + +pub(crate) mod fq { + /// Copy of BLS12-377's Fq + use crate::{ + biginteger::BigInteger384 as BigInteger, + fields::{FftParameters, Fp384, Fp384Parameters, FpParameters}, + }; + + pub type Fq = Fp384; + + pub struct FqParameters; + + impl Fp384Parameters for FqParameters {} + impl FftParameters for FqParameters { + type BigInt = BigInteger; + + const TWO_ADICITY: u32 = 46u32; + + #[rustfmt::skip] + const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([ + 2022196864061697551u64, + 17419102863309525423u64, + 8564289679875062096u64, + 17152078065055548215u64, + 17966377291017729567u64, + 68610905582439508u64, + ]); + } + impl FpParameters for FqParameters { + /// MODULUS = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 + #[rustfmt::skip] + const MODULUS: BigInteger = BigInteger([ + 0x8508c00000000001, + 0x170b5d4430000000, + 0x1ef3622fba094800, + 0x1a22d9f300f5138f, + 0xc63b05c06ca1493b, + 0x1ae3a4617c510ea, + ]); + + const MODULUS_BITS: u32 = 377; + + const CAPACITY: u32 = Self::MODULUS_BITS - 1; + + const REPR_SHAVE_BITS: u32 = 7; + + /// R = 85013442423176922659824578519796707547925331718418265885885478904210582549405549618995257669764901891699128663912 + #[rustfmt::skip] + const R: BigInteger = BigInteger([ + 202099033278250856u64, + 5854854902718660529u64, + 11492539364873682930u64, + 8885205928937022213u64, + 5545221690922665192u64, + 39800542322357402u64, + ]); + + #[rustfmt::skip] + const R2: BigInteger = BigInteger([ + 0xb786686c9400cd22, + 0x329fcaab00431b1, + 0x22a5f11162d6b46d, + 0xbfdf7d03827dc3ac, + 0x837e92f041790bf9, + 0x6dfccb1e914b88, + ]); + + const INV: u64 = 9586122913090633727u64; + + /// GENERATOR = -5 + /// Encoded in Montgomery form, so the value here is + /// (-5 * R) % q = 92261639910053574722182574790803529333160366917737991650341130812388023949653897454961487930322210790384999596794 + #[rustfmt::skip] + const GENERATOR: BigInteger = BigInteger([ + 0xfc0b8000000002fa, + 0x97d39cf6e000018b, + 0x2072420fbfa05044, + 0xcbbcbd50d97c3802, + 0xbaf1ec35813f9eb, + 0x9974a2c0945ad2, + ]); + + #[rustfmt::skip] + const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0x4284600000000000, + 0xb85aea218000000, + 0x8f79b117dd04a400, + 0x8d116cf9807a89c7, + 0x631d82e03650a49d, + 0xd71d230be28875, + ]); + + // T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T + // For T coprime to 2 + + // T = (MODULUS - 1) // 2^S = + // 3675842578061421676390135839012792950148785745837396071634149488243117337281387659330802195819009059 + #[rustfmt::skip] + const T: BigInteger = BigInteger([ + 0x7510c00000021423, + 0x88bee82520005c2d, + 0x67cc03d44e3c7bcd, + 0x1701b28524ec688b, + 0xe9185f1443ab18ec, + 0x6b8, + ]); + + // (T - 1) // 2 = + // 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529 + #[rustfmt::skip] + const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([ + 0xba88600000010a11, + 0xc45f741290002e16, + 0xb3e601ea271e3de6, + 0xb80d94292763445, + 0x748c2f8a21d58c76, + 0x35c, + ]); + } + + #[test] + fn test_const_from_repr() { + use crate::fields::PrimeField; + let int = BigInteger([ + 9586122913090633730, + 4981570305181876224, + 14262076793150106624, + 7033126720376490667, + 699094806891394796, + 0, + ]); + let r2 = FqParameters::R2; + let modulus = FqParameters::MODULUS; + let inv = FqParameters::INV; + + assert_eq!( + Fq::from_repr(int).unwrap(), + Fq::const_from_repr(int, r2, modulus, inv) + ); + } } diff --git a/test-curves/src/bls12_381/fq.rs b/test-curves/src/bls12_381/fq.rs index 53ed1471f..0db87501b 100644 --- a/test-curves/src/bls12_381/fq.rs +++ b/test-curves/src/bls12_381/fq.rs @@ -111,5 +111,5 @@ impl FpParameters for FqParameters { ]); } -pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R); -pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0, 0, 0])); +pub const FQ_ONE: Fq = field_new!(Fq, "1"); +pub const FQ_ZERO: Fq = field_new!(Fq, "0"); diff --git a/test-curves/src/bls12_381/g1.rs b/test-curves/src/bls12_381/g1.rs index 234a8850a..a4d82e6e1 100644 --- a/test-curves/src/bls12_381/g1.rs +++ b/test-curves/src/bls12_381/g1.rs @@ -3,10 +3,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{ - biginteger::{BigInteger256, BigInteger384}, - field_new, Zero, -}; +use ark_ff::{field_new, Zero}; pub type G1Affine = GroupAffine; pub type G1Projective = GroupProjective; @@ -21,18 +18,11 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 0 - const COEFF_A: Fq = field_new!(Fq, BigInteger384([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])); + const COEFF_A: Fq = field_new!(Fq, "0"); /// COEFF_B = 4 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, BigInteger384([ - 0xaa270000000cfff3, - 0x53cc0032fc34000a, - 0x478fe97a6b0a807f, - 0xb1d37ebee6ba24d7, - 0x8ec9733bbf78ab2f, - 0x9d645513d83de7e, - ])); + const COEFF_B: Fq = field_new!(Fq, "4"); /// COFACTOR = (x - 1)^2 / 3 = 76329603384216526031706109802092473003 const COFACTOR: &'static [u64] = &[0x8c00aaab0000aaab, 0x396c8c005555e156]; @@ -40,12 +30,7 @@ impl SWModelParameters for Parameters { /// COFACTOR_INV = COFACTOR^{-1} mod r /// = 52435875175126190458656871551744051925719901746859129887267498875565241663483 #[rustfmt::skip] - const COFACTOR_INV: Fr = field_new!(Fr, BigInteger256([ - 288839107172787499, - 1152722415086798946, - 2612889808468387987, - 5124657601728438008, - ])); + const COFACTOR_INV: Fr = field_new!(Fr, "52435875175126190458656871551744051925719901746859129887267498875565241663483"); /// AFFINE_GENERATOR_COEFFS = (G1_GENERATOR_X, G1_GENERATOR_Y) const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = @@ -60,23 +45,9 @@ impl SWModelParameters for Parameters { /// G1_GENERATOR_X = /// 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger384([ - 0x5cb38790fd530c16, - 0x7817fc679976fff5, - 0x154f95c7143ba1c1, - 0xf0ae6acdf3d0e747, - 0xedce6ecc21dbf440, - 0x120177419e0bfb75, -])); +pub const G1_GENERATOR_X: Fq = field_new!(Fq, "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"); /// G1_GENERATOR_Y = /// 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger384([ - 0xbaac93d50ce72271, - 0x8c22631a7918fd8e, - 0xdd595f13570725ce, - 0x51ac582950405194, - 0xe1c8c3fad0059c0, - 0xbbc3efc5008a26a, -])); +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"); diff --git a/test-curves/src/mnt4_753/fr.rs b/test-curves/src/mnt4_753/fr.rs index d3ffac9e4..dbf42e984 100644 --- a/test-curves/src/mnt4_753/fr.rs +++ b/test-curves/src/mnt4_753/fr.rs @@ -7,7 +7,7 @@ pub type Fr = Fp768; pub struct FrParameters; -pub const FR_ONE: Fr = ark_ff::field_new!(Fr, FrParameters::R); +pub const FR_ONE: Fr = ark_ff::field_new!(Fr, "1"); impl Fp768Parameters for FrParameters {} impl FftParameters for FrParameters { diff --git a/test-curves/src/mnt4_753/g1.rs b/test-curves/src/mnt4_753/g1.rs index 260b76ac7..71863ead0 100644 --- a/test-curves/src/mnt4_753/g1.rs +++ b/test-curves/src/mnt4_753/g1.rs @@ -2,7 +2,7 @@ use ark_ec::{ models::{ModelParameters, SWModelParameters}, short_weierstrass_jacobian::*, }; -use ark_ff::{biginteger::BigInteger768, field_new}; +use ark_ff::field_new; use crate::mnt4_753::{Fq, Fr, FR_ONE}; @@ -20,37 +20,12 @@ impl ModelParameters for Parameters { impl SWModelParameters for Parameters { /// COEFF_A = 2 #[rustfmt::skip] - const COEFF_A: Fq = field_new!(Fq, BigInteger768([ - 3553860551672651396, - 2565472393707818253, - 3424927325234966109, - 17487811826058095619, - 15730291918544907998, - 4332070408724822737, - 7212646118208244402, - 12904649141092619460, - 9289117987390442562, - 2254330573517213976, - 3065472942259520298, - 271095073719429, - ])); + const COEFF_A: Fq = field_new!(Fq, "2"); /// COEFF_B = 0x01373684A8C9DCAE7A016AC5D7748D3313CD8E39051C596560835DF0C9E50A5B59B882A92C78DC537E51A16703EC9855C77FC3D8BB21C8D68BB8CFB9DB4B8C8FBA773111C36C8B1B4E8F1ECE940EF9EAAD265458E06372009C9A0491678EF4 + /// = 28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540 #[rustfmt::skip] - const COEFF_B: Fq = field_new!(Fq, BigInteger768([ - 2672638521926201442, - 17587766986973859626, - 1309143029066506763, - 1756412671449422902, - 5395165286423163724, - 589638022240022974, - 7360845090332416697, - 9829497896347590557, - 9341553552113883496, - 5888515763059971584, - 10173739464651404689, - 456607542322059, - ])); + const COEFF_B: Fq = field_new!(Fq, "28798803903456388891410036793299405764940372360099938340752576406393880372126970068421383312482853541572780087363938442377933706865252053507077543420534380486492786626556269083255657125025963825610840222568694137138741554679540"); /// COFACTOR = 1 const COFACTOR: &'static [u64] = &[1]; @@ -70,34 +45,8 @@ impl SWModelParameters for Parameters { // Y = 6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648, /// G1_GENERATOR_X = #[rustfmt::skip] -pub const G1_GENERATOR_X: Fq = field_new!(Fq, BigInteger768([ - 9433494781491502420, - 373642694095780604, - 7974079134466535382, - 15325904219470166885, - 16825705122208020751, - 898733863352481713, - 3802318585082797759, - 14417069684372068941, - 4332882897981414838, - 15138727514183191816, - 16850594895992448907, - 30598511593902 -])); +pub const G1_GENERATOR_X: Fq = field_new!(Fq, "7790163481385331313124631546957228376128961350185262705123068027727518350362064426002432450801002268747950550964579198552865939244360469674540925037890082678099826733417900510086646711680891516503232107232083181010099241949569"); /// G1_GENERATOR_Y = #[rustfmt::skip] -pub const G1_GENERATOR_Y: Fq = field_new!(Fq, BigInteger768([ - 15710199097794077134, - 3645667958306606136, - 8298269426007169475, - 5277073422205725562, - 10451808582969862130, - 14392820246664025579, - 4365987620174557815, - 14007263953321073101, - 1355600847400958219, - 3872959105252355444, - 18016882244107198324, - 424779036457857 -])); +pub const G1_GENERATOR_Y: Fq = field_new!(Fq, "6913648190367314284606685101150155872986263667483624713540251048208073654617802840433842931301128643140890502238233930290161632176167186761333725658542781350626799660920481723757654531036893265359076440986158843531053720994648");