bls12_381: Implement pairing traits

This commit is contained in:
Jack Grigg 2020-06-24 13:08:23 +12:00
parent eae5df0fb9
commit 4b4a4ee8dc
5 changed files with 259 additions and 5 deletions

View File

@ -35,6 +35,11 @@ version = "0.6"
default-features = false
optional = true
[dependencies.pairing]
path = "../pairing"
version = "0.16"
optional = true
[dependencies.rand_core]
version = "0.5"
default-features = false
@ -46,7 +51,7 @@ default-features = false
[features]
default = ["groups", "pairings", "alloc"]
groups = ["group"]
pairings = ["groups"]
pairings = ["groups", "pairing"]
alloc = []
nightly = ["subtle/nightly"]

View File

@ -4,6 +4,7 @@ use crate::fp6::*;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
/// This represents an element $c_0 + c_1 w$ of $\mathbb{F}_{p^12} = \mathbb{F}_{p^6} / w^2 - v$.
@ -99,6 +100,13 @@ impl Fp12 {
}
}
pub(crate) fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
Fp12 {
c0: Fp6::random(rng),
c1: Fp6::random(rng),
}
}
pub fn mul_by_014(&self, c0: &Fp2, c1: &Fp2, c4: &Fp2) -> Fp12 {
let aa = self.c0.mul_by_01(c0, c1);
let bb = self.c1.mul_by_1(c4);

View File

@ -3,6 +3,7 @@ use crate::fp2::*;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
/// This represents an element $c_0 + c_1 v + c_2 v^2$ of $\mathbb{F}_{p^6} = \mathbb{F}_{p^2} / v^3 - u - 1$.
@ -95,6 +96,14 @@ impl Fp6 {
}
}
pub(crate) fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
Fp6 {
c0: Fp2::random(rng),
c1: Fp2::random(rng),
c2: Fp2::random(rng),
}
}
pub fn mul_by_1(&self, c1: &Fp2) -> Fp6 {
let b_b = self.c1 * c1;

View File

@ -74,7 +74,7 @@ const BLS_X_IS_NEGATIVE: bool = true;
mod pairings;
#[cfg(feature = "pairings")]
pub use pairings::{pairing, Gt, MillerLoopResult};
pub use pairings::{pairing, Bls12, Gt, MillerLoopResult};
#[cfg(all(feature = "pairings", feature = "alloc"))]
pub use pairings::{multi_miller_loop, G2Prepared};

View File

@ -1,10 +1,16 @@
use crate::fp::Fp;
use crate::fp12::Fp12;
use crate::fp2::Fp2;
use crate::fp6::Fp6;
use crate::{G1Affine, G2Affine, G2Projective, Scalar, BLS_X, BLS_X_IS_NEGATIVE};
use crate::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar, BLS_X, BLS_X_IS_NEGATIVE};
use core::borrow::Borrow;
use core::fmt;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use group::Group;
use pairing::{Engine, MultiMillerLoop, PairingCurveAffine};
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[cfg(feature = "alloc")]
@ -174,9 +180,15 @@ impl_add_binop_specify_output!(MillerLoopResult, MillerLoopResult, MillerLoopRes
///
/// Typically, $\mathbb{G}_T$ is written multiplicatively but we will write it additively to
/// keep code and abstractions consistent.
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Default)]
pub struct Gt(pub(crate) Fp12);
impl fmt::Display for Gt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl ConstantTimeEq for Gt {
fn ct_eq(&self, other: &Self) -> Choice {
self.0.ct_eq(&other.0)
@ -276,6 +288,166 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a Gt {
impl_binops_additive!(Gt, Gt);
impl_binops_multiplicative!(Gt, Scalar);
impl<T> Sum<T> for Gt
where
T: Borrow<Gt>,
{
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = T>,
{
iter.fold(Self::identity(), |acc, item| acc + item.borrow())
}
}
impl Group for Gt {
type Scalar = Scalar;
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
loop {
let inner = Fp12::random(rng);
// Not all elements of Fp12 are elements of the prime-order multiplicative
// subgroup. We run the random element through final_exponentiation to obtain
// a valid element, which requires that it is non-zero.
if !bool::from(inner.is_zero()) {
return MillerLoopResult(inner).final_exponentiation();
}
}
}
fn identity() -> Self {
Self::identity()
}
fn generator() -> Self {
// pairing(&G1Affine::generator(), &G2Affine::generator())
Gt(Fp12 {
c0: Fp6 {
c0: Fp2 {
c0: Fp::from_raw_unchecked([
0x1972_e433_a01f_85c5,
0x97d3_2b76_fd77_2538,
0xc8ce_546f_c96b_cdf9,
0xcef6_3e73_66d4_0614,
0xa611_3427_8184_3780,
0x13f3_448a_3fc6_d825,
]),
c1: Fp::from_raw_unchecked([
0xd263_31b0_2e9d_6995,
0x9d68_a482_f779_7e7d,
0x9c9b_2924_8d39_ea92,
0xf480_1ca2_e131_07aa,
0xa16c_0732_bdbc_b066,
0x083c_a4af_ba36_0478,
]),
},
c1: Fp2 {
c0: Fp::from_raw_unchecked([
0x59e2_61db_0916_b641,
0x2716_b6f4_b23e_960d,
0xc8e5_5b10_a0bd_9c45,
0x0bdb_0bd9_9c4d_eda8,
0x8cf8_9ebf_57fd_aac5,
0x12d6_b792_9e77_7a5e,
]),
c1: Fp::from_raw_unchecked([
0x5fc8_5188_b0e1_5f35,
0x34a0_6e3a_8f09_6365,
0xdb31_26a6_e02a_d62c,
0xfc6f_5aa9_7d9a_990b,
0xa12f_55f5_eb89_c210,
0x1723_703a_926f_8889,
]),
},
c2: Fp2 {
c0: Fp::from_raw_unchecked([
0x9358_8f29_7182_8778,
0x43f6_5b86_11ab_7585,
0x3183_aaf5_ec27_9fdf,
0xfa73_d7e1_8ac9_9df6,
0x64e1_76a6_a64c_99b0,
0x179f_a78c_5838_8f1f,
]),
c1: Fp::from_raw_unchecked([
0x672a_0a11_ca2a_ef12,
0x0d11_b9b5_2aa3_f16b,
0xa444_12d0_699d_056e,
0xc01d_0177_221a_5ba5,
0x66e0_cede_6c73_5529,
0x05f5_a71e_9fdd_c339,
]),
},
},
c1: Fp6 {
c0: Fp2 {
c0: Fp::from_raw_unchecked([
0xd30a_88a1_b062_c679,
0x5ac5_6a5d_35fc_8304,
0xd0c8_34a6_a81f_290d,
0xcd54_30c2_da37_07c7,
0xf0c2_7ff7_8050_0af0,
0x0924_5da6_e2d7_2eae,
]),
c1: Fp::from_raw_unchecked([
0x9f2e_0676_791b_5156,
0xe2d1_c823_4918_fe13,
0x4c9e_459f_3c56_1bf4,
0xa3e8_5e53_b9d3_e3c1,
0x820a_121e_21a7_0020,
0x15af_6183_41c5_9acc,
]),
},
c1: Fp2 {
c0: Fp::from_raw_unchecked([
0x7c95_658c_2499_3ab1,
0x73eb_3872_1ca8_86b9,
0x5256_d749_4774_34bc,
0x8ba4_1902_ea50_4a8b,
0x04a3_d3f8_0c86_ce6d,
0x18a6_4a87_fb68_6eaa,
]),
c1: Fp::from_raw_unchecked([
0xbb83_e71b_b920_cf26,
0x2a52_77ac_92a7_3945,
0xfc0e_e59f_94f0_46a0,
0x7158_cdf3_7860_58f7,
0x7cc1_061b_82f9_45f6,
0x03f8_47aa_9fdb_e567,
]),
},
c2: Fp2 {
c0: Fp::from_raw_unchecked([
0x8078_dba5_6134_e657,
0x1cd7_ec9a_4399_8a6e,
0xb1aa_599a_1a99_3766,
0xc9a0_f62f_0842_ee44,
0x8e15_9be3_b605_dffa,
0x0c86_ba0d_4af1_3fc2,
]),
c1: Fp::from_raw_unchecked([
0xe80f_f2a0_6a52_ffb1,
0x7694_ca48_721a_906c,
0x7583_183e_03b0_8514,
0xf567_afdd_40ce_e4e2,
0x9a6d_96d2_e526_a5fc,
0x197e_9f49_861f_2242,
]),
},
},
})
}
fn is_identity(&self) -> Choice {
self.ct_eq(&Self::identity())
}
#[must_use]
fn double(&self) -> Self {
self.double()
}
}
#[cfg(feature = "alloc")]
#[derive(Clone, Debug)]
/// This structure contains cached computations pertaining to a $\mathbb{G}_2$
@ -558,6 +730,66 @@ fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) {
(t10, t1, t9)
}
impl PairingCurveAffine for G1Affine {
type Pair = G2Affine;
type PairingResult = Gt;
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
pairing(self, other)
}
}
impl PairingCurveAffine for G2Affine {
type Pair = G1Affine;
type PairingResult = Gt;
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
pairing(other, self)
}
}
/// A [`pairing::Engine`] for BLS12-381 pairing operations.
#[derive(Clone, Debug)]
pub struct Bls12;
impl Engine for Bls12 {
type Fr = Scalar;
type G1 = G1Projective;
type G1Affine = G1Affine;
type G2 = G2Projective;
type G2Affine = G2Affine;
type Gt = Gt;
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
pairing(p, q)
}
}
impl pairing::MillerLoopResult for MillerLoopResult {
type Gt = Gt;
fn final_exponentiation(&self) -> Self::Gt {
self.final_exponentiation()
}
}
impl MultiMillerLoop for Bls12 {
type G2Prepared = G2Prepared;
type Result = MillerLoopResult;
fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
multi_miller_loop(terms)
}
}
#[test]
fn test_gt_generator() {
assert_eq!(
Gt::generator(),
pairing(&G1Affine::generator(), &G2Affine::generator())
);
}
#[test]
fn test_bilinearity() {
use crate::Scalar;