|
| 1 | +//! Helper library for working with NOISE handshake Act data. Contains utilities for passing Act |
| 2 | +//! objects around and building them from received data. |
| 3 | +//! Act objects are thin wrappers about raw arrays for stack-based processing as well as convenient |
| 4 | +//! coercion to slices for flexible use by the higher-level modules. |
| 5 | +
|
| 6 | +use std::{cmp, ops}; |
| 7 | + |
| 8 | +pub const ACT_ONE_TWO_LENGTH: usize = 50; |
| 9 | +pub const ACT_THREE_LENGTH: usize = 66; |
| 10 | +pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_TWO_LENGTH]; |
| 11 | +pub const EMPTY_ACT_TWO: ActTwo = EMPTY_ACT_ONE; |
| 12 | +pub const EMPTY_ACT_THREE: ActThree = [0; ACT_THREE_LENGTH]; |
| 13 | +type ActOne = [u8; ACT_ONE_TWO_LENGTH]; |
| 14 | +type ActTwo = ActOne; |
| 15 | +type ActThree = [u8; ACT_THREE_LENGTH]; |
| 16 | + |
| 17 | +/// Wrapper for any act message |
| 18 | +pub(super) enum Act { |
| 19 | + One(ActOne), |
| 20 | + Two(ActTwo), |
| 21 | + Three(ActThree) |
| 22 | +} |
| 23 | + |
| 24 | +impl Act { |
| 25 | + /// Returns the size of the underlying array |
| 26 | + fn len(&self) -> usize { |
| 27 | + self.as_ref().len() |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +impl From<ActBuilder> for Act { |
| 32 | + /// Convert a finished ActBuilder into an Act |
| 33 | + fn from(act_builder: ActBuilder) -> Self { |
| 34 | + assert!(act_builder.is_finished()); |
| 35 | + act_builder.partial_act |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +impl ops::Deref for Act { |
| 40 | + type Target = [u8]; |
| 41 | + |
| 42 | + /// Allows automatic coercion to slices in function calls |
| 43 | + /// &Act -> &[u8] |
| 44 | + fn deref(&self) -> &Self::Target { |
| 45 | + match self { |
| 46 | + &Act::One(ref act) => { |
| 47 | + act |
| 48 | + } |
| 49 | + &Act::Two(ref act) => { |
| 50 | + act |
| 51 | + } |
| 52 | + &Act::Three(ref act) => { |
| 53 | + act |
| 54 | + } |
| 55 | + } |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +impl AsRef<[u8]> for Act { |
| 60 | + /// Allow convenient exposure of the underlying array through as_ref() |
| 61 | + /// Act.as_ref() -> &[u8] |
| 62 | + fn as_ref(&self) -> &[u8] { |
| 63 | + &self |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +// Simple fill implementation for both almost-identical structs to deduplicate code |
| 68 | +// $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed |
| 69 | +macro_rules! fill_impl { |
| 70 | + ($act:expr, $write_pos:expr, $input:expr) => {{ |
| 71 | + let fill_amount = cmp::min($act.len() - $write_pos, $input.len()); |
| 72 | + |
| 73 | + $act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]); |
| 74 | + |
| 75 | + $write_pos += fill_amount; |
| 76 | + &$input[fill_amount..] |
| 77 | + }} |
| 78 | +} |
| 79 | + |
| 80 | +/// Light wrapper around an Act that allows multiple fill() calls before finally |
| 81 | +/// converting to an Act via Act::from(act_builder). Handles all of the bookkeeping |
| 82 | +/// and edge cases of the array fill |
| 83 | +pub(super) struct ActBuilder { |
| 84 | + partial_act: Act, |
| 85 | + write_pos: usize |
| 86 | +} |
| 87 | + |
| 88 | +impl ActBuilder { |
| 89 | + /// Returns a new ActBuilder for Act::One |
| 90 | + pub(super) fn new(empty_act: Act) -> Self { |
| 91 | + Self { |
| 92 | + partial_act: empty_act, |
| 93 | + write_pos: 0 |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + /// Fills the Act with bytes from input and returns the unprocessed bytes |
| 98 | + pub(super) fn fill<'a>(&mut self, input: &'a [u8]) -> &'a [u8] { |
| 99 | + match &mut self.partial_act { |
| 100 | + &mut Act::One(ref mut act) => { |
| 101 | + fill_impl!(act, self.write_pos, input) |
| 102 | + } |
| 103 | + &mut Act::Two(ref mut act) => { |
| 104 | + fill_impl!(act, self.write_pos, input) |
| 105 | + } |
| 106 | + &mut Act::Three(ref mut act) => { |
| 107 | + fill_impl!(act, self.write_pos, input) |
| 108 | + } |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + /// Returns true if the Act is finished building (enough bytes via fill()) |
| 113 | + pub(super) fn is_finished(&self) -> bool { |
| 114 | + self.write_pos == self.partial_act.len() |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +#[cfg(test)] |
| 119 | +mod tests { |
| 120 | + use super::*; |
| 121 | + |
| 122 | + // Test bookkeeping of partial fill |
| 123 | + #[test] |
| 124 | + fn partial_fill() { |
| 125 | + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); |
| 126 | + |
| 127 | + let remaining = builder.fill(&[1, 2, 3]); |
| 128 | + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); |
| 129 | + assert_eq!(builder.write_pos, 3); |
| 130 | + assert!(!builder.is_finished()); |
| 131 | + assert_eq!(remaining, &[]); |
| 132 | + } |
| 133 | + |
| 134 | + // Test bookkeeping of exact fill |
| 135 | + #[test] |
| 136 | + fn exact_fill() { |
| 137 | + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); |
| 138 | + |
| 139 | + let input = [0; 50]; |
| 140 | + let remaining = builder.fill(&input); |
| 141 | + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); |
| 142 | + assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); |
| 143 | + assert!(builder.is_finished()); |
| 144 | + assert_eq!(Act::from(builder).as_ref(), &input[..]); |
| 145 | + assert_eq!(remaining, &[]); |
| 146 | + } |
| 147 | + |
| 148 | + // Test bookkeeping of overfill |
| 149 | + #[test] |
| 150 | + fn over_fill() { |
| 151 | + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); |
| 152 | + |
| 153 | + let input = [0; 51]; |
| 154 | + let remaining = builder.fill(&input); |
| 155 | + |
| 156 | + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); |
| 157 | + assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); |
| 158 | + assert!(builder.is_finished()); |
| 159 | + assert_eq!(Act::from(builder).as_ref(), &input[..50]); |
| 160 | + assert_eq!(remaining, &[0]); |
| 161 | + } |
| 162 | + |
| 163 | + // Converting an unfinished ActBuilder panics |
| 164 | + #[test] |
| 165 | + #[should_panic(expected="as")] |
| 166 | + fn convert_not_finished_panics() { |
| 167 | + let builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); |
| 168 | + let _should_panic = Act::from(builder); |
| 169 | + } |
| 170 | +} |
| 171 | + |
0 commit comments