diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 8bcb8aa20..465bc2d70 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,6 +1,6 @@ use ff::{Field, PrimeField, ScalarEngine}; use group::{CurveAffine, CurveProjective, Group, PrimeGroup}; -use pairing::{Engine, PairingCurveAffine}; +use pairing::{Engine, MillerLoopResult, PairingCurveAffine}; use rand_core::RngCore; use std::fmt; @@ -357,10 +357,14 @@ impl Engine for DummyEngine { acc } +} + +impl MillerLoopResult for Fr { + type Gt = Fr; /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::MillerLoopResult) -> CtOption { - CtOption::new(*this, Choice::from(1)) + fn final_exponentiation(&self) -> Self::Gt { + *self } } diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index ae55b1409..d29a4bc9b 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -1,5 +1,5 @@ use group::{CurveAffine, CurveProjective}; -use pairing::{Engine, PairingCurveAffine}; +use pairing::{Engine, MillerLoopResult, PairingCurveAffine}; use std::ops::{AddAssign, Neg}; use super::{PreparedVerifyingKey, Proof, VerifyingKey}; @@ -41,14 +41,14 @@ pub fn verify_proof<'a, E: Engine>( // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta // which allows us to do a single final exponentiation. - Ok(E::final_exponentiation(&E::miller_loop( + Ok(E::miller_loop( [ (&proof.a.prepare(), &proof.b.prepare()), (&acc.to_affine().prepare(), &pvk.neg_gamma_g2), (&proof.c.prepare(), &pvk.neg_delta_g2), ] .iter(), - )) - .unwrap() + ) + .final_exponentiation() == pvk.alpha_g1_beta_g2) } diff --git a/pairing/benches/bls12_381/mod.rs b/pairing/benches/bls12_381/mod.rs index 212e7baaf..ad030579c 100644 --- a/pairing/benches/bls12_381/mod.rs +++ b/pairing/benches/bls12_381/mod.rs @@ -10,7 +10,7 @@ use rand_xorshift::XorShiftRng; use group::Group; use pairing::bls12_381::*; -use pairing::{Engine, PairingCurveAffine}; +use pairing::{Engine, MillerLoopResult, PairingCurveAffine}; fn bench_pairing_g1_preparation(c: &mut Criterion) { const SAMPLES: usize = 1000; @@ -100,7 +100,7 @@ fn bench_pairing_final_exponentiation(c: &mut Criterion) { let mut count = 0; c.bench_function("Final exponentiation", |b| { b.iter(|| { - let tmp = Bls12::final_exponentiation(&v[count]); + let tmp = v[count].final_exponentiation(); count = (count + 1) % SAMPLES; tmp }) diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index c47327062..6dd2cb416 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -21,12 +21,11 @@ pub use self::fq2::Fq2; pub use self::fq6::Fq6; pub use self::fr::{Fr, FrRepr}; -use super::{Engine, PairingCurveAffine}; +use super::{Engine, MillerLoopResult, PairingCurveAffine}; use ff::{BitIterator, Field, ScalarEngine}; use group::CurveAffine; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; -use subtle::CtOption; // The BLS parameter x for BLS12-381 is -0xd201000000010000 const BLS_X: u64 = 0xd201000000010000; @@ -110,59 +109,66 @@ impl Engine for Bls12 { f } +} - fn final_exponentiation(r: &Fq12) -> CtOption { - let mut f1 = *r; +impl MillerLoopResult for Fq12 { + type Gt = Fq12; + + fn final_exponentiation(&self) -> Fq12 { + let mut f1 = *self; f1.conjugate(); - r.invert().map(|mut f2| { - let mut r = f1; - r.mul_assign(&f2); - f2 = r; - r.frobenius_map(2); - r.mul_assign(&f2); + self.invert() + .map(|mut f2| { + let mut r = f1; + r.mul_assign(&f2); + f2 = r; + r.frobenius_map(2); + r.mul_assign(&f2); - fn exp_by_x(f: &mut Fq12, x: u64) { - *f = f.pow_vartime(&[x]); - if BLS_X_IS_NEGATIVE { - f.conjugate(); + fn exp_by_x(f: &mut Fq12, x: u64) { + *f = f.pow_vartime(&[x]); + if BLS_X_IS_NEGATIVE { + f.conjugate(); + } } - } - let mut x = BLS_X; - let y0 = r.square(); - let mut y1 = y0; - exp_by_x(&mut y1, x); - x >>= 1; - let mut y2 = y1; - exp_by_x(&mut y2, x); - x <<= 1; - let mut y3 = r; - y3.conjugate(); - y1.mul_assign(&y3); - y1.conjugate(); - y1.mul_assign(&y2); - y2 = y1; - exp_by_x(&mut y2, x); - y3 = y2; - exp_by_x(&mut y3, x); - y1.conjugate(); - y3.mul_assign(&y1); - y1.conjugate(); - y1.frobenius_map(3); - y2.frobenius_map(2); - y1.mul_assign(&y2); - y2 = y3; - exp_by_x(&mut y2, x); - y2.mul_assign(&y0); - y2.mul_assign(&r); - y1.mul_assign(&y2); - y2 = y3; - y2.frobenius_map(1); - y1.mul_assign(&y2); + let mut x = BLS_X; + let y0 = r.square(); + let mut y1 = y0; + exp_by_x(&mut y1, x); + x >>= 1; + let mut y2 = y1; + exp_by_x(&mut y2, x); + x <<= 1; + let mut y3 = r; + y3.conjugate(); + y1.mul_assign(&y3); + y1.conjugate(); + y1.mul_assign(&y2); + y2 = y1; + exp_by_x(&mut y2, x); + y3 = y2; + exp_by_x(&mut y3, x); + y1.conjugate(); + y3.mul_assign(&y1); + y1.conjugate(); + y1.frobenius_map(3); + y2.frobenius_map(2); + y1.mul_assign(&y2); + y2 = y3; + exp_by_x(&mut y2, x); + y2.mul_assign(&y0); + y2.mul_assign(&r); + y1.mul_assign(&y2); + y2 = y3; + y2.frobenius_map(1); + y1.mul_assign(&y2); - y1 - }) + y1 + }) + // self must be nonzero. + .unwrap() } } diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 4c3ce959b..5248208d1 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -23,7 +23,6 @@ pub mod bls12_381; use core::ops::Mul; use ff::{Field, PrimeField, ScalarEngine}; use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned}; -use subtle::CtOption; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// with well-defined relationships. In particular, the G1/G2 curve groups are @@ -66,7 +65,7 @@ pub trait Engine: ScalarEngine { + for<'a> Mul<&'a Self::Fr, Output = Self::G2>; /// The type returned by `Engine::miller_loop`. - type MillerLoopResult; + type MillerLoopResult: MillerLoopResult; /// The extension field that hosts the target group of the pairing. type Gt: Field; @@ -81,19 +80,14 @@ pub trait Engine: ScalarEngine { ), >; - /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(_: &Self::MillerLoopResult) -> CtOption; - /// Performs a complete pairing operation `(p, q)`. fn pairing(p: G1, q: G2) -> Self::Gt where G1: Into, G2: Into, { - Self::final_exponentiation(&Self::miller_loop( - [(&(p.into().prepare()), &(q.into().prepare()))].iter(), - )) - .unwrap() + Self::miller_loop([(&(p.into().prepare()), &(q.into().prepare()))].iter()) + .final_exponentiation() } } @@ -110,3 +104,18 @@ pub trait PairingCurveAffine: CurveAffine { /// Perform a pairing fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult; } + +/// Represents results of a Miller loop, one of the most expensive portions of the pairing +/// function. +/// +/// `MillerLoopResult`s cannot be compared with each other until +/// [`MillerLoopResult::final_exponentiation`] is called, which is also expensive. +pub trait MillerLoopResult { + /// The extension field that hosts the target group of the pairing. + type Gt: Field; + + /// This performs a "final exponentiation" routine to convert the result of a Miller + /// loop into an element of [`MillerLoopResult::Gt`], so that it can be compared with + /// other elements of `Gt`. + fn final_exponentiation(&self) -> Self::Gt; +} diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 44111c671..df2ad8abd 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -4,7 +4,7 @@ use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::MulAssign; -use crate::{Engine, PairingCurveAffine}; +use crate::{Engine, MillerLoopResult, PairingCurveAffine}; pub fn engine_tests() { let mut rng = XorShiftRng::from_seed([ @@ -31,22 +31,22 @@ pub fn engine_tests() { assert_eq!( E::Gt::one(), - E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap() + E::miller_loop(&[(&z1, &b)]).final_exponentiation() ); assert_eq!( E::Gt::one(), - E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap() + E::miller_loop(&[(&a, &z2)]).final_exponentiation() ); assert_eq!( - E::final_exponentiation(&E::miller_loop(&[(&z1, &b), (&c, &d)])).unwrap(), - E::final_exponentiation(&E::miller_loop(&[(&a, &z2), (&c, &d)])).unwrap() + E::miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(), + E::miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation() ); assert_eq!( - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&z1, &d)])).unwrap(), - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &z2)])).unwrap() + E::miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(), + E::miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation() ); } @@ -70,7 +70,7 @@ fn random_miller_loop_tests() { let a = a.to_affine().prepare(); let b = b.to_affine().prepare(); - let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap(); + let p1 = E::miller_loop(&[(&a, &b)]).final_exponentiation(); assert_eq!(p1, p2); } @@ -93,8 +93,7 @@ fn random_miller_loop_tests() { let c = c.to_affine().prepare(); let d = d.to_affine().prepare(); - let abcd_with_double_loop = - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &d)])).unwrap(); + let abcd_with_double_loop = E::miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation(); assert_eq!(abcd, abcd_with_double_loop); }