# sparx
[](https://hex.pm/packages/sparx)
[](https://hexdocs.pm/sparx/)
A pure Gleam implementation of the [SPARX](https://www.cryptolux.org/index.php/SPARX) family of lightweight block ciphers, designed by Leo Perrin and Daniel Dinu at CryptoLUX (University of Luxembourg).
All three official variants are implemented and verified against the reference test vectors:
| Variant | Block size | Key size |
|---|---|---|
| `sparx64` | 64-bit | 128-bit |
| `sparx128_128` | 128-bit | 128-bit |
| `sparx128_256` | 128-bit | 256-bit |
## Installation
```sh
gleam add sparx@1
```
## Usage
Keys and plaintexts are represented as tuples of `Uint16` values (16-bit words in little-endian order). Use `sparx/uint16.unsafe_from_int` to construct them from integer literals.
### SPARX-64/128
64-bit block, 128-bit key.
```gleam
import sparx/sparx64
import sparx/uint16
pub fn main() {
let key =
sparx64.key_schedule(#(
uint16.unsafe_from_int(0x0011),
uint16.unsafe_from_int(0x2233),
uint16.unsafe_from_int(0x4455),
uint16.unsafe_from_int(0x6677),
uint16.unsafe_from_int(0x8899),
uint16.unsafe_from_int(0xaabb),
uint16.unsafe_from_int(0xccdd),
uint16.unsafe_from_int(0xeeff),
))
let plaintext = #(
uint16.unsafe_from_int(0x0123),
uint16.unsafe_from_int(0x4567),
uint16.unsafe_from_int(0x89ab),
uint16.unsafe_from_int(0xcdef),
)
let ciphertext = sparx64.sparx_encrypt(plaintext, key)
// -> #(0x2bbe, 0xf152, 0x01f5, 0x5f98)
let recovered = sparx64.sparx_decrypt(ciphertext, key)
// -> plaintext
}
```
### SPARX-128/128
128-bit block, 128-bit key.
```gleam
import sparx/sparx128_128
import sparx/uint16
pub fn main() {
let key =
sparx128_128.key_schedule(#(
uint16.unsafe_from_int(0x0011),
uint16.unsafe_from_int(0x2233),
uint16.unsafe_from_int(0x4455),
uint16.unsafe_from_int(0x6677),
uint16.unsafe_from_int(0x8899),
uint16.unsafe_from_int(0xaabb),
uint16.unsafe_from_int(0xccdd),
uint16.unsafe_from_int(0xeeff),
))
let plaintext = #(
uint16.unsafe_from_int(0x0123),
uint16.unsafe_from_int(0x4567),
uint16.unsafe_from_int(0x89ab),
uint16.unsafe_from_int(0xcdef),
uint16.unsafe_from_int(0xfedc),
uint16.unsafe_from_int(0xba98),
uint16.unsafe_from_int(0x7654),
uint16.unsafe_from_int(0x3210),
)
let ciphertext = sparx128_128.sparx_encrypt(plaintext, key)
// -> #(0x1cee, 0x7540, 0x7dbf, 0x23d8, 0xe0ee, 0x1597, 0xf428, 0x52d8)
let recovered = sparx128_128.sparx_decrypt(ciphertext, key)
// -> plaintext
}
```
### SPARX-128/256
128-bit block, 256-bit key.
```gleam
import sparx/sparx128_256
import sparx/uint16
pub fn main() {
let key =
sparx128_256.key_schedule(#(
uint16.unsafe_from_int(0x0011),
uint16.unsafe_from_int(0x2233),
uint16.unsafe_from_int(0x4455),
uint16.unsafe_from_int(0x6677),
uint16.unsafe_from_int(0x8899),
uint16.unsafe_from_int(0xaabb),
uint16.unsafe_from_int(0xccdd),
uint16.unsafe_from_int(0xeeff),
uint16.unsafe_from_int(0xffee),
uint16.unsafe_from_int(0xddcc),
uint16.unsafe_from_int(0xbbaa),
uint16.unsafe_from_int(0x9988),
uint16.unsafe_from_int(0x7766),
uint16.unsafe_from_int(0x5544),
uint16.unsafe_from_int(0x3322),
uint16.unsafe_from_int(0x1100),
))
let plaintext = #(
uint16.unsafe_from_int(0x0123),
uint16.unsafe_from_int(0x4567),
uint16.unsafe_from_int(0x89ab),
uint16.unsafe_from_int(0xcdef),
uint16.unsafe_from_int(0xfedc),
uint16.unsafe_from_int(0xba98),
uint16.unsafe_from_int(0x7654),
uint16.unsafe_from_int(0x3210),
)
let ciphertext = sparx128_256.sparx_encrypt(plaintext, key)
// -> #(0x3328, 0xe637, 0x14c7, 0x6ce6, 0x32d1, 0x5a54, 0xe4b0, 0xc820)
let recovered = sparx128_256.sparx_decrypt(ciphertext, key)
// -> plaintext
}
```
## API Reference
Full documentation is available on [hexdocs.pm/sparx](https://hexdocs.pm/sparx).
### `sparx64`
| Function | Signature | Description |
|---|---|---|
| `key_schedule` | `(Masterkey) -> Subkeys` | Derives subkeys from a 128-bit master key (8-tuple of `Uint16`) |
| `sparx_encrypt` | `(Plaintext, Subkeys) -> Plaintext` | Encrypts a 64-bit block (4-tuple of `Uint16`) |
| `sparx_decrypt` | `(Plaintext, Subkeys) -> Plaintext` | Decrypts a 64-bit block |
### `sparx128_128`
| Function | Signature | Description |
|---|---|---|
| `key_schedule` | `(Masterkey) -> Subkeys` | Derives subkeys from a 128-bit master key (8-tuple of `Uint16`) |
| `sparx_encrypt` | `(Plaintext, Subkeys) -> Plaintext` | Encrypts a 128-bit block (8-tuple of `Uint16`) |
| `sparx_decrypt` | `(Plaintext, Subkeys) -> Plaintext` | Decrypts a 128-bit block |
### `sparx128_256`
| Function | Signature | Description |
|---|---|---|
| `key_schedule` | `(Masterkey) -> Subkeys` | Derives subkeys from a 256-bit master key (16-tuple of `Uint16`) |
| `sparx_encrypt` | `(Plaintext, Subkeys) -> Plaintext` | Encrypts a 128-bit block (8-tuple of `Uint16`) |
| `sparx_decrypt` | `(Plaintext, Subkeys) -> Plaintext` | Decrypts a 128-bit block |
## Security Notice
This library is a reference implementation for educational and research purposes. It has not been independently audited. Do not use it to protect sensitive data in production without a thorough security review.
## References
- [SPARX specification](https://www.cryptolux.org/index.php/SPARX)
- Perrin, L., Dinu, D., Biryukov, A.: *SPARX: A side-channel resistant ARX cipher*. ASIACRYPT 2016.
## Development
```sh
gleam test # Run the tests
gleam build # Build the project
```
## License
LGPL-3.0-or-later