diff --git a/Cargo.toml b/Cargo.toml index 3fa69a3ee..e671bebc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,11 @@ repository = "https://github.com/ebfull/bellman" version = "0.0.3" [dependencies] -rand = "0.3.*" -byteorder = "1.*" -serde = "1.0" -crossbeam = "0.2" -num_cpus = "1.0" +#rand = "0.3.*" +#byteorder = "1.*" +#serde = "1.0" +#crossbeam = "0.2" +#num_cpus = "1.0" [dev-dependencies] -bincode = "0.8.0" +#bincode = "0.8.0" diff --git a/benches/curve.rs b/benches/curve.rs deleted file mode 100644 index 18507c434..000000000 --- a/benches/curve.rs +++ /dev/null @@ -1,235 +0,0 @@ -#![feature(test)] -#![allow(unused_mut)] - -extern crate rand; -extern crate bellman; -extern crate test; - -use bellman::curves::*; -use bellman::curves::bls381::*; - -const SAMPLES: usize = 30; - -macro_rules! benchmark( - ($name:ident, $engine:ident, $input:ident($rng:ident) = $pre:expr; $post:expr) => ( - #[bench] - fn $name(b: &mut test::Bencher) { - let $rng = &mut rand::thread_rng(); - let $engine = &Bls381::new(); - let $input: Vec<_> = (0..SAMPLES).map(|_| $pre).collect(); - - let mut c = 0; - - b.iter(|| { - c += 1; - - let mut $input = $input[c % SAMPLES].clone(); - - $post - }) - } - ) -); - -benchmark!(g1_multiexp, e, - input(rng) = { - let mut g = G1::random(e, rng); - let mut a = G1::random(e, rng); - ( - (0..1000).map(|_| { - g.add_assign(e, &a); - a.double(e); - g.to_affine(e) - }).collect::>(), - (0..1000).map(|_| Fr::random(e, rng)).collect::>(), - ) - }; - - e.multiexp::(&input.0, &input.1) -); - -benchmark!(g2_multiexp, e, - input(rng) = { - let mut g = G2::random(e, rng); - let mut a = G2::random(e, rng); - ( - (0..1000).map(|_| { - g.add_assign(e, &a); - a.double(e); - g.to_affine(e) - }).collect::>(), - (0..1000).map(|_| Fr::random(e, rng)).collect::>(), - ) - }; - - e.multiexp::(&input.0, &input.1) -); - -benchmark!(full_pairing, e, - input(rng) = (G1::random(e, rng), G2::random(e, rng)); - - e.pairing(&input.0, &input.1) -); - -benchmark!(g1_pairing_preparation, e, - input(rng) = G1::random(e, rng); - - input.prepare(e) -); - -benchmark!(g2_pairing_preparation, e, - input(rng) = G2::random(e, rng); - - input.prepare(e) -); - -benchmark!(miller_loop, e, - input(rng) = (G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e)); - - e.miller_loop([(&input.0, &input.1)].into_iter()) -); - -benchmark!(double_miller_loop, e, - input(rng) = (G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e), G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e)); - - e.miller_loop([ - (&input.0, &input.1), - (&input.2, &input.3), - ].into_iter()) -); - -benchmark!(final_exponentiation, e, - input(rng) = e.miller_loop([ - (&G1::random(e, rng).prepare(e), &G2::random(e, rng).prepare(e)), - ].into_iter()); - - e.final_exponentiation(&input) -); - -macro_rules! group_tests( - ( - $name:ident, - $mul:ident, - $mul_mixed:ident, - $add:ident - ) => { - benchmark!($mul, e, - input(rng) = ($name::random(e, rng), Fr::random(e, rng)); - - {input.0.mul_assign(e, &input.1); input.0} - ); - - benchmark!($mul_mixed, e, - input(rng) = ($name::random(e, rng).to_affine(e), Fr::random(e, rng)); - - {input.0.mul(e, &input.1)} - ); - - benchmark!($add, e, - input(rng) = ($name::random(e, rng), $name::random(e, rng)); - - {input.0.add_assign(e, &input.1); input.0} - ); - }; -); - -macro_rules! field_tests( - ( - @nosqrt, - $name:ident, - $mul:ident, - $square:ident, - $add:ident, - $inverse:ident - ) => { - benchmark!($mul, e, - input(rng) = ($name::random(e, rng), $name::random(e, rng)); - - {input.0.mul_assign(e, &input.1); input.0} - ); - - benchmark!($square, e, - input(rng) = $name::random(e, rng); - - {input.square(e); input} - ); - - benchmark!($add, e, - input(rng) = ($name::random(e, rng), $name::random(e, rng)); - - {input.0.add_assign(e, &input.1); input.0} - ); - - benchmark!($inverse, e, - input(rng) = $name::random(e, rng); - - {input.inverse(e)} - ); - }; - ( - $name:ident, - $mul:ident, - $square:ident, - $add:ident, - $inverse:ident, - $sqrt:ident - ) => { - field_tests!(@nosqrt, $name, $mul, $square, $add, $inverse); - - benchmark!($sqrt, e, - input(rng) = {let mut tmp = $name::random(e, rng); tmp.square(e); tmp}; - - {input.sqrt(e)} - ); - }; -); - -field_tests!( - Fr, - fr_multiplication, - fr_squaring, - fr_addition, - fr_inverse, - fr_sqrt -); - -field_tests!( - Fq, - fq_multiplication, - fq_squaring, - fq_addition, - fq_inverse, - fq_sqrt -); - -field_tests!( - Fq2, - fq2_multiplication, - fq2_squaring, - fq2_addition, - fq2_inverse, - fq2_sqrt -); - -field_tests!( - @nosqrt, - Fq12, - fq12_multiplication, - fq12_squaring, - fq12_addition, - fq12_inverse -); - -group_tests!( - G1, - g1_multiplication, - g1_multiplication_mixed, - g1_addition -); - -group_tests!( - G2, - g2_multiplication, - g2_multiplication_mixed, - g2_addition -); diff --git a/src/curves/bls381/ec.rs b/src/curves/bls381/ec.rs deleted file mode 100644 index 4d4db81dc..000000000 --- a/src/curves/bls381/ec.rs +++ /dev/null @@ -1,456 +0,0 @@ -macro_rules! curve_impl { - ( - $engine:ident, - $name:ident, - $name_affine:ident, - $name_prepared:ident, - $name_uncompressed:ident, - $params_name:ident, - $params_field:ident, - $basefield:ident, - $scalarfield:ident - ) => { - #[repr(C)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub struct $name_affine { - x: $basefield, - y: $basefield, - infinity: bool - } - - #[repr(C)] - #[derive(Copy, Clone, Debug)] - pub struct $name { - x: $basefield, - y: $basefield, - z: $basefield - } - - #[derive(Clone)] - struct $params_name { - zero: $name, - one: $name, - coeff_b: $basefield, - windows: Vec, - batch_windows: (usize, Vec) - } - - impl Convert<$name_affine, $engine> for $name { - type Target = $name_affine; - - fn convert(&self, engine: &$engine) -> Cow<$name_affine> { - Cow::Owned(self.to_affine(engine)) - } - } - - impl Group<$engine> for $name { - fn group_zero(e: &$engine) -> $name { - $name::zero(e) - } - fn group_mul_assign(&mut self, e: &$engine, scalar: &$scalarfield) { - self.mul_assign(e, scalar); - } - fn group_add_assign(&mut self, e: &$engine, other: &Self) { - self.add_assign(e, other); - } - fn group_sub_assign(&mut self, e: &$engine, other: &Self) { - self.sub_assign(e, other); - } - } - - impl CurveAffine<$engine> for $name_affine { - type Jacobian = $name; - type Uncompressed = $name_uncompressed; - - fn is_valid(&self, e: &$engine) -> bool { - if self.is_zero() { - true - } else { - // Check that the point is on the curve - let mut y2 = self.y; - y2.square(e); - - let mut x3b = self.x; - x3b.square(e); - x3b.mul_assign(e, &self.x); - x3b.add_assign(e, &e.$params_field.coeff_b); - - if y2 == x3b { - // Check that the point is in the correct subgroup - if self.mul(e, &$scalarfield::char(e)).is_zero() { - true - } else { - false - } - } else { - false - } - } - } - - fn to_uncompressed(&self, engine: &$engine) -> Self::Uncompressed { - $name_uncompressed::from_affine(self, engine) - } - - fn to_jacobian(&self, engine: &$engine) -> $name { - if self.infinity { - $name::zero(engine) - } else { - $name { - x: self.x, - y: self.y, - z: $basefield::one(engine) - } - } - } - - fn prepare(self, e: &$engine) -> $name_prepared { - $name_prepared::from_engine(e, self) - } - - fn is_zero(&self) -> bool { - self.infinity - } - - fn mul>::Repr, $engine>>(&self, e: &$engine, other: &S) -> $name { - let mut res = $name::zero(e); - - for i in BitIterator::new((*other.convert(e)).borrow()) - { - res.double(e); - - if i { - res.add_assign_mixed(e, self); - } - } - - res - } - - fn negate(&mut self, e: &$engine) { - if !self.is_zero() { - self.y.negate(e); - } - } - } - - impl multiexp::Projective<$engine> for $name { - type WindowTable = wnaf::WindowTable<$engine, $name>; - - fn identity(e: &$engine) -> Self { - Self::zero(e) - } - - fn add_to_projective(&self, e: &$engine, projective: &mut Self) { - projective.add_assign(e, self); - } - - fn exponentiate(&mut self, - e: &$engine, - scalar: <$scalarfield as PrimeField<$engine>>::Repr, - table: &mut Self::WindowTable, - scratch: &mut wnaf::WNAFTable - ) - { - *self = self.optimal_exp(e, scalar, table, scratch); - } - - fn new_window_table(e: &$engine) -> Self::WindowTable { - wnaf::WindowTable::<$engine, $name>::new(e, $name::zero(e), 2) - } - } - - impl Curve<$engine> for $name { - type Affine = $name_affine; - type Prepared = $name_prepared; - - fn optimal_window(engine: &$engine, scalar_bits: usize) -> Option { - for (i, bits) in engine.$params_field.windows.iter().enumerate().rev() { - if &scalar_bits >= bits { - return Some(i + 2); - } - } - - None - } - - fn optimal_window_batch(&self, engine: &$engine, scalars: usize) -> wnaf::WindowTable<$engine, $name> { - let mut window = engine.$params_field.batch_windows.0; - - for i in &engine.$params_field.batch_windows.1 { - if scalars >= *i { - window += 1; - } else { - break; - } - } - - wnaf::WindowTable::new(engine, *self, window) - } - - fn zero(engine: &$engine) -> Self { - engine.$params_field.zero - } - - fn one(engine: &$engine) -> Self { - engine.$params_field.one - } - - fn random(engine: &$engine, rng: &mut R) -> Self { - let mut tmp = Self::one(engine); - tmp.mul_assign(engine, &$scalarfield::random(engine, rng)); - - tmp - } - - fn is_zero(&self) -> bool { - self.z.is_zero() - } - - fn is_equal(&self, engine: &$engine, other: &Self) -> bool { - if self.is_zero() { - return other.is_zero(); - } - - if other.is_zero() { - return false; - } - - let mut z1 = self.z; - z1.square(engine); - let mut z2 = other.z; - z2.square(engine); - - let mut tmp1 = self.x; - tmp1.mul_assign(engine, &z2); - - let mut tmp2 = other.x; - tmp2.mul_assign(engine, &z1); - - if tmp1 != tmp2 { - return false; - } - - z1.mul_assign(engine, &self.z); - z2.mul_assign(engine, &other.z); - z2.mul_assign(engine, &self.y); - z1.mul_assign(engine, &other.y); - - if z1 != z2 { - return false; - } - - true - } - - fn to_affine(&self, engine: &$engine) -> Self::Affine { - if self.is_zero() { - $name_affine { - x: $basefield::zero(), - y: $basefield::one(engine), - infinity: true - } - } else { - let zinv = self.z.inverse(engine).unwrap(); - let mut zinv_powered = zinv; - zinv_powered.square(engine); - - let mut x = self.x; - x.mul_assign(engine, &zinv_powered); - - let mut y = self.y; - zinv_powered.mul_assign(engine, &zinv); - y.mul_assign(engine, &zinv_powered); - - $name_affine { - x: x, - y: y, - infinity: false - } - } - } - - fn prepare(&self, e: &$engine) -> $name_prepared { - self.to_affine(e).prepare(e) - } - - fn double(&mut self, engine: &$engine) { - if self.is_zero() { - return; - } - - let mut a = self.x; - a.square(engine); - let mut c = self.y; - c.square(engine); - let mut d = c; - c.square(engine); - d.add_assign(engine, &self.x); - d.square(engine); - d.sub_assign(engine, &a); - d.sub_assign(engine, &c); - d.double(engine); - let mut e = a; - e.add_assign(engine, &a); - e.add_assign(engine, &a); - self.x = e; - self.x.square(engine); - self.x.sub_assign(engine, &d); - self.x.sub_assign(engine, &d); - c.double(engine); - c.double(engine); - c.double(engine); - self.z.mul_assign(engine, &self.y); - self.z.double(engine); - self.y = d; - self.y.sub_assign(engine, &self.x); - self.y.mul_assign(engine, &e); - self.y.sub_assign(engine, &c); - } - - fn negate(&mut self, engine: &$engine) { - if !self.is_zero() { - self.y.negate(engine) - } - } - - fn mul_assign>::Repr, $engine>>(&mut self, engine: &$engine, other: &S) { - let mut res = Self::zero(engine); - - for i in BitIterator::new((*other.convert(engine)).borrow()) - { - res.double(engine); - - if i { - res.add_assign(engine, self); - } - } - - *self = res; - } - - fn sub_assign(&mut self, engine: &$engine, other: &Self) { - let mut tmp = *other; - tmp.negate(engine); - self.add_assign(engine, &tmp); - } - - fn add_assign_mixed(&mut self, e: &$engine, other: &$name_affine) { - if other.is_zero() { - return; - } - - if self.is_zero() { - self.x = other.x; - self.y = other.y; - self.z = $basefield::one(e); - return; - } - - let mut z1z1 = self.z; - z1z1.square(e); - let mut u2 = other.x; - u2.mul_assign(e, &z1z1); - let mut z1cubed = self.z; - z1cubed.mul_assign(e, &z1z1); - let mut s2 = other.y; - s2.mul_assign(e, &z1cubed); - - if self.x == u2 && self.y == s2 { - self.double(e); - return; - } - - let mut h = u2; - h.sub_assign(e, &self.x); - let mut hh = h; - hh.square(e); - let mut i = hh; - i.double(e); - i.double(e); - let mut j = h; - j.mul_assign(e, &i); - let mut r = s2; - r.sub_assign(e, &self.y); - r.double(e); - let mut v = self.x; - v.mul_assign(e, &i); - - self.x = r; - self.x.square(e); - self.x.sub_assign(e, &j); - self.x.sub_assign(e, &v); - self.x.sub_assign(e, &v); - - self.y.mul_assign(e, &j); - let mut tmp = v; - tmp.sub_assign(e, &self.x); - tmp.mul_assign(e, &r); - tmp.sub_assign(e, &self.y); - tmp.sub_assign(e, &self.y); - self.y = tmp; - - self.z.add_assign(e, &h); - self.z.square(e); - self.z.sub_assign(e, &z1z1); - self.z.sub_assign(e, &hh); - } - - fn add_assign(&mut self, engine: &$engine, other: &Self) { - if self.is_zero() { - *self = *other; - return; - } - - if other.is_zero() { - return; - } - - let mut z1_squared = self.z; - z1_squared.square(engine); - let mut z2_squared = other.z; - z2_squared.square(engine); - let mut u1 = self.x; - u1.mul_assign(engine, &z2_squared); - let mut u2 = other.x; - u2.mul_assign(engine, &z1_squared); - let mut s1 = other.z; - s1.mul_assign(engine, &z2_squared); - s1.mul_assign(engine, &self.y); - let mut s2 = self.z; - s2.mul_assign(engine, &z1_squared); - s2.mul_assign(engine, &other.y); - - if u1 == u2 && s1 == s2 { - self.double(engine); - } else { - u2.sub_assign(engine, &u1); - s2.sub_assign(engine, &s1); - s2.double(engine); - let mut i = u2; - i.double(engine); - i.square(engine); - let mut v = i; - v.mul_assign(engine, &u1); - i.mul_assign(engine, &u2); - s1.mul_assign(engine, &i); - s1.double(engine); - self.x = s2; - self.x.square(engine); - self.x.sub_assign(engine, &i); - self.x.sub_assign(engine, &v); - self.x.sub_assign(engine, &v); - self.y = v; - self.y.sub_assign(engine, &self.x); - self.y.mul_assign(engine, &s2); - self.y.sub_assign(engine, &s1); - self.z.add_assign(engine, &other.z); - self.z.square(engine); - self.z.sub_assign(engine, &z1_squared); - self.z.sub_assign(engine, &z2_squared); - self.z.mul_assign(engine, &u2); - } - } - } - } -} diff --git a/src/curves/bls381/fp.rs b/src/curves/bls381/fp.rs deleted file mode 100644 index 43fc77a95..000000000 --- a/src/curves/bls381/fp.rs +++ /dev/null @@ -1,771 +0,0 @@ -macro_rules! fp_params_impl { - ( - $name:ident = (3 mod 4), - engine = $engine:ident, - params = $params_field:ident : $params_name:ident, - limbs = $limbs:expr, - modulus = $modulus:expr, - r1 = $r1:expr, - r2 = $r2:expr, - modulus_minus_3_over_4 = $modulus_minus_3_over_4:expr, - modulus_minus_1_over_2 = $modulus_minus_1_over_2:expr, - inv = $inv:expr - ) => { - #[derive(Clone)] - struct $params_name { - modulus: [u64; $limbs], - r1: $name, - r2: $name, - inv: u64, - one: $name, - num_bits: usize, - modulus_minus_3_over_4: [u64; $limbs], - modulus_minus_1_over_2: [u64; $limbs], - base10: [$name; 11] - } - - impl $params_name { - fn partial_init() -> $params_name { - let mut tmp = $params_name { - modulus: $modulus, - r1: $name($r1), - r2: $name($r2), - inv: $inv, - one: $name::zero(), - num_bits: 0, - modulus_minus_3_over_4: $modulus_minus_3_over_4, - modulus_minus_1_over_2: $modulus_minus_1_over_2, - base10: [$name::zero(); 11] - }; - - tmp.one.0[0] = 1; - - tmp - } - } - }; - ( - $name:ident = (1 mod 16), - engine = $engine:ident, - params = $params_field:ident : $params_name:ident, - limbs = $limbs:expr, - modulus = $modulus:expr, - r1 = $r1:expr, - r2 = $r2:expr, - modulus_minus_1_over_2 = $modulus_minus_1_over_2:expr, - s = $s:expr, - t = $t:expr, - t_plus_1_over_2 = $t_plus_1_over_2:expr, - inv = $inv:expr - ) => { - #[derive(Clone)] - struct $params_name { - modulus: [u64; $limbs], - r1: $name, - r2: $name, - inv: u64, - one: $name, - num_bits: usize, - modulus_minus_1_over_2: [u64; $limbs], - s: u64, - t: [u64; $limbs], - t_plus_1_over_2: [u64; $limbs], - root_of_unity: $name, - multiplicative_generator: $name, - base10: [$name; 11] - } - - impl $params_name { - fn partial_init() -> $params_name { - let mut tmp = $params_name { - modulus: $modulus, - r1: $name($r1), - r2: $name($r2), - inv: $inv, - one: $name::zero(), - num_bits: 0, - modulus_minus_1_over_2: $modulus_minus_1_over_2, - s: $s, - t: $t, - t_plus_1_over_2: $t_plus_1_over_2, - root_of_unity: $name::zero(), - multiplicative_generator: $name::zero(), - base10: [$name::zero(); 11] - }; - - tmp.one.0[0] = 1; - - tmp - } - } - }; -} - -macro_rules! fp_sqrt_impl { - ( - $name:ident = (3 mod 4), - engine = $engine:ident, - params = $params_field:ident : $params_name:ident - ) => { - impl SqrtField<$engine> for $name { - fn sqrt(&self, engine: &$engine) -> Option { - let mut a1 = self.pow(engine, &engine.$params_field.modulus_minus_3_over_4); - - let mut a0 = a1; - a0.square(engine); - a0.mul_assign(engine, self); - - let mut neg1 = Self::one(engine); - neg1.negate(engine); - - if a0 == neg1 { - None - } else { - a1.mul_assign(engine, self); - Some(a1) - } - } - } - }; - ( - $name:ident = (1 mod 16), - engine = $engine:ident, - params = $params_field:ident : $params_name:ident - ) => { - impl SqrtField<$engine> for $name { - fn sqrt(&self, engine: &$engine) -> Option { - if self.is_zero() { - return Some(*self); - } - - if self.pow(engine, &engine.$params_field.modulus_minus_1_over_2) != $name::one(engine) { - None - } else { - let mut c = engine.$params_field.root_of_unity; - - let mut r = self.pow(engine, &engine.$params_field.t_plus_1_over_2); - let mut t = self.pow(engine, &engine.$params_field.t); - let mut m = engine.$params_field.s; - - while t != Self::one(engine) { - let mut i = 1; - { - let mut t2i = t; - t2i.square(engine); - loop { - if t2i == Self::one(engine) { - break; - } - t2i.square(engine); - i += 1; - } - } - - for _ in 0..(m - i - 1) { - c.square(engine); - } - r.mul_assign(engine, &c); - c.square(engine); - t.mul_assign(engine, &c); - m = i; - } - - Some(r) - } - } - } - }; -} - -macro_rules! fp_impl { - ( - $name:ident = ($($congruency:tt)*), - engine = $engine:ident, - params = $params_field:ident : $params_name:ident, - arith = $arith_mod:ident, - repr = $repr:ident, - limbs = $limbs:expr, - $($params:tt)* - ) => { - fp_params_impl!( - $name = ($($congruency)*), - engine = $engine, - params = $params_field : $params_name, - limbs = $limbs, - $($params)* - ); - - impl $params_name { - fn base10(e: &$engine) -> [$name; 11] { - let mut ret = [$name::zero(); 11]; - - let mut acc = $name::zero(); - for i in 0..11 { - ret[i] = acc; - acc.add_assign(e, &$name::one(e)); - } - - ret - } - } - - fp_sqrt_impl!( - $name = ($($congruency)*), - engine = $engine, - params = $params_field : $params_name - ); - - #[derive(Copy, Clone, PartialEq, Eq)] - #[repr(C)] - pub struct $name([u64; $limbs]); - - #[derive(Copy, Clone, PartialEq, Eq)] - #[repr(C)] - pub struct $repr([u64; $limbs]); - - impl PrimeFieldRepr for $repr { - fn from_u64(a: u64) -> Self { - let mut tmp: [u64; $limbs] = Default::default(); - tmp[0] = a; - $repr(tmp) - } - - fn sub_noborrow(&mut self, other: &Self) { - $arith_mod::sub_noborrow(&mut self.0, &other.0); - } - - fn add_nocarry(&mut self, other: &Self) { - $arith_mod::add_nocarry(&mut self.0, &other.0); - } - - fn num_bits(&self) -> usize { - $arith_mod::num_bits(&self.0) - } - - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e==0) - } - - fn is_odd(&self) -> bool { - $arith_mod::odd(&self.0) - } - - fn div2(&mut self) { - $arith_mod::div2(&mut self.0); - } - } - - impl AsRef<[u64]> for $repr { - fn as_ref(&self) -> &[u64] { - &self.0 - } - } - - impl Ord for $repr { - fn cmp(&self, other: &$repr) -> Ordering { - if $arith_mod::lt(&self.0, &other.0) { - Ordering::Less - } else if self.0 == other.0 { - Ordering::Equal - } else { - Ordering::Greater - } - } - } - - impl PartialOrd for $repr { - fn partial_cmp(&self, other: &$repr) -> Option { - Some(self.cmp(other)) - } - } - - impl fmt::Debug for $name - { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ENGINE.with(|e| { - try!(write!(f, "Fp(0x")); - for i in self.into_repr(&e).0.iter().rev() { - try!(write!(f, "{:016x}", *i)); - } - write!(f, ")") - }) - } - } - - impl $name - { - #[inline] - fn mont_reduce(&mut self, engine: &$engine, res: &mut [u64; $limbs*2]) { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - for i in 0..$limbs { - let k = res[i].wrapping_mul(engine.$params_field.inv); - $arith_mod::mac_digit(&mut res[i..], &engine.$params_field.modulus, k); - } - - self.0.copy_from_slice(&res[$limbs..]); - - self.reduce(engine); - } - - #[inline] - fn reduce(&mut self, engine: &$engine) { - if !$arith_mod::lt(&self.0, &engine.$params_field.modulus) { - $arith_mod::sub_noborrow(&mut self.0, &engine.$params_field.modulus); - } - } - } - - impl Convert<$repr, $engine> for $name - { - type Target = $repr; - - fn convert(&self, engine: &$engine) -> Cow<$repr> { - Cow::Owned(self.into_repr(engine)) - } - } - - impl PrimeField<$engine> for $name - { - type Repr = $repr; - - fn from_repr(engine: &$engine, repr: Self::Repr) -> Result { - let mut tmp = $name(repr.0); - if $arith_mod::lt(&tmp.0, &engine.$params_field.modulus) { - tmp.mul_assign(engine, &engine.$params_field.r2); - Ok(tmp) - } else { - Err(()) - } - } - - fn into_repr(&self, engine: &$engine) -> Self::Repr { - let mut tmp = *self; - tmp.mul_assign(engine, &engine.$params_field.one); - $repr(tmp.0) - } - - fn from_u64(engine: &$engine, n: u64) -> Self { - let mut r = [0; $limbs]; - r[0] = n; - - Self::from_repr(engine, $repr(r)).unwrap() - } - - fn from_str(engine: &$engine, s: &str) -> Result { - let mut res = Self::zero(); - for c in s.chars() { - match c.to_digit(10) { - Some(d) => { - res.mul_assign(engine, &engine.$params_field.base10[10]); - res.add_assign(engine, &engine.$params_field.base10[d as usize]); - }, - None => { - return Err(()); - } - } - } - - Ok(res) - } - - fn char(engine: &$engine) -> Self::Repr { - $repr(engine.$params_field.modulus) - } - - fn num_bits(engine: &$engine) -> usize { - engine.$params_field.num_bits - } - - fn capacity(engine: &$engine) -> usize { - Self::num_bits(engine) - 1 - } - } - - impl Field<$engine> for $name - { - fn zero() -> Self { - $name([0; $limbs]) - } - - fn one(engine: &$engine) -> Self { - engine.$params_field.r1 - } - - fn random(engine: &$engine, rng: &mut R) -> Self { - let mut tmp = [0; $limbs*2]; - for i in &mut tmp { - *i = rng.gen(); - } - - $name($arith_mod::divrem(&tmp, &engine.$params_field.modulus).1) - } - - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e==0) - } - - fn double(&mut self, engine: &$engine) { - $arith_mod::mul2(&mut self.0); - - self.reduce(engine); - } - - fn frobenius_map(&mut self, _: &$engine, _: usize) - { - // This is the identity function for a prime field. - } - - fn negate(&mut self, engine: &$engine) { - if !self.is_zero() { - let mut tmp = engine.$params_field.modulus; - $arith_mod::sub_noborrow(&mut tmp, &self.0); - - self.0 = tmp; - } - } - - fn add_assign(&mut self, engine: &$engine, other: &Self) { - $arith_mod::add_nocarry(&mut self.0, &other.0); - - self.reduce(engine); - } - - fn sub_assign(&mut self, engine: &$engine, other: &Self) { - if $arith_mod::lt(&self.0, &other.0) { - $arith_mod::add_nocarry(&mut self.0, &engine.$params_field.modulus); - } - - $arith_mod::sub_noborrow(&mut self.0, &other.0); - } - - fn square(&mut self, engine: &$engine) - { - let mut res = [0; $limbs*2]; - $arith_mod::mac3(&mut res, &self.0, &self.0); - - self.mont_reduce(engine, &mut res); - } - - fn mul_assign(&mut self, engine: &$engine, other: &Self) { - let mut res = [0; $limbs*2]; - $arith_mod::mac3(&mut res, &self.0, &other.0); - - self.mont_reduce(engine, &mut res); - } - - fn inverse(&self, engine: &$engine) -> Option { - 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 mut u = self.0; - let mut v = engine.$params_field.modulus; - let mut b = engine.$params_field.r2; // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != engine.$params_field.one.0 && v != engine.$params_field.one.0 { - while $arith_mod::even(&u) { - $arith_mod::div2(&mut u); - - if $arith_mod::even(&b.0) { - $arith_mod::div2(&mut b.0); - } else { - $arith_mod::add_nocarry(&mut b.0, &engine.$params_field.modulus); - $arith_mod::div2(&mut b.0); - } - } - - while $arith_mod::even(&v) { - $arith_mod::div2(&mut v); - - if $arith_mod::even(&c.0) { - $arith_mod::div2(&mut c.0); - } else { - $arith_mod::add_nocarry(&mut c.0, &engine.$params_field.modulus); - $arith_mod::div2(&mut c.0); - } - } - - if $arith_mod::lt(&v, &u) { - $arith_mod::sub_noborrow(&mut u, &v); - b.sub_assign(engine, &c); - } else { - $arith_mod::sub_noborrow(&mut v, &u); - c.sub_assign(engine, &b); - } - } - - if u == engine.$params_field.one.0 { - Some(b) - } else { - Some(c) - } - } - } - } - - mod $arith_mod { - // Arithmetic - #[allow(dead_code)] - pub fn num_bits(v: &[u64; $limbs]) -> usize - { - let mut ret = 64 * $limbs; - for i in v.iter().rev() { - let leading = i.leading_zeros() as usize; - ret -= leading; - if leading != 64 { - break; - } - } - - ret - } - - #[inline] - pub fn mac_digit(acc: &mut [u64], b: &[u64], c: u64) - { - #[inline] - fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { - let tmp = (a as u128) + (b as u128) * (c as u128) + (*carry as u128); - - *carry = (tmp >> 64) as u64; - - tmp as u64 - } - - let mut b_iter = b.iter(); - let mut carry = 0; - - for ai in acc.iter_mut() { - if let Some(bi) = b_iter.next() { - *ai = mac_with_carry(*ai, *bi, c, &mut carry); - } else { - *ai = mac_with_carry(*ai, 0, c, &mut carry); - } - } - - debug_assert!(carry == 0); - } - - #[inline] - pub fn mac3_long(acc: &mut [u64], b: &[u64], c: &[u64]) { - for (i, xi) in b.iter().enumerate() { - mac_digit(&mut acc[i..], c, *xi); - } - } - - #[inline] - pub fn mac3(acc: &mut [u64; $limbs*2], b: &[u64; $limbs], c: &[u64; $limbs]) { - if $limbs > 4 { - let (x0, x1) = b.split_at($limbs / 2); - let (y0, y1) = c.split_at($limbs / 2); - - let mut p = [0; $limbs+1]; - mac3_long(&mut p, x1, y1); - add_nocarry(&mut acc[$limbs/2..], &p); - add_nocarry(&mut acc[$limbs..], &p); - p = [0; $limbs+1]; - mac3_long(&mut p, x0, y0); - add_nocarry(&mut acc[..], &p); - add_nocarry(&mut acc[$limbs/2..], &p); - - let mut sign; - let mut j0 = [0; $limbs / 2]; - let mut j1 = [0; $limbs / 2]; - if lt(x1, x0) { - sign = false; - j0.copy_from_slice(x0); - sub_noborrow(&mut j0, x1); - } else { - sign = true; - j0.copy_from_slice(x1); - sub_noborrow(&mut j0, x0); - } - if lt(&y1, &y0) { - sign = sign == false; - j1.copy_from_slice(y0); - sub_noborrow(&mut j1, y1); - } else { - sign = sign == true; - j1.copy_from_slice(y1); - sub_noborrow(&mut j1, y0); - } - - if sign { - p = [0; $limbs+1]; - mac3_long(&mut p, &j0, &j1); - sub_noborrow(&mut acc[$limbs/2..], &p); - } else { - mac3_long(&mut acc[$limbs/2..], &j0, &j1); - } - } else { - mac3_long(acc, b, c); - } - } - - #[inline] - pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { - let tmp = (a as u128) + (b as u128) + (*carry as u128); - - *carry = (tmp >> 64) as u64; - - tmp as u64 - } - - #[inline] - #[allow(dead_code)] - pub fn add_carry(a: &mut [u64], b: &[u64]) { - use std::iter; - - let mut carry = 0; - - for (a, b) in a.into_iter().zip(b.iter().chain(iter::repeat(&0))) { - *a = adc(*a, *b, &mut carry); - } - - debug_assert!(0 == carry); - } - - #[inline] - pub fn add_nocarry(a: &mut [u64], b: &[u64]) { - let mut carry = 0; - - for (a, b) in a.into_iter().zip(b.iter()) { - *a = adc(*a, *b, &mut carry); - } - - debug_assert!(0 == carry); - } - - /// Returns true if a < b. - #[inline] - pub fn lt(a: &[u64], b: &[u64]) -> bool { - for (a, b) in a.iter().zip(b.iter()).rev() { - if *a > *b { - return false; - } else if *a < *b { - return true; - } - } - - false - } - - #[inline] - pub fn sub_noborrow(a: &mut [u64], b: &[u64]) { - #[inline] - fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { - let tmp = (1u128 << 64) + (a as u128) - (b as u128) - (*borrow as u128); - - *borrow = if tmp >> 64 == 0 { 1 } else { 0 }; - - tmp as u64 - } - - let mut borrow = 0; - - for (a, b) in a.into_iter().zip(b.iter()) { - *a = sbb(*a, *b, &mut borrow); - } - - debug_assert!(0 == borrow); - } - - /// Returns if number is even. - #[inline(always)] - #[allow(dead_code)] - pub fn even(a: &[u64; $limbs]) -> bool { - a[0] & 1 == 0 - } - - #[inline(always)] - #[allow(dead_code)] - pub fn odd(a: &[u64; $limbs]) -> bool { - a[0] & 1 == 1 - } - - /// Divide by two - #[inline] - pub fn div2(a: &mut [u64; $limbs]) { - let mut t = 0; - for i in a.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - } - - #[inline] - pub fn mul2(a: &mut [u64; $limbs]) { - let mut last = 0; - for i in a { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - } - - fn get_bit(this: &[u64; $limbs*2], n: usize) -> bool { - let part = n / 64; - let bit = n - (64 * part); - - this[part] & (1 << bit) > 0 - } - - fn set_bit(this: &mut [u64; $limbs], n: usize, to: bool) -> bool - { - let part = n / 64; - let bit = n - (64 * part); - - match this.get_mut(part) { - Some(e) => { - if to { - *e |= 1 << bit; - } else { - *e &= !(1 << bit); - } - - true - }, - None => false - } - } - - pub fn divrem( - this: &[u64; $limbs*2], - modulo: &[u64; $limbs] - ) -> (Option<[u64; $limbs]>, [u64; $limbs]) - { - let mut q = Some([0; $limbs]); - let mut r = [0; $limbs]; - - for i in (0..($limbs*2*64)).rev() { - // NB: modulo's first bit is unset so this will never - // destroy information - mul2(&mut r); - assert!(set_bit(&mut r, 0, get_bit(this, i))); - if !lt(&r, modulo) { - sub_noborrow(&mut r, modulo); - if q.is_some() && !set_bit(q.as_mut().unwrap(), i, true) { - q = None - } - } - } - - if q.is_some() && !lt(q.as_ref().unwrap(), modulo) { - (None, r) - } else { - (q, r) - } - } - } - } -} diff --git a/src/curves/bls381/fq12.rs b/src/curves/bls381/fq12.rs deleted file mode 100644 index c70a01478..000000000 --- a/src/curves/bls381/fq12.rs +++ /dev/null @@ -1,151 +0,0 @@ -use super::{Bls381, Fq2, Fq6}; -use rand; -use super::Field; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Fq12 { - pub c0: Fq6, - pub c1: Fq6 -} - -impl Fq12 { - pub fn unitary_inverse(&mut self, e: &Bls381) - { - self.c1.negate(e); - } - - pub fn mul_by_015( - &mut self, - e: &Bls381, - a: &Fq2, - b: &Fq2, - c: &Fq2 - ) - { - let mut aa = self.c0; - aa.mul_by_01(e, a, b); - let mut bb = self.c1; - bb.mul_by_1(e, c); - let mut o = *b; - o.add_assign(e, &c); - self.c1.add_assign(e, &self.c0); - self.c1.mul_by_01(e, a, &o); - self.c1.sub_assign(e, &aa); - self.c1.sub_assign(e, &bb); - self.c0 = bb; - self.c0.mul_by_nonresidue(e); - self.c0.add_assign(e, &aa); - } -} - -impl Field for Fq12 -{ - fn zero() -> Self { - Fq12 { - c0: Fq6::zero(), - c1: Fq6::zero() - } - } - - fn one(engine: &Bls381) -> Self { - Fq12 { - c0: Fq6::one(engine), - c1: Fq6::zero() - } - } - - fn random(engine: &Bls381, rng: &mut R) -> Self { - Fq12 { - c0: Fq6::random(engine, rng), - c1: Fq6::random(engine, rng) - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() - } - - fn double(&mut self, engine: &Bls381) { - self.c0.double(engine); - self.c1.double(engine); - } - - fn negate(&mut self, engine: &Bls381) { - self.c0.negate(engine); - self.c1.negate(engine); - } - - fn add_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.add_assign(engine, &other.c0); - self.c1.add_assign(engine, &other.c1); - } - - fn sub_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.sub_assign(engine, &other.c0); - self.c1.sub_assign(engine, &other.c1); - } - - fn frobenius_map(&mut self, e: &Bls381, power: usize) - { - self.c0.frobenius_map(e, power); - self.c1.frobenius_map(e, power); - - self.c1.c0.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]); - self.c1.c1.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]); - self.c1.c2.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]); - } - - fn square(&mut self, e: &Bls381) { - let mut ab = self.c0; - ab.mul_assign(e, &self.c1); - let mut c0c1 = self.c0; - c0c1.add_assign(e, &self.c1); - let mut c0 = self.c1; - c0.mul_by_nonresidue(e); - c0.add_assign(e, &self.c0); - c0.mul_assign(e, &c0c1); - c0.sub_assign(e, &ab); - self.c1 = ab; - self.c1.add_assign(e, &ab); - ab.mul_by_nonresidue(e); - c0.sub_assign(e, &ab); - self.c0 = c0; - } - - fn mul_assign(&mut self, e: &Bls381, other: &Self) { - let mut aa = self.c0; - aa.mul_assign(e, &other.c0); - let mut bb = self.c1; - bb.mul_assign(e, &other.c1); - let mut o = other.c0; - o.add_assign(e, &other.c1); - self.c1.add_assign(e, &self.c0); - self.c1.mul_assign(e, &o); - self.c1.sub_assign(e, &aa); - self.c1.sub_assign(e, &bb); - self.c0 = bb; - self.c0.mul_by_nonresidue(e); - self.c0.add_assign(e, &aa); - } - - fn inverse(&self, e: &Bls381) -> Option { - let mut c0s = self.c0; - c0s.square(e); - let mut c1s = self.c1; - c1s.square(e); - c1s.mul_by_nonresidue(e); - c0s.sub_assign(e, &c1s); - - c0s.inverse(e).map(|t| { - let mut tmp = Fq12 { - c0: t, - c1: t - }; - tmp.c0.mul_assign(e, &self.c0); - tmp.c1.mul_assign(e, &self.c1); - tmp.c1.negate(e); - - tmp - }) - } -} diff --git a/src/curves/bls381/fq2.rs b/src/curves/bls381/fq2.rs deleted file mode 100644 index d3aa93825..000000000 --- a/src/curves/bls381/fq2.rs +++ /dev/null @@ -1,156 +0,0 @@ -use super::{Bls381, Fq}; -use rand; -use super::{Field, SqrtField}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Fq2 { - pub c0: Fq, - pub c1: Fq -} - -impl Fq2 { - pub fn mul_by_nonresidue(&mut self, e: &Bls381) { - let t0 = self.c0; - self.c0.sub_assign(e, &self.c1); - self.c1.add_assign(e, &t0); - } -} - -impl SqrtField for Fq2 { - fn sqrt(&self, engine: &Bls381) -> Option { - // Algorithm 9, https://eprint.iacr.org/2012/685.pdf - - if self.is_zero() { - return Some(Self::zero()); - } else { - let mut a1 = self.pow(engine, &engine.fqparams.modulus_minus_3_over_4); - let mut alpha = a1; - alpha.square(engine); - alpha.mul_assign(engine, self); - let mut a0 = alpha.pow(engine, &engine.fqparams.modulus); - a0.mul_assign(engine, &alpha); - - let mut neg1 = Self::one(engine); - neg1.negate(engine); - - if a0 == neg1 { - None - } else { - a1.mul_assign(engine, self); - - if alpha == neg1 { - a1.mul_assign(engine, &Fq2{c0: Fq::zero(), c1: Fq::one(engine)}); - } else { - alpha.add_assign(engine, &Fq2::one(engine)); - alpha = alpha.pow(engine, &engine.fqparams.modulus_minus_1_over_2); - a1.mul_assign(engine, &alpha); - } - - Some(a1) - } - } - } -} - -impl Field for Fq2 -{ - fn zero() -> Self { - Fq2 { - c0: Fq::zero(), - c1: Fq::zero() - } - } - - fn one(engine: &Bls381) -> Self { - Fq2 { - c0: Fq::one(engine), - c1: Fq::zero() - } - } - - fn random(engine: &Bls381, rng: &mut R) -> Self { - Fq2 { - c0: Fq::random(engine, rng), - c1: Fq::random(engine, rng) - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() - } - - fn double(&mut self, engine: &Bls381) { - self.c0.double(engine); - self.c1.double(engine); - } - - fn negate(&mut self, engine: &Bls381) { - self.c0.negate(engine); - self.c1.negate(engine); - } - - fn add_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.add_assign(engine, &other.c0); - self.c1.add_assign(engine, &other.c1); - } - - fn sub_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.sub_assign(engine, &other.c0); - self.c1.sub_assign(engine, &other.c1); - } - - fn frobenius_map(&mut self, e: &Bls381, power: usize) - { - self.c1.mul_assign(e, &e.frobenius_coeff_fq2[power % 2]); - } - - fn square(&mut self, engine: &Bls381) { - let mut ab = self.c0; - ab.mul_assign(engine, &self.c1); - let mut c0c1 = self.c0; - c0c1.add_assign(engine, &self.c1); - let mut c0 = self.c1; - c0.negate(engine); - c0.add_assign(engine, &self.c0); - c0.mul_assign(engine, &c0c1); - c0.sub_assign(engine, &ab); - self.c1 = ab; - self.c1.add_assign(engine, &ab); - c0.add_assign(engine, &ab); - self.c0 = c0; - } - - fn mul_assign(&mut self, engine: &Bls381, other: &Self) { - let mut aa = self.c0; - aa.mul_assign(engine, &other.c0); - let mut bb = self.c1; - bb.mul_assign(engine, &other.c1); - let mut o = other.c0; - o.add_assign(engine, &other.c1); - self.c1.add_assign(engine, &self.c0); - self.c1.mul_assign(engine, &o); - self.c1.sub_assign(engine, &aa); - self.c1.sub_assign(engine, &bb); - self.c0 = aa; - self.c0.sub_assign(engine, &bb); - } - - fn inverse(&self, engine: &Bls381) -> Option { - let mut t1 = self.c1; - t1.square(engine); - let mut t0 = self.c0; - t0.square(engine); - t0.add_assign(engine, &t1); - t0.inverse(engine).map(|t| { - let mut tmp = Fq2 { - c0: self.c0, - c1: self.c1 - }; - tmp.c0.mul_assign(engine, &t); - tmp.c1.mul_assign(engine, &t); - tmp.c1.negate(engine); - - tmp - }) - } -} diff --git a/src/curves/bls381/fq6.rs b/src/curves/bls381/fq6.rs deleted file mode 100644 index b1119ffe2..000000000 --- a/src/curves/bls381/fq6.rs +++ /dev/null @@ -1,295 +0,0 @@ -use super::{Bls381, Fq2}; -use rand; -use super::Field; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Fq6 { - pub c0: Fq2, - pub c1: Fq2, - pub c2: Fq2 -} - -impl Fq6 { - pub fn mul_by_nonresidue(&mut self, e: &Bls381) { - use std::mem::swap; - swap(&mut self.c0, &mut self.c1); - swap(&mut self.c0, &mut self.c2); - - self.c0.mul_by_nonresidue(e); - } - - pub fn mul_by_1(&mut self, e: &Bls381, c1: &Fq2) - { - let mut b_b = self.c1; - b_b.mul_assign(e, c1); - - let mut t1 = *c1; - { - let mut tmp = self.c1; - tmp.add_assign(e, &self.c2); - - t1.mul_assign(e, &tmp); - t1.sub_assign(e, &b_b); - t1.mul_by_nonresidue(e); - } - - let mut t2 = *c1; - { - let mut tmp = self.c0; - tmp.add_assign(e, &self.c1); - - t2.mul_assign(e, &tmp); - t2.sub_assign(e, &b_b); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = b_b; - } - - pub fn mul_by_01(&mut self, e: &Bls381, c0: &Fq2, c1: &Fq2) - { - let mut a_a = self.c0; - let mut b_b = self.c1; - a_a.mul_assign(e, c0); - b_b.mul_assign(e, c1); - - let mut t1 = *c1; - { - let mut tmp = self.c1; - tmp.add_assign(e, &self.c2); - - t1.mul_assign(e, &tmp); - t1.sub_assign(e, &b_b); - t1.mul_by_nonresidue(e); - t1.add_assign(e, &a_a); - } - - let mut t3 = *c0; - { - let mut tmp = self.c0; - tmp.add_assign(e, &self.c2); - - t3.mul_assign(e, &tmp); - t3.sub_assign(e, &a_a); - t3.add_assign(e, &b_b); - } - - let mut t2 = *c0; - t2.add_assign(e, c1); - { - let mut tmp = self.c0; - tmp.add_assign(e, &self.c1); - - t2.mul_assign(e, &tmp); - t2.sub_assign(e, &a_a); - t2.sub_assign(e, &b_b); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = t3; - } -} - -impl Field for Fq6 -{ - fn zero() -> Self { - Fq6 { - c0: Fq2::zero(), - c1: Fq2::zero(), - c2: Fq2::zero() - } - } - - fn one(engine: &Bls381) -> Self { - Fq6 { - c0: Fq2::one(engine), - c1: Fq2::zero(), - c2: Fq2::zero() - } - } - - fn random(engine: &Bls381, rng: &mut R) -> Self { - Fq6 { - c0: Fq2::random(engine, rng), - c1: Fq2::random(engine, rng), - c2: Fq2::random(engine, rng) - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero() - } - - fn double(&mut self, engine: &Bls381) { - self.c0.double(engine); - self.c1.double(engine); - self.c2.double(engine); - } - - fn negate(&mut self, engine: &Bls381) { - self.c0.negate(engine); - self.c1.negate(engine); - self.c2.negate(engine); - } - - fn add_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.add_assign(engine, &other.c0); - self.c1.add_assign(engine, &other.c1); - self.c2.add_assign(engine, &other.c2); - } - - fn sub_assign(&mut self, engine: &Bls381, other: &Self) { - self.c0.sub_assign(engine, &other.c0); - self.c1.sub_assign(engine, &other.c1); - self.c2.sub_assign(engine, &other.c2); - } - - fn frobenius_map(&mut self, e: &Bls381, power: usize) - { - self.c0.frobenius_map(e, power); - self.c1.frobenius_map(e, power); - self.c2.frobenius_map(e, power); - - self.c1.mul_assign(e, &e.frobenius_coeff_fq6_c1[power % 6]); - self.c2.mul_assign(e, &e.frobenius_coeff_fq6_c2[power % 6]); - } - - fn square(&mut self, e: &Bls381) { - let mut s0 = self.c0; - s0.square(e); - let mut ab = self.c0; - ab.mul_assign(e, &self.c1); - let mut s1 = ab; - s1.double(e); - let mut s2 = self.c0; - s2.sub_assign(e, &self.c1); - s2.add_assign(e, &self.c2); - s2.square(e); - let mut bc = self.c1; - bc.mul_assign(e, &self.c2); - let mut s3 = bc; - s3.double(e); - let mut s4 = self.c2; - s4.square(e); - - self.c0 = s3; - self.c0.mul_by_nonresidue(e); - self.c0.add_assign(e, &s0); - - self.c1 = s4; - self.c1.mul_by_nonresidue(e); - self.c1.add_assign(e, &s1); - - self.c2 = s1; - self.c2.add_assign(e, &s2); - self.c2.add_assign(e, &s3); - self.c2.sub_assign(e, &s0); - self.c2.sub_assign(e, &s4); - } - - fn mul_assign(&mut self, e: &Bls381, other: &Self) { - let mut a_a = self.c0; - let mut b_b = self.c1; - let mut c_c = self.c2; - a_a.mul_assign(e, &other.c0); - b_b.mul_assign(e, &other.c1); - c_c.mul_assign(e, &other.c2); - - let mut t1 = other.c1; - t1.add_assign(e, &other.c2); - { - let mut tmp = self.c1; - tmp.add_assign(e, &self.c2); - - t1.mul_assign(e, &tmp); - t1.sub_assign(e, &b_b); - t1.sub_assign(e, &c_c); - t1.mul_by_nonresidue(e); - t1.add_assign(e, &a_a); - } - - let mut t3 = other.c0; - t3.add_assign(e, &other.c2); - { - let mut tmp = self.c0; - tmp.add_assign(e, &self.c2); - - t3.mul_assign(e, &tmp); - t3.sub_assign(e, &a_a); - t3.add_assign(e, &b_b); - t3.sub_assign(e, &c_c); - } - - let mut t2 = other.c0; - t2.add_assign(e, &other.c1); - { - let mut tmp = self.c0; - tmp.add_assign(e, &self.c1); - - t2.mul_assign(e, &tmp); - t2.sub_assign(e, &a_a); - t2.sub_assign(e, &b_b); - c_c.mul_by_nonresidue(e); - t2.add_assign(e, &c_c); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = t3; - } - - fn inverse(&self, e: &Bls381) -> Option { - let mut c0 = self.c2; - c0.mul_by_nonresidue(e); - c0.mul_assign(e, &self.c1); - c0.negate(e); - { - let mut c0s = self.c0; - c0s.square(e); - c0.add_assign(e, &c0s); - } - let mut c1 = self.c2; - c1.square(e); - c1.mul_by_nonresidue(e); - { - let mut c01 = self.c0; - c01.mul_assign(e, &self.c1); - c1.sub_assign(e, &c01); - } - let mut c2 = self.c1; - c2.square(e); - { - let mut c02 = self.c0; - c02.mul_assign(e, &self.c2); - c2.sub_assign(e, &c02); - } - - let mut tmp1 = self.c2; - tmp1.mul_assign(e, &c1); - let mut tmp2 = self.c1; - tmp2.mul_assign(e, &c2); - tmp1.add_assign(e, &tmp2); - tmp1.mul_by_nonresidue(e); - tmp2 = self.c0; - tmp2.mul_assign(e, &c0); - tmp1.add_assign(e, &tmp2); - - match tmp1.inverse(e) { - Some(t) => { - let mut tmp = Fq6 { - c0: t, - c1: t, - c2: t - }; - tmp.c0.mul_assign(e, &c0); - tmp.c1.mul_assign(e, &c1); - tmp.c2.mul_assign(e, &c2); - - Some(tmp) - }, - None => None - } - } -} diff --git a/src/curves/bls381/mod.rs b/src/curves/bls381/mod.rs deleted file mode 100644 index 2a5615107..000000000 --- a/src/curves/bls381/mod.rs +++ /dev/null @@ -1,1101 +0,0 @@ -use rand; -use std::fmt; - -use std::cmp::Ordering; -use std::borrow::Borrow; -use ::BitIterator; -use super::{ - Engine, - Group, - Curve, - CurveAffine, - CurveRepresentation, - PrimeField, - PrimeFieldRepr, - Field, - SnarkField, - SqrtField, - Convert, - Cow, - multiexp, - wnaf -}; - -use serde::ser::{Serialize, Serializer, SerializeTuple}; -use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error}; - -#[macro_use] -mod fp; -#[macro_use] -mod ec; - -mod fq2; -mod fq6; -mod fq12; -pub use self::fq2::Fq2; -pub use self::fq6::Fq6; -pub use self::fq12::Fq12; - -// The BLS parameter x for BLS12-381 is -0xd201000000010000 -const BLS_X: u64 = 0xd201000000010000; -const BLS_X_IS_NEGATIVE: bool = true; - -// Multiplicative generator of r-1 order, additionally chosen to be -// nonsquare, so that the root of unity can be used for Tonelli-Shanks -// square root. -const FR_MULTIPLICATIVE_GENERATOR: &'static str = "7"; -// Generator taken to the t'th power (r - 1 = 2^s * t with t odd) -const FR_ROOT_OF_UNITY: &'static str = "10238227357739495823651030575849232062558860180284477541189508159991286009131"; - -// y^2 = x^3 + b -const BLS_B: &'static str = "4"; - -// Generators for G1 and G2 -const BLS_G1_X: &'static str = "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507"; -const BLS_G1_Y: &'static str = "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569"; -const BLS_G2_X_C0: &'static str = "1468726562419257979478817182087966534126060822705880368502120176847060928972041501528146094283660107570228075847785"; -const BLS_G2_X_C1: &'static str = "192619896028380442851999297362581720263330513191716562546672373167036922975724849633269992752324699688798815266013"; -const BLS_G2_Y_C0: &'static str = "2403786323187906729693550489351819856705060824828191844887396442983655568083290027942568172155055249312505578112188"; -const BLS_G2_Y_C1: &'static str = "1887759871634257894151445480492390612163057076015645365125874782999431522408747359398458417857763544644994493115328"; - -// Implementation of Fq -fp_impl!( - Fq = (3 mod 4), - engine = Bls381, - params = fqparams: FqParams, - arith = fq_arith, - repr = FqRepr, - limbs = 6, - // q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 - modulus = [ 0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a ], - // (2^ 384 ) mod q - r1 = [ 0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493 ], - // (2^ 384 )^2 mod q - r2 = [ 0xf4df1f341c341746, 0x0a76e6a609d104f1, 0x8de5476c4c95b6d5, 0x67eb88a9939d83c0, 0x9a793e85b519952d, 0x11988fe592cae3aa ], - modulus_minus_3_over_4 = [ 0xee7fbfffffffeaaa, 0x07aaffffac54ffff, 0xd9cc34a83dac3d89, 0xd91dd2e13ce144af, 0x92c6e9ed90d2eb35, 0x0680447a8e5ff9a6 ], - modulus_minus_1_over_2 = [ 0xdcff7fffffffd555, 0x0f55ffff58a9ffff, 0xb39869507b587b12, 0xb23ba5c279c2895f, 0x258dd3db21a5d66b, 0x0d0088f51cbff34d ], - // - q ^-1 mod 2^64 - inv = 0x89f3fffcfffcfffd -); - -// Implementation of Fr -fp_impl!( - Fr = (1 mod 16), - engine = Bls381, - params = frparams: FrParams, - arith = fr_arith, - repr = FrRepr, - limbs = 4, - // r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 - modulus = [ 0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48 ], - // (2^ 256 ) mod r - r1 = [ 0x00000001fffffffe, 0x5884b7fa00034802, 0x998c4fefecbc4ff5, 0x1824b159acc5056f ], - // (2^ 256 )^2 mod r - r2 = [ 0xc999e990f3f29c6d, 0x2b6cedcb87925c23, 0x05d314967254398f, 0x0748d9d99f59ff11 ], - modulus_minus_1_over_2 = [ 0x7fffffff80000000, 0xa9ded2017fff2dff, 0x199cec0404d0ec02, 0x39f6d3a994cebea4 ], - // r - 1 = 2^s * t with t odd - s = 32 , - t = [ 0xfffe5bfeffffffff, 0x09a1d80553bda402, 0x299d7d483339d808, 0x0000000073eda753 ], - t_plus_1_over_2 = [ 0x7fff2dff80000000, 0x04d0ec02a9ded201, 0x94cebea4199cec04, 0x0000000039f6d3a9 ], - // - r ^-1 mod 2^64 - inv = 0xfffffffeffffffff -); - -impl Group for Fr { - fn group_zero(_: &Bls381) -> Fr { - Fr::zero() - } - fn group_mul_assign(&mut self, e: &Bls381, scalar: &Fr) { - self.mul_assign(e, scalar); - } - fn group_add_assign(&mut self, e: &Bls381, other: &Self) { - self.add_assign(e, other); - } - fn group_sub_assign(&mut self, e: &Bls381, other: &Self) { - self.sub_assign(e, other); - } -} - -curve_impl!(Bls381, G1, G1Affine, G1Affine, G1Uncompressed, G1Params, g1params, Fq, Fr); -curve_impl!(Bls381, G2, G2Affine, G2Prepared, G2Uncompressed, G2Params, g2params, Fq2, Fr); - -pub struct G1PointData([u8; 96]); -pub struct G2PointData([u8; 192]); - -impl Serialize for G1PointData { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - let mut seq = serializer.serialize_tuple(96)?; - for i in self.0.iter() { - seq.serialize_element(i)?; - } - seq.end() - } -} - -impl<'a> Deserialize<'a> for G1PointData { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - struct G1PointVisitor; - - impl<'a> Visitor<'a> for G1PointVisitor { - type Value = G1PointData; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected 96-byte G1 point X, Y coordinates") - } - - fn visit_seq(self, mut seq: A) -> Result - where A: SeqAccess<'a> - { - let mut tmp = [0; 96]; - for i in &mut tmp[..] { - if let Some(v) = seq.next_element()? { - *i = v; - } else { - return Err(A::Error::custom("not enough bytes")) - } - } - - Ok(G1PointData(tmp)) - } - } - - deserializer.deserialize_tuple(96, G1PointVisitor) - } -} - -impl Serialize for G2PointData { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - let mut seq = serializer.serialize_tuple(192)?; - for i in self.0.iter() { - seq.serialize_element(i)?; - } - seq.end() - } -} - -impl<'a> Deserialize<'a> for G2PointData { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - struct G2PointVisitor; - - impl<'a> Visitor<'a> for G2PointVisitor { - type Value = G2PointData; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected 192-byte G2 point X, Y coordinates") - } - - fn visit_seq(self, mut seq: A) -> Result - where A: SeqAccess<'a> - { - let mut tmp = [0; 192]; - for i in &mut tmp[..] { - if let Some(v) = seq.next_element()? { - *i = v; - } else { - return Err(A::Error::custom("not enough bytes")) - } - } - - Ok(G2PointData(tmp)) - } - } - - deserializer.deserialize_tuple(192, G2PointVisitor) - } -} - -pub enum G1Uncompressed { - Point(G1PointData), - Infinity -} -pub enum G2Uncompressed { - Point(G2PointData), - Infinity -} - -impl Serialize for G1Uncompressed { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - let mut tup = serializer.serialize_tuple(2)?; - - match *self { - G1Uncompressed::Infinity => { - tup.serialize_element(&0u8)?; - tup.serialize_element(&())?; - tup.end() - }, - G1Uncompressed::Point(ref v) => { - tup.serialize_element(&4u8)?; - tup.serialize_element(v)?; - tup.end() - } - } - } -} - -impl<'a> Deserialize<'a> for G1Uncompressed { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - use std::fmt; - - struct G1Visitor; - - impl<'a> Visitor<'a> for G1Visitor { - type Value = G1Uncompressed; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected uncompressed G1 element") - } - - fn visit_seq(self, mut seq: A) -> Result - where A: SeqAccess<'a> - { - if let Some(t) = seq.next_element::()? { - if t == 0 { - if let Some(()) = seq.next_element::<()>()? { - Ok(G1Uncompressed::Infinity) - } else { - Err(A::Error::custom("expected null coordinate")) - } - } else if t == 4 { - if let Some(p) = seq.next_element::()? { - Ok(G1Uncompressed::Point(p)) - } else { - Err(A::Error::custom("expected X, Y coordinate")) - } - } else { - Err(A::Error::custom("expected IEEE prefix for uncompressed G1 element")) - } - } else { - Err(A::Error::custom("expected IEEE prefix for uncompressed G1 element")) - } - } - } - - let v = G1Visitor; - - deserializer.deserialize_tuple(2, v) - } -} - -impl Serialize for G2Uncompressed { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - let mut tup = serializer.serialize_tuple(2)?; - - match *self { - G2Uncompressed::Infinity => { - tup.serialize_element(&0u8)?; - tup.serialize_element(&())?; - tup.end() - }, - G2Uncompressed::Point(ref v) => { - tup.serialize_element(&4u8)?; - tup.serialize_element(v)?; - tup.end() - } - } - } -} - -impl<'a> Deserialize<'a> for G2Uncompressed { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> - { - use std::fmt; - - struct G2Visitor; - - impl<'a> Visitor<'a> for G2Visitor { - type Value = G2Uncompressed; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected uncompressed G2 element") - } - - fn visit_seq(self, mut seq: A) -> Result - where A: SeqAccess<'a> - { - if let Some(t) = seq.next_element::()? { - if t == 0 { - if let Some(()) = seq.next_element::<()>()? { - Ok(G2Uncompressed::Infinity) - } else { - Err(A::Error::custom("expected null coordinate")) - } - } else if t == 4 { - if let Some(p) = seq.next_element::()? { - Ok(G2Uncompressed::Point(p)) - } else { - Err(A::Error::custom("expected X, Y coordinate")) - } - } else { - Err(A::Error::custom("expected IEEE prefix for uncompressed G2 element")) - } - } else { - Err(A::Error::custom("expected IEEE prefix for uncompressed G2 element")) - } - } - } - - let v = G2Visitor; - - deserializer.deserialize_tuple(2, v) - } -} - -impl CurveRepresentation for G1Uncompressed { - type Affine = G1Affine; - - fn to_affine_unchecked(&self, e: &Bls381) -> Result { - match self { - &G1Uncompressed::Infinity => { - Ok(G1::zero(e).to_affine(e)) - }, - &G1Uncompressed::Point(ref bytes) => { - use byteorder::{ReadBytesExt, BigEndian}; - - let mut bytes = &bytes.0[..]; - - let mut x = [0; 6]; - let mut y = [0; 6]; - - for x in x.iter_mut().rev() { - *x = bytes.read_u64::().unwrap(); - } - for y in y.iter_mut().rev() { - *y = bytes.read_u64::().unwrap(); - } - - Ok(G1Affine { - x: try!(Fq::from_repr(e, FqRepr(x))), - y: try!(Fq::from_repr(e, FqRepr(y))), - infinity: false - }) - } - } - } -} - -impl CurveRepresentation for G2Uncompressed { - type Affine = G2Affine; - - fn to_affine_unchecked(&self, e: &Bls381) -> Result { - match self { - &G2Uncompressed::Infinity => { - Ok(G2::zero(e).to_affine(e)) - }, - &G2Uncompressed::Point(ref bytes) => { - use byteorder::{ReadBytesExt, BigEndian}; - - let mut bytes = &bytes.0[..]; - - let mut x = [0; 12]; - let mut y = [0; 12]; - - for x in x.iter_mut().rev() { - *x = bytes.read_u64::().unwrap(); - } - for y in y.iter_mut().rev() { - *y = bytes.read_u64::().unwrap(); - } - - if let (Some(x_c1), x_c0) = fq_arith::divrem(&x, &e.fqparams.modulus) { - if let (Some(y_c1), y_c0) = fq_arith::divrem(&y, &e.fqparams.modulus) { - return Ok(G2Affine { - x: Fq2 { - c0: try!(Fq::from_repr(e, FqRepr(x_c0))), - c1: try!(Fq::from_repr(e, FqRepr(x_c1))) - }, - y: Fq2 { - c0: try!(Fq::from_repr(e, FqRepr(y_c0))), - c1: try!(Fq::from_repr(e, FqRepr(y_c1))) - }, - infinity: false - }); - } - } - - Err(()) - } - } - } -} - -impl G1Uncompressed { - fn from_affine(p: &G1Affine, e: &Bls381) -> Self { - if p.infinity { - G1Uncompressed::Infinity - } else { - use byteorder::{WriteBytesExt, BigEndian}; - - let mut tmp = [0; 96]; - - { - let mut tmp = &mut tmp[0..]; - for &digit in p.x.into_repr(e).0.iter().rev() { - tmp.write_u64::(digit).unwrap(); - } - } - - { - let mut tmp = &mut tmp[48..]; - for &digit in p.y.into_repr(e).0.iter().rev() { - tmp.write_u64::(digit).unwrap(); - } - } - - G1Uncompressed::Point(G1PointData(tmp)) - } - } -} - -impl G2Uncompressed { - fn from_affine(p: &G2Affine, e: &Bls381) -> Self { - if p.infinity { - G2Uncompressed::Infinity - } else { - use byteorder::{WriteBytesExt, BigEndian}; - - let mut tmp = [0; 192]; - - { - let mut tmp = &mut tmp[0..]; - let mut x = [0; 12]; - fq_arith::mac3(&mut x, &p.x.c1.into_repr(e).0, &e.fqparams.modulus); - fq_arith::add_carry(&mut x, &p.x.c0.into_repr(e).0); - - for &digit in x.iter().rev() { - tmp.write_u64::(digit).unwrap(); - } - } - - { - let mut tmp = &mut tmp[96..]; - let mut y = [0; 12]; - fq_arith::mac3(&mut y, &p.y.c1.into_repr(e).0, &e.fqparams.modulus); - fq_arith::add_carry(&mut y, &p.y.c0.into_repr(e).0); - - for &digit in y.iter().rev() { - tmp.write_u64::(digit).unwrap(); - } - } - - G2Uncompressed::Point(G2PointData(tmp)) - } - } -} - -impl G1Affine { - fn from_engine(_: &Bls381, p: G1Affine) -> Self { - p - } -} - -#[derive(Clone)] -pub struct G2Prepared { - coeffs: Vec<(Fq2, Fq2, Fq2)>, - infinity: bool -} - -impl G2Prepared { - fn is_zero(&self) -> bool { - self.infinity - } - - fn from_engine(e: &Bls381, q: G2Affine) -> Self { - if q.is_zero() { - return G2Prepared { - coeffs: vec![], - infinity: true - } - } - - fn doubling_step( - e: &Bls381, - r: &mut G2 - ) -> (Fq2, Fq2, Fq2) - { - // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf - let mut tmp0 = r.x; - tmp0.square(e); - - let mut tmp1 = r.y; - tmp1.square(e); - - let mut tmp2 = tmp1; - tmp2.square(e); - - let mut tmp3 = tmp1; - tmp3.add_assign(e, &r.x); - tmp3.square(e); - tmp3.sub_assign(e, &tmp0); - tmp3.sub_assign(e, &tmp2); - tmp3.double(e); - - let mut tmp4 = tmp0; - tmp4.double(e); - tmp4.add_assign(e, &tmp0); - - let mut tmp6 = r.x; - tmp6.add_assign(e, &tmp4); - - let mut tmp5 = tmp4; - tmp5.square(e); - - let mut zsquared = r.z; - zsquared.square(e); - - r.x = tmp5; - r.x.sub_assign(e, &tmp3); - r.x.sub_assign(e, &tmp3); - - r.z.add_assign(e, &r.y); - r.z.square(e); - r.z.sub_assign(e, &tmp1); - r.z.sub_assign(e, &zsquared); - - r.y = tmp3; - r.y.sub_assign(e, &r.x); - r.y.mul_assign(e, &tmp4); - - tmp2.double(e); - tmp2.double(e); - tmp2.double(e); - - r.y.sub_assign(e, &tmp2); - - tmp3 = tmp4; - tmp3.mul_assign(e, &zsquared); - tmp3.double(e); - tmp3.negate(e); - - tmp6.square(e); - tmp6.sub_assign(e, &tmp0); - tmp6.sub_assign(e, &tmp5); - - tmp1.double(e); - tmp1.double(e); - - tmp6.sub_assign(e, &tmp1); - - tmp0 = r.z; - tmp0.mul_assign(e, &zsquared); - tmp0.double(e); - - (tmp0, tmp3, tmp6) - } - - fn addition_step( - e: &Bls381, - r: &mut G2, - q: &G2Affine - ) -> (Fq2, Fq2, Fq2) - { - // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf - let mut zsquared = r.z; - zsquared.square(e); - - let mut ysquared = q.y; - ysquared.square(e); - - let mut t0 = zsquared; - t0.mul_assign(e, &q.x); - - let mut t1 = q.y; - t1.add_assign(e, &r.z); - t1.square(e); - t1.sub_assign(e, &ysquared); - t1.sub_assign(e, &zsquared); - t1.mul_assign(e, &zsquared); - - let mut t2 = t0; - t2.sub_assign(e, &r.x); - - let mut t3 = t2; - t3.square(e); - - let mut t4 = t3; - t4.double(e); - t4.double(e); - - let mut t5 = t4; - t5.mul_assign(e, &t2); - - let mut t6 = t1; - t6.sub_assign(e, &r.y); - t6.sub_assign(e, &r.y); - - let mut t9 = t6; - t9.mul_assign(e, &q.x); - - let mut t7 = t4; - t7.mul_assign(e, &r.x); - - r.x = t6; - r.x.square(e); - r.x.sub_assign(e, &t5); - r.x.sub_assign(e, &t7); - r.x.sub_assign(e, &t7); - - r.z.add_assign(e, &t2); - r.z.square(e); - r.z.sub_assign(e, &zsquared); - r.z.sub_assign(e, &t3); - - let mut t10 = q.y; - t10.add_assign(e, &r.z); - - let mut t8 = t7; - t8.sub_assign(e, &r.x); - t8.mul_assign(e, &t6); - - t0 = r.y; - t0.mul_assign(e, &t5); - t0.double(e); - - r.y = t8; - r.y.sub_assign(e, &t0); - - t10.square(e); - t10.sub_assign(e, &ysquared); - - let mut ztsquared = r.z; - ztsquared.square(e); - - t10.sub_assign(e, &ztsquared); - - t9.double(e); - t9.sub_assign(e, &t10); - - t10 = r.z; - t10.double(e); - - t6.negate(e); - - t1 = t6; - t1.double(e); - - (t10, t1, t9) - } - - let mut coeffs = vec![]; - let mut r = q.to_jacobian(e); - - let mut found_one = false; - for i in BitIterator::new(&[BLS_X >> 1]) { - if !found_one { - found_one = i; - continue; - } - - coeffs.push(doubling_step(e, &mut r)); - - if i { - coeffs.push(addition_step(e, &mut r, &q)); - } - } - - coeffs.push(doubling_step(e, &mut r)); - - G2Prepared { - coeffs: coeffs, - infinity: false - } - } -} - -#[derive(Clone)] -pub struct Bls381 { - fqparams: FqParams, - frparams: FrParams, - g1params: G1Params, - g2params: G2Params, - frobenius_coeff_fq2: [Fq; 2], - frobenius_coeff_fq6_c1: [Fq2; 6], - frobenius_coeff_fq6_c2: [Fq2; 6], - frobenius_coeff_fq12: [Fq2; 12] -} - -thread_local!(static ENGINE: Bls381 = Bls381::new()); - -impl SnarkField for Fr { - fn s(e: &Bls381) -> u64 { - e.frparams.s - } - fn multiplicative_generator(e: &Bls381) -> Self { - e.frparams.multiplicative_generator - } - fn root_of_unity(e: &Bls381) -> Self { - e.frparams.root_of_unity - } -} - -impl Engine for Bls381 { - type Fq = Fq; - type Fr = Fr; - type Fqe = Fq2; - type Fqk = Fq12; - - type G1 = G1; - type G2 = G2; - - fn with FnOnce(&'a Self) -> R>(cb: F) -> R { - ENGINE.with(|e| { - cb(e) - }) - } - - fn new() -> Bls381 { - let mut tmp = Bls381 { - fqparams: FqParams::partial_init(), - frparams: FrParams::partial_init(), - g1params: G1Params { - zero: G1 { x: Fq::zero(), y: Fq::zero(), z: Fq::zero() }, - one: G1 { x: Fq::zero(), y: Fq::zero(), z: Fq::zero() }, - coeff_b: Fq::zero(), - windows: vec![11, 35, 110], - batch_windows: (4, vec![2, 3, 10, 20, 53, 111, 266, 426, 1273, 4742, 6054, 6054, 6054]) - }, - g2params: G2Params { - zero: G2 { x: Fq2::zero(), y: Fq2::zero(), z: Fq2::zero() }, - one: G2 { x: Fq2::zero(), y: Fq2::zero(), z: Fq2::zero() }, - coeff_b: Fq2::zero(), - windows: vec![11, 35, 114], - batch_windows: (4, vec![2, 4, 10, 29, 54, 120, 314, 314, 314, 314]) - }, - frobenius_coeff_fq2: [Fq::zero(); 2], - frobenius_coeff_fq6_c1: [Fq2::zero(); 6], - frobenius_coeff_fq6_c2: [Fq2::zero(); 6], - frobenius_coeff_fq12: [Fq2::zero(); 12] - }; - - // Initialize the base 10 numbers for from_str - tmp.fqparams.base10 = FqParams::base10(&tmp); - tmp.frparams.base10 = FrParams::base10(&tmp); - - // Initialize field parameters - tmp.frparams.multiplicative_generator = Fr::from_str(&tmp, FR_MULTIPLICATIVE_GENERATOR).unwrap(); - tmp.frparams.root_of_unity = Fr::from_str(&tmp, FR_ROOT_OF_UNITY).unwrap(); - - tmp.fqparams.num_bits = 381; - tmp.frparams.num_bits = 255; - - // Initialize the coefficients for the Frobenius map - tmp.frobenius_coeff_fq2[0] = Fq::from_str(&tmp, "1").unwrap(); - tmp.frobenius_coeff_fq2[1] = Fq::from_str(&tmp, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786").unwrap(); - tmp.frobenius_coeff_fq6_c1[0] = Fq2 { - c0: Fq::from_str(&tmp, "1").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c1[1] = Fq2 { - c0: Fq::from_str(&tmp, "0").unwrap(), - c1: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436").unwrap() - }; - tmp.frobenius_coeff_fq6_c1[2] = Fq2 { - c0: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c1[3] = Fq2 { - c0: Fq::from_str(&tmp, "0").unwrap(), - c1: Fq::from_str(&tmp, "1").unwrap() - }; - tmp.frobenius_coeff_fq6_c1[4] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c1[5] = Fq2 { - c0: Fq::from_str(&tmp, "0").unwrap(), - c1: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[0] = Fq2 { - c0: Fq::from_str(&tmp, "1").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[1] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[2] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[3] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[4] = Fq2 { - c0: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq6_c2[5] = Fq2 { - c0: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[0] = Fq2 { - c0: Fq::from_str(&tmp, "1").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[1] = Fq2 { - c0: Fq::from_str(&tmp, "3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760").unwrap(), - c1: Fq::from_str(&tmp, "151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027").unwrap() - }; - tmp.frobenius_coeff_fq12[2] = Fq2 { - c0: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[3] = Fq2 { - c0: Fq::from_str(&tmp, "2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530").unwrap(), - c1: Fq::from_str(&tmp, "1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257").unwrap() - }; - tmp.frobenius_coeff_fq12[4] = Fq2 { - c0: Fq::from_str(&tmp, "793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[5] = Fq2 { - c0: Fq::from_str(&tmp, "3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557").unwrap(), - c1: Fq::from_str(&tmp, "877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230").unwrap() - }; - tmp.frobenius_coeff_fq12[6] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[7] = Fq2 { - c0: Fq::from_str(&tmp, "151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027").unwrap(), - c1: Fq::from_str(&tmp, "3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760").unwrap() - }; - tmp.frobenius_coeff_fq12[8] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[9] = Fq2 { - c0: Fq::from_str(&tmp, "1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257").unwrap(), - c1: Fq::from_str(&tmp, "2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530").unwrap() - }; - tmp.frobenius_coeff_fq12[10] = Fq2 { - c0: Fq::from_str(&tmp, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437").unwrap(), - c1: Fq::from_str(&tmp, "0").unwrap() - }; - tmp.frobenius_coeff_fq12[11] = Fq2 { - c0: Fq::from_str(&tmp, "877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230").unwrap(), - c1: Fq::from_str(&tmp, "3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557").unwrap() - }; - - // G1 parameters - tmp.g1params.zero.y = Fq::one(&tmp); - tmp.g1params.coeff_b = Fq::from_str(&tmp, BLS_B).unwrap(); - tmp.g1params.one.x = Fq::from_str(&tmp, BLS_G1_X).unwrap(); - tmp.g1params.one.y = Fq::from_str(&tmp, BLS_G1_Y).unwrap(); - tmp.g1params.one.z = Fq::one(&tmp); - - // G2 parameters - tmp.g2params.zero.y = Fq2::one(&tmp); - tmp.g2params.coeff_b = Fq2 { - c0: Fq::from_str(&tmp, BLS_B).unwrap(), - c1: Fq::from_str(&tmp, BLS_B).unwrap() - }; - tmp.g2params.one.x = Fq2 { - c0: Fq::from_str(&tmp, BLS_G2_X_C0).unwrap(), - c1: Fq::from_str(&tmp, BLS_G2_X_C1).unwrap() - }; - tmp.g2params.one.y = Fq2 { - c0: Fq::from_str(&tmp, BLS_G2_Y_C0).unwrap(), - c1: Fq::from_str(&tmp, BLS_G2_Y_C1).unwrap() - }; - tmp.g2params.one.z = Fq2::one(&tmp); - - tmp - } - - fn final_exponentiation(&self, r: &Fq12) -> Fq12 { - let mut f1 = *r; - f1.unitary_inverse(self); - let mut f2 = r.inverse(self).unwrap(); - let mut r = f1; - r.mul_assign(self, &f2); - f2 = r; - r.frobenius_map(self, 2); - r.mul_assign(self, &f2); - - fn exp_by_x(e: &Bls381, f: &mut Fq12, x: u64) - { - *f = f.pow(e, &[x]); - if BLS_X_IS_NEGATIVE { - f.unitary_inverse(e); - } - } - - let mut x = BLS_X; - let mut y0 = r; - y0.square(self); - let mut y1 = y0; - exp_by_x(self, &mut y1, x); - x >>= 1; - let mut y2 = y1; - exp_by_x(self, &mut y2, x); - x <<= 1; - let mut y3 = r; - y3.unitary_inverse(self); - y1.mul_assign(self, &y3); - y1.unitary_inverse(self); - y1.mul_assign(self, &y2); - y2 = y1; - exp_by_x(self, &mut y2, x); - y3 = y2; - exp_by_x(self, &mut y3, x); - y1.unitary_inverse(self); - y3.mul_assign(self, &y1); - y1.unitary_inverse(self); - y1.frobenius_map(self, 3); - y2.frobenius_map(self, 2); - y1.mul_assign(self, &y2); - y2 = y3; - exp_by_x(self, &mut y2, x); - y2.mul_assign(self, &y0); - y2.mul_assign(self, &r); - y1.mul_assign(self, &y2); - y2 = y3; - y2.frobenius_map(self, 1); - y1.mul_assign(self, &y2); - y1 - } - - fn miller_loop<'a, I>(&self, i: I) -> Self::Fqk - where I: IntoIterator>::Prepared, - &'a >::Prepared - )> - { - let mut pairs = vec![]; - for &(p, q) in i { - if !p.is_zero() && !q.is_zero() { - pairs.push((p, q.coeffs.iter())); - } - } - - // Twisting isomorphism from E to E' - fn ell( - e: &Bls381, - f: &mut Fq12, - coeffs: &(Fq2, Fq2, Fq2), - p: &G1Affine - ) - { - let mut c0 = coeffs.0; - let mut c1 = coeffs.1; - - c0.c0.mul_assign(e, &p.y); - c0.c1.mul_assign(e, &p.y); - - c1.c0.mul_assign(e, &p.x); - c1.c1.mul_assign(e, &p.x); - - // Sparse multiplication in Fq12 - f.mul_by_015(e, &coeffs.2, &c1, &c0); - } - - let mut f = Fq12::one(self); - - let mut found_one = false; - for i in BitIterator::new(&[BLS_X >> 1]) { - if !found_one { - found_one = i; - continue; - } - - for &mut (p, ref mut coeffs) in &mut pairs { - ell(self, &mut f, coeffs.next().unwrap(), p); - } - - if i { - for &mut (p, ref mut coeffs) in &mut pairs { - ell(self, &mut f, coeffs.next().unwrap(), p); - } - } - - f.square(self); - } - - for &mut (p, ref mut coeffs) in &mut pairs { - ell(self, &mut f, coeffs.next().unwrap(), p); - } - - f - } - - fn batchexp, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>) - { - use crossbeam; - use num_cpus; - - assert_eq!(g.len(), scalars.as_ref().len()); - - let chunk = (g.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for (g, s) in g.chunks_mut(chunk).zip(scalars.as_ref().chunks(chunk)) { - scope.spawn(move || { - let mut table = wnaf::WindowTable::new(self, G::zero(self), 2); - let mut scratch = wnaf::WNAFTable::new(); - - for (g, s) in g.iter_mut().zip(s.iter()) { - let mut s = *s; - match coeff { - Some(coeff) => { - s.mul_assign(self, coeff); - }, - _ => {} - }; - *g = g.to_jacobian(self) - .optimal_exp(self, s.into_repr(self), &mut table, &mut scratch) - .to_affine(self); - } - }); - } - }); - } - - fn batch_baseexp, S: AsRef<[Self::Fr]>>(&self, table: &wnaf::WindowTable, s: S) -> Vec - { - use crossbeam; - use num_cpus; - - let s = s.as_ref(); - let mut ret = vec![G::zero(self).to_affine(self); s.len()]; - - crossbeam::scope(|scope| { - let chunk = (s.len() / num_cpus::get()) + 1; - - for (s, b) in s.chunks(chunk).zip(ret.chunks_mut(chunk)) { - scope.spawn(move || { - let mut scratch = wnaf::WNAFTable::new(); - - for (s, b) in s.iter().zip(b.iter_mut()) { - scratch.set_scalar(table, s.into_repr(self)); - *b = table.exp(self, &scratch).to_affine(self); - } - }); - } - }); - - ret - } - - fn multiexp>(&self, g: &[G::Affine], s: &[Fr]) -> Result { - super::multiexp::perform_multiexp(self, g, s) - } -} - -#[cfg(test)] -mod tests; diff --git a/src/curves/bls381/tests/g1_serialized.bin b/src/curves/bls381/tests/g1_serialized.bin deleted file mode 100644 index c117a7030..000000000 Binary files a/src/curves/bls381/tests/g1_serialized.bin and /dev/null differ diff --git a/src/curves/bls381/tests/g2_serialized.bin b/src/curves/bls381/tests/g2_serialized.bin deleted file mode 100644 index 60c385205..000000000 Binary files a/src/curves/bls381/tests/g2_serialized.bin and /dev/null differ diff --git a/src/curves/bls381/tests/mod.rs b/src/curves/bls381/tests/mod.rs deleted file mode 100644 index 29d98ea58..000000000 --- a/src/curves/bls381/tests/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -extern crate bincode; - -use curves::*; -use super::*; - -fn test_vectors>(e: &E, expected: &[u8]) { - let mut bytes = vec![]; - let mut acc = G::zero(e); - let mut expected_reader = expected; - - for _ in 0..10000 { - { - let acc = acc.to_affine(e); - let exp: >::Uncompressed = - bincode::deserialize_from(&mut expected_reader, bincode::Infinite).unwrap(); - - assert!(acc == exp.to_affine(e).unwrap()); - - let acc = acc.to_uncompressed(e); - bincode::serialize_into(&mut bytes, &acc, bincode::Infinite).unwrap(); - } - acc.double(e); - acc.add_assign(e, &G::one(e)); - } - - assert_eq!(&bytes[..], expected); -} - -#[test] -fn g1_serialization_test_vectors() { - let engine = Bls381::new(); - - test_vectors::(&engine, include_bytes!("g1_serialized.bin")); -} - -#[test] -fn g2_serialization_test_vectors() { - let engine = Bls381::new(); - - test_vectors::(&engine, include_bytes!("g2_serialized.bin")); -} diff --git a/src/curves/domain.rs b/src/curves/domain.rs deleted file mode 100644 index de0779fff..000000000 --- a/src/curves/domain.rs +++ /dev/null @@ -1,374 +0,0 @@ -use super::{Engine, Field, SnarkField, PrimeField, Group}; -use crossbeam; -use num_cpus; - -pub struct EvaluationDomain { - pub m: u64, - exp: u64, - omega: E::Fr, - omegainv: E::Fr, - geninv: E::Fr, - minv: E::Fr -} - -impl EvaluationDomain { - pub fn new(e: &E, needed: u64) -> Self { - if needed > 268435456 { - panic!("circuit depths larger than 2^28 are not supported"); - } - - let mut m = 1; - let mut exp = 0; - while m < needed { - m *= 2; - exp += 1; - - assert!(exp < E::Fr::s(e)); - } - - let mut omega = E::Fr::root_of_unity(e); - for _ in exp..E::Fr::s(e) { - omega.square(e); - } - - EvaluationDomain { - m: m, - exp: exp, - omega: omega, - omegainv: omega.inverse(e).unwrap(), - geninv: E::Fr::multiplicative_generator(e).inverse(e).unwrap(), - minv: E::Fr::from_u64(e, m).inverse(e).unwrap() - } - } - - pub fn z(&self, e: &E, tau: &E::Fr) -> E::Fr { - let mut tmp = tau.pow(e, &[self.m]); - tmp.sub_assign(e, &E::Fr::one(e)); - - tmp - } - - pub fn ifft>(&self, e: &E, v: &mut [T]) - { - assert!(v.len() == self.m as usize); - best_fft(e, v, &self.omegainv, self.exp); - - let chunk = (v.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for v in v.chunks_mut(chunk) { - scope.spawn(move || { - for v in v { - v.group_mul_assign(e, &self.minv); - } - }); - } - }); - } - - fn mul_coset(&self, e: &E, v: &mut [E::Fr], g: &E::Fr) - { - let chunk = (v.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for (i, v) in v.chunks_mut(chunk).enumerate() { - scope.spawn(move || { - let mut u = g.pow(e, &[(i * chunk) as u64]); - for v in v.iter_mut() { - v.mul_assign(e, &u); - u.mul_assign(e, g); - } - }); - } - }); - } - - pub fn coset_fft(&self, e: &E, v: &mut [E::Fr]) - { - self.mul_coset(e, v, &E::Fr::multiplicative_generator(e)); - self.fft(e, v); - } - - pub fn icoset_fft(&self, e: &E, v: &mut [E::Fr]) - { - self.ifft(e, v); - self.mul_coset(e, v, &self.geninv); - } - - pub fn divide_by_z_on_coset(&self, e: &E, v: &mut [E::Fr]) - { - let i = self.z(e, &E::Fr::multiplicative_generator(e)).inverse(e).unwrap(); - - let chunk = (v.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for v in v.chunks_mut(chunk) { - scope.spawn(move || { - for v in v { - v.mul_assign(e, &i); - } - }); - } - }); - } - - pub fn mul_assign(&self, e: &E, a: &mut [E::Fr], b: Vec) { - assert_eq!(a.len(), b.len()); - - let chunk = (a.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for (a, b) in a.chunks_mut(chunk).zip(b.chunks(chunk)) { - scope.spawn(move || { - for (a, b) in a.iter_mut().zip(b.iter()) { - a.mul_assign(e, b); - } - }); - } - }); - } - - pub fn sub_assign(&self, e: &E, a: &mut [E::Fr], b: Vec) { - assert_eq!(a.len(), b.len()); - - let chunk = (a.len() / num_cpus::get()) + 1; - - crossbeam::scope(|scope| { - for (a, b) in a.chunks_mut(chunk).zip(b.chunks(chunk)) { - scope.spawn(move || { - for (a, b) in a.iter_mut().zip(b.iter()) { - a.sub_assign(e, b); - } - }); - } - }); - } - - pub fn fft>(&self, e: &E, a: &mut [T]) - { - best_fft(e, a, &self.omega, self.exp); - } -} - -fn best_fft>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64) -{ - let log_cpus = get_log_cpus(); - - if log_n < log_cpus { - serial_fft(e, a, omega, log_n); - } else { - parallel_fft(e, a, omega, log_n, log_cpus); - } -} - -fn parallel_fft>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64, log_cpus: u64) -{ - assert!(log_n >= log_cpus); - - let num_cpus = 1 << log_cpus; - let log_new_n = log_n - log_cpus; - let mut tmp = vec![vec![T::group_zero(e); 1 << log_new_n]; num_cpus]; - let omega_num_cpus = omega.pow(e, &[num_cpus as u64]); - - crossbeam::scope(|scope| { - let a = &*a; - - for (j, tmp) in tmp.iter_mut().enumerate() { - scope.spawn(move || { - let omega_j = omega.pow(e, &[j as u64]); - let omega_step = omega.pow(e, &[(j as u64) << log_new_n]); - - let mut elt = E::Fr::one(e); - for i in 0..(1 << log_new_n) { - for s in 0..num_cpus { - let idx = (i + (s << log_new_n)) % (1 << log_n); - let mut t = a[idx]; - t.group_mul_assign(e, &elt); - tmp[i].group_add_assign(e, &t); - elt.mul_assign(e, &omega_step); - } - elt.mul_assign(e, &omega_j); - } - - serial_fft(e, tmp, &omega_num_cpus, log_new_n); - }); - } - }); - - let chunk = (a.len() / num_cpus) + 1; - - crossbeam::scope(|scope| { - let tmp = &tmp; - - for (idx, a) in a.chunks_mut(chunk).enumerate() { - scope.spawn(move || { - let mut idx = idx * chunk; - let mask = (1 << log_cpus) - 1; - for a in a { - *a = tmp[idx & mask][idx >> log_cpus]; - idx += 1; - } - }); - } - }); -} - -fn serial_fft>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64) -{ - fn bitreverse(mut n: usize, l: u64) -> usize { - let mut r = 0; - for _ in 0..l { - r = (r << 1) | (n & 1); - n >>= 1; - } - r - } - - let n = a.len(); - assert_eq!(n, 1 << log_n); - - for k in 0..n { - let rk = bitreverse(k, log_n); - if k < rk { - let tmp1 = a[rk]; - let tmp2 = a[k]; - a[rk] = tmp2; - a[k] = tmp1; - } - } - - let mut m = 1; - for _ in 0..log_n { - let w_m = omega.pow(e, &[(n / (2*m)) as u64]); - - let mut k = 0; - while k < n { - let mut w = E::Fr::one(e); - for j in 0..m { - let mut t = a[(k+j+m) as usize]; - t.group_mul_assign(e, &w); - let mut tmp = a[(k+j) as usize]; - tmp.group_sub_assign(e, &t); - a[(k+j+m) as usize] = tmp; - a[(k+j) as usize].group_add_assign(e, &t); - w.mul_assign(e, &w_m); - } - - k += 2*m; - } - - m *= 2; - } -} - -// Test multiplying various (low degree) polynomials together and -// comparing with naive evaluations. -#[test] -fn polynomial_arith() { - use curves::*; - use curves::bls381::Bls381; - use rand; - - fn test_mul(e: &E, rng: &mut R) - { - for coeffs_a in 1..70 { - for coeffs_b in 1..70 { - let final_degree = coeffs_a + coeffs_b - 1; - - let domain = EvaluationDomain::new(e, final_degree as u64); - let mut a: Vec<_> = (0..coeffs_a).map(|_| E::Fr::random(e, rng)).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| E::Fr::random(e, rng)).collect(); - - // naive evaluation - let mut naive = vec![E::Fr::zero(); domain.m as usize]; - for (i1, a) in a.iter().enumerate() { - for (i2, b) in b.iter().enumerate() { - let mut prod = *a; - prod.mul_assign(e, b); - naive[i1 + i2].add_assign(e, &prod); - } - } - - a.resize(domain.m as usize, E::Fr::zero()); - b.resize(domain.m as usize, E::Fr::zero()); - let mut c = vec![]; - c.resize(domain.m as usize, E::Fr::zero()); - - domain.fft(e, &mut a); - domain.fft(e, &mut b); - - for ((a, b), c) in a.iter().zip(b.iter()).zip(c.iter_mut()) { - *c = *a; - c.mul_assign(e, b); - } - - domain.ifft(e, &mut c); - - for (naive, fft) in naive.iter().zip(c.iter()) { - assert_eq!(naive, fft); - } - } - } - } - - let e = &Bls381::new(); - let rng = &mut rand::thread_rng(); - - test_mul(e, rng); -} - -fn get_log_cpus() -> u64 { - let num = num_cpus::get(); - log2_floor(num) -} - -fn log2_floor(num: usize) -> u64 { - assert!(num > 0); - - let mut pow = 0; - - while (1 << (pow+1)) <= num { - pow += 1; - } - - pow -} - -#[test] -fn test_log2_floor() { - assert_eq!(log2_floor(1), 0); - assert_eq!(log2_floor(2), 1); - assert_eq!(log2_floor(3), 1); - assert_eq!(log2_floor(4), 2); - assert_eq!(log2_floor(5), 2); - assert_eq!(log2_floor(6), 2); - assert_eq!(log2_floor(7), 2); - assert_eq!(log2_floor(8), 3); -} - -#[test] -fn parallel_fft_consistency() { - use curves::*; - use curves::bls381::{Bls381, Fr}; - use std::cmp::min; - use rand; - - let e = &Bls381::new(); - let rng = &mut rand::thread_rng(); - - for log_d in 0..10 { - let d = 1 << log_d; - let domain = EvaluationDomain::new(e, d); - assert_eq!(domain.m, d); - - for log_cpus in 0..min(log_d, 3) { - let mut v1 = (0..d).map(|_| Fr::random(e, rng)).collect::>(); - let mut v2 = v1.clone(); - - parallel_fft(e, &mut v1, &domain.omega, log_d, log_cpus); - serial_fft(e, &mut v2, &domain.omega, log_d); - - assert_eq!(v1, v2); - } - } -} diff --git a/src/curves/mod.rs b/src/curves/mod.rs deleted file mode 100644 index 4a2456c52..000000000 --- a/src/curves/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use rand; -use std::fmt; - -use std::borrow::Borrow; -use serde::{Serialize, Deserialize}; -use super::BitIterator; - -use super::{Cow, Convert}; - -pub mod bls381; -pub mod multiexp; -pub mod wnaf; -pub mod domain; - -pub trait Engine: Sized + Clone + Send + Sync -{ - type Fq: PrimeField + Convert<>::Repr, Self>; - type Fr: SnarkField + Convert<>::Repr, Self>; - type Fqe: SqrtField; - type Fqk: Field; - type G1: Curve + Convert<>::Affine, Self>; - type G2: Curve + Convert<>::Affine, Self>; - - fn new() -> Self; - - /// Operate over the thread-local engine instance - fn with FnOnce(&'a Self) -> R>(F) -> R; - - fn pairing(&self, p: &G1, q: &G2) -> Self::Fqk - where G1: Convert<>::Affine, Self>, - G2: Convert<>::Affine, Self> - { - self.final_exponentiation(&self.miller_loop( - [( - &(*p.convert(self)).borrow().prepare(self), - &(*q.convert(self)).borrow().prepare(self) - )].into_iter() - )) - } - fn miller_loop<'a, I>(&self, I) -> Self::Fqk - where I: IntoIterator>::Prepared, - &'a >::Prepared - )>; - fn final_exponentiation(&self, &Self::Fqk) -> Self::Fqk; - - /// Perform multi-exponentiation. g and s must have the same length. - fn multiexp>(&self, g: &[G::Affine], s: &[Self::Fr]) -> Result; - fn batch_baseexp, S: AsRef<[Self::Fr]>>(&self, table: &wnaf::WindowTable, scalars: S) -> Vec; - - fn batchexp, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>); -} - -pub trait Group: Copy + Send + Sync + Sized -{ - fn group_zero(&E) -> Self; - fn group_mul_assign(&mut self, &E, scalar: &E::Fr); - fn group_add_assign(&mut self, &E, other: &Self); - fn group_sub_assign(&mut self, &E, other: &Self); -} - -pub trait Curve: Sized + - Copy + - Clone + - Send + - Sync + - fmt::Debug + - 'static + - Group + - self::multiexp::Projective -{ - type Affine: CurveAffine; - type Prepared: Clone + Send + Sync + 'static; - - fn zero(&E) -> Self; - fn one(&E) -> Self; - fn random(&E, &mut R) -> Self; - - fn is_zero(&self) -> bool; - fn is_equal(&self, &E, other: &Self) -> bool; - - fn to_affine(&self, &E) -> Self::Affine; - fn prepare(&self, &E) -> Self::Prepared; - - fn double(&mut self, &E); - fn negate(&mut self, engine: &E); - fn add_assign(&mut self, &E, other: &Self); - fn sub_assign(&mut self, &E, other: &Self); - fn add_assign_mixed(&mut self, &E, other: &Self::Affine); - fn mul_assign>::Repr, E>>(&mut self, &E, other: &S); - - fn optimal_window(&E, scalar_bits: usize) -> Option; - fn optimal_window_batch(&self, &E, scalars: usize) -> wnaf::WindowTable; - - /// Performs optimal exponentiation of this curve element given the scalar, using - /// wNAF when necessary. - fn optimal_exp( - &self, - e: &E, - scalar: >::Repr, - table: &mut wnaf::WindowTable, - scratch: &mut wnaf::WNAFTable - ) -> Self { - let bits = scalar.num_bits(); - match Self::optimal_window(e, bits) { - Some(window) => { - table.set_base(e, *self, window); - scratch.set_scalar(table, scalar); - table.exp(e, scratch) - }, - None => { - let mut tmp = *self; - tmp.mul_assign(e, &scalar); - tmp - } - } - } -} - -pub trait CurveAffine: Copy + - Clone + - Sized + - Send + - Sync + - fmt::Debug + - PartialEq + - Eq + - 'static -{ - type Jacobian: Curve; - type Uncompressed: CurveRepresentation; - - fn to_jacobian(&self, &E) -> Self::Jacobian; - fn prepare(self, &E) -> >::Prepared; - fn is_zero(&self) -> bool; - fn mul>::Repr, E>>(&self, &E, other: &S) -> Self::Jacobian; - fn negate(&mut self, &E); - - /// Returns true iff the point is on the curve and in the correct - /// subgroup. This is guaranteed to return true unless the user - /// invokes `to_affine_unchecked`. - fn is_valid(&self, &E) -> bool; - - /// Produces an "uncompressed" representation of the curve point according - /// to IEEE standards. - fn to_uncompressed(&self, &E) -> Self::Uncompressed; -} - -pub trait CurveRepresentation: Serialize + for<'a> Deserialize<'a> -{ - type Affine: CurveAffine; - - /// If the point representation is valid (lies on the curve, correct - /// subgroup) this function will return it. - fn to_affine(&self, e: &E) -> Result { - let p = try!(self.to_affine_unchecked(e)); - - if p.is_valid(e) { - Ok(p) - } else { - Err(()) - } - } - - /// Returns the point under the assumption that it is valid. Undefined - /// behavior if `to_affine` would have rejected the point. - fn to_affine_unchecked(&self, &E) -> Result; -} - -pub trait Field: Sized + - Eq + - PartialEq + - Copy + - Clone + - Send + - Sync + - fmt::Debug + - 'static -{ - fn zero() -> Self; - fn one(&E) -> Self; - fn random(&E, &mut R) -> Self; - fn is_zero(&self) -> bool; - fn square(&mut self, engine: &E); - fn double(&mut self, engine: &E); - fn negate(&mut self, &E); - fn add_assign(&mut self, &E, other: &Self); - fn sub_assign(&mut self, &E, other: &Self); - fn mul_assign(&mut self, &E, other: &Self); - fn inverse(&self, &E) -> Option; - fn frobenius_map(&mut self, &E, power: usize); - fn pow>(&self, engine: &E, exp: S) -> Self - { - let mut res = Self::one(engine); - - for i in BitIterator::new(exp) { - res.square(engine); - if i { - res.mul_assign(engine, self); - } - } - - res - } -} - -pub trait SqrtField: Field -{ - /// Returns a square root of the field element, if it is - /// quadratic residue. - fn sqrt(&self, engine: &E) -> Option; -} - -pub trait PrimeFieldRepr: Clone + Eq + Ord + AsRef<[u64]> { - fn from_u64(a: u64) -> Self; - fn sub_noborrow(&mut self, other: &Self); - fn add_nocarry(&mut self, other: &Self); - fn num_bits(&self) -> usize; - fn is_zero(&self) -> bool; - fn is_odd(&self) -> bool; - fn div2(&mut self); -} - -pub trait PrimeField: SqrtField -{ - type Repr: PrimeFieldRepr; - - fn from_u64(&E, u64) -> Self; - fn from_str(&E, s: &str) -> Result; - fn from_repr(&E, Self::Repr) -> Result; - fn into_repr(&self, &E) -> Self::Repr; - - /// Returns the field characteristic; the modulus. - fn char(&E) -> Self::Repr; - - /// Returns how many bits are needed to represent an element of this - /// field. - fn num_bits(&E) -> usize; - - /// Returns how many bits of information can be reliably stored in the - /// field element. - fn capacity(&E) -> usize; -} - -pub trait SnarkField: PrimeField + Group -{ - fn s(&E) -> u64; - fn multiplicative_generator(&E) -> Self; - fn root_of_unity(&E) -> Self; -} - -#[cfg(test)] -mod tests; - -#[test] -fn bls381_test_suite() { - tests::test_engine::(); -} diff --git a/src/curves/multiexp.rs b/src/curves/multiexp.rs deleted file mode 100644 index 37b583b21..000000000 --- a/src/curves/multiexp.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! This module provides an abstract implementation of the Bos-Coster multi-exponentiation algorithm. - -use super::{Engine, Curve, CurveAffine, Field, PrimeField, PrimeFieldRepr}; -use super::wnaf; -use std::cmp::Ordering; -use std::collections::BinaryHeap; - -pub trait Projective: Sized + Copy + Clone + Send { - type WindowTable; - - /// Constructs an identity element. - fn identity(e: &E) -> Self; - - /// Adds this projective element to another projective element. - fn add_to_projective(&self, e: &E, projective: &mut Self); - - /// Exponentiates by a scalar. - fn exponentiate( - &mut self, - e: &E, - scalar: >::Repr, - table: &mut Self::WindowTable, - scratch: &mut wnaf::WNAFTable - ); - - /// Construct a blank window table - fn new_window_table(e: &E) -> Self::WindowTable; -} - -pub trait Chunk: Send { - type Projective: Projective; - - /// Skips the next element from the source. - fn skip(&mut self, e: &E) -> Result<(), ()>; - - /// Adds the next element from the source to a projective element - fn add_to_projective(&mut self, e: &E, acc: &mut Self::Projective) -> Result<(), ()>; - - /// Turns the next element of the source into a projective element. - fn into_projective(&mut self, e: &E) -> Result; -} - -/// An `ElementSource` is something that contains a sequence of group elements or -/// group element tuples. -pub trait ElementSource { - type Chunk: Chunk; - - /// Gets the number of elements from the source. - fn num_elements(&self) -> usize; - - /// Returns a chunk size and a vector of chunks. - fn chunks(&mut self, chunks: usize) -> (usize, Vec); -} - -impl<'a, E: Engine, G: CurveAffine> ElementSource for &'a [G] { - type Chunk = &'a [G]; - - fn num_elements(&self) -> usize { - self.len() - } - - fn chunks(&mut self, chunks: usize) -> (usize, Vec) { - let chunk_size = (self.len() / chunks) + 1; - - (chunk_size, (*self).chunks(chunk_size).collect()) - } -} - -impl<'a, E: Engine, G: CurveAffine> Chunk for &'a [G] -{ - type Projective = G::Jacobian; - - fn skip(&mut self, _: &E) -> Result<(), ()> { - if self.len() == 0 { - Err(()) - } else { - *self = &self[1..]; - Ok(()) - } - } - - /// Adds the next element from the source to a projective element - fn add_to_projective(&mut self, e: &E, acc: &mut Self::Projective) -> Result<(), ()> { - if self.len() == 0 { - Err(()) - } else { - acc.add_assign_mixed(e, &self[0]); - *self = &self[1..]; - Ok(()) - } - } - - /// Turns the next element of the accumulator into a projective element. - fn into_projective(&mut self, e: &E) -> Result { - if self.len() == 0 { - Err(()) - } else { - let ret = Ok(self[0].to_jacobian(e)); - *self = &self[1..]; - ret - } - } -} - -fn justexp( - largest: &>::Repr, - smallest: &>::Repr -) -> bool -{ - use std::cmp::min; - - let abits = largest.num_bits(); - let bbits = smallest.num_bits(); - let limit = min(abits-bbits, 20); - - if bbits < (1<>( - e: &E, - mut bases: Source, - scalars: &[E::Fr] -) -> Result<>::Projective, ()> -{ - if bases.num_elements() != scalars.len() { - return Err(()) - } - - use crossbeam; - use num_cpus; - - let (chunk_len, bases) = bases.chunks(num_cpus::get()); - - return crossbeam::scope(|scope| { - let mut threads = vec![]; - - for (mut chunk, scalars) in bases.into_iter().zip(scalars.chunks(chunk_len)) { - threads.push(scope.spawn(move || { - let mut heap: BinaryHeap> = BinaryHeap::with_capacity(scalars.len()); - let mut elements = Vec::with_capacity(scalars.len()); - - let mut acc = Projective::::identity(e); - let one = E::Fr::one(e); - - for scalar in scalars { - if scalar.is_zero() { - // Skip processing bases when we're multiplying by a zero anyway. - chunk.skip(e)?; - } else if *scalar == one { - // Just perform mixed addition when we're multiplying by one. - chunk.add_to_projective(e, &mut acc)?; - } else { - elements.push(chunk.into_projective(e)?); - heap.push(Exp { - scalar: scalar.into_repr(e), - index: elements.len() - 1 - }); - } - } - - let mut window = <>::Projective as Projective>::new_window_table(e); - let mut scratch = wnaf::WNAFTable::new(); - - // Now that the heap is populated... - while let Some(mut greatest) = heap.pop() { - { - let second_greatest = heap.peek(); - if second_greatest.is_none() || justexp::(&greatest.scalar, &second_greatest.unwrap().scalar) { - // Either this is the last value or multiplying is considered more efficient than - // rewriting and reinsertion into the heap. - //opt_exp(engine, &mut elements[greatest.index], greatest.scalar, &mut table); - elements[greatest.index].exponentiate(e, greatest.scalar, &mut window, &mut scratch); - elements[greatest.index].add_to_projective(e, &mut acc); - continue; - } else { - // Rewrite - let second_greatest = second_greatest.unwrap(); - - greatest.scalar.sub_noborrow(&second_greatest.scalar); - let mut tmp = elements[second_greatest.index]; - elements[greatest.index].add_to_projective(e, &mut tmp); - elements[second_greatest.index] = tmp; - } - } - if !greatest.scalar.is_zero() { - // Reinsert only nonzero scalars. - heap.push(greatest); - } - } - - Ok(acc) - })); - } - - - let mut acc = Projective::::identity(e); - for t in threads { - t.join()?.add_to_projective(e, &mut acc); - } - - Ok(acc) - }) -} - -struct Exp { - scalar: >::Repr, - index: usize -} - -impl Ord for Exp { - fn cmp(&self, other: &Exp) -> Ordering { - self.scalar.cmp(&other.scalar) - } -} - -impl PartialOrd for Exp { - fn partial_cmp(&self, other: &Exp) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for Exp { - fn eq(&self, other: &Exp) -> bool { - self.scalar == other.scalar - } -} - -impl Eq for Exp { } diff --git a/src/curves/tests/curves.rs b/src/curves/tests/curves.rs deleted file mode 100644 index 3682709ba..000000000 --- a/src/curves/tests/curves.rs +++ /dev/null @@ -1,277 +0,0 @@ -use rand; -use super::super::{Engine, Field, PrimeField, Curve, CurveAffine}; - -fn random_test_mixed_addition>(e: &E) -{ - let rng = &mut rand::thread_rng(); - - // affine is zero - { - let a = G::zero(e).to_affine(e); - let mut b = G::random(e, rng); - let bcpy = b; - - b.add_assign_mixed(e, &a); - - assert!(bcpy.is_equal(e, &b)); - assert_eq!(bcpy.to_affine(e), b.to_affine(e)); - } - - // self is zero - { - let a = G::random(e, rng).to_affine(e); - let mut b = G::zero(e); - let acpy = a.to_jacobian(e); - - b.add_assign_mixed(e, &a); - - assert!(acpy.is_equal(e, &b)); - assert_eq!(acpy.to_affine(e), b.to_affine(e)); - } - - // both are zero - { - let a = G::zero(e).to_affine(e); - let mut b = G::zero(e); - let acpy = a.to_jacobian(e); - - b.add_assign_mixed(e, &a); - - assert!(acpy.is_equal(e, &b)); - assert_eq!(acpy.to_affine(e), b.to_affine(e)); - } - - // one is negative of the other - { - let a = G::random(e, rng); - let mut b = a; - b.negate(e); - let a = a.to_affine(e); - - b.add_assign_mixed(e, &a); - assert!(b.is_zero()); - assert_eq!(b.to_affine(e), G::zero(e).to_affine(e)); - } - - // doubling case - { - let a = G::random(e, rng); - let b = a.to_affine(e); - let mut acpy = a; - acpy.add_assign_mixed(e, &b); - - let mut t = a; - t.double(e); - assert!(acpy.is_equal(e, &t)); - } - - for _ in 0..100 { - let mut x = G::random(e, rng); - let mut y = x; - let b = G::random(e, rng); - let baffine = b.to_affine(e); - - x.add_assign(e, &b); - y.add_assign_mixed(e, &baffine); - - assert!(x.is_equal(e, &y)); - } -} - -fn random_test_addition>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..50 { - let r1 = G::random(e, rng); - let r2 = G::random(e, rng); - let r3 = G::random(e, rng); - - { - let mut tmp1 = r1; - tmp1.add_assign(e, &r2); - tmp1.add_assign(e, &r3); - - let mut tmp2 = r2; - tmp2.add_assign(e, &r3); - tmp2.add_assign(e, &r1); - - assert!(tmp1.is_equal(e, &tmp2)); - } - - { - let mut tmp = r1; - tmp.add_assign(e, &r2); - tmp.add_assign(e, &r3); - tmp.sub_assign(e, &r1); - tmp.sub_assign(e, &r2); - tmp.sub_assign(e, &r3); - - assert!(tmp.is_zero()); - } - } -} - -fn random_test_doubling>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..50 { - let r1 = G::random(e, rng); - let r2 = G::random(e, rng); - let ti = E::Fr::from_str(e, "2").unwrap().inverse(e).unwrap(); - - { - let mut tmp_1 = r1; - tmp_1.add_assign(e, &r2); - tmp_1.add_assign(e, &r1); - - let mut tmp_2 = r1; - tmp_2.double(e); - tmp_2.add_assign(e, &r2); - - assert!(tmp_1.is_equal(e, &tmp_2)); - } - - { - let mut tmp = r1; - tmp.double(e); - tmp.mul_assign(e, &ti); - - assert!(tmp.is_equal(e, &r1)); - } - } -} - -fn random_test_dh>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..50 { - let alice_sk = E::Fr::random(e, rng); - let bob_sk = E::Fr::random(e, rng); - - let mut alice_pk = G::one(e); - alice_pk.mul_assign(e, &alice_sk); - let mut bob_pk = G::one(e); - bob_pk.mul_assign(e, &bob_sk); - - let mut alice_shared = bob_pk; - alice_shared.mul_assign(e, &alice_sk); - let mut bob_shared = alice_pk; - bob_shared.mul_assign(e, &bob_sk); - - assert!(alice_shared.is_equal(e, &bob_shared)); - } -} - -fn random_mixed_addition>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..50 { - let a = G::random(e, rng); - - let mut res = a; - res.double(e); - - let affine = a.to_affine(e); - let mut jacobian = affine.to_jacobian(e); - jacobian.double(e); - - assert!(jacobian.is_equal(e, &res)); - } -} - -fn random_test_equality>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..50 { - let begin = G::random(e, rng); - - let mut acc = begin; - - let a = E::Fr::random(e, rng); - let b = G::random(e, rng); - let c = E::Fr::random(e, rng); - let d = G::random(e, rng); - - for _ in 0..10 { - acc.mul_assign(e, &a); - acc.negate(e); - acc.add_assign(e, &b); - acc.mul_assign(e, &c); - acc.negate(e); - acc.sub_assign(e, &d); - acc.double(e); - } - - assert!(!acc.is_equal(e, &begin)); - - let ai = a.inverse(e).unwrap(); - let ci = c.inverse(e).unwrap(); - let ti = E::Fr::from_str(e, "2").unwrap().inverse(e).unwrap(); - - for _ in 0..10 { - acc.mul_assign(e, &ti); - acc.add_assign(e, &d); - acc.negate(e); - acc.mul_assign(e, &ci); - acc.sub_assign(e, &b); - acc.negate(e); - acc.mul_assign(e, &ai); - } - - assert!(acc.is_equal(e, &begin)); - } -} - -pub fn test_curve>(e: &E) { - { - let rng = &mut rand::thread_rng(); - let mut g = G::random(e, rng); - let order = >::char(e); - g.mul_assign(e, &order); - - assert!(g.is_zero()); - } - { - let rng = &mut rand::thread_rng(); - let mut neg1 = E::Fr::one(e); - neg1.negate(e); - for _ in 0..1000 { - let orig = G::random(e, rng); - let mut a = orig; - a.mul_assign(e, &neg1); - assert!(!a.is_zero()); - a.add_assign(e, &orig); - assert!(a.is_zero()); - } - } - { - let mut o = G::one(e); - o.sub_assign(e, &G::one(e)); - assert!(o.is_zero()); - } - { - let mut o = G::one(e); - o.add_assign(e, &G::one(e)); - let mut r = G::one(e); - r.mul_assign(e, &E::Fr::from_str(e, "2").unwrap()); - assert!(o.is_equal(e, &r)); - } - { - let mut z = G::zero(e); - assert!(z.is_zero()); - z.double(e); - assert!(z.is_zero()); - - let zaffine = z.to_affine(e); - let zjacobian = zaffine.to_jacobian(e); - - assert!(zjacobian.is_zero()); - } - - random_test_equality::(e); - random_test_dh::(e); - random_test_doubling::(e); - random_test_addition::(e); - random_mixed_addition::(e); - random_test_mixed_addition::(e); -} diff --git a/src/curves/tests/fields.rs b/src/curves/tests/fields.rs deleted file mode 100644 index 0b381133c..000000000 --- a/src/curves/tests/fields.rs +++ /dev/null @@ -1,219 +0,0 @@ -use rand::{self, Rng}; -use super::super::{Engine, Field, SqrtField, PrimeField}; - -fn inversion_tests, R: Rng>(e: &E, rng: &mut R) { - let mut a = F::one(e); - for _ in 0..10000 { - let mut b = a.inverse(e).unwrap(); - b.mul_assign(e, &a); - assert_eq!(b, F::one(e)); - a.add_assign(e, &F::one(e)); - } - a = F::one(e); - a.negate(e); - for _ in 0..10000 { - let mut b = a.inverse(e).unwrap(); - b.mul_assign(e, &a); - assert_eq!(b, F::one(e)); - a.sub_assign(e, &F::one(e)); - } - a = F::zero(); - assert!(a.inverse(e).is_none()); - for _ in 0..10000 { - let r = F::random(e, rng); - assert!(!r.is_zero()); - let mut rinv = r.inverse(e).unwrap(); - rinv.mul_assign(e, &r); - assert_eq!(rinv, F::one(e)); - } -} - -fn expansion_tests, R: Rng>(e: &E, rng: &mut R) { - for _ in 0..100 { - let a = F::random(e, rng); - let b = F::random(e, rng); - let c = F::random(e, rng); - let d = F::random(e, rng); - - let lhs; - { - let mut t0 = a; - t0.add_assign(e, &b); - let mut t1 = c; - t1.add_assign(e, &d); - t0.mul_assign(e, &t1); - lhs = t0; - } - - let rhs; - { - let mut t0 = a; - t0.mul_assign(e, &c); - let mut t1 = b; - t1.mul_assign(e, &c); - let mut t2 = a; - t2.mul_assign(e, &d); - let mut t3 = b; - t3.mul_assign(e, &d); - t0.add_assign(e, &t1); - t0.add_assign(e, &t2); - t0.add_assign(e, &t3); - rhs = t0; - } - - assert_eq!(lhs, rhs); - } -} - -fn squaring_tests, R: Rng>(e: &E, rng: &mut R) { - for _ in 0..100 { - let mut a = F::random(e, rng); - let mut b = a; - b.mul_assign(e, &a); - a.square(e); - - assert_eq!(a, b); - } - - let mut cur = F::zero(); - for _ in 0..100 { - let mut a = cur; - a.square(e); - let mut b = cur; - b.mul_assign(e, &cur); - - assert_eq!(a, b); - - cur.add_assign(e, &F::one(e)); - } -} - -fn operation_tests, R: Rng>(e: &E, rng: &mut R) { - { - let mut acc = F::zero(); - for _ in 0..1000 { - let mut a = acc; - a.negate(e); - a.add_assign(e, &acc); - - assert_eq!(a, F::zero()); - acc.add_assign(e, &F::one(e)); - } - } - { - for _ in 0..1000 { - let mut a = F::random(e, rng); - let mut at = a; - let mut b = F::random(e, rng); - - a.sub_assign(e, &b); - b.negate(e); - at.add_assign(e, &b); - - assert_eq!(a, at); - } - } -} - -pub fn test_field>(e: &E) { - let rng = &mut rand::thread_rng(); - - inversion_tests::(e, rng); - expansion_tests::(e, rng); - squaring_tests::(e, rng); - operation_tests::(e, rng); -} - -pub fn test_sqrt_field>(e: &E) { - const SAMPLES: isize = 10000; - - { - let mut acc = F::one(e); - - for _ in 0..SAMPLES { - let mut b = acc; - b.square(e); - let mut c = b.sqrt(e).unwrap(); - if c != acc { - c.negate(e); - } - - assert_eq!(acc, c); - - acc.add_assign(e, &F::one(e)); - } - } - - { - let mut acc = F::one(e); - - for _ in 0..SAMPLES { - match acc.sqrt(e) { - Some(mut a) => { - a.square(e); - - assert_eq!(a, acc); - }, - None => {} - } - - acc.add_assign(e, &F::one(e)); - } - } - - { - let rng = &mut rand::thread_rng(); - - for _ in 0..SAMPLES { - let a = F::random(e, rng); - let mut b = a; - b.square(e); - let mut c = b.sqrt(e).unwrap(); - if c != a { - c.negate(e); - } - - assert_eq!(a, c); - } - } - - { - let rng = &mut rand::thread_rng(); - - let mut qr: isize = 0; - let mut nqr: isize = 0; - for _ in 0..SAMPLES { - let a = F::random(e, rng); - match a.sqrt(e) { - Some(mut b) => { - qr += 1; - b.square(e); - assert_eq!(a, b); - }, - None => { - nqr += 1; - } - } - } - - assert!((qr - nqr < (SAMPLES / 20)) || (qr - nqr > -(SAMPLES / 20))); - } -} - -pub fn test_prime_field>(e: &E) { - let rng = &mut rand::thread_rng(); - - for _ in 0..100 { - let a = F::random(e, rng); - let b = F::random(e, rng); - let mut c = a; - c.mul_assign(e, &b); - let a = a.into_repr(e); - let b = b.into_repr(e); - let expected_a = F::from_repr(e, a).unwrap(); - let expected_b = F::from_repr(e, b).unwrap(); - let mut expected_c = expected_a; - expected_c.mul_assign(e, &expected_b); - assert_eq!(c, expected_c); - } -} diff --git a/src/curves/tests/mod.rs b/src/curves/tests/mod.rs deleted file mode 100644 index c615526a0..000000000 --- a/src/curves/tests/mod.rs +++ /dev/null @@ -1,182 +0,0 @@ -use super::{Engine, Curve, CurveAffine, Field, PrimeField}; -use rand::{self, Rng}; - -mod fields; -mod curves; - -fn test_batchexp>(e: &E) { - let rng = &mut rand::thread_rng(); - - fn test_batchexp_case, R: Rng>(e: &E, rng: &mut R, amount: usize, coeff: Option<&E::Fr>) - { - let mut g: Vec = (0..amount).map(|_| G::random(e, rng).to_affine(e)).collect(); - let mut s: Vec = (0..amount).map(|_| E::Fr::random(e, rng)).collect(); - - let mut g_batch = g.clone(); - - e.batchexp::(&mut g_batch, &s, coeff); - - for (g, s) in g.iter_mut().zip(s.iter_mut()) { - match coeff { - Some(coeff) => { - s.mul_assign(e, &coeff); - }, - _ => {} - } - *g = g.mul(e, s).to_affine(e); - } - - assert_eq!(g_batch, g); - } - - for amt in 10..100 { - if amt % 2 == 0 { - let coeff = &E::Fr::random(e, rng); - test_batchexp_case::(e, rng, amt, Some(coeff)); - } else { - test_batchexp_case::(e, rng, amt, None); - } - } -} - -fn test_multiexp>(e: &E) { - fn naiveexp>(e: &E, g: &[G::Affine], s: &[E::Fr]) -> G - { - assert!(g.len() == s.len()); - - let mut expected = G::zero(e); - for (g, s) in g.iter().zip(s.iter()) { - expected.add_assign(e, &g.mul(e, s)); - } - - expected - } - - { - let rng = &mut rand::thread_rng(); - - let g: Vec = (0..1000).map(|_| G::random(e, rng).to_affine(e)).collect(); - let s: Vec = (0..1000).map(|_| E::Fr::random(e, rng)).collect(); - - let naive = naiveexp::(e, &g, &s); - let multi = e.multiexp::(&g, &s).unwrap(); - - assert!(naive.is_equal(e, &multi)); - assert!(multi.is_equal(e, &naive)); - } - - { - let rng = &mut rand::thread_rng(); - let g: Vec = (0..2).map(|_| G::random(e, rng).to_affine(e)).collect(); - let s = vec![E::Fr::from_str(e, "3435973836800000000000000000000000").unwrap(), E::Fr::from_str(e, "3435973836700000000000000000000000").unwrap()]; - - let naive = naiveexp::(e, &g, &s); - let multi = e.multiexp::(&g, &s).unwrap(); - - assert!(naive.is_equal(e, &multi)); - assert!(multi.is_equal(e, &naive)); - } - - { - let rng = &mut rand::thread_rng(); - let s = vec![E::Fr::one(e); 100]; - let g = vec![G::random(e, rng).to_affine(e); 101]; - - assert!(e.multiexp::(&g, &s).is_err()); - } -} - -fn test_bilinearity(e: &E) { - let rng = &mut rand::thread_rng(); - - let a = E::G1::random(e, rng); - let b = E::G2::random(e, rng); - let s = E::Fr::random(e, rng); - - let mut a_s = a; - a_s.mul_assign(e, &s); - - let mut b_s = b; - b_s.mul_assign(e, &s); - - let test1 = e.pairing(&a_s, &b); - assert!(test1 != E::Fqk::one(e)); - let test2 = e.pairing(&a, &b_s); - assert_eq!(test1, test2); - - let mut test4 = e.pairing(&a, &b); - assert!(test4 != test1); - test4 = test4.pow(e, &s.into_repr(e)); - assert_eq!(test1, test4); -} - -fn test_multimiller(e: &E) { - let rng = &mut rand::thread_rng(); - - let a1 = E::G1::random(e, rng); - let a2 = E::G2::random(e, rng); - - let b1 = E::G1::random(e, rng); - let b2 = E::G2::random(e, rng); - - let mut p1 = e.pairing(&a1, &a2); - let p2 = e.pairing(&b1, &b2); - p1.mul_assign(e, &p2); - - let mm = e.final_exponentiation(&e.miller_loop( - [ - (&a1.prepare(e), &a2.prepare(e)), - (&b1.prepare(e), &b2.prepare(e)) - ].into_iter() - )); - - assert_eq!(p1, mm); -} - -pub fn test_engine() { - let engine = E::new(); - - fields::test_prime_field::(&engine); - fields::test_prime_field::(&engine); - fields::test_sqrt_field::(&engine); - fields::test_sqrt_field::(&engine); - fields::test_sqrt_field::(&engine); - - fields::test_field::(&engine); - fields::test_field::(&engine); - fields::test_field::(&engine); - fields::test_field::(&engine); - - curves::test_curve::(&engine); - curves::test_curve::(&engine); - - test_bilinearity(&engine); - test_multimiller(&engine); - test_frobenius(&engine); - test_multiexp::(&engine); - test_multiexp::(&engine); - - test_batchexp::(&engine); - test_batchexp::(&engine); -} - -fn test_frobenius(e: &E) { - let rng = &mut rand::thread_rng(); - let modulus = E::Fq::char(e); - - let a = E::Fqk::random(e, rng); - let mut acpy = a; - acpy.frobenius_map(e, 0); - assert_eq!(acpy, a); - - let mut a_q = a.pow(e, &modulus); - - for p in 1..12 { - acpy = a; - acpy.frobenius_map(e, p); - - assert_eq!(acpy, a_q); - - a_q = a_q.pow(e, &modulus); - } -} diff --git a/src/curves/wnaf.rs b/src/curves/wnaf.rs deleted file mode 100644 index c4f062eda..000000000 --- a/src/curves/wnaf.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::marker::PhantomData; -use super::{Engine, Curve, PrimeField, PrimeFieldRepr}; - -/// Represents the scratch space for a wNAF form scalar. -pub struct WNAFTable { - window: usize, - wnaf: Vec -} - -impl WNAFTable { - pub fn new() -> WNAFTable { - WNAFTable { - window: 0, - wnaf: vec![] - } - } - - /// Convert the scalar into wNAF form. - pub fn set_scalar>(&mut self, table: &WindowTable, mut c: >::Repr) { - self.window = table.window; - self.wnaf.truncate(0); - - while !c.is_zero() { - let mut u; - if c.is_odd() { - u = (c.as_ref()[0] % (1 << (self.window+1))) as i64; - - if u > (1 << self.window) { - u -= 1 << (self.window+1); - } - - if u > 0 { - c.sub_noborrow(&<>::Repr as PrimeFieldRepr>::from_u64(u as u64)); - } else { - c.add_nocarry(&<>::Repr as PrimeFieldRepr>::from_u64((-u) as u64)); - } - } else { - u = 0; - } - - self.wnaf.push(u); - - c.div2(); - } - } -} - -/// Represents a window table for a base curve point. -pub struct WindowTable>{ - window: usize, - table: Vec, - _marker: PhantomData -} - -impl> WindowTable { - /// Construct a new window table for a given base. - pub fn new(e: &E, base: G, window: usize) -> Self { - let mut tmp = WindowTable { - window: 0, - table: vec![], - _marker: PhantomData - }; - - tmp.set_base(e, base, window); - - tmp - } - - /// Replace this window table with a new one generated by a different base. - pub fn set_base(&mut self, e: &E, mut base: G, window: usize) { - assert!(window < 23); - assert!(window > 1); - - self.window = window; - self.table.truncate(0); - self.table.reserve(1 << (window-1)); - - let mut dbl = base; - dbl.double(e); - - for _ in 0..(1 << (window-1)) { - self.table.push(base); - base.add_assign(e, &dbl); - } - } - - pub fn exp(&self, e: &E, wnaf: &WNAFTable) -> G { - assert_eq!(wnaf.window, self.window); - - let mut result = G::zero(e); - - for n in wnaf.wnaf.iter().rev() { - result.double(e); - - if *n != 0 { - if *n > 0 { - result.add_assign(e, &self.table[(n/2) as usize]); - } else { - result.sub_assign(e, &self.table[((-n)/2) as usize]); - } - } - } - - result - } - - pub fn current_window(&self) -> usize { - self.window - } -} diff --git a/src/groth16/mod.rs b/src/groth16/mod.rs deleted file mode 100644 index f7902c9b5..000000000 --- a/src/groth16/mod.rs +++ /dev/null @@ -1,527 +0,0 @@ -use curves::*; -use super::*; - -pub struct ProvingKey { - a_inputs: Vec<>::Affine>, - b1_inputs: Vec<>::Affine>, - b2_inputs: Vec<>::Affine>, - a_aux: Vec<>::Affine>, - b1_aux: Vec<>::Affine>, - b2_aux: Vec<>::Affine>, - h: Vec<>::Affine>, - l: Vec<>::Affine>, - alpha_g1: >::Affine, - beta_g1: >::Affine, - beta_g2: >::Affine, - delta_g1: >::Affine, - delta_g2: >::Affine -} - -pub struct VerifyingKey { - alpha_g1: >::Affine, - beta_g2: >::Affine, - gamma_g2: >::Affine, - delta_g2: >::Affine, - ic: Vec<>::Affine> -} - -pub struct PreparedVerifyingKey { - alpha_g1_beta_g2: E::Fqk, - neg_gamma_g2: >::Prepared, - neg_delta_g2: >::Prepared, - ic: Vec<>::Affine> -} - -pub struct Proof { - a: E::G1, - b: E::G2, - c: E::G1 -} - -pub fn keypair>( - e: &E, - circuit: C, - tau: &E::Fr, - alpha: &E::Fr, - beta: &E::Fr, - gamma: &E::Fr, - delta: &E::Fr -) -> (ProvingKey, VerifyingKey) -{ - struct KeypairAssembly { - num_inputs: usize, - num_aux: usize, - num_constraints: usize, - at_inputs: Vec>, - bt_inputs: Vec>, - ct_inputs: Vec>, - at_aux: Vec>, - bt_aux: Vec>, - ct_aux: Vec> - } - - impl PublicConstraintSystem for KeypairAssembly { - fn alloc_input(&mut self, _: E::Fr) -> Variable { - let index = self.num_inputs; - self.num_inputs += 1; - - self.at_inputs.push(vec![]); - self.bt_inputs.push(vec![]); - self.ct_inputs.push(vec![]); - - Variable(Index::Input(index)) - } - } - - impl ConstraintSystem for KeypairAssembly { - fn alloc(&mut self, _: E::Fr) -> Variable { - let index = self.num_aux; - self.num_aux += 1; - - self.at_aux.push(vec![]); - self.bt_aux.push(vec![]); - self.ct_aux.push(vec![]); - - Variable(Index::Aux(index)) - } - - fn enforce( - &mut self, - a: LinearCombination, - b: LinearCombination, - c: LinearCombination - ) - { - fn qap_eval( - l: LinearCombination, - inputs: &mut [Vec<(E::Fr, usize)>], - aux: &mut [Vec<(E::Fr, usize)>], - this_constraint: usize - ) - { - for (index, coeff) in l.0 { - match index { - Index::Input(id) => inputs[id].push((coeff, this_constraint)), - Index::Aux(id) => aux[id].push((coeff, this_constraint)) - } - } - } - - qap_eval(a, &mut self.at_inputs, &mut self.at_aux, self.num_constraints); - qap_eval(b, &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints); - qap_eval(c, &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints); - - self.num_constraints += 1; - } - } - - let mut assembly = KeypairAssembly { - num_inputs: 0, - num_aux: 0, - num_constraints: 0, - at_inputs: vec![], - bt_inputs: vec![], - ct_inputs: vec![], - at_aux: vec![], - bt_aux: vec![], - ct_aux: vec![] - }; - - assembly.alloc_input(E::Fr::one(e)); - - circuit.synthesize(e, &mut assembly).synthesize(e, &mut assembly); - - // Input consistency constraints: x * 0 = 0 - for i in 0..assembly.num_inputs { - assembly.enforce(LinearCombination::zero(e).add(E::Fr::one(e), Variable(Index::Input(i))), - LinearCombination::zero(e), - LinearCombination::zero(e)); - } - - let domain = domain::EvaluationDomain::new(e, assembly.num_constraints as u64); - - let mut u = Vec::with_capacity(domain.m as usize); - { - let mut acc = E::Fr::one(e); - for _ in 0..domain.m { - u.push(acc); - acc.mul_assign(e, tau); - } - } - - let gamma_inverse = gamma.inverse(e).unwrap(); - let delta_inverse = delta.inverse(e).unwrap(); - - let g1_table; - let h; - { - let mut powers_of_tau = u.clone(); - powers_of_tau.truncate((domain.m - 1) as usize); - - let mut coeff = delta_inverse; - coeff.mul_assign(e, &domain.z(e, tau)); - for h in &mut powers_of_tau { - h.mul_assign(e, &coeff); - } - - g1_table = E::G1::one(e).optimal_window_batch(e, - (domain.m - 1) as usize + (assembly.num_inputs + assembly.num_aux) * 3 - ); - - h = e.batch_baseexp(&g1_table, powers_of_tau); - } - - domain.ifft(e, &mut u); - - fn eval( - e: &E, - u: &[E::Fr], - alpha: &E::Fr, - beta: &E::Fr, - inv: &E::Fr, - at_in: Vec>, - bt_in: Vec>, - ct_in: Vec> - ) -> (Vec, Vec, Vec) - { - assert_eq!(at_in.len(), bt_in.len()); - assert_eq!(bt_in.len(), ct_in.len()); - - fn eval_at_tau( - e: &E, - val: Vec<(E::Fr, usize)>, - u: &[E::Fr] - ) -> E::Fr - { - let mut acc = E::Fr::zero(); - - for (coeff, index) in val { - let mut n = u[index]; - n.mul_assign(e, &coeff); - acc.add_assign(e, &n); - } - - acc - } - - let mut a_out = Vec::with_capacity(at_in.len()); - let mut b_out = Vec::with_capacity(at_in.len()); - let mut l_out = Vec::with_capacity(at_in.len()); - - for ((a, b), c) in at_in.into_iter().zip(bt_in.into_iter()).zip(ct_in.into_iter()) { - let a = eval_at_tau(e, a, u); - let b = eval_at_tau(e, b, u); - - let mut t0 = a; - t0.mul_assign(e, beta); - - let mut t1 = b; - t1.mul_assign(e, alpha); - - t0.add_assign(e, &t1); - t0.add_assign(e, &eval_at_tau(e, c, u)); - t0.mul_assign(e, inv); - - a_out.push(a); - b_out.push(b); - l_out.push(t0); - } - - (a_out, b_out, l_out) - } - - let (a_inputs, b_inputs, ic_coeffs) = eval(e, &u, alpha, beta, &gamma_inverse, assembly.at_inputs, assembly.bt_inputs, assembly.ct_inputs); - let a_inputs = e.batch_baseexp(&g1_table, a_inputs); - let b1_inputs = e.batch_baseexp(&g1_table, &b_inputs); - let ic_coeffs = e.batch_baseexp(&g1_table, ic_coeffs); - let (a_aux, b_aux, l_coeffs) = eval(e, &u, alpha, beta, &delta_inverse, assembly.at_aux, assembly.bt_aux, assembly.ct_aux); - let a_aux = e.batch_baseexp(&g1_table, a_aux); - let b1_aux = e.batch_baseexp(&g1_table, &b_aux); - let l_coeffs = e.batch_baseexp(&g1_table, l_coeffs); - - drop(g1_table); - - let g2_table = E::G2::one(e).optimal_window_batch(e, - (assembly.num_inputs + assembly.num_aux) - ); - - let b2_inputs = e.batch_baseexp(&g2_table, b_inputs); - let b2_aux = e.batch_baseexp(&g2_table, b_aux); - - let mut alpha_g1 = E::G1::one(e); - alpha_g1.mul_assign(e, alpha); - let mut beta_g1 = E::G1::one(e); - beta_g1.mul_assign(e, beta); - let mut beta_g2 = E::G2::one(e); - beta_g2.mul_assign(e, beta); - let mut gamma_g2 = E::G2::one(e); - gamma_g2.mul_assign(e, gamma); - let mut delta_g1 = E::G1::one(e); - delta_g1.mul_assign(e, delta); - let mut delta_g2 = E::G2::one(e); - delta_g2.mul_assign(e, delta); - - ( - ProvingKey { - a_inputs: a_inputs, - b1_inputs: b1_inputs, - b2_inputs: b2_inputs, - a_aux: a_aux, - b1_aux: b1_aux, - b2_aux: b2_aux, - h: h, - l: l_coeffs, - delta_g1: delta_g1.to_affine(e), - delta_g2: delta_g2.to_affine(e), - alpha_g1: alpha_g1.to_affine(e), - beta_g1: beta_g1.to_affine(e), - beta_g2: beta_g2.to_affine(e) - }, - VerifyingKey { - alpha_g1: alpha_g1.to_affine(e), - beta_g2: beta_g2.to_affine(e), - gamma_g2: gamma_g2.to_affine(e), - delta_g2: delta_g2.to_affine(e), - ic: ic_coeffs - } - ) -} - -pub fn prepare_verifying_key( - e: &E, - vk: &VerifyingKey -) -> PreparedVerifyingKey -{ - let mut gamma = vk.gamma_g2; - gamma.negate(e); - let mut delta = vk.delta_g2; - delta.negate(e); - - PreparedVerifyingKey { - alpha_g1_beta_g2: e.pairing(&vk.alpha_g1, &vk.beta_g2), - neg_gamma_g2: gamma.prepare(e), - neg_delta_g2: delta.prepare(e), - ic: vk.ic.clone() - } -} - -pub struct VerifierInput<'a, E: Engine + 'a> { - e: &'a E, - acc: E::G1, - ic: &'a [>::Affine], - insufficient_inputs: bool, - num_inputs: usize, - num_aux: usize -} - -impl<'a, E: Engine> ConstraintSystem for VerifierInput<'a, E> { - fn alloc(&mut self, _: E::Fr) -> Variable { - let index = self.num_aux; - self.num_aux += 1; - - Variable(Index::Aux(index)) - } - - fn enforce( - &mut self, - _: LinearCombination, - _: LinearCombination, - _: LinearCombination - ) - { - // Do nothing; we don't care about the constraint system - // in this context. - } -} - -pub fn verify<'a, E: Engine, C: Input, F: FnOnce(&mut VerifierInput<'a, E>) -> C>( - e: &'a E, - circuit: F, - proof: &Proof, - pvk: &'a PreparedVerifyingKey -) -> bool -{ - struct InputAllocator(T); - - impl<'a, 'b, E: Engine> PublicConstraintSystem for InputAllocator<&'b mut VerifierInput<'a, E>> { - fn alloc_input(&mut self, value: E::Fr) -> Variable { - if self.0.ic.len() == 0 { - self.0.insufficient_inputs = true; - } else { - self.0.acc.add_assign(self.0.e, &self.0.ic[0].mul(self.0.e, &value)); - self.0.ic = &self.0.ic[1..]; - } - - let index = self.0.num_inputs; - self.0.num_inputs += 1; - - Variable(Index::Input(index)) - } - } - - impl<'a, 'b, E: Engine> ConstraintSystem for InputAllocator<&'b mut VerifierInput<'a, E>> { - fn alloc(&mut self, num: E::Fr) -> Variable { - self.0.alloc(num) - } - - fn enforce( - &mut self, - a: LinearCombination, - b: LinearCombination, - c: LinearCombination - ) - { - self.0.enforce(a, b, c); - } - } - - let mut witness = VerifierInput { - e: e, - acc: pvk.ic[0].to_jacobian(e), - ic: &pvk.ic[1..], - insufficient_inputs: false, - num_inputs: 1, - num_aux: 0 - }; - - circuit(&mut witness).synthesize(e, &mut InputAllocator(&mut witness)); - - if witness.ic.len() != 0 || witness.insufficient_inputs { - return false; - } - - e.final_exponentiation( - &e.miller_loop([ - (&proof.a.prepare(e), &proof.b.prepare(e)), - (&witness.acc.prepare(e), &pvk.neg_gamma_g2), - (&proof.c.prepare(e), &pvk.neg_delta_g2) - ].into_iter()) - ) == pvk.alpha_g1_beta_g2 -} - -pub fn prove>( - e: &E, - circuit: C, - r: &E::Fr, - s: &E::Fr, - pk: &ProvingKey -) -> Result, ()> -{ - struct ProvingAssignment<'a, E: Engine + 'a> { - e: &'a E, - // Evaluations of A, B, C polynomials - a: Vec, - b: Vec, - c: Vec, - // Assignments of variables - input_assignment: Vec, - aux_assignment: Vec - } - - impl<'a, E: Engine> PublicConstraintSystem for ProvingAssignment<'a, E> { - fn alloc_input(&mut self, value: E::Fr) -> Variable { - self.input_assignment.push(value); - - Variable(Index::Input(self.input_assignment.len() - 1)) - } - } - - impl<'a, E: Engine> ConstraintSystem for ProvingAssignment<'a, E> { - fn alloc(&mut self, value: E::Fr) -> Variable { - self.aux_assignment.push(value); - - Variable(Index::Aux(self.aux_assignment.len() - 1)) - } - - fn enforce( - &mut self, - a: LinearCombination, - b: LinearCombination, - c: LinearCombination - ) - { - self.a.push(a.evaluate(self.e, &self.input_assignment, &self.aux_assignment)); - self.b.push(b.evaluate(self.e, &self.input_assignment, &self.aux_assignment)); - self.c.push(c.evaluate(self.e, &self.input_assignment, &self.aux_assignment)); - } - } - - let mut prover = ProvingAssignment { - e: e, - a: vec![], - b: vec![], - c: vec![], - input_assignment: vec![], - aux_assignment: vec![] - }; - - prover.alloc_input(E::Fr::one(e)); - - circuit.synthesize(e, &mut prover).synthesize(e, &mut prover); - - // Input consistency constraints: x * 0 = 0 - for i in 0..prover.input_assignment.len() { - prover.enforce(LinearCombination::zero(e).add(E::Fr::one(e), Variable(Index::Input(i))), - LinearCombination::zero(e), - LinearCombination::zero(e)); - } - - // Perform FFTs - let h = { - let domain = domain::EvaluationDomain::new(e, prover.a.len() as u64); - prover.a.resize(domain.m as usize, E::Fr::zero()); - prover.b.resize(domain.m as usize, E::Fr::zero()); - prover.c.resize(domain.m as usize, E::Fr::zero()); - domain.ifft(e, &mut prover.a); - domain.coset_fft(e, &mut prover.a); - domain.ifft(e, &mut prover.b); - domain.coset_fft(e, &mut prover.b); - domain.ifft(e, &mut prover.c); - domain.coset_fft(e, &mut prover.c); - - let mut h = prover.a; - domain.mul_assign(e, &mut h, prover.b); - domain.sub_assign(e, &mut h, prover.c); - domain.divide_by_z_on_coset(e, &mut h); - domain.icoset_fft(e, &mut h); - - e.multiexp(&pk.h, &h[0..(domain.m-1) as usize])? - }; - - // Construct proof - let mut g_a = pk.delta_g1.mul(e, r); - g_a.add_assign(e, &pk.alpha_g1.to_jacobian(e)); - let mut g_b = pk.delta_g2.mul(e, s); - g_b.add_assign(e, &pk.beta_g2.to_jacobian(e)); - let mut g_c; - { - let mut rs = *r; - rs.mul_assign(e, s); - g_c = pk.delta_g1.mul(e, &rs); - g_c.add_assign(e, &pk.alpha_g1.mul(e, s)); - g_c.add_assign(e, &pk.beta_g1.mul(e, r)); - } - let mut a_answer: E::G1 = e.multiexp(&pk.a_inputs, &prover.input_assignment)?; - a_answer.add_assign(e, &e.multiexp(&pk.a_aux, &prover.aux_assignment)?); - g_a.add_assign(e, &a_answer); - a_answer.mul_assign(e, s); - g_c.add_assign(e, &a_answer); - let mut b1_answer: E::G1 = e.multiexp(&pk.b1_inputs, &prover.input_assignment)?; - b1_answer.add_assign(e, &e.multiexp(&pk.b1_aux, &prover.aux_assignment)?); - let mut b2_answer: E::G2 = e.multiexp(&pk.b2_inputs, &prover.input_assignment)?; - b2_answer.add_assign(e, &e.multiexp(&pk.b2_aux, &prover.aux_assignment)?); - g_b.add_assign(e, &b2_answer); - b1_answer.mul_assign(e, r); - g_c.add_assign(e, &b1_answer); - g_c.add_assign(e, &h); - g_c.add_assign(e, &e.multiexp(&pk.l, &prover.aux_assignment)?); - - Ok(Proof { - a: g_a, - b: g_b, - c: g_c - }) -} - -#[cfg(test)] -mod tests; diff --git a/src/groth16/tests/mod.rs b/src/groth16/tests/mod.rs deleted file mode 100644 index 908de83b4..000000000 --- a/src/groth16/tests/mod.rs +++ /dev/null @@ -1,207 +0,0 @@ -use super::*; -use rand::{Rng, thread_rng}; - -struct RootCircuit { - root: E::Fr -} - -impl Circuit for RootCircuit { - type InputMap = RootInput; - - fn synthesize>(self, - e: &E, - cs: &mut CS) - -> Self::InputMap - { - let root_var = cs.alloc(self.root); - - let mut cur = root_var; - let mut cur_val = self.root; - - for _ in 0..99 { - cur_val.mul_assign(e, &self.root); - let new = cs.alloc(cur_val); - - cs.enforce( - LinearCombination::zero(e) + (E::Fr::from_str(e, "3").unwrap(), cur), - LinearCombination::zero(e) + (E::Fr::from_str(e, "4").unwrap(), root_var), - LinearCombination::zero(e) + (E::Fr::from_str(e, "12").unwrap(), new), - ); - - cur = new; - } - - RootInput { - num: cur_val, - num_var: cur - } - } -} - -struct RootInput { - num: E::Fr, - num_var: Variable -} - -impl Input for RootInput { - fn synthesize>( - self, - e: &E, - cs: &mut CS - ) - { - let result_input = cs.alloc_input(self.num); - cs.enforce( - LinearCombination::zero(e) + result_input, - LinearCombination::one(e), - LinearCombination::zero(e) + self.num_var - ); - } -} - -fn test_snark_system( - e: &E, - rng: &mut R -) -{ - let tau = E::Fr::random(e, rng); - let alpha = E::Fr::random(e, rng); - let beta = E::Fr::random(e, rng); - let gamma = E::Fr::random(e, rng); - let delta = E::Fr::random(e, rng); - - // create keypair - let (pk, vk) = { - let c = RootCircuit { - root: E::Fr::zero() - }; - - keypair(e, c, &tau, &alpha, &beta, &gamma, &delta) - }; - - // construct proof - let proof = { - let r = E::Fr::random(e, rng); - let s = E::Fr::random(e, rng); - - let c = RootCircuit { - root: E::Fr::from_str(e, "2").unwrap() - }; - - prove(e, c, &r, &s, &pk).unwrap() - }; - - // prepare verifying key - let pvk = prepare_verifying_key(e, &vk); - - // verify proof - assert!(verify(e, |cs| { - RootInput { - num: E::Fr::from_str(e, "1267650600228229401496703205376").unwrap(), - num_var: cs.alloc(E::Fr::one(e)) - } - }, &proof, &pvk)); - - // verify invalid proof - assert!(!verify(e, |cs| { - RootInput { - num: E::Fr::from_str(e, "1267650600228229401496703205375").unwrap(), - num_var: cs.alloc(E::Fr::one(e)) - } - }, &proof, &pvk)); - - // simulate a groth proof with trapdoors - // ---------------- - // 99: a1 * a0 = l* - // 100: a0 * 0 = 0 - // 101: a1 * 0 = 0 - // --- - // u_0(tau) = tau^100 - // u_1(tau) = tau^99 + tau^101 - // v_0(tau) = tau^99 - // v_1(tau) = 0 - // w_0(tau) = 0 - // w_1(tau) = 0 - // --- - - let mut lagrange_coeffs: Vec = (0..128).map(|i| tau.pow(e, &[i])).collect(); - - let d = domain::EvaluationDomain::new(e, 128); - d.ifft(e, &mut lagrange_coeffs); - - let a = E::Fr::random(e, rng); - let b = E::Fr::random(e, rng); - - let mut c = a; - c.mul_assign(e, &b); - - let mut alphabeta = alpha; - alphabeta.mul_assign(e, &beta); - c.sub_assign(e, &alphabeta); - - let mut ic = E::Fr::zero(); - { - let mut ic_i_beta = lagrange_coeffs[100]; - ic_i_beta.mul_assign(e, &beta); - - let mut ic_i_alpha = lagrange_coeffs[99]; - ic_i_alpha.mul_assign(e, &alpha); - - ic_i_beta.add_assign(e, &ic_i_alpha); - - ic.add_assign(e, &ic_i_beta); - } - { - let mut ic_i_beta = lagrange_coeffs[99]; - ic_i_beta.add_assign(e, &lagrange_coeffs[101]); - ic_i_beta.mul_assign(e, &beta); - - ic_i_beta.mul_assign(e, &E::Fr::from_str(e, "100").unwrap()); - - ic.add_assign(e, &ic_i_beta); - } - - c.sub_assign(e, &ic); - c.mul_assign(e, &delta.inverse(e).unwrap()); - - let mut a_g = E::G1::one(e); - a_g.mul_assign(e, &a); - - let mut b_g = E::G2::one(e); - b_g.mul_assign(e, &b); - - let mut c_g = E::G1::one(e); - c_g.mul_assign(e, &c); - - let fake_proof = Proof { - a: a_g, - b: b_g, - c: c_g - }; - - // verify fake proof - assert!(verify(e, |cs| { - RootInput { - num: E::Fr::from_str(e, "100").unwrap(), - num_var: cs.alloc(E::Fr::one(e)) - } - }, &fake_proof, &pvk)); - - // verify fake proof with wrong input - assert!(!verify(e, |cs| { - RootInput { - num: E::Fr::from_str(e, "101").unwrap(), - num_var: cs.alloc(E::Fr::one(e)) - } - }, &fake_proof, &pvk)); -} - -#[test] -fn groth_with_bls381() { - use curves::bls381::Bls381; - - let e = &Bls381::new(); - let rng = &mut thread_rng(); - - test_snark_system(e, rng); -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 52ccb71d7..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,215 +0,0 @@ -#![feature(i128_type)] - -extern crate rand; -extern crate num_cpus; -extern crate crossbeam; -extern crate byteorder; -extern crate serde; - -pub mod curves; -pub mod groth16; - -use std::collections::HashMap; -use std::ops; -use std::ops::Deref; -use std::borrow::Borrow; - -use curves::{Engine, Field}; - -#[derive(Copy, Clone)] -pub struct Variable(Index); - -impl Variable { - pub fn one() -> Self { - Variable(Index::Input(0)) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -enum Index { - Input(usize), - Aux(usize) -} - -pub struct LinearCombination<'a, E: Engine + 'a>(HashMap, &'a E); - -impl<'a, E: Engine + 'a> ops::Add for LinearCombination<'a, E> { - type Output = LinearCombination<'a, E>; - - fn add(self, other: Variable) -> LinearCombination<'a, E> { - let one = E::Fr::one(self.1); - - self.add(one, other) - } -} - -impl<'a, E: Engine + 'a> ops::Add<(E::Fr, Variable)> for LinearCombination<'a, E> { - type Output = LinearCombination<'a, E>; - - fn add(self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<'a, E> { - self.add(coeff, var) - } -} - -impl<'a, E: Engine + 'a> ops::Sub for LinearCombination<'a, E> { - type Output = LinearCombination<'a, E>; - - fn sub(self, other: Variable) -> LinearCombination<'a, E> { - let one = E::Fr::one(self.1); - - self.sub(one, other) - } -} - -impl<'a, E: Engine + 'a> ops::Sub<(E::Fr, Variable)> for LinearCombination<'a, E> { - type Output = LinearCombination<'a, E>; - - fn sub(self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<'a, E> { - self.sub(coeff, var) - } -} - -impl<'a, E: Engine> LinearCombination<'a, E> { - pub fn zero(e: &'a E) -> LinearCombination<'a, E> { - LinearCombination(HashMap::new(), e) - } - - pub fn one(e: &'a E) -> LinearCombination<'a, E> { - LinearCombination::zero(e).add(E::Fr::one(e), Variable::one()) - } - - pub fn add(mut self, coeff: E::Fr, var: Variable) -> Self - { - self.0.entry(var.0) - .or_insert(E::Fr::zero()) - .add_assign(self.1, &coeff); - - self - } - - pub fn sub(self, mut coeff: E::Fr, var: Variable) -> Self - { - coeff.negate(self.1); - - self.add(coeff, var) - } - - fn evaluate( - &self, - e: &E, - input_assignment: &[E::Fr], - aux_assignment: &[E::Fr] - ) -> E::Fr - { - let mut acc = E::Fr::zero(); - for (index, coeff) in self.0.iter() { - let mut n = *coeff; - match index { - &Index::Input(id) => { - n.mul_assign(e, &input_assignment[id]); - }, - &Index::Aux(id) => { - n.mul_assign(e, &aux_assignment[id]); - } - } - acc.add_assign(e, &n); - } - - acc - } -} - -pub trait Circuit { - type InputMap: Input; - - /// Synthesize the circuit into a rank-1 quadratic constraint system - #[must_use] - fn synthesize>(self, engine: &E, cs: &mut CS) -> Self::InputMap; -} - -pub trait Input { - /// Synthesize the circuit, except with additional access to public input - /// variables - fn synthesize>(self, engine: &E, cs: &mut CS); -} - -pub trait PublicConstraintSystem: ConstraintSystem { - /// Allocate a public input that the verifier knows. - fn alloc_input(&mut self, value: E::Fr) -> Variable; -} - -pub trait ConstraintSystem { - /// Allocate a private variable in the constraint system, setting it to - /// the provided value. - fn alloc(&mut self, value: E::Fr) -> Variable; - - /// Enforce that `A` * `B` = `C`. - fn enforce( - &mut self, - a: LinearCombination, - b: LinearCombination, - c: LinearCombination - ); -} - -pub enum Cow<'a, T: 'a> { - Owned(T), - Borrowed(&'a T) -} - -impl<'a, T: 'a> Deref for Cow<'a, T> { - type Target = T; - - fn deref(&self) -> &T { - match *self { - Cow::Owned(ref v) => v, - Cow::Borrowed(v) => v - } - } -} - -pub trait Convert { - type Target: Borrow; - - fn convert(&self, &E) -> Cow; -} - -impl Convert for T { - type Target = T; - - fn convert(&self, _: &E) -> Cow { - Cow::Borrowed(self) - } -} - -pub struct BitIterator { - t: T, - n: usize -} - -impl> BitIterator { - fn new(t: T) -> Self { - let bits = 64 * t.as_ref().len(); - - BitIterator { - t: t, - n: bits - } - } -} - -impl> Iterator for BitIterator { - type Item = bool; - - fn next(&mut self) -> Option { - if self.n == 0 { - None - } else { - self.n -= 1; - let part = self.n / 64; - let bit = self.n - (64 * part); - - Some(self.t.as_ref()[part] & (1 << bit) > 0) - } - } -}