aurora_engine_precompiles/bls12_381/
map_fp_to_g1.rs

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