Skip to content

Commit

Permalink
BN254 pairing check hint
Browse files Browse the repository at this point in the history
  • Loading branch information
ytham committed Jan 3, 2025
1 parent 137e42d commit 1585991
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 23 deletions.
109 changes: 104 additions & 5 deletions extensions/pairing/guest/src/bn254/pairing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloc::vec::Vec;

use itertools::izip;
use openvm_algebra_guest::{field::FieldExtension, DivUnsafe, Field};
use openvm_algebra_guest::{field::FieldExtension, DivUnsafe, ExpBytes, Field, IntMod};
use openvm_ecc_guest::AffinePoint;
#[cfg(target_os = "zkvm")]
use {
Expand All @@ -12,9 +12,14 @@ use {
};

use super::{Bn254, Fp, Fp12, Fp2};
use crate::pairing::{
Evaluatable, EvaluatedLine, FromLineDType, LineMulDType, MillerStep, MultiMillerLoop,
PairingCheck, PairingCheckError, PairingIntrinsics, UnevaluatedLine,
#[cfg(not(target_os = "zkvm"))]
use crate::curve_const::bn254::{U27_COEFF_0, U27_COEFF_1};
use crate::{
curve_const::bn254::{EXP1, EXP2, M_INV, R_INV},
pairing::{
Evaluatable, EvaluatedLine, FromLineDType, LineMulDType, MillerStep, MultiMillerLoop,
PairingCheck, PairingCheckError, PairingIntrinsics, UnevaluatedLine,
},
};

// TODO[jpw]: make macro
Expand Down Expand Up @@ -307,7 +312,101 @@ impl PairingCheck for Bn254 {
) -> (Self::Fp12, Self::Fp12) {
#[cfg(not(target_os = "zkvm"))]
{
todo!()
let f = Self::multi_miller_loop(P, Q);

// Residue witness
let mut c;
// Cubic nonresidue power
let u;

// get the 27th root of unity
let u0 = U27_COEFF_0.to_bytes_be();
let u1 = U27_COEFF_1.to_bytes_be();
let u_coeffs = Fp2::from_coeffs([Fp::from_be_bytes(&u0), Fp::from_be_bytes(&u1)]);

let mut unity_root_27 = Fp12::from_coeffs([
Fp2::ZERO,
Fp2::ZERO,
u_coeffs,
Fp2::ZERO,
Fp2::ZERO,
Fp2::ZERO,
]);
debug_assert_eq!(
unity_root_27.exp_bytes(true, &27u32.to_be_bytes()),
Fp12::ONE
);

if f.exp_bytes(true, &EXP1.to_bytes_be()) == Fp12::ONE {
c = f;
u = Fp12::ONE;
} else {
let f_mul_unity_root_27 = f * unity_root_27.clone();
if f_mul_unity_root_27.exp_bytes(true, &EXP1.to_bytes_be()) == Fp12::ONE {
c = f_mul_unity_root_27;
u = unity_root_27.clone();
} else {
c = f_mul_unity_root_27 * unity_root_27.clone();
unity_root_27.square_assign();
u = unity_root_27.clone();
}
}

// 1. Compute r-th root and exponentiate to rInv where
// rInv = 1/r mod (p^12-1)/r
c = c.exp_bytes(true, &R_INV.to_bytes_be());

// 2. Compute m-th root where
// m = (6x + 2 + q^3 - q^2 +q)/3r
// Exponentiate to mInv where
// mInv = 1/m mod p^12-1
c = c.exp_bytes(true, &M_INV.to_bytes_be());

// 3. Compute cube root
// since gcd(3, (p^12-1)/r) != 1, we use a modified Tonelli-Shanks algorithm
// see Alg.4 of https://eprint.iacr.org/2024/640.pdf
// Typo in the paper: p^k-1 = 3^n * s instead of p-1 = 3^r * s
// where k=12 and n=3 here and exp2 = (s+1)/3
let mut x = c.exp_bytes(true, &EXP2.to_bytes_be());

// 3^t is ord(x^3 / residueWitness)
let c_inv = c.invert();
let mut x2 = x.clone();
x2.square_assign();
let mut x3 = x2 * x.clone() * c_inv.clone();
let mut t = 0;
let mut tmp = x3.clone();
tmp.square_assign();

// Modified Tonelli-Shanks algorithm for computing the cube root
fn tonelli_shanks_loop(x3: &mut Fp12, tmp: &mut Fp12, t: &mut i32) {
while *x3 != Fp12::ONE {
*tmp = x3.clone();
tmp.square_assign();
*x3 *= tmp.clone();
*t += 1;
}
}

tonelli_shanks_loop(&mut x3, &mut tmp, &mut t);

while t != 0 {
tmp = unity_root_27.exp_bytes(true, &EXP2.to_bytes_be());
x *= tmp.clone();

let mut x2 = x.clone();
x2.square_assign();
x3 = x2 * x.clone() * c_inv.clone();
t = 0;
tonelli_shanks_loop(&mut x3, &mut tmp, &mut t);
}

debug_assert_eq!(c, x.clone() * x.clone() * x.clone());

// x is the cube root of the residue witness c
c = x.clone();

(c, u)
}
#[cfg(target_os = "zkvm")]
{
Expand Down
38 changes: 37 additions & 1 deletion extensions/pairing/guest/src/bn254/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use super::{Fp, Fp12, Fp2};
use crate::{
bn254::{Bn254, G2Affine as OpenVmG2Affine},
pairing::{
fp2_invert_assign, fp6_invert_assign, fp6_square_assign, MultiMillerLoop, PairingIntrinsics,
fp2_invert_assign, fp6_invert_assign, fp6_square_assign, FinalExp, MultiMillerLoop,
PairingCheck, PairingIntrinsics,
},
};

Expand Down Expand Up @@ -286,3 +287,38 @@ fn test_bn254_g2_affine() {
}
}
}

#[test]
fn test_bn254_pairing_check_hint_host() {
let mut rng = StdRng::seed_from_u64(83);
let h2c_p = G1Affine::random(&mut rng);
let h2c_q = G2Affine::random(&mut rng);

let p = AffinePoint {
x: convert_bn254_halo2_fq_to_fp(h2c_p.x),
y: convert_bn254_halo2_fq_to_fp(h2c_p.y),
};
let q = AffinePoint {
x: convert_bn254_halo2_fq2_to_fp2(h2c_q.x),
y: convert_bn254_halo2_fq2_to_fp2(h2c_q.y),
};

let (c, u) = Bn254::pairing_check_hint(&[p], &[q]);

let p_cmp = AffinePoint {
x: h2c_p.x,
y: h2c_p.y,
};
let q_cmp = AffinePoint {
x: h2c_q.x,
y: h2c_q.y,
};

let f_cmp = crate::halo2curves_shims::bn254::Bn254::multi_miller_loop(&[p_cmp], &[q_cmp]);
let (c_cmp, u_cmp) = crate::halo2curves_shims::bn254::Bn254::final_exp_hint(&f_cmp);
let c_cmp = convert_bn254_halo2_fq12_to_fp12(c_cmp);
let u_cmp = convert_bn254_halo2_fq12_to_fp12(u_cmp);

assert_eq!(c, c_cmp);
assert_eq!(u, u_cmp);
}
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,3 @@ lazy_static! {
// t = -x = 15132376222941642752
pub static ref SEED_NEG: BigUint = BigUint::from_str_radix("15132376222941642752", 10).unwrap();
}

pub struct Bls12_381;
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,3 @@ lazy_static! {
10
).unwrap();
}

pub struct Bn254;
11 changes: 11 additions & 0 deletions extensions/pairing/guest/src/curve_const/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[cfg(all(
any(feature = "bls12_381", feature = "halo2curves"),
not(target_os = "zkvm")
))]
pub mod bls12_381;

#[cfg(all(
any(feature = "bn254", feature = "halo2curves"),
not(target_os = "zkvm")
))]
pub mod bn254;
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ use openvm_ecc_guest::{
AffinePoint,
};

use super::{Bls12_381, FINAL_EXP_FACTOR, LAMBDA, POLY_FACTOR};
use crate::pairing::{FinalExp, MultiMillerLoop};
use super::Bls12_381;
use crate::{
curve_const::bls12_381::{FINAL_EXP_FACTOR, LAMBDA, POLY_FACTOR},
pairing::{FinalExp, MultiMillerLoop},
};

#[allow(non_snake_case)]
impl FinalExp for Bls12_381 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ use openvm_ecc_guest::{
AffinePoint,
};

use super::{Bls12_381, BLS12_381_XI};
use crate::pairing::{EvaluatedLine, LineMulMType};
use super::Bls12_381;
use crate::{
curve_const::bls12_381::BLS12_381_XI,
pairing::{EvaluatedLine, LineMulMType},
};

impl LineMulMType<Fq2, Fq12> for Bls12_381 {
fn mul_023_by_023(l0: &EvaluatedLine<Fq2>, l1: &EvaluatedLine<Fq2>) -> [Fq2; 5] {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod curve;
mod final_exp;
mod line;
mod miller_loop;

pub use curve::*;
pub use line::*;

#[cfg(test)]
Expand All @@ -18,6 +16,8 @@ use crate::{
pairing::{Evaluatable, EvaluatedLine, FromLineMType, UnevaluatedLine},
};

pub struct Bls12_381;

impl FromLineMType<Fq2> for Fq12 {
fn from_evaluated_line_m_type(line: EvaluatedLine<Fq2>) -> Fq12 {
Fq12::from_coeffs([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use num_traits::Num;
use openvm_ecc_guest::{algebra::ExpBytes, AffinePoint};

use crate::{
halo2curves_shims::bls12_381::{Bls12_381, SEED_NEG},
curve_const::bls12_381::SEED_NEG,
halo2curves_shims::bls12_381::Bls12_381,
pairing::{FinalExp, MultiMillerLoop},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ use halo2curves_axiom::{
};
use openvm_ecc_guest::{algebra::field::FieldExtension, AffinePoint};

use super::{Bn254, EXP1, EXP2, M_INV, R_INV, U27_COEFF_0, U27_COEFF_1};
use crate::pairing::{FinalExp, MultiMillerLoop};
use super::Bn254;
use crate::{
curve_const::bn254::{EXP1, EXP2, M_INV, R_INV, U27_COEFF_0, U27_COEFF_1},
pairing::{FinalExp, MultiMillerLoop},
};

#[allow(non_snake_case)]
impl FinalExp for Bn254 {
Expand Down
7 changes: 5 additions & 2 deletions extensions/pairing/guest/src/halo2curves_shims/bn254/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ use openvm_ecc_guest::{
AffinePoint,
};

use super::{Bn254, BN254_XI};
use crate::pairing::{EvaluatedLine, LineMulDType};
use super::Bn254;
use crate::{
curve_const::bn254::BN254_XI,
pairing::{EvaluatedLine, LineMulDType},
};

impl LineMulDType<Fq2, Fq12> for Bn254 {
/// Multiplies two lines in 013-form to get an element in 01234-form
Expand Down
4 changes: 2 additions & 2 deletions extensions/pairing/guest/src/halo2curves_shims/bn254/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod curve;
mod final_exp;
mod line;
mod miller_loop;

pub use curve::*;
pub use line::*;

#[cfg(test)]
Expand All @@ -18,6 +16,8 @@ use crate::{
pairing::{Evaluatable, EvaluatedLine, FromLineDType, UnevaluatedLine},
};

pub struct Bn254;

impl FromLineDType<Fq2> for Fq12 {
fn from_evaluated_line_d_type(line: EvaluatedLine<Fq2>) -> Fq12 {
FieldExtension::<Fq2>::from_coeffs([
Expand Down
6 changes: 6 additions & 0 deletions extensions/pairing/guest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ pub mod halo2curves_shims;
/// Traits for optimal Ate pairing check using intrinsic functions.
pub mod pairing;

#[cfg(all(
any(feature = "bls12_381", feature = "bn254", feature = "halo2curves"),
not(target_os = "zkvm")
))]
pub mod curve_const;

/// Types for BLS12-381 curve with intrinsic functions.
#[cfg(feature = "bls12_381")]
pub mod bls12_381;
Expand Down

0 comments on commit 1585991

Please sign in to comment.