Skip to main content

cryptography/ciphers/
simon.rs

1//! Simon family of lightweight block ciphers.
2//!
3//! Implemented from "The SIMON and SPECK Families of Lightweight Block Ciphers"
4//! (Beaulieu et al., NSA, 2013), §3 and Appendix B.  All 10 variants.
5//!
6//! # Byte conventions
7//!
8//! **Block** — two words *(x ∥ y)* laid out in little-endian word order with x
9//! first.  x is the "left" word in the paper's Feistel diagram — the operand
10//! of the nonlinear function f.
11//!
12//! **Key** — m words *(k₀ ∥ ℓ₀ ∥ … ∥ ℓ_{m−2})* in little-endian word order,
13//! k₀ first.  This matches the C reference-implementation convention.
14//!
15//! # Naming
16//!
17//! `Simon{B}_{K}` denotes a B-bit block with a K-bit key, e.g. `Simon64_128`.
18//!
19//! # Test vectors
20//!
21//! Known-answer tests use Appendix B of the 2013 paper.
22
23use super::simon_speck_util::{load_le, rotl, rotr, store_le};
24
25// ─────────────────────────────────────────────────────────────────────────────
26// Z sequences — Table 3.2
27//
28// WHY they exist: without a varying constant, the key schedule recurrence
29//   k_i = ∼k_{i−m} ⊕ tmp
30// produces identical round keys whenever all master-key words are equal (e.g.
31// an all-zero key yields all-zero round keys).  Injecting a different bit each
32// round — drawn from a pseudo-random sequence — breaks that symmetry and
33// prevents slide and related-key attacks that exploit a degenerate schedule.
34//
35// WHAT they are: five binary sequences of period 62, tabulated directly in
36// the paper (Table 3.2).  The paper states they were produced by binary LFSRs
37// with primitive feedback polynomials, but does not list those polynomials;
38// the sequences are reproduced verbatim from the NSA Python reference
39// implementation (2013).
40//
41// HOW to access: bit i of sequence z_j is  (Z[j] >> (i % 62)) & 1  (LSB = bit 0).
42// The schedule uses  i' = (round_index − m)  so that the first key-schedule
43// step draws Z bit 0, the next draws bit 1, and so on, cycling every 62 steps.
44// ─────────────────────────────────────────────────────────────────────────────
45
46const Z: [u64; 5] = [
47    0b01_1001_1100_0011_0101_0010_0010_1111_1011_0011_1000_0110_1010_0100_0101_1111,
48    0b01_0110_1000_0110_0100_1111_1011_1000_1010_1101_0000_1100_1001_1111_0111_0001,
49    0b11_0011_0110_1001_1111_1000_1000_0101_0001_1001_0010_1100_0000_1110_1111_0101,
50    0b11_1100_0010_1100_1110_0101_0001_0010_0000_0111_1010_0110_0011_0101_1101_1011,
51    0b11_1101_1100_1001_0100_1100_0011_1010_0000_0100_0110_1101_0110_0111_1000_1011,
52];
53
54// ─────────────────────────────────────────────────────────────────────────────
55// Key expansion — §3
56//
57// Initial words k₀ … k_{m-1} come from the key bytes (k₀ first, LE).
58// For i = m … T-1:
59//
60//   tmp  = S⁻³(k_{i-1})              right-rotate by 3
61//   if m = 4: tmp ⊕= k_{i-3}
62//   tmp ⊕= S⁻¹(tmp)                  applies (I ⊕ S⁻¹)
63//   k_i  = ∼3 ⊕ zⱼ[(i−m) mod 62] ⊕ k_{i-m} ⊕ tmp
64// ─────────────────────────────────────────────────────────────────────────────
65
66fn simon_expand(key: &[u8], n: u32, m: usize, t: usize, z_idx: usize, mask: u64, rk: &mut [u64]) {
67    let wb = (n / 8) as usize;
68    for i in 0..m {
69        rk[i] = load_le(&key[i * wb..(i + 1) * wb]);
70    }
71    for i in m..t {
72        let mut tmp = rotr(rk[i - 1], 3, n, mask);
73        if m == 4 {
74            tmp ^= rk[i - 3];
75        }
76        tmp ^= rotr(tmp, 1, n, mask);
77        let z_bit = (Z[z_idx] >> ((i - m) % 62)) & 1;
78        rk[i] = (!rk[i - m] ^ tmp ^ z_bit ^ 3) & mask;
79    }
80}
81
82// ─────────────────────────────────────────────────────────────────────────────
83// Block cipher core
84//
85// Round function (Figure 3.3):
86//   f(x) = (S¹x & S⁸x) ⊕ S²x
87//
88// Encrypt: for each round key k:
89//   (x, y) ← (k ⊕ f(x) ⊕ y,  x)
90//
91// Decrypt: same step applied in reverse round order using the inverse:
92//   given post-round (x, y), the pre-round values are (y,  k ⊕ f(y) ⊕ x)
93// ─────────────────────────────────────────────────────────────────────────────
94
95fn simon_enc(block: &mut [u8], rk: &[u64], n: u32, mask: u64) {
96    let wb = (n / 8) as usize;
97    let mut x = load_le(&block[0..wb]);
98    let mut y = load_le(&block[wb..2 * wb]);
99    for &k in rk {
100        let t = x;
101        x = y ^ (rotl(x, 1, n, mask) & rotl(x, 8, n, mask)) ^ rotl(x, 2, n, mask) ^ k;
102        y = t;
103    }
104    store_le(x, &mut block[0..wb]);
105    store_le(y, &mut block[wb..2 * wb]);
106}
107
108fn simon_dec(block: &mut [u8], rk: &[u64], n: u32, mask: u64) {
109    let wb = (n / 8) as usize;
110    let mut x = load_le(&block[0..wb]);
111    let mut y = load_le(&block[wb..2 * wb]);
112    for &k in rk.iter().rev() {
113        let t = y;
114        y = x ^ (rotl(y, 1, n, mask) & rotl(y, 8, n, mask)) ^ rotl(y, 2, n, mask) ^ k;
115        x = t;
116    }
117    store_le(x, &mut block[0..wb]);
118    store_le(y, &mut block[wb..2 * wb]);
119}
120
121// ─────────────────────────────────────────────────────────────────────────────
122// Public API — one struct per variant (Table 3.1)
123//
124// Macro arguments:
125//   $Name     — struct identifier
126//   $n        — word size in bits
127//   $m        — number of key words
128//   $T        — number of rounds (literal, also used as array size)
129//   $z        — Z-sequence index (0–4)
130//   $mask     — (1 << $n) - 1
131//   $key_len  — key length in bytes = ($n / 8) * $m
132//   $blk_len  — block length in bytes = ($n / 8) * 2
133// ─────────────────────────────────────────────────────────────────────────────
134
135macro_rules! simon_variant {
136    ($Name:ident, $n:expr, $m:expr, $T:literal, $z:expr, $mask:expr,
137     $key_len:literal, $blk_len:literal) => {
138        pub struct $Name {
139            round_keys: [u64; $T],
140        }
141        impl $Name {
142            /// Expand the paper-defined master key into this variant's round keys.
143            pub fn new(key: &[u8; $key_len]) -> Self {
144                let mut rk = [0u64; $T];
145                simon_expand(key, $n, $m, $T, $z, $mask, &mut rk);
146                Self { round_keys: rk }
147            }
148            /// Expand the key and then wipe the caller-owned key buffer.
149            pub fn new_wiping(key: &mut [u8; $key_len]) -> Self {
150                // Mirrors `new`, but clears the caller-owned key bytes after
151                // expansion so only the internal round keys remain live.
152                let out = Self::new(key);
153                crate::ct::zeroize_slice(key.as_mut_slice());
154                out
155            }
156            /// Encrypt one block using the already-expanded round keys.
157            pub fn encrypt_block(&self, block: &[u8; $blk_len]) -> [u8; $blk_len] {
158                let mut out = *block;
159                simon_enc(&mut out, &self.round_keys, $n, $mask);
160                out
161            }
162            /// Decrypt one block using the same round keys in reverse order.
163            pub fn decrypt_block(&self, block: &[u8; $blk_len]) -> [u8; $blk_len] {
164                let mut out = *block;
165                simon_dec(&mut out, &self.round_keys, $n, $mask);
166                out
167            }
168        }
169        impl crate::BlockCipher for $Name {
170            const BLOCK_LEN: usize = $blk_len;
171            fn encrypt(&self, block: &mut [u8]) {
172                let arr: &[u8; $blk_len] = (&*block).try_into().expect("wrong block length");
173                block.copy_from_slice(&self.encrypt_block(arr));
174            }
175            fn decrypt(&self, block: &mut [u8]) {
176                let arr: &[u8; $blk_len] = (&*block).try_into().expect("wrong block length");
177                block.copy_from_slice(&self.decrypt_block(arr));
178            }
179        }
180        impl Drop for $Name {
181            fn drop(&mut self) {
182                // SIMON already avoids table lookups; this handles the
183                // remaining concern of clearing stored round keys.
184                crate::ct::zeroize_slice(self.round_keys.as_mut_slice());
185            }
186        }
187    };
188}
189
190// All parameters transcribed from Table 3.1 of the 2013 paper.
191// Each row: (n=word bits, m=key words, T=rounds, z=Z-seq index).
192// T is ALSO the compile-time array size for round_keys — a wrong value
193// silently produces a wrong cipher, so each row cites the paper directly.
194// The KAT vectors in the tests below provide a second, independent check.
195//
196//                           n    m    T    z   mask                      key  blk   paper §T
197simon_variant!(Simon32_64,  16,  4,  32,  0,  0xffff_u64,               8,  4); // Table 3.1 T=32
198simon_variant!(Simon48_72,  24,  3,  36,  0,  0xff_ffff_u64,            9,  6); // Table 3.1 T=36
199simon_variant!(Simon48_96,  24,  4,  36,  1,  0xff_ffff_u64,           12,  6); // Table 3.1 T=36
200simon_variant!(Simon64_96,  32,  3,  42,  2,  0xffff_ffff_u64,         12,  8); // Table 3.1 T=42
201simon_variant!(Simon64_128, 32,  4,  44,  3,  0xffff_ffff_u64,         16,  8); // Table 3.1 T=44
202simon_variant!(Simon96_96,  48,  2,  52,  2,  0xffff_ffff_ffff_u64,   12, 12); // Table 3.1 T=52
203simon_variant!(Simon96_144, 48,  3,  54,  3,  0xffff_ffff_ffff_u64,   18, 12); // Table 3.1 T=54
204simon_variant!(Simon128_128, 64, 2,  68,  2,  u64::MAX,                16, 16); // Table 3.1 T=68
205simon_variant!(Simon128_192, 64, 3,  69,  3,  u64::MAX,                24, 16); // Table 3.1 T=69
206simon_variant!(Simon128_256, 64, 4,  72,  4,  u64::MAX,                32, 16); // Table 3.1 T=72
207
208// ─────────────────────────────────────────────────────────────────────────────
209// Tests — known-answer vectors from Appendix B of the 2013 paper;
210//         all other variants verified by encrypt→decrypt roundtrip.
211//
212// Block bytes: (x ∥ y) little-endian, x first.
213// Key bytes:   (k₀ ∥ ℓ₀ ∥ … ∥ ℓ_{m-2}) little-endian, k₀ first.
214//
215// Example derivation for Simon 32/64:
216//   Paper words: k₃k₂k₁k₀ = 0x1918 1110 0908 0100
217//   k₀ = 0x0100 → LE bytes 00 01; …; k₃ = 0x1918 → LE bytes 18 19
218//   Key bytes: 00 01 08 09 10 11 18 19
219//   PT: x = 0x6565 → 65 65;  y = 0x6877 → 77 68  (LE)
220//   CT: x = 0xc69b → 9b c6;  y = 0xe9bb → bb e9  (LE)
221// ─────────────────────────────────────────────────────────────────────────────
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    fn parse<const N: usize>(s: &str) -> [u8; N] {
228        let v: Vec<u8> = (0..s.len())
229            .step_by(2)
230            .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
231            .collect();
232        v.try_into().unwrap()
233    }
234
235    // ── Simon 32/64 — Appendix B ─────────────────────────────────────────────
236    // Key words (k₃,k₂,k₁,k₀) = (0x1918, 0x1110, 0x0908, 0x0100).
237    // PT (x,y) = (0x6565, 0x6877).  CT (x,y) = (0xc69b, 0xe9bb).
238
239    #[test]
240    fn simon32_64_kat() {
241        let key: [u8; 8] = parse("0001080910111819");
242        let pt: [u8; 4] = parse("65657768");
243        let ct: [u8; 4] = parse("9bc6bbe9");
244        let c = Simon32_64::new(&key);
245        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
246        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
247    }
248
249    // ── Simon 64/128 — Appendix B ────────────────────────────────────────────
250    // Key words (k₃…k₀) = (0x1b1a1918, 0x13121110, 0x0b0a0908, 0x03020100).
251    // PT (x,y) = (0x656b696c, 0x20646e75).
252    // CT (x,y) = (0x44c8fc20, 0xb9dfa07a).
253
254    #[test]
255    fn simon64_128_kat() {
256        let key: [u8; 16] = parse("0001020308090a0b1011121318191a1b");
257        let pt: [u8; 8] = parse("6c696b65756e6420");
258        let ct: [u8; 8] = parse("20fcc8447aa0dfb9");
259        let c = Simon64_128::new(&key);
260        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
261        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
262    }
263
264    // ── Simon 48/72 — Appendix B ─────────────────────────────────────────────
265    // Key (k₂,k₁,k₀) = (0x121110, 0x0a0908, 0x020100).
266    // PT (x,y) = (0x612067, 0x6e696c).  CT (x,y) = (0xdae5ac, 0x292cac).
267
268    #[test]
269    fn simon48_72_kat() {
270        let key: [u8; 9] = parse("00010208090a101112");
271        let pt: [u8; 6] = parse("6720616c696e");
272        let ct: [u8; 6] = parse("ace5daac2c29");
273        let c = Simon48_72::new(&key);
274        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
275        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
276    }
277
278    // ── Simon 48/96 — Appendix B ─────────────────────────────────────────────
279    // Key (k₃..k₀) = (0x1a1918, 0x121110, 0x0a0908, 0x020100).
280    // PT (x,y) = (0x726963, 0x20646e).  CT (x,y) = (0x6e06a5, 0xacf156).
281
282    #[test]
283    fn simon48_96_kat() {
284        let key: [u8; 12] = parse("00010208090a10111218191a");
285        let pt: [u8; 6] = parse("6369726e6420");
286        let ct: [u8; 6] = parse("a5066e56f1ac");
287        let c = Simon48_96::new(&key);
288        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
289        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
290    }
291
292    // ── Simon 64/96 — Appendix B ─────────────────────────────────────────────
293    // Key (k₂,k₁,k₀) = (0x13121110, 0x0b0a0908, 0x03020100).
294    // PT (x,y) = (0x6f722067, 0x6e696c63).  CT (x,y) = (0x5ca2e27f, 0x111a8fc8).
295
296    #[test]
297    fn simon64_96_kat() {
298        let key: [u8; 12] = parse("0001020308090a0b10111213");
299        let pt: [u8; 8] = parse("6720726f636c696e");
300        let ct: [u8; 8] = parse("7fe2a25cc88f1a11");
301        let c = Simon64_96::new(&key);
302        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
303        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
304    }
305
306    // ── Simon 96/96 — Appendix B ─────────────────────────────────────────────
307    // Key (k₁,k₀) = (0x0d0c0b0a0908, 0x050403020100).
308    // PT (x,y) = (0x2072616c6c69, 0x702065687420).
309    // CT (x,y) = (0x602807a462b4, 0x69063d8ff082).
310
311    #[test]
312    fn simon96_96_kat() {
313        let key: [u8; 12] = parse("00010203040508090a0b0c0d");
314        let pt: [u8; 12] = parse("696c6c617220207468652070");
315        let ct: [u8; 12] = parse("b462a407286082f08f3d0669");
316        let c = Simon96_96::new(&key);
317        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
318        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
319    }
320
321    // ── Simon 96/144 — Appendix B ────────────────────────────────────────────
322    // Key (k₂..k₀) = (0x151413121110, 0x0d0c0b0a0908, 0x050403020100).
323    // PT (x,y) = (0x746168742074, 0x73756420666f).
324    // CT (x,y) = (0xecad1c6c451e, 0x3f59c5db1ae9).
325
326    #[test]
327    fn simon96_144_kat() {
328        let key: [u8; 18] = parse("00010203040508090a0b0c0d101112131415");
329        let pt: [u8; 12] = parse("7420746861746f6620647573");
330        let ct: [u8; 12] = parse("1e456c1cadece91adbc5593f");
331        let c = Simon96_144::new(&key);
332        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
333        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
334    }
335
336    // ── Simon 128/128 — Appendix B ───────────────────────────────────────────
337    // Key (k₁,k₀) = (0x0f0e0d0c0b0a0908, 0x0706050403020100).
338    // PT (x,y) = (0x6373656420737265, 0x6c6c657661727420).
339    // CT (x,y) = (0x49681b1e1e54fe3f, 0x65aa832af84e0bbc).
340
341    #[test]
342    fn simon128_128_kat() {
343        let key: [u8; 16] = parse("000102030405060708090a0b0c0d0e0f");
344        let pt: [u8; 16] = parse("65727320646573632074726176656c6c");
345        let ct: [u8; 16] = parse("3ffe541e1e1b6849bc0b4ef82a83aa65");
346        let c = Simon128_128::new(&key);
347        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
348        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
349    }
350
351    // ── Simon 128/192 — Appendix B ───────────────────────────────────────────
352    // Key (k₂..k₀) = (0x1716151413121110, 0x0f0e0d0c0b0a0908, 0x0706050403020100).
353    // PT (x,y) = (0x206572656874206e, 0x6568772065626972).
354    // CT (x,y) = (0xc4ac61effcdc0d4f, 0x6c9c8d6e2597b85b).
355
356    #[test]
357    fn simon128_192_kat() {
358        let key: [u8; 24] = parse("000102030405060708090a0b0c0d0e0f1011121314151617");
359        let pt: [u8; 16] = parse("6e207468657265207269626520776865");
360        let ct: [u8; 16] = parse("4f0ddcfcef61acc45bb897256e8d9c6c");
361        let c = Simon128_192::new(&key);
362        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
363        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
364    }
365
366    // ── Simon 128/256 — Appendix B ───────────────────────────────────────────
367    // Key (k₃..k₀) = (0x1f1e1d1c1b1a1918, 0x1716151413121110,
368    //                  0x0f0e0d0c0b0a0908, 0x0706050403020100).
369    // PT (x,y) = (0x74206e69206d6f6f, 0x6d69732061207369).
370    // CT (x,y) = (0x8d2b5579afc8a3a0, 0x3bf72a87efe7b868).
371
372    #[test]
373    fn simon128_256_kat() {
374        let key: [u8; 32] =
375            parse("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
376        let pt: [u8; 16] = parse("6f6f6d20696e2074697320612073696d");
377        let ct: [u8; 16] = parse("a0a3c8af79552b8d68b8e7ef872af73b");
378        let c = Simon128_256::new(&key);
379        assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
380        assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
381    }
382}