pub const N: usize = 256;
pub const Q: i32 = 8380417;
pub const QINV: i64 = 58728449;
pub const D: u32 = 13;
pub const ROOT_OF_UNITY: i32 = 1753;
pub const SEEDBYTES: usize = 32;
pub const CRHBYTES: usize = 64;
pub const TRBYTES: usize = 64;
pub const RNDBYTES: usize = 32;
pub const K_MAX: usize = 8;
pub const L_MAX: usize = 7;
pub const POLYT1_PACKEDBYTES: usize = 320;
pub const POLYT0_PACKEDBYTES: usize = 416;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DilithiumMode {
Dilithium2,
Dilithium3,
Dilithium5,
}
pub const ML_DSA_44: DilithiumMode = DilithiumMode::Dilithium2;
pub const ML_DSA_65: DilithiumMode = DilithiumMode::Dilithium3;
pub const ML_DSA_87: DilithiumMode = DilithiumMode::Dilithium5;
pub const HASH_ML_DSA_44_OID: &[u8] = &[
0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11,
];
pub const HASH_ML_DSA_65_OID: &[u8] = &[
0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12,
];
pub const HASH_ML_DSA_87_OID: &[u8] = &[
0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13,
];
impl DilithiumMode {
#[inline]
#[must_use]
pub const fn mode_tag(self) -> u8 {
match self {
Self::Dilithium2 => 0x02,
Self::Dilithium3 => 0x03,
Self::Dilithium5 => 0x05,
}
}
#[must_use]
pub const fn from_tag(tag: u8) -> Option<Self> {
match tag {
0x02 => Some(Self::Dilithium2),
0x03 => Some(Self::Dilithium3),
0x05 => Some(Self::Dilithium5),
_ => None,
}
}
#[inline]
#[must_use]
pub const fn k(self) -> usize {
match self {
Self::Dilithium2 => 4,
Self::Dilithium3 => 6,
Self::Dilithium5 => 8,
}
}
#[inline]
#[must_use]
pub const fn l(self) -> usize {
match self {
Self::Dilithium2 => 4,
Self::Dilithium3 => 5,
Self::Dilithium5 => 7,
}
}
#[inline]
#[must_use]
pub const fn eta(self) -> i32 {
match self {
Self::Dilithium2 => 2,
Self::Dilithium3 => 4,
Self::Dilithium5 => 2,
}
}
#[inline]
#[must_use]
pub const fn tau(self) -> usize {
match self {
Self::Dilithium2 => 39,
Self::Dilithium3 => 49,
Self::Dilithium5 => 60,
}
}
#[inline]
#[must_use]
pub const fn beta(self) -> i32 {
match self {
Self::Dilithium2 => 78,
Self::Dilithium3 => 196,
Self::Dilithium5 => 120,
}
}
#[inline]
#[must_use]
pub const fn gamma1(self) -> i32 {
match self {
Self::Dilithium2 => 1 << 17, Self::Dilithium3 => 1 << 19, Self::Dilithium5 => 1 << 19,
}
}
#[inline]
#[must_use]
pub const fn gamma2(self) -> i32 {
match self {
Self::Dilithium2 => (Q - 1) / 88, Self::Dilithium3 => (Q - 1) / 32, Self::Dilithium5 => (Q - 1) / 32,
}
}
#[inline]
#[must_use]
pub const fn omega(self) -> usize {
match self {
Self::Dilithium2 => 80,
Self::Dilithium3 => 55,
Self::Dilithium5 => 75,
}
}
#[inline]
#[must_use]
pub const fn ctildebytes(self) -> usize {
match self {
Self::Dilithium2 => 32,
Self::Dilithium3 => 48,
Self::Dilithium5 => 64,
}
}
#[inline]
#[must_use]
pub const fn polyz_packedbytes(self) -> usize {
match self {
Self::Dilithium2 => 576, Self::Dilithium3 => 640, Self::Dilithium5 => 640,
}
}
#[inline]
#[must_use]
pub const fn polyw1_packedbytes(self) -> usize {
match self {
Self::Dilithium2 => 192, Self::Dilithium3 => 128, Self::Dilithium5 => 128,
}
}
#[inline]
#[must_use]
pub const fn polyeta_packedbytes(self) -> usize {
match self {
Self::Dilithium2 => 96, Self::Dilithium3 => 128, Self::Dilithium5 => 96,
}
}
#[inline]
#[must_use]
pub const fn public_key_bytes(self) -> usize {
SEEDBYTES + self.k() * POLYT1_PACKEDBYTES
}
#[inline]
#[must_use]
pub const fn secret_key_bytes(self) -> usize {
2 * SEEDBYTES
+ TRBYTES
+ self.l() * self.polyeta_packedbytes()
+ self.k() * self.polyeta_packedbytes()
+ self.k() * POLYT0_PACKEDBYTES
}
#[inline]
#[must_use]
pub const fn signature_bytes(self) -> usize {
self.ctildebytes() + self.l() * self.polyz_packedbytes() + self.omega() + self.k()
}
#[inline]
#[must_use]
pub fn hash_oid(self) -> &'static [u8] {
match self {
Self::Dilithium2 => HASH_ML_DSA_44_OID,
Self::Dilithium3 => HASH_ML_DSA_65_OID,
Self::Dilithium5 => HASH_ML_DSA_87_OID,
}
}
#[must_use]
pub fn fips_name(self) -> &'static str {
match self {
Self::Dilithium2 => "ML-DSA-44",
Self::Dilithium3 => "ML-DSA-65",
Self::Dilithium5 => "ML-DSA-87",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dilithium2_sizes() {
let m = DilithiumMode::Dilithium2;
assert_eq!(m.public_key_bytes(), 1312);
assert_eq!(m.secret_key_bytes(), 2560);
assert_eq!(m.signature_bytes(), 2420);
}
#[test]
fn test_dilithium3_sizes() {
let m = DilithiumMode::Dilithium3;
assert_eq!(m.public_key_bytes(), 1952);
assert_eq!(m.secret_key_bytes(), 4032);
assert_eq!(m.signature_bytes(), 3309);
}
#[test]
fn test_dilithium5_sizes() {
let m = DilithiumMode::Dilithium5;
assert_eq!(m.public_key_bytes(), 2592);
assert_eq!(m.secret_key_bytes(), 4896);
assert_eq!(m.signature_bytes(), 4627);
}
}