Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: pairing_check_hint for #[cfg(not(target_os = "zkvm"))] #1168

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion extensions/pairing/guest/src/bls12_381/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ use openvm_algebra_guest::{
DivUnsafe, Field,
};
use openvm_ecc_guest::AffinePoint;
#[cfg(not(target_os = "zkvm"))]
use {
crate::curve_const::bls12_381::{FINAL_EXP_FACTOR, LAMBDA, POLY_FACTOR},
num_bigint::BigUint,
openvm_algebra_guest::ExpBytes,
};
#[cfg(target_os = "zkvm")]
use {
crate::pairing::shifted_funct7,
Expand Down Expand Up @@ -275,7 +281,68 @@ impl PairingCheck for Bls12_381 {
) -> (Self::Fp12, Self::Fp12) {
#[cfg(not(target_os = "zkvm"))]
{
todo!()
let f = Self::multi_miller_loop(P, Q);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer for code maintenance if you just converted to halo2 curves type and called the associated method there. this duplicate code is not good for upkeep


// 1. get p-th root inverse
let mut exp = FINAL_EXP_FACTOR.clone() * BigUint::from(27u32);
let mut root = f.exp_bytes(true, &exp.to_bytes_be());
let root_pth_inv: Fp12;
if root == Fp12::ONE {
root_pth_inv = Fp12::ONE;
} else {
let exp_inv = exp.modinv(&POLY_FACTOR.clone()).unwrap();
exp = exp_inv % POLY_FACTOR.clone();
root_pth_inv = root.exp_bytes(false, &exp.to_bytes_be());
}

// 2.1. get order of 3rd primitive root
let three = BigUint::from(3u32);
let mut order_3rd_power: u32 = 0;
exp = POLY_FACTOR.clone() * FINAL_EXP_FACTOR.clone();

root = f.exp_bytes(true, &exp.to_bytes_be());
let three_be = three.to_bytes_be();
// NOTE[yj]: we can probably remove this first check as an optimization since we initizlize order_3rd_power to 0
if root == Fp12::ONE {
order_3rd_power = 0;
}
root = root.exp_bytes(true, &three_be);
if root == Fp12::ONE {
order_3rd_power = 1;
}
root = root.exp_bytes(true, &three_be);
if root == Fp12::ONE {
order_3rd_power = 2;
}
root = root.exp_bytes(true, &three_be);
if root == Fp12::ONE {
order_3rd_power = 3;
}

// 2.2. get 27th root inverse
let root_27th_inv: Fp12;
if order_3rd_power == 0 {
root_27th_inv = Fp12::ONE;
} else {
let order_3rd = three.pow(order_3rd_power);
exp = POLY_FACTOR.clone() * FINAL_EXP_FACTOR.clone();
root = f.exp_bytes(true, &exp.to_bytes_be());
let exp_inv = exp.modinv(&order_3rd).unwrap();
exp = exp_inv % order_3rd;
root_27th_inv = root.exp_bytes(false, &exp.to_bytes_be());
}

// 2.3. shift the Miller loop result so that millerLoop * scalingFactor
// is of order finalExpFactor
let s = root_pth_inv * root_27th_inv;
let f = f * s.clone();

// 3. get the witness residue
// lambda = q - u, the optimal exponent
exp = LAMBDA.clone().modinv(&FINAL_EXP_FACTOR.clone()).unwrap();
let c = f.exp_bytes(true, &exp.to_bytes_be());

(c, s)
}
#[cfg(target_os = "zkvm")]
{
Expand Down
39 changes: 38 additions & 1 deletion extensions/pairing/guest/src/bls12_381/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::{
bls12_381::{Bls12_381, 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 @@ -300,3 +301,39 @@ fn test_bls12381_g2_affine() {
}
}
}

#[test]
fn test_bls12381_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_bls12381_halo2_fq_to_fp(h2c_p.x),
y: convert_bls12381_halo2_fq_to_fp(h2c_p.y),
};
let q = AffinePoint {
x: convert_bls12381_halo2_fq2_to_fp2(h2c_q.x),
y: convert_bls12381_halo2_fq2_to_fp2(h2c_q.y),
};

let (c, s) = Bls12_381::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::bls12_381::Bls12_381::multi_miller_loop(&[p_cmp], &[q_cmp]);
let (c_cmp, s_cmp) = crate::halo2curves_shims::bls12_381::Bls12_381::final_exp_hint(&f_cmp);
let c_cmp = convert_bls12381_halo2_fq12_to_fp12(c_cmp);
let s_cmp = convert_bls12381_halo2_fq12_to_fp12(s_cmp);

assert_eq!(c, c_cmp);
assert_eq!(s, s_cmp);
}
101 changes: 100 additions & 1 deletion extensions/pairing/guest/src/bn254/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ use alloc::vec::Vec;
use itertools::izip;
use openvm_algebra_guest::{field::FieldExtension, DivUnsafe, Field};
use openvm_ecc_guest::AffinePoint;
#[cfg(not(target_os = "zkvm"))]
use {
crate::curve_const::bn254::{EXP1, EXP2, M_INV, R_INV, U27_COEFF_0, U27_COEFF_1},
openvm_algebra_guest::{ExpBytes, IntMod},
};
#[cfg(target_os = "zkvm")]
use {
crate::pairing::shifted_funct7,
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
@@ -1,12 +1,18 @@
use halo2curves_axiom::bls12_381::{Fq, Fq2};
use lazy_static::lazy_static;
use num_bigint::BigUint;
use num_traits::Num;
use openvm_ecc_guest::algebra::{field::FieldExtension, Field};
#[cfg(feature = "halo2curves")]
use {
halo2curves_axiom::bls12_381::{Fq, Fq2},
openvm_ecc_guest::algebra::{field::FieldExtension, Field},
};

#[cfg(feature = "halo2curves")]
lazy_static! {
pub static ref BLS12_381_XI: Fq2 = Fq2::from_coeffs([Fq::ONE, Fq::ONE]);
}

lazy_static! {
// polyFactor = (1-x)/3
pub static ref POLY_FACTOR: BigUint = BigUint::from_str_radix("5044125407647214251", 10).unwrap();

Expand All @@ -19,5 +25,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
@@ -1,12 +1,18 @@
use halo2curves_axiom::bn256::{Fq, Fq2};
use lazy_static::lazy_static;
use num_bigint::BigUint;
use num_traits::Num;
use openvm_ecc_guest::algebra::field::FieldExtension;
#[cfg(feature = "halo2curves")]
use {
halo2curves_axiom::bn256::{Fq, Fq2},
openvm_ecc_guest::algebra::field::FieldExtension,
};

#[cfg(feature = "halo2curves")]
lazy_static! {
pub static ref BN254_XI: Fq2 = Fq2::from_coeffs([Fq::from_raw([9, 0, 0, 0]), Fq::one()]);
}

lazy_static! {
// exp1 = (p^12 - 1) / 3
pub static ref EXP1: BigUint = BigUint::from_str_radix(
"4030969696062745741797811005853058291874379204406359442560681893891674450106959530046539719647151210908190211459382793062006703141168852426020468083171325367934590379984666859998399967609544754664110191464072930598755441160008826659219834762354786403012110463250131961575955268597858015384895449311534622125256548620283853223733396368939858981844663598065852816056384933498610930035891058807598891752166582271931875150099691598048016175399382213304673796601585080509443902692818733420199004555566113537482054218823936116647313678747500267068559627206777530424029211671772692598157901876223857571299238046741502089890557442500582300718504160740314926185458079985126192563953772118929726791041828902047546977272656240744693339962973939047279285351052107950250121751682659529260304162131862468322644288196213423232132152125277136333208005221619443705106431645884840489295409272576227859206166894626854018093044908314720",
Expand Down Expand Up @@ -38,5 +44,3 @@ lazy_static! {
10
).unwrap();
}

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

#[cfg(any(feature = "bn254", feature = "halo2curves"))]
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
Loading