1#![no_std]
2#![allow(non_upper_case_globals)]
3extern crate cipher;
4#[cfg(test)]
5#[macro_use]
6extern crate hex_literal;
7use core::convert::TryInto;
8use core::ops::BitXor;
9
10mod consts;
11use consts::{C240, P_1024, P_256, P_512, R_1024, R_256, R_512};
12
13use cipher::generic_array::typenum::{U1, U128, U32, U64};
14use cipher::generic_array::GenericArray;
15pub use cipher::{BlockCipher, NewBlockCipher};
16
17fn mix(r: u32, x: (u64, u64)) -> (u64, u64) {
18 let y0 = x.0.wrapping_add(x.1);
19 let y1 = x.1.rotate_left(r) ^ y0;
20 (y0, y1)
21}
22
23fn inv_mix(r: u32, y: (u64, u64)) -> (u64, u64) {
24 let x1 = (y.0 ^ y.1).rotate_right(r);
25 let x0 = y.0.wrapping_sub(x1);
26 (x0, x1)
27}
28
29fn read_u64v_le(ns: &mut [u64], buf: &[u8]) {
30 for (c, n) in buf.chunks_exact(8).zip(ns) {
31 *n = u64::from_le_bytes(c.try_into().unwrap());
32 }
33}
34
35fn write_u64v_le(buf: &mut [u8], ns: &[u64]) {
36 for (c, n) in buf.chunks_exact_mut(8).zip(ns) {
37 c.copy_from_slice(&n.to_le_bytes());
38 }
39}
40
41#[rustfmt::skip]
42#[cfg(not(feature = "no_unroll"))]
43macro_rules! unroll8 {
44 ($var:ident, $body:block) => {
45 { const $var: usize = 0; $body; }
46 { const $var: usize = 1; $body; }
47 { const $var: usize = 2; $body; }
48 { const $var: usize = 3; $body; }
49 { const $var: usize = 4; $body; }
50 { const $var: usize = 5; $body; }
51 { const $var: usize = 6; $body; }
52 { const $var: usize = 7; $body; }
53 };
54}
55
56#[cfg(feature = "no_unroll")]
57macro_rules! unroll8 {
58 ($var:ident, $body:block) => {
59 for $var in 0..8 $body
60 }
61}
62
63#[rustfmt::skip]
64#[cfg(not(feature = "no_unroll"))]
65macro_rules! unroll8_rev {
66 ($var:ident, $body:block) => {
67 { const $var: usize = 7; $body; }
68 { const $var: usize = 6; $body; }
69 { const $var: usize = 5; $body; }
70 { const $var: usize = 4; $body; }
71 { const $var: usize = 3; $body; }
72 { const $var: usize = 2; $body; }
73 { const $var: usize = 1; $body; }
74 { const $var: usize = 0; $body; }
75 };
76}
77
78#[cfg(feature = "no_unroll")]
79macro_rules! unroll8_rev {
80 ($var:ident, $body:block) => {
81 for $var in (0..8).rev() $body
82 }
83}
84
85macro_rules! impl_threefish(
86 (
87 $name:ident, $rounds:expr, $n_w:expr, $block_size:ty,
88 $rot:expr, $perm:expr
89 ) => (
90
91 #[derive(Clone, Copy)]
92 pub struct $name {
93 sk: [[u64; $n_w]; $rounds / 4 + 1]
94 }
95
96 impl $name {
97 pub fn with_tweak(key: &GenericArray<u8, $block_size>, tweak0: u64, tweak1: u64) -> $name {
98 let mut k = [0u64; $n_w + 1];
99 read_u64v_le(&mut k[..$n_w], key);
100 k[$n_w] = k[..$n_w].iter().fold(C240, BitXor::bitxor);
101
102 let t = [tweak0, tweak1, tweak0 ^ tweak1];
103 let mut sk = [[0u64; $n_w]; $rounds / 4 + 1];
104 for s in 0..=($rounds / 4) {
105 for i in 0..$n_w {
106 sk[s][i] = k[(s + i) % ($n_w + 1)];
107 if i == $n_w - 3 {
108 sk[s][i] = sk[s][i].wrapping_add(t[s % 3]);
109 } else if i == $n_w - 2 {
110 sk[s][i] = sk[s][i].wrapping_add(t[(s + 1) % 3]);
111 } else if i == $n_w - 1 {
112 sk[s][i] = sk[s][i].wrapping_add(s as u64);
113 }
114 }
115 }
116
117 $name { sk }
118 }
119 }
120
121 impl NewBlockCipher for $name {
122 type KeySize = $block_size;
123
124 fn new(key: &GenericArray<u8, $block_size>) -> $name {
125 Self::with_tweak(key, 0, 0)
126 }
127 }
128
129 impl BlockCipher for $name {
130 type BlockSize = $block_size;
131 type ParBlocks = U1;
132
133 fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>)
134 {
135 let mut v = [0u64; $n_w];
136 read_u64v_le(&mut v, block);
137
138 for i in 0..$rounds/8 {
139 unroll8!(d, {
140 let v_tmp = v.clone();
141 for j in 0..($n_w / 2) {
142 let (v0, v1) = (v_tmp[2 * j], v_tmp[2 * j + 1]);
143 let (e0, e1) =
144 if d % 4 == 0 {
145 (v0.wrapping_add(self.sk[2 * i + d / 4][2 * j]),
146 v1.wrapping_add(self.sk[2 * i + d / 4][2 * j + 1]))
147 } else {
148 (v0, v1)
149 };
150 let r = $rot[d % 8][j];
151 let (f0, f1) = mix(r, (e0, e1));
152 let (pi0, pi1) =
153 ($perm[2 * j], $perm[2 * j + 1]);
154 v[pi0] = f0;
155 v[pi1] = f1;
156 }
157 });
158 }
159
160 for i in 0..$n_w {
161 v[i] = v[i].wrapping_add(self.sk[$rounds / 4][i]);
162 }
163
164 write_u64v_le(block, &v[..]);
165 }
166
167 fn decrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>)
168 {
169 let mut v = [0u64; $n_w];
170 read_u64v_le(&mut v, &block[..]);
171
172 for i in 0..$n_w {
173 v[i] = v[i].wrapping_sub(self.sk[$rounds / 4][i]);
174 }
175
176 for i in (0..$rounds/8).rev() {
177 unroll8_rev!(d, {
178 let v_tmp = v.clone();
179 for j in 0..($n_w / 2) {
180 let (inv_pi0, inv_pi1) = ($perm[2 * j], $perm[2 * j + 1]);
181 let (f0, f1) = (v_tmp[inv_pi0], v_tmp[inv_pi1]);
182 let r = $rot[d % 8][j];
183 let (e0, e1) = inv_mix(r, (f0, f1));
184 let (v0, v1) =
185 if d % 4 == 0 {
186 (e0.wrapping_sub(self.sk[2 * i + d / 4][2 * j]),
187 e1.wrapping_sub(self.sk[2 * i + d / 4][2 * j + 1]))
188 } else {
189 (e0, e1)
190 };
191 v[2 * j] = v0;
192 v[2 * j + 1] = v1;
193 }
194 });
195 }
196
197 write_u64v_le(block, &v[..]);
198 }
199 }
200 )
201);
202
203impl_threefish!(Threefish256, 72, 4, U32, R_256, P_256);
204impl_threefish!(Threefish512, 72, 8, U64, R_512, P_512);
205impl_threefish!(Threefish1024, 80, 16, U128, R_1024, P_1024);
206
207#[cfg(test)]
208mod test {
209 use super::{Threefish1024, Threefish256, Threefish512};
212 use cipher::generic_array::GenericArray;
213 use cipher::{BlockCipher, NewBlockCipher};
214
215 #[test]
216 fn test_256() {
217 let fish = Threefish256::new(&GenericArray::default());
218 let mut block = GenericArray::default();
219 fish.encrypt_block(&mut block);
220 let expected = hex!("84da2a1f8beaee947066ae3e3103f1ad536db1f4a1192495116b9f3ce6133fd8");
221 assert_eq!(&block[..], &expected[..]);
222
223 let fish = Threefish256::new(&GenericArray::default());
224 fish.decrypt_block(&mut block);
225 assert_eq!(&block[..], &[0; 32][..]);
226
227 let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f").into();
228 let fish = Threefish256::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
229 let input = hex!("FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0");
230 let mut block = input.into();
231 fish.encrypt_block(&mut block);
232 let expected = hex!("e0d091ff0eea8fdfc98192e62ed80ad59d865d08588df476657056b5955e97df");
233 assert_eq!(&block[..], &expected[..]);
234
235 let fish = Threefish256::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
236 fish.decrypt_block(&mut block);
237 assert_eq!(&block[..], &input[..]);
238 }
239
240 #[test]
241 fn test_512() {
242 let fish = Threefish512::new(&GenericArray::default());
243 let mut block = GenericArray::default();
244 fish.encrypt_block(&mut block);
245 let expected = hex!(
246 "
247 b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b
248 7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"
249 );
250 assert_eq!(&block[..], &expected[..]);
251
252 let fish = Threefish512::new(&GenericArray::default());
253 fish.decrypt_block(&mut block);
254 assert_eq!(&block[..], &[0; 64][..]);
255
256 let mut key = GenericArray::default();
257 key.copy_from_slice(&hex!(
258 "
259 101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f
260 303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
261 ));
262 let fish = Threefish512::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
263 let mut block = GenericArray::default();
264 let input = hex!(
265 "
266 fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0
267 dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0"
268 );
269 block.copy_from_slice(&input);
270 fish.encrypt_block(&mut block);
271 let expected = hex!(
272 "
273 e304439626d45a2cb401cad8d636249a6338330eb06d45dd8b36b90e97254779
274 272a0a8d99463504784420ea18c9a725af11dffea10162348927673d5c1caf3d"
275 );
276 assert_eq!(&block[..], &expected[..]);
277
278 let fish = Threefish512::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
279 fish.decrypt_block(&mut block);
280 assert_eq!(&block[..], &input[..]);
281 }
282
283 #[test]
284 fn test_1024() {
285 let fish = Threefish1024::new(&GenericArray::default());
286 let mut block = GenericArray::default();
287 fish.encrypt_block(&mut block);
288 let expected = hex!(
289 "
290 f05c3d0a3d05b304f785ddc7d1e036015c8aa76e2f217b06c6e1544c0bc1a90d
291 f0accb9473c24e0fd54fea68057f43329cb454761d6df5cf7b2e9b3614fbd5a2
292 0b2e4760b40603540d82eabc5482c171c832afbe68406bc39500367a592943fa
293 9a5b4a43286ca3c4cf46104b443143d560a4b230488311df4feef7e1dfe8391e"
294 );
295 assert_eq!(&block[..], &expected[..]);
296
297 let fish = Threefish1024::new(&GenericArray::default());
298 fish.decrypt_block(&mut block);
299 assert_eq!(&block[..], &[0; 128][..]);
300
301 let mut key = GenericArray::default();
302 key.copy_from_slice(&hex!(
303 "
304 101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f
305 303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
306 505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f
307 707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f"
308 ));
309 let fish = Threefish1024::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
310 let mut block = GenericArray::default();
311 let input = hex!(
312 "
313 fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0
314 dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0
315 bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0
316 9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180"
317 );
318 block.copy_from_slice(&input);
319 fish.encrypt_block(&mut block);
320 let expected = hex!(
321 "
322 a6654ddbd73cc3b05dd777105aa849bce49372eaaffc5568d254771bab85531c
323 94f780e7ffaae430d5d8af8c70eebbe1760f3b42b737a89cb363490d670314bd
324 8aa41ee63c2e1f45fbd477922f8360b388d6125ea6c7af0ad7056d01796e90c8
325 3313f4150a5716b30ed5f569288ae974ce2b4347926fce57de44512177dd7cde"
326 );
327 assert_eq!(&block[..], &expected[..]);
328
329 let fish = Threefish1024::with_tweak(&key, 0x0706050403020100, 0x0f0e0d0c0b0a0908);
330 fish.decrypt_block(&mut block);
331 assert_eq!(&block[..], &input[..]);
332 }
333}