#[cfg(zisk_guest)]
use crate::alloc_extern::vec::Vec;
use crate::zisklib::{
eq, fcall_bn254_twist_add_line_coeffs, fcall_bn254_twist_dbl_line_coeffs, is_zero,
};
use super::{
fp::{inv_fp_bn254, mul_fp_bn254, neg_fp_bn254},
fp12::{sparse_mul_fp12_bn254, square_fp12_bn254},
fp2::{
add_fp2_bn254, dbl_fp2_bn254, mul_fp2_bn254, neg_fp2_bn254, scalar_mul_fp2_bn254,
square_fp2_bn254, sub_fp2_bn254,
},
twist::{neg_twist_bn254, utf_endomorphism_twist_bn254},
};
const LOOP_LENGTH: [i8; 65] = [
1, 1, 0, 1, 0, 0, -1, 0, 1, 1, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, -1,
0, 0, 1, 1, 1, 0, 0, 0, 0, -1, 0, 1, 0, 0, -1, 0, 1, 1, 0, 0, 1, 0, 0, -1, 1, 0, 0, -1, 0, 1,
0, 1, 0, 0, 0,
];
pub fn miller_loop_bn254(
p: &[u64; 8],
q: &[u64; 16],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let mut xp_prime: [u64; 4] = p[0..4].try_into().unwrap();
let mut yp_prime: [u64; 4] = p[4..8].try_into().unwrap();
yp_prime = inv_fp_bn254(
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
xp_prime = neg_fp_bn254(
&xp_prime,
#[cfg(feature = "hints")]
hints,
);
xp_prime = mul_fp_bn254(
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
let mut r: [u64; 16] = q[0..16].try_into().unwrap();
let mut f = [0u64; 48];
f[0] = 1;
for &bit in LOOP_LENGTH.iter().skip(1) {
let (lambda, mu) = fcall_bn254_twist_dbl_line_coeffs(
&r,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_tangent_twist_bn254(
&r,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line is not tangent to the curve at r"
);
f = square_fp12_bn254(
&f,
#[cfg(feature = "hints")]
hints,
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
r = dbl_twist_with_hints_bn254(
&r,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
if bit * bit == 1 {
let q_prime = if bit == 1 {
q
} else {
&neg_twist_bn254(
q,
#[cfg(feature = "hints")]
hints,
)
};
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
&r,
q_prime,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
&r,
q_prime,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line does not pass through r and q'"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
r = add_twist_with_hints_bn254(
&r,
q_prime,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
}
}
let q_frob = utf_endomorphism_twist_bn254(
q,
#[cfg(feature = "hints")]
hints,
);
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
&r,
&q_frob,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
&r,
&q_frob,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line does not pass through r and utf(q)"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
r = add_twist_with_hints_bn254(
&r,
&q_frob,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
let q_frob2 = neg_twist_bn254(
&utf_endomorphism_twist_bn254(
&q_frob,
#[cfg(feature = "hints")]
hints,
),
#[cfg(feature = "hints")]
hints,
);
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
&r,
&q_frob2,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
&r,
&q_frob2,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints
),
"Line does not pass through r and -utf(utf(q))"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
f
}
pub fn miller_loop_batch_bn254(
g1_points: &[[u64; 8]],
g2_points: &[[u64; 16]],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let mut xp_primes: Vec<[u64; 4]> = Vec::with_capacity(g1_points.len());
let mut yp_primes: Vec<[u64; 4]> = Vec::with_capacity(g1_points.len());
for p in g1_points.iter() {
let mut xp_prime: [u64; 4] = p[0..4].try_into().unwrap();
let mut yp_prime: [u64; 4] = p[4..8].try_into().unwrap();
yp_prime = inv_fp_bn254(
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
xp_prime = neg_fp_bn254(
&xp_prime,
#[cfg(feature = "hints")]
hints,
);
xp_prime = mul_fp_bn254(
&xp_prime,
&yp_prime,
#[cfg(feature = "hints")]
hints,
);
xp_primes.push(xp_prime);
yp_primes.push(yp_prime);
}
let mut r: Vec<[u64; 16]> = g2_points.iter().map(|q| q[0..16].try_into().unwrap()).collect();
let mut f = [0u64; 48];
f[0] = 1;
let n = g1_points.len();
for &bit in LOOP_LENGTH.iter().skip(1) {
f = square_fp12_bn254(
&f,
#[cfg(feature = "hints")]
hints,
);
for i in 0..n {
let r = &mut r[i];
let (lambda, mu) = fcall_bn254_twist_dbl_line_coeffs(
r,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_tangent_twist_bn254(
r,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line is not tangent to the curve at r"
);
let xp_prime = &xp_primes[i];
let yp_prime = &yp_primes[i];
let l = line_eval_twist_bn254(
&lambda,
&mu,
xp_prime,
yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
*r = dbl_twist_with_hints_bn254(
r,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
if bit * bit == 1 {
let q = &g2_points[i];
let q_prime = if bit == 1 {
q
} else {
&neg_twist_bn254(
q,
#[cfg(feature = "hints")]
hints,
)
};
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
r,
q_prime,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
r,
q_prime,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line does not pass through r and q'"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
xp_prime,
yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
*r = add_twist_with_hints_bn254(
r,
q_prime,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
}
}
}
for i in 0..n {
let q = &g2_points[i];
let r = &mut r[i];
let xp_prime = &xp_primes[i];
let yp_prime = &yp_primes[i];
let q_frob = utf_endomorphism_twist_bn254(
q,
#[cfg(feature = "hints")]
hints,
);
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
r,
&q_frob,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
r,
&q_frob,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line does not pass through r and utf(q)"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
xp_prime,
yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
*r = add_twist_with_hints_bn254(
r,
&q_frob,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
);
let q_frob2 = neg_twist_bn254(
&utf_endomorphism_twist_bn254(
&q_frob,
#[cfg(feature = "hints")]
hints,
),
#[cfg(feature = "hints")]
hints,
);
let (lambda, mu) = fcall_bn254_twist_add_line_coeffs(
r,
&q_frob2,
#[cfg(feature = "hints")]
hints,
);
assert!(
is_line_twist_bn254(
r,
&q_frob2,
&lambda,
&mu,
#[cfg(feature = "hints")]
hints,
),
"Line does not pass through r and -utf(utf(q))"
);
let l = line_eval_twist_bn254(
&lambda,
&mu,
xp_prime,
yp_prime,
#[cfg(feature = "hints")]
hints,
);
f = sparse_mul_fp12_bn254(
&f,
&l,
#[cfg(feature = "hints")]
hints,
);
}
f
}
#[inline]
fn is_line_twist_bn254(
q1: &[u64; 16],
q2: &[u64; 16],
lambda: &[u64; 8],
mu: &[u64; 8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> bool {
if eq(&q1[0..8], &q2[0..8]) {
return false;
}
let check_q1 = line_check_twist_bn254(
q1,
lambda,
mu,
#[cfg(feature = "hints")]
hints,
);
let check_q2 = line_check_twist_bn254(
q2,
lambda,
mu,
#[cfg(feature = "hints")]
hints,
);
check_q1 && check_q2
}
#[inline]
fn is_tangent_twist_bn254(
q: &[u64; 16],
lambda: &[u64; 8],
mu: &[u64; 8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> bool {
let x: &[u64; 8] = q[0..8].try_into().unwrap();
let y: &[u64; 8] = q[8..16].try_into().unwrap();
if is_zero(y) {
return false;
}
let check_q = line_check_twist_bn254(
q,
lambda,
mu,
#[cfg(feature = "hints")]
hints,
);
let mut lhs = mul_fp2_bn254(
lambda,
y,
#[cfg(feature = "hints")]
hints,
);
lhs = dbl_fp2_bn254(
&lhs,
#[cfg(feature = "hints")]
hints,
);
let mut rhs = square_fp2_bn254(
x,
#[cfg(feature = "hints")]
hints,
);
rhs = scalar_mul_fp2_bn254(
&rhs,
&[3, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
check_q && eq(&lhs, &rhs)
}
#[inline]
fn line_check_twist_bn254(
q: &[u64; 16],
lambda: &[u64; 8],
mu: &[u64; 8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> bool {
let x: &[u64; 8] = q[0..8].try_into().unwrap();
let y: &[u64; 8] = q[8..16].try_into().unwrap();
let mut rhs = mul_fp2_bn254(
lambda,
x,
#[cfg(feature = "hints")]
hints,
);
rhs = add_fp2_bn254(
&rhs,
mu,
#[cfg(feature = "hints")]
hints,
);
eq(&rhs, y)
}
#[inline]
fn line_eval_twist_bn254(
lambda: &[u64; 8],
mu: &[u64; 8],
x: &[u64; 4],
y: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 16] {
let coeff1 = scalar_mul_fp2_bn254(
lambda,
x,
#[cfg(feature = "hints")]
hints,
);
let coeff2 = scalar_mul_fp2_bn254(
mu,
&neg_fp_bn254(
y,
#[cfg(feature = "hints")]
hints,
),
#[cfg(feature = "hints")]
hints,
);
let mut result = [0; 16];
result[0..8].copy_from_slice(&coeff1);
result[8..16].copy_from_slice(&coeff2);
result
}
#[inline]
fn add_twist_with_hints_bn254(
q1: &[u64; 16],
q2: &[u64; 16],
lambda: &[u64; 8],
mu: &[u64; 8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 16] {
let x1: &[u64; 8] = q1[0..8].try_into().unwrap();
let x2: &[u64; 8] = q2[0..8].try_into().unwrap();
let mut x3 = square_fp2_bn254(
lambda,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bn254(
&x3,
x1,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bn254(
&x3,
x2,
#[cfg(feature = "hints")]
hints,
);
let mut y3 = mul_fp2_bn254(
lambda,
&x3,
#[cfg(feature = "hints")]
hints,
);
y3 = add_fp2_bn254(
mu,
&y3,
#[cfg(feature = "hints")]
hints,
);
y3 = neg_fp2_bn254(
&y3,
#[cfg(feature = "hints")]
hints,
);
[
x3[0], x3[1], x3[2], x3[3], x3[4], x3[5], x3[6], x3[7], y3[0], y3[1], y3[2], y3[3], y3[4],
y3[5], y3[6], y3[7],
]
}
#[inline]
fn dbl_twist_with_hints_bn254(
q: &[u64; 16],
lambda: &[u64; 8],
mu: &[u64; 8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 16] {
let x: &[u64; 8] = q[0..8].try_into().unwrap();
let mut x3 = square_fp2_bn254(
lambda,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bn254(
&x3,
&dbl_fp2_bn254(
x,
#[cfg(feature = "hints")]
hints,
),
#[cfg(feature = "hints")]
hints,
);
let mut y3 = mul_fp2_bn254(
lambda,
&x3,
#[cfg(feature = "hints")]
hints,
);
y3 = add_fp2_bn254(
mu,
&y3,
#[cfg(feature = "hints")]
hints,
);
y3 = neg_fp2_bn254(
&y3,
#[cfg(feature = "hints")]
hints,
);
[
x3[0], x3[1], x3[2], x3[3], x3[4], x3[5], x3[6], x3[7], y3[0], y3[1], y3[2], y3[3], y3[4],
y3[5], y3[6], y3[7],
]
}