revm_precompile/bls12_381/
map_fp_to_g1.rs
1use super::{
2 g1::encode_g1_point,
3 utils::{fp_from_bendian, remove_padding, PADDED_FP_LENGTH},
4};
5use crate::{u64_to_address, PrecompileWithAddress};
6use blst::{blst_map_to_g1, blst_p1, blst_p1_affine, blst_p1_to_affine};
7use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileOutput, PrecompileResult};
8
9pub const PRECOMPILE: PrecompileWithAddress =
11 PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(map_fp_to_g1));
12
13pub const ADDRESS: u64 = 0x12;
15
16const MAP_FP_TO_G1_BASE: u64 = 5500;
18
19pub(super) fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult {
23 if MAP_FP_TO_G1_BASE > gas_limit {
24 return Err(PrecompileError::OutOfGas.into());
25 }
26
27 if input.len() != PADDED_FP_LENGTH {
28 return Err(PrecompileError::Other(format!(
29 "MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}",
30 input.len()
31 ))
32 .into());
33 }
34
35 let input_p0 = remove_padding(input)?;
36 let fp = fp_from_bendian(input_p0)?;
37
38 let mut p = blst_p1::default();
39 unsafe { blst_map_to_g1(&mut p, &fp, core::ptr::null()) };
42
43 let mut p_aff = blst_p1_affine::default();
44 unsafe { blst_p1_to_affine(&mut p_aff, &p) };
46
47 let out = encode_g1_point(&p_aff);
48 Ok(PrecompileOutput::new(MAP_FP_TO_G1_BASE, out))
49}
50
51#[cfg(test)]
52mod test {
53 use super::*;
54 use crate::primitives::hex;
55
56 #[test]
57 fn sanity_test() {
58 let input = Bytes::from(hex!("000000000000000000000000000000006900000000000000636f6e7472616374595a603f343061cd305a03f40239f5ffff31818185c136bc2595f2aa18e08f17"));
59 let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE);
60 assert_eq!(
61 fail,
62 Err(PrecompileError::Other("non-canonical fp value".to_string()).into())
63 );
64 }
65}