speck_rs/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3
4pub mod cipher_modes;
5
6use crate::cipher_modes::ECB;
7
8/// This library implements NSA's lightweight block cipher Speck.
9/// The formal specification of Speck can be found: https://eprint.iacr.org/2013/404.pdf
10///
11/// The Speck parameters are found in Table 4.1 in the above paper.
12
13/// Speck parameters (for 128-bit security)
14/// ALPHA and BETA are the parameters to the rotations
15/// ROUNDS is the number of times to apply the round function
16const ALPHA: u32 = 8;
17const BETA: u32 = 3;
18const ROUNDS: usize = 32;
19
20/// Performs the Speck round function once.
21/// (S^{-\alpha}x + y) \oplus k, S^{\beta}y \oplus (S^{-\alpha}x + y) \oplus k
22///
23/// Notice that (S^{-\alpha}x + y) \oplus k component gets used twice, thus
24/// we can simplify the round function to 2 rotations, 1 addition, and 2 XORs.
25#[inline(always)]
26fn round(x: &mut u64, y: &mut u64, k: &u64) {
27    *x = x.rotate_right(ALPHA).wrapping_add(*y) ^ k;
28    *y = y.rotate_left(BETA) ^ *x;
29}
30
31/// Performs the Speck inverse round function once.
32/// The inverse round function is necessary for decryption.
33/// (S^{\alpha}((x \oplus k) - S^{-\beta}(x \oplus y)), S^{-\beta}(x \oplus y))
34///
35/// Notice that that S^{-\beta}(x \oplus y) component gets used twice, thus
36/// we can simplify the round function to 2 rotations, 1 subtraction, and 2 XORs.
37#[inline(always)]
38fn inv_round(x: &mut u64, y: &mut u64, k: &u64) {
39    *y = (*y ^ *x).rotate_right(BETA);
40    *x = (*x ^ *k).wrapping_sub(*y).rotate_left(ALPHA);
41}
42
43/// Computes the Speck key schedule via the round function.
44#[inline(always)]
45fn key_schedule(k1: &mut u64, k2: &mut u64) -> [u64; ROUNDS] {
46    let mut schedule = [0u64; ROUNDS];
47    for i in 0..ROUNDS as u64 {
48        schedule[i as usize] = *k2;
49        round(k1, k2, &i)
50    }
51    schedule
52}
53
54/// Implements Speck encryption/decryption.
55/// This tuple-struct takes a key schedule as input.
56///
57/// TODO: Build an API around generating the key schedule
58pub struct Speck([u64; ROUNDS]);
59
60impl Speck {
61    pub fn new(key: &u128) -> Self {
62        let mut k1 = (key >> 64) as u64;
63        let mut k2 = *key as u64;
64
65        Speck(key_schedule(&mut k1, &mut k2))
66    }
67
68    /// Performs a raw encryption using Speck.
69    /// This is not exposed via the Speck type because the raw
70    /// encryption function is generally unsafe to use.
71    ///
72    /// TODO: Implement ciphermodes, potentially expose this as ECB.
73    pub(crate) fn encrypt(&self, plaintext: &u128) -> u128 {
74        // Split the u128 block into u64 chunks
75        let mut chunk_1 = (plaintext >> 64) as u64;
76        let mut chunk_2 = *plaintext as u64;
77
78        // Perform the Speck round with each of its round keys
79        for round_key in &self.0 {
80            round(&mut chunk_1, &mut chunk_2, round_key);
81        }
82
83        // The chunks are mutated in place, so we just put them back together
84        chunk_2 as u128 | (chunk_1 as u128) << 64
85    }
86
87    /// Performs a raw decryption using Speck.
88    ///
89    /// TODO: Implement ciphermodes, potentially expose this as ECB.
90    pub(crate) fn decrypt(&self, ciphertext: &u128) -> u128 {
91        // Split the u128 block into u64 chunks
92        let mut chunk_1 = (ciphertext >> 64) as u64;
93        let mut chunk_2 = *ciphertext as u64;
94
95        // Perform the Speck round with each of its round keys
96        for round_key in self.0.iter().rev() {
97            inv_round(&mut chunk_1, &mut chunk_2, round_key);
98        }
99
100        // The chunks are mutated in place, so we just put them back together
101        chunk_2 as u128 | (chunk_1 as u128) << 64
102    }
103}
104
105impl ECB for Speck {
106    fn encrypt(&self, plaintext: &u128) -> u128 {
107        self.encrypt(plaintext)
108    }
109
110    fn decrypt(&self, ciphertext: &u128) -> u128 {
111        self.decrypt(ciphertext)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_speck128_128_encryption_and_decryption() {
121        // Speck128/128 test vectors (see Appendix C in the paper)
122        let key: u128 = 0x0f0e0d0c0b0a09080706050403020100;
123        let plaintext: u128 = 0x6c617669757165207469206564616d20;
124        let ciphertext: u128 = 0xa65d9851797832657860fedf5c570d18;
125
126        let speck = Speck::new(&key);
127        assert_eq!(speck.encrypt(&plaintext), ciphertext);
128        assert_eq!(speck.decrypt(&ciphertext), plaintext);
129    }
130
131    #[test]
132    fn test_speck_ecb_mode() {
133        let key: u128 = 0x0f0e0d0c0b0a09080706050403020100;
134        let plaintext: u128 = 0x6c617669757165207469206564616d20;
135        let ciphertext: u128 = 0xa65d9851797832657860fedf5c570d18;
136
137        let speck = Speck::new(&key);
138        assert_eq!(<Speck as ECB>::encrypt(&speck, &plaintext), ciphertext);
139        assert_eq!(<Speck as ECB>::decrypt(&speck, &ciphertext), plaintext);
140    }
141}