Skip to content

Commit

Permalink
nearing 0.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
eschorn1 committed Oct 30, 2023
1 parent cdf8198 commit 0fb0cba
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: integration
name: test

on:
pull_request:
Expand Down
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
# [IntegrityChain] FIPS 203 (Initial Public Draft): Module-Lattice-Based Key-Encapsulation Mechanism Standard
# [IntegrityChain]: FIPS 203 Module-Lattice-Based Key-Encapsulation Mechanism Standard

[![crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
[![Build Status][build-image]][build-link]
![Apache2/MIT licensed][license-image]
![Rust Version][rustc-image]

[MlKem] Module-Lattice-Based Key-Encapsulation Mechanism Standard written in pure Rust.
[FIPS 203] (Initial Public Draft) Module-Lattice-Based Key-Encapsulation Mechanism
Standard written in pure Rust.

This library implements the FIPS 203 **draft** standard in pure Rust with minimal and
mainstream dependencies. All three security parameter sets are fully functional. The
code does not require the standard library, e.g. `#[no_std]`, and has no heap
allocations so will be suitable for WASM, embedded and bare-metal applications.
Significant performance optimizations will be forthcoming.
Significant performance optimizations are forthcoming.

See: <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf>
See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf> for a full
description of the target functionality.

The functionality is very simple to use, per the following example.
The functionality is extremely simple to use, as demonstrated by the following example.

~~~rust
// Use the desired target parameter set
use ml_kem_rs::ml_kem_512; // Could also be ml_kem_1024 or ml_kem_768
// Use the desired target parameter set.
use ml_kem_rs::ml_kem_512; // Could also be ml_kem_768 or ml_kem_1024.

// Alice runs KeyGen, and then serializes the encaps key ek for Bob (to bytes)
// Alice runs `key_gen()` and then serializes the encaps key `ek` for Bob (to bytes).
let (alice_ek, alice_dk) = ml_kem_512::key_gen();
let alice_ek_bytes = alice_ek.to_bytes();

// Alice sends the encaps key ek_bytes to Bob
// Alice sends the encaps key `ek_bytes` to Bob.
let bob_ek_bytes = alice_ek_bytes;

// Bob deserializes the encaps ek_bytes, runs Encaps, to get the shared secret
// and ciphertext ct. He serializes the ciphertext ct for Alice (to bytes)
// Bob deserializes the encaps `ek_bytes` and then runs `encaps() to get the shared
// secret `ssk` and ciphertext `ct`. He serializes the ciphertext `ct` for Alice (to bytes).
let bob_ek = ml_kem_512::new_ek(bob_ek_bytes);
let (bob_ssk_bytes, bob_ct) = bob_ek.encaps();
let bob_ct_bytes = bob_ct.to_bytes();

// Bob sends the ciphertext ct_bytes to Alice
// Bob sends the ciphertext `ct_bytes` to Alice
let alice_ct_bytes = bob_ct_bytes;

// Alice deserializes the ciphertext_ct and runs Decaps with decaps key
// Alice deserializes the ciphertext `ct` and runs `decaps()` with her decaps key
let alice_ct = ml_kem_512::new_ct(alice_ct_bytes);
let alice_ssk_bytes = alice_dk.decaps( & alice_ct);
let alice_ssk_bytes = alice_dk.decaps(&alice_ct);

// Alice and Bob will now have the same secret key
assert_eq!(bob_ssk_bytes, alice_ssk_bytes);
~~~

[Documentation][docs-link]
Rust [Documentation][docs-link]

## Security Notes

This crate is under construction.
This crate is functional and corresponds to the first initial public draft of FIPS 203.

USE AT YOUR OWN RISK!

Expand Down Expand Up @@ -109,4 +111,4 @@ dual licensed as above, without any additional terms or conditions.

[IntegrityChain]: https://github.com/integritychain/

[MlKem]: https://csrc.nist.gov/pubs/fips/203/ipd
[FIPS 203]: https://csrc.nist.gov/pubs/fips/203/ipd
41 changes: 36 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
/// See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf>

// TODO
// 3. Implement bench, fix-->CT
// 4. Fix github actions
// 5. Review main Doc; features: no_std, no alloc, minimal dependencies, CT
// 6. Tag, Git push to CC, publish as 0.1.1
// 7. Re-read spec
// 1. Fix github actions
// 2. Tag, Git push to CC, publish as 0.1.1
#[cfg(test)]
extern crate alloc;

Expand Down Expand Up @@ -87,6 +84,7 @@ impl PartialEq for SharedSecretKey {
// This common functionality is injected into each parameter set module
macro_rules! functionality {
() => {

const ETA1_64: usize = ETA1 * 64; // Currently, Rust does not allow expressions involving
const ETA1_512: usize = ETA1 * 512; // constants in type expressions such as [u8, ETA1 * 64].
const ETA2_64: usize = ETA2 * 64; // So this is handled manually...what a pain
Expand Down Expand Up @@ -249,6 +247,17 @@ macro_rules! functionality {
/// ML-KEM-512 is claimed to be in security category 1, see table 2 & 3 on page 33.
#[cfg(feature = "ml_kem_512")]
pub mod ml_kem_512 {
//!
//! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf>
//!
//! Typical usage flow entails:
//! 1. The originator runs `key_gen()` to get an encaps key `encapsKey` and decaps key `decapsKey`.
//! 2. The originator deserializes the encaps key via `encapsKey.to_bytes()` and sends to the remote party.
//! 3. The remote party serializes the bytes via `new_ek(<bytes>)` to get the shared secret key `ssk` and ciphertext `cipherText`.
//! 4. The remote party deserializes the cipertext via `cipherText.to_bytes()` and sends to the originator.
//! 5. The originator serializes the ciphertext via `new_ct(<bytes>)` then runs `decapsKey.decaps(cipherText)` to the get shared secret ket `ssk`.
//! 6. Both the originator and remote party now have the same shared secret key `ssk`.

use crate::{ml_kem, SharedSecretKey};

const K: usize = 2;
Expand All @@ -267,6 +276,17 @@ pub mod ml_kem_512 {
/// ML-KEM-768 is claimed to be in security category 3, see table 2 & 3 on page 33.
#[cfg(feature = "ml_kem_768")]
pub mod ml_kem_768 {
//!
//! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf>
//!
//! Typical usage flow entails:
//! 1. The originator runs `key_gen()` to get an encaps key `encapsKey` and decaps key `decapsKey`.
//! 2. The originator deserializes the encaps key via `encapsKey.to_bytes()` and sends to the remote party.
//! 3. The remote party serializes the bytes via `new_ek(<bytes>)` to get the shared secret key `ssk` and ciphertext `cipherText`.
//! 4. The remote party deserializes the cipertext via `cipherText.to_bytes()` and sends to the originator.
//! 5. The originator serializes the ciphertext via `new_ct(<bytes>)` then runs `decapsKey.decaps(cipherText)` to the get shared secret ket `ssk`.
//! 6. Both the originator and remote party now have the same shared secret key `ssk`.

use crate::{ml_kem, SharedSecretKey};

const K: usize = 3;
Expand All @@ -285,6 +305,17 @@ pub mod ml_kem_768 {
/// ML-KEM-1024 is claimed to be in security category 5, see table 2 & 3 on page 33.
#[cfg(feature = "ml_kem_1024")]
pub mod ml_kem_1024 {
//!
//! See <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf>
//!
//! Typical usage flow entails:
//! 1. The originator runs `key_gen()` to get an encaps key `encapsKey` and decaps key `decapsKey`.
//! 2. The originator deserializes the encaps key via `encapsKey.to_bytes()` and sends to the remote party.
//! 3. The remote party serializes the bytes via `new_ek(<bytes>)` to get the shared secret key `ssk` and ciphertext `cipherText`.
//! 4. The remote party deserializes the cipertext via `cipherText.to_bytes()` and sends to the originator.
//! 5. The originator serializes the ciphertext via `new_ct(<bytes>)` then runs `decapsKey.decaps(cipherText)` to the get shared secret ket `ssk`.
//! 6. Both the originator and remote party now have the same shared secret key `ssk`.

use crate::{ml_kem, SharedSecretKey};

const K: usize = 4;
Expand Down
5 changes: 4 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::Q;

// While Z256 is nice, simple and correct, the performance is atrocious.
// This will be addressed (particularly in matrix operations etc).

/// Stored as u16, but arithmetic as u32 (so we can multiply/reduce/etc)
#[derive(Clone, Copy)]
pub struct Z256(pub u16);
Expand All @@ -14,7 +17,7 @@ impl Z256 {
self.0 = u16::try_from(a % Q).unwrap(); // TODO: Revisit
}

#[allow(dead_code)] // stitch in when we get overall correct
#[allow(dead_code)] // Barrett mult/reduce; Will be incorporated shortly...
pub fn mul(self, other: Self) -> Self {
let prod = u64::from(self.0) * u64::from(other.0);
let div = prod * (2u64.pow(24) / (u64::from(Q)));
Expand Down

0 comments on commit 0fb0cba

Please sign in to comment.