ovr_evm_precompile_blake2/
lib.rs1extern crate alloc;
19
20mod eip_152;
21
22use core::mem::size_of;
23use fp_evm::{
24 Context, ExitError, ExitSucceed, Precompile, PrecompileFailure, PrecompileOutput,
25 PrecompileResult,
26};
27
28pub struct Blake2F;
29
30impl Blake2F {
31 const GAS_COST_PER_ROUND: u64 = 1; }
33
34impl Precompile for Blake2F {
35 fn execute(
38 input: &[u8],
39 target_gas: Option<u64>,
40 _context: &Context,
41 _is_static: bool,
42 ) -> PrecompileResult {
43 const BLAKE2_F_ARG_LEN: usize = 213;
44
45 if input.len() != BLAKE2_F_ARG_LEN {
46 return Err(PrecompileFailure::Error {
47 exit_status: ExitError::Other(
48 "input length for Blake2 F precompile should be exactly 213 bytes".into(),
49 ),
50 });
51 }
52
53 let mut rounds_buf: [u8; 4] = [0; 4];
54 rounds_buf.copy_from_slice(&input[0..4]);
55 let rounds: u32 = u32::from_be_bytes(rounds_buf);
56
57 let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND;
58 if let Some(gas_left) = target_gas {
59 if gas_left < gas_cost {
60 return Err(PrecompileFailure::Error {
61 exit_status: ExitError::OutOfGas,
62 });
63 }
64 }
65
66 let mut h_buf: [u8; 64] = [0; 64];
69 h_buf.copy_from_slice(&input[4..68]);
70 let mut h = [0u64; 8];
71 let mut ctr = 0;
72 for state_word in &mut h {
73 let mut temp: [u8; 8] = Default::default();
74 temp.copy_from_slice(&h_buf[(ctr * 8)..(ctr + 1) * 8]);
75 *state_word = u64::from_le_bytes(temp).into();
76 ctr += 1;
77 }
78
79 let mut m_buf: [u8; 128] = [0; 128];
80 m_buf.copy_from_slice(&input[68..196]);
81 let mut m = [0u64; 16];
82 ctr = 0;
83 for msg_word in &mut m {
84 let mut temp: [u8; 8] = Default::default();
85 temp.copy_from_slice(&m_buf[(ctr * 8)..(ctr + 1) * 8]);
86 *msg_word = u64::from_le_bytes(temp).into();
87 ctr += 1;
88 }
89
90 let mut t_0_buf: [u8; 8] = [0; 8];
91 t_0_buf.copy_from_slice(&input[196..204]);
92 let t_0 = u64::from_le_bytes(t_0_buf);
93
94 let mut t_1_buf: [u8; 8] = [0; 8];
95 t_1_buf.copy_from_slice(&input[204..212]);
96 let t_1 = u64::from_le_bytes(t_1_buf);
97
98 let f = if input[212] == 1 {
99 true
100 } else if input[212] == 0 {
101 false
102 } else {
103 return Err(PrecompileFailure::Error {
104 exit_status: ExitError::Other("incorrect final block indicator flag".into()),
105 });
106 };
107
108 crate::eip_152::compress(&mut h, m, [t_0.into(), t_1.into()], f, rounds as usize);
109
110 let mut output_buf = [0u8; 8 * size_of::<u64>()];
111 for (i, state_word) in h.iter().enumerate() {
112 output_buf[i * 8..(i + 1) * 8].copy_from_slice(&state_word.to_le_bytes());
113 }
114
115 Ok(PrecompileOutput {
116 exit_status: ExitSucceed::Returned,
117 cost: gas_cost,
118 output: output_buf.to_vec(),
119 logs: Default::default(),
120 })
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use pallet_evm_test_vector_support::test_precompile_test_vectors;
128
129 #[test]
130 fn process_consensus_tests() -> Result<(), String> {
131 test_precompile_test_vectors::<Blake2F>("../testdata/blake2F.json")?;
132 Ok(())
133 }
134}