sntrup
A pure-Rust implementation of Streamlined NTRU Prime for all parameter sizes.
NTRU Prime is a lattice-based cryptosystem aiming to improve the security of lattice schemes at minimal cost. It is thought to be resistant to quantum computing advances, in particular Shor's algorithm. It made it to NIST final round but was not selected for finalization.
Please read the warnings before use.
The algorithm was authored by Daniel J. Bernstein, Chitchanok Chuengsatiansup, Tanja Lange & Christine van Vredendaal. This implementation is aligned with the PQClean reference and verified against the IETF draft KAT vectors.
Parameter Sets
| Parameter Set | NIST Level | P | Q | W | Public Key | Secret Key | Ciphertext | Shared Secret |
|---|---|---|---|---|---|---|---|---|
| sntrup653 | 1 | 653 | 4621 | 288 | 994 | 1518 | 897 | 32 |
| sntrup761 | 2 | 761 | 4591 | 286 | 1158 | 1763 | 1039 | 32 |
| sntrup857 | 3 | 857 | 5167 | 322 | 1322 | 1999 | 1184 | 32 |
| sntrup953 | 4 | 953 | 6343 | 396 | 1505 | 2254 | 1349 | 32 |
| sntrup1013 | 5 | 1013 | 7177 | 448 | 1623 | 2417 | 1455 | 32 |
| sntrup1277 | 5 | 1277 | 7879 | 492 | 2067 | 3059 | 1847 | 32 |
All key and ciphertext sizes are in bytes. Sizes are fixed per parameter set using a canonical encoding enforced by the code.
Note: sntrup653 (NIST Level 1) is recommended for research and testing only. Prefer sntrup761 or higher for production use.
Features
- Pure Rust,
no_std-compatible, dependency-minimal - All six parameter sizes: sntrup653, sntrup761, sntrup857, sntrup953, sntrup1013, sntrup1277
- IND-CCA2 secure with implicit rejection
- Constant-time operations throughout (branchless sort, constant-time comparison and selection)
- SIMD acceleration (AVX2 on x86_64, NEON on aarch64) with automatic detection
- Optional
serdesupport via theserdefeature - Deterministic key generation from a 32-byte seed
Installation
Add to your Cargo.toml:
[]
= "0.1"
Feature Flags
The KEM API is split into three default features so downstream crates can pull in only what they need:
| Feature | Default | Description |
|---|---|---|
kgen |
yes | Key generation: SntrupKem::generate_key, SntrupKem::generate_key_deterministic |
ecap |
yes | Encapsulation: EncapsulationKey::encapsulate |
dcap |
yes | Decapsulation: DecapsulationKey::decapsulate |
force-scalar |
no | Disable SIMD (AVX2/NEON) and use pure-Rust scalar code |
serde |
no | Enables Serialize/Deserialize for all key and ciphertext types (via serdect for constant-time hex encoding) |
js |
no | Enables WebAssembly support for wasm32-unknown-unknown by configuring getrandom to use JavaScript's crypto.getRandomValues() |
To use only a subset of the KEM API, disable defaults and pick the features you need:
[]
# Decapsulation only (e.g. a receiver that never generates keys or encapsulates)
= { = "0.1", = false, = ["dcap"] }
Usage
Key generation
use ;
let mut rng = rng;
let = generate_key;
All six parameter sets are available as type aliases:
use ;
let mut rng = rng;
let = generate_key;
let = generate_key;
let = generate_key;
let = generate_key;
let = generate_key;
let = generate_key;
Or use the convenience modules with parameter-specific types:
let mut rng = rng;
let = generate_key;
Encapsulation
The sender uses the encapsulation (public) key to produce a ciphertext and shared secret:
use ;
let mut rng = rng;
let = generate_key;
// Sender side
let = encapsulation_key.encapsulate;
Decapsulation
The receiver uses the decapsulation (secret) key and the ciphertext to recover the shared secret:
use ;
let mut rng = rng;
let = generate_key;
let = encapsulation_key.encapsulate;
// Receiver side — implicit rejection: always returns a key
let shared_secret_receiver = decapsulation_key.decapsulate;
assert_eq!;
Deterministic key generation
Derive the same keypair from a 32-byte seed:
use ;
let seed = ; // must come from a cryptographically secure source
let = generate_key_deterministic;
let = generate_key_deterministic;
assert_eq!;
assert_eq!;
Serialization with serde
Enable the serde feature:
= { = "0.1", = ["serde"] }
Keys and ciphertexts serialize to hex in human-readable formats (JSON) and raw bytes in binary formats (postcard, bincode):
use ;
let mut rng = rng;
let = generate_key;
let json = to_string.unwrap;
let ek2: = from_str.unwrap;
assert_eq!;
Byte conversions
All types support AsRef<[u8]> and TryFrom<&[u8]>:
use ;
let mut rng = rng;
let = generate_key;
// Serialize to bytes
let ek_bytes: & = ek.as_ref;
// Deserialize from bytes (validates size)
let ek2 = try_from.unwrap;
assert_eq!;
WebAssembly
To compile for wasm32-unknown-unknown, enable the js feature so that getrandom uses JavaScript's crypto.getRandomValues() for randomness:
[]
= { = "0.1", = ["js"] }
Install the target and build:
For wasm32-wasi (or wasm32-wasip1), the js feature is not needed since WASI provides its own random source.
Security Properties
- IND-CCA2 security via implicit rejection: decapsulation always returns a shared key. On failure, a pseudorandom key is derived from secret randomness (
rho), making it indistinguishable from a valid key to an attacker. - Hash domain separation: all hashes use prefix bytes (following the NTRU Prime specification).
- Constant-time operations: branchless sorting (djbsort), constant-time weight checks, constant-time ciphertext comparison, and constant-time selection in decapsulation.
- Zeroization: secret key material is zeroized on drop.
Warnings
Implementation
This implementation has not undergone any security auditing and while care has been taken no guarantees can be made for either correctness or the constant time running of the underlying functions. Please use at your own risk.
Algorithm
Streamlined NTRU Prime was first published in 2016. The algorithm still requires careful security review. Please see here for further warnings from the authors regarding NTRU Prime and lattice-based encryption schemes.
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.