1use crate::ct::zeroize_slice;
16use crate::BlockCipher;
17
18const RHO: u32 = 0x0101_0101;
20const MDS_GF_POLY: u16 = 0x0169;
24const RS_GF_POLY: u16 = 0x014d;
25
26const Q0_T0: [u8; 16] = [8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4];
27const Q0_T1: [u8; 16] = [14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13];
28const Q0_T2: [u8; 16] = [11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1];
29const Q0_T3: [u8; 16] = [13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10];
30
31const Q1_T0: [u8; 16] = [2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5];
32const Q1_T1: [u8; 16] = [1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8];
33const Q1_T2: [u8; 16] = [4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15];
34const Q1_T3: [u8; 16] = [11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10];
35
36const RS: [[u8; 8]; 4] = [
38 [0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E],
39 [0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5],
40 [0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19],
41 [0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03],
42];
43
44const MDS: [[u8; 4]; 4] = [
46 [0x01, 0xEF, 0x5B, 0x5B],
47 [0x5B, 0xEF, 0xEF, 0x01],
48 [0xEF, 0x5B, 0x01, 0xEF],
49 [0xEF, 0x01, 0xEF, 0x5B],
50];
51
52#[inline]
53const fn nibble_lookup(table: &[u8; 16], idx: u8) -> u8 {
54 table[idx as usize]
55}
56
57#[inline]
58const fn ror4(x: u8) -> u8 {
59 ((x >> 1) | ((x & 1) << 3)) & 0x0f
60}
61
62const fn q_perm_const(x: u8, which: usize) -> u8 {
74 let (t0, t1, t2, t3) = if which == 0 {
75 (&Q0_T0, &Q0_T1, &Q0_T2, &Q0_T3)
76 } else {
77 (&Q1_T0, &Q1_T1, &Q1_T2, &Q1_T3)
78 };
79
80 let a0 = x >> 4;
81 let b0 = x & 0x0f;
82 let a1 = a0 ^ b0;
84 let b1 = a0 ^ ror4(b0) ^ ((a0 << 3) & 0x0f);
85 let a2 = nibble_lookup(t0, a1);
87 let b2 = nibble_lookup(t1, b1);
88 let a3 = a2 ^ b2;
90 let b3 = a2 ^ ror4(b2) ^ ((a2 << 3) & 0x0f);
91 let a4 = nibble_lookup(t2, a3);
93 let b4 = nibble_lookup(t3, b3);
94 (b4 << 4) | a4
95}
96
97const fn build_q(which: usize) -> [u8; 256] {
98 let mut out = [0u8; 256];
99 let mut i = 0u8;
100 loop {
101 out[i as usize] = q_perm_const(i, which);
102 if i == u8::MAX {
103 break;
104 }
105 i = i.wrapping_add(1);
106 }
107 out
108}
109
110const Q0: [u8; 256] = build_q(0);
111const Q1: [u8; 256] = build_q(1);
112
113#[inline]
114fn q_perm_ct(x: u8, which: usize) -> u8 {
115 let (t0, t1, t2, t3) = if which == 0 {
116 (&Q0_T0, &Q0_T1, &Q0_T2, &Q0_T3)
117 } else {
118 (&Q1_T0, &Q1_T1, &Q1_T2, &Q1_T3)
119 };
120
121 let a0 = x >> 4;
122 let b0 = x & 0x0f;
123 let a1 = a0 ^ b0;
124 let b1 = a0 ^ ror4(b0) ^ ((a0 << 3) & 0x0f);
125 let a2 = crate::ct::ct_lookup_u8_16(t0, a1);
126 let b2 = crate::ct::ct_lookup_u8_16(t1, b1);
127 let a3 = a2 ^ b2;
128 let b3 = a2 ^ ror4(b2) ^ ((a2 << 3) & 0x0f);
129 let a4 = crate::ct::ct_lookup_u8_16(t2, a3);
130 let b4 = crate::ct::ct_lookup_u8_16(t3, b3);
131 (b4 << 4) | a4
132}
133
134#[inline]
135fn q_perm(x: u8, which: usize, use_ct: bool) -> u8 {
136 if use_ct {
137 q_perm_ct(x, which)
138 } else if which == 0 {
139 Q0[x as usize]
140 } else {
141 Q1[x as usize]
142 }
143}
144
145#[inline]
146fn gf_mul(mut a: u8, mut b: u8, poly: u16) -> u8 {
147 let mut out = 0u8;
148 for _ in 0..8 {
149 let mask = 0u8.wrapping_sub(b & 1);
150 out ^= a & mask;
151 let hi = a & 0x80;
152 a <<= 1;
153 a ^= ((poly & 0xff) as u8) & 0u8.wrapping_sub((hi >> 7) & 1);
154 b >>= 1;
155 }
156 out
157}
158
159fn rs_mds_encode(bytes: [u8; 8]) -> u32 {
160 let mut out = [0u8; 4];
162 let mut row = 0usize;
163 while row < 4 {
164 let mut acc = 0u8;
165 let mut col = 0usize;
166 while col < 8 {
167 acc ^= gf_mul(RS[row][col], bytes[col], RS_GF_POLY);
168 col += 1;
169 }
170 out[row] = acc;
171 row += 1;
172 }
173 u32::from_le_bytes(out)
174}
175
176#[inline]
177fn b(word: u32, idx: usize) -> u8 {
178 ((word >> (idx * 8)) & 0xff) as u8
179}
180
181fn mds_multiply(y: [u8; 4]) -> u32 {
182 let mut out = [0u8; 4];
184 let mut row = 0usize;
185 while row < 4 {
186 let mut acc = 0u8;
187 let mut col = 0usize;
188 while col < 4 {
189 acc ^= gf_mul(MDS[row][col], y[col], MDS_GF_POLY);
190 col += 1;
191 }
192 out[row] = acc;
193 row += 1;
194 }
195 u32::from_le_bytes(out)
196}
197
198fn h(x: u32, l: &[u32; 4], words: usize, use_ct: bool) -> u32 {
199 let mut y = x.to_le_bytes();
200
201 if words == 4 {
204 y[0] = q_perm(y[0], 1, use_ct) ^ b(l[3], 0);
205 y[1] = q_perm(y[1], 0, use_ct) ^ b(l[3], 1);
206 y[2] = q_perm(y[2], 0, use_ct) ^ b(l[3], 2);
207 y[3] = q_perm(y[3], 1, use_ct) ^ b(l[3], 3);
208 }
209 if words >= 3 {
210 y[0] = q_perm(y[0], 1, use_ct) ^ b(l[2], 0);
211 y[1] = q_perm(y[1], 1, use_ct) ^ b(l[2], 1);
212 y[2] = q_perm(y[2], 0, use_ct) ^ b(l[2], 2);
213 y[3] = q_perm(y[3], 0, use_ct) ^ b(l[2], 3);
214 }
215
216 y[0] = q_perm(
220 q_perm(q_perm(y[0], 0, use_ct) ^ b(l[1], 0), 0, use_ct) ^ b(l[0], 0),
221 1,
222 use_ct,
223 );
224 y[1] = q_perm(
225 q_perm(q_perm(y[1], 1, use_ct) ^ b(l[1], 1), 0, use_ct) ^ b(l[0], 1),
226 0,
227 use_ct,
228 );
229 y[2] = q_perm(
230 q_perm(q_perm(y[2], 0, use_ct) ^ b(l[1], 2), 1, use_ct) ^ b(l[0], 2),
231 1,
232 use_ct,
233 );
234 y[3] = q_perm(
235 q_perm(q_perm(y[3], 1, use_ct) ^ b(l[1], 3), 1, use_ct) ^ b(l[0], 3),
236 0,
237 use_ct,
238 );
239
240 mds_multiply(y)
241}
242
243fn expand_key<const N: usize>(key: &[u8; N], use_ct: bool) -> ([u32; 40], [u32; 4], usize) {
244 let words = N / 8;
245
246 let mut me = [0u32; 4];
247 let mut mo = [0u32; 4];
248 let mut s_words = [0u32; 4];
249
250 let mut word_idx = 0usize;
251 while word_idx < words {
252 me[word_idx] = u32::from_le_bytes(key[word_idx * 8..word_idx * 8 + 4].try_into().unwrap());
256 mo[word_idx] =
257 u32::from_le_bytes(key[word_idx * 8 + 4..word_idx * 8 + 8].try_into().unwrap());
258 let chunk: &[u8; 8] = key[word_idx * 8..word_idx * 8 + 8].try_into().unwrap();
259 s_words[words - 1 - word_idx] = rs_mds_encode(*chunk);
260 word_idx += 1;
261 }
262
263 let mut sub = [0u32; 40];
264 let mut subkey_idx = 0usize;
265 while subkey_idx < 20 {
266 let even_input = u32::try_from(2 * subkey_idx).expect("subkey index fits in u32");
269 let odd_input = even_input + 1;
270 let even_g = h(even_input.wrapping_mul(RHO), &me, words, use_ct);
271 let odd_g = h(odd_input.wrapping_mul(RHO), &mo, words, use_ct).rotate_left(8);
272 sub[2 * subkey_idx] = even_g.wrapping_add(odd_g);
273 sub[2 * subkey_idx + 1] = even_g
274 .wrapping_add(odd_g.wrapping_add(odd_g))
275 .rotate_left(9);
276 subkey_idx += 1;
277 }
278
279 (sub, s_words, words)
280}
281
282#[inline]
283fn round_f(
284 x0: u32,
285 x1: u32,
286 subkeys: &[u32; 40],
287 s: &[u32; 4],
288 words: usize,
289 round: usize,
290 use_ct: bool,
291) -> (u32, u32) {
292 let t0 = h(x0, s, words, use_ct);
295 let t1 = h(x1.rotate_left(8), s, words, use_ct);
296 let f0 = t0.wrapping_add(t1).wrapping_add(subkeys[8 + 2 * round]);
297 let f1 = t0
298 .wrapping_add(t1.wrapping_add(t1))
299 .wrapping_add(subkeys[8 + 2 * round + 1]);
300 (f0, f1)
301}
302
303#[derive(Clone, Copy)]
304struct TwofishCore {
305 subkeys: [u32; 40],
306 s: [u32; 4],
307 words: usize,
308 use_ct: bool,
309}
310
311impl TwofishCore {
312 fn new<const N: usize>(key: &[u8; N], use_ct: bool) -> Self {
313 let (subkeys, s, words) = expand_key(key, use_ct);
314 Self {
315 subkeys,
316 s,
317 words,
318 use_ct,
319 }
320 }
321
322 fn encrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
323 let mut x0 = u32::from_le_bytes(block[0..4].try_into().unwrap()) ^ self.subkeys[0];
324 let mut x1 = u32::from_le_bytes(block[4..8].try_into().unwrap()) ^ self.subkeys[1];
325 let mut x2 = u32::from_le_bytes(block[8..12].try_into().unwrap()) ^ self.subkeys[2];
326 let mut x3 = u32::from_le_bytes(block[12..16].try_into().unwrap()) ^ self.subkeys[3];
327
328 let mut round = 0usize;
329 while round < 8 {
330 let (f0, f1) = round_f(
333 x0,
334 x1,
335 &self.subkeys,
336 &self.s,
337 self.words,
338 2 * round,
339 self.use_ct,
340 );
341 x2 = (x2 ^ f0).rotate_right(1);
342 x3 = x3.rotate_left(1) ^ f1;
343
344 let (f0, f1) = round_f(
345 x2,
346 x3,
347 &self.subkeys,
348 &self.s,
349 self.words,
350 2 * round + 1,
351 self.use_ct,
352 );
353 x0 = (x0 ^ f0).rotate_right(1);
354 x1 = x1.rotate_left(1) ^ f1;
355
356 round += 1;
357 }
358
359 let c0 = x2 ^ self.subkeys[4];
360 let c1 = x3 ^ self.subkeys[5];
361 let c2 = x0 ^ self.subkeys[6];
362 let c3 = x1 ^ self.subkeys[7];
363
364 let mut out = [0u8; 16];
365 out[0..4].copy_from_slice(&c0.to_le_bytes());
366 out[4..8].copy_from_slice(&c1.to_le_bytes());
367 out[8..12].copy_from_slice(&c2.to_le_bytes());
368 out[12..16].copy_from_slice(&c3.to_le_bytes());
369 out
370 }
371
372 fn decrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
373 let mut x2 = u32::from_le_bytes(block[0..4].try_into().unwrap()) ^ self.subkeys[4];
374 let mut x3 = u32::from_le_bytes(block[4..8].try_into().unwrap()) ^ self.subkeys[5];
375 let mut x0 = u32::from_le_bytes(block[8..12].try_into().unwrap()) ^ self.subkeys[6];
376 let mut x1 = u32::from_le_bytes(block[12..16].try_into().unwrap()) ^ self.subkeys[7];
377
378 let mut round = 8usize;
379 while round > 0 {
380 round -= 1;
381
382 let (f0, f1) = round_f(
385 x2,
386 x3,
387 &self.subkeys,
388 &self.s,
389 self.words,
390 2 * round + 1,
391 self.use_ct,
392 );
393 x1 = (x1 ^ f1).rotate_right(1);
394 x0 = x0.rotate_left(1) ^ f0;
395
396 let (f0, f1) = round_f(
397 x0,
398 x1,
399 &self.subkeys,
400 &self.s,
401 self.words,
402 2 * round,
403 self.use_ct,
404 );
405 x3 = (x3 ^ f1).rotate_right(1);
406 x2 = x2.rotate_left(1) ^ f0;
407 }
408
409 let p0 = x0 ^ self.subkeys[0];
410 let p1 = x1 ^ self.subkeys[1];
411 let p2 = x2 ^ self.subkeys[2];
412 let p3 = x3 ^ self.subkeys[3];
413
414 let mut out = [0u8; 16];
415 out[0..4].copy_from_slice(&p0.to_le_bytes());
416 out[4..8].copy_from_slice(&p1.to_le_bytes());
417 out[8..12].copy_from_slice(&p2.to_le_bytes());
418 out[12..16].copy_from_slice(&p3.to_le_bytes());
419 out
420 }
421}
422
423macro_rules! define_twofish_type {
424 ($name:ident, $name_ct:ident, $key_len:expr) => {
425 pub struct $name {
426 core: TwofishCore,
427 }
428
429 impl $name {
430 pub fn new(key: &[u8; $key_len]) -> Self {
432 Self {
433 core: TwofishCore::new(key, false),
434 }
435 }
436
437 pub fn new_wiping(key: &mut [u8; $key_len]) -> Self {
439 let out = Self::new(key);
440 zeroize_slice(key);
441 out
442 }
443
444 pub fn encrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
446 self.core.encrypt_block(block)
447 }
448
449 pub fn decrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
451 self.core.decrypt_block(block)
452 }
453 }
454
455 impl BlockCipher for $name {
456 const BLOCK_LEN: usize = 16;
457
458 fn encrypt(&self, block: &mut [u8]) {
459 let arr: &[u8; 16] = (&*block).try_into().expect("wrong block length");
460 let out = self.encrypt_block(arr);
461 block.copy_from_slice(&out);
462 }
463
464 fn decrypt(&self, block: &mut [u8]) {
465 let arr: &[u8; 16] = (&*block).try_into().expect("wrong block length");
466 let out = self.decrypt_block(arr);
467 block.copy_from_slice(&out);
468 }
469 }
470
471 impl Drop for $name {
472 fn drop(&mut self) {
473 zeroize_slice(&mut self.core.subkeys);
474 zeroize_slice(&mut self.core.s);
475 }
476 }
477
478 pub struct $name_ct {
479 core: TwofishCore,
480 }
481
482 impl $name_ct {
483 pub fn new(key: &[u8; $key_len]) -> Self {
485 Self {
486 core: TwofishCore::new(key, true),
487 }
488 }
489
490 pub fn new_wiping(key: &mut [u8; $key_len]) -> Self {
492 let out = Self::new(key);
493 zeroize_slice(key);
494 out
495 }
496
497 pub fn encrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
499 self.core.encrypt_block(block)
500 }
501
502 pub fn decrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {
504 self.core.decrypt_block(block)
505 }
506 }
507
508 impl BlockCipher for $name_ct {
509 const BLOCK_LEN: usize = 16;
510
511 fn encrypt(&self, block: &mut [u8]) {
512 let arr: &[u8; 16] = (&*block).try_into().expect("wrong block length");
513 let out = self.encrypt_block(arr);
514 block.copy_from_slice(&out);
515 }
516
517 fn decrypt(&self, block: &mut [u8]) {
518 let arr: &[u8; 16] = (&*block).try_into().expect("wrong block length");
519 let out = self.decrypt_block(arr);
520 block.copy_from_slice(&out);
521 }
522 }
523
524 impl Drop for $name_ct {
525 fn drop(&mut self) {
526 zeroize_slice(&mut self.core.subkeys);
527 zeroize_slice(&mut self.core.s);
528 }
529 }
530 };
531}
532
533define_twofish_type!(Twofish128, Twofish128Ct, 16);
534define_twofish_type!(Twofish192, Twofish192Ct, 24);
535define_twofish_type!(Twofish256, Twofish256Ct, 32);
536
537pub type Twofish = Twofish128;
538pub type TwofishCt = Twofish128Ct;
539
540#[cfg(test)]
541mod tests {
542 use super::*;
543
544 fn decode_hex<const N: usize>(s: &str) -> [u8; N] {
545 assert_eq!(s.len(), N * 2);
546 let mut out = [0u8; N];
547 let bytes = s.as_bytes();
548 let mut i = 0usize;
549 while i < N {
550 let hi = u8::try_from((bytes[2 * i] as char).to_digit(16).unwrap())
551 .expect("decoded hex nibble fits in u8");
552 let lo = u8::try_from((bytes[2 * i + 1] as char).to_digit(16).unwrap())
553 .expect("decoded hex nibble fits in u8");
554 out[i] = (hi << 4) | lo;
555 i += 1;
556 }
557 out
558 }
559
560 #[test]
561 fn twofish128_zero_kat() {
562 let key = [0u8; 16];
563 let pt = [0u8; 16];
564 let ct = decode_hex::<16>("9F589F5CF6122C32B6BFEC2F2AE8C35A");
565 let fast = Twofish128::new(&key);
566 let slow = Twofish128Ct::new(&key);
567 assert_eq!(fast.encrypt_block(&pt), ct);
568 assert_eq!(slow.encrypt_block(&pt), ct);
569 assert_eq!(fast.decrypt_block(&ct), pt);
570 assert_eq!(slow.decrypt_block(&ct), pt);
571 }
572
573 #[test]
574 fn twofish128_nonzero_kat() {
575 let key = decode_hex::<16>("D491DB16E7B1C39E86CB086B789F5419");
577 let pt = decode_hex::<16>("019F9809DE1711858FAAC3A3BA20FBC3");
578 let ct = decode_hex::<16>("6363977DE839486297E661C6C9D668EB");
579 let fast = Twofish128::new(&key);
580 let slow = Twofish128Ct::new(&key);
581 assert_eq!(fast.encrypt_block(&pt), ct);
582 assert_eq!(slow.encrypt_block(&pt), ct);
583 assert_eq!(fast.decrypt_block(&ct), pt);
584 assert_eq!(slow.decrypt_block(&ct), pt);
585 }
586
587 #[test]
588 fn twofish192_zero_kat() {
589 let key = [0u8; 24];
590 let pt = [0u8; 16];
591 let ct = decode_hex::<16>("EFA71F788965BD4453F860178FC19101");
592 let fast = Twofish192::new(&key);
593 let slow = Twofish192Ct::new(&key);
594 assert_eq!(fast.encrypt_block(&pt), ct);
595 assert_eq!(slow.encrypt_block(&pt), ct);
596 assert_eq!(fast.decrypt_block(&ct), pt);
597 assert_eq!(slow.decrypt_block(&ct), pt);
598 }
599
600 #[test]
601 fn twofish192_nonzero_kat() {
602 let key = decode_hex::<24>("88B2B2706B105E36B446BB6D731A1E88EFA71F788965BD44");
604 let pt = decode_hex::<16>("39DA69D6BA4997D585B6DC073CA341B2");
605 let ct = decode_hex::<16>("182B02D81497EA45F9DAACDC29193A65");
606 let fast = Twofish192::new(&key);
607 let slow = Twofish192Ct::new(&key);
608 assert_eq!(fast.encrypt_block(&pt), ct);
609 assert_eq!(slow.encrypt_block(&pt), ct);
610 assert_eq!(fast.decrypt_block(&ct), pt);
611 assert_eq!(slow.decrypt_block(&ct), pt);
612 }
613
614 #[test]
615 fn twofish256_zero_kat() {
616 let key = [0u8; 32];
617 let pt = [0u8; 16];
618 let ct = decode_hex::<16>("57FF739D4DC92C1BD7FC01700CC8216F");
619 let fast = Twofish256::new(&key);
620 let slow = Twofish256Ct::new(&key);
621 assert_eq!(fast.encrypt_block(&pt), ct);
622 assert_eq!(slow.encrypt_block(&pt), ct);
623 assert_eq!(fast.decrypt_block(&ct), pt);
624 assert_eq!(slow.decrypt_block(&ct), pt);
625 }
626
627 #[test]
628 fn twofish256_nonzero_kat() {
629 let key =
631 decode_hex::<32>("D43BB7556EA32E46F2A282B7D45B4E0D57FF739D4DC92C1BD7FC01700CC8216F");
632 let pt = decode_hex::<16>("90AFE91BB288544F2C32DC239B2635E6");
633 let ct = decode_hex::<16>("6CB4561C40BF0A9705931CB6D408E7FA");
634 let fast = Twofish256::new(&key);
635 let slow = Twofish256Ct::new(&key);
636 assert_eq!(fast.encrypt_block(&pt), ct);
637 assert_eq!(slow.encrypt_block(&pt), ct);
638 assert_eq!(fast.decrypt_block(&ct), pt);
639 assert_eq!(slow.decrypt_block(&ct), pt);
640 }
641
642 #[test]
643 fn q_tables_match_ct_path() {
644 let mut i = 0usize;
645 while i < 256 {
646 let idx = u8::try_from(i).expect("Q table index fits in u8");
647 assert_eq!(Q0[i], q_perm_ct(idx, 0));
648 assert_eq!(Q1[i], q_perm_ct(idx, 1));
649 i += 1;
650 }
651 }
652}