revm_precompile/kzg_point_evaluation/
blst.rs1use crate::{
3 bls12_381::blst::{
4 p1_add_or_double, p1_from_affine, p1_scalar_mul, p1_to_affine, p2_add_or_double,
5 p2_from_affine, p2_scalar_mul, p2_to_affine, pairing_check,
6 },
7 bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES,
8 PrecompileError,
9};
10use ::blst::{
11 blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, blst_p2_affine, blst_scalar,
12 blst_scalar_fr_check, blst_scalar_from_bendian,
13};
14use primitives::OnceLock;
15
16#[inline]
21pub fn verify_kzg_proof(
22 commitment: &[u8; 48],
23 z: &[u8; 32],
24 y: &[u8; 32],
25 proof: &[u8; 48],
26) -> bool {
27 let Ok(commitment_point) = parse_g1_compressed(commitment) else {
29 return false;
30 };
31
32 let Ok(proof_point) = parse_g1_compressed(proof) else {
34 return false;
35 };
36
37 let Ok(z_scalar) = read_scalar_canonical(z) else {
39 return false;
40 };
41 let Ok(y_scalar) = read_scalar_canonical(y) else {
42 return false;
43 };
44
45 let tau_g2 = get_trusted_setup_g2();
47
48 let g1 = get_g1_generator();
50 let g2 = get_g2_generator();
51
52 let y_g1 = p1_scalar_mul(&g1, &y_scalar);
54 let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
55
56 let z_g2 = p2_scalar_mul(&g2, &z_scalar);
58 let x_minus_z = p2_sub_affine(tau_g2, &z_g2);
59
60 let neg_g2 = p2_neg(&g2);
63
64 pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)])
65}
66
67fn get_trusted_setup_g2() -> &'static blst_p2_affine {
70 static TAU_G2: OnceLock<blst_p2_affine> = OnceLock::new();
71 TAU_G2.get_or_init(|| {
72 let mut g2_affine = blst_p2_affine::default();
74 unsafe {
75 let result =
78 blst::blst_p2_uncompress(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr());
79 if result != blst::BLST_ERROR::BLST_SUCCESS {
80 panic!("Failed to deserialize trusted setup G2 point");
81 }
82 }
83 g2_affine
84 })
85}
86
87fn get_g1_generator() -> blst_p1_affine {
89 unsafe { ::blst::BLS12_381_G1 }
90}
91
92fn get_g2_generator() -> blst_p2_affine {
94 unsafe { ::blst::BLS12_381_G2 }
95}
96
97fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<blst_p1_affine, PrecompileError> {
99 let mut point = blst_p1_affine::default();
100 unsafe {
101 let result = blst::blst_p1_uncompress(&mut point, bytes.as_ptr());
102 if result != blst::BLST_ERROR::BLST_SUCCESS {
103 return Err(PrecompileError::KzgInvalidG1Point);
104 }
105
106 if !blst_p1_affine_on_curve(&point) {
108 return Err(PrecompileError::KzgG1PointNotOnCurve);
109 }
110
111 if !blst_p1_affine_in_g1(&point) {
113 return Err(PrecompileError::KzgG1PointNotInSubgroup);
114 }
115 }
116 Ok(point)
117}
118
119fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<blst_scalar, PrecompileError> {
121 let mut scalar = blst_scalar::default();
122
123 unsafe {
125 blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
126 }
127
128 if unsafe { !blst_scalar_fr_check(&scalar) } {
129 return Err(PrecompileError::NonCanonicalFp);
130 }
131
132 Ok(scalar)
133}
134
135fn p1_sub_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine {
137 let a_jacobian = p1_from_affine(a);
139
140 let neg_b = p1_neg(b);
142
143 let result = p1_add_or_double(&a_jacobian, &neg_b);
145
146 p1_to_affine(&result)
147}
148
149fn p2_sub_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine {
151 let a_jacobian = p2_from_affine(a);
153
154 let neg_b = p2_neg(b);
156
157 let result = p2_add_or_double(&a_jacobian, &neg_b);
159
160 p2_to_affine(&result)
161}
162
163fn p1_neg(p: &blst_p1_affine) -> blst_p1_affine {
165 let mut p_jacobian = p1_from_affine(p);
167 unsafe {
168 ::blst::blst_p1_cneg(&mut p_jacobian, true);
169 }
170 p1_to_affine(&p_jacobian)
171}
172
173fn p2_neg(p: &blst_p2_affine) -> blst_p2_affine {
175 let mut p_jacobian = p2_from_affine(p);
177 unsafe {
178 ::blst::blst_p2_cneg(&mut p_jacobian, true);
179 }
180 p2_to_affine(&p_jacobian)
181}