From 4b4a4ee8dcbaa08562048851617ce6e176dfdac6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 24 Jun 2020 13:08:23 +1200 Subject: [PATCH] bls12_381: Implement pairing traits --- bls12_381/Cargo.toml | 7 +- bls12_381/src/fp12.rs | 8 ++ bls12_381/src/fp6.rs | 9 ++ bls12_381/src/lib.rs | 2 +- bls12_381/src/pairings.rs | 238 +++++++++++++++++++++++++++++++++++++- 5 files changed, 259 insertions(+), 5 deletions(-) diff --git a/bls12_381/Cargo.toml b/bls12_381/Cargo.toml index 21995b99a..1799294f2 100644 --- a/bls12_381/Cargo.toml +++ b/bls12_381/Cargo.toml @@ -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"] diff --git a/bls12_381/src/fp12.rs b/bls12_381/src/fp12.rs index 735f91e5d..f6177cc80 100644 --- a/bls12_381/src/fp12.rs +++ b/bls12_381/src/fp12.rs @@ -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(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); diff --git a/bls12_381/src/fp6.rs b/bls12_381/src/fp6.rs index 3f310dc17..9df150f65 100644 --- a/bls12_381/src/fp6.rs +++ b/bls12_381/src/fp6.rs @@ -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(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; diff --git a/bls12_381/src/lib.rs b/bls12_381/src/lib.rs index d5b4d512f..5e8a7db29 100644 --- a/bls12_381/src/lib.rs +++ b/bls12_381/src/lib.rs @@ -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}; diff --git a/bls12_381/src/pairings.rs b/bls12_381/src/pairings.rs index ef7180a5e..440d3038f 100644 --- a/bls12_381/src/pairings.rs +++ b/bls12_381/src/pairings.rs @@ -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 Sum for Gt +where + T: Borrow, +{ + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + } +} + +impl Group for Gt { + type Scalar = Scalar; + + fn random(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;