Skip to content

Commit

Permalink
Bn254 pairing (#889)
Browse files Browse the repository at this point in the history
* save work

* save work

* add check if a g2point is subgroup of twisted curve

* save work

* double and add functions

* test double and add naive

* tests add and double don't work

* save work

* added g2 points for the tests

* miller naive implementation

* save work. added test to check frobenius

* save work

* finished all needed functions. Time to debug

* save work

* save work

* added double acumulate line and add line

* new implementation pairing_v2

* pairing batch now works

* add tests

* save work

* Pairing always returned one. Final exponentiation implemented

* pairing working

* Files organized. All tests passed.

* cargo fmt clippy

* fix clippy

* fix clippy

* fix clippy

* remove println!

* use one()

* ensure points are in affine form

* use double function

* speed is_in_subgroup

* simplify is_in_subgroup

* format

* remove unnecessary affine

* remove clones

* add field_extension tests

* check non degeneracy

---------

Co-authored-by: jotabulacios <[email protected]>
Co-authored-by: Nicole <[email protected]>
Co-authored-by: Nicole <[email protected]>
Co-authored-by: Diego K <[email protected]>
Co-authored-by: diegokingston <[email protected]>
  • Loading branch information
6 people authored Aug 15, 2024
1 parent 3925b01 commit 01fff47
Show file tree
Hide file tree
Showing 4 changed files with 961 additions and 15 deletions.
135 changes: 120 additions & 15 deletions math/src/elliptic_curve/short_weierstrass/curves/bn_254/curve.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use super::field_extension::{BN254PrimeField, Degree2ExtensionField};
use super::{
field_extension::{BN254PrimeField, Degree2ExtensionField},
pairing::{GAMMA_12, GAMMA_13, X},
twist::BN254TwistCurve,
};
use crate::cyclic_group::IsGroup;
use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint;
use crate::elliptic_curve::traits::IsEllipticCurve;
use crate::{
Expand Down Expand Up @@ -34,18 +39,45 @@ impl IsShortWeierstrass for BN254Curve {
}
}

impl ShortWeierstrassProjectivePoint<BN254TwistCurve> {
/// phi morphism used to G2 subgroup check for twisted curve.
/// We also use phi at the last lines of the Miller Loop of the pairing.
/// phi(q) = (x^p, y^p, z^p), where (x, y, z) are the projective coordinates of q.
/// See https://hackmd.io/@Wimet/ry7z1Xj-2#Subgroup-Checks.
pub fn phi(&self) -> Self {
let [x, y, z] = self.coordinates();
Self::new([
x.conjugate() * GAMMA_12,
y.conjugate() * GAMMA_13,
z.conjugate(),
])
}

// Checks if a G2 point is in the subgroup of the twisted curve.
pub fn is_in_subgroup(&self) -> bool {
let q_times_x = &self.operate_with_self(X);
let q_times_x_plus_1 = &self.operate_with(q_times_x);
let q_times_2x = q_times_x.double();

// (x+1)Q + phi(xQ) + phi(phi(xQ)) == phi(phi(phi(2xQ)))
q_times_x_plus_1.operate_with(&q_times_x.phi().operate_with(&q_times_x.phi().phi()))
== q_times_2x.phi().phi().phi()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
cyclic_group::IsGroup, elliptic_curve::traits::EllipticCurveError,
field::element::FieldElement,
field::element::FieldElement, unsigned_integer::element::U256,
};

use super::BN254Curve;

#[allow(clippy::upper_case_acronyms)]
type FE = FieldElement<BN254PrimeField>;
type FpE = FieldElement<BN254PrimeField>;
type Fp2E = FieldElement<Degree2ExtensionField>;

/*
Sage script:
Expand All @@ -59,10 +91,10 @@ mod tests {
1)
*/
fn point() -> ShortWeierstrassProjectivePoint<BN254Curve> {
let x = FE::from_hex_unchecked(
let x = FpE::from_hex_unchecked(
"27749cb56beffb211b6622d7366253aa8208cf0aff7867d7945f53f3997cfedb",
);
let y = FE::from_hex_unchecked(
let y = FpE::from_hex_unchecked(
"2598371545fd02273e206c4a3e5e6d062c46baade65567b817c343170a15ff0d",
);
BN254Curve::create_point_from_affine(x, y).unwrap()
Expand Down Expand Up @@ -91,10 +123,10 @@ mod tests {
*/

fn point_times_5() -> ShortWeierstrassProjectivePoint<BN254Curve> {
let x = FE::from_hex_unchecked(
let x = FpE::from_hex_unchecked(
"16ab03b69dfb4f870b0143ebf6a71b7b2e4053ca7a4421d09a913b8b834bbfa3",
);
let y = FE::from_hex_unchecked(
let y = FpE::from_hex_unchecked(
"2512347279ba1049ef97d4ec348d838f939d2b7623e88f4826643cf3889599b2",
);
BN254Curve::create_point_from_affine(x, y).unwrap()
Expand All @@ -112,25 +144,25 @@ mod tests {
let p = point();
assert_eq!(
*p.x(),
FE::new_base("27749cb56beffb211b6622d7366253aa8208cf0aff7867d7945f53f3997cfedb")
FpE::new_base("27749cb56beffb211b6622d7366253aa8208cf0aff7867d7945f53f3997cfedb")
);
assert_eq!(
*p.y(),
FE::new_base("2598371545fd02273e206c4a3e5e6d062c46baade65567b817c343170a15ff0d")
FpE::new_base("2598371545fd02273e206c4a3e5e6d062c46baade65567b817c343170a15ff0d")
);
assert_eq!(*p.z(), FE::one());
assert_eq!(*p.z(), FpE::one());
}

#[test]
fn addition_with_neutral_element_returns_same_element() {
let p = point();
assert_eq!(
*p.x(),
FE::new_base("27749cb56beffb211b6622d7366253aa8208cf0aff7867d7945f53f3997cfedb")
FpE::new_base("27749cb56beffb211b6622d7366253aa8208cf0aff7867d7945f53f3997cfedb")
);
assert_eq!(
*p.y(),
FE::new_base("2598371545fd02273e206c4a3e5e6d062c46baade65567b817c343170a15ff0d")
FpE::new_base("2598371545fd02273e206c4a3e5e6d062c46baade65567b817c343170a15ff0d")
);

let neutral_element = ShortWeierstrassProjectivePoint::<BN254Curve>::neutral_element();
Expand All @@ -151,7 +183,7 @@ mod tests {
#[test]
fn create_invalid_points_returns_an_error() {
assert_eq!(
BN254Curve::create_point_from_affine(FE::from(0), FE::from(1)),
BN254Curve::create_point_from_affine(FpE::from(0), FpE::from(1)),
Err(EllipticCurveError::InvalidPoint)
);
}
Expand All @@ -174,8 +206,8 @@ mod tests {
let x = g2_affine.x();
let y = g2_affine.y();

// calculate both sides of BLS12-381 equation
let three = FieldElement::from(3);
// calculate both sides of BN254 equation
let three = FpE::from(3);
let y_sq_0 = x.pow(3_u16) + three;
let y_sq_1 = y.pow(2_u16);

Expand All @@ -190,4 +222,77 @@ mod tests {
g.operate_with_self(3_u16)
);
}

#[test]
fn operate_with_self_works_2() {
let g = BN254TwistCurve::generator();
assert_eq!(
(g.operate_with_self(X)).double(),
(g.operate_with_self(2 * X))
)
}

#[test]
fn operate_with_self_works_3() {
let g = BN254TwistCurve::generator();
assert_eq!(
(g.operate_with_self(X)).operate_with(&g),
(g.operate_with_self(X + 1))
)
}

#[test]
fn generator_g2_is_in_subgroup() {
let g = BN254TwistCurve::generator();
assert!(g.is_in_subgroup())
}

#[test]
fn other_g2_point_is_in_subgroup() {
let g = BN254TwistCurve::generator().operate_with_self(32u64);
assert!(g.is_in_subgroup())
}

#[test]
fn invalid_g2_is_not_in_subgroup() {
let q = ShortWeierstrassProjectivePoint::<BN254TwistCurve>::new([
Fp2E::new([
FpE::new(U256::from_hex_unchecked(
"1800deef121f1e76426a00665e5c4479674322d4f75edaddde46bd5cd992f6ed",
)),
FpE::new(U256::from_hex_unchecked(
"198e9393920daef312c20b9f1099ecefa8b45575d349b0a6f04c16d0d58af900",
)),
]),
Fp2E::new([
FpE::new(U256::from_hex_unchecked(
"22376289c558493c1d6cc413a5f07dcb54526a964e4e687b65a881aa9752faa2",
)),
FpE::new(U256::from_hex_unchecked(
"05a7a5759338c23ca603c1c4adf979e004c2f3e3c5bad6f07693c59a85d600a9",
)),
]),
Fp2E::one(),
]);
assert!(!q.is_in_subgroup())
}

#[test]
fn g2_conjugate_two_times_is_identity() {
let a = Fp2E::zero();
let mut expected = a.conjugate();
expected = expected.conjugate();

assert_eq!(a, expected);
}

#[test]
fn apply_12_times_phi_is_identity() {
let q = BN254TwistCurve::generator();
let mut result = q.phi();
for _ in 1..12 {
result = result.phi();
}
assert_eq!(q, result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,71 @@ impl FieldElement<Degree12ExtensionField> {
])
}
}

#[cfg(test)]
mod tests {

use super::*;
type FpE = FieldElement<BN254PrimeField>;
type Fp2E = FieldElement<Degree2ExtensionField>;
type Fp6E = FieldElement<Degree6ExtensionField>;
type Fp12E = FieldElement<Degree12ExtensionField>;

#[test]
fn embed_base_field_with_degree_2_extension() {
let a = FpE::from(3);
let a_extension = Fp2E::from(3);
assert_eq!(a.to_extension::<Degree2ExtensionField>(), a_extension);
}

#[test]
fn add_base_field_with_degree_2_extension() {
let a = FpE::from(3);
let a_extension = Fp2E::from(3);
let b = Fp2E::from(2);
assert_eq!(a + &b, a_extension + b);
}

#[test]
fn mul_degree_2_with_degree_6_extension() {
let a = Fp2E::new([FpE::from(3), FpE::from(4)]);
let a_extension = a.clone().to_extension::<Degree2ExtensionField>();
let b = Fp6E::from(2);
assert_eq!(a * &b, a_extension * b);
}

#[test]
fn div_degree_6_degree_12_extension() {
let a = Fp6E::from(3);
let a_extension = Fp12E::from(3);
let b = Fp12E::from(2);
assert_eq!(a / &b, a_extension / b);
}

#[test]
fn double_equals_sum_two_times() {
let a = FpE::from(3);
assert_eq!(a.double(), a.clone() + a);
}

#[test]
fn base_field_sum_is_asociative() {
let a = FpE::from(3);
let b = FpE::from(2);
let c = &a + &b;
assert_eq!(a.double() + b, a + c);
}

#[test]
fn degree_2_extension_mul_is_conmutative() {
let a = Fp2E::from(3);
let b = Fp2E::new([FpE::from(2), FpE::from(4)]);
assert_eq!(&a * &b, b * a);
}

#[test]
fn base_field_pow_p_is_identity() {
let a = FpE::from(3);
assert_eq!(a.pow(BN254_PRIME_FIELD_ORDER), a);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod curve;
pub mod default_types;
pub mod field_extension;
pub mod pairing;
pub mod twist;
Loading

0 comments on commit 01fff47

Please sign in to comment.