diff --git a/.github/workflows/ml-kem.yml b/.github/workflows/ml-kem.yml index 6281f8b..8015ecb 100644 --- a/.github/workflows/ml-kem.yml +++ b/.github/workflows/ml-kem.yml @@ -23,32 +23,30 @@ jobs: with: msrv: 1.74.0 -# TODO -# no_std: -# needs: set-msrv -# runs-on: ubuntu-latest -# strategy: -# matrix: -# rust: -# - ${{needs.set-msrv.outputs.msrv}} -# - stable -# target: -# - thumbv7em-none-eabi -# - wasm32-unknown-unknown -# steps: -# - uses: actions/checkout@v4 -# - uses: RustCrypto/actions/cargo-cache@master -# - uses: dtolnay/rust-toolchain@master -# with: -# toolchain: ${{ matrix.rust }} -# targets: ${{ matrix.target }} -# - run: cargo build --no-default-features --target ${{ matrix.target }} + no_std: + needs: set-msrv + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - ${{needs.set-msrv.outputs.msrv}} + - stable + target: + - thumbv7em-none-eabi + - wasm32-unknown-unknown + steps: + - uses: actions/checkout@v4 + - uses: RustCrypto/actions/cargo-cache@master + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + - run: cargo build --no-default-features --target ${{ matrix.target }} -# TODO -# minimal-versions: -# uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master -# with: -# working-directory: ${{ github.workflow }} + minimal-versions: + uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master + with: + working-directory: ${{ github.workflow }} test: needs: set-msrv @@ -64,34 +62,31 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - - run: cargo build --all-features - # TODO(tarcieri): remove cargo build, run cargo test - #- run: cargo test --no-default-features - #- run: cargo test - #- run: cargo test --all-features + - run: cargo test --no-default-features + - run: cargo test + - run: cargo test --all-features -# TODO(tarcieri): miri -# miri: -# runs-on: ubuntu-latest -# env: -# MIRIFLAGS: "-Zmiri-symbolic-alignment-check -Zmiri-strict-provenance" -# strategy: -# matrix: -# target: -# - x86_64-unknown-linux-gnu -# - s390x-unknown-linux-gnu -# steps: -# - uses: actions/checkout@v4 -# - uses: RustCrypto/actions/cargo-cache@master -# - uses: dtolnay/rust-toolchain@master -# with: -# toolchain: nightly -# - name: Install Miri -# run: | -# rustup component add miri -# cargo miri setup -# - name: Test with Miri -# run: | -# cargo miri test --target ${{ matrix.target }} --no-default-features -# cargo miri test --target ${{ matrix.target }} -# cargo miri test --target ${{ matrix.target }} --all-features + miri: + runs-on: ubuntu-latest + env: + MIRIFLAGS: "-Zmiri-symbolic-alignment-check -Zmiri-strict-provenance" + strategy: + matrix: + target: + - x86_64-unknown-linux-gnu + - s390x-unknown-linux-gnu + steps: + - uses: actions/checkout@v4 + - uses: RustCrypto/actions/cargo-cache@master + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly + - name: Install Miri + run: | + rustup component add miri + cargo miri setup + - name: Test with Miri + run: | + cargo miri test --target ${{ matrix.target }} --no-default-features + cargo miri test --target ${{ matrix.target }} + cargo miri test --target ${{ matrix.target }} --all-features diff --git a/ml-kem/Cargo.toml b/ml-kem/Cargo.toml index d93c141..e4bceff 100644 --- a/ml-kem/Cargo.toml +++ b/ml-kem/Cargo.toml @@ -6,15 +6,14 @@ rust-version = "1.74" license = "Apache-2.0 OR MIT" [features] -default = [] +default = ["std"] +std = ["sha3/std"] deterministic = [] # Expose deterministic generation and encapsulation functions [dependencies] -const-default = "1.0.0" -crypto-common = { version = "0.1.6", features = ["getrandom"] } -generic-array = { version = "1.0.0", features = ["const-default"] } hybrid-array = { version = "0.2.0-rc.6" } -sha3 = "0.10.8" +rand_core = "0.6.4" +sha3 = { version = "0.10.8", default-features = false } [dev-dependencies] criterion = "0.5.1" diff --git a/ml-kem/src/crypto.rs b/ml-kem/src/crypto.rs index 9d6c343..7def894 100644 --- a/ml-kem/src/crypto.rs +++ b/ml-kem/src/crypto.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] -use crypto_common::rand_core::CryptoRngCore; use hybrid_array::{Array, ArraySize}; +use rand_core::CryptoRngCore; use sha3::{ digest::{ExtendableOutput, Update, XofReader}, Digest, Sha3_256, Sha3_512, Shake128, Shake256, diff --git a/ml-kem/src/encode.rs b/ml-kem/src/encode.rs index 285e393..9750218 100644 --- a/ml-kem/src/encode.rs +++ b/ml-kem/src/encode.rs @@ -144,7 +144,6 @@ where #[cfg(test)] pub(crate) mod test { use super::*; - use core::cmp::PartialEq; use core::fmt::Debug; use core::ops::Rem; use hybrid_array::typenum::{ diff --git a/ml-kem/src/kem.rs b/ml-kem/src/kem.rs index 2c5606f..580efa9 100644 --- a/ml-kem/src/kem.rs +++ b/ml-kem/src/kem.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use crypto_common::rand_core::CryptoRngCore; use hybrid_array::typenum::U32; +use rand_core::CryptoRngCore; use crate::crypto::{rand, G, H, J}; use crate::param::{DecapsulationKeySize, EncapsulationKeySize, EncodedCiphertext, KemParams}; diff --git a/ml-kem/src/lib.rs b/ml-kem/src/lib.rs index 5bd837f..3ac7766 100644 --- a/ml-kem/src/lib.rs +++ b/ml-kem/src/lib.rs @@ -56,11 +56,11 @@ pub mod kem; mod param; use core::fmt::Debug; -use crypto_common::rand_core::CryptoRngCore; use hybrid_array::{ typenum::{U10, U11, U2, U3, U4, U5}, Array, }; +use rand_core::CryptoRngCore; #[cfg(feature = "deterministic")] pub use util::B32; @@ -132,10 +132,25 @@ pub trait KemCore { type CiphertextSize: ArraySize; /// A decapsulation key for this KEM - type DecapsulationKey: Decapsulate, SharedKey> + Debug + PartialEq; + type DecapsulationKey: Decapsulate, SharedKey> + + EncodedSizeUser + + Debug + + PartialEq; /// An encapsulation key for this KEM - type EncapsulationKey: Encapsulate, SharedKey> + Debug + PartialEq; + #[cfg(not(feature = "deterministic"))] + type EncapsulationKey: Encapsulate, SharedKey> + + EncodedSizeUser + + Debug + + PartialEq; + + /// An encapsulation key for this KEM + #[cfg(feature = "deterministic")] + type EncapsulationKey: Encapsulate, SharedKey> + + EncapsulateDeterministic, SharedKey> + + EncodedSizeUser + + Debug + + PartialEq; /// Generate a new (decapsulation, encapsulation) key pair fn generate(rng: &mut impl CryptoRngCore) -> (Self::DecapsulationKey, Self::EncapsulationKey); diff --git a/ml-kem/src/util.rs b/ml-kem/src/util.rs index b0690e8..3a4ed98 100644 --- a/ml-kem/src/util.rs +++ b/ml-kem/src/util.rs @@ -12,77 +12,6 @@ use hybrid_array::{ /// A 32-byte array, defined here for brevity because it is used several times pub type B32 = Array; -/// Benchmarking shows that `Array::clone` does not optimize as well as this alternative -/// implementation. (Obviously, we can't re-implement Clone, so we have a new name.) -pub trait FastClone { - fn fast_clone(&self) -> Self; -} - -impl FastClone for Array -where - T: Copy + Default, - N: ArraySize, -{ - fn fast_clone(&self) -> Self { - self.map(Clone::clone) - } -} - -/// Benchmarking shows that the `FunctionalSequence` versions of `zip`, `fold`, and `map` do not -/// optimize as well as these alternative implementations. -pub trait FunctionalArray -where - N: ArraySize, -{ - fn map(&self, f: F) -> Array - where - U: Default, - F: Fn(&T) -> U; - - fn zip(&self, b: &Self, f: F) -> Array - where - U: Default, - F: Fn(&T, &T) -> U; - - fn fold(&self, f: F) -> T - where - T: Clone, - F: Fn(&T, &T) -> T; -} - -impl FunctionalArray for Array -where - N: ArraySize, -{ - fn map(&self, f: F) -> Array - where - U: Default, - F: Fn(&T) -> U, - { - Array::from_fn(|i| f(&self[i])) - } - - fn zip(&self, other: &Self, f: F) -> Array - where - U: Default, - F: Fn(&T, &T) -> U, - { - Array::from_fn(|i| f(&self[i], &other[i])) - } - - fn fold(&self, f: F) -> T - where - T: Clone, - F: Fn(&T, &T) -> T, - { - let mut out = self[0].clone(); - for i in 1..N::USIZE { - out = f(&out, &self[i]); - } - out - } -} - /// Safely truncate an unsigned integer value to shorter representation pub trait Truncate { fn truncate(self) -> T; diff --git a/ml-kem/tests/vectors.rs b/ml-kem/tests/vectors.rs index a5255c0..02c5f88 100644 --- a/ml-kem/tests/vectors.rs +++ b/ml-kem/tests/vectors.rs @@ -1,6 +1,6 @@ #![cfg(feature = "deterministic")] -use generic_array::GenericArray; +use hybrid_array::Array; use ml_kem::*; pub struct GenerateVector { @@ -12,8 +12,8 @@ pub struct GenerateVector { impl GenerateVector { pub fn verify(&self) { - let d = GenericArray::from_slice(&self.d); - let z = GenericArray::from_slice(&self.z); + let d = Array::from_slice(&self.d); + let z = Array::from_slice(&self.z); let (dk, ek) = K::generate_deterministic(d, z); assert_eq!(dk.as_bytes().as_slice(), self.dk); assert_eq!(ek.as_bytes().as_slice(), self.ek); @@ -35,10 +35,10 @@ pub struct EncapsulateVector { impl EncapsulateVector { pub fn verify(&self) { - let m = GenericArray::from_slice(&self.m); + let m = Array::from_slice(&self.m); let ek_bytes = Encoded::::from_slice(self.ek); let ek = K::EncapsulationKey::from_bytes(ek_bytes); - let (k, c) = ek.encapsulate_deterministic(m); + let (c, k) = ek.encapsulate_deterministic(m).unwrap(); assert_eq!(k.as_slice(), &self.k); assert_eq!(c.as_slice(), self.c); } @@ -56,7 +56,7 @@ impl DecapsulateVector { let dk = K::DecapsulationKey::from_bytes(dk_bytes); let c_bytes = Ciphertext::::from_slice(self.c); - let k = dk.decapsulate(c_bytes); + let k = dk.decapsulate(c_bytes).unwrap(); assert_eq!(k.as_slice(), &self.k); } }