Skip to main content

cryptography/ciphers/
rabbit.rs

1//! Rabbit stream cipher — RFC 4503.
2//!
3//! Rabbit is a software-oriented 128-bit stream cipher from the eSTREAM era.
4//! Its state consists of eight 32-bit state words, eight 32-bit counters, and
5//! one carry bit. Each round advances the counters, runs the nonlinear
6//! `g`-function on each state word plus counter, and then mixes the eight `g`
7//! outputs into the next state.
8//!
9//! The implementation follows RFC 4503 directly:
10//!
11//! - 128-bit key
12//! - optional 64-bit IV setup
13//! - 16-byte keystream blocks
14//!
15//! Rabbit is naturally byte-oriented like the other stream ciphers in this
16//! crate: `apply_keystream` `XOR`s the keystream into caller-owned buffers.
17
18// Rabbit counter increments `A[i]` from RFC 4503 §2.5 (derived from the
19// fractional part of sqrt(pi) in the original Rabbit specification).
20const A: [u32; 8] = [
21    0x4D34_D34D,
22    0xD34D_34D3,
23    0x34D3_4D34,
24    0x4D34_D34D,
25    0xD34D_34D3,
26    0x34D3_4D34,
27    0x4D34_D34D,
28    0xD34D_34D3,
29];
30
31#[inline]
32fn load_u16_be(bytes: &[u8]) -> u16 {
33    let mut tmp = [0u8; 2];
34    tmp.copy_from_slice(bytes);
35    u16::from_be_bytes(tmp)
36}
37
38#[inline]
39fn load_u32_be(bytes: &[u8]) -> u32 {
40    let mut tmp = [0u8; 4];
41    tmp.copy_from_slice(bytes);
42    u32::from_be_bytes(tmp)
43}
44
45#[inline]
46fn cat16(hi: u16, lo: u16) -> u32 {
47    (u32::from(hi) << 16) | u32::from(lo)
48}
49
50#[inline]
51fn g_func(x: u32, c: u32) -> u32 {
52    let sum = u64::from(x.wrapping_add(c));
53    let square = sum.wrapping_mul(sum);
54    (square as u32) ^ ((square >> 32) as u32)
55}
56
57#[derive(Clone)]
58struct RabbitCore {
59    x: [u32; 8],
60    c: [u32; 8],
61    carry: u32,
62}
63
64impl RabbitCore {
65    fn from_key(key: &[u8; 16]) -> Self {
66        let mut k = [0u16; 8];
67        for (i, chunk) in key.rchunks_exact(2).enumerate() {
68            k[i] = load_u16_be(chunk);
69        }
70
71        let mut core = Self {
72            x: [
73                cat16(k[1], k[0]),
74                cat16(k[6], k[5]),
75                cat16(k[3], k[2]),
76                cat16(k[0], k[7]),
77                cat16(k[5], k[4]),
78                cat16(k[2], k[1]),
79                cat16(k[7], k[6]),
80                cat16(k[4], k[3]),
81            ],
82            c: [
83                cat16(k[4], k[5]),
84                cat16(k[1], k[2]),
85                cat16(k[6], k[7]),
86                cat16(k[3], k[4]),
87                cat16(k[0], k[1]),
88                cat16(k[5], k[6]),
89                cat16(k[2], k[3]),
90                cat16(k[7], k[0]),
91            ],
92            carry: 0,
93        };
94
95        for _ in 0..4 {
96            core.next_state();
97        }
98
99        for i in 0..8 {
100            core.c[i] ^= core.x[(i + 4) & 7];
101        }
102
103        core
104    }
105
106    fn apply_iv(&mut self, iv: &[u8; 8]) {
107        let v0 = load_u32_be(&iv[4..8]);
108        let v1 = cat16(load_u16_be(&iv[0..2]), load_u16_be(&iv[4..6]));
109        let v2 = load_u32_be(&iv[0..4]);
110        let v3 = cat16(load_u16_be(&iv[2..4]), load_u16_be(&iv[6..8]));
111
112        self.c[0] ^= v0;
113        self.c[1] ^= v1;
114        self.c[2] ^= v2;
115        self.c[3] ^= v3;
116        self.c[4] ^= v0;
117        self.c[5] ^= v1;
118        self.c[6] ^= v2;
119        self.c[7] ^= v3;
120
121        for _ in 0..4 {
122            self.next_state();
123        }
124    }
125
126    #[inline]
127    fn next_state(&mut self) {
128        let old_c = self.c;
129        let mut carry = self.carry;
130        for i in 0..8 {
131            let sum = u64::from(old_c[i]) + u64::from(A[i]) + u64::from(carry);
132            self.c[i] = sum as u32;
133            carry = (sum >> 32) as u32;
134        }
135        self.carry = carry;
136
137        let mut g = [0u32; 8];
138        for (i, gi) in g.iter_mut().enumerate() {
139            *gi = g_func(self.x[i], self.c[i]);
140        }
141
142        self.x[0] = g[0]
143            .wrapping_add(g[7].rotate_left(16))
144            .wrapping_add(g[6].rotate_left(16));
145        self.x[1] = g[1].wrapping_add(g[0].rotate_left(8)).wrapping_add(g[7]);
146        self.x[2] = g[2]
147            .wrapping_add(g[1].rotate_left(16))
148            .wrapping_add(g[0].rotate_left(16));
149        self.x[3] = g[3].wrapping_add(g[2].rotate_left(8)).wrapping_add(g[1]);
150        self.x[4] = g[4]
151            .wrapping_add(g[3].rotate_left(16))
152            .wrapping_add(g[2].rotate_left(16));
153        self.x[5] = g[5].wrapping_add(g[4].rotate_left(8)).wrapping_add(g[3]);
154        self.x[6] = g[6]
155            .wrapping_add(g[5].rotate_left(16))
156            .wrapping_add(g[4].rotate_left(16));
157        self.x[7] = g[7].wrapping_add(g[6].rotate_left(8)).wrapping_add(g[5]);
158    }
159
160    #[inline]
161    fn keystream_block(&mut self) -> [u8; 16] {
162        self.next_state();
163
164        let s = [
165            self.x[0] ^ (self.x[5] >> 16) ^ self.x[3].wrapping_shl(16),
166            self.x[2] ^ (self.x[7] >> 16) ^ self.x[5].wrapping_shl(16),
167            self.x[4] ^ (self.x[1] >> 16) ^ self.x[7].wrapping_shl(16),
168            self.x[6] ^ (self.x[3] >> 16) ^ self.x[1].wrapping_shl(16),
169        ];
170
171        // RFC 4503 publishes Rabbit test vectors in octet form using I2OSP, so
172        // the stream is emitted most-significant word first in big-endian.
173        let mut out = [0u8; 16];
174        out[0..4].copy_from_slice(&s[3].to_be_bytes());
175        out[4..8].copy_from_slice(&s[2].to_be_bytes());
176        out[8..12].copy_from_slice(&s[1].to_be_bytes());
177        out[12..16].copy_from_slice(&s[0].to_be_bytes());
178        out
179    }
180}
181
182/// Rabbit stream cipher.
183///
184/// The `new` constructor applies both the key setup and the RFC IV setup.
185/// `without_iv` leaves the cipher in the key-only state used by the RFC's
186/// key-setup test vectors.
187pub struct Rabbit {
188    core: RabbitCore,
189    block: [u8; 16],
190    offset: usize,
191}
192
193impl Rabbit {
194    /// Create Rabbit from a 128-bit key and 64-bit IV.
195    #[must_use]
196    pub fn new(key: &[u8; 16], iv: &[u8; 8]) -> Self {
197        let mut core = RabbitCore::from_key(key);
198        core.apply_iv(iv);
199        Self {
200            core,
201            block: [0u8; 16],
202            offset: 16,
203        }
204    }
205
206    /// Create Rabbit from a 128-bit key without applying the optional IV setup.
207    #[must_use]
208    pub fn without_iv(key: &[u8; 16]) -> Self {
209        Self {
210            core: RabbitCore::from_key(key),
211            block: [0u8; 16],
212            offset: 16,
213        }
214    }
215
216    /// Create and wipe the caller's key and IV buffers.
217    pub fn new_wiping(key: &mut [u8; 16], iv: &mut [u8; 8]) -> Self {
218        let out = Self::new(key, iv);
219        crate::ct::zeroize_slice(key.as_mut_slice());
220        crate::ct::zeroize_slice(iv.as_mut_slice());
221        out
222    }
223
224    /// Create without IV setup and wipe the caller's key buffer.
225    pub fn without_iv_wiping(key: &mut [u8; 16]) -> Self {
226        let out = Self::without_iv(key);
227        crate::ct::zeroize_slice(key.as_mut_slice());
228        out
229    }
230
231    #[inline]
232    fn refill(&mut self) {
233        self.block = self.core.keystream_block();
234        self.offset = 0;
235    }
236
237    /// XOR the Rabbit keystream into `buf` in place.
238    pub fn apply_keystream(&mut self, buf: &mut [u8]) {
239        let mut done = 0usize;
240        while done < buf.len() {
241            if self.offset == 16 {
242                self.refill();
243            }
244            let take = core::cmp::min(16 - self.offset, buf.len() - done);
245            for i in 0..take {
246                buf[done + i] ^= self.block[self.offset + i];
247            }
248            self.offset += take;
249            done += take;
250        }
251    }
252
253    /// Fill `buf` with keystream bytes by `XORing` into the existing contents.
254    pub fn fill(&mut self, buf: &mut [u8]) {
255        self.apply_keystream(buf);
256    }
257
258    /// Return the next 16 bytes of keystream.
259    pub fn keystream_block(&mut self) -> [u8; 16] {
260        let mut out = [0u8; 16];
261        self.apply_keystream(&mut out);
262        out
263    }
264}
265
266impl Drop for Rabbit {
267    fn drop(&mut self) {
268        crate::ct::zeroize_slice(self.core.x.as_mut_slice());
269        crate::ct::zeroize_slice(self.core.c.as_mut_slice());
270        self.core.carry = 0;
271        crate::ct::zeroize_slice(self.block.as_mut_slice());
272        self.offset = 0;
273    }
274}
275
276#[cfg(test)]
277mod tests {
278    use super::*;
279
280    fn decode_hex(s: &str) -> Vec<u8> {
281        assert!(
282            s.len().is_multiple_of(2),
283            "hex string must have even length"
284        );
285        let mut out = Vec::with_capacity(s.len() / 2);
286        let bytes = s.as_bytes();
287        for i in (0..bytes.len()).step_by(2) {
288            let hi = (bytes[i] as char).to_digit(16).expect("hex") as u8;
289            let lo = (bytes[i + 1] as char).to_digit(16).expect("hex") as u8;
290            out.push((hi << 4) | lo);
291        }
292        out
293    }
294
295    #[test]
296    fn rabbit_zero_key_rfc_keystream() {
297        let mut rabbit = Rabbit::without_iv(&[0u8; 16]);
298        let mut out = [0u8; 48];
299        rabbit.fill(&mut out);
300        let expected = decode_hex(
301            "B15754F036A5D6ECF56B45261C4AF702\
302             88E8D815C59C0C397B696C4789C68AA7\
303             F416A1C3700CD451DA68D1881673D696",
304        );
305        assert_eq!(out.as_slice(), expected.as_slice());
306    }
307
308    #[test]
309    fn rabbit_key_only_rfc_vector_two() {
310        let key = decode_hex("912813292E3D36FE3BFC62F1DC51C3AC");
311        let mut key_arr = [0u8; 16];
312        key_arr.copy_from_slice(&key);
313        let mut rabbit = Rabbit::without_iv(&key_arr);
314        let mut out = [0u8; 48];
315        rabbit.fill(&mut out);
316        let expected = decode_hex(
317            "3D2DF3C83EF627A1E97FC38487E2519C\
318             F576CD61F4405B8896BF53AA8554FC19\
319             E5547473FBDB43508AE53B20204D4C5E",
320        );
321        assert_eq!(out.as_slice(), expected.as_slice());
322    }
323
324    #[test]
325    fn rabbit_zero_key_zero_iv_rfc_keystream() {
326        let mut rabbit = Rabbit::new(&[0u8; 16], &[0u8; 8]);
327        let mut out = [0u8; 48];
328        rabbit.fill(&mut out);
329        let expected = decode_hex(
330            "C6A7275EF85495D87CCD5D376705B7ED\
331             5F29A6AC04F5EFD47B8F293270DC4A8D\
332             2ADE822B29DE6C1EE52BDB8A47BF8F66",
333        );
334        assert_eq!(out.as_slice(), expected.as_slice());
335    }
336
337    #[test]
338    fn rabbit_roundtrip() {
339        let key = [0x42u8; 16];
340        let iv = [0x24u8; 8];
341        let plain = *b"rabbit stream demo";
342
343        let mut enc = Rabbit::new(&key, &iv);
344        let mut ct = plain;
345        enc.apply_keystream(&mut ct);
346
347        let mut dec = Rabbit::new(&key, &iv);
348        dec.apply_keystream(&mut ct);
349
350        assert_eq!(ct, plain);
351    }
352}