Add safe Rust wrappers for ML-KEM-768 and ML-KEM-1024#456
Add safe Rust wrappers for ML-KEM-768 and ML-KEM-1024#456kornelski merged 1 commit intocloudflare:masterfrom
Conversation
3daa1d4 to
131049c
Compare
cjpatton
left a comment
There was a problem hiding this comment.
It should be possible to deduplicate this code using traits.
pub trait Kem {
/// Note: SEED_BYTES and SHARED_SECRET_BYTES are the same for all ML-KEM parameters
const PUBLIC_KEY_BYTES: usize;
const CIPHERTEXT_BYTES: usize;
type PublicKey;
type PrivateKey;
}
pub trait KemOps: Kem {
fn generate() -> (Kem::PublicKey, Kem::PrivateKey) { ... }
fn encapsulate ..
fn decapsulate ...
}719707e to
377c7b3
Compare
377c7b3 to
cb22731
Compare
cjpatton
left a comment
There was a problem hiding this comment.
Hmm, I think defining the Kem and KemOps traits are worth it unless we can actually deduplicate between MLKEM768 and 1024. I think we'll either need to live with duplicated code (I'd be OK with this) or figure out something else.
I think the fundamental problem is that the API we're trying to design doesn't quite match the API of BoringSSL.
I think hash.rs in this directory may provide the inspiration we need. There is a struct Hasher that has a constructor (new) that takes in MessageDigest that defines the algorithm in use (SHA-256, SHA-384, etc.). Then the API calls for actually using the hash is the same regardless of which algorithm is used.
I think we could do the same thing for a struct Kem. Its constructor would determine whether we're using 768 or 1024, and it would have a unified API. One wrinkle is that we would need to handle the the public key and private key as byte strings, but I think that's pretty reasonable.
For example:
pub MlKemParam(...);
pub struct MlKem { ... }
impl MlKem {
pub fn new(p: MlKemParam) -> Result<Self, ErrorStack> { ... }
pub fn key_gen(&self) -> Result<(Vec<u8>, [SEED_BYTES; u8]), ErrorStack> { ... } // returns public key, private key
pub fn encapsulate(&self, pk: &[u8]) -> Result<(Vec<u8>, [SHARED_SECRET_BYTES; u8], ErrorStack> { ... } // returns ciphertext
pub fn decapsulate(&self, sk: &[u8], ciphertext: &[u8]) -> Result<[u8; SHARED_SECRET_BYTES], ErrorStack> { ... }
}Notes:
- Elsewhere in this crate crypto operations return ErrorStack instead of a module-specific error type. I think that's probably appropriate here as well.
- The length of the public key and ciphertext depend on the KEM type, which is why I've handled them as a vector. Unfortunately we can't use an array without adding the length of the array as a generic
const. This could work, but would clutter the API unnecessarily. An alternative that we can make alloc-free is have the user pass a&mut [u8]buffer and fail if it's the wrong size.
afaefeb to
3de4e6a
Compare
kornelski
left a comment
There was a problem hiding this comment.
Oops, I forgot GitHub wants to buffer source review comments, and didn't post my comments yesterday.
boring/src/mlkem.rs
Outdated
|
|
||
| let mut bytes = [0u8; mlkem768::PUBLIC_KEY_BYTES]; | ||
| let mut cbb: MaybeUninit<ffi::CBB> = MaybeUninit::uninit(); | ||
| ffi::CBB_init_fixed(cbb.as_mut_ptr(), bytes.as_mut_ptr(), bytes.len()); |
There was a problem hiding this comment.
Please add error checking. There are cvt_* helpers for this.
boring/src/mlkem.rs
Outdated
| impl Drop for MlKem1024PrivateKey { | ||
| fn drop(&mut self) { | ||
| // zeroize seed | ||
| self.seed.iter_mut().for_each(|b| *b = 0); |
There was a problem hiding this comment.
Please use OPENSSL_cleanse for consistency with other key implementations, which already ensures to use proper functions that won't be optimized out.
5a32c66 to
1d5cc23
Compare
1d5cc23 to
47452a9
Compare
| use crate::error::ErrorStack; | ||
| use crate::ffi; | ||
|
|
||
| // CBS_init is inline in BoringSSL, so bindgen can't generate bindings for it. |
There was a problem hiding this comment.
I don't expect CBS_init to change, but this is not ideal at all! @davidben thoughts?
There was a problem hiding this comment.
bindgen has a --wrap-static-fns feature. If you use that, it picks up our inline functions just fine.
rust-lang/rust-bindgen#2405
|
I think it's good to merge. We can still iterate on it in followup PRs. |
Adds safe Rust wrappers around BoringSSL's ML-KEM (FIPS 203) key encapsulation, covering both ML-KEM-768 and ML-KEM-1024 parameter sets.