aurora_engine_precompiles/bls12_381/
pairing_check.rs

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