SpeckEx
A high-performance Elixir library for the Speck block cipher, powered by Rust NIFs. Provides Speck in three modes: high-level CTR mode encryption, authenticated encryption in the form of Speck-Poly1305 and the primitive block cipher.
This package is in an experimental state. It has not been audited or reviewed, and its backing Rust packages haven’t either. The AEAD-mode in particular, combining Speck and Poly1305, is running dangerously close to “rolling your own encryption”. Use at your own risk.
Features
- 🚀 High Performance: Rust-backed implementation using NIFs for maximum speed
- 🔐 Complete: All 10 Speck cipher variants supported
- 🎯 Multiple Modes: Low-level block operations, CTR mode, and AEAD (Speck-Poly1305)
- ✅ Well Tested: Comprehensive test suite with official test vectors
Supported Variants
| Variant | Block Size | Key Size | CTR/AEAD Mode Support |
|---|---|---|---|
speck32_64 | 32-bit (4 bytes) | 64-bit (8 bytes) | ⚠️ |
speck48_72 | 48-bit (6 bytes) | 72-bit (9 bytes) | ❌ |
speck48_96 | 48-bit (6 bytes) | 96-bit (12 bytes) | ❌ |
speck64_96 | 64-bit (8 bytes) | 96-bit (12 bytes) | ⚠️ |
speck64_128 | 64-bit (8 bytes) | 128-bit (16 bytes) | ⚠️ |
speck96_96 | 96-bit (12 bytes) | 96-bit (12 bytes) | ❌ |
speck96_144 | 96-bit (12 bytes) | 144-bit (18 bytes) | ❌ |
speck128_128 | 128-bit (16 bytes) | 128-bit (16 bytes) | ✅ |
speck128_192 | 128-bit (16 bytes) | 192-bit (24 bytes) | ✅ |
speck128_256 | 128-bit (16 bytes) | 256-bit (32 bytes) | ✅ (default) |
Note: CTR and AEAD modes are only available for variants with standard block sizes (32, 64 and 128 bits) due to Rust ctr crate limitations. All variants support low-level block operations.
Because using 32 and 64 bits variants with CTR and AEAD modes is a very tricky proposition, they are unsupported through the main entrypoint module, and only available through the SpeckEx.CTR and SpeckEx.AEAD modules. You should not use them unless you have an exceedingly good reason to do so and you know what you are doing. You have been warned.
Installation
Add speck_ex to your list of dependencies in mix.exs:
def deps do
[
{:speck_ex, "~> 0.1.0"}
]
endDocumentation can be found on hexdocs.pm.
Precompiled binaries
SpeckEx includes precompiled NIFs for most common architectures (Linux, macOS, Windows on x86_64, ARM64, etc.). The Rust toolchain is not required for typical installations.
If you’re on an unsupported platform, Rustler will automatically compile from source during installation, which requires the Rust toolchain.
Quick Start
High-Level CTR Mode Encryption
# Generate a random key
key = :crypto.strong_rand_bytes(32) # 256-bit key
# Encrypt data - nonce is automatically generated and returned
plaintext = "Hello, World! This is a secret message."
{nonce, ciphertext} = SpeckEx.crypt(plaintext, key)
# Decrypt data - provide the nonce from encryption
{_nonce, decrypted} = SpeckEx.crypt(ciphertext, key, nonce: nonce)
# => "Hello, World! This is a secret message."
# Or manually provide a nonce (12 bytes)
nonce = :crypto.strong_rand_bytes(12)
{^nonce, ciphertext} = SpeckEx.crypt(plaintext, key, nonce: nonce)Authenticated Encryption (AEAD)
Speck-Poly1305 provides authenticated encryption, which protects both the confidentiality and integrity of your data.
# Generate a random key
key = :crypto.strong_rand_bytes(32)
aad = "user_id:12345" # Optional associated data (authenticated but not encrypted)
# Encrypt and authenticate - nonce is automatically generated and returned
{nonce, ciphertext, tag} = SpeckEx.aead_encrypt("Secret message", key, aad: aad)
# Verify and decrypt
{:ok, plaintext} = SpeckEx.aead_decrypt(ciphertext, tag, key, nonce, aad: aad)
# => {:ok, "Secret message"}
# Or manually provide a nonce (12 bytes)
nonce = :crypto.strong_rand_bytes(12)
{^nonce, ciphertext, tag} = SpeckEx.aead_encrypt("Secret message", key, nonce: nonce, aad: aad)Using Different Variants
# Speck128/128 (smaller key)
key = :crypto.strong_rand_bytes(16)
{nonce, ciphertext} = SpeckEx.crypt("Secret data", key, variant: :speck128_128)
# Note: Speck variants with smaller block sizes are not available via the main module.Advanced Usage: Low-Level Modules
For advanced users who need more control, SpeckEx provides low-level modules:
SpeckEx.Block- Direct block cipher operations (all variants)SpeckEx.CTR- CTR mode for block sizes 32, 64, 128 bitsSpeckEx.AEAD- AEAD mode for block sizes 32, 64, 128 bits
These modules have no safety guardrails. You must manage nonces correctly (full block size), understand counter space partitioning, and be aware of birthday bounds for smaller block sizes. Use the main SpeckEx module unless you have specific requirements and know what you’re doing.
Security Considerations
⚠️ Important Security Notes:
Read the documentation: You are strongly encouraged to read the comprehensive security guidelines in the
m:SpeckEx#module-security-guidelinesmodule documentation.Use the main module: The
SpeckExmodule provides important safety features including automatic nonce generation, proper counter space partitioning, and limiting access to only 128-bit block variants. UseSpeckEx.CTR,SpeckEx.AEAD, orSpeckEx.Blockonly if you have specific requirements and understand the risks.Encryption limits: Don’t encrypt more than 64 GiB with the same nonce. Cycle your key after 4 billion messages to avoid birthday bound issues.
Speck Cipher Status: Speck is an NSA-designed cipher optimized for performance on constrained devices. While no practical attacks are known, it has received less academic scrutiny than AES. Consider your threat model carefully - the authors themselves recommend AES whenever the available compute resources allow it.
Performance
SpeckEx leverages Rust NIFs for near-native performance. Speck is designed to be one of the fastest software ciphers, particularly on resource-constrained devices.
# AMD Ryzen AI 9 HX 375, Fedora 43
AES 128/256 block dec: 10_388_586 ops/s
AES 128/256 block enc: 10_230_587 ops/s
Speck 64/128 block dec: 9_060_300 ops/s
Speck 128/256 block enc: 8_921_293 ops/s
Speck 64/128 block enc: 8_806_018 ops/s
Speck 128/256 block dec: 8_651_637 ops/s
Blowfish 64/128 block enc: 7_985_090 ops/s
Blowfish 64/128 block dec: 7_628_045 ops/s
Speck 96/144 block enc: 7_482_359 ops/s
Speck 96/144 block dec: 6_736_502 ops/s
Speck 128/256 init + block enc: 3_011_647 ops/s
AES 128/256 init + block enc: 2_823_029 ops/s
AES 128/256 AEAD 1K blocks enc: 648_185 ops/s
AES 128/256 CTR 1K blocks enc: 474_121 ops/s
Speck 128/256 CTR 1K blocks enc: 53_783 ops/s
Blowfish 64/128 init + block enc: 47_983 ops/s
Speck 128/256 AEAD 1K blocks enc: 45_199 ops/s# Raspberry Pi 4, Raspbian 5 (Bookworm)
Speck 64/128 block enc: 1_152_034 ops/s
Speck 64/128 block dec: 1_139_208 ops/s
Speck 128/256 block dec: 1_133_155 ops/s
Speck 128/256 block enc: 1_092_916 ops/s
Speck 96/144 block enc: 1_086_639 ops/s
Speck 96/144 block dec: 1_044_686 ops/s
Blowfish 64/128 block enc: 889_855 ops/s
Blowfish 64/128 block dec: 865_773 ops/s
AES 128/256 block enc: 687_009 ops/s
AES 128/256 block dec: 604_879 ops/s
Speck 128/256 init + block enc: 329_179 ops/s
AES 128/256 init + block enc: 176_190 ops/s
Blowfish 64/128 init + block enc: 13_246 ops/s
Speck 128/256 CTR 1K blocks enc: 7_894 ops/s
Speck 128/256 AEAD 1K blocks enc: 6_363 ops/s
AES 128/256 CTR 1K blocks enc: 4_950 ops/s
AES 128/256 AEAD 1K blocks enc: 2_918 ops/s
All single thread runs. Run benchmarks with mix run benchmark/speck.exs. Notes:
-
The “init + block” runs are
:crypto.crypto_one_time/4equivalents. -
The “block” results are attained after initiation, so
:crypto.crypto_update/2equivalent. - The “CTR” results represent init + encrypting 16KB.
- The “AEAD” results represent init + encrypting + poly1305 16KB.
- Blowfish is notoriously slow to initialize and it shows.
- If you encrypt many small things with a different key (so you init every time), Speck is particularly quick.
- If you have AES hardware acceleration you should use AES.
License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
References
- Speck Cipher Specification
- IACR ePrint Archive: The SIMON and SPECK Families of Lightweight Block Ciphers
- Rust speck-cipher crate
- RustCrypto cipher traits
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Acknowledgments
- Built with Rustler for Elixir-Rust interoperability
- Uses the RustCrypto cipher traits and implementations