Skip to main content

cryptography/ciphers/
snow3g.rs

1//! SNOW 3G stream cipher core from the ETSI/SAGE v1.1 specification.
2//!
3//! SNOW 3G is the 128-bit stream cipher used underneath 3GPP UEA2/UIA2.
4//! This module implements the raw keystream generator from Document 2
5//! ("SNOW 3G Specification"), not the higher-level UEA2/UIA2 framing.
6
7#[rustfmt::skip]
8const SR: [u8; 256] = [
9    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
10    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
11    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
12    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
13    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
14    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
15    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
16    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
17    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
18    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
19    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
20    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
21    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
22    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
23    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
24    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
25];
26
27#[rustfmt::skip]
28const SQ: [u8; 256] = [
29    0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB,
30    0xE4, 0x8E, 0x48, 0x49, 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2,
31    0xD8, 0xE9, 0xCC, 0xED, 0x40, 0x2F, 0x11, 0x28, 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, 0x1B, 0xB9,
32    0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, 0x07, 0x4B, 0x0E, 0xC1, 0x51, 0xAA, 0x89, 0xD4,
33    0xCA, 0x01, 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, 0x9F, 0x20, 0x4C, 0x64,
34    0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4,
35    0x8D, 0xB0, 0xE5, 0x93, 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA,
36    0xBC, 0x0F, 0x08, 0x52, 0x1D, 0x55, 0x1A, 0xC5, 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, 0x5B, 0x5A,
37    0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, 0x50, 0x8A, 0xB6, 0x62, 0xF5, 0x0A, 0xF8, 0xDC,
38    0x03, 0x3C, 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, 0x81, 0x32, 0xA0, 0x00,
39    0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53,
40    0x63, 0x75, 0x35, 0x2C, 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD,
41    0xD9, 0xC7, 0xAF, 0x6B, 0x54, 0x0B, 0xE0, 0x38, 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, 0x87, 0x9C,
42    0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, 0x74, 0x91, 0xAB, 0x26, 0x61, 0x76, 0x34, 0x2B,
43    0xAD, 0x99, 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, 0x3E, 0x18, 0x10, 0x3A,
44    0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86,
45];
46
47const SR_ANF: [[u128; 2]; 8] = crate::ct::build_byte_sbox_anf(&SR);
48const SQ_ANF: [[u128; 2]; 8] = crate::ct::build_byte_sbox_anf(&SQ);
49
50// ETSI/SAGE Doc 2 defines multiplication/division by alpha in GF(2^8)
51// (reduction polynomial x^8 + x^7 + x^5 + x^3 + 1, encoded as 0xA9 here).
52// These are the four-byte packed coefficients used in the LFSR feedback.
53const MUL_ALPHA: [u32; 256] = build_alpha_table([23, 245, 48, 239]);
54const DIV_ALPHA: [u32; 256] = build_alpha_table([16, 39, 6, 64]);
55const MUL_ALPHA_FACTORS: [u8; 4] = alpha_factors([23, 245, 48, 239]);
56const DIV_ALPHA_FACTORS: [u8; 4] = alpha_factors([16, 39, 6, 64]);
57
58#[inline]
59fn load_be_u32(bytes: &[u8]) -> u32 {
60    let mut word = [0u8; 4];
61    word.copy_from_slice(bytes);
62    u32::from_be_bytes(word)
63}
64
65#[inline]
66const fn mulx(v: u8, c: u8) -> u8 {
67    if (v & 0x80) != 0 {
68        (v << 1) ^ c
69    } else {
70        v << 1
71    }
72}
73
74#[inline]
75fn mulx_ct(v: u8, c: u8) -> u8 {
76    let hi = 0u8.wrapping_sub(v >> 7);
77    (v << 1) ^ (c & hi)
78}
79
80#[inline]
81const fn mulx_pow(mut v: u8, i: u8, c: u8) -> u8 {
82    let mut n = 0;
83    while n < i {
84        v = mulx(v, c);
85        n += 1;
86    }
87    v
88}
89
90const fn build_alpha_table(pows: [u8; 4]) -> [u32; 256] {
91    let mut table = [0u32; 256];
92    let mut i = 0;
93    while i < 256 {
94        let c = i as u8;
95        table[i] = u32::from_be_bytes([
96            mulx_pow(c, pows[0], 0xA9),
97            mulx_pow(c, pows[1], 0xA9),
98            mulx_pow(c, pows[2], 0xA9),
99            mulx_pow(c, pows[3], 0xA9),
100        ]);
101        i += 1;
102    }
103    table
104}
105
106const fn alpha_factors(pows: [u8; 4]) -> [u8; 4] {
107    [
108        mulx_pow(1, pows[0], 0xA9),
109        mulx_pow(1, pows[1], 0xA9),
110        mulx_pow(1, pows[2], 0xA9),
111        mulx_pow(1, pows[3], 0xA9),
112    ]
113}
114
115#[inline]
116fn gf_mul_const_ct(mut value: u8, mut factor: u8, poly: u8) -> u8 {
117    let mut out = 0u8;
118    let mut i = 0u8;
119    while i < 8 {
120        let bit_mask = 0u8.wrapping_sub(factor & 1);
121        out ^= value & bit_mask;
122        value = mulx_ct(value, poly);
123        factor >>= 1;
124        i = i.wrapping_add(1);
125    }
126    out
127}
128
129#[inline]
130fn alpha_word_ct(input: u8, factors: [u8; 4]) -> u32 {
131    u32::from_be_bytes([
132        gf_mul_const_ct(input, factors[0], 0xA9),
133        gf_mul_const_ct(input, factors[1], 0xA9),
134        gf_mul_const_ct(input, factors[2], 0xA9),
135        gf_mul_const_ct(input, factors[3], 0xA9),
136    ])
137}
138
139#[inline]
140fn sbox_eval(coeffs: &[[u128; 2]; 8], input: u8) -> u8 {
141    crate::ct::eval_byte_sbox(coeffs, input)
142}
143
144#[inline]
145fn s1<const CT: bool>(w: u32) -> u32 {
146    let (srw0, srw1, srw2, srw3) = if CT {
147        (
148            sbox_eval(&SR_ANF, (w >> 24) as u8),
149            sbox_eval(&SR_ANF, ((w >> 16) & 0xFF) as u8),
150            sbox_eval(&SR_ANF, ((w >> 8) & 0xFF) as u8),
151            sbox_eval(&SR_ANF, (w & 0xFF) as u8),
152        )
153    } else {
154        (
155            SR[(w >> 24) as usize],
156            SR[((w >> 16) & 0xFF) as usize],
157            SR[((w >> 8) & 0xFF) as usize],
158            SR[(w & 0xFF) as usize],
159        )
160    };
161    let mul = if CT { mulx_ct } else { mulx };
162    let r0 = mul(srw0, 0x1B) ^ srw1 ^ srw2 ^ mul(srw3, 0x1B) ^ srw3;
163    let r1 = mul(srw0, 0x1B) ^ srw0 ^ mul(srw1, 0x1B) ^ srw2 ^ srw3;
164    let r2 = srw0 ^ mul(srw1, 0x1B) ^ srw1 ^ mul(srw2, 0x1B) ^ srw3;
165    let r3 = srw0 ^ srw1 ^ mul(srw2, 0x1B) ^ srw2 ^ mul(srw3, 0x1B);
166    u32::from_be_bytes([r0, r1, r2, r3])
167}
168
169#[inline]
170fn s2<const CT: bool>(w: u32) -> u32 {
171    let (sqw0, sqw1, sqw2, sqw3) = if CT {
172        (
173            sbox_eval(&SQ_ANF, (w >> 24) as u8),
174            sbox_eval(&SQ_ANF, ((w >> 16) & 0xFF) as u8),
175            sbox_eval(&SQ_ANF, ((w >> 8) & 0xFF) as u8),
176            sbox_eval(&SQ_ANF, (w & 0xFF) as u8),
177        )
178    } else {
179        (
180            SQ[(w >> 24) as usize],
181            SQ[((w >> 16) & 0xFF) as usize],
182            SQ[((w >> 8) & 0xFF) as usize],
183            SQ[(w & 0xFF) as usize],
184        )
185    };
186    let mul = if CT { mulx_ct } else { mulx };
187    let r0 = mul(sqw0, 0x69) ^ sqw1 ^ sqw2 ^ mul(sqw3, 0x69) ^ sqw3;
188    let r1 = mul(sqw0, 0x69) ^ sqw0 ^ mul(sqw1, 0x69) ^ sqw2 ^ sqw3;
189    let r2 = sqw0 ^ mul(sqw1, 0x69) ^ sqw1 ^ mul(sqw2, 0x69) ^ sqw3;
190    let r3 = sqw0 ^ sqw1 ^ mul(sqw2, 0x69) ^ sqw2 ^ mul(sqw3, 0x69);
191    u32::from_be_bytes([r0, r1, r2, r3])
192}
193
194struct Snow3gCore {
195    s: [u32; 16],
196    r1: u32,
197    r2: u32,
198    r3: u32,
199}
200
201#[inline]
202fn clock_fsm<const CT: bool>(core: &mut Snow3gCore) -> u32 {
203    let f = core.s[15].wrapping_add(core.r1) ^ core.r2;
204    let r = core.r2.wrapping_add(core.r3 ^ core.s[5]);
205    core.r3 = s2::<CT>(core.r2);
206    core.r2 = s1::<CT>(core.r1);
207    core.r1 = r;
208    f
209}
210
211#[inline]
212fn lfsr_feedback<const CT: bool>(core: &Snow3gCore) -> u32 {
213    let mul_alpha = if CT {
214        alpha_word_ct((core.s[0] >> 24) as u8, MUL_ALPHA_FACTORS)
215    } else {
216        MUL_ALPHA[(core.s[0] >> 24) as usize]
217    };
218    let div_alpha = if CT {
219        alpha_word_ct((core.s[11] & 0xFF) as u8, DIV_ALPHA_FACTORS)
220    } else {
221        DIV_ALPHA[(core.s[11] & 0xFF) as usize]
222    };
223    ((core.s[0] << 8) & 0xFFFF_FF00)
224        ^ mul_alpha
225        ^ core.s[2]
226        ^ ((core.s[11] >> 8) & 0x00FF_FFFF)
227        ^ div_alpha
228}
229
230#[inline]
231fn clock_lfsr<const CT: bool>(core: &mut Snow3gCore, f: Option<u32>) {
232    let mut v = lfsr_feedback::<CT>(core);
233    if let Some(fsm_word) = f {
234        v ^= fsm_word;
235    }
236    core.s.copy_within(1..16, 0);
237    core.s[15] = v;
238}
239
240fn init_core<const CT: bool>(key: &[u8; 16], iv: &[u8; 16]) -> Snow3gCore {
241    let k = [
242        load_be_u32(&key[0..4]),
243        load_be_u32(&key[4..8]),
244        load_be_u32(&key[8..12]),
245        load_be_u32(&key[12..16]),
246    ];
247    let iv = [
248        load_be_u32(&iv[0..4]),
249        load_be_u32(&iv[4..8]),
250        load_be_u32(&iv[8..12]),
251        load_be_u32(&iv[12..16]),
252    ];
253
254    let mut core = Snow3gCore {
255        s: [
256            k[0] ^ 0xFFFF_FFFF,
257            k[1] ^ 0xFFFF_FFFF,
258            k[2] ^ 0xFFFF_FFFF,
259            k[3] ^ 0xFFFF_FFFF,
260            k[0],
261            k[1],
262            k[2],
263            k[3],
264            k[0] ^ 0xFFFF_FFFF,
265            k[1] ^ 0xFFFF_FFFF ^ iv[3],
266            k[2] ^ 0xFFFF_FFFF ^ iv[2],
267            k[3] ^ 0xFFFF_FFFF,
268            k[0] ^ iv[1],
269            k[1],
270            k[2],
271            k[3] ^ iv[0],
272        ],
273        r1: 0,
274        r2: 0,
275        r3: 0,
276    };
277
278    for _ in 0..32 {
279        let f = clock_fsm::<CT>(&mut core);
280        clock_lfsr::<CT>(&mut core, Some(f));
281    }
282
283    let _ = clock_fsm::<CT>(&mut core);
284    clock_lfsr::<CT>(&mut core, None);
285    core
286}
287
288#[inline]
289fn next_word_core<const CT: bool>(core: &mut Snow3gCore) -> u32 {
290    let z = clock_fsm::<CT>(core) ^ core.s[0];
291    clock_lfsr::<CT>(core, None);
292    z
293}
294
295fn fill_core<const CT: bool>(core: &mut Snow3gCore, buf: &mut [u8]) {
296    let mut chunks = buf.chunks_exact_mut(4);
297    for chunk in &mut chunks {
298        let ks = next_word_core::<CT>(core).to_be_bytes();
299        for (b, k) in chunk.iter_mut().zip(ks.iter()) {
300            *b ^= k;
301        }
302    }
303    let rem = chunks.into_remainder();
304    if !rem.is_empty() {
305        let ks = next_word_core::<CT>(core).to_be_bytes();
306        for (b, k) in rem.iter_mut().zip(ks.iter()) {
307            *b ^= k;
308        }
309    }
310}
311
312/// SNOW 3G stream cipher (ETSI/SAGE v1.1).
313pub struct Snow3g {
314    core: Snow3gCore,
315}
316
317/// SNOW 3G constant-time software path.
318///
319/// `Snow3gCt` preserves the same LFSR and FSM structure as [`Snow3g`] but
320/// replaces secret-indexed S-box and alpha-table reads with constant-time
321/// evaluators and fixed-scan lookups.
322pub struct Snow3gCt {
323    core: Snow3gCore,
324}
325
326impl Snow3g {
327    /// Construct SNOW 3G from a 128-bit key and 128-bit IV.
328    #[must_use]
329    pub fn new(key: &[u8; 16], iv: &[u8; 16]) -> Self {
330        Self {
331            core: init_core::<false>(key, iv),
332        }
333    }
334
335    /// Construct and wipe the caller-provided key and IV buffers.
336    pub fn new_wiping(key: &mut [u8; 16], iv: &mut [u8; 16]) -> Self {
337        let out = Self::new(key, iv);
338        crate::ct::zeroize_slice(key.as_mut_slice());
339        crate::ct::zeroize_slice(iv.as_mut_slice());
340        out
341    }
342
343    /// Generate the next 32-bit keystream word.
344    pub fn next_word(&mut self) -> u32 {
345        next_word_core::<false>(&mut self.core)
346    }
347
348    /// XOR `buf` with keystream bytes in big-endian word order.
349    pub fn fill(&mut self, buf: &mut [u8]) {
350        fill_core::<false>(&mut self.core, buf);
351    }
352}
353
354impl Snow3gCt {
355    /// Construct SNOW 3G constant-time software path from a 128-bit key and IV.
356    #[must_use]
357    pub fn new(key: &[u8; 16], iv: &[u8; 16]) -> Self {
358        Self {
359            core: init_core::<true>(key, iv),
360        }
361    }
362
363    /// Construct and wipe the caller-provided key and IV buffers.
364    pub fn new_wiping(key: &mut [u8; 16], iv: &mut [u8; 16]) -> Self {
365        let out = Self::new(key, iv);
366        crate::ct::zeroize_slice(key.as_mut_slice());
367        crate::ct::zeroize_slice(iv.as_mut_slice());
368        out
369    }
370
371    /// Generate the next 32-bit keystream word.
372    pub fn next_word(&mut self) -> u32 {
373        next_word_core::<true>(&mut self.core)
374    }
375
376    /// XOR `buf` with keystream bytes in big-endian word order.
377    pub fn fill(&mut self, buf: &mut [u8]) {
378        fill_core::<true>(&mut self.core, buf);
379    }
380}
381
382impl Drop for Snow3g {
383    fn drop(&mut self) {
384        crate::ct::zeroize_slice(self.core.s.as_mut_slice());
385        self.core.r1 = 0;
386        self.core.r2 = 0;
387        self.core.r3 = 0;
388    }
389}
390
391impl Drop for Snow3gCt {
392    fn drop(&mut self) {
393        crate::ct::zeroize_slice(self.core.s.as_mut_slice());
394        self.core.r1 = 0;
395        self.core.r2 = 0;
396        self.core.r3 = 0;
397    }
398}
399
400#[cfg(test)]
401mod tests {
402    use super::*;
403
404    fn xorshift64(state: &mut u64) -> u64 {
405        let mut x = *state;
406        x ^= x << 13;
407        x ^= x >> 7;
408        x ^= x << 17;
409        *state = x;
410        x
411    }
412
413    fn fill_bytes(state: &mut u64, out: &mut [u8]) {
414        for chunk in out.chunks_mut(8) {
415            let bytes = xorshift64(state).to_le_bytes();
416            let n = chunk.len();
417            chunk.copy_from_slice(&bytes[..n]);
418        }
419    }
420
421    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
422    struct TraceRow {
423        s0: u32,
424        s2: u32,
425        s5: u32,
426        s11: u32,
427        s15: u32,
428        r1: u32,
429        r2: u32,
430        r3: u32,
431    }
432
433    fn trace_row(core: &Snow3gCore) -> TraceRow {
434        TraceRow {
435            s0: core.s[0],
436            s2: core.s[2],
437            s5: core.s[5],
438            s11: core.s[11],
439            s15: core.s[15],
440            r1: core.r1,
441            r2: core.r2,
442            r3: core.r3,
443        }
444    }
445
446    fn initial_lfsr_from_key_iv(key: &[u8; 16], iv: &[u8; 16]) -> [u32; 16] {
447        let k = [
448            load_be_u32(&key[0..4]),
449            load_be_u32(&key[4..8]),
450            load_be_u32(&key[8..12]),
451            load_be_u32(&key[12..16]),
452        ];
453        let iv = [
454            load_be_u32(&iv[0..4]),
455            load_be_u32(&iv[4..8]),
456            load_be_u32(&iv[8..12]),
457            load_be_u32(&iv[12..16]),
458        ];
459        [
460            k[0] ^ 0xFFFF_FFFF,
461            k[1] ^ 0xFFFF_FFFF,
462            k[2] ^ 0xFFFF_FFFF,
463            k[3] ^ 0xFFFF_FFFF,
464            k[0],
465            k[1],
466            k[2],
467            k[3],
468            k[0] ^ 0xFFFF_FFFF,
469            k[1] ^ 0xFFFF_FFFF ^ iv[3],
470            k[2] ^ 0xFFFF_FFFF ^ iv[2],
471            k[3] ^ 0xFFFF_FFFF,
472            k[0] ^ iv[1],
473            k[1],
474            k[2],
475            k[3] ^ iv[0],
476        ]
477    }
478
479    #[derive(Clone, Copy)]
480    struct OfficialTraceCase {
481        key: [u8; 16],
482        iv: [u8; 16],
483        initial_lfsr: [u32; 16],
484        init_rows: [TraceRow; 8],
485        final_lfsr: [u32; 16],
486        final_fsm: [u32; 3],
487        keystream_rows: [TraceRow; 3],
488        outputs: [u32; 2],
489    }
490
491    fn assert_official_trace<const CT: bool>(case: &OfficialTraceCase) {
492        assert_eq!(
493            initial_lfsr_from_key_iv(&case.key, &case.iv),
494            case.initial_lfsr
495        );
496
497        let mut core = Snow3gCore {
498            s: case.initial_lfsr,
499            r1: 0,
500            r2: 0,
501            r3: 0,
502        };
503
504        assert_eq!(trace_row(&core), case.init_rows[0], "initial row");
505        for (i, expected) in case.init_rows.iter().enumerate().skip(1) {
506            let f = clock_fsm::<CT>(&mut core);
507            clock_lfsr::<CT>(&mut core, Some(f));
508            assert_eq!(trace_row(&core), *expected, "init row {i}");
509        }
510
511        for _ in (case.init_rows.len() - 1)..32 {
512            let f = clock_fsm::<CT>(&mut core);
513            clock_lfsr::<CT>(&mut core, Some(f));
514        }
515
516        assert_eq!(core.s, case.final_lfsr, "final LFSR after init");
517        assert_eq!(
518            [core.r1, core.r2, core.r3],
519            case.final_fsm,
520            "final FSM after init"
521        );
522
523        let _ = clock_fsm::<CT>(&mut core);
524        clock_lfsr::<CT>(&mut core, None);
525        assert_eq!(trace_row(&core), case.keystream_rows[0], "keystream row 0");
526
527        let z1 = next_word_core::<CT>(&mut core);
528        assert_eq!(z1, case.outputs[0], "z1");
529        assert_eq!(trace_row(&core), case.keystream_rows[1], "keystream row 1");
530
531        let z2 = next_word_core::<CT>(&mut core);
532        assert_eq!(z2, case.outputs[1], "z2");
533        assert_eq!(trace_row(&core), case.keystream_rows[2], "keystream row 2");
534    }
535
536    fn assert_iterated_test_set_4<const CT: bool>() {
537        let key = [
538            0x0D, 0xED, 0x72, 0x63, 0x10, 0x9C, 0xF9, 0x2E, 0x33, 0x52, 0x25, 0x5A, 0x14, 0x0E,
539            0x0F, 0x76,
540        ];
541        let iv = [
542            0x6B, 0x68, 0x07, 0x9A, 0x41, 0xA7, 0xC4, 0xC9, 0x1B, 0xEF, 0xD7, 0x9F, 0x7F, 0xDC,
543            0xC2, 0x33,
544        ];
545
546        let mut core = init_core::<CT>(&key, &iv);
547        assert_eq!(next_word_core::<CT>(&mut core), 0xD712_C05C, "z1");
548        assert_eq!(next_word_core::<CT>(&mut core), 0xA937_C2A6, "z2");
549        assert_eq!(next_word_core::<CT>(&mut core), 0xEB7E_AAE3, "z3");
550        for _ in 0..2496 {
551            let _ = next_word_core::<CT>(&mut core);
552        }
553        assert_eq!(next_word_core::<CT>(&mut core), 0x9C0D_B3AA, "z2500");
554    }
555
556    #[test]
557    fn keystream_test_set_1() {
558        let key = [
559            0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81,
560            0xFF, 0x48,
561        ];
562        let iv = [
563            0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84, 0xDF, 0x1F, 0x9B, 0x25, 0x1C, 0x0B,
564            0xF4, 0x5F,
565        ];
566        let mut snow = Snow3g::new(&key, &iv);
567        assert_eq!(snow.next_word(), 0xABEE_9704);
568        assert_eq!(snow.next_word(), 0x7AC3_1373);
569    }
570
571    #[test]
572    fn keystream_test_set_2() {
573        let key = [
574            0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66,
575            0xB1, 0xF3,
576        ];
577        let iv = [
578            0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0xDE, 0x55, 0x19, 0x88, 0xCE, 0xB2,
579            0xF9, 0xB7,
580        ];
581        let mut snow = Snow3g::new(&key, &iv);
582        assert_eq!(snow.next_word(), 0xEFF8_A342);
583        assert_eq!(snow.next_word(), 0xF751_480F);
584    }
585
586    #[test]
587    fn keystream_test_set_3() {
588        let key = [
589            0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86, 0x67, 0xB1, 0x71,
590            0x40, 0x13,
591        ];
592        let iv = [
593            0x62, 0xA5, 0x40, 0x98, 0x1B, 0xA6, 0xF9, 0xB7, 0x45, 0x92, 0xB0, 0xE7, 0x86, 0x90,
594            0xF7, 0x1B,
595        ];
596        let mut snow = Snow3g::new(&key, &iv);
597        assert_eq!(snow.next_word(), 0xA8C8_74A9);
598        assert_eq!(snow.next_word(), 0x7AE7_C4F8);
599    }
600
601    #[test]
602    fn keystream_test_set_1_ct() {
603        let key = [
604            0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81,
605            0xFF, 0x48,
606        ];
607        let iv = [
608            0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84, 0xDF, 0x1F, 0x9B, 0x25, 0x1C, 0x0B,
609            0xF4, 0x5F,
610        ];
611        let mut snow = Snow3gCt::new(&key, &iv);
612        assert_eq!(snow.next_word(), 0xABEE_9704);
613        assert_eq!(snow.next_word(), 0x7AC3_1373);
614    }
615
616    #[test]
617    fn keystream_test_set_2_ct() {
618        let key = [
619            0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66,
620            0xB1, 0xF3,
621        ];
622        let iv = [
623            0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0xDE, 0x55, 0x19, 0x88, 0xCE, 0xB2,
624            0xF9, 0xB7,
625        ];
626        let mut snow = Snow3gCt::new(&key, &iv);
627        assert_eq!(snow.next_word(), 0xEFF8_A342);
628        assert_eq!(snow.next_word(), 0xF751_480F);
629    }
630
631    #[test]
632    fn keystream_test_set_3_ct() {
633        let key = [
634            0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86, 0x67, 0xB1, 0x71,
635            0x40, 0x13,
636        ];
637        let iv = [
638            0x62, 0xA5, 0x40, 0x98, 0x1B, 0xA6, 0xF9, 0xB7, 0x45, 0x92, 0xB0, 0xE7, 0x86, 0x90,
639            0xF7, 0x1B,
640        ];
641        let mut snow = Snow3gCt::new(&key, &iv);
642        assert_eq!(snow.next_word(), 0xA8C8_74A9);
643        assert_eq!(snow.next_word(), 0x7AE7_C4F8);
644    }
645
646    #[test]
647    fn fill_xor_roundtrip() {
648        let key = [0x12u8; 16];
649        let iv = [0x34u8; 16];
650        let plaintext = b"Hello, SNOW 3G!!";
651        let mut buf = *plaintext;
652        Snow3g::new(&key, &iv).fill(&mut buf);
653        Snow3g::new(&key, &iv).fill(&mut buf);
654        assert_eq!(&buf, plaintext);
655    }
656
657    #[test]
658    fn fill_partial_word() {
659        let key = [0xABu8; 16];
660        let iv = [0xCDu8; 16];
661        let mut buf7 = [0u8; 7];
662        let mut buf8 = [0u8; 8];
663        Snow3g::new(&key, &iv).fill(&mut buf7);
664        Snow3g::new(&key, &iv).fill(&mut buf8);
665        assert_eq!(buf7[..], buf8[..7]);
666    }
667
668    #[test]
669    fn fill_xor_roundtrip_ct() {
670        let key = [0x12u8; 16];
671        let iv = [0x34u8; 16];
672        let plaintext = b"Hello, SNOW 3G!!";
673        let mut buf = *plaintext;
674        Snow3gCt::new(&key, &iv).fill(&mut buf);
675        Snow3gCt::new(&key, &iv).fill(&mut buf);
676        assert_eq!(&buf, plaintext);
677    }
678
679    #[test]
680    fn fill_partial_word_ct() {
681        let key = [0xABu8; 16];
682        let iv = [0xCDu8; 16];
683        let mut buf7 = [0u8; 7];
684        let mut buf8 = [0u8; 8];
685        Snow3gCt::new(&key, &iv).fill(&mut buf7);
686        Snow3gCt::new(&key, &iv).fill(&mut buf8);
687        assert_eq!(buf7[..], buf8[..7]);
688    }
689
690    #[test]
691    fn ct_sboxes_match_tables() {
692        for x in 0u16..=255 {
693            let b = u8::try_from(x).expect("table index fits in u8");
694            assert_eq!(sbox_eval(&SR_ANF, b), SR[x as usize], "SR {x:02x}");
695            assert_eq!(sbox_eval(&SQ_ANF, b), SQ[x as usize], "SQ {x:02x}");
696            assert_eq!(
697                alpha_word_ct(b, MUL_ALPHA_FACTORS),
698                MUL_ALPHA[x as usize],
699                "MUL {x:02x}"
700            );
701            assert_eq!(
702                alpha_word_ct(b, DIV_ALPHA_FACTORS),
703                DIV_ALPHA[x as usize],
704                "DIV {x:02x}"
705            );
706        }
707    }
708
709    #[test]
710    fn snow3g_and_ct_match() {
711        let key = [0x12u8; 16];
712        let iv = [0x34u8; 16];
713        let mut fast = Snow3g::new(&key, &iv);
714        let mut slow = Snow3gCt::new(&key, &iv);
715        for _ in 0..4 {
716            assert_eq!(fast.next_word(), slow.next_word());
717        }
718    }
719
720    #[test]
721    fn snow3g_and_ct_match_random_streams() {
722        let mut seed = 0xfeed_face_cafe_beefu64;
723        for _ in 0..128 {
724            let mut key = [0u8; 16];
725            let mut iv = [0u8; 16];
726            fill_bytes(&mut seed, &mut key);
727            fill_bytes(&mut seed, &mut iv);
728            let len = (xorshift64(&mut seed) as usize % 2048) + 1;
729
730            let mut fast_buf = vec![0u8; len];
731            let mut ct_buf = vec![0u8; len];
732            fill_bytes(&mut seed, &mut fast_buf);
733            ct_buf.copy_from_slice(&fast_buf);
734
735            Snow3g::new(&key, &iv).fill(&mut fast_buf);
736            Snow3gCt::new(&key, &iv).fill(&mut ct_buf);
737            assert_eq!(fast_buf, ct_buf);
738        }
739    }
740
741    #[test]
742    fn official_test_set_1_trace_fast_and_ct() {
743        let key = [
744            0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81,
745            0xFF, 0x48,
746        ];
747        let iv = [
748            0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84, 0xDF, 0x1F, 0x9B, 0x25, 0x1C, 0x0B,
749            0xF4, 0x5F,
750        ];
751        let initial_lfsr = [
752            0xD429_BA60,
753            0x7D3A_4CFF,
754            0x6AD3_B6EF,
755            0xB77E_00B7,
756            0x2BD6_459F,
757            0x82C5_B300,
758            0x952C_4910,
759            0x4881_FF48,
760            0xD429_BA60,
761            0x6131_B8A0,
762            0xB5CC_2DCA,
763            0xB77E_00B7,
764            0x868A_081B,
765            0x82C5_B300,
766            0x952C_4910,
767            0xA283_B85C,
768        ];
769        let init_rows = [
770            TraceRow {
771                s0: 0xD429_BA60,
772                s2: 0x6AD3_B6EF,
773                s5: 0x82C5_B300,
774                s11: 0xB77E_00B7,
775                s15: 0xA283_B85C,
776                r1: 0x0000_0000,
777                r2: 0x0000_0000,
778                r3: 0x0000_0000,
779            },
780            TraceRow {
781                s0: 0x7D3A_4CFF,
782                s2: 0xB77E_00B7,
783                s5: 0x952C_4910,
784                s11: 0x868A_081B,
785                s15: 0x97DF_2884,
786                r1: 0x82C5_B300,
787                r2: 0x6363_6363,
788                r3: 0x2525_2525,
789            },
790            TraceRow {
791                s0: 0x6AD3_B6EF,
792                s2: 0x2BD6_459F,
793                s5: 0x4881_FF48,
794                s11: 0x82C5_B300,
795                s15: 0x311B_A301,
796                r1: 0x136C_CF98,
797                r2: 0x486C_5BC4,
798                r3: 0x9393_9393,
799            },
800            TraceRow {
801                s0: 0xB77E_00B7,
802                s2: 0x82C5_B300,
803                s5: 0xD429_BA60,
804                s11: 0x952C_4910,
805                s15: 0xA69F_CBCB,
806                r1: 0x237E_C89F,
807                r2: 0xEAEB_C424,
808                r3: 0x4B78_15EA,
809            },
810            TraceRow {
811                s0: 0x2BD6_459F,
812                s2: 0x952C_4910,
813                s5: 0x6131_B8A0,
814                s11: 0xA283_B85C,
815                s15: 0xE76F_0ADA,
816                r1: 0x8A3D_73AE,
817                r2: 0x21A4_385B,
818                r3: 0xE662_EC27,
819            },
820            TraceRow {
821                s0: 0x82C5_B300,
822                s2: 0x4881_FF48,
823                s5: 0xB5CC_2DCA,
824                s11: 0x97DF_2884,
825                s15: 0xA52D_CD12,
826                r1: 0xA8F7_8CE2,
827                r2: 0x63A7_F600,
828                r3: 0xBC3F_3A8D,
829            },
830            TraceRow {
831                s0: 0x952C_4910,
832                s2: 0xD429_BA60,
833                s5: 0xB77E_00B7,
834                s11: 0x311B_A301,
835                s15: 0x1A34_9A62,
836                r1: 0x6D9B_0D47,
837                r2: 0x2071_2A2D,
838                r3: 0x391D_0883,
839            },
840            TraceRow {
841                s0: 0x4881_FF48,
842                s2: 0x6131_B8A0,
843                s5: 0x868A_081B,
844                s11: 0xA69F_CBCB,
845                s15: 0x2A2A_44DB,
846                r1: 0xAED4_3261,
847                r2: 0x401B_1511,
848                r3: 0x45A6_ED60,
849            },
850        ];
851        let final_lfsr = [
852            0x8F12_15A6,
853            0xE003_A052,
854            0x9241_C929,
855            0x68D7_BF8C,
856            0x16BF_4C2A,
857            0x8DEF_9D70,
858            0x3238_1704,
859            0x11DD_346A,
860            0xE18B_81EA,
861            0x77EB_D4FE,
862            0x57ED_9505,
863            0x0C33_C0EF,
864            0x1A03_7B59,
865            0x9759_1E82,
866            0xA91C_CB44,
867            0x7B48_E04F,
868        ];
869        let final_fsm = [0x61DA_9249, 0x427D_F38C, 0x0FB6_B101];
870        let keystream_rows = [
871            TraceRow {
872                s0: 0xE003_A052,
873                s2: 0x68D7_BF8C,
874                s5: 0x3238_1704,
875                s11: 0x1A03_7B59,
876                s15: 0x1646_644C,
877                r1: 0xC4D7_1FFD,
878                r2: 0x90F0_B31F,
879                r3: 0xCC61_2008,
880            },
881            TraceRow {
882                s0: 0x9241_C929,
883                s2: 0x16BF_4C2A,
884                s5: 0x11DD_346A,
885                s11: 0x9759_1E82,
886                s15: 0x52E4_3190,
887                r1: 0x8F49_EA2B,
888                r2: 0x0AAC_C1E1,
889                r3: 0x3367_438C,
890            },
891            TraceRow {
892                s0: 0x68D7_BF8C,
893                s2: 0x8DEF_9D70,
894                s5: 0xE18B_81EA,
895                s11: 0xA91C_CB44,
896                s15: 0xB737_110E,
897                r1: 0x2D67_39C7,
898                r2: 0x5295_DA23,
899                r3: 0x5293_E49E,
900            },
901        ];
902        let outputs = [0xABEE_9704, 0x7AC3_1373];
903
904        let case = OfficialTraceCase {
905            key,
906            iv,
907            initial_lfsr,
908            init_rows,
909            final_lfsr,
910            final_fsm,
911            keystream_rows,
912            outputs,
913        };
914        assert_official_trace::<false>(&case);
915        assert_official_trace::<true>(&case);
916    }
917
918    #[test]
919    fn official_test_set_2_trace_fast_and_ct() {
920        let key = [
921            0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66,
922            0xB1, 0xF3,
923        ];
924        let iv = [
925            0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0xDE, 0x55, 0x19, 0x88, 0xCE, 0xB2,
926            0xF9, 0xB7,
927        ];
928        let initial_lfsr = [
929            0x731C_C1D3,
930            0x3C3F_4A03,
931            0xE0C2_1759,
932            0x2399_4E0C,
933            0x8CE3_3E2C,
934            0xC3C0_B5FC,
935            0x1F3D_E8A6,
936            0xDC66_B1F3,
937            0x731C_C1D3,
938            0xF28D_B3B4,
939            0x3E97_0ED1,
940            0x2399_4E0C,
941            0xBE9C_8F30,
942            0xC3C0_B5FC,
943            0x1F3D_E8A6,
944            0x0FA3_6461,
945        ];
946        let init_rows = [
947            TraceRow {
948                s0: 0x731C_C1D3,
949                s2: 0xE0C2_1759,
950                s5: 0xC3C0_B5FC,
951                s11: 0x2399_4E0C,
952                s15: 0x0FA3_6461,
953                r1: 0x0000_0000,
954                r2: 0x0000_0000,
955                r3: 0x0000_0000,
956            },
957            TraceRow {
958                s0: 0x3C3F_4A03,
959                s2: 0x2399_4E0C,
960                s5: 0x1F3D_E8A6,
961                s11: 0xBE9C_8F30,
962                s15: 0xEF81_E474,
963                r1: 0xC3C0_B5FC,
964                r2: 0x6363_6363,
965                r3: 0x2525_2525,
966            },
967            TraceRow {
968                s0: 0xE0C2_1759,
969                s2: 0x8CE3_3E2C,
970                s5: 0xDC66_B1F3,
971                s11: 0xC3C0_B5FC,
972                s15: 0x7A55_4815,
973                r1: 0x9D7C_30E6,
974                r2: 0xF878_FA8B,
975                r3: 0x9393_9393,
976            },
977            TraceRow {
978                s0: 0x2399_4E0C,
979                s2: 0xC3C0_B5FC,
980                s5: 0x731C_C1D3,
981                s11: 0x1F3D_E8A6,
982                s15: 0x53E0_AE66,
983                r1: 0x486E_1CEB,
984                r2: 0x2148_E845,
985                r3: 0x098F_198B,
986            },
987            TraceRow {
988                s0: 0x8CE3_3E2C,
989                s2: 0x1F3D_E8A6,
990                s5: 0xF28D_B3B4,
991                s11: 0x0FA3_6461,
992                s15: 0x9A1E_E9B8,
993                r1: 0x9BDC_C09D,
994                r2: 0x87A6_22BB,
995                r3: 0xEFFA_4239,
996            },
997            TraceRow {
998                s0: 0xC3C0_B5FC,
999                s2: 0xDC66_B1F3,
1000                s5: 0x3E97_0ED1,
1001                s11: 0xEF81_E474,
1002                s15: 0x2390_FE04,
1003                r1: 0xA51E_1448,
1004                r2: 0xF6CF_B4FB,
1005                r3: 0x2087_DC1D,
1006            },
1007            TraceRow {
1008                s0: 0x1F3D_E8A6,
1009                s2: 0x731C_C1D3,
1010                s5: 0x2399_4E0C,
1011                s11: 0x7A55_4815,
1012                s15: 0x6FB8_C36C,
1013                r1: 0x14E0_87C7,
1014                r2: 0x7246_2DC5,
1015                r3: 0x0B8B_F471,
1016            },
1017            TraceRow {
1018                s0: 0xDC66_B1F3,
1019                s2: 0xF28D_B3B4,
1020                s5: 0xBE9C_8F30,
1021                s11: 0x53E0_AE66,
1022                s15: 0xBA5D_B98F,
1023                r1: 0x9A58_E842,
1024                r2: 0x481D_2AB5,
1025                r3: 0x5C8E_E565,
1026            },
1027        ];
1028        let final_lfsr = [
1029            0x04D6_A929,
1030            0x942E_1440,
1031            0x82AB_D3FE,
1032            0x5832_E9F4,
1033            0x5F97_02A0,
1034            0x0871_2C81,
1035            0x644C_C9B9,
1036            0xDBF6_DE13,
1037            0xBAA5_B1D0,
1038            0x92E9_DD53,
1039            0xA2E2_FA6D,
1040            0xCE69_65AA,
1041            0x02C0_CD4E,
1042            0x6E6D_984F,
1043            0x114A_90E7,
1044            0x5279_F8DA,
1045        ];
1046        let final_fsm = [0x6513_0120, 0xA14C_7DBD, 0xB68B_551A];
1047        let keystream_rows = [
1048            TraceRow {
1049                s0: 0x942E_1440,
1050                s2: 0x5832_E9F4,
1051                s5: 0x644C_C9B9,
1052                s11: 0x02C0_CD4E,
1053                s15: 0xC1E9_3B6B,
1054                r1: 0x6046_F758,
1055                r2: 0x59E6_85C1,
1056                r3: 0x7DCB_C989,
1057            },
1058            TraceRow {
1059                s0: 0x82AB_D3FE,
1060                s2: 0x5F97_02A0,
1061                s5: 0xDBF6_DE13,
1062                s11: 0x6E6D_984F,
1063                s15: 0xCEB9_9926,
1064                r1: 0x736D_85F1,
1065                r2: 0x37DD_84E6,
1066                r3: 0xA9BE_CBB1,
1067            },
1068            TraceRow {
1069                s0: 0x5832_E9F4,
1070                s2: 0x0871_2C81,
1071                s5: 0xBAA5_B1D0,
1072                s11: 0x114A_90E7,
1073                s15: 0xE34F_6919,
1074                r1: 0xAA25_9A88,
1075                r2: 0x56C4_5F48,
1076                r3: 0xC354_6A61,
1077            },
1078        ];
1079        let outputs = [0xEFF8_A342, 0xF751_480F];
1080
1081        let case = OfficialTraceCase {
1082            key,
1083            iv,
1084            initial_lfsr,
1085            init_rows,
1086            final_lfsr,
1087            final_fsm,
1088            keystream_rows,
1089            outputs,
1090        };
1091        assert_official_trace::<false>(&case);
1092        assert_official_trace::<true>(&case);
1093    }
1094
1095    #[test]
1096    fn official_test_set_3_trace_fast_and_ct() {
1097        let key = [
1098            0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86, 0x67, 0xB1, 0x71,
1099            0x40, 0x13,
1100        ];
1101        let iv = [
1102            0x62, 0xA5, 0x40, 0x98, 0x1B, 0xA6, 0xF9, 0xB7, 0x45, 0x92, 0xB0, 0xE7, 0x86, 0x90,
1103            0xF7, 0x1B,
1104        ];
1105        let initial_lfsr = [
1106            0xBFCA_3997,
1107            0xF507_392E,
1108            0x5700_7998,
1109            0x4E8E_BFEC,
1110            0x4035_C668,
1111            0x0AF8_C6D1,
1112            0xA8FF_8667,
1113            0xB171_4013,
1114            0xBFCA_3997,
1115            0x7397_CE35,
1116            0x1292_C97F,
1117            0x4E8E_BFEC,
1118            0x5B93_3FDF,
1119            0x0AF8_C6D1,
1120            0xA8FF_8667,
1121            0xD3D4_008B,
1122        ];
1123        let init_rows = [
1124            TraceRow {
1125                s0: 0xBFCA_3997,
1126                s2: 0x5700_7998,
1127                s5: 0x0AF8_C6D1,
1128                s11: 0x4E8E_BFEC,
1129                s15: 0xD3D4_008B,
1130                r1: 0x0000_0000,
1131                r2: 0x0000_0000,
1132                r3: 0x0000_0000,
1133            },
1134            TraceRow {
1135                s0: 0xF507_392E,
1136                s2: 0x4E8E_BFEC,
1137                s5: 0xA8FF_8667,
1138                s11: 0x5B93_3FDF,
1139                s15: 0xEE2C_ABF5,
1140                r1: 0x0AF8_C6D1,
1141                r2: 0x6363_6363,
1142                r3: 0x2525_2525,
1143            },
1144            TraceRow {
1145                s0: 0x5700_7998,
1146                s2: 0x4035_C668,
1147                s5: 0xB171_4013,
1148                s11: 0x0AF8_C6D1,
1149                s15: 0x6673_56A3,
1150                r1: 0xF13E_06A5,
1151                r2: 0x79A1_E99D,
1152                r3: 0x9393_9393,
1153            },
1154            TraceRow {
1155                s0: 0x4E8E_BFEC,
1156                s2: 0x0AF8_C6D1,
1157                s5: 0xBFCA_3997,
1158                s11: 0xA8FF_8667,
1159                s15: 0x6410_181D,
1160                r1: 0x9C84_BD1D,
1161                r2: 0x8EEE_B4AE,
1162                r3: 0xE599_5CC4,
1163            },
1164            TraceRow {
1165                s0: 0x4035_C668,
1166                s2: 0xA8FF_8667,
1167                s5: 0x7397_CE35,
1168                s11: 0xD3D4_008B,
1169                s15: 0x241A_7790,
1170                r1: 0xE942_1A01,
1171                r2: 0x7519_6F5C,
1172                r3: 0xC83E_1776,
1173            },
1174            TraceRow {
1175                s0: 0x0AF8_C6D1,
1176                s2: 0xB171_4013,
1177                s5: 0x1292_C97F,
1178                s11: 0xEE2C_ABF5,
1179                s15: 0xC485_B826,
1180                r1: 0x30C3_489F,
1181                r2: 0x36A4_4937,
1182                r3: 0x0F31_7420,
1183            },
1184            TraceRow {
1185                s0: 0xA8FF_8667,
1186                s2: 0xBFCA_3997,
1187                s5: 0x4E8E_BFEC,
1188                s11: 0x6673_56A3,
1189                s15: 0xA211_C1E9,
1190                r1: 0x5448_0696,
1191                r2: 0x02D9_0971,
1192                r3: 0x3D98_2023,
1193            },
1194            TraceRow {
1195                s0: 0xB171_4013,
1196                s2: 0x7397_CE35,
1197                s5: 0x5B93_3FDF,
1198                s11: 0x6410_181D,
1199                s15: 0x6E8A_E7E6,
1200                r1: 0x75EF_A940,
1201                r2: 0xD63B_98F8,
1202                r3: 0x883F_13A7,
1203            },
1204        ];
1205        let final_lfsr = [
1206            0xFEAF_BAD8,
1207            0x1B11_050A,
1208            0x2370_8014,
1209            0xAC84_94DB,
1210            0xED97_D431,
1211            0xDBBB_59B3,
1212            0x6CD3_0005,
1213            0x7EC3_6405,
1214            0xB20F_02AC,
1215            0xEB40_7735,
1216            0x50E4_1A0E,
1217            0xFFA8_ABC1,
1218            0xEB48_00A7,
1219            0xD4E6_749D,
1220            0xD1C4_52FE,
1221            0xA92A_3153,
1222        ];
1223        let final_fsm = [0x6599_AA50, 0x5EA9_188B, 0xF418_89FC];
1224        let keystream_rows = [
1225            TraceRow {
1226                s0: 0x1B11_050A,
1227                s2: 0xAC84_94DB,
1228                s5: 0x6CD3_0005,
1229                s11: 0xEB48_00A7,
1230                s15: 0x0FE9_1C6F,
1231                r1: 0x8E4C_E8DA,
1232                r2: 0x2DEF_74EA,
1233                r3: 0x42B4_B0A3,
1234            },
1235            TraceRow {
1236                s0: 0x2370_8014,
1237                s2: 0xED97_D431,
1238                s5: 0x7EC3_6405,
1239                s11: 0xD4E6_749D,
1240                s15: 0xC3CB_3734,
1241                r1: 0x5C57_2590,
1242                r2: 0x79B5_1828,
1243                r3: 0x2496_A1E1,
1244            },
1245            TraceRow {
1246                s0: 0xAC84_94DB,
1247                s2: 0xDBBB_59B3,
1248                s5: 0xB20F_02AC,
1249                s11: 0xD1C4_52FE,
1250                s15: 0x739A_B29C,
1251                r1: 0xD40A_DE0C,
1252                r2: 0x5037_B990,
1253                r3: 0x32D1_FAE0,
1254            },
1255        ];
1256        let outputs = [0xA8C8_74A9, 0x7AE7_C4F8];
1257
1258        let case = OfficialTraceCase {
1259            key,
1260            iv,
1261            initial_lfsr,
1262            init_rows,
1263            final_lfsr,
1264            final_fsm,
1265            keystream_rows,
1266            outputs,
1267        };
1268        assert_official_trace::<false>(&case);
1269        assert_official_trace::<true>(&case);
1270    }
1271
1272    #[test]
1273    fn official_test_set_4_iterated_fast_and_ct() {
1274        assert_iterated_test_set_4::<false>();
1275        assert_iterated_test_set_4::<true>();
1276    }
1277}