revm_precompile/bn254/
arkworks.rs1use super::{FQ2_LEN, FQ_LEN, G1_LEN, G2_LEN, SCALAR_LEN};
3use crate::PrecompileHalt;
4use std::vec::Vec;
5
6use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine};
7use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
8use ark_ff::{One, PrimeField, Zero};
9use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
10
11#[inline]
21fn read_fq(input_be: &[u8; FQ_LEN]) -> Result<Fq, PrecompileHalt> {
22 let mut input_le = [0u8; FQ_LEN];
23 input_le.copy_from_slice(input_be);
24
25 input_le.reverse();
27
28 Fq::deserialize_uncompressed(&input_le[..])
29 .map_err(|_| PrecompileHalt::Bn254FieldPointNotAMember)
30}
31#[inline]
42fn read_fq2(input: &[u8]) -> Result<Fq2, PrecompileHalt> {
43 let input: &[u8; FQ2_LEN] = input[..FQ2_LEN]
44 .try_into()
45 .expect("input must be at least FQ2_LEN bytes");
46 let (y, x) = input.split_at(FQ_LEN);
47 let y = read_fq(y.try_into().expect("split must yield FQ_LEN bytes"))?;
48 let x = read_fq(x.try_into().expect("split must yield FQ_LEN bytes"))?;
49
50 Ok(Fq2::new(x, y))
51}
52
53#[inline]
63fn new_g1_point(px: Fq, py: Fq) -> Result<G1Affine, PrecompileHalt> {
64 if px.is_zero() && py.is_zero() {
65 Ok(G1Affine::zero())
66 } else {
67 let point = G1Affine::new_unchecked(px, py);
69 if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() {
70 return Err(PrecompileHalt::Bn254AffineGFailedToCreate);
71 }
72 Ok(point)
73 }
74}
75
76#[inline]
88fn new_g2_point(x: Fq2, y: Fq2) -> Result<G2Affine, PrecompileHalt> {
89 let point = if x.is_zero() && y.is_zero() {
90 G2Affine::zero()
91 } else {
92 let point = G2Affine::new_unchecked(x, y);
94 if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() {
95 return Err(PrecompileHalt::Bn254AffineGFailedToCreate);
96 }
97 point
98 };
99
100 Ok(point)
101}
102
103#[inline]
112pub(super) fn read_g1_point(input: &[u8]) -> Result<G1Affine, PrecompileHalt> {
113 let input: &[u8; G1_LEN] = input[..G1_LEN]
114 .try_into()
115 .expect("input must be at least G1_LEN bytes");
116 let (px, py) = input.split_at(FQ_LEN);
117 let px = read_fq(px.try_into().expect("split must yield FQ_LEN bytes"))?;
118 let py = read_fq(py.try_into().expect("split must yield FQ_LEN bytes"))?;
119 new_g1_point(px, py)
120}
121
122#[inline]
130pub(super) fn encode_g1_point(point: G1Affine) -> [u8; G1_LEN] {
131 let mut output = [0u8; G1_LEN];
132 let Some((x, y)) = point.xy() else {
133 return output;
134 };
135
136 let mut x_bytes = [0u8; FQ_LEN];
137 x.serialize_uncompressed(&mut x_bytes[..])
138 .expect("Failed to serialize x coordinate");
139
140 let mut y_bytes = [0u8; FQ_LEN];
141 y.serialize_uncompressed(&mut y_bytes[..])
142 .expect("Failed to serialize x coordinate");
143
144 x_bytes.reverse();
146 y_bytes.reverse();
147
148 output[0..FQ_LEN].copy_from_slice(&x_bytes);
150 output[FQ_LEN..(FQ_LEN * 2)].copy_from_slice(&y_bytes);
151
152 output
153}
154
155#[inline]
164pub(super) fn read_g2_point(input: &[u8]) -> Result<G2Affine, PrecompileHalt> {
165 let input: &[u8; G2_LEN] = input[..G2_LEN]
166 .try_into()
167 .expect("input must be at least G2_LEN bytes");
168 let (ba, bb) = input.split_at(FQ2_LEN);
169 let ba = read_fq2(ba)?;
170 let bb = read_fq2(bb)?;
171 new_g2_point(ba, bb)
172}
173
174#[inline]
182pub(super) fn read_scalar(input: &[u8]) -> Fr {
183 let input: &[u8; SCALAR_LEN] = input.try_into().expect("input must be SCALAR_LEN bytes");
184 Fr::from_be_bytes_mod_order(input)
185}
186
187#[inline]
189pub(crate) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileHalt> {
190 let p1 = read_g1_point(p1_bytes)?;
191 let p2 = read_g1_point(p2_bytes)?;
192
193 let p1_jacobian: G1Projective = p1.into();
194
195 let p3 = p1_jacobian + p2;
196 let output = encode_g1_point(p3.into_affine());
197
198 Ok(output)
199}
200
201#[inline]
203pub(crate) fn g1_point_mul(
204 point_bytes: &[u8],
205 fr_bytes: &[u8],
206) -> Result<[u8; 64], PrecompileHalt> {
207 let p = read_g1_point(point_bytes)?;
208 let fr = read_scalar(fr_bytes);
209
210 let big_int = fr.into_bigint();
211 let result = p.mul_bigint(big_int);
212
213 let output = encode_g1_point(result.into_affine());
214
215 Ok(output)
216}
217
218#[inline]
224pub(crate) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileHalt> {
225 let mut g1_points = Vec::with_capacity(pairs.len());
226 let mut g2_points = Vec::with_capacity(pairs.len());
227
228 for (g1_bytes, g2_bytes) in pairs {
229 let g1 = read_g1_point(g1_bytes)?;
230 let g2 = read_g2_point(g2_bytes)?;
231
232 if !g1.is_zero() && !g2.is_zero() {
234 g1_points.push(g1);
235 g2_points.push(g2);
236 }
237 }
238
239 if g1_points.is_empty() {
240 return Ok(true);
241 }
242
243 let pairing_result = Bn254::multi_pairing(&g1_points, &g2_points);
244 Ok(pairing_result.0.is_one())
245}