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};
12
13#[inline]
18pub fn verify_kzg_proof(
19 commitment: &[u8; 48],
20 z: &[u8; 32],
21 y: &[u8; 32],
22 proof: &[u8; 48],
23) -> bool {
24 let Ok(commitment_point) = parse_g1_compressed(commitment) else {
26 return false;
27 };
28
29 let Ok(proof_point) = parse_g1_compressed(proof) else {
31 return false;
32 };
33
34 let Ok(z_scalar) = read_scalar_canonical(z) else {
36 return false;
37 };
38 let Ok(y_scalar) = 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_scalar);
51 let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
52
53 let z_g2 = p2_scalar_mul(&g2, &z_scalar);
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() -> blst_p2_affine {
67 let mut g2_affine = blst_p2_affine::default();
69 unsafe {
70 let result = blst::blst_p2_deserialize(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr());
73 if result != blst::BLST_ERROR::BLST_SUCCESS {
74 panic!("Failed to deserialize trusted setup G2 point");
75 }
76 }
77 g2_affine
78}
79
80fn get_g1_generator() -> blst_p1_affine {
82 unsafe { ::blst::BLS12_381_G1 }
83}
84
85fn get_g2_generator() -> blst_p2_affine {
87 unsafe { ::blst::BLS12_381_G2 }
88}
89
90fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<blst_p1_affine, PrecompileError> {
92 let mut point = blst_p1_affine::default();
93 unsafe {
94 let result = blst::blst_p1_deserialize(&mut point, bytes.as_ptr());
95 if result != blst::BLST_ERROR::BLST_SUCCESS {
96 return Err(PrecompileError::KzgInvalidG1Point);
97 }
98
99 if !blst_p1_affine_on_curve(&point) {
101 return Err(PrecompileError::KzgG1PointNotOnCurve);
102 }
103
104 if !blst_p1_affine_in_g1(&point) {
106 return Err(PrecompileError::KzgG1PointNotInSubgroup);
107 }
108 }
109 Ok(point)
110}
111
112fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<blst_scalar, PrecompileError> {
114 let mut scalar = blst_scalar::default();
115
116 unsafe {
118 blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
119 }
120
121 if unsafe { !blst_scalar_fr_check(&scalar) } {
122 return Err(PrecompileError::NonCanonicalFp);
123 }
124
125 Ok(scalar)
126}
127
128fn p1_sub_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine {
130 let a_jacobian = p1_from_affine(a);
132
133 let neg_b = p1_neg(b);
135
136 let result = p1_add_or_double(&a_jacobian, &neg_b);
138
139 p1_to_affine(&result)
140}
141
142fn p2_sub_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine {
144 let a_jacobian = p2_from_affine(a);
146
147 let neg_b = p2_neg(b);
149
150 let result = p2_add_or_double(&a_jacobian, &neg_b);
152
153 p2_to_affine(&result)
154}
155
156fn p1_neg(p: &blst_p1_affine) -> blst_p1_affine {
158 let mut p_jacobian = p1_from_affine(p);
160 unsafe {
161 ::blst::blst_p1_cneg(&mut p_jacobian, true);
162 }
163 p1_to_affine(&p_jacobian)
164}
165
166fn p2_neg(p: &blst_p2_affine) -> blst_p2_affine {
168 let mut p_jacobian = p2_from_affine(p);
170 unsafe {
171 ::blst::blst_p2_cneg(&mut p_jacobian, true);
172 }
173 p2_to_affine(&p_jacobian)
174}