Merge pull request #244 from str4d/pairing-gt-fix

pairing: Bound Engine::Gt on Group instead of Field
This commit is contained in:
str4d 2020-06-25 09:53:15 +12:00 committed by GitHub
commit 7134ab8215
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 198 additions and 34 deletions

View File

@ -367,7 +367,7 @@ macro_rules! curve_impl {
impl PairingCurveAffine for $affine {
type Pair = $pairing;
type PairingResult = Fq12;
type PairingResult = Gt;
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.perform_pairing(other)
@ -1205,7 +1205,7 @@ impl fmt::Display for GroupDecodingError {
}
pub mod g1 {
use super::super::{Fq, Fq12, FqRepr, Fr};
use super::super::{Fq, FqRepr, Fr, Gt};
use super::{g2::G2Affine, GroupDecodingError};
use crate::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, PrimeField};
@ -1446,7 +1446,7 @@ pub mod g1 {
super::super::fq::B_COEFF
}
fn perform_pairing(&self, other: &G2Affine) -> Fq12 {
fn perform_pairing(&self, other: &G2Affine) -> Gt {
super::super::Bls12::pairing(self, other)
}
}
@ -1788,7 +1788,7 @@ pub mod g1 {
}
pub mod g2 {
use super::super::{Fq, Fq12, Fq2, FqRepr, Fr};
use super::super::{Fq, Fq2, FqRepr, Fr, Gt};
use super::{g1::G1Affine, GroupDecodingError};
use crate::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, PrimeField};
@ -2078,7 +2078,7 @@ pub mod g2 {
self.mul_bits_u64(cofactor)
}
fn perform_pairing(&self, other: &G1Affine) -> Fq12 {
fn perform_pairing(&self, other: &G1Affine) -> Gt {
super::super::Bls12::pairing(other, self)
}
}

View File

@ -23,14 +23,184 @@ pub use self::fr::{Fr, FrRepr};
use super::{Engine, MillerLoopResult, MultiMillerLoop};
use ff::{BitIterator, Field};
use group::cofactor::CofactorCurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{BitIterator, Field, PrimeField};
use group::{cofactor::CofactorCurveAffine, Group};
use rand_core::RngCore;
use std::fmt;
use std::iter::Sum;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable};
// The BLS parameter x for BLS12-381 is -0xd201000000010000
const BLS_X: u64 = 0xd201000000010000;
const BLS_X_IS_NEGATIVE: bool = true;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Gt(Fq12);
impl fmt::Display for Gt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl ConditionallySelectable for Gt {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Gt(Fq12::conditional_select(&a.0, &b.0, choice))
}
}
impl Neg for Gt {
type Output = Gt;
fn neg(self) -> Self::Output {
let mut ret = self.0;
ret.conjugate();
Gt(ret)
}
}
impl Sum for Gt {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::identity(), Add::add)
}
}
impl<'r> Sum<&'r Gt> for Gt {
fn sum<I: Iterator<Item = &'r Self>>(iter: I) -> Self {
iter.fold(Self::identity(), Add::add)
}
}
impl Add for Gt {
type Output = Gt;
fn add(self, rhs: Self) -> Self::Output {
Gt(self.0 * rhs.0)
}
}
impl Add<&Gt> for Gt {
type Output = Gt;
fn add(self, rhs: &Gt) -> Self::Output {
Gt(self.0 * rhs.0)
}
}
impl AddAssign for Gt {
fn add_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
impl AddAssign<&Gt> for Gt {
fn add_assign(&mut self, rhs: &Gt) {
self.0 *= rhs.0;
}
}
impl Sub for Gt {
type Output = Gt;
fn sub(self, rhs: Self) -> Self::Output {
self + (-rhs)
}
}
impl Sub<&Gt> for Gt {
type Output = Gt;
fn sub(self, rhs: &Gt) -> Self::Output {
self + (-*rhs)
}
}
impl SubAssign for Gt {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl SubAssign<&Gt> for Gt {
fn sub_assign(&mut self, rhs: &Gt) {
*self = *self - rhs;
}
}
impl Mul<&Fr> for Gt {
type Output = Gt;
fn mul(self, other: &Fr) -> Self::Output {
let mut acc = Self::identity();
// This is a simple double-and-add implementation of group element
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We skip the leading bit because it's always unset for Fr
// elements.
for bit in other
.to_repr()
.as_ref()
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = Gt::conditional_select(&acc, &(acc + self), bit);
}
acc
}
}
impl Mul<Fr> for Gt {
type Output = Gt;
fn mul(self, other: Fr) -> Self::Output {
self * &other
}
}
impl<'r> MulAssign<&'r Fr> for Gt {
fn mul_assign(&mut self, other: &'r Fr) {
*self = *self * other
}
}
impl MulAssign<Fr> for Gt {
fn mul_assign(&mut self, other: Fr) {
self.mul_assign(&other);
}
}
impl Group for Gt {
type Scalar = Fr;
fn random<R: RngCore + ?Sized>(_rng: &mut R) -> Self {
unimplemented!()
}
fn identity() -> Self {
Gt(Fq12::one())
}
fn generator() -> Self {
unimplemented!()
}
fn is_identity(&self) -> Choice {
Choice::from(if self.0 == Fq12::one() { 1 } else { 0 })
}
#[must_use]
fn double(&self) -> Self {
Gt(self.0.square())
}
}
#[derive(Clone, Debug)]
pub struct Bls12;
@ -40,7 +210,7 @@ impl Engine for Bls12 {
type G1Affine = G1Affine;
type G2 = G2;
type G2Affine = G2Affine;
type Gt = Fq12;
type Gt = Gt;
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
Self::multi_miller_loop(&[(p, &(*q).into())]).final_exponentiation()
@ -109,9 +279,9 @@ impl MultiMillerLoop for Bls12 {
}
impl MillerLoopResult for Fq12 {
type Gt = Fq12;
type Gt = Gt;
fn final_exponentiation(&self) -> Fq12 {
fn final_exponentiation(&self) -> Gt {
let mut f1 = *self;
f1.conjugate();
@ -162,7 +332,7 @@ impl MillerLoopResult for Fq12 {
y2.frobenius_map(1);
y1.mul_assign(&y2);
y1
Gt(y1)
})
// self must be nonzero.
.unwrap()

View File

@ -26,7 +26,7 @@ fn test_pairing_result_against_relic() {
0F41E58663BF08CF 068672CBD01A7EC7 3BACA4D72CA93544 DEFF686BFD6DF543 D48EAA24AFE47E1E FDE449383B676631
*/
assert_eq!(Bls12::pairing(&G1Affine::generator(), &G2Affine::generator()), Fq12 {
assert_eq!(Bls12::pairing(&G1Affine::generator(), &G2Affine::generator()), Gt(Fq12 {
c0: Fq6 {
c0: Fq2 {
c0: Fq::from_str("2819105605953691245277803056322684086884703000473961065716485506033588504203831029066448642358042597501014294104502").unwrap(),
@ -55,7 +55,7 @@ fn test_pairing_result_against_relic() {
c1: Fq::from_str("2348330098288556420918672502923664952620152483128593484301759394583320358354186482723629999370241674973832318248497").unwrap()
}
}
});
}));
}
fn uncompressed_test_vectors<G: CofactorCurve>(expected: &[u8])

View File

@ -21,10 +21,10 @@ pub mod tests;
pub mod bls12_381;
use core::ops::Mul;
use ff::{Field, PrimeField};
use ff::PrimeField;
use group::{
cofactor::{CofactorCurve, CofactorCurveAffine},
GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned, UncompressedEncoding,
Group, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned, UncompressedEncoding,
};
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
@ -71,7 +71,7 @@ pub trait Engine: Sized + 'static + Clone {
+ for<'a> Mul<&'a Self::Fr, Output = Self::G2>;
/// The extension field that hosts the target group of the pairing.
type Gt: Field;
type Gt: Group<Scalar = Self::Fr> + ScalarMul<Self::Fr> + ScalarMulOwned<Self::Fr>;
/// Invoke the pairing function `G1 x G2 -> Gt` without the use of precomputation and
/// other optimizations.
@ -82,7 +82,7 @@ pub trait Engine: Sized + 'static + Clone {
/// to perform pairings.
pub trait PairingCurveAffine: CofactorCurveAffine + UncompressedEncoding {
type Pair: PairingCurveAffine<Pair = Self>;
type PairingResult: Field;
type PairingResult: Group;
/// Perform a pairing
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
@ -108,7 +108,7 @@ pub trait MultiMillerLoop: Engine {
/// [`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;
type Gt: Group;
/// 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

View File

@ -1,8 +1,8 @@
use ff::{Endianness, Field, PrimeField};
use ff::Field;
use group::{cofactor::CofactorCurveAffine, Curve, Group};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::MulAssign;
use std::ops::Mul;
use crate::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
@ -30,12 +30,12 @@ pub fn engine_tests<E: MultiMillerLoop>() {
let d = E::G2::random(&mut rng).to_affine().into();
assert_eq!(
E::Gt::one(),
E::Gt::identity(),
E::multi_miller_loop(&[(&z1, &b)]).final_exponentiation()
);
assert_eq!(
E::Gt::one(),
E::Gt::identity(),
E::multi_miller_loop(&[(&a, &z2)]).final_exponentiation()
);
@ -85,8 +85,7 @@ fn random_miller_loop_tests<E: MultiMillerLoop>() {
let ab = E::pairing(&a, &b);
let cd = E::pairing(&c, &d);
let mut abcd = ab;
abcd.mul_assign(&cd);
let abcd = ab + &cd;
let a = a;
let b = b.into();
@ -121,14 +120,9 @@ fn random_bilinearity_tests<E: Engine>() {
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);
use byteorder::ByteOrder;
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 ab = E::pairing(&a, &b);
let cd = c * &d;
let abcd = Mul::<E::Fr>::mul(ab, cd);
assert_eq!(acbd, adbc);
assert_eq!(acbd, abcd);

View File

@ -17,7 +17,7 @@ bs58 = { version = "0.3", features = ["check"] }
ff = { version = "0.6", path = "../ff" }
hex = "0.3"
pairing = { version = "0.16", path = "../pairing" }
protobuf = "2"
protobuf = "=2.14.0" # 2.15 has MSRV of 1.44.1
subtle = "2"
zcash_primitives = { version = "0.2", path = "../zcash_primitives" }