1#![no_std]
2
3use core::cmp;
4use gimli_permutation::{ SIZE, gimli, state_with as with };
5
6
7const RATE: usize = 16;
8
9#[derive(Clone)]
10pub struct GimliHash {
11 state: [u32; SIZE],
12 pos: usize
13}
14
15impl Default for GimliHash {
16 fn default() -> Self {
17 GimliHash { state: [0; SIZE], pos: 0 }
18 }
19}
20
21impl GimliHash {
22 #[inline]
23 pub fn update(&mut self, buf: &[u8]) {
24 self.absorb(buf);
25 }
26
27 #[inline]
28 pub fn finalize(self, buf: &mut [u8]) {
29 self.xof().squeeze(buf);
30 }
31
32 #[inline]
33 pub fn xof(mut self) -> XofReader {
34 self.pad();
35 XofReader { state: self.state, pos: 0 }
36 }
37
38 pub fn fill_block(&mut self) {
39 self.pos = 0;
40 gimli(&mut self.state);
41 }
42
43 fn absorb(&mut self, buf: &[u8]) {
44 let take = cmp::min(RATE - self.pos, buf.len());
45 let (prefix, buf) = buf.split_at(take);
46
47 if !prefix.is_empty() {
48 let pos = self.pos;
49 with(&mut self.state, |state| {
50 for (dest, src) in state.iter_mut()
51 .skip(pos)
52 .zip(prefix)
53 {
54 *dest ^= *src;
55 }
56 });
57
58 self.pos += prefix.len();
59
60 if self.pos == RATE {
61 gimli(&mut self.state);
62 self.pos = 0;
63 }
64 }
65
66 let mut iter = buf.chunks_exact(RATE);
67 for chunk in &mut iter {
68 with(&mut self.state, |state| {
69 for (dest, src) in state.iter_mut().zip(chunk) {
70 *dest ^= *src;
71 }
72 });
73 gimli(&mut self.state);
74 }
75
76 let chunk = iter.remainder();
77 if !chunk.is_empty() {
78 with(&mut self.state, |state| {
79 for (dest, src) in state.iter_mut().zip(chunk) {
80 *dest ^= *src;
81 }
82 });
83 self.pos += chunk.len();
84 }
85 }
86
87 fn pad(&mut self) {
88 let pos = self.pos;
89 with(&mut self.state, |state| {
90 state[pos] ^= 0x1f;
91 state[RATE - 1] ^= 0x80;
92 });
93 gimli(&mut self.state);
94 }
95}
96
97
98pub struct XofReader {
99 state: [u32; SIZE],
100 pos: usize
101}
102
103impl XofReader {
104 pub fn squeeze(&mut self, buf: &mut [u8]) {
105 let take = cmp::min(RATE - self.pos, buf.len());
106 let (prefix, buf) = buf.split_at_mut(take);
107
108 if !prefix.is_empty() {
109 let pos = self.pos;
110 with(&mut self.state, |state| {
111 prefix.copy_from_slice(&state[pos..][..prefix.len()]);
112 });
113
114 self.pos += prefix.len();
115
116 if self.pos == RATE {
117 gimli(&mut self.state);
118 self.pos = 0;
119 }
120 }
121
122 let mut iter = buf.chunks_exact_mut(RATE);
123 for chunk in &mut iter {
124 with(&mut self.state, |state| chunk.copy_from_slice(&state[..RATE]));
125 gimli(&mut self.state);
126 }
127
128 let chunk = iter.into_remainder();
129 if !chunk.is_empty() {
130 with(&mut self.state, |state| {
131 chunk.copy_from_slice(&state[..chunk.len()]);
132 });
133 self.pos += take;
134 }
135 }
136}