revm_precompile/bls12_381/
map_fp2_to_g2.rs

1use super::{
2    crypto_backend::{encode_g2_point, map_fp2_to_g2 as blst_map_fp2_to_g2, read_fp2},
3    utils::remove_fp_padding,
4};
5use crate::bls12_381_const::{
6    MAP_FP2_TO_G2_ADDRESS, MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH, PADDED_FP_LENGTH,
7};
8use crate::PrecompileWithAddress;
9use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
10use primitives::Bytes;
11
12/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile.
13pub const PRECOMPILE: PrecompileWithAddress =
14    PrecompileWithAddress(MAP_FP2_TO_G2_ADDRESS, map_fp2_to_g2);
15
16/// Field-to-curve call expects 128 bytes as an input that is interpreted as
17/// an element of Fp2. Output of this call is 256 bytes and is an encoded G2
18/// point.
19/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-mapping-fp2-element-to-g2-point>
20pub(super) fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult {
21    if MAP_FP2_TO_G2_BASE_GAS_FEE > gas_limit {
22        return Err(PrecompileError::OutOfGas);
23    }
24
25    if input.len() != PADDED_FP2_LENGTH {
26        return Err(PrecompileError::Other(format!(
27            "MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}",
28            input.len()
29        )));
30    }
31
32    let input_p0_x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?;
33    let input_p0_y = remove_fp_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?;
34    let fp2 = read_fp2(input_p0_x, input_p0_y)?;
35    let p_aff = blst_map_fp2_to_g2(&fp2);
36
37    let out = encode_g2_point(&p_aff);
38    Ok(PrecompileOutput::new(
39        MAP_FP2_TO_G2_BASE_GAS_FEE,
40        out.into(),
41    ))
42}