1use core::ops::{Deref, DerefMut};
4
5use keccak;
6use zeroize::Zeroize;
7
8const STROBE_R: u8 = 166;
10
11const FLAG_I: u8 = 1;
12const FLAG_A: u8 = 1 << 1;
13const FLAG_C: u8 = 1 << 2;
14const FLAG_T: u8 = 1 << 3;
15const FLAG_M: u8 = 1 << 4;
16const FLAG_K: u8 = 1 << 5;
17
18fn transmute_state(st: &mut AlignedKeccakState) -> &mut [u64; 25] {
19 unsafe { &mut *(st as *mut AlignedKeccakState as *mut [u64; 25]) }
20}
21
22#[derive(Clone, Zeroize)]
26#[zeroize(drop)]
27#[repr(align(8))]
28struct AlignedKeccakState([u8; 200]);
29
30#[derive(Clone, Zeroize)]
34pub struct Strobe128 {
35 state: AlignedKeccakState,
36 pos: u8,
37 pos_begin: u8,
38 cur_flags: u8,
39}
40
41impl ::core::fmt::Debug for Strobe128 {
42 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
43 write!(f, "Strobe128: STATE OMITTED")
45 }
46}
47
48impl Strobe128 {
49 pub fn new(protocol_label: &[u8]) -> Strobe128 {
50 let initial_state = {
51 let mut st = AlignedKeccakState([0u8; 200]);
52 st[0..6].copy_from_slice(&[1, STROBE_R + 2, 1, 0, 1, 96]);
53 st[6..18].copy_from_slice(b"STROBEv1.0.2");
54 keccak::f1600(transmute_state(&mut st));
55
56 st
57 };
58
59 let mut strobe = Strobe128 {
60 state: initial_state,
61 pos: 0,
62 pos_begin: 0,
63 cur_flags: 0,
64 };
65
66 strobe.meta_ad(protocol_label, false);
67
68 strobe
69 }
70
71 pub fn meta_ad(&mut self, data: &[u8], more: bool) {
72 self.begin_op(FLAG_M | FLAG_A, more);
73 self.absorb(data);
74 }
75
76 pub fn ad(&mut self, data: &[u8], more: bool) {
77 self.begin_op(FLAG_A, more);
78 self.absorb(data);
79 }
80
81 pub fn prf(&mut self, data: &mut [u8], more: bool) {
82 self.begin_op(FLAG_I | FLAG_A | FLAG_C, more);
83 self.squeeze(data);
84 }
85
86 pub fn key(&mut self, data: &[u8], more: bool) {
87 self.begin_op(FLAG_A | FLAG_C, more);
88 self.overwrite(data);
89 }
90}
91
92impl Strobe128 {
93 fn run_f(&mut self) {
94 self.state[self.pos as usize] ^= self.pos_begin;
95 self.state[(self.pos + 1) as usize] ^= 0x04;
96 self.state[(STROBE_R + 1) as usize] ^= 0x80;
97 keccak::f1600(transmute_state(&mut self.state));
98 self.pos = 0;
99 self.pos_begin = 0;
100 }
101
102 fn absorb(&mut self, data: &[u8]) {
103 for byte in data {
104 self.state[self.pos as usize] ^= byte;
105 self.pos += 1;
106 if self.pos == STROBE_R {
107 self.run_f();
108 }
109 }
110 }
111
112 fn overwrite(&mut self, data: &[u8]) {
113 for byte in data {
114 self.state[self.pos as usize] = *byte;
115 self.pos += 1;
116 if self.pos == STROBE_R {
117 self.run_f();
118 }
119 }
120 }
121
122 fn squeeze(&mut self, data: &mut [u8]) {
123 for byte in data {
124 *byte = self.state[self.pos as usize];
125 self.state[self.pos as usize] = 0;
126 self.pos += 1;
127 if self.pos == STROBE_R {
128 self.run_f();
129 }
130 }
131 }
132
133 fn begin_op(&mut self, flags: u8, more: bool) {
134 if more {
136 assert_eq!(
137 self.cur_flags, flags,
138 "You tried to continue op {:#b} but changed flags to {:#b}",
139 self.cur_flags, flags,
140 );
141 return;
142 }
143
144 assert_eq!(
146 flags & FLAG_T,
147 0u8,
148 "You used the T flag, which this implementation doesn't support"
149 );
150
151 let old_begin = self.pos_begin;
152 self.pos_begin = self.pos + 1;
153 self.cur_flags = flags;
154
155 self.absorb(&[old_begin, flags]);
156
157 let force_f = 0 != (flags & (FLAG_C | FLAG_K));
159
160 if force_f && self.pos != 0 {
161 self.run_f();
162 }
163 }
164}
165
166impl Deref for AlignedKeccakState {
167 type Target = [u8; 200];
168
169 fn deref(&self) -> &Self::Target {
170 &self.0
171 }
172}
173
174impl DerefMut for AlignedKeccakState {
175 fn deref_mut(&mut self) -> &mut Self::Target {
176 &mut self.0
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use strobe_rs::{self, SecParam};
183
184 #[test]
185 fn test_conformance() {
186 let mut s1 = super::Strobe128::new(b"Conformance Test Protocol");
187 let mut s2 = strobe_rs::Strobe::new(b"Conformance Test Protocol", SecParam::B128);
188
189 let msg = [99u8; 1024];
192
193 s1.meta_ad(b"ms", false);
194 s1.meta_ad(b"g", true);
195 s1.ad(&msg, false);
196
197 s2.meta_ad(b"ms", false);
198 s2.meta_ad(b"g", true);
199 s2.ad(&msg, false);
200
201 let mut prf1 = [0u8; 32];
204 s1.meta_ad(b"prf", false);
205 s1.prf(&mut prf1, false);
206
207 let mut prf2 = [0u8; 32];
208 s2.meta_ad(b"prf", false);
209 s2.prf(&mut prf2, false);
210
211 assert_eq!(prf1, prf2);
212
213 s1.meta_ad(b"key", false);
216 s1.key(&prf1, false);
217
218 s2.meta_ad(b"key", false);
219 s2.key(&prf2, false);
220
221 let mut prf1 = [0u8; 32];
224 s1.meta_ad(b"prf", false);
225 s1.prf(&mut prf1, false);
226
227 let mut prf2 = [0u8; 32];
228 s2.meta_ad(b"prf", false);
229 s2.prf(&mut prf2, false);
230
231 assert_eq!(prf1, prf2);
232 }
233}