use crate::{
bls12_381::blst::{
p1_add_or_double, p1_from_affine, p1_scalar_mul, p1_to_affine, p2_add_or_double,
p2_from_affine, p2_scalar_mul, p2_to_affine, pairing_check,
},
bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES,
PrecompileHalt,
};
use ::blst::{
blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, blst_p2_affine, blst_scalar,
blst_scalar_fr_check, blst_scalar_from_bendian,
};
use primitives::OnceLock;
#[inline]
pub fn verify_kzg_proof(
commitment: &[u8; 48],
z: &[u8; 32],
y: &[u8; 32],
proof: &[u8; 48],
) -> bool {
let Ok(commitment_point) = parse_g1_compressed(commitment) else {
return false;
};
let Ok(proof_point) = parse_g1_compressed(proof) else {
return false;
};
let Ok(z_scalar) = read_scalar_canonical(z) else {
return false;
};
let Ok(y_scalar) = read_scalar_canonical(y) else {
return false;
};
let tau_g2 = get_trusted_setup_g2();
let g1 = get_g1_generator();
let g2 = get_g2_generator();
let y_g1 = p1_scalar_mul(&g1, &y_scalar);
let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
let z_g2 = p2_scalar_mul(&g2, &z_scalar);
let x_minus_z = p2_sub_affine(tau_g2, &z_g2);
let neg_g2 = p2_neg(&g2);
pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)])
}
fn get_trusted_setup_g2() -> &'static blst_p2_affine {
static TAU_G2: OnceLock<blst_p2_affine> = OnceLock::new();
TAU_G2.get_or_init(|| {
let mut g2_affine = blst_p2_affine::default();
unsafe {
let result =
blst::blst_p2_uncompress(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr());
if result != blst::BLST_ERROR::BLST_SUCCESS {
panic!("Failed to deserialize trusted setup G2 point");
}
}
g2_affine
})
}
fn get_g1_generator() -> blst_p1_affine {
unsafe { ::blst::BLS12_381_G1 }
}
fn get_g2_generator() -> blst_p2_affine {
unsafe { ::blst::BLS12_381_G2 }
}
fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<blst_p1_affine, PrecompileHalt> {
let mut point = blst_p1_affine::default();
unsafe {
let result = blst::blst_p1_uncompress(&mut point, bytes.as_ptr());
if result != blst::BLST_ERROR::BLST_SUCCESS {
return Err(PrecompileHalt::KzgInvalidG1Point);
}
if !blst_p1_affine_on_curve(&point) {
return Err(PrecompileHalt::KzgG1PointNotOnCurve);
}
if !blst_p1_affine_in_g1(&point) {
return Err(PrecompileHalt::KzgG1PointNotInSubgroup);
}
}
Ok(point)
}
fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<blst_scalar, PrecompileHalt> {
let mut scalar = blst_scalar::default();
unsafe {
blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
}
if unsafe { !blst_scalar_fr_check(&scalar) } {
return Err(PrecompileHalt::NonCanonicalFp);
}
Ok(scalar)
}
fn p1_sub_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine {
let a_jacobian = p1_from_affine(a);
let neg_b = p1_neg(b);
let result = p1_add_or_double(&a_jacobian, &neg_b);
p1_to_affine(&result)
}
fn p2_sub_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine {
let a_jacobian = p2_from_affine(a);
let neg_b = p2_neg(b);
let result = p2_add_or_double(&a_jacobian, &neg_b);
p2_to_affine(&result)
}
fn p1_neg(p: &blst_p1_affine) -> blst_p1_affine {
let mut p_jacobian = p1_from_affine(p);
unsafe {
::blst::blst_p1_cneg(&mut p_jacobian, true);
}
p1_to_affine(&p_jacobian)
}
fn p2_neg(p: &blst_p2_affine) -> blst_p2_affine {
let mut p_jacobian = p2_from_affine(p);
unsafe {
::blst::blst_p2_cneg(&mut p_jacobian, true);
}
p2_to_affine(&p_jacobian)
}