Skip to content

Commit

Permalink
Merge branch 'dev' into franziskus/mlkem-c
Browse files Browse the repository at this point in the history
  • Loading branch information
franziskuskiefer committed Jun 3, 2024
2 parents 95c3ab5 + f22a356 commit ab7694b
Show file tree
Hide file tree
Showing 27 changed files with 7,235 additions and 16 deletions.
97 changes: 97 additions & 0 deletions .github/workflows/mldsa.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: ML-DSA

on:
push:
branches: ["main", "dev"]
pull_request:
branches: ["main", "dev", "*"]
workflow_dispatch:
merge_group:

env:
CARGO_TERM_COLOR: always

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
strategy:
fail-fast: false
matrix:
bits: [32, 64]
os:
- macos-13 # Intel mac
- macos-latest # macos-14 m1
- ubuntu-latest
- windows-latest
exclude:
- bits: 32
os: "macos-latest"
- bits: 32
os: "macos-13"

runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
working-directory: libcrux-ml-dsa

steps:
- uses: actions/checkout@v4

- run: echo "RUST_TARGET_FLAG=" > $GITHUB_ENV
if: ${{ matrix.bits == 64 }}

- name: 🛠️ Setup Rust Nightly
run: rustup toolchain install nightly

- name: 🛠️ Setup Ubuntu x86
if: ${{ matrix.bits == 32 && matrix.os == 'ubuntu-latest' }}
run: |
rustup target add i686-unknown-linux-gnu
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib
- name: 🛠️ Setup Ubuntu x64
if: ${{ matrix.bits == 64 && matrix.os == 'ubuntu-latest' }}
run: |
rustup target add aarch64-unknown-linux-gnu
# Set up 32 bit systems

- name: 🛠️ Config Windows x86
run: echo "RUST_TARGET_FLAG=--target=i686-pc-windows-msvc" > $GITHUB_ENV
if: ${{ matrix.bits == 32 && matrix.os == 'windows-latest' }}

- name: 🛠️ Config Linux x86
run: |
echo "RUST_TARGET_FLAG=--target=i686-unknown-linux-gnu" > $GITHUB_ENV
if: ${{ matrix.bits == 32 && matrix.os == 'ubuntu-latest' }}

# Build ...

- name: 🔨 Build
run: |
rustc --print=cfg
cargo build --verbose $RUST_TARGET_FLAG
- name: 🔨 Build Release
run: cargo build --verbose --release $RUST_TARGET_FLAG

- name: 🏃🏻 Asan MacOS
if: ${{ matrix.os == 'macos-latest' }}
run: RUSTDOCFLAGS=-Zsanitizer=address RUSTFLAGS=-Zsanitizer=address cargo +nightly test --release --target aarch64-apple-darwin

# Test ML-DSA

- name: 🏃🏻‍♀️ Test
run: |
cargo clean
cargo test --verbose $RUST_TARGET_FLAG
- name: 🏃🏻‍♀️ Test Release
run: |
cargo clean
cargo test --verbose --release $RUST_TARGET_FLAG
1 change: 1 addition & 0 deletions libcrux-ml-dsa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ readme.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libcrux-sha3 = { version = "0.0.2-pre.2", path = "../libcrux-sha3" }

[dev-dependencies]
hex = { version = "0.4.3", features = ["serde"] }
Expand Down
63 changes: 63 additions & 0 deletions libcrux-ml-dsa/src/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use crate::constants::{BITS_IN_LOWER_PART_OF_T, COEFFICIENTS_IN_RING_ELEMENT, FIELD_MODULUS};

/// Values having this type hold a representative 'x' of the ML-DSA field.
pub(crate) type FieldElement = i32;

#[derive(Clone, Copy)]
pub struct PolynomialRingElement {
pub(crate) coefficients: [FieldElement; COEFFICIENTS_IN_RING_ELEMENT],
}

impl PolynomialRingElement {
pub const ZERO: Self = Self {
// FIXME: hax issue, 256 is COEFFICIENTS_IN_RING_ELEMENT
coefficients: [0i32; 256],
};
}

// Splits 0 ≤ t < Q into t0 and t1 with a = t1*2ᴰ + t0
// and -2ᴰ⁻¹ < t0 < 2ᴰ⁻¹. Returns t0 and t1 computed as.
//
// - t0 = t mod± 2ᵈ
// - t1 = (t - t0) / 2ᵈ.
//
// This approach has been taken from:
// https://github.com/cloudflare/circl/blob/main/sign/dilithium/internal/common/field.go#L35
pub(crate) fn power2round(t: i32) -> (i32, i32) {
debug_assert!(t >= 0 && t < FIELD_MODULUS);

// Compute t mod 2ᵈ
// t0 is now one of 0, 1, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹, 2ᵈ⁻¹+1, ..., 2ᵈ-1
let mut t0 = t & ((1 << BITS_IN_LOWER_PART_OF_T) - 1);

// now t0 is -2ᵈ⁻¹-1, -2ᵈ⁻¹, ..., -2, -1, 0, ..., 2ᵈ⁻¹-2
t0 -= (1 << (BITS_IN_LOWER_PART_OF_T - 1)) + 1;

// Next, we add 2ᴰ to those t0 that are negative
// now a0 is 2ᵈ⁻¹-1, 2ᵈ⁻¹, ..., 2ᵈ-2, 2ᵈ-1, 0, ..., 2ᵈ⁻¹-2
t0 += (t0 >> 31) & (1 << BITS_IN_LOWER_PART_OF_T);

// now t0 is 0, 1, 2, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹-1, -2ᵈ⁻¹-1, ...
// which is what we want.
t0 -= (1 << (BITS_IN_LOWER_PART_OF_T - 1)) - 1;

let t1 = (t - t0) >> BITS_IN_LOWER_PART_OF_T;

(t0, t1)
}

pub(crate) fn t0_to_unsigned_representative(t0: i32) -> i32 {
(1 << (BITS_IN_LOWER_PART_OF_T - 1)) - t0
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_power2round() {
assert_eq!(power2round(2898283), (-1685, 354));
assert_eq!(power2round(3821421), (3949, 466));
assert_eq!(power2round(2577417), (-3063, 315));
}
}
13 changes: 12 additions & 1 deletion libcrux-ml-dsa/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
pub(crate) const FIELD_MODULUS: i32 = 8_380_417;

pub(crate) const COEFFICIENTS_IN_RING_ELEMENT: usize = 256;

pub(crate) const FIELD_MODULUS_MINUS_ONE_BIT_LENGTH: usize = 23;

pub(crate) const DROPPED_BITS_FROM_T: usize = 13;
pub(crate) const BITS_IN_LOWER_PART_OF_T: usize = 13;

pub(crate) const BITS_IN_UPPER_PART_OF_T: usize =
FIELD_MODULUS_MINUS_ONE_BIT_LENGTH - BITS_IN_LOWER_PART_OF_T;

pub(crate) const SEED_FOR_A_SIZE: usize = 32;
pub(crate) const HASH_OF_PUBLIC_KEY_SIZE: usize = 64;
pub(crate) const SEED_FOR_SIGNING_SIZE: usize = 32;
36 changes: 36 additions & 0 deletions libcrux-ml-dsa/src/hash_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![allow(non_snake_case)]
pub(crate) fn H<const OUTPUT_LENGTH: usize>(input: &[u8]) -> [u8; OUTPUT_LENGTH] {
let mut out = [0u8; OUTPUT_LENGTH];
libcrux_sha3::portable::shake256(&mut out, input);

out
}

pub(crate) mod H_128 {
use libcrux_sha3::portable::{incremental, KeccakState1};

const BLOCK_SIZE: usize = 168;
const FIVE_BLOCKS_SIZE: usize = BLOCK_SIZE * 5;

#[inline(always)]
pub(crate) fn new(seed: [u8; 34]) -> KeccakState1 {
let mut state = incremental::shake128_init();
incremental::shake128_absorb_final(&mut state, &seed);

state
}

pub(crate) fn squeeze_first_five_blocks(state: &mut KeccakState1) -> [u8; FIVE_BLOCKS_SIZE] {
let mut out = [0u8; FIVE_BLOCKS_SIZE];
incremental::shake128_squeeze_first_five_blocks(state, &mut out);

out
}

pub(crate) fn squeeze_next_block(state: &mut KeccakState1) -> [u8; BLOCK_SIZE] {
let mut out = [0u8; BLOCK_SIZE];
incremental::shake128_squeeze_next_block(state, &mut out);

out
}
}
7 changes: 7 additions & 0 deletions libcrux-ml-dsa/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
mod arithmetic;
mod constants;
mod hash_functions;
mod matrix;
mod sample;
mod serialize;
mod utils;

mod ml_dsa_generic;

pub mod ml_dsa_65;
27 changes: 27 additions & 0 deletions libcrux-ml-dsa/src/matrix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::{arithmetic::PolynomialRingElement, sample::sample_ring_element_uniform};

#[allow(non_snake_case)]
#[inline(always)]
pub(crate) fn expand_to_A<const ROWS_IN_A: usize, const COLUMNS_IN_A: usize>(
mut seed: [u8; 34],
transposed: bool,
) -> [[PolynomialRingElement; COLUMNS_IN_A]; ROWS_IN_A] {
let mut A = [[PolynomialRingElement::ZERO; COLUMNS_IN_A]; ROWS_IN_A];

for i in 0..ROWS_IN_A {
for j in 0..COLUMNS_IN_A {
seed[32] = i as u8;
seed[33] = j as u8;

let sampled = sample_ring_element_uniform(seed);

if transposed {
A[j][i] = sampled;
} else {
A[i][j] = sampled;
}
}
}

A
}
34 changes: 24 additions & 10 deletions libcrux-ml-dsa/src/ml_dsa_65.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,37 @@ use crate::constants::*;
const ROWS_IN_A: usize = 6;
const COLUMNS_IN_A: usize = 5;

const PUBLIC_KEY_SIZE: usize =
32 + (32 * ROWS_IN_A * (FIELD_MODULUS_MINUS_ONE_BIT_LENGTH - DROPPED_BITS_FROM_T));
const SECRET_KEY_SIZE: usize =
(32 + 32 + 64) + 32 * (((ROWS_IN_A + COLUMNS_IN_A) * 4) + (DROPPED_BITS_FROM_T * ROWS_IN_A));
const ETA: usize = 4;
const TWO_TIMES_ETA_BIT_SIZE: usize = 4; // ⌊log_2(4)⌋ + 1

const VERIFICATION_KEY_SIZE: usize = SEED_FOR_A_SIZE
+ (COEFFICIENTS_IN_RING_ELEMENT
* ROWS_IN_A
* (FIELD_MODULUS_MINUS_ONE_BIT_LENGTH - BITS_IN_LOWER_PART_OF_T))
/ 8;

const SIGNING_KEY_SIZE: usize = (SEED_FOR_A_SIZE + SEED_FOR_SIGNING_SIZE + HASH_OF_PUBLIC_KEY_SIZE)
+ (COEFFICIENTS_IN_RING_ELEMENT
* (((ROWS_IN_A + COLUMNS_IN_A) * TWO_TIMES_ETA_BIT_SIZE)
+ (BITS_IN_LOWER_PART_OF_T * ROWS_IN_A)))
/ 8;

pub struct MLDSA65KeyPair {
pub secret_key: [u8; SECRET_KEY_SIZE],
pub public_key: [u8; PUBLIC_KEY_SIZE],
pub signing_key: [u8; SIGNING_KEY_SIZE],
pub verification_key: [u8; VERIFICATION_KEY_SIZE],
}

/// Generate an ML-DSA-65 Key Pair
pub fn generate_key_pair(randomness: [u8; 32]) -> MLDSA65KeyPair {
let (secret_key, public_key) =
crate::ml_dsa_generic::generate_key_pair::<SECRET_KEY_SIZE, PUBLIC_KEY_SIZE>(randomness);
let (signing_key, verification_key) = crate::ml_dsa_generic::generate_key_pair::<
ROWS_IN_A,
COLUMNS_IN_A,
SIGNING_KEY_SIZE,
VERIFICATION_KEY_SIZE,
>(randomness);

MLDSA65KeyPair {
secret_key,
public_key,
signing_key,
verification_key,
}
}
19 changes: 16 additions & 3 deletions libcrux-ml-dsa/src/ml_dsa_generic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
pub(crate) fn generate_key_pair<const SECRET_KEY_SIZE: usize, const PUBLIC_KEY_SIZE: usize>(
use crate::{hash_functions::H, matrix::expand_to_A, utils::into_padded_array};

#[allow(non_snake_case)]
pub(crate) fn generate_key_pair<
const ROWS_IN_A: usize,
const COLUMNS_IN_A: usize,
const SIGNING_KEY_SIZE: usize,
const VERIFICATION_KEY_SIZE: usize,
>(
randomness: [u8; 32],
) -> ([u8; SECRET_KEY_SIZE], [u8; PUBLIC_KEY_SIZE]) {
let _ = randomness;
) -> ([u8; SIGNING_KEY_SIZE], [u8; VERIFICATION_KEY_SIZE]) {
let seed_expanded = H::<1024>(&randomness);
let (seed_for_A, seed_expanded) = seed_expanded.split_at(32);
let (_seed_for_short_vectors, _random_seed_for_signing) = seed_expanded.split_at(64);

let _A_hat = expand_to_A::<ROWS_IN_A, COLUMNS_IN_A>(into_padded_array(seed_for_A), false);

todo!();
}
Loading

0 comments on commit ab7694b

Please sign in to comment.