diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 487455844..3af8dc5e9 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -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) } } diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 0c3de349e..99ba70a06 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -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>(iter: I) -> Self { + iter.fold(Self::identity(), Add::add) + } +} + +impl<'r> Sum<&'r Gt> for Gt { + fn sum>(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 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 for Gt { + fn mul_assign(&mut self, other: Fr) { + self.mul_assign(&other); + } +} + +impl Group for Gt { + type Scalar = Fr; + + fn random(_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() diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs index b698c0a0f..137694c43 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/pairing/src/bls12_381/tests/mod.rs @@ -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(expected: &[u8]) diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index e25d364e5..bb57d21a7 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -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 + ScalarMul + ScalarMulOwned; /// 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; - 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 diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 6e971622f..2b56ae3dd 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -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() { 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() { 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() { let acbd = E::pairing(&ac, &bd); let adbc = E::pairing(&ad, &bc); - let mut cd = (c * &d).to_repr(); - ::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::::mul(ab, cd); assert_eq!(acbd, adbc); assert_eq!(acbd, abcd);