revm_precompile/kzg_point_evaluation/
blst.rs1use crate::bls12_381::blst::{
3 p1_add_or_double, p1_from_affine, p1_scalar_mul, p1_to_affine, p2_add_or_double,
4 p2_from_affine, p2_scalar_mul, p2_to_affine, pairing_check,
5};
6use crate::bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES;
7use crate::PrecompileError;
8use ::blst::{
9 blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, blst_p2_affine, blst_scalar,
10 blst_scalar_fr_check, blst_scalar_from_bendian,
11};
12use std::string::ToString;
13
14#[inline]
19pub fn verify_kzg_proof(
20 commitment: &[u8; 48],
21 z: &[u8; 32],
22 y: &[u8; 32],
23 proof: &[u8; 48],
24) -> bool {
25 let Ok(commitment_point) = parse_g1_compressed(commitment) else {
27 return false;
28 };
29
30 let Ok(proof_point) = parse_g1_compressed(proof) else {
32 return false;
33 };
34
35 let Ok(z_scalar) = read_scalar_canonical(z) else {
37 return false;
38 };
39 let Ok(y_scalar) = read_scalar_canonical(y) else {
40 return false;
41 };
42
43 let tau_g2 = get_trusted_setup_g2();
45
46 let g1 = get_g1_generator();
48 let g2 = get_g2_generator();
49
50 let y_g1 = p1_scalar_mul(&g1, &y_scalar);
52 let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
53
54 let z_g2 = p2_scalar_mul(&g2, &z_scalar);
56 let x_minus_z = p2_sub_affine(&tau_g2, &z_g2);
57
58 let neg_g2 = p2_neg(&g2);
61
62 pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)])
63}
64
65fn get_trusted_setup_g2() -> blst_p2_affine {
68 let mut g2_affine = blst_p2_affine::default();
70 unsafe {
71 let result = blst::blst_p2_deserialize(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr());
74 if result != blst::BLST_ERROR::BLST_SUCCESS {
75 panic!("Failed to deserialize trusted setup G2 point");
76 }
77 }
78 g2_affine
79}
80
81fn get_g1_generator() -> blst_p1_affine {
83 unsafe { ::blst::BLS12_381_G1 }
84}
85
86fn get_g2_generator() -> blst_p2_affine {
88 unsafe { ::blst::BLS12_381_G2 }
89}
90
91fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<blst_p1_affine, PrecompileError> {
93 let mut point = blst_p1_affine::default();
94 unsafe {
95 let result = blst::blst_p1_deserialize(&mut point, bytes.as_ptr());
96 if result != blst::BLST_ERROR::BLST_SUCCESS {
97 return Err(PrecompileError::Other(
98 "Invalid compressed G1 point".to_string(),
99 ));
100 }
101
102 if !blst_p1_affine_on_curve(&point) {
104 return Err(PrecompileError::Other("G1 point not on curve".to_string()));
105 }
106
107 if !blst_p1_affine_in_g1(&point) {
109 return Err(PrecompileError::Other(
110 "G1 point not in correct subgroup".to_string(),
111 ));
112 }
113 }
114 Ok(point)
115}
116
117fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<blst_scalar, PrecompileError> {
119 let mut scalar = blst_scalar::default();
120
121 unsafe {
123 blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
124 }
125
126 if unsafe { !blst_scalar_fr_check(&scalar) } {
127 return Err(PrecompileError::Other(
128 "Non-canonical scalar field element".to_string(),
129 ));
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}