Skip to content

Commit

Permalink
expanded keys
Browse files Browse the repository at this point in the history
  • Loading branch information
eschorn1 committed Mar 6, 2024
1 parent 2e55391 commit a6bf9a7
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 110 deletions.
28 changes: 18 additions & 10 deletions benches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ Figure-of-merit ... no particular care taken to disable turbo boost etc
// $ RUSTFLAGS="-C target-cpu=native" cargo bench
// Intel® Core™ i7-7700K CPU @ 4.20GHz × 8
// Mar 5 2024
// Mar 6 2024
ml_dsa_44 keygen time: [92.030 µs 92.113 µs 92.266 µs]
ml_dsa_65 keygen time: [168.05 µs 168.07 µs 168.09 µs]
ml_dsa_87 keygen time: [244.87 µs 244.96 µs 245.05 µs]
ml_dsa_44 keygen time: [97.518 µs 97.535 µs 97.552 µs]
ml_dsa_65 keygen time: [179.85 µs 180.16 µs 180.75 µs]
ml_dsa_87 keygen time: [263.45 µs 263.65 µs 263.91 µs]
ml_dsa_44 sign time: [361.25 µs 365.44 µs 369.65 µs]
ml_dsa_65 sign time: [589.35 µs 598.81 µs 608.16 µs]
ml_dsa_87 sign time: [718.22 µs 726.95 µs 735.49 µs]
ml_dsa_44 sk sign time: [364.11 µs 367.89 µs 371.69 µs]
ml_dsa_65 sk sign time: [591.80 µs 600.07 µs 608.24 µs]
ml_dsa_87 sk sign time: [724.66 µs 733.22 µs 741.71 µs]
ml_dsa 44 verify time: [118.81 µs 118.86 µs 118.95 µs]
ml_dsa 65 verify time: [216.02 µs 216.04 µs 216.07 µs]
ml_dsa 87 verify time: [351.97 µs 351.99 µs 352.01 µs]
ml_dsa_44 esk sign time: [297.77 µs 301.36 µs 305.08 µs] // 18% improvement
ml_dsa_65 esk sign time: [474.79 µs 481.79 µs 489.26 µs]
ml_dsa_87 esk sign time: [513.10 µs 520.88 µs 528.78 µs]
ml_dsa 44 pk verify time: [138.94 µs 139.08 µs 139.25 µs]
ml_dsa 65 pk verify time: [225.74 µs 225.77 µs 225.79 µs]
ml_dsa 87 pk verify time: [400.09 µs 400.20 µs 400.32 µs]
ml_dsa 44 epk verify time: [78.406 µs 78.477 µs 78.551 µs] // 43% improvement
ml_dsa 65 epk verify time: [117.81 µs 117.86 µs 117.90 µs]
ml_dsa 87 epk verify time: [219.52 µs 219.68 µs 219.84 µs]
~~~
28 changes: 21 additions & 7 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use criterion::{criterion_group, criterion_main, Criterion};
use fips204::traits::{Signer, Verifier};
use fips204::traits::{KeyGen, Signer, Verifier};
use fips204::{ml_dsa_44, ml_dsa_65, ml_dsa_87};


Expand All @@ -8,25 +8,39 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let message = [0u8, 1, 2, 3, 4, 5, 6, 7];

let (pk44, sk44) = ml_dsa_44::try_keygen_vt().unwrap();
let esk44 = ml_dsa_44::KG::gen_expanded_private_vt(&sk44).unwrap();
let epk44 = ml_dsa_44::KG::gen_expanded_public_vt(&pk44).unwrap();
let sig44 = sk44.try_sign_ct(&message).unwrap();

let (pk65, sk65) = ml_dsa_65::try_keygen_vt().unwrap();
let esk65 = ml_dsa_65::KG::gen_expanded_private_vt(&sk65).unwrap();
let epk65 = ml_dsa_65::KG::gen_expanded_public_vt(&pk65).unwrap();
let sig65 = sk65.try_sign_ct(&message).unwrap();

let (pk87, sk87) = ml_dsa_87::try_keygen_vt().unwrap();
let esk87 = ml_dsa_87::KG::gen_expanded_private_vt(&sk87).unwrap();
let epk87 = ml_dsa_87::KG::gen_expanded_public_vt(&pk87).unwrap();
let sig87 = sk87.try_sign_ct(&message).unwrap();

c.bench_function("ml_dsa_44 keygen", |b| b.iter(|| ml_dsa_44::try_keygen_vt()));
c.bench_function("ml_dsa_65 keygen", |b| b.iter(|| ml_dsa_65::try_keygen_vt()));
c.bench_function("ml_dsa_87 keygen", |b| b.iter(|| ml_dsa_87::try_keygen_vt()));

c.bench_function("ml_dsa_44 sign", |b| b.iter(|| sk44.try_sign_ct(&message)));
c.bench_function("ml_dsa_65 sign", |b| b.iter(|| sk65.try_sign_ct(&message)));
c.bench_function("ml_dsa_87 sign", |b| b.iter(|| sk87.try_sign_ct(&message)));
c.bench_function("ml_dsa_44 sk sign", |b| b.iter(|| sk44.try_sign_ct(&message)));
c.bench_function("ml_dsa_65 sk sign", |b| b.iter(|| sk65.try_sign_ct(&message)));
c.bench_function("ml_dsa_87 sk sign", |b| b.iter(|| sk87.try_sign_ct(&message)));

c.bench_function("ml_dsa 44 verify", |b| b.iter(|| pk44.try_verify_vt(&message, &sig44)));
c.bench_function("ml_dsa 65 verify", |b| b.iter(|| pk65.try_verify_vt(&message, &sig65)));
c.bench_function("ml_dsa 87 verify", |b| b.iter(|| pk87.try_verify_vt(&message, &sig87)));
c.bench_function("ml_dsa_44 esk sign", |b| b.iter(|| esk44.try_sign_ct(&message)));
c.bench_function("ml_dsa_65 esk sign", |b| b.iter(|| esk65.try_sign_ct(&message)));
c.bench_function("ml_dsa_87 esk sign", |b| b.iter(|| esk87.try_sign_ct(&message)));

c.bench_function("ml_dsa 44 pk verify", |b| b.iter(|| pk44.try_verify_vt(&message, &sig44)));
c.bench_function("ml_dsa 65 pk verify", |b| b.iter(|| pk65.try_verify_vt(&message, &sig65)));
c.bench_function("ml_dsa 87 pk verify", |b| b.iter(|| pk87.try_verify_vt(&message, &sig87)));

c.bench_function("ml_dsa 44 epk verify", |b| b.iter(|| epk44.try_verify_vt(&message, &sig44)));
c.bench_function("ml_dsa 65 epk verify", |b| b.iter(|| epk65.try_verify_vt(&message, &sig65)));
c.bench_function("ml_dsa 87 epk verify", |b| b.iter(|| epk87.try_verify_vt(&message, &sig87)));
}

criterion_group!(benches, criterion_benchmark);
Expand Down
8 changes: 5 additions & 3 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub const fn bit_length(a: i32) -> usize { a.ilog2() as usize + 1 }
/// modulo α. 'ready to optimize'
pub fn center_mod(m: i32) -> i32 {
let t = full_reduce32(m);
let over2 = (Q / 2) - t; // check if t is larger than Q/2
let over2 = (Q / 2) - t; // check if t is larger than Q/2
t - ((over2 >> 31) & Q) // sub Q if over2 is negative
}

Expand All @@ -86,7 +86,9 @@ pub(crate) fn mat_vec_mul<const K: usize, const L: usize>(
#[allow(clippy::needless_range_loop)] // clarity
for j in 0..L {
w_hat[i].iter_mut().enumerate().for_each(|(m, e)| {
*e = partial_reduce64(i64::from(*e) + i64::from(a_hat[i][j][m]) * i64::from(u_hat[j][m]));
*e = partial_reduce64(
i64::from(*e) + i64::from(a_hat[i][j][m]) * i64::from(u_hat[j][m]),
);
});
}
}
Expand All @@ -108,7 +110,7 @@ pub(crate) fn vec_add<const K: usize>(vec_a: &[R; K], vec_b: &[R; K]) -> [R; K]


pub fn infinity_norm<const ROW: usize, const COL: usize>(w: &[[i32; COL]; ROW]) -> i32 {
let mut result = 0; // no early exit
let mut result = 0; // no early exit
for row in w {
for element in row {
let z_q = center_mod(*element).abs();
Expand Down
2 changes: 1 addition & 1 deletion src/high_low.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! This file implements functionality from FIPS 204 section 8.4 High Order / Low Order Bits and Hints
use crate::helpers::{full_reduce32};
use crate::helpers::full_reduce32;
use crate::types::{Zero, Zq, R};
use crate::{D, Q};

Expand Down
83 changes: 58 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

// Roadmap
// 1. Clean up; resolve math
// 2. Resolve/remove precompute signing
// - sk/sign could precompute steps 1-5 of alg 2 (sign)
// - pk/verify could precompute steps 1,5, (last part)10 of alg 3 (verify)
// - Q: how to design the best API, maybe normal->fast key plus sign-fast & verif-fast
// 3. More robust unit testing; consider whether to test debug statements: release-vs-test
// 2. CT inspection
// 3. implement ct_cm4
// 4. rework fuzz harness to include expanded keys
// 5. Intensive/extensive pass on documentation
// 6. Revisit/expand unit testing; consider whether to test debug statements: release-vs-test


// Functionality map per FIPS 204 draft
Expand Down Expand Up @@ -83,7 +83,7 @@ macro_rules! functionality {
() => {
use crate::encodings::{pk_decode, sk_decode};
use crate::ml_dsa;
use crate::traits::{KeyGen, PreGen, SerDes, Signer, Verifier};
use crate::traits::{KeyGen, SerDes, Signer, Verifier};
use rand_core::CryptoRngCore;
use zeroize::{Zeroize, ZeroizeOnDrop};

Expand All @@ -93,16 +93,26 @@ macro_rules! functionality {
// ----- 'EXTERNAL' DATA TYPES -----

/// Correctly sized private key specific to the target security parameter set. <br>
/// Implements the [`crate::traits::Signer`], [`crate::traits::SerDes`], and
/// [`crate::traits::PreGen`] traits.
/// Implements the [`crate::traits::Signer`] and [`crate::traits::SerDes`] traits.
pub type PrivateKey = crate::types::PrivateKey<SK_LEN>;

/// Expanded private key, specific to the target security parameter set, that contains <br>
/// precomputed elements which increase (repeated) signature performance. Implements only
/// the [`crate::traits::Signer`] trait.
pub type ExpandedPrivateKey = crate::types::ExpandedPrivateKey<K, L>;


/// Correctly sized public key specific to the target security parameter set. <br>
/// Implements the [`crate::traits::Verifier`] and [`crate::traits::SerDes`] traits.
pub type PublicKey = crate::types::PublicKey<PK_LEN>;


/// Expanded public key, specific to the target security parameter set, that contains <br>
/// precomputed elements which increase (repeated) verification performance. Implements only
/// the [`crate::traits::Verifier`] traits.
pub type ExpandedPublicKey = crate::types::ExpandedPublicKey22<K, L>;


/// Empty struct to enable `KeyGen` trait objects across security parameter sets. <br>
/// Implements the [`crate::traits::KeyGen`] trait.
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
Expand Down Expand Up @@ -171,6 +181,8 @@ macro_rules! functionality {


impl KeyGen for KG {
type ExpandedPrivateKey = ExpandedPrivateKey;
type ExpandedPublicKey = ExpandedPublicKey;
type PrivateKey = PrivateKey;
type PublicKey = PublicKey;

Expand All @@ -180,6 +192,20 @@ macro_rules! functionality {
let (pk, sk) = ml_dsa::key_gen::<K, L, PK_LEN, SK_LEN>(rng, ETA)?;
Ok((PublicKey { 0: pk }, PrivateKey { 0: sk }))
}

fn gen_expanded_private_vt(
sk: &PrivateKey,
) -> Result<Self::ExpandedPrivateKey, &'static str> {
let esk = ml_dsa::sign_start(ETA, &sk.0)?;
Ok(esk)
}

fn gen_expanded_public_vt(
pk: &PublicKey,
) -> Result<Self::ExpandedPublicKey, &'static str> {
let epk = ml_dsa::verify_start(&pk.0)?;
Ok(epk)
}
}


Expand All @@ -189,31 +215,23 @@ macro_rules! functionality {
fn try_sign_with_rng_ct(
&self, rng: &mut impl CryptoRngCore, message: &[u8],
) -> Result<Self::Signature, &'static str> {
let sig = ml_dsa::sign::<K, L, LAMBDA_DIV4, SIG_LEN, SK_LEN>(
rng, BETA, ETA, GAMMA1, GAMMA2, OMEGA, TAU, &self.0, message,
let esk = ml_dsa::sign_start(ETA, &self.0)?;
let sig = ml_dsa::sign_finish::<K, L, LAMBDA_DIV4, SIG_LEN, SK_LEN>(
rng, BETA, GAMMA1, GAMMA2, OMEGA, TAU, &esk, message,
)?;
Ok(sig)
}
}


impl PreGen for PrivateKey {
type PreCompute = PrivatePreCompute;

fn gen_precompute(&self) -> PrivatePreCompute {
PrivatePreCompute(self.clone().into_bytes())
}
}


impl Signer for PrivatePreCompute {
impl Signer for ExpandedPrivateKey {
type Signature = [u8; SIG_LEN];

fn try_sign_with_rng_ct(
&self, rng: &mut impl CryptoRngCore, message: &[u8],
) -> Result<Self::Signature, &'static str> {
let sig = ml_dsa::sign::<K, L, LAMBDA_DIV4, SIG_LEN, SK_LEN>(
rng, BETA, ETA, GAMMA1, GAMMA2, OMEGA, TAU, &self.0, message,
let sig = ml_dsa::sign_finish::<K, L, LAMBDA_DIV4, SIG_LEN, SK_LEN>(
rng, BETA, GAMMA1, GAMMA2, OMEGA, TAU, &self, message,
)?;
Ok(sig)
}
Expand All @@ -223,9 +241,24 @@ macro_rules! functionality {
impl Verifier for PublicKey {
type Signature = [u8; SIG_LEN];

fn try_verify_vt(&self, message: &[u8], sig: &Self::Signature) -> Result<bool, &'static str> {
ml_dsa::verify::<K, L, LAMBDA_DIV4, PK_LEN, SIG_LEN>(
BETA, GAMMA1, GAMMA2, OMEGA, TAU, &self.0, &message, &sig,
fn try_verify_vt(
&self, message: &[u8], sig: &Self::Signature,
) -> Result<bool, &'static str> {
let epk = ml_dsa::verify_start(&self.0)?;
ml_dsa::verify_finish::<K, L, LAMBDA_DIV4, PK_LEN, SIG_LEN>(
BETA, GAMMA1, GAMMA2, OMEGA, TAU, &epk, &message, &sig,
)
}
}

impl Verifier for ExpandedPublicKey {
type Signature = [u8; SIG_LEN];

fn try_verify_vt(
&self, message: &[u8], sig: &Self::Signature,
) -> Result<bool, &'static str> {
ml_dsa::verify_finish::<K, L, LAMBDA_DIV4, PK_LEN, SIG_LEN>(
BETA, GAMMA1, GAMMA2, OMEGA, TAU, &self, &message, &sig,
)
}
}
Expand Down
Loading

0 comments on commit a6bf9a7

Please sign in to comment.