A whimsical STROBE based encryption protocol
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refactor kat harness, ratchet_inner & increment_position

+88 -85
+69 -68
src/herding_kats/harness.rs
··· 1 1 extern crate std; 2 2 3 - use std::{boxed::Box, string::String, vec::Vec}; 3 + use std::{string::String, vec::Vec}; 4 4 5 5 use serde::{Deserialize, Deserializer, de}; 6 6 ··· 37 37 Length(usize), 38 38 } 39 39 40 - /// A boxed closure type, representing the operation to be executed by our Kat. 41 - type KatClosure<'s> = Box<dyn for<'a> Fn(&mut StrobeState, DataOrLength<'a>, bool) + 's>; 40 + // Given the name of the operation and its required parameters, run the STROBE operation. 41 + fn run_kat_operation( 42 + op_name: &str, 43 + meta: bool, 44 + s: &mut StrobeState, 45 + dol: DataOrLength, 46 + more: bool, 47 + ) { 48 + let data = match dol { 49 + DataOrLength::Length(len) => { 50 + if !meta { 51 + assert_eq!(op_name, "RATCHET", "Got length input without RATCHET op"); 52 + s.ratchet(len); 53 + return; 54 + } else { 55 + assert_eq!(op_name, "RATCHET", "Got length input without RATCHET op"); 56 + s.meta_ratchet(len); 57 + return; 58 + } 59 + } 60 + DataOrLength::Data(data) => data, 61 + }; 42 62 43 - // Given the name of the operation and meta flag, returns a closure that performs this operation. 44 - // Returns a boxed closure, because the input and output types of the closure have to fit all 45 - // possible STROBE operations and it is easier to erase that via boxing. 46 - fn get_operation<'s>(op_name: &'s str, meta: bool) -> KatClosure<'s> { 47 - let f = move |s: &mut StrobeState, dol: DataOrLength, more: bool| { 48 - let data = match dol { 49 - DataOrLength::Length(len) => { 50 - if !meta { 51 - assert_eq!(op_name, "RATCHET", "Got length input without RATCHET op"); 52 - s.ratchet(len); 53 - return; 54 - } else { 55 - assert_eq!(op_name, "RATCHET", "Got length input without RATCHET op"); 56 - s.meta_ratchet(len); 57 - return; 58 - } 59 - } 60 - DataOrLength::Data(data) => data, 61 - }; 63 + // To prevent streaming, reset ops *before* executing the operation 64 + // in order to ensure the output state matches the KAT assertion 65 + if !more { 66 + s.reset_ops(); 67 + } 62 68 63 - // To prevent streaming, reset ops *before* executing the operation 64 - // in order to ensure the output state matches the KAT assertion 65 - if !more { 66 - s.reset_ops(); 69 + // Note: we don't expect recv_MAC to work on random inputs. We test recv_MAC's 70 + // correctness in basic_kats.rs. Also MAC sizes are 14 bytes in the KAT. 71 + if !meta { 72 + match op_name { 73 + "AD" => s.ad(data), 74 + "KEY" => s.key(data), 75 + "PRF" => s.prf(data), 76 + "send_CLR" => s.send_clr(data), 77 + "recv_CLR" => s.recv_clr(data), 78 + "send_ENC" => s.send_enc(data), 79 + "recv_ENC" => s.recv_enc(data), 80 + "send_MAC" => s.send_mac(data), 81 + "recv_MAC" => s 82 + .recv_mac::<14>(data.as_ref().try_into().unwrap()) 83 + .unwrap_or(()), 84 + "RATCHET" => panic!("Got RATCHET op without length input"), 85 + _ => panic!("Unexpected op name: {}", op_name), 67 86 } 68 - 69 - // Note: we don't expect recv_MAC to work on random inputs. We test recv_MAC's 70 - // correctness in basic_kats.rs. Also MAC sizes are 14 bytes in the KAT. 71 - if !meta { 72 - match op_name { 73 - "AD" => s.ad(data), 74 - "KEY" => s.key(data), 75 - "PRF" => s.prf(data), 76 - "send_CLR" => s.send_clr(data), 77 - "recv_CLR" => s.recv_clr(data), 78 - "send_ENC" => s.send_enc(data), 79 - "recv_ENC" => s.recv_enc(data), 80 - "send_MAC" => s.send_mac(data), 81 - "recv_MAC" => s 82 - .recv_mac::<14>(data.as_ref().try_into().unwrap()) 83 - .unwrap_or(()), 84 - "RATCHET" => panic!("Got RATCHET op without length input"), 85 - _ => panic!("Unexpected op name: {}", op_name), 86 - } 87 - } else { 88 - match op_name { 89 - "AD" => s.meta_ad(data), 90 - "KEY" => s.meta_key(data), 91 - "PRF" => s.meta_prf(data), 92 - "send_CLR" => s.meta_send_clr(data), 93 - "recv_CLR" => s.meta_recv_clr(data), 94 - "send_ENC" => s.meta_send_enc(data), 95 - "recv_ENC" => s.meta_recv_enc(data), 96 - "send_MAC" => s.meta_send_mac(data), 97 - "recv_MAC" => s 98 - .meta_recv_mac::<14>(data.as_ref().try_into().unwrap()) 99 - .unwrap_or(()), 100 - "RATCHET" => panic!("Got RATCHET op without length input"), 101 - _ => panic!("Unexpected op name: {}", op_name), 102 - } 87 + } else { 88 + match op_name { 89 + "AD" => s.meta_ad(data), 90 + "KEY" => s.meta_key(data), 91 + "PRF" => s.meta_prf(data), 92 + "send_CLR" => s.meta_send_clr(data), 93 + "recv_CLR" => s.meta_recv_clr(data), 94 + "send_ENC" => s.meta_send_enc(data), 95 + "recv_ENC" => s.meta_recv_enc(data), 96 + "send_MAC" => s.meta_send_mac(data), 97 + "recv_MAC" => s 98 + .meta_recv_mac::<14>(data.as_ref().try_into().unwrap()) 99 + .unwrap_or(()), 100 + "RATCHET" => panic!("Got RATCHET op without length input"), 101 + _ => panic!("Unexpected op name: {}", op_name), 103 102 } 104 - }; 105 - 106 - Box::new(f) 103 + } 107 104 } 108 105 109 106 // Runs the test vector and compares to the expected output at each step of the way ··· 126 123 stream, 127 124 expected_output, 128 125 expected_state_after, 129 - }| { 130 - if name != "init" { 126 + }| match name.as_str() { 127 + "init" => { 128 + // Check that the initial state matches what is expected in the KAT operation 129 + assert_eq!(&strobe.state.0[..], expected_state_after.as_slice()); 130 + } 131 + name => { 131 132 // RATCHET inputs are given as strings of zeros instead of lengths. So just take the 132 133 // length of the string of zeros. 133 - let input = if &name == "RATCHET" { 134 + let input = if name == "RATCHET" { 134 135 DataOrLength::Length(input_data.len()) 135 136 } else { 136 137 DataOrLength::Data(input_data.as_mut_slice()) 137 138 }; 138 139 139 - get_operation(&name, meta)(&mut strobe, input, stream); 140 + run_kat_operation(name, meta, &mut strobe, input, stream); 140 141 141 142 assert_eq!(&strobe.state.0[..], expected_state_after.as_slice()); 142 143
+19 -17
src/strobe.rs
··· 169 169 self.start = 0; 170 170 } 171 171 172 - fn increment_position(&mut self) { 173 - self.position += 1; 172 + fn increment_position(&mut self, increment: usize) { 173 + self.position += increment; 174 174 175 175 if self.position == self.rate { 176 176 self.permutation_f(); ··· 183 183 data.iter().for_each(|&b| { 184 184 self.state.0[self.position] ^= b; 185 185 186 - self.increment_position(); 186 + self.increment_position(1); 187 187 }); 188 188 } 189 189 ··· 195 195 *state_byte ^= *b; 196 196 *b = *state_byte; 197 197 198 - self.increment_position(); 198 + self.increment_position(1); 199 199 }); 200 200 } 201 201 ··· 205 205 data.iter_mut().for_each(|b| { 206 206 *b = self.state.0[self.position]; 207 207 208 - self.increment_position(); 208 + self.increment_position(1); 209 209 }); 210 210 } 211 211 ··· 217 217 *b ^= *state_byte; 218 218 *state_byte ^= *b; 219 219 220 - self.increment_position(); 220 + self.increment_position(1); 221 221 }); 222 222 } 223 223 ··· 227 227 data.iter().for_each(|&b| { 228 228 self.state.0[self.position] = b; 229 229 230 - self.increment_position(); 230 + self.increment_position(1); 231 231 }); 232 232 } 233 233 ··· 240 240 *b = *state_byte; 241 241 *state_byte = 0; 242 242 243 - self.increment_position(); 243 + self.increment_position(1); 244 244 }); 245 245 } 246 246 ··· 252 252 // Do the zero-writing in chunks 253 253 while bytes_to_zero > 0 { 254 254 let slice_len = core::cmp::min(self.rate - self.position, bytes_to_zero); 255 + 255 256 self.state.0[self.position..(self.position + slice_len)].fill(0); 256 257 257 - self.position += slice_len; 258 258 bytes_to_zero -= slice_len; 259 259 260 - if self.position == self.rate { 261 - self.permutation_f(); 262 - } 260 + self.increment_position(slice_len); 263 261 } 264 262 } 265 263 ··· 397 395 ) 398 396 } 399 397 400 - fn ratchet_inner(&mut self, num_bytes_to_zero: usize, more: bool, flags: BitFlags<OpFlags>) { 398 + fn ratchet_inner(&mut self, num_bytes_to_zero: usize, flags: BitFlags<OpFlags>) { 399 + let more = self.prev_flags.bits().ct_eq(&flags.bits()); 400 + 401 401 // We don't make an `operate` call, since this is a super special case. That means we have 402 402 // to make the `begin_op` call manually. 403 403 self.prev_flags = flags; 404 404 405 - if !more { 405 + if !bool::from(more) { 406 406 self.begin_op(flags); 407 407 } 408 408 ··· 410 410 } 411 411 412 412 pub fn ratchet(&mut self, num_bytes_to_zero: usize) { 413 - let flags = OpFlags::Cipher.into(); 414 - self.ratchet_inner(num_bytes_to_zero, self.prev_flags == flags, flags); 413 + let flags = BitFlags::from(OpFlags::Cipher); 414 + 415 + self.ratchet_inner(num_bytes_to_zero, flags); 415 416 } 416 417 417 418 pub fn meta_ratchet(&mut self, num_bytes_to_zero: usize) { 418 419 let flags = OpFlags::Cipher | OpFlags::Meta; 419 - self.ratchet_inner(num_bytes_to_zero, self.prev_flags == flags, flags); 420 + 421 + self.ratchet_inner(num_bytes_to_zero, flags); 420 422 } 421 423 422 424 define_mut_operations! {