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};
14
15#[inline]
20pub fn verify_kzg_proof(
21 commitment: &[u8; 48],
22 z: &[u8; 32],
23 y: &[u8; 32],
24 proof: &[u8; 48],
25) -> bool {
26 let Ok(commitment_point) = parse_g1_compressed(commitment) else {
28 return false;
29 };
30
31 let Ok(proof_point) = parse_g1_compressed(proof) else {
33 return false;
34 };
35
36 let Ok(z_scalar) = read_scalar_canonical(z) else {
38 return false;
39 };
40 let Ok(y_scalar) = read_scalar_canonical(y) else {
41 return false;
42 };
43
44 let tau_g2 = get_trusted_setup_g2();
46
47 let g1 = get_g1_generator();
49 let g2 = get_g2_generator();
50
51 let y_g1 = p1_scalar_mul(&g1, &y_scalar);
53 let p_minus_y = p1_sub_affine(&commitment_point, &y_g1);
54
55 let z_g2 = p2_scalar_mul(&g2, &z_scalar);
57 let x_minus_z = p2_sub_affine(&tau_g2, &z_g2);
58
59 let neg_g2 = p2_neg(&g2);
62
63 pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)])
64}
65
66fn get_trusted_setup_g2() -> blst_p2_affine {
69 let mut g2_affine = blst_p2_affine::default();
71 unsafe {
72 let result = blst::blst_p2_uncompress(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr());
75 if result != blst::BLST_ERROR::BLST_SUCCESS {
76 panic!("Failed to deserialize trusted setup G2 point");
77 }
78 }
79 g2_affine
80}
81
82fn get_g1_generator() -> blst_p1_affine {
84 unsafe { ::blst::BLS12_381_G1 }
85}
86
87fn get_g2_generator() -> blst_p2_affine {
89 unsafe { ::blst::BLS12_381_G2 }
90}
91
92fn parse_g1_compressed(bytes: &[u8; 48]) -> Result<blst_p1_affine, PrecompileError> {
94 let mut point = blst_p1_affine::default();
95 unsafe {
96 let result = blst::blst_p1_uncompress(&mut point, bytes.as_ptr());
97 if result != blst::BLST_ERROR::BLST_SUCCESS {
98 return Err(PrecompileError::KzgInvalidG1Point);
99 }
100
101 if !blst_p1_affine_on_curve(&point) {
103 return Err(PrecompileError::KzgG1PointNotOnCurve);
104 }
105
106 if !blst_p1_affine_in_g1(&point) {
108 return Err(PrecompileError::KzgG1PointNotInSubgroup);
109 }
110 }
111 Ok(point)
112}
113
114fn read_scalar_canonical(bytes: &[u8; 32]) -> Result<blst_scalar, PrecompileError> {
116 let mut scalar = blst_scalar::default();
117
118 unsafe {
120 blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
121 }
122
123 if unsafe { !blst_scalar_fr_check(&scalar) } {
124 return Err(PrecompileError::NonCanonicalFp);
125 }
126
127 Ok(scalar)
128}
129
130fn p1_sub_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine {
132 let a_jacobian = p1_from_affine(a);
134
135 let neg_b = p1_neg(b);
137
138 let result = p1_add_or_double(&a_jacobian, &neg_b);
140
141 p1_to_affine(&result)
142}
143
144fn p2_sub_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine {
146 let a_jacobian = p2_from_affine(a);
148
149 let neg_b = p2_neg(b);
151
152 let result = p2_add_or_double(&a_jacobian, &neg_b);
154
155 p2_to_affine(&result)
156}
157
158fn p1_neg(p: &blst_p1_affine) -> blst_p1_affine {
160 let mut p_jacobian = p1_from_affine(p);
162 unsafe {
163 ::blst::blst_p1_cneg(&mut p_jacobian, true);
164 }
165 p1_to_affine(&p_jacobian)
166}
167
168fn p2_neg(p: &blst_p2_affine) -> blst_p2_affine {
170 let mut p_jacobian = p2_from_affine(p);
172 unsafe {
173 ::blst::blst_p2_cneg(&mut p_jacobian, true);
174 }
175 p2_to_affine(&p_jacobian)
176}