threefish_cipher/
lib.rs

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    //! tests from NIST submission
210
211    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}