sigma_rs/duplex_sponge/
keccak.rs1use crate::duplex_sponge::DuplexSpongeInterface;
7use zerocopy::IntoBytes;
8
9const RATE: usize = 136;
10const LENGTH: usize = 136 + 64;
11
12#[derive(Clone, Default)]
14pub struct KeccakPermutationState([u64; LENGTH / 8]);
15
16impl KeccakPermutationState {
17 pub fn new(iv: [u8; 32]) -> Self {
18 let mut state = Self::default();
19 state.as_mut()[RATE..RATE + 32].copy_from_slice(&iv);
20 state
21 }
22
23 pub fn permute(&mut self) {
24 keccak::f1600(&mut self.0);
25 }
26}
27
28impl AsRef<[u8]> for KeccakPermutationState {
29 fn as_ref(&self) -> &[u8] {
30 self.0.as_bytes()
31 }
32}
33
34impl AsMut<[u8]> for KeccakPermutationState {
35 fn as_mut(&mut self) -> &mut [u8] {
36 self.0.as_mut_bytes()
37 }
38}
39
40#[derive(Clone)]
42pub struct KeccakDuplexSponge {
43 state: KeccakPermutationState,
44 absorb_index: usize,
45 squeeze_index: usize,
46}
47
48impl KeccakDuplexSponge {
49 pub fn new(iv: [u8; 32]) -> Self {
50 let state = KeccakPermutationState::new(iv);
51 KeccakDuplexSponge {
52 state,
53 absorb_index: 0,
54 squeeze_index: RATE,
55 }
56 }
57}
58
59impl DuplexSpongeInterface for KeccakDuplexSponge {
60 fn new(iv: [u8; 32]) -> Self {
61 KeccakDuplexSponge::new(iv)
62 }
63
64 fn absorb(&mut self, mut input: &[u8]) {
65 self.squeeze_index = RATE;
66
67 while !input.is_empty() {
68 if self.absorb_index == RATE {
69 self.state.permute();
70 self.absorb_index = 0;
71 }
72
73 let chunk_size = usize::min(RATE - self.absorb_index, input.len());
74 let dest = &mut self.state.as_mut()[self.absorb_index..self.absorb_index + chunk_size];
75 dest.copy_from_slice(&input[..chunk_size]);
76 self.absorb_index += chunk_size;
77 input = &input[chunk_size..];
78 }
79 }
80
81 fn squeeze(&mut self, mut length: usize) -> Vec<u8> {
82 let mut output = Vec::new();
83 while length != 0 {
84 if self.squeeze_index == RATE {
85 self.state.permute();
86 self.squeeze_index = 0;
87 self.absorb_index = 0;
88 }
89
90 let chunk_size = usize::min(RATE - self.squeeze_index, length);
91 output.extend_from_slice(
92 &self.state.as_mut()[self.squeeze_index..self.squeeze_index + chunk_size],
93 );
94 self.squeeze_index += chunk_size;
95 length -= chunk_size;
96 }
97 output
98 }
99
100 fn ratchet(&mut self) {
101 self.state.permute();
102 self.absorb_index = 0;
103 self.squeeze_index = RATE;
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::duplex_sponge::DuplexSpongeInterface;
111 use hex_literal::hex;
112
113 #[test]
114 fn test_associativity_of_absorb() {
115 let expected_output =
116 hex!("7dfada182d6191e106ce287c2262a443ce2fb695c7cc5037a46626e88889af58");
117 let tag = *b"absorb-associativity-domain-----";
118
119 let mut sponge1 = KeccakDuplexSponge::new(tag);
121 sponge1.absorb(b"hello world");
122 let out1 = sponge1.squeeze(32);
123
124 let mut sponge2 = KeccakDuplexSponge::new(tag);
126 sponge2.absorb(b"hello");
127 sponge2.absorb(b" world");
128 let out2 = sponge2.squeeze(32);
129
130 assert_eq!(out1, expected_output);
131 assert_eq!(out2, expected_output);
132 }
133}