aurora_engine_precompiles/bls12_381/
map_fp2_to_g2.rs

1use aurora_engine_sdk::bls12_381::{self, PADDED_FP2_LENGTH};
2use aurora_evm::{Context, ExitError};
3
4use crate::prelude::types::{Address, EthGas, make_address};
5use crate::prelude::{Borrowed, Vec};
6use crate::{EvmPrecompileResult, Precompile, PrecompileOutput};
7
8/// Base gas fee for BLS12-381 `map_fp2_to_g2` operation.
9const BASE_GAS_FEE: u64 = 23800;
10
11/// BLS12-381 Map FP2 to G2
12pub struct BlsMapFp2ToG2;
13
14impl BlsMapFp2ToG2 {
15    pub const ADDRESS: Address = make_address(0, 0x11);
16
17    fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
18        bls12_381::map_fp2_to_g2(input).map_err(|e| ExitError::Other(Borrowed(e.as_ref())))
19    }
20}
21
22impl Precompile for BlsMapFp2ToG2 {
23    fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError>
24    where
25        Self: Sized,
26    {
27        Ok(EthGas::new(BASE_GAS_FEE))
28    }
29
30    /// Field-to-curve call expects 128 bytes as an input that is interpreted as
31    /// an element of Fp2. Output of this call is 256 bytes and is an encoded G2
32    /// point.
33    /// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-mapping-fp2-element-to-g2-point>
34    fn run(
35        &self,
36        input: &[u8],
37        target_gas: Option<EthGas>,
38        _context: &Context,
39        _is_static: bool,
40    ) -> EvmPrecompileResult {
41        let cost = Self::required_gas(input)?;
42        if let Some(target_gas) = target_gas {
43            if cost > target_gas {
44                return Err(ExitError::OutOfGas);
45            }
46        }
47
48        if input.len() != PADDED_FP2_LENGTH {
49            return Err(ExitError::Other(Borrowed("ERR_BLS_MAP_FP2_TO_G2_LEN")));
50        }
51
52        let output = Self::execute(input)?;
53        Ok(PrecompileOutput::without_logs(cost, output))
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use aurora_engine_types::H160;
61
62    #[test]
63    fn bls12_381_fp2_to_g2() {
64        let precompile = BlsMapFp2ToG2;
65        let ctx = Context {
66            address: H160::zero(),
67            caller: H160::zero(),
68            apparent_value: 0.into(),
69        };
70        let input = hex::decode("\
71               000000000000000000000000000000000f470603a402bc134db1b389fd187460f9eb2dd001a2e99f730af386508c62f0e911d831a2562da84bce11d39f2ff13f\
72			   000000000000000000000000000000000d8c45f4ab20642d0cba9764126e0818b7d731a6ba29ed234d9d6309a5e8ddfbd85193f1fa8b7cfeed3d31b23b904ee9")
73            .expect("hex decoding failed");
74
75        let res = precompile
76            .run(&input, None, &ctx, false)
77            .expect("precompile run should not fail");
78        let expected = hex::decode("\
79               0000000000000000000000000000000012e74d5a0c005a86ca148e9eff8e34a00bfa8b6e6aadf633d65cd09bb29917e0ceb0d5c9d9650c162d7fe4aa27452685\
80			   0000000000000000000000000000000005f09101a2088712619f9c096403b66855a12f9016c55aef6047372fba933f02d9d59db1a86df7be57978021e2457821\
81			   00000000000000000000000000000000136975b37fe400d1d217a2b496c1552b39be4e9e71dd7ad482f5f0836d271d02959fdb698dda3d0530587fb86e0db1dd\
82			   0000000000000000000000000000000000bad0aabd9309e92e2dd752f4dd73be07c0de2c5ddd57916b9ffa065d7440d03d44e7c042075cda694414a9fb639bb7")
83            .expect("hex decoding failed");
84
85        assert_eq!(res.output, expected);
86    }
87}