1use aurora_evm::{Context, ExitError};
2
3use crate::prelude::types::EthGas;
4use crate::prelude::{
5 types::{make_address, Address},
6 Borrowed,
7};
8use crate::{EvmPrecompileResult, Precompile, PrecompileOutput};
9use aurora_engine_types::Vec;
10
11mod costs {
13 use crate::prelude::types::EthGas;
14
15 pub(super) const F_ROUND: EthGas = EthGas::new(1);
17}
18
19mod consts {
21 pub(super) const INPUT_LENGTH: usize = 213;
22
23 pub(super) const SIGMA: [[usize; 16]; 10] = [
27 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
28 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
29 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
30 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
31 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
32 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
33 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
34 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
35 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
36 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
37 ];
38
39 pub(super) const IV: [u64; 8] = [
43 0x6a09e667f3bcc908,
44 0xbb67ae8584caa73b,
45 0x3c6ef372fe94f82b,
46 0xa54ff53a5f1d36f1,
47 0x510e527fade682d1,
48 0x9b05688c2b3e6c1f,
49 0x1f83d9abfb41bd6b,
50 0x5be0cd19137e2179,
51 ];
52
53 pub(super) const R1: u32 = 32;
57
58 pub(super) const R2: u32 = 24;
60
61 pub(super) const R3: u32 = 16;
63
64 pub(super) const R4: u32 = 63;
66}
67
68#[allow(clippy::many_single_char_names)]
74fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
75 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
76 v[d] = (v[d] ^ v[a]).rotate_right(consts::R1);
77 v[c] = v[c].wrapping_add(v[d]);
78 v[b] = (v[b] ^ v[c]).rotate_right(consts::R2);
79 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
80 v[d] = (v[d] ^ v[a]).rotate_right(consts::R3);
81 v[c] = v[c].wrapping_add(v[d]);
82 v[b] = (v[b] ^ v[c]).rotate_right(consts::R4);
83}
84
85#[allow(clippy::many_single_char_names)]
94fn f(mut h: [u64; 8], m: [u64; 16], t: [u64; 2], f: bool, rounds: u32) -> Vec<u8> {
95 let mut v = [0u64; 16];
97 v[0..8].copy_from_slice(&h); v[8..16].copy_from_slice(&consts::IV); v[12] ^= t[0]; v[13] ^= t[1]; if f {
104 v[14] = !v[14]; }
107
108 for i in 0..rounds {
109 let s = &consts::SIGMA[usize::try_from(i).expect("Round can convert to usize") % 10];
112 g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]);
113 g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]);
114 g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]);
115 g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]);
116
117 g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]);
118 g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
119 g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
120 g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
121 }
122
123 for i in 0..8 {
124 h[i] ^= v[i] ^ v[i + 8];
126 }
127
128 let mut result = Vec::with_capacity(64);
129 for value in h {
130 result.extend_from_slice(&value.to_le_bytes());
131 }
132
133 result
134}
135
136pub struct Blake2F;
137
138impl Blake2F {
139 pub const ADDRESS: Address = make_address(0, 9);
140}
141
142impl Precompile for Blake2F {
143 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
144 let (int_bytes, _) = input.split_at(size_of::<u32>());
145 let num_rounds = u32::from_be_bytes(
146 int_bytes.try_into().unwrap(),
148 );
149 Ok(num_rounds * costs::F_ROUND)
150 }
151
152 fn run(
163 &self,
164 input: &[u8],
165 target_gas: Option<EthGas>,
166 _context: &Context,
167 _is_static: bool,
168 ) -> EvmPrecompileResult {
169 if input.len() != consts::INPUT_LENGTH {
170 return Err(ExitError::Other(Borrowed("ERR_BLAKE2F_INVALID_LEN")));
171 }
172
173 let cost = Self::required_gas(input)?;
174 if let Some(target_gas) = target_gas {
175 if cost > target_gas {
176 return Err(ExitError::OutOfGas);
177 }
178 }
179
180 let mut rounds_bytes = [0u8; 4];
181 rounds_bytes.copy_from_slice(&input[0..4]);
182 let rounds = u32::from_be_bytes(rounds_bytes);
183
184 let mut h = [0u64; 8];
185 for (mut x, value) in h.iter_mut().enumerate() {
186 let mut word: [u8; 8] = [0u8; 8];
187 x = x * 8 + 4;
188 word.copy_from_slice(&input[x..(x + 8)]);
189 *value = u64::from_le_bytes(word);
190 }
191
192 let mut m = [0u64; 16];
193 for (mut x, value) in m.iter_mut().enumerate() {
194 let mut word: [u8; 8] = [0u8; 8];
195 x = x * 8 + 68;
196 word.copy_from_slice(&input[x..(x + 8)]);
197 *value = u64::from_le_bytes(word);
198 }
199
200 let mut t: [u64; 2] = [0u64; 2];
201 for (mut x, value) in t.iter_mut().enumerate() {
202 let mut word: [u8; 8] = [0u8; 8];
203 x = x * 8 + 196;
204 word.copy_from_slice(&input[x..(x + 8)]);
205 *value = u64::from_le_bytes(word);
206 }
207
208 if input[212] != 0 && input[212] != 1 {
209 return Err(ExitError::Other(Borrowed("ERR_BLAKE2F_FINAL_FLAG")));
210 }
211 let finished = input[212] != 0;
212
213 let output = f(h, m, t, finished, rounds);
214 Ok(PrecompileOutput::without_logs(cost, output))
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::super::utils::new_context;
221 use crate::prelude::Vec;
222
223 use super::*;
224
225 const INPUT: &str = "\
232 0000000c\
233 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
234 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
235 6162630000000000000000000000000000000000000000000000000000000000\
236 0000000000000000000000000000000000000000000000000000000000000000\
237 0000000000000000000000000000000000000000000000000000000000000000\
238 0000000000000000000000000000000000000000000000000000000000000000\
239 0300000000000000\
240 0000000000000000\
241 01";
242
243 fn test_blake2f_out_of_gas() -> EvmPrecompileResult {
244 let input = hex::decode(INPUT).unwrap();
245 Blake2F.run(&input, Some(EthGas::new(11)), &new_context(), false)
246 }
247
248 fn test_blake2f_empty() -> EvmPrecompileResult {
249 let input = [0u8; 0];
250 Blake2F.run(&input, Some(EthGas::new(0)), &new_context(), false)
251 }
252
253 fn test_blake2f_invalid_len_1() -> EvmPrecompileResult {
254 let input = hex::decode(
255 "\
256 00000c\
257 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
258 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
259 6162630000000000000000000000000000000000000000000000000000000000\
260 0000000000000000000000000000000000000000000000000000000000000000\
261 0000000000000000000000000000000000000000000000000000000000000000\
262 0000000000000000000000000000000000000000000000000000000000000000\
263 0300000000000000\
264 0000000000000000\
265 01",
266 )
267 .unwrap();
268 Blake2F.run(&input, Some(EthGas::new(12)), &new_context(), false)
269 }
270
271 fn test_blake2f_invalid_len_2() -> EvmPrecompileResult {
272 let input = hex::decode(
273 "\
274 000000000c\
275 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
276 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
277 6162630000000000000000000000000000000000000000000000000000000000\
278 0000000000000000000000000000000000000000000000000000000000000000\
279 0000000000000000000000000000000000000000000000000000000000000000\
280 0000000000000000000000000000000000000000000000000000000000000000\
281 0300000000000000\
282 0000000000000000\
283 01",
284 )
285 .unwrap();
286 Blake2F.run(&input, Some(EthGas::new(12)), &new_context(), false)
287 }
288
289 fn test_blake2f_invalid_flag() -> EvmPrecompileResult {
290 let input = hex::decode(
291 "\
292 0000000c\
293 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
294 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
295 6162630000000000000000000000000000000000000000000000000000000000\
296 0000000000000000000000000000000000000000000000000000000000000000\
297 0000000000000000000000000000000000000000000000000000000000000000\
298 0000000000000000000000000000000000000000000000000000000000000000\
299 0300000000000000\
300 0000000000000000\
301 02",
302 )
303 .unwrap();
304 Blake2F.run(&input, Some(EthGas::new(12)), &new_context(), false)
305 }
306
307 fn test_blake2f_r_0() -> Vec<u8> {
308 let input = hex::decode(
309 "\
310 00000000\
311 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
312 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
313 6162630000000000000000000000000000000000000000000000000000000000\
314 0000000000000000000000000000000000000000000000000000000000000000\
315 0000000000000000000000000000000000000000000000000000000000000000\
316 0000000000000000000000000000000000000000000000000000000000000000\
317 0300000000000000\
318 0000000000000000\
319 01",
320 )
321 .unwrap();
322 Blake2F
323 .run(&input, Some(EthGas::new(12)), &new_context(), false)
324 .unwrap()
325 .output
326 }
327
328 fn test_blake2f_r_12() -> Vec<u8> {
329 let input = hex::decode(INPUT).unwrap();
330 Blake2F
331 .run(&input, Some(EthGas::new(12)), &new_context(), false)
332 .unwrap()
333 .output
334 }
335
336 fn test_blake2f_final_block_false() -> Vec<u8> {
337 let input = hex::decode(
338 "\
339 0000000c\
340 48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5\
341 d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b\
342 6162630000000000000000000000000000000000000000000000000000000000\
343 0000000000000000000000000000000000000000000000000000000000000000\
344 0000000000000000000000000000000000000000000000000000000000000000\
345 0000000000000000000000000000000000000000000000000000000000000000\
346 0300000000000000\
347 0000000000000000\
348 00",
349 )
350 .unwrap();
351 Blake2F
352 .run(&input, Some(EthGas::new(12)), &new_context(), false)
353 .unwrap()
354 .output
355 }
356
357 #[test]
358 fn test_blake2f() {
359 assert!(matches!(
360 test_blake2f_out_of_gas(),
361 Err(ExitError::OutOfGas)
362 ));
363
364 assert!(matches!(
365 test_blake2f_empty(),
366 Err(ExitError::Other(Borrowed("ERR_BLAKE2F_INVALID_LEN")))
367 ));
368
369 assert!(matches!(
370 test_blake2f_invalid_len_1(),
371 Err(ExitError::Other(Borrowed("ERR_BLAKE2F_INVALID_LEN")))
372 ));
373
374 assert!(matches!(
375 test_blake2f_invalid_len_2(),
376 Err(ExitError::Other(Borrowed("ERR_BLAKE2F_INVALID_LEN")))
377 ));
378
379 assert!(matches!(
380 test_blake2f_invalid_flag(),
381 Err(ExitError::Other(Borrowed("ERR_BLAKE2F_FINAL_FLAG",)))
382 ));
383
384 let expected = hex::decode(
385 "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d\
386 282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
387 )
388 .unwrap();
389 assert_eq!(test_blake2f_r_0(), expected);
390
391 let expected = hex::decode(
392 "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1\
393 7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
394 )
395 .unwrap();
396 assert_eq!(test_blake2f_r_12(), expected);
397
398 let expected = hex::decode(
399 "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d28752\
400 98743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
401 )
402 .unwrap();
403 assert_eq!(test_blake2f_final_block_false(), expected);
404 }
405}