revm_precompile/bn254/
arkworks.rs1use super::{FQ2_LEN, FQ_LEN, G1_LEN, SCALAR_LEN};
3use crate::PrecompileError;
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]) -> Result<Fq, PrecompileError> {
22 assert_eq!(input_be.len(), FQ_LEN, "input must be {FQ_LEN} bytes");
23
24 let mut input_le = [0u8; FQ_LEN];
25 input_le.copy_from_slice(input_be);
26
27 input_le.reverse();
29
30 Fq::deserialize_uncompressed(&input_le[..])
31 .map_err(|_| PrecompileError::Bn254FieldPointNotAMember)
32}
33#[inline]
44fn read_fq2(input: &[u8]) -> Result<Fq2, PrecompileError> {
45 let y = read_fq(&input[..FQ_LEN])?;
46 let x = read_fq(&input[FQ_LEN..2 * FQ_LEN])?;
47
48 Ok(Fq2::new(x, y))
49}
50
51#[inline]
61fn new_g1_point(px: Fq, py: Fq) -> Result<G1Affine, PrecompileError> {
62 if px.is_zero() && py.is_zero() {
63 Ok(G1Affine::zero())
64 } else {
65 let point = G1Affine::new_unchecked(px, py);
67 if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() {
68 return Err(PrecompileError::Bn254AffineGFailedToCreate);
69 }
70 Ok(point)
71 }
72}
73
74#[inline]
86fn new_g2_point(x: Fq2, y: Fq2) -> Result<G2Affine, PrecompileError> {
87 let point = if x.is_zero() && y.is_zero() {
88 G2Affine::zero()
89 } else {
90 let point = G2Affine::new_unchecked(x, y);
92 if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() {
93 return Err(PrecompileError::Bn254AffineGFailedToCreate);
94 }
95 point
96 };
97
98 Ok(point)
99}
100
101#[inline]
110pub(super) fn read_g1_point(input: &[u8]) -> Result<G1Affine, PrecompileError> {
111 let px = read_fq(&input[0..FQ_LEN])?;
112 let py = read_fq(&input[FQ_LEN..2 * FQ_LEN])?;
113 new_g1_point(px, py)
114}
115
116#[inline]
124pub(super) fn encode_g1_point(point: G1Affine) -> [u8; G1_LEN] {
125 let mut output = [0u8; G1_LEN];
126 let Some((x, y)) = point.xy() else {
127 return output;
128 };
129
130 let mut x_bytes = [0u8; FQ_LEN];
131 x.serialize_uncompressed(&mut x_bytes[..])
132 .expect("Failed to serialize x coordinate");
133
134 let mut y_bytes = [0u8; FQ_LEN];
135 y.serialize_uncompressed(&mut y_bytes[..])
136 .expect("Failed to serialize x coordinate");
137
138 x_bytes.reverse();
140 y_bytes.reverse();
141
142 output[0..FQ_LEN].copy_from_slice(&x_bytes);
144 output[FQ_LEN..(FQ_LEN * 2)].copy_from_slice(&y_bytes);
145
146 output
147}
148
149#[inline]
158pub(super) fn read_g2_point(input: &[u8]) -> Result<G2Affine, PrecompileError> {
159 let ba = read_fq2(&input[0..FQ2_LEN])?;
160 let bb = read_fq2(&input[FQ2_LEN..2 * FQ2_LEN])?;
161 new_g2_point(ba, bb)
162}
163
164#[inline]
172pub(super) fn read_scalar(input: &[u8]) -> Fr {
173 assert_eq!(
174 input.len(),
175 SCALAR_LEN,
176 "unexpected scalar length. got {}, expected {SCALAR_LEN}",
177 input.len()
178 );
179 Fr::from_be_bytes_mod_order(input)
180}
181
182#[inline]
184pub(crate) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> {
185 let p1 = read_g1_point(p1_bytes)?;
186 let p2 = read_g1_point(p2_bytes)?;
187
188 let p1_jacobian: G1Projective = p1.into();
189
190 let p3 = p1_jacobian + p2;
191 let output = encode_g1_point(p3.into_affine());
192
193 Ok(output)
194}
195
196#[inline]
198pub(crate) fn g1_point_mul(
199 point_bytes: &[u8],
200 fr_bytes: &[u8],
201) -> Result<[u8; 64], PrecompileError> {
202 let p = read_g1_point(point_bytes)?;
203 let fr = read_scalar(fr_bytes);
204
205 let big_int = fr.into_bigint();
206 let result = p.mul_bigint(big_int);
207
208 let output = encode_g1_point(result.into_affine());
209
210 Ok(output)
211}
212
213#[inline]
219pub(crate) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileError> {
220 let mut g1_points = Vec::with_capacity(pairs.len());
221 let mut g2_points = Vec::with_capacity(pairs.len());
222
223 for (g1_bytes, g2_bytes) in pairs {
224 let g1 = read_g1_point(g1_bytes)?;
225 let g2 = read_g2_point(g2_bytes)?;
226
227 if !g1.is_zero() && !g2.is_zero() {
229 g1_points.push(g1);
230 g2_points.push(g2);
231 }
232 }
233
234 if g1_points.is_empty() {
235 return Ok(true);
236 }
237
238 let pairing_result = Bn254::multi_pairing(&g1_points, &g2_points);
239 Ok(pairing_result.0.is_one())
240}