|
| 1 | +use crate::consts::*; |
| 2 | + |
| 3 | +const W: usize = MD6_W; // number of bits in a word (64) |
| 4 | +const C: usize = MD6_C; // size of compression output in words (16) |
| 5 | +const N: usize = MD6_N; // size of compression input block in words (89) |
| 6 | +const Q: usize = MD6_Q; // Q words in a compression block (>= 0) (15) |
| 7 | +const K: usize = MD6_K; // key words per compression block (>= 0) (8) |
| 8 | +const U: usize = MD6_U; // words for unique node ID (0 or 64/w) |
| 9 | +const V: usize = MD6_V; // words for control word (0 or 64/w) |
| 10 | +const B: usize = MD6_B; // data words per compression block (> 0) (64) |
| 11 | + |
| 12 | +const T0: usize = 17; // index for linear feedback |
| 13 | +const T1: usize = 18; // index for first input to first and |
| 14 | +const T2: usize = 21; // index for second input to first and |
| 15 | +const T3: usize = 31; // index for first input to second and |
| 16 | +const T4: usize = 67; // index for second input to second and |
| 17 | +const T5: usize = 89; // last tap |
| 18 | + |
| 19 | +macro_rules! call_loop_bodies { |
| 20 | + ($w: ident, $s: expr, $i: expr) => { |
| 21 | + if $w == 64 { |
| 22 | + loop_body!(10, 11, 0, $s, $i); |
| 23 | + loop_body!(5, 24, 1, $s, $i); |
| 24 | + loop_body!(13, 9, 2, $s, $i); |
| 25 | + loop_body!(10, 16, 3, $s, $i); |
| 26 | + loop_body!(11, 15, 4, $s, $i); |
| 27 | + loop_body!(12, 9, 5, $s, $i); |
| 28 | + loop_body!(2, 27, 6, $s, $i); |
| 29 | + loop_body!(7, 15, 7, $s, $i); |
| 30 | + loop_body!(14, 6, 8, $s, $i); |
| 31 | + loop_body!(15, 2, 9, $s, $i); |
| 32 | + loop_body!(7, 29, 10, $s, $i); |
| 33 | + loop_body!(13, 8, 11, $s, $i); |
| 34 | + loop_body!(11, 15, 12, $s, $i); |
| 35 | + loop_body!(7, 5, 13, $s, $i); |
| 36 | + loop_body!(6, 31, 14, $s, $i); |
| 37 | + loop_body!(12, 9, 15, $s, $i); |
| 38 | + } else if $w == 32 { |
| 39 | + loop_body!(5, 4, 0, $s, $i); |
| 40 | + loop_body!(3, 7, 1, $s, $i); |
| 41 | + loop_body!(6, 7, 2, $s, $i); |
| 42 | + loop_body!(5, 9, 3, $s, $i); |
| 43 | + loop_body!(4, 13, 4, $s, $i); |
| 44 | + loop_body!(6, 8, 5, $s, $i); |
| 45 | + loop_body!(7, 4, 6, $s, $i); |
| 46 | + loop_body!(3, 14, 7, $s, $i); |
| 47 | + loop_body!(5, 7, 8, $s, $i); |
| 48 | + loop_body!(6, 4, 9, $s, $i); |
| 49 | + loop_body!(5, 8, 10, $s, $i); |
| 50 | + loop_body!(5, 11, 11, $s, $i); |
| 51 | + loop_body!(4, 5, 12, $s, $i); |
| 52 | + loop_body!(6, 8, 13, $s, $i); |
| 53 | + loop_body!(7, 2, 14, $s, $i); |
| 54 | + loop_body!(5, 11, 15, $s, $i); |
| 55 | + } else if $w == 16 { |
| 56 | + loop_body!(5, 6, 0, $s, $i); |
| 57 | + loop_body!(4, 7, 1, $s, $i); |
| 58 | + loop_body!(3, 2, 2, $s, $i); |
| 59 | + loop_body!(5, 4, 3, $s, $i); |
| 60 | + loop_body!(7, 2, 4, $s, $i); |
| 61 | + loop_body!(5, 6, 5, $s, $i); |
| 62 | + loop_body!(5, 3, 6, $s, $i); |
| 63 | + loop_body!(2, 7, 7, $s, $i); |
| 64 | + loop_body!(4, 5, 8, $s, $i); |
| 65 | + loop_body!(3, 7, 9, $s, $i); |
| 66 | + loop_body!(4, 6, 10, $s, $i); |
| 67 | + loop_body!(3, 5, 11, $s, $i); |
| 68 | + loop_body!(4, 5, 12, $s, $i); |
| 69 | + loop_body!(7, 6, 13, $s, $i); |
| 70 | + loop_body!(7, 4, 14, $s, $i); |
| 71 | + loop_body!(2, 3, 15, $s, $i); |
| 72 | + } else if $w == 8 { |
| 73 | + loop_body!(3, 2, 0, $s, $i); |
| 74 | + loop_body!(3, 4, 1, $s, $i); |
| 75 | + loop_body!(3, 2, 2, $s, $i); |
| 76 | + loop_body!(4, 3, 3, $s, $i); |
| 77 | + loop_body!(3, 2, 4, $s, $i); |
| 78 | + loop_body!(3, 2, 5, $s, $i); |
| 79 | + loop_body!(3, 2, 6, $s, $i); |
| 80 | + loop_body!(3, 4, 7, $s, $i); |
| 81 | + loop_body!(2, 3, 8, $s, $i); |
| 82 | + loop_body!(2, 3, 9, $s, $i); |
| 83 | + loop_body!(3, 2, 10, $s, $i); |
| 84 | + loop_body!(2, 3, 11, $s, $i); |
| 85 | + loop_body!(2, 3, 12, $s, $i); |
| 86 | + loop_body!(3, 4, 13, $s, $i); |
| 87 | + loop_body!(2, 3, 14, $s, $i); |
| 88 | + loop_body!(3, 4, 15, $s, $i); |
| 89 | + } |
| 90 | + }; |
| 91 | +} |
| 92 | + |
| 93 | +fn get_s_constants(ws: usize) -> (Md6Word, Md6Word) { |
| 94 | + match ws { |
| 95 | + 64 => (0x0123456789abcdef, 0x7311c2812425cfa0), |
| 96 | + 32 => (0x01234567, 0x7311c281), |
| 97 | + 16 => (0x01234, 0x7311), |
| 98 | + 8 => (0x01, 0x73), |
| 99 | + _ => panic!("bad w"), |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +fn main_compression_loop(a: &mut [Md6Word], r: usize) { |
| 104 | + macro_rules! loop_body { |
| 105 | + ($rs: expr, $ls: expr, $step: expr, $s: expr, $i: expr) => { |
| 106 | + let mut x = $s; // feedback constant |
| 107 | + x ^= a[$i + $step - T5]; // end-around feedback |
| 108 | + x ^= a[$i + $step - T0]; // linear feedback |
| 109 | + x ^= (a[$i + $step - T1] & a[$i + $step - T2]); // first quadratic term |
| 110 | + x ^= (a[$i + $step - T3] & a[$i + $step - T4]); // second quadratic term |
| 111 | + x ^= x >> $rs; // right shift |
| 112 | + a[$i + $step] = x ^ (x << $ls); // left shift |
| 113 | + }; |
| 114 | + } |
| 115 | + |
| 116 | + // Get the initial values for `s` and `smask` based on the width `w`. |
| 117 | + let (mut s, smask) = get_s_constants(W); |
| 118 | + |
| 119 | + let mut i = N; |
| 120 | + let mut j = 0; |
| 121 | + |
| 122 | + while j < r * C { |
| 123 | + // Call the loop bodies based on the value of `w`. |
| 124 | + // This will perform the main computation for each step in the compression loop. |
| 125 | + call_loop_bodies!(W, s, i); |
| 126 | + |
| 127 | + // Advance round constant s to the next round constant. |
| 128 | + s = (s << 1) ^ (s >> (W - 1)) ^ (s & smask); |
| 129 | + i += 16; |
| 130 | + j += C; |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +pub fn compress(c: &mut [Md6Word], n: &mut [Md6Word], r: usize, a: &mut [Md6Word]) { |
| 135 | + // check that the input is sensible |
| 136 | + assert!(!n.is_empty()); |
| 137 | + assert!(!n.is_empty()); |
| 138 | + assert!(r <= MD6_MAX_R); |
| 139 | + assert!(!a.is_empty()); |
| 140 | + |
| 141 | + a[..n.len()].copy_from_slice(n); // copy n to front of a |
| 142 | + |
| 143 | + main_compression_loop(a, r); // do the main computation |
| 144 | + |
| 145 | + c.copy_from_slice(&a[((r - 1) * C + N)..((r - 1) * C + N + C)]); // output into c |
| 146 | +} |
| 147 | + |
| 148 | +fn make_control_word( |
| 149 | + r: usize, |
| 150 | + l: usize, |
| 151 | + z: usize, |
| 152 | + p: usize, |
| 153 | + keylen: usize, |
| 154 | + d: usize, |
| 155 | +) -> Md6ControlWord { |
| 156 | + (0 as Md6ControlWord) << 60 // reserved width 4 bits |
| 157 | + | (r as Md6ControlWord) << 48 // r width 12 bits |
| 158 | + | (l as Md6ControlWord) << 40 // L width 8 bits |
| 159 | + | (z as Md6ControlWord) << 36 // z width 4 bits |
| 160 | + | (p as Md6ControlWord) << 20 // p width 16 bits |
| 161 | + | (keylen as Md6ControlWord) << 12 // keylen width 8 bits |
| 162 | + | (d as Md6ControlWord) // d width 12 bits |
| 163 | +} |
| 164 | + |
| 165 | +pub fn make_node_id(ell: usize, i: Md6Word) -> Md6NodeID { |
| 166 | + (ell as Md6NodeID) << 56 | i // ell width 8 bits, i width 56 bits |
| 167 | +} |
| 168 | + |
| 169 | +pub fn pack( |
| 170 | + n: &mut [Md6Word], |
| 171 | + q: &[Md6Word], |
| 172 | + k: [Md6Word; K], |
| 173 | + ell: usize, |
| 174 | + i: Md6Word, |
| 175 | + r: usize, |
| 176 | + l: usize, |
| 177 | + z: usize, |
| 178 | + p: usize, |
| 179 | + keylen: usize, |
| 180 | + d: usize, |
| 181 | + b: [Md6Word; 64], |
| 182 | +) { |
| 183 | + let mut ni = 0; |
| 184 | + |
| 185 | + n[ni..ni + Q].copy_from_slice(&q[..Q]); // q: q in words 0--14 |
| 186 | + ni += Q; |
| 187 | + |
| 188 | + n[ni..ni + K].copy_from_slice(&k[..K]); // k: key in words 15--22 |
| 189 | + ni += K; |
| 190 | + |
| 191 | + let u = make_node_id(ell, i); // u: unique node ID in 23 |
| 192 | + n[ni] = u; |
| 193 | + ni += U; |
| 194 | + |
| 195 | + let v = make_control_word(r, l, z, p, keylen, d); // v: control word in 24 |
| 196 | + n[ni] = v; |
| 197 | + ni += V; |
| 198 | + |
| 199 | + n[ni..ni + B].copy_from_slice(&b[..B]); // b: data words 25--88 |
| 200 | +} |
| 201 | + |
| 202 | +pub fn standard_compress( |
| 203 | + c: &mut [Md6Word], |
| 204 | + q: &[Md6Word], |
| 205 | + k: [Md6Word; K], |
| 206 | + ell: usize, |
| 207 | + i: Md6Word, |
| 208 | + r: usize, |
| 209 | + l: usize, |
| 210 | + z: usize, |
| 211 | + p: usize, |
| 212 | + keylen: usize, |
| 213 | + d: usize, |
| 214 | + b: [Md6Word; 64], |
| 215 | +) { |
| 216 | + let mut n = [0; MD6_N]; |
| 217 | + let mut a = [0; 5000]; |
| 218 | + |
| 219 | + // check that the input values are sensible |
| 220 | + assert!(!c.is_empty()); |
| 221 | + assert!(!q.is_empty()); |
| 222 | + assert!(!b.is_empty()); |
| 223 | + assert!(r <= MD6_MAX_R); |
| 224 | + assert!(l <= 255); |
| 225 | + assert!(ell <= 255); |
| 226 | + assert!(p <= B * W); |
| 227 | + assert!(d <= C * W / 2); |
| 228 | + assert!(!k.is_empty()); |
| 229 | + |
| 230 | + pack(&mut n, q, k, ell, i, r, l, z, p, keylen, d, b); // pack input data into N |
| 231 | + |
| 232 | + compress(c, &mut n, r, &mut a); // compress |
| 233 | +} |
0 commit comments