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}