Merge branch 'pairing-refactor'

This commit is contained in:
Jack Grigg 2020-06-17 09:48:24 +12:00
commit 4e685a847d
10 changed files with 213 additions and 267 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::Fqk,
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

@ -1,6 +1,6 @@
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, Group, PrimeGroup};
use pairing::{Engine, PairingCurveAffine};
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
use rand_core::RngCore;
use std::fmt;
@ -330,24 +330,24 @@ impl Engine for DummyEngine {
type G1Affine = Fr;
type G2 = Fr;
type G2Affine = Fr;
type Fq = Fr;
type Fqe = Fr;
// TODO: This should be F_645131 or something. Doesn't matter for now.
type Fqk = Fr;
type Gt = Fr;
fn miller_loop<'a, I>(i: I) -> Self::Fqk
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).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::G2Prepared)]) -> 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);
@ -355,10 +355,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::Fqk) -> CtOption<Self::Fqk> {
CtOption::new(*this, Choice::from(1))
fn final_exponentiation(&self) -> Self::Gt {
*self
}
}
@ -391,7 +395,6 @@ impl PrimeGroup for Fr {}
impl CurveProjective for Fr {
type Affine = Fr;
type Base = Fr;
fn batch_normalize(p: &[Self], q: &mut [Self::Affine]) {
assert_eq!(p.len(), q.len());
@ -433,7 +436,6 @@ impl CurveAffine for Fr {
type Compressed = FakePoint;
type Uncompressed = FakePoint;
type Projective = Fr;
type Base = Fr;
type Scalar = Fr;
fn identity() -> Self {
@ -478,14 +480,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,24 +1,24 @@
use group::{CurveAffine, CurveProjective};
use pairing::{Engine, 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(),
alpha_g1_beta_g2: E::pairing(&vk.alpha_g1, &vk.beta_g2),
neg_gamma_g2: gamma.into(),
neg_delta_g2: delta.into(),
ic: vk.ic.clone(),
}
}
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::final_exponentiation(&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()
Ok(E::multi_miller_loop(&[
(&proof.a, &proof.b.into()),
(&acc.to_affine(), &pvk.neg_gamma_g2),
(&proof.c, &pvk.neg_delta_g2),
])
.final_exponentiation()
== pvk.alpha_g1_beta_g2)
}

View File

@ -1,7 +1,7 @@
// Catch documentation errors caused by code changes.
#![deny(intra_doc_link_resolution_failure)]
use ff::{Field, PrimeField};
use ff::PrimeField;
use rand::RngCore;
use std::fmt;
use std::iter::Sum;
@ -93,7 +93,6 @@ pub trait CurveProjective:
+ GroupOps<<Self as CurveProjective>::Affine>
+ GroupOpsOwned<<Self as CurveProjective>::Affine>
{
type Base: Field;
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>
+ Mul<Self::Scalar, Output = Self>
+ for<'r> Mul<Self::Scalar, Output = Self>;
@ -132,7 +131,6 @@ pub trait CurveAffine:
+ for<'r> Mul<<Self as CurveAffine>::Scalar, Output = <Self as CurveAffine>::Projective>
{
type Scalar: PrimeField;
type Base: Field;
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
type Uncompressed: Default + AsRef<[u8]> + AsMut<[u8]>;
type Compressed: Default + AsRef<[u8]> + AsMut<[u8]>;

View File

@ -10,27 +10,7 @@ use rand_xorshift::XorShiftRng;
use group::Group;
use pairing::bls12_381::*;
use pairing::{Engine, 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
})
});
}
use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
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
})
@ -60,11 +40,11 @@ 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(),
G2Affine::from(G2::random(&mut rng)).prepare(),
G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).into(),
)
})
.collect();
@ -72,7 +52,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,17 +70,17 @@ fn bench_pairing_final_exponentiation(c: &mut Criterion) {
let v: Vec<Fq12> = (0..SAMPLES)
.map(|_| {
(
G1Affine::from(G1::random(&mut rng)).prepare(),
G2Affine::from(G2::random(&mut rng)).prepare(),
G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).into(),
)
})
.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;
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
})
@ -115,14 +95,14 @@ fn bench_pairing_full(c: &mut Criterion) {
0xe5,
]);
let v: Vec<(G1, G2)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng), G2::random(&mut rng)))
let v: Vec<(G1Affine, G2Affine)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng).into(), G2::random(&mut rng).into()))
.collect();
let mut count = 0;
c.bench_function("Full pairing", |b| {
b.iter(|| {
let tmp = Bls12::pairing(v[count].0, v[count].1);
let tmp = Bls12::pairing(&v[count].0, &v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
@ -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,
@ -200,7 +199,6 @@ macro_rules! curve_impl {
impl CurveAffine for $affine {
type Scalar = $scalarfield;
type Base = $basefield;
type Projective = $projective;
type Uncompressed = $uncompressed;
type Compressed = $compressed;
@ -282,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)
}
@ -748,7 +741,6 @@ macro_rules! curve_impl {
impl PrimeGroup for $projective {}
impl CurveProjective for $projective {
type Base = $basefield;
type Affine = $affine;
fn batch_normalize(p: &[Self], q: &mut [$affine]) {
@ -919,7 +911,6 @@ pub mod g1 {
"G1",
G1,
G1Affine,
G1Prepared,
Fq,
Fr,
G1Uncompressed,
@ -1143,7 +1134,7 @@ pub mod g1 {
}
fn perform_pairing(&self, other: &G2Affine) -> Fq12 {
super::super::Bls12::pairing(*self, *other)
super::super::Bls12::pairing(self, other)
}
}
@ -1175,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();
@ -1509,7 +1487,6 @@ pub mod g2 {
"G2",
G2,
G2Affine,
G2Prepared,
Fq2,
Fr,
G2Uncompressed,
@ -1782,7 +1759,7 @@ pub mod g2 {
}
fn perform_pairing(&self, other: &G1Affine) -> Fq12 {
super::super::Bls12::pairing(*other, *self)
super::super::Bls12::pairing(other, self)
}
}
@ -1820,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,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, MultiMillerLoop};
use ff::{BitIterator, Field};
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;
@ -41,22 +40,21 @@ impl Engine for Bls12 {
type G1Affine = G1Affine;
type G2 = G2;
type G2Affine = G2Affine;
type Fq = Fq;
type Fqe = Fq2;
type Fqk = Fq12;
type Gt = Fq12;
fn miller_loop<'a, I>(i: I) -> Self::Fqk
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).into())]).final_exponentiation()
}
}
impl MultiMillerLoop for Bls12 {
type G2Prepared = G2Prepared;
type Result = Fq12;
fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> 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()));
}
}
@ -86,12 +84,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);
}
}
@ -99,7 +97,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 {
@ -108,59 +106,66 @@ impl Engine for Bls12 {
f
}
}
fn final_exponentiation(r: &Fq12) -> CtOption<Fq12> {
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()
}
}

View File

@ -1,5 +1,5 @@
use ff::PrimeField;
use group::{CurveAffine, CurveProjective, Group};
use group::{CurveAffine, CurveProjective};
use super::*;
use crate::*;
@ -23,7 +23,7 @@ fn test_pairing_result_against_relic() {
0F41E58663BF08CF 068672CBD01A7EC7 3BACA4D72CA93544 DEFF686BFD6DF543 D48EAA24AFE47E1E FDE449383B676631
*/
assert_eq!(Bls12::pairing(G1::generator(), G2::generator()), Fq12 {
assert_eq!(Bls12::pairing(&G1Affine::generator(), &G2Affine::generator()), Fq12 {
c0: Fq6 {
c0: Fq2 {
c0: Fq::from_str("2819105605953691245277803056322684086884703000473961065716485506033588504203831029066448642358042597501014294104502").unwrap(),

View File

@ -23,7 +23,6 @@ pub mod bls12_381;
use core::ops::Mul;
use ff::{Field, PrimeField};
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
@ -33,7 +32,7 @@ pub trait Engine: Sized + 'static + Clone {
type Fr: PrimeField;
/// The projective representation of an element in G1.
type G1: CurveProjective<Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
type G1: CurveProjective<Scalar = Self::Fr, Affine = Self::G1Affine>
+ From<Self::G1Affine>
+ GroupOps<Self::G1Affine>
+ GroupOpsOwned<Self::G1Affine>
@ -42,17 +41,16 @@ pub trait Engine: Sized + 'static + Clone {
/// The affine representation of an element in G1.
type G1Affine: PairingCurveAffine<
Base = Self::Fq,
Scalar = Self::Fr,
Projective = Self::G1,
Pair = Self::G2Affine,
PairingResult = Self::Fqk,
PairingResult = Self::Gt,
> + From<Self::G1>
+ Mul<Self::Fr, Output = Self::G1>
+ for<'a> Mul<&'a Self::Fr, Output = Self::G1>;
/// The projective representation of an element in G2.
type G2: CurveProjective<Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine>
type G2: CurveProjective<Scalar = Self::Fr, Affine = Self::G2Affine>
+ From<Self::G2Affine>
+ GroupOps<Self::G2Affine>
+ GroupOpsOwned<Self::G2Affine>
@ -61,60 +59,56 @@ pub trait Engine: Sized + 'static + Clone {
/// The affine representation of an element in G2.
type G2Affine: PairingCurveAffine<
Base = Self::Fqe,
Scalar = Self::Fr,
Projective = Self::G2,
Pair = Self::G1Affine,
PairingResult = Self::Fqk,
PairingResult = Self::Gt,
> + From<Self::G2>
+ Mul<Self::Fr, Output = Self::G2>
+ for<'a> Mul<&'a Self::Fr, Output = Self::G2>;
/// The base field that hosts G1.
type Fq: PrimeField;
/// The extension field that hosts G2.
type Fqe: Field;
/// The extension field that hosts the target group of the pairing.
type Fqk: Field;
type Gt: Field;
/// Perform a miller loop with some number of (G1, G2) pairs.
fn miller_loop<'a, I>(i: I) -> Self::Fqk
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
),
>;
/// Perform final exponentiation of the result of a miller loop.
fn final_exponentiation(_: &Self::Fqk) -> CtOption<Self::Fqk>;
/// Performs a complete pairing operation `(p, q)`.
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk
where
G1: Into<Self::G1Affine>,
G2: Into<Self::G2Affine>,
{
Self::final_exponentiation(&Self::miller_loop(
[(&(p.into().prepare()), &(q.into().prepare()))].iter(),
))
.unwrap()
}
/// 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;
}
/// 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::G2Prepared)]) -> Self::Result;
}
/// 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;
}

View File

@ -4,9 +4,9 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::MulAssign;
use crate::{Engine, 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,
@ -17,36 +17,36 @@ pub fn engine_tests<E: Engine>() {
let b = E::G2::random(&mut rng).to_affine();
assert!(a.pairing_with(&b) == b.pairing_with(&a));
assert!(a.pairing_with(&b) == E::pairing(a, b));
assert!(a.pairing_with(&b) == E::pairing(&a, &b));
}
for _ in 0..1000 {
let z1 = E::G1Affine::identity().prepare();
let z2 = E::G2Affine::identity().prepare();
let z1 = E::G1Affine::identity();
let z2 = E::G2Affine::identity().into();
let a = E::G1::random(&mut rng).to_affine().prepare();
let b = E::G2::random(&mut rng).to_affine().prepare();
let c = E::G1::random(&mut rng).to_affine().prepare();
let d = E::G2::random(&mut rng).to_affine().prepare();
let a = E::G1::random(&mut rng).to_affine();
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().into();
assert_eq!(
E::Fqk::one(),
E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap()
E::Gt::one(),
E::multi_miller_loop(&[(&z1, &b)]).final_exponentiation()
);
assert_eq!(
E::Fqk::one(),
E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap()
E::Gt::one(),
E::multi_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::multi_miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(),
E::multi_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::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,
@ -62,39 +62,39 @@ fn random_miller_loop_tests<E: Engine>() {
// Exercise the miller loop for a reduced pairing
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let a = E::G1::random(&mut rng).to_affine();
let b = E::G2::random(&mut rng).to_affine();
let p2 = E::pairing(a, b);
let p2 = E::pairing(&a, &b);
let a = a.to_affine().prepare();
let b = b.to_affine().prepare();
let a = a;
let b = b.into();
let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap();
let p1 = E::multi_miller_loop(&[(&a, &b)]).final_exponentiation();
assert_eq!(p1, p2);
}
// Exercise a double miller loop
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let c = E::G1::random(&mut rng);
let d = E::G2::random(&mut rng);
let a = E::G1::random(&mut rng).to_affine();
let b = E::G2::random(&mut rng).to_affine();
let c = E::G1::random(&mut rng).to_affine();
let d = E::G2::random(&mut rng).to_affine();
let ab = E::pairing(a, b);
let cd = E::pairing(c, d);
let ab = E::pairing(&a, &b);
let cd = E::pairing(&c, &d);
let mut abcd = ab;
abcd.mul_assign(&cd);
let a = a.to_affine().prepare();
let b = b.to_affine().prepare();
let c = c.to_affine().prepare();
let d = d.to_affine().prepare();
let a = a;
let b = b.into();
let c = c;
let d = d.into();
let abcd_with_double_loop =
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &d)])).unwrap();
E::multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();
assert_eq!(abcd, abcd_with_double_loop);
}
@ -107,26 +107,19 @@ fn random_bilinearity_tests<E: Engine>() {
]);
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let a = E::G1::random(&mut rng).to_affine();
let b = E::G2::random(&mut rng).to_affine();
let c = E::Fr::random(&mut rng);
let d = E::Fr::random(&mut rng);
let mut ac = a;
MulAssign::<&E::Fr>::mul_assign(&mut ac, &c);
let ac = (a * &c).to_affine();
let ad = (a * &d).to_affine();
let bc = (b * &c).to_affine();
let bd = (b * &d).to_affine();
let mut ad = a;
MulAssign::<&E::Fr>::mul_assign(&mut ad, &d);
let mut bc = b;
MulAssign::<&E::Fr>::mul_assign(&mut bc, &c);
let mut bd = b;
MulAssign::<&E::Fr>::mul_assign(&mut bd, &d);
let acbd = E::pairing(ac, bd);
let adbc = E::pairing(ad, bc);
let acbd = E::pairing(&ac, &bd);
let adbc = E::pairing(&ad, &bc);
let mut cd = (c * &d).to_repr();
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut cd);
@ -135,7 +128,7 @@ fn random_bilinearity_tests<E: Engine>() {
let mut cd_limbs = [0; 4];
byteorder::LittleEndian::read_u64_into(cd.as_ref(), &mut cd_limbs);
let abcd = E::pairing(a, b).pow_vartime(cd_limbs);
let abcd = E::pairing(&a, &b).pow_vartime(cd_limbs);
assert_eq!(acbd, adbc);
assert_eq!(acbd, abcd);