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
use group::CurveAffine;
use pairing::{Engine, PairingCurveAffine};
use pairing::{Engine, MultiMillerLoop};
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
alpha_g1_beta_g2: E::Gt,
/// -gamma in G2
neg_gamma_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
neg_gamma_g2: E::G2Prepared,
/// -delta in G2
neg_delta_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
neg_delta_g2: E::G2Prepared,
/// Copy of IC from `VerifiyingKey`.
ic: Vec<E::G1Affine>,
}

View File

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

View File

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

View File

@ -12,26 +12,6 @@ use group::Group;
use pairing::bls12_381::*;
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) {
const SAMPLES: usize = 1000;
@ -45,7 +25,7 @@ fn bench_pairing_g2_preparation(c: &mut Criterion) {
let mut count = 0;
c.bench_function("G2 preparation", |b| {
b.iter(|| {
let tmp = G2Affine::from(v[count]).prepare();
let tmp = G2Prepared::from(G2Affine::from(v[count]));
count = (count + 1) % SAMPLES;
tmp
})
@ -64,7 +44,7 @@ fn bench_pairing_miller_loop(c: &mut Criterion) {
.map(|_| {
(
G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).prepare(),
G2Affine::from(G2::random(&mut rng)).into(),
)
})
.collect();
@ -91,7 +71,7 @@ fn bench_pairing_final_exponentiation(c: &mut Criterion) {
.map(|_| {
(
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)]))
@ -131,7 +111,6 @@ fn bench_pairing_full(c: &mut Criterion) {
criterion_group!(
benches,
bench_pairing_g1_preparation,
bench_pairing_g2_preparation,
bench_pairing_miller_loop,
bench_pairing_final_exponentiation,

View File

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

View File

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

View File

@ -21,7 +21,7 @@ pub mod tests;
pub mod bls12_381;
use core::ops::Mul;
use ff::{Field, PrimeField, ScalarEngine};
use ff::{Field, ScalarEngine};
use group::{CurveAffine, CurveProjective, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned};
/// 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
/// to perform pairings.
pub trait PairingCurveAffine: CurveAffine {
type Prepared: Clone + Send + Sync + 'static;
type Pair: PairingCurveAffine<Pair = Self>;
type PairingResult: Field;
/// Prepares this element for pairing purposes.
fn prepare(&self) -> Self::Prepared;
/// Perform a pairing
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
}
/// An engine that can compute sums of pairings in an efficient way.
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`.
type Result: MillerLoopResult<Gt = Self::Gt>;
/// 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).$$
fn multi_miller_loop(
terms: &[(
&Self::G1Affine,
&<Self::G2Affine as PairingCurveAffine>::Prepared,
)],
) -> Self::Result;
fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result;
}
/// 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 {
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 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 d = E::G2::random(&mut rng).to_affine().prepare();
let d = E::G2::random(&mut rng).to_affine().into();
assert_eq!(
E::Gt::one(),
@ -68,7 +68,7 @@ fn random_miller_loop_tests<E: MultiMillerLoop>() {
let p2 = E::pairing(&a, &b);
let a = a;
let b = b.prepare();
let b = b.into();
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);
let a = a;
let b = b.prepare();
let b = b.into();
let c = c;
let d = d.prepare();
let d = d.into();
let abcd_with_double_loop =
E::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();