pairing: Extract Engine::miller_loop into a MultiMillerLoop trait
This enables MultiMillerLoop to be conditionally implemented, for example in libraries where Engine::pairing supports no-std, but MultiMillerLoop requires an allocator.
This commit is contained in:
parent
da2e638c7d
commit
b9d6df9133
|
@ -1,6 +1,6 @@
|
|||
use ff::{Field, PrimeField, ScalarEngine};
|
||||
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
|
||||
use pairing::{Engine, MillerLoopResult, PairingCurveAffine};
|
||||
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||
|
||||
use rand_core::RngCore;
|
||||
use std::fmt;
|
||||
|
@ -335,21 +335,26 @@ impl Engine for DummyEngine {
|
|||
type G2Affine = Fr;
|
||||
|
||||
// TODO: This should be F_645131 or something. Doesn't matter for now.
|
||||
type MillerLoopResult = Fr;
|
||||
type Gt = Fr;
|
||||
|
||||
fn miller_loop<'a, I>(i: I) -> Self::MillerLoopResult
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>,
|
||||
{
|
||||
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
|
||||
Self::multi_miller_loop(&[(p, &(q.prepare()))]).final_exponentiation()
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiMillerLoop for DummyEngine {
|
||||
// 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 {
|
||||
let mut acc = <Fr as Field>::zero();
|
||||
|
||||
for &(a, b) in i {
|
||||
for &(a, b) in terms {
|
||||
let mut tmp = *a;
|
||||
MulAssign::mul_assign(&mut tmp, b);
|
||||
AddAssign::add_assign(&mut acc, &tmp);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use group::{CurveAffine, CurveProjective};
|
||||
use pairing::{Engine, MillerLoopResult, PairingCurveAffine};
|
||||
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||
use std::ops::{AddAssign, Neg};
|
||||
|
||||
use super::{PreparedVerifyingKey, Proof, VerifyingKey};
|
||||
|
@ -18,7 +18,7 @@ pub fn prepare_verifying_key<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyi
|
|||
}
|
||||
}
|
||||
|
||||
pub fn verify_proof<'a, E: Engine>(
|
||||
pub fn verify_proof<'a, E: MultiMillerLoop>(
|
||||
pvk: &'a PreparedVerifyingKey<E>,
|
||||
proof: &Proof<E>,
|
||||
public_inputs: &[E::Fr],
|
||||
|
@ -41,14 +41,11 @@ 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::miller_loop(
|
||||
[
|
||||
(&proof.a.prepare(), &proof.b.prepare()),
|
||||
(&acc.to_affine().prepare(), &pvk.neg_gamma_g2),
|
||||
(&proof.c.prepare(), &pvk.neg_delta_g2),
|
||||
]
|
||||
.iter(),
|
||||
)
|
||||
Ok(E::multi_miller_loop(&[
|
||||
(&proof.a, &proof.b.prepare()),
|
||||
(&acc.to_affine(), &pvk.neg_gamma_g2),
|
||||
(&proof.c, &pvk.neg_delta_g2),
|
||||
])
|
||||
.final_exponentiation()
|
||||
== pvk.alpha_g1_beta_g2)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use rand_xorshift::XorShiftRng;
|
|||
|
||||
use group::Group;
|
||||
use pairing::bls12_381::*;
|
||||
use pairing::{Engine, MillerLoopResult, PairingCurveAffine};
|
||||
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||
|
||||
fn bench_pairing_g1_preparation(c: &mut Criterion) {
|
||||
const SAMPLES: usize = 1000;
|
||||
|
@ -60,10 +60,10 @@ fn bench_pairing_miller_loop(c: &mut Criterion) {
|
|||
0xe5,
|
||||
]);
|
||||
|
||||
let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES)
|
||||
let v: Vec<(G1Affine, G2Prepared)> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
(
|
||||
G1Affine::from(G1::random(&mut rng)).prepare(),
|
||||
G1Affine::from(G1::random(&mut rng)),
|
||||
G2Affine::from(G2::random(&mut rng)).prepare(),
|
||||
)
|
||||
})
|
||||
|
@ -72,7 +72,7 @@ fn bench_pairing_miller_loop(c: &mut Criterion) {
|
|||
let mut count = 0;
|
||||
c.bench_function("Miller loop", |b| {
|
||||
b.iter(|| {
|
||||
let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]);
|
||||
let tmp = Bls12::multi_miller_loop(&[(&v[count].0, &v[count].1)]);
|
||||
count = (count + 1) % SAMPLES;
|
||||
tmp
|
||||
})
|
||||
|
@ -90,11 +90,11 @@ fn bench_pairing_final_exponentiation(c: &mut Criterion) {
|
|||
let v: Vec<Fq12> = (0..SAMPLES)
|
||||
.map(|_| {
|
||||
(
|
||||
G1Affine::from(G1::random(&mut rng)).prepare(),
|
||||
G1Affine::from(G1::random(&mut rng)),
|
||||
G2Affine::from(G2::random(&mut rng)).prepare(),
|
||||
)
|
||||
})
|
||||
.map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)]))
|
||||
.map(|(ref p, ref q)| Bls12::multi_miller_loop(&[(p, q)]))
|
||||
.collect();
|
||||
|
||||
let mut count = 0;
|
||||
|
|
|
@ -21,7 +21,7 @@ pub use self::fq2::Fq2;
|
|||
pub use self::fq6::Fq6;
|
||||
pub use self::fr::{Fr, FrRepr};
|
||||
|
||||
use super::{Engine, MillerLoopResult, PairingCurveAffine};
|
||||
use super::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||
|
||||
use ff::{BitIterator, Field, ScalarEngine};
|
||||
use group::CurveAffine;
|
||||
|
@ -43,21 +43,25 @@ impl Engine for Bls12 {
|
|||
type G1Affine = G1Affine;
|
||||
type G2 = G2;
|
||||
type G2Affine = G2Affine;
|
||||
type MillerLoopResult = Fq12;
|
||||
type Gt = Fq12;
|
||||
|
||||
fn miller_loop<'a, I>(i: I) -> Self::MillerLoopResult
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>,
|
||||
{
|
||||
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
|
||||
Self::multi_miller_loop(&[(p, &(q.prepare()))]).final_exponentiation()
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiMillerLoop for Bls12 {
|
||||
type Result = Fq12;
|
||||
|
||||
fn multi_miller_loop(
|
||||
terms: &[(
|
||||
&Self::G1Affine,
|
||||
&<Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
)],
|
||||
) -> Self::Result {
|
||||
let mut pairs = vec![];
|
||||
for &(p, q) in i {
|
||||
if !p.is_identity() && !q.is_identity() {
|
||||
for &(p, q) in terms {
|
||||
if !bool::from(p.is_identity()) && !q.is_identity() {
|
||||
pairs.push((p, q.coeffs.iter()));
|
||||
}
|
||||
}
|
||||
|
@ -87,12 +91,12 @@ impl Engine for Bls12 {
|
|||
}
|
||||
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
ell(&mut f, coeffs.next().unwrap(), p);
|
||||
}
|
||||
|
||||
if i {
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
ell(&mut f, coeffs.next().unwrap(), p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +104,7 @@ impl Engine for Bls12 {
|
|||
}
|
||||
|
||||
for &mut (p, ref mut coeffs) in &mut pairs {
|
||||
ell(&mut f, coeffs.next().unwrap(), &p.0);
|
||||
ell(&mut f, coeffs.next().unwrap(), p);
|
||||
}
|
||||
|
||||
if BLS_X_IS_NEGATIVE {
|
||||
|
|
|
@ -64,27 +64,12 @@ pub trait Engine: ScalarEngine {
|
|||
+ Mul<Self::Fr, Output = Self::G2>
|
||||
+ for<'a> Mul<&'a Self::Fr, Output = Self::G2>;
|
||||
|
||||
/// The type returned by `Engine::miller_loop`.
|
||||
type MillerLoopResult: MillerLoopResult<Gt = Self::Gt>;
|
||||
|
||||
/// The extension field that hosts the target group of the pairing.
|
||||
type Gt: Field;
|
||||
|
||||
/// Perform a miller loop with some number of (G1, G2) pairs.
|
||||
fn miller_loop<'a, I>(i: I) -> Self::MillerLoopResult
|
||||
where
|
||||
I: IntoIterator<
|
||||
Item = &'a (
|
||||
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
|
||||
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
|
||||
),
|
||||
>;
|
||||
|
||||
/// Invoke the pairing function `G1 x G2 -> Gt` without the use of precomputation and
|
||||
/// other optimizations.
|
||||
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
|
||||
Self::miller_loop([(&(p.prepare()), &(q.prepare()))].iter()).final_exponentiation()
|
||||
}
|
||||
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt;
|
||||
}
|
||||
|
||||
/// Affine representation of an elliptic curve point that can be used
|
||||
|
@ -101,6 +86,21 @@ pub trait PairingCurveAffine: CurveAffine {
|
|||
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 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;
|
||||
}
|
||||
|
||||
/// Represents results of a Miller loop, one of the most expensive portions of the pairing
|
||||
/// function.
|
||||
///
|
||||
|
|
|
@ -4,9 +4,9 @@ use rand_core::SeedableRng;
|
|||
use rand_xorshift::XorShiftRng;
|
||||
use std::ops::MulAssign;
|
||||
|
||||
use crate::{Engine, MillerLoopResult, PairingCurveAffine};
|
||||
use crate::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
|
||||
|
||||
pub fn engine_tests<E: Engine>() {
|
||||
pub fn engine_tests<E: MultiMillerLoop>() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
|
@ -21,32 +21,32 @@ pub fn engine_tests<E: Engine>() {
|
|||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
let z1 = E::G1Affine::identity().prepare();
|
||||
let z1 = E::G1Affine::identity();
|
||||
let z2 = E::G2Affine::identity().prepare();
|
||||
|
||||
let a = E::G1::random(&mut rng).to_affine().prepare();
|
||||
let a = E::G1::random(&mut rng).to_affine();
|
||||
let b = E::G2::random(&mut rng).to_affine().prepare();
|
||||
let c = E::G1::random(&mut rng).to_affine().prepare();
|
||||
let c = E::G1::random(&mut rng).to_affine();
|
||||
let d = E::G2::random(&mut rng).to_affine().prepare();
|
||||
|
||||
assert_eq!(
|
||||
E::Gt::one(),
|
||||
E::miller_loop(&[(&z1, &b)]).final_exponentiation()
|
||||
E::multi_miller_loop(&[(&z1, &b)]).final_exponentiation()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::Gt::one(),
|
||||
E::miller_loop(&[(&a, &z2)]).final_exponentiation()
|
||||
E::multi_miller_loop(&[(&a, &z2)]).final_exponentiation()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(),
|
||||
E::miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation()
|
||||
E::multi_miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(),
|
||||
E::multi_miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(),
|
||||
E::miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation()
|
||||
E::multi_miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(),
|
||||
E::multi_miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub fn engine_tests<E: Engine>() {
|
|||
random_miller_loop_tests::<E>();
|
||||
}
|
||||
|
||||
fn random_miller_loop_tests<E: Engine>() {
|
||||
fn random_miller_loop_tests<E: MultiMillerLoop>() {
|
||||
let mut rng = XorShiftRng::from_seed([
|
||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||
0xe5,
|
||||
|
@ -67,10 +67,10 @@ fn random_miller_loop_tests<E: Engine>() {
|
|||
|
||||
let p2 = E::pairing(&a, &b);
|
||||
|
||||
let a = a.prepare();
|
||||
let a = a;
|
||||
let b = b.prepare();
|
||||
|
||||
let p1 = E::miller_loop(&[(&a, &b)]).final_exponentiation();
|
||||
let p1 = E::multi_miller_loop(&[(&a, &b)]).final_exponentiation();
|
||||
|
||||
assert_eq!(p1, p2);
|
||||
}
|
||||
|
@ -88,12 +88,13 @@ fn random_miller_loop_tests<E: Engine>() {
|
|||
let mut abcd = ab;
|
||||
abcd.mul_assign(&cd);
|
||||
|
||||
let a = a.prepare();
|
||||
let a = a;
|
||||
let b = b.prepare();
|
||||
let c = c.prepare();
|
||||
let c = c;
|
||||
let d = d.prepare();
|
||||
|
||||
let abcd_with_double_loop = E::miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();
|
||||
let abcd_with_double_loop =
|
||||
E::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();
|
||||
|
||||
assert_eq!(abcd, abcd_with_double_loop);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue