ml-dsa: make PartialEq for ExpandedSigningKey constant time (#1286)

This commit is contained in:
Arthur Gautier
2026-04-03 15:58:36 -07:00
committed by GitHub
parent f282377eb6
commit d011b9a356
3 changed files with 40 additions and 5 deletions
Generated
+4 -2
View File
@@ -715,6 +715,7 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214"
dependencies = [
"ctutils",
"subtle",
"typenum",
"zeroize",
@@ -868,10 +869,11 @@ dependencies = [
[[package]]
name = "module-lattice"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cbdc2ac6ead7d0889a5d96e70b7f11a8812702a100ca7c65c5c71fdf076e182"
checksum = "164eb3faeaecbd14b0b2a917c1b4d0c035097a9c559b0bed85c2cdd032bc8faa"
dependencies = [
"ctutils",
"hybrid-array",
"num-traits",
"zeroize",
+1 -1
View File
@@ -34,7 +34,7 @@ pkcs8 = ["dep:const-oid", "dep:pkcs8"]
[dependencies]
ctutils = { version = "0.4", default-features = false }
hybrid-array = { version = "0.4", features = ["extra-sizes"] }
module-lattice = "0.2"
module-lattice = { version = "0.2.1", features = ["ctutils"] }
sha3 = { version = "0.11", default-features = false }
signature = { version = "3.0.0-rc.10", default-features = false, features = ["digest"] }
+35 -2
View File
@@ -58,6 +58,7 @@ use crate::param::{ParameterSet, QMinus1, SamplingSize, SpecQ};
use crate::sampling::{expand_a, expand_mask, expand_s, sample_in_ball};
use core::convert::{TryFrom, TryInto};
use core::fmt;
use ctutils::{Choice, CtEq};
use hybrid_array::{
Array,
typenum::{
@@ -187,7 +188,7 @@ impl AsMut<Shake256> for MuBuilder {
}
/// An ML-DSA signing key initialized through a seed
#[derive(Clone, PartialEq)]
#[derive(Clone)]
pub struct SigningKey<P: MlDsaParams> {
/// The signing key of the key pair
signing_key: ExpandedSigningKey<P>,
@@ -254,8 +255,22 @@ impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for SigningKey<P> {
}
}
impl<P: MlDsaParams> PartialEq for SigningKey<P> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<P: MlDsaParams> CtEq for SigningKey<P> {
fn ct_eq(&self, other: &Self) -> Choice {
self.signing_key
.ct_eq(&other.signing_key)
.and(self.seed.ct_eq(&other.seed))
}
}
/// An ML-DSA signing key
#[derive(Clone, PartialEq)]
#[derive(Clone)]
pub struct ExpandedSigningKey<P: MlDsaParams> {
rho: B32,
K: B32,
@@ -661,6 +676,24 @@ impl<P: MlDsaParams> RandomizedDigestSigner<Shake256, Signature<P>> for Expanded
}
}
impl<P: MlDsaParams> PartialEq for ExpandedSigningKey<P> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
}
}
impl<P: MlDsaParams> CtEq for ExpandedSigningKey<P> {
fn ct_eq(&self, other: &Self) -> Choice {
self.rho
.ct_eq(&other.rho)
.and(self.K.ct_eq(&other.K))
.and(self.tr.ct_eq(&other.tr))
.and(self.s1.ct_eq(&other.s1))
.and(self.s2.ct_eq(&other.s2))
.and(self.t0.ct_eq(&other.t0))
}
}
/// An ML-DSA verification key
#[derive(Clone, Debug, PartialEq)]
pub struct VerifyingKey<P: ParameterSet> {