revm_precompile/kzg_point_evaluation/
arkworks.rs1use crate::bls12_381::arkworks::pairing_check;
3use crate::bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES;
4use crate::PrecompileError;
5use ark_bls12_381::{Fr, G1Affine, G2Affine};
6use ark_ec::{AffineRepr, CurveGroup};
7use ark_ff::{BigInteger, PrimeField};
8use ark_serialize::CanonicalDeserialize;
9use core::ops::Neg;
10use std::string::ToString;
11
12#[inline]
17pub fn verify_kzg_proof(
18 commitment: &[u8; 48],
19 z: &[u8; 32],
20 y: &[u8; 32],
21 proof: &[u8; 48],
22) -> bool {
23 let Ok(commitment_point) = parse_g1_compressed(commitment) else {
25 return false;
26 };
27
28 let Ok(proof_point) = parse_g1_compressed(proof) else {
30 return false;
31 };
32
33 let Ok(z_fr) = read_scalar_canonical(z) else {
36 return false;
37 };
38 let Ok(y_fr) = read_scalar_canonical(y) else {
39 return false;
40 };
41
42 let tau_g2 = get_trusted_setup_g2();
44
45 let g1 = get_g1_generator();
47 let g2 = get_g2_generator();
48
49 let y_g1 = p1_scalar_mul(&g1, &y_fr);
51 let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
52
53 let z_g2 = p2_scalar_mul(&g2, &z_fr);
55 let x_minus_z = p2_sub_affine(&tau_g2, &z_g2);
56
57 let neg_g2 = p2_neg(&g2);
60
61 pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)])
62}
63
64fn get_trusted_setup_g2() -> G2Affine {
67 G2Affine::deserialize_compressed_unchecked(&TRUSTED_SETUP_TAU_G2_BYTES[..])
70 .expect("Failed to parse trusted setup G2 point")
71}
72
73fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<G1Affine, PrecompileError> {
75 G1Affine::deserialize_compressed(&bytes[..])
76 .map_err(|_| PrecompileError::Other("Invalid compressed G1 point".to_string()))
77}
78
79fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<Fr, PrecompileError> {
81 let fr = Fr::from_be_bytes_mod_order(bytes);
82
83 let bytes_roundtrip = fr.into_bigint().to_bytes_be();
85
86 if bytes_roundtrip.as_slice() != bytes {
87 return Err(PrecompileError::Other(
88 "Non-canonical scalar field element".to_string(),
89 ));
90 }
91
92 Ok(fr)
93}
94
95#[inline]
97fn get_g1_generator() -> G1Affine {
98 G1Affine::generator()
99}
100
101#[inline]
103fn get_g2_generator() -> G2Affine {
104 G2Affine::generator()
105}
106
107#[inline]
109fn p1_scalar_mul(point: &G1Affine, scalar: &Fr) -> G1Affine {
110 point.mul_bigint(scalar.into_bigint()).into_affine()
111}
112
113#[inline]
115fn p2_scalar_mul(point: &G2Affine, scalar: &Fr) -> G2Affine {
116 point.mul_bigint(scalar.into_bigint()).into_affine()
117}
118
119#[inline]
121fn p1_sub_affine(a: &G1Affine, b: &G1Affine) -> G1Affine {
122 (a.into_group() - b.into_group()).into_affine()
123}
124
125#[inline]
127fn p2_sub_affine(a: &G2Affine, b: &G2Affine) -> G2Affine {
128 (a.into_group() - b.into_group()).into_affine()
129}
130
131#[inline]
133fn p2_neg(p: &G2Affine) -> G2Affine {
134 p.neg()
135}