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}