fluentbase_runtime/syscall_handler/hashing/
keccak256_permute.rs1use crate::RuntimeContext;
2use rwasm::{StoreTr, TrapCode, Value};
3
4pub(crate) const STATE_SIZE: u32 = 25;
5
6pub const STATE_NUM_WORDS: u32 = STATE_SIZE * 2;
8
9#[repr(C, align(8))]
10struct Aligned200([u8; 200]);
11
12impl Aligned200 {
13 #[inline]
15 pub fn into_lanes_le(self) -> [u64; 25] {
16 const _: () = assert!(size_of::<[u8; 200]>() == size_of::<[u64; 25]>());
18 #[cfg(not(target_endian = "little"))]
19 const _: () = panic!("into_lanes_le requires little-endian platform");
20 unsafe { core::mem::transmute::<[u8; 200], [u64; 25]>(self.0) }
23 }
24
25 #[inline]
27 pub fn from_lanes_le(lanes: [u64; 25]) -> Self {
28 #[cfg(not(target_endian = "little"))]
29 const _: () = panic!("from_lanes_le requires little-endian platform");
30
31 let bytes: [u8; 200] = unsafe { core::mem::transmute(lanes) };
32 Self(bytes)
33 }
34}
35
36pub fn syscall_hashing_keccak256_permute_handler(
37 ctx: &mut impl StoreTr<RuntimeContext>,
38 params: &[Value],
39 _result: &mut [Value],
40) -> Result<(), TrapCode> {
41 let state_ptr = params[0].i32().unwrap() as u32;
42 let mut state = [0u8; 200];
43 ctx.memory_read(state_ptr as usize, &mut state)?;
44 let mut state = Aligned200(state).into_lanes_le();
45 syscall_hashing_keccak256_permute_impl(&mut state);
46 let state = Aligned200::from_lanes_le(state);
47 ctx.memory_write(state_ptr as usize, &state.0)?;
48 Ok(())
49}
50
51pub fn syscall_hashing_keccak256_permute_impl(state: &mut [u64; 25]) {
52 use tiny_keccak::keccakf;
53 keccakf(state);
54}
55
56#[cfg(test)]
57mod tests {
58 use crate::syscall_handler::syscall_hashing_keccak256_permute_impl;
59 use fluentbase_types::hex;
60
61 const RATE: usize = 136; const LANES: usize = 25; pub fn tiny_keccak256(inp: &[u8]) -> [u8; 32] {
65 let mut s = [0u64; 25];
66 let mut i = 0;
67 while i + RATE <= inp.len() {
69 for (j, &b) in inp[i..i + RATE].iter().enumerate() {
70 s[j / 8] ^= (b as u64) << ((j % 8) * 8);
71 }
72 syscall_hashing_keccak256_permute_impl(&mut s);
73 i += RATE;
74 }
75 let r = inp.len() - i;
77 for (j, &b) in inp[i..].iter().enumerate() {
78 s[j / 8] ^= (b as u64) << ((j % 8) * 8);
79 }
80 s[r / 8] ^= 1u64 << ((r % 8) * 8);
81 s[(RATE - 1) / 8] ^= 0x80u64 << (((RATE - 1) % 8) * 8);
82 syscall_hashing_keccak256_permute_impl(&mut s);
84 let mut out = [0u8; 32];
86 for k in 0..32 {
87 out[k] = ((s[k / 8] >> ((k % 8) * 8)) & 0xFF) as u8;
88 }
89 out
90 }
91
92 #[test]
93 fn test_keccak256_permute() {
94 let hash = tiny_keccak256("Hello, World".as_bytes());
95 assert_eq!(
96 hash,
97 hex!("a04a451028d0f9284ce82243755e245238ab1e4ecf7b9dd8bf4734d9ecfd0529")
98 );
99 let hash = tiny_keccak256(&[]);
100 assert_eq!(
101 hash,
102 hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
103 );
104 let hash = tiny_keccak256("abc".as_bytes());
105 assert_eq!(
106 hash,
107 hex!("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
108 );
109 }
110
111 fn ref_keccak256(data: &[u8]) -> [u8; 32] {
112 use tiny_keccak::{Hasher, Keccak};
113 let mut hasher = Keccak::v256(); hasher.update(data);
115 let mut out = [0u8; 32];
116 hasher.finalize(&mut out);
117 out
118 }
119
120 #[test]
121 fn corner_lengths_near_rate() {
122 for &len in &[
124 0usize, 1, 2, 3, 7, 8, 15, 16, 31, 32, 63, 64, 127, 135, 136, 137,
125 ] {
126 let msg: Vec<u8> = (0..len as u64)
127 .map(|x| (x as u8).wrapping_mul(0x9d))
128 .collect();
129 assert_eq!(tiny_keccak256(&msg), ref_keccak256(&msg), "len={}", len);
130 }
131 }
132
133 #[test]
134 fn unicode_bytes() {
135 let s1 = "Привет, мир! 👋🌍".as_bytes();
137 let s2 = "ちりも積もれば山となる".as_bytes();
138 let s3 = "مرحبا بالعالم".as_bytes();
139 for (i, m) in [s1, s2, s3].into_iter().enumerate() {
140 assert_eq!(tiny_keccak256(m), ref_keccak256(m), "unicode idx={}", i);
141 }
142 }
143
144 #[test]
145 fn long_messages() {
146 let mut m1 = vec![0u8; 10_000]; for (i, b) in m1.iter_mut().enumerate() {
149 *b = (i as u8).wrapping_mul(17);
150 }
151 assert_eq!(tiny_keccak256(&m1), ref_keccak256(&m1));
152
153 let m2 = vec![b'a'; 1_000_000];
155 assert_eq!(tiny_keccak256(&m2), ref_keccak256(&m2));
156 }
157
158 #[test]
159 fn every_tail_len_0_to_200() {
160 let head: Vec<u8> = (0..512u16).map(|x| (x as u8).wrapping_mul(73)).collect();
162 for tail_len in 0..=200 {
163 let mut m = head.clone();
164 m.extend((0..tail_len as u16).map(|x| (x as u8).wrapping_add(5)));
165 assert_eq!(
166 tiny_keccak256(&m),
167 ref_keccak256(&m),
168 "tail_len={}",
169 tail_len
170 );
171 }
172 }
173}