Skip to content

Implementation of ML-DSA#10

Open
jnsiemer wants to merge 5 commits into
devfrom
ml_dsa
Open

Implementation of ML-DSA#10
jnsiemer wants to merge 5 commits into
devfrom
ml_dsa

Conversation

@jnsiemer
Copy link
Copy Markdown
Member

Description

This PR implements...

  • a not up-to-spec implementation of ML-DSA,
  • benchmarks for ML-DSA

Testing

  • I added basic working examples (possibly in doc-comment)

Checklist:

  • I have performed a self-review of my own code
    • The code provides good readability and maintainability s.t. it fulfills best practices like talking code, modularity, ...
      • The chosen implementation is not more complex than it has to be
    • My code should work as intended and no side effects occur (e.g. memory leaks)
    • The doc comments fit our style guide
    • I have credited related sources if needed

Benchmarks

Quickly run benchmarks on my old laptop

ML-DSA cycle 44         time:   [5.2569 ms 5.4252 ms 5.6071 ms]                            
ML-DSA key_gen 44       time:   [971.81 µs 972.22 µs 972.64 µs]                               
ML-DSA sign 44          time:   [3.1065 ms 3.2465 ms 3.3897 ms]                            
ML-DSA vfy 44           time:   [1.2287 ms 1.2292 ms 1.2298 ms]                           

ML-DSA cycle 65         time:   [9.6770 ms 10.354 ms 11.109 ms]                            
ML-DSA key_gen 65       time:   [1.7178 ms 1.8538 ms 2.0244 ms]                               
ML-DSA sign 65          time:   [5.9097 ms 6.5367 ms 7.2212 ms]                           
ML-DSA vfy 65           time:   [2.1117 ms 2.1128 ms 2.1139 ms]                           

ML-DSA cycle 87         time:   [13.540 ms 14.042 ms 14.560 ms]                            
ML-DSA key_gen 87       time:   [2.8620 ms 2.8640 ms 2.8660 ms]                               
ML-DSA sign 87          time:   [6.2018 ms 6.5699 ms 6.9440 ms]                           
ML-DSA vfy 87           time:   [3.6565 ms 3.7136 ms 3.8167 ms]

@jnsiemer jnsiemer self-assigned this Apr 26, 2026
@jnsiemer jnsiemer added the enhancement📈 New feature or request label Apr 26, 2026
Copy link
Copy Markdown
Member

@Marvin-Beckmann Marvin-Beckmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mostly minor comments, but looks good as an example in general. I feel like the simplifications that you have made compared to the standard should be either collected at one place, or mentioned more explicitly in the documentation

Comment thread benches/ml_dsa.rs
// qfall-schemes is free software: you can redistribute it and/or modify it under
// the terms of the Mozilla Public License Version 2.0 as published by the
// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filedescription missing

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benchmark files never have a file description. Any (doc-) comments that are part of the benchmarks aren't available in the documentation anyway. So, these comments are really "just" for developers.

Comment thread benches/ml_dsa.rs
Comment thread src/signature/ml_dsa.rs
//! **WARNING:** This implementation is a toy implementation of the basics below
//! ML-DSA and is mostly supposed to showcase the prototyping capabilities of the `qFALL` library.
//! It omits certain strict encoding/decoding constraints, specific byte-level hash prunings,
//! and NTT-representations defined in FIPS 204.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NTT representations for the ring used here are supported by our library, so it could be worth considering using those in the toy example, if it makes sense

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To optionally introduce NTT for this implementation (by basically using a binary toggle parameter), I'd need to basically give two implementations (one with NTT, one without). This would add significant overhead to each function. Therefore, I'd recommend against it for now. Once our NTT actually outperforms / is eye-to-eye Karatsuba, I'd reconsider.

Comment thread src/signature/ml_dsa.rs
///
/// Parameters:
/// - `vector`: The vector of polynomials to be split.
///
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example missing; for schemes this could be fine. Not gonna comment the same for the other subfunctions

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving these functions to the tools crate as these seem to be reused in other schemes such as Mitaka, etc.
So, there might be value to present them as a "broadly" utilised tool that could be useful for other signature schemes as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More specifically, I'd consider pushing the power2round, decompose, and make_hint, use_hint functions to the tools-crate.

Comment thread src/signature/ml_dsa.rs
Comment thread src/signature/ml_dsa.rs
Comment on lines +224 to +233
/// Samples a polynomial with a specific Hamming weight from a seed.
///
/// This generates the challenge polynomial `c` used during signing and verification.
/// It ensures that exactly `tau` coefficients are set to either `1` or `-1`,
/// and all other coefficients are `0`.
///
/// Parameters:
/// - `seed`: A 32-byte seed used to deterministically generate the polynomial.
///
/// Returns a [`PolyOverZ`] representing the challenge polynomial.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the context of representation it is probably ok not to do the actual computation, but the changes should be expressed more in the function description.
I guess that you use the hash-digest as a seed here, but I would prefer to use the unmodified version here.

Comment thread src/signature/ml_dsa.rs

for row in 0..vec_r_1.get_num_rows() {
for col in 0..vec_r_1.get_num_columns() {
let v_1_entry: PolyOverZ = unsafe { vec_v_1.get_entry_unchecked(row, col) };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment regarding separation

Comment thread src/signature/ml_dsa.rs

for row in 0..r_vector.get_num_rows() {
for col in 0..r_vector.get_num_columns() {
let entry_r_0 = unsafe { vec_r_0.get_entry_unchecked(row, col) };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Comment thread src/signature/ml_dsa.rs
Comment on lines +372 to +385
fn hamming_weight(matrix: &MatPolyOverZ) -> u64 {
let mut count = 0;

let entries = matrix.get_entries_rowwise();
for entry in entries {
for i in 0..=entry.get_degree() {
if 0 != unsafe { entry.get_coeff_unchecked(i) } {
count += 1;
}
}
}

count
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with version from math, once that is on dev

Comment thread src/signature/ml_dsa.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement📈 New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants