Skip to content

Commit

Permalink
ml-kem: add real CI (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
bifurcation authored Mar 3, 2024
1 parent 893c3bc commit 62a05d7
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 143 deletions.
105 changes: 50 additions & 55 deletions .github/workflows/ml-kem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
9 changes: 4 additions & 5 deletions ml-kem/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion ml-kem/src/crypto.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
1 change: 0 additions & 1 deletion ml-kem/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
2 changes: 1 addition & 1 deletion ml-kem/src/kem.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down
21 changes: 18 additions & 3 deletions ml-kem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -132,10 +132,25 @@ pub trait KemCore {
type CiphertextSize: ArraySize;

/// A decapsulation key for this KEM
type DecapsulationKey: Decapsulate<Ciphertext<Self>, SharedKey<Self>> + Debug + PartialEq;
type DecapsulationKey: Decapsulate<Ciphertext<Self>, SharedKey<Self>>
+ EncodedSizeUser
+ Debug
+ PartialEq;

/// An encapsulation key for this KEM
type EncapsulationKey: Encapsulate<Ciphertext<Self>, SharedKey<Self>> + Debug + PartialEq;
#[cfg(not(feature = "deterministic"))]
type EncapsulationKey: Encapsulate<Ciphertext<Self>, SharedKey<Self>>
+ EncodedSizeUser
+ Debug
+ PartialEq;

/// An encapsulation key for this KEM
#[cfg(feature = "deterministic")]
type EncapsulationKey: Encapsulate<Ciphertext<Self>, SharedKey<Self>>
+ EncapsulateDeterministic<Ciphertext<Self>, SharedKey<Self>>
+ EncodedSizeUser
+ Debug
+ PartialEq;

/// Generate a new (decapsulation, encapsulation) key pair
fn generate(rng: &mut impl CryptoRngCore) -> (Self::DecapsulationKey, Self::EncapsulationKey);
Expand Down
71 changes: 0 additions & 71 deletions ml-kem/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8, U32>;

/// 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<T, N> FastClone for Array<T, N>
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<T, N>
where
N: ArraySize,
{
fn map<U, F>(&self, f: F) -> Array<U, N>
where
U: Default,
F: Fn(&T) -> U;

fn zip<U, F>(&self, b: &Self, f: F) -> Array<U, N>
where
U: Default,
F: Fn(&T, &T) -> U;

fn fold<F>(&self, f: F) -> T
where
T: Clone,
F: Fn(&T, &T) -> T;
}

impl<T, N> FunctionalArray<T, N> for Array<T, N>
where
N: ArraySize,
{
fn map<U, F>(&self, f: F) -> Array<U, N>
where
U: Default,
F: Fn(&T) -> U,
{
Array::from_fn(|i| f(&self[i]))
}

fn zip<U, F>(&self, other: &Self, f: F) -> Array<U, N>
where
U: Default,
F: Fn(&T, &T) -> U,
{
Array::from_fn(|i| f(&self[i], &other[i]))
}

fn fold<F>(&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<T> {
fn truncate(self) -> T;
Expand Down
12 changes: 6 additions & 6 deletions ml-kem/tests/vectors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg(feature = "deterministic")]

use generic_array::GenericArray;
use hybrid_array::Array;
use ml_kem::*;

pub struct GenerateVector {
Expand All @@ -12,8 +12,8 @@ pub struct GenerateVector {

impl GenerateVector {
pub fn verify<K: KemCore>(&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);
Expand All @@ -35,10 +35,10 @@ pub struct EncapsulateVector {

impl EncapsulateVector {
pub fn verify<K: KemCore>(&self) {
let m = GenericArray::from_slice(&self.m);
let m = Array::from_slice(&self.m);
let ek_bytes = Encoded::<K::EncapsulationKey>::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);
}
Expand All @@ -56,7 +56,7 @@ impl DecapsulateVector {
let dk = K::DecapsulationKey::from_bytes(dk_bytes);

let c_bytes = Ciphertext::<K>::from_slice(self.c);
let k = dk.decapsulate(c_bytes);
let k = dk.decapsulate(c_bytes).unwrap();
assert_eq!(k.as_slice(), &self.k);
}
}

0 comments on commit 62a05d7

Please sign in to comment.