aurora_engine_precompiles/bls12_381/
pairing_check.rs

1use aurora_engine_sdk::bls12_381::{self, PAIRING_INPUT_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, utils};
7
8/// Multiplier gas fee for BLS12-381 pairing operation.
9const PAIRING_MULTIPLIER_BASE: u64 = 32600;
10/// Offset gas fee for BLS12-381 pairing operation.
11const PAIRING_OFFSET_BASE: u64 = 37700;
12
13/// BLS12-381 Pairing check
14pub struct BlsPairingCheck;
15
16impl BlsPairingCheck {
17    pub const ADDRESS: Address = make_address(0, 0xF);
18
19    fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
20        bls12_381::pairing_check(input).map_err(|e| ExitError::Other(Borrowed(e.as_ref())))
21    }
22}
23
24impl Precompile for BlsPairingCheck {
25    fn required_gas(input: &[u8]) -> Result<EthGas, ExitError>
26    where
27        Self: Sized,
28    {
29        let k = u64::try_from(input.len() / PAIRING_INPUT_LENGTH).map_err(utils::err_usize_conv)?;
30        Ok(EthGas::new(
31            PAIRING_MULTIPLIER_BASE * k + PAIRING_OFFSET_BASE,
32        ))
33    }
34
35    /// Pairing call expects 384*k (k being a positive integer) bytes as an inputs
36    /// that is interpreted as byte concatenation of k slices. Each slice has the
37    /// following structure:
38    ///    * 128 bytes of G1 point encoding
39    ///    * 256 bytes of G2 point encoding
40    ///
41    /// Each point is expected to be in the subgroup of order q.
42    /// Output is 32 bytes where first 31 bytes are equal to 0x00 and the last byte
43    /// is 0x01 if pairing result is equal to the multiplicative identity in a pairing
44    /// target field and 0x00 otherwise.
45    ///
46    /// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-pairing>
47    fn run(
48        &self,
49        input: &[u8],
50        target_gas: Option<EthGas>,
51        _context: &Context,
52        _is_static: bool,
53    ) -> EvmPrecompileResult {
54        let input_len = input.len();
55        if input_len == 0 || input_len % PAIRING_INPUT_LENGTH != 0 {
56            return Err(ExitError::Other(Borrowed("ERR_BLS_PAIRING_INVALID_LENGTH")));
57        }
58
59        let cost = Self::required_gas(input)?;
60        if let Some(target_gas) = target_gas {
61            if cost > target_gas {
62                return Err(ExitError::OutOfGas);
63            }
64        }
65
66        let output = Self::execute(input)?;
67        Ok(PrecompileOutput::without_logs(cost, output))
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use aurora_engine_types::H160;
75
76    #[test]
77    fn bls12_381_pairing() {
78        let precompile = BlsPairingCheck;
79        let ctx = Context {
80            address: H160::zero(),
81            caller: H160::zero(),
82            apparent_value: 0.into(),
83        };
84        let input = hex::decode("\
85			   000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80\
86			   000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d5\
87			   00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e\
88			   000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834\
89			   000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e\
90			   0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e\
91			   000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80\
92			   00000000000000000000000000000000118cd94e36ab177de95f52f180fdbdc584b8d30436eb882980306fa0625f07a1f7ad3b4c38a921c53d14aa9a6ba5b8d6\
93			   00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e\
94			   000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834\
95			   000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e\
96			   0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e")
97            .expect("hex decoding failed");
98
99        let res = precompile
100            .run(&input, None, &ctx, false)
101            .expect("precompile run should not fail");
102        let expected =
103            hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
104                .expect("hex decoding failed");
105
106        assert_eq!(res.output, expected);
107    }
108}