Merge branch 'pairing-refactor'
This commit is contained in:
commit
4e685a847d
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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]>;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue