Skip to main content

revm_precompile/bls12_381/
map_fp2_to_g2.rs

1//! BLS12-381 map fp2 to g2 precompile. More details in [`map_fp2_to_g2`]
2use super::utils::{pad_g2_point, remove_fp_padding};
3use crate::{
4    bls12_381_const::{
5        MAP_FP2_TO_G2_ADDRESS, MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH, PADDED_FP_LENGTH,
6    },
7    crypto, eth_precompile_fn, EthPrecompileOutput, EthPrecompileResult, Precompile,
8    PrecompileHalt, PrecompileId,
9};
10
11eth_precompile_fn!(map_fp2_to_g2_precompile, map_fp2_to_g2);
12
13/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile.
14pub const PRECOMPILE: Precompile = Precompile::new(
15    PrecompileId::Bls12MapFp2ToGp2,
16    MAP_FP2_TO_G2_ADDRESS,
17    map_fp2_to_g2_precompile,
18);
19
20/// Field-to-curve call expects 128 bytes as an input that is interpreted as
21/// an element of Fp2. Output of this call is 256 bytes and is an encoded G2
22/// point.
23/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-mapping-fp2-element-to-g2-point>
24pub fn map_fp2_to_g2(input: &[u8], gas_limit: u64) -> EthPrecompileResult {
25    if MAP_FP2_TO_G2_BASE_GAS_FEE > gas_limit {
26        return Err(PrecompileHalt::OutOfGas);
27    }
28
29    if input.len() != PADDED_FP2_LENGTH {
30        return Err(PrecompileHalt::Bls12381MapFp2ToG2InputLength);
31    }
32
33    let input_p0_x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?;
34    let input_p0_y = remove_fp_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?;
35
36    let unpadded_result = crypto().bls12_381_fp2_to_g2((*input_p0_x, *input_p0_y))?;
37
38    // Pad the result for EVM compatibility
39    let padded_result = pad_g2_point(&unpadded_result);
40
41    Ok(EthPrecompileOutput::new(
42        MAP_FP2_TO_G2_BASE_GAS_FEE,
43        padded_result.into(),
44    ))
45}