This is a conservative fork of Argyle-Software's Kyber crate.
A rust implementation of the Kyber algorithm, a KEM standardised by the NIST Post-Quantum Standardization Project.
This library:
- Is no_std compatible and needs no allocator, suitable for embedded devices.
- Reference files contain no unsafe code and are written in pure rust.
- Compiles to WASM using wasm-bindgen and has a ready-to-use binary published on NPM.
See the features section for different options regarding security levels and modes of operation. The default security setting is kyber768.
It is recommended to use Kyber in a hybrid system alongside a traditional key exchange algorithm such as X25519.
Please also read the security considerations before use.
Minimum Supported Rust Version: 1.56.0
cargo add safe_pqc_kyber
use safe_pqc_kyber::*;
// Generate Keypair
let keys_bob = keypair(&mut rng);
// Alice encapsulates a shared secret using Bob's public key
let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?;
// Bob decapsulates a shared secret using the ciphertext sent by Alice
let shared_secret_bob = decapsulate(&ciphertext, &keys_bob.secret)?;
assert_eq!(shared_secret_alice, shared_secret_bob);
let mut rng = rand::thread_rng();
// Initialize the key exchange structs
let mut alice = Uake::new();
let mut bob = Uake::new();
// Generate Bob's Keypair
let bob_keys = keypair(&mut rng);
// Alice initiates key exchange
let client_init = alice.client_init(&bob_keys.public, &mut rng);
// Bob authenticates and responds
let server_response = bob.server_receive(
client_init, &bob_keys.secret, &mut rng
)?;
// Alice decapsulates the shared secret
alice.client_confirm(server_response)?;
// Both key exchange structs now have the same shared secret
assert_eq!(alice.shared_secret, bob.shared_secret);
Follows the same workflow except Bob requires Alice's public keys:
let mut alice = Ake::new();
let mut bob = Ake::new();
let alice_keys = keypair(&mut rng);
let bob_keys = keypair(&mut rng);
let client_init = alice.client_init(&bob_keys.public, &mut rng);
let server_response = bob.server_receive(
client_init, &alice_keys.public, &bob_keys.secret, &mut rng
)?;
alice.client_confirm(server_response, &alice_keys.secret)?;
assert_eq!(alice.shared_secret, bob.shared_secret);
The KyberError enum has two variants:
-
InvalidInput - One or more inputs to a function are incorrectly sized. A possible cause of this is two parties using different security levels while trying to negotiate a key exchange.
-
Decapsulation - The ciphertext was unable to be authenticated. The shared secret was not decapsulated.
If no security level is specified then kyber768 is used by default as recommended by the authors. It is roughly equivalent to AES-192. Apart from the two security levels, all other features can be combined as needed. For example:
[dependencies]
safe_pqc_kyber = {version = "0.6.0", features = ["kyber512"]}
Feature | Description |
---|---|
std | Enable the standard library |
kyber512 | Enables kyber512 mode, with a security level roughly equivalent to AES-128. |
kyber1024 | Enables kyber1024 mode, with a security level roughly equivalent to AES-256. A compile-time error is raised if more than one security level is specified. |
wasm | For compiling to WASM targets |
zeroize | This will zero out the key exchange structs on drop using the zeroize crate |
benchmarking | Enables the criterion benchmarking suite |
The run_all_tests script will traverse all possible codepaths by running a matrix of the security levels, variants and crate features.
Known Answer Tests require deterministic rng seeds, enable kyber_kat
in RUSTFLAGS
to use them.
Using this outside of cargo test
will result in a compile-time error.
The test vector files are quite large, you will need to build them yourself from the C reference code.
There's a helper script to do this here.
# This example runs the basic tests for kyber768
cargo test
See the testing readme for more comprehensive info.
Uses criterion for benchmarking. If you have GNUPlot installed it will generate statistical graphs in ./target/criterion/
.
You will need to enable the benchmarking
feature.
See the benchmarking readme for information on correct usage.
The fuzzing suite uses honggfuzz, installation and instructions are on the fuzzing page.
While much care has been taken porting from the C reference codebase, this library has not undergone any third-party security auditing nor can any guarantees be made about the potential for underlying vulnerabilities in LWE cryptography or potential side-channel attacks arising from this implementation.
Kyber is relatively new, it is advised to use it in a hybrid key exchange system alongside a traditional algorithm like X25519 rather than by itself.
For further reading the IETF have a draft construction for hybrid key exchange in TLS 1.3:
https://www.ietf.org/archive/id/draft-ietf-tls-hybrid-design-04.html
You can also see how such a system is implemented here in C by OpenSSH
Please use at your own risk.
Kyber is an IND-CCA2-secure key encapsulation mechanism (KEM), whose security is based on the hardness of solving the learning-with-errors (LWE) problem over module lattices. It is the final standardised algorithm resulting from the NIST post-quantum cryptography project.
The official website: https://pq-crystals.org/kyber/
Authors of the Kyber Algorithm:
- Roberto Avanzi, ARM Limited (DE)
- Joppe Bos, NXP Semiconductors (BE)
- Léo Ducas, CWI Amsterdam (NL)
- Eike Kiltz, Ruhr University Bochum (DE)
- Tancrède Lepoint, SRI International (US)
- Vadim Lyubashevsky, IBM Research Zurich (CH)
- John M. Schanck, University of Waterloo (CA)
- Peter Schwabe, Radboud University (NL)
- Gregor Seiler, IBM Research Zurich (CH)
- Damien Stehle, ENS Lyon (FR)
Contributions welcome. For pull requests create a feature fork and submit it to the development branch. More information is available on the contributing page
The PQClean project has rust bindings for their Kyber C codebase: