# lwbc
Rust implementations of the SPECK, SIMON, and SIMECK block cipher families.
These are small block ciphers (32-bit to 96-bit blocks) designed by the NSA and academic researchers. While often marketed for constrained environments, small block ciphers have broader applications:
- Encrypting counters - Hide sequential patterns in counter-based systems (packet numbers, sequence IDs)
- Short identifier encryption - Encrypt user IDs, order numbers, or database keys without size expansion
- Format-preserving encryption - Encrypt small fixed-size values while maintaining their original format
- Database field encryption - Encrypt individual columns while preserving storage efficiency
- Obfuscation of sequential data - Turn predictable sequences into seemingly random values
- Protocol design - When you need encryption but can't afford block size overhead
- Embedded systems - Minimal code size and RAM usage
- High-throughput scenarios - Smaller state means better cache utilization
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
lwbc = { git = "https://github.com/jedisct1/rust-lwbc" }
```
## Usage
### Basic encryption/decryption
```rust
use lwbc::Speck32;
// Initialize with a 64-bit key (4 x u16)
let cipher = Speck32::new([0x0100, 0x0908, 0x1110, 0x1918]);
// Encrypt a 32-bit block (2 x u16)
let plaintext = [0x6574u16, 0x694c];
let ciphertext = cipher.encrypt(plaintext);
let decrypted = cipher.decrypt(ciphertext);
assert_eq!(plaintext, decrypted);
```
### 48-bit and 96-bit block ciphers
Rust has no native 24-bit or 48-bit types, so these ciphers use `u32` and `u64` to store masked values:
```rust
use lwbc::Speck48;
// 48-bit block cipher: key is 4 x u32 (only lower 24 bits used)
let cipher = Speck48::new([0x020100, 0x0a0908, 0x121110, 0x1a1918]);
let ciphertext = cipher.encrypt([0x6d2073, 0x696874]);
// Byte-oriented: 6-byte blocks
let ct = cipher.encrypt_block([0x73, 0x20, 0x6d, 0x74, 0x68, 0x69]);
```
```rust
use lwbc::Speck96;
// 96-bit block cipher: key is 3 x u64 (only lower 48 bits used, m=3)
let cipher = Speck96::new([0x050403020100, 0x0d0c0b0a0908, 0x151413121110]);
let ciphertext = cipher.encrypt([0x656d6974206e, 0x69202c726576]);
// Byte-oriented: 12-byte blocks
let ct = cipher.encrypt_block([0x6e, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x69]);
```
### Byte-oriented API
```rust
use lwbc::Speck64;
// Initialize from raw bytes (little-endian)
let cipher = Speck64::from_bytes([
0x00, 0x01, 0x02, 0x03,
0x08, 0x09, 0x0a, 0x0b,
0x10, 0x11, 0x12, 0x13,
0x18, 0x19, 0x1a, 0x1b,
]);
// Encrypt/decrypt byte arrays directly
let plaintext = [0x74, 0x65, 0x72, 0x3b, 0x2d, 0x43, 0x75, 0x74];
let ciphertext = cipher.encrypt_block(plaintext);
let decrypted = cipher.decrypt_block(ciphertext);
```
### Key whitening
Whitened variants XOR additional key material before and after encryption, providing extra security margin with minimal overhead:
```rust
use lwbc::Speck32Whitened;
// Extended key: 4 words for cipher + 2 pre-whitening + 2 post-whitening
let cipher = Speck32Whitened::new([
0x0100, 0x0908, 0x1110, 0x1918, // cipher key
0xdead, 0xbeef, // pre-whitening
0xcafe, 0xbabe, // post-whitening
]);
let ciphertext = cipher.encrypt([0x6574, 0x694c]);
```
Available whitened types: `Speck32Whitened`, `Speck48Whitened`, `Speck64Whitened`, `Speck96Whitened`, `Simon32Whitened`, `Simon48Whitened`, `Simon64Whitened`, `Simon96Whitened`, `Simeck32Whitened`, `Simeck64Whitened`.
The 96-bit whitened variants take 7-word keys (3 cipher + 2 pre + 2 post) since they use the m=3 key schedule:
```rust
use lwbc::Speck96Whitened;
let cipher = Speck96Whitened::new([
0x050403020100, 0x0d0c0b0a0908, 0x151413121110, // cipher key (3 words)
0xdeadbeefcafe, 0xbabe12345678, // pre-whitening
0x9abcdef01234, 0x567890abcdef, // post-whitening
]);
```
## Cipher specifications
| SPECK32/64 | 32-bit | 64-bit | 22 | ARX (add-rotate-xor) |
| SPECK48/96 | 48-bit | 96-bit | 23 | ARX |
| SPECK64/128 | 64-bit | 128-bit | 27 | ARX |
| SPECK96/144 | 96-bit | 144-bit | 29 | ARX (m=3 key sched.) |
| SIMON32/64 | 32-bit | 64-bit | 32 | Feistel + bitwise ops |
| SIMON48/96 | 48-bit | 96-bit | 36 | Feistel + bitwise ops |
| SIMON64/128 | 64-bit | 128-bit | 44 | Feistel + bitwise ops |
| SIMON96/144 | 96-bit | 144-bit | 54 | Feistel (m=3 key) |
| SIMECK32/64 | 32-bit | 64-bit | 32 | Hybrid SIMON/SPECK |
| SIMECK64/128 | 64-bit | 128-bit | 44 | Hybrid SIMON/SPECK |
Word sizes: 32-bit variants use `u16`, 48-bit use `u32` (24-bit masked), 64-bit use `u32`, 96-bit use `u64` (48-bit masked).
Byte order: All byte-level operations use little-endian encoding.
## Performance
SPECK is the fastest due to its simple ARX structure. SIMON trades speed for smaller hardware implementation. SIMECK aims to balance both.
Run benchmarks with:
```sh
cargo run --release
```
## Security considerations
These ciphers provide strong encryption for their block sizes, but small blocks have inherent limitations:
- Birthday bound: With a 32-bit block, collision probability becomes significant after 2^16 blocks (~65K). For 48-bit blocks, after 2^24 (~16M). For 64-bit blocks, after 2^32 (~4B). For 96-bit blocks, after 2^48 (~281T).
- Block cipher modes: Use appropriate modes (CTR, CBC, etc.) and respect the birthday bound limits.
- Not a replacement for AES: Use standard 128-bit block ciphers when block size overhead is acceptable.
SPECK and SIMON were designed by the NSA and have undergone significant public cryptanalysis. SIMECK was designed by academic researchers at the University of Waterloo.
## References
- [The SIMON and SPECK Families of Lightweight Block Ciphers](https://eprint.iacr.org/2013/404.pdf) - Original NSA paper
- [The SIMECK Family of Lightweight Block Ciphers](https://eprint.iacr.org/2015/612.pdf) - Academic paper introducing SIMECK
- [SIMON and SPECK Implementation Guide](https://nsacyber.github.io/simon-speck/implementations/ImplementationGuide1.1.pdf) - NSA implementation reference