pallet_evm_precompile_blake2/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(unused_crate_dependencies)]
20
21mod eip_152;
22
23use fp_evm::{
24 ExitError, ExitSucceed, Precompile, PrecompileFailure, PrecompileHandle, 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(handle: &mut impl PrecompileHandle) -> PrecompileResult {
38 const BLAKE2_F_ARG_LEN: usize = 213;
39
40 let input = handle.input();
41
42 if input.len() != BLAKE2_F_ARG_LEN {
43 return Err(PrecompileFailure::Error {
44 exit_status: ExitError::Other(
45 "input length for Blake2 F precompile should be exactly 213 bytes".into(),
46 ),
47 });
48 }
49
50 let mut rounds_buf: [u8; 4] = [0; 4];
51 rounds_buf.copy_from_slice(&input[0..4]);
52 let rounds: u32 = u32::from_be_bytes(rounds_buf);
53
54 let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND;
55 handle.record_cost(gas_cost)?;
56
57 let input = handle.input();
58
59 let mut h_buf: [u8; 64] = [0; 64];
62 h_buf.copy_from_slice(&input[4..68]);
63 let mut h = [0u64; 8];
64 let mut ctr = 0;
65 for state_word in &mut h {
66 let mut temp: [u8; 8] = Default::default();
67 temp.copy_from_slice(&h_buf[(ctr * 8)..(ctr + 1) * 8]);
68 *state_word = u64::from_le_bytes(temp);
69 ctr += 1;
70 }
71
72 let mut m_buf: [u8; 128] = [0; 128];
73 m_buf.copy_from_slice(&input[68..196]);
74 let mut m = [0u64; 16];
75 ctr = 0;
76 for msg_word in &mut m {
77 let mut temp: [u8; 8] = Default::default();
78 temp.copy_from_slice(&m_buf[(ctr * 8)..(ctr + 1) * 8]);
79 *msg_word = u64::from_le_bytes(temp);
80 ctr += 1;
81 }
82
83 let mut t_0_buf: [u8; 8] = [0; 8];
84 t_0_buf.copy_from_slice(&input[196..204]);
85 let t_0 = u64::from_le_bytes(t_0_buf);
86
87 let mut t_1_buf: [u8; 8] = [0; 8];
88 t_1_buf.copy_from_slice(&input[204..212]);
89 let t_1 = u64::from_le_bytes(t_1_buf);
90
91 let f = if input[212] == 1 {
92 true
93 } else if input[212] == 0 {
94 false
95 } else {
96 return Err(PrecompileFailure::Error {
97 exit_status: ExitError::Other("incorrect final block indicator flag".into()),
98 });
99 };
100
101 crate::eip_152::compress(&mut h, m, [t_0, t_1], f, rounds as usize);
102
103 let mut output_buf = [0u8; u64::BITS as usize];
104 for (i, state_word) in h.iter().enumerate() {
105 output_buf[i * 8..(i + 1) * 8].copy_from_slice(&state_word.to_le_bytes());
106 }
107
108 Ok(PrecompileOutput {
109 exit_status: ExitSucceed::Returned,
110 output: output_buf.to_vec(),
111 })
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use pallet_evm_test_vector_support::test_precompile_test_vectors;
119
120 #[test]
121 fn process_consensus_tests() -> Result<(), String> {
122 test_precompile_test_vectors::<Blake2F>("../testdata/blake2F.json")?;
123 Ok(())
124 }
125}