pairing: Move PairingCurveAffine::Prepared to MultiMillerLoop trait

Prepared elements are only used by MultiMillerLoop, and we don't need
the ability to "prepare" G1 elements there.
This commit is contained in:
Jack Grigg 2020-06-03 18:01:57 +12:00
parent b9d6df9133
commit 03f086221b
8 changed files with 38 additions and 93 deletions

View File

@ -3,7 +3,7 @@
//! [Groth16]: https://eprint.iacr.org/2016/260 //! [Groth16]: https://eprint.iacr.org/2016/260
use group::CurveAffine; use group::CurveAffine;
use pairing::{Engine, PairingCurveAffine}; use pairing::{Engine, MultiMillerLoop};
use crate::SynthesisError; use crate::SynthesisError;
@ -398,13 +398,13 @@ impl<E: Engine> Parameters<E> {
} }
} }
pub struct PreparedVerifyingKey<E: Engine> { pub struct PreparedVerifyingKey<E: MultiMillerLoop> {
/// Pairing result of alpha*beta /// Pairing result of alpha*beta
alpha_g1_beta_g2: E::Gt, alpha_g1_beta_g2: E::Gt,
/// -gamma in G2 /// -gamma in G2
neg_gamma_g2: <E::G2Affine as PairingCurveAffine>::Prepared, neg_gamma_g2: E::G2Prepared,
/// -delta in G2 /// -delta in G2
neg_delta_g2: <E::G2Affine as PairingCurveAffine>::Prepared, neg_delta_g2: E::G2Prepared,
/// Copy of IC from `VerifiyingKey`. /// Copy of IC from `VerifiyingKey`.
ic: Vec<E::G1Affine>, ic: Vec<E::G1Affine>,
} }

View File

@ -338,20 +338,16 @@ impl Engine for DummyEngine {
type Gt = Fr; type Gt = Fr;
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt { fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
Self::multi_miller_loop(&[(p, &(q.prepare()))]).final_exponentiation() Self::multi_miller_loop(&[(p, &(*q).into())]).final_exponentiation()
} }
} }
impl MultiMillerLoop for DummyEngine { impl MultiMillerLoop for DummyEngine {
type G2Prepared = Fr;
// TODO: This should be F_645131 or something. Doesn't matter for now. // TODO: This should be F_645131 or something. Doesn't matter for now.
type Result = Fr; type Result = Fr;
fn multi_miller_loop( fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
terms: &[(
&Self::G1Affine,
&<Self::G2Affine as PairingCurveAffine>::Prepared,
)],
) -> Self::Result {
let mut acc = <Fr as Field>::zero(); let mut acc = <Fr as Field>::zero();
for &(a, b) in terms { for &(a, b) in terms {
@ -487,14 +483,9 @@ impl CurveAffine for Fr {
} }
impl PairingCurveAffine for Fr { impl PairingCurveAffine for Fr {
type Prepared = Fr;
type Pair = Fr; type Pair = Fr;
type PairingResult = Fr; type PairingResult = Fr;
fn prepare(&self) -> Self::Prepared {
*self
}
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.mul(*other) self.mul(*other)
} }

View File

@ -1,19 +1,19 @@
use group::{CurveAffine, CurveProjective}; use group::{CurveAffine, CurveProjective};
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use pairing::{MillerLoopResult, MultiMillerLoop};
use std::ops::{AddAssign, Neg}; use std::ops::{AddAssign, Neg};
use super::{PreparedVerifyingKey, Proof, VerifyingKey}; use super::{PreparedVerifyingKey, Proof, VerifyingKey};
use crate::SynthesisError; use crate::SynthesisError;
pub fn prepare_verifying_key<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> { pub fn prepare_verifying_key<E: MultiMillerLoop>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> {
let gamma = vk.gamma_g2.neg(); let gamma = vk.gamma_g2.neg();
let delta = vk.delta_g2.neg(); let delta = vk.delta_g2.neg();
PreparedVerifyingKey { PreparedVerifyingKey {
alpha_g1_beta_g2: E::pairing(&vk.alpha_g1, &vk.beta_g2), alpha_g1_beta_g2: E::pairing(&vk.alpha_g1, &vk.beta_g2),
neg_gamma_g2: gamma.prepare(), neg_gamma_g2: gamma.into(),
neg_delta_g2: delta.prepare(), neg_delta_g2: delta.into(),
ic: vk.ic.clone(), ic: vk.ic.clone(),
} }
} }
@ -42,7 +42,7 @@ pub fn verify_proof<'a, E: MultiMillerLoop>(
// which allows us to do a single final exponentiation. // which allows us to do a single final exponentiation.
Ok(E::multi_miller_loop(&[ Ok(E::multi_miller_loop(&[
(&proof.a, &proof.b.prepare()), (&proof.a, &proof.b.into()),
(&acc.to_affine(), &pvk.neg_gamma_g2), (&acc.to_affine(), &pvk.neg_gamma_g2),
(&proof.c, &pvk.neg_delta_g2), (&proof.c, &pvk.neg_delta_g2),
]) ])

View File

@ -12,26 +12,6 @@ use group::Group;
use pairing::bls12_381::*; use pairing::bls12_381::*;
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
fn bench_pairing_g1_preparation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<G1> = (0..SAMPLES).map(|_| G1::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("G1 preparation", |b| {
b.iter(|| {
let tmp = G1Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_pairing_g2_preparation(c: &mut Criterion) { fn bench_pairing_g2_preparation(c: &mut Criterion) {
const SAMPLES: usize = 1000; const SAMPLES: usize = 1000;
@ -45,7 +25,7 @@ fn bench_pairing_g2_preparation(c: &mut Criterion) {
let mut count = 0; let mut count = 0;
c.bench_function("G2 preparation", |b| { c.bench_function("G2 preparation", |b| {
b.iter(|| { b.iter(|| {
let tmp = G2Affine::from(v[count]).prepare(); let tmp = G2Prepared::from(G2Affine::from(v[count]));
count = (count + 1) % SAMPLES; count = (count + 1) % SAMPLES;
tmp tmp
}) })
@ -64,7 +44,7 @@ fn bench_pairing_miller_loop(c: &mut Criterion) {
.map(|_| { .map(|_| {
( (
G1Affine::from(G1::random(&mut rng)), G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).prepare(), G2Affine::from(G2::random(&mut rng)).into(),
) )
}) })
.collect(); .collect();
@ -91,7 +71,7 @@ fn bench_pairing_final_exponentiation(c: &mut Criterion) {
.map(|_| { .map(|_| {
( (
G1Affine::from(G1::random(&mut rng)), G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).prepare(), G2Affine::from(G2::random(&mut rng)).into(),
) )
}) })
.map(|(ref p, ref q)| Bls12::multi_miller_loop(&[(p, q)])) .map(|(ref p, ref q)| Bls12::multi_miller_loop(&[(p, q)]))
@ -131,7 +111,6 @@ fn bench_pairing_full(c: &mut Criterion) {
criterion_group!( criterion_group!(
benches, benches,
bench_pairing_g1_preparation,
bench_pairing_g2_preparation, bench_pairing_g2_preparation,
bench_pairing_miller_loop, bench_pairing_miller_loop,
bench_pairing_final_exponentiation, bench_pairing_final_exponentiation,

View File

@ -3,7 +3,6 @@ macro_rules! curve_impl {
$name:expr, $name:expr,
$projective:ident, $projective:ident,
$affine:ident, $affine:ident,
$prepared:ident,
$basefield:ident, $basefield:ident,
$scalarfield:ident, $scalarfield:ident,
$uncompressed:ident, $uncompressed:ident,
@ -281,14 +280,9 @@ macro_rules! curve_impl {
} }
impl PairingCurveAffine for $affine { impl PairingCurveAffine for $affine {
type Prepared = $prepared;
type Pair = $pairing; type Pair = $pairing;
type PairingResult = Fq12; type PairingResult = Fq12;
fn prepare(&self) -> Self::Prepared {
$prepared::from_affine(*self)
}
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.perform_pairing(other) self.perform_pairing(other)
} }
@ -917,7 +911,6 @@ pub mod g1 {
"G1", "G1",
G1, G1,
G1Affine, G1Affine,
G1Prepared,
Fq, Fq,
Fr, Fr,
G1Uncompressed, G1Uncompressed,
@ -1173,19 +1166,6 @@ pub mod g1 {
} }
} }
#[derive(Clone, Debug)]
pub struct G1Prepared(pub(crate) G1Affine);
impl G1Prepared {
pub fn is_identity(&self) -> bool {
self.0.is_identity().into()
}
pub fn from_affine(p: G1Affine) -> Self {
G1Prepared(p)
}
}
#[test] #[test]
fn g1_generator() { fn g1_generator() {
let mut x = Fq::zero(); let mut x = Fq::zero();
@ -1507,7 +1487,6 @@ pub mod g2 {
"G2", "G2",
G2, G2,
G2Affine, G2Affine,
G2Prepared,
Fq2, Fq2,
Fr, Fr,
G2Uncompressed, G2Uncompressed,
@ -1818,6 +1797,12 @@ pub mod g2 {
pub(crate) infinity: bool, pub(crate) infinity: bool,
} }
impl From<G2Affine> for G2Prepared {
fn from(val: G2Affine) -> Self {
Self::from_affine(val)
}
}
#[test] #[test]
fn g2_generator() { fn g2_generator() {
let mut x = Fq2::zero(); let mut x = Fq2::zero();

View File

@ -12,8 +12,8 @@ mod fr;
mod tests; mod tests;
pub use self::ec::{ pub use self::ec::{
G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, G1Affine, G1Compressed, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, G2Uncompressed, G1,
G2Uncompressed, G1, G2, G2,
}; };
pub use self::fq::{Fq, FqRepr}; pub use self::fq::{Fq, FqRepr};
pub use self::fq12::Fq12; pub use self::fq12::Fq12;
@ -21,7 +21,7 @@ pub use self::fq2::Fq2;
pub use self::fq6::Fq6; pub use self::fq6::Fq6;
pub use self::fr::{Fr, FrRepr}; pub use self::fr::{Fr, FrRepr};
use super::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use super::{Engine, MillerLoopResult, MultiMillerLoop};
use ff::{BitIterator, Field, ScalarEngine}; use ff::{BitIterator, Field, ScalarEngine};
use group::CurveAffine; use group::CurveAffine;
@ -46,19 +46,15 @@ impl Engine for Bls12 {
type Gt = Fq12; type Gt = Fq12;
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt { fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
Self::multi_miller_loop(&[(p, &(q.prepare()))]).final_exponentiation() Self::multi_miller_loop(&[(p, &(*q).into())]).final_exponentiation()
} }
} }
impl MultiMillerLoop for Bls12 { impl MultiMillerLoop for Bls12 {
type G2Prepared = G2Prepared;
type Result = Fq12; type Result = Fq12;
fn multi_miller_loop( fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
terms: &[(
&Self::G1Affine,
&<Self::G2Affine as PairingCurveAffine>::Prepared,
)],
) -> Self::Result {
let mut pairs = vec![]; let mut pairs = vec![];
for &(p, q) in terms { for &(p, q) in terms {
if !bool::from(p.is_identity()) && !q.is_identity() { if !bool::from(p.is_identity()) && !q.is_identity() {

View File

@ -21,7 +21,7 @@ pub mod tests;
pub mod bls12_381; pub mod bls12_381;
use core::ops::Mul; use core::ops::Mul;
use ff::{Field, PrimeField, ScalarEngine}; use ff::{Field, ScalarEngine};
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned}; use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned};
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
@ -75,30 +75,24 @@ pub trait Engine: ScalarEngine {
/// Affine representation of an elliptic curve point that can be used /// Affine representation of an elliptic curve point that can be used
/// to perform pairings. /// to perform pairings.
pub trait PairingCurveAffine: CurveAffine { pub trait PairingCurveAffine: CurveAffine {
type Prepared: Clone + Send + Sync + 'static;
type Pair: PairingCurveAffine<Pair = Self>; type Pair: PairingCurveAffine<Pair = Self>;
type PairingResult: Field; type PairingResult: Field;
/// Prepares this element for pairing purposes.
fn prepare(&self) -> Self::Prepared;
/// Perform a pairing /// Perform a pairing
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult; fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
} }
/// An engine that can compute sums of pairings in an efficient way. /// An engine that can compute sums of pairings in an efficient way.
pub trait MultiMillerLoop: Engine { pub trait MultiMillerLoop: Engine {
/// The prepared form of `Self::G2Affine`.
type G2Prepared: Clone + Send + Sync + From<Self::G2Affine>;
/// The type returned by `Engine::miller_loop`. /// The type returned by `Engine::miller_loop`.
type Result: MillerLoopResult<Gt = Self::Gt>; type Result: MillerLoopResult<Gt = Self::Gt>;
/// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms /// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms
/// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$ /// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$
fn multi_miller_loop( fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result;
terms: &[(
&Self::G1Affine,
&<Self::G2Affine as PairingCurveAffine>::Prepared,
)],
) -> Self::Result;
} }
/// Represents results of a Miller loop, one of the most expensive portions of the pairing /// Represents results of a Miller loop, one of the most expensive portions of the pairing

View File

@ -22,12 +22,12 @@ pub fn engine_tests<E: MultiMillerLoop>() {
for _ in 0..1000 { for _ in 0..1000 {
let z1 = E::G1Affine::identity(); let z1 = E::G1Affine::identity();
let z2 = E::G2Affine::identity().prepare(); let z2 = E::G2Affine::identity().into();
let a = E::G1::random(&mut rng).to_affine(); let a = E::G1::random(&mut rng).to_affine();
let b = E::G2::random(&mut rng).to_affine().prepare(); let b = E::G2::random(&mut rng).to_affine().into();
let c = E::G1::random(&mut rng).to_affine(); let c = E::G1::random(&mut rng).to_affine();
let d = E::G2::random(&mut rng).to_affine().prepare(); let d = E::G2::random(&mut rng).to_affine().into();
assert_eq!( assert_eq!(
E::Gt::one(), E::Gt::one(),
@ -68,7 +68,7 @@ fn random_miller_loop_tests<E: MultiMillerLoop>() {
let p2 = E::pairing(&a, &b); let p2 = E::pairing(&a, &b);
let a = a; let a = a;
let b = b.prepare(); let b = b.into();
let p1 = E::multi_miller_loop(&[(&a, &b)]).final_exponentiation(); let p1 = E::multi_miller_loop(&[(&a, &b)]).final_exponentiation();
@ -89,9 +89,9 @@ fn random_miller_loop_tests<E: MultiMillerLoop>() {
abcd.mul_assign(&cd); abcd.mul_assign(&cd);
let a = a; let a = a;
let b = b.prepare(); let b = b.into();
let c = c; let c = c;
let d = d.prepare(); let d = d.into();
let abcd_with_double_loop = let abcd_with_double_loop =
E::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation(); E::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();