mirror of
https://github.com/RustCrypto/signatures
synced 2026-06-21 13:45:42 +00:00
ml-dsa: apply and fix workspace-level lints (#1338)
Applies the workspace-level config added in #1323 to this crate and fixes any failures.
This commit is contained in:
@@ -17,6 +17,7 @@ members = [
|
||||
opt-level = 2
|
||||
|
||||
[workspace.lints.clippy]
|
||||
as_conversions = "warn"
|
||||
borrow_as_ptr = "warn"
|
||||
cast_lossless = "warn"
|
||||
cast_possible_truncation = "warn"
|
||||
@@ -26,6 +27,7 @@ cast_sign_loss = "warn"
|
||||
checked_conversions = "warn"
|
||||
from_iter_instead_of_collect = "warn"
|
||||
implicit_saturating_sub = "warn"
|
||||
integer_division_remainder_used = "warn"
|
||||
manual_assert = "warn"
|
||||
map_unwrap_or = "warn"
|
||||
missing_errors_doc = "warn"
|
||||
|
||||
+14
-14
@@ -20,24 +20,24 @@ pub use pkcs8::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use pkcs8::{EncodePrivateKey, spki::EncodePublicKey};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use pkcs8::der::{
|
||||
Document, SecretDocument,
|
||||
asn1::{BitStringRef, OctetStringRef},
|
||||
pub use pkcs8::{
|
||||
EncodePrivateKey,
|
||||
der::{
|
||||
Document, SecretDocument,
|
||||
asn1::{BitStringRef, OctetStringRef},
|
||||
},
|
||||
spki::EncodePublicKey,
|
||||
};
|
||||
|
||||
use crate::COMPONENT_SIZE;
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(feature = "pem")]
|
||||
use core::str;
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "zerocopy")]
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
|
||||
#[cfg(feature = "zeroize")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// Algorithm [`ObjectIdentifier`] for the Ed25519 digital signature algorithm
|
||||
/// (`id-Ed25519`).
|
||||
@@ -73,7 +73,7 @@ pub struct KeypairBytes {
|
||||
/// Little endian serialization of an element of the Curve25519 scalar
|
||||
/// field, prior to "clamping" (i.e. setting/clearing bits to ensure the
|
||||
/// scalar is actually a valid field element)
|
||||
pub secret_key: [u8; Self::BYTE_SIZE / 2],
|
||||
pub secret_key: [u8; COMPONENT_SIZE],
|
||||
|
||||
/// Ed25519 public key (if available).
|
||||
///
|
||||
@@ -90,7 +90,7 @@ impl KeypairBytes {
|
||||
#[allow(clippy::missing_panics_doc, reason = "MSRV TODO")]
|
||||
pub fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Self {
|
||||
// TODO(tarcieri): use `as_chunks` when MSRV is 1.88
|
||||
let (sk, pk) = bytes.split_at(Self::BYTE_SIZE / 2);
|
||||
let (sk, pk) = bytes.split_at(COMPONENT_SIZE);
|
||||
|
||||
Self {
|
||||
secret_key: sk.try_into().expect("secret key size error"),
|
||||
@@ -109,7 +109,7 @@ impl KeypairBytes {
|
||||
pub fn to_bytes(&self) -> Option<[u8; Self::BYTE_SIZE]> {
|
||||
if let Some(public_key) = &self.public_key {
|
||||
let mut result = [0u8; Self::BYTE_SIZE];
|
||||
let (sk, pk) = result.split_at_mut(Self::BYTE_SIZE / 2);
|
||||
let (sk, pk) = result.split_at_mut(COMPONENT_SIZE);
|
||||
sk.copy_from_slice(&self.secret_key);
|
||||
pk.copy_from_slice(public_key.as_ref());
|
||||
Some(result)
|
||||
@@ -130,7 +130,7 @@ impl Drop for KeypairBytes {
|
||||
impl EncodePrivateKey for KeypairBytes {
|
||||
fn to_pkcs8_der(&self) -> Result<SecretDocument> {
|
||||
// Serialize private key as nested OCTET STRING
|
||||
let mut private_key = [0u8; 2 + (Self::BYTE_SIZE / 2)];
|
||||
let mut private_key = [0u8; 2 + (COMPONENT_SIZE)];
|
||||
private_key[0] = 0x04;
|
||||
private_key[1] = 0x20;
|
||||
private_key[2..].copy_from_slice(&self.secret_key);
|
||||
|
||||
+14
-12
@@ -20,19 +20,21 @@ pub use pkcs8::{
|
||||
};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use pkcs8::{EncodePrivateKey, spki::EncodePublicKey};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use pkcs8::der::{
|
||||
Document, SecretDocument,
|
||||
asn1::{BitStringRef, OctetStringRef},
|
||||
pub use pkcs8::{
|
||||
EncodePrivateKey,
|
||||
der::{
|
||||
Document, SecretDocument,
|
||||
asn1::{BitStringRef, OctetStringRef},
|
||||
},
|
||||
spki::EncodePublicKey,
|
||||
};
|
||||
|
||||
use crate::COMPONENT_SIZE;
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
/// Algorithm [`ObjectIdentifier`] for the Ed448 digital signature algorithm
|
||||
/// (`id-Ed448`).
|
||||
///
|
||||
@@ -67,7 +69,7 @@ pub struct KeypairBytes {
|
||||
/// Little endian serialization of an element of the Curve448 scalar
|
||||
/// field, prior to "clamping" (i.e. setting/clearing bits to ensure the
|
||||
/// scalar is actually a valid field element)
|
||||
pub secret_key: [u8; Self::BYTE_SIZE / 2],
|
||||
pub secret_key: [u8; COMPONENT_SIZE],
|
||||
|
||||
/// Ed448 public key (if available).
|
||||
///
|
||||
@@ -84,7 +86,7 @@ impl KeypairBytes {
|
||||
#[allow(clippy::missing_panics_doc, reason = "MSRV TODO")]
|
||||
pub fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Self {
|
||||
// TODO(tarcieri): use `as_chunks` when MSRV is 1.88
|
||||
let (sk, pk) = bytes.split_at(Self::BYTE_SIZE / 2);
|
||||
let (sk, pk) = bytes.split_at(COMPONENT_SIZE);
|
||||
|
||||
Self {
|
||||
secret_key: sk.try_into().expect("secret key size error"),
|
||||
@@ -103,7 +105,7 @@ impl KeypairBytes {
|
||||
pub fn to_bytes(&self) -> Option<[u8; Self::BYTE_SIZE]> {
|
||||
if let Some(public_key) = &self.public_key {
|
||||
let mut result = [0u8; Self::BYTE_SIZE];
|
||||
let (sk, pk) = result.split_at_mut(Self::BYTE_SIZE / 2);
|
||||
let (sk, pk) = result.split_at_mut(COMPONENT_SIZE);
|
||||
sk.copy_from_slice(&self.secret_key);
|
||||
pk.copy_from_slice(public_key.as_ref());
|
||||
Some(result)
|
||||
@@ -124,7 +126,7 @@ impl Drop for KeypairBytes {
|
||||
impl EncodePrivateKey for KeypairBytes {
|
||||
fn to_pkcs8_der(&self) -> Result<SecretDocument> {
|
||||
// Serialize private key as nested OCTET STRING
|
||||
let mut private_key = [0u8; 2 + (Self::BYTE_SIZE / 2)];
|
||||
let mut private_key = [0u8; 2 + COMPONENT_SIZE];
|
||||
private_key[0] = 0x04;
|
||||
private_key[1] = 0x39;
|
||||
private_key[2..].copy_from_slice(&self.secret_key);
|
||||
|
||||
@@ -57,3 +57,9 @@ serde_json = "1.0.132"
|
||||
[[bench]]
|
||||
name = "ml_dsa"
|
||||
harness = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
//! ML-DSA benchmarks.
|
||||
|
||||
#![allow(clippy::unwrap_used, reason = "benchmarks")]
|
||||
#![allow(missing_docs, reason = "benchmarks")]
|
||||
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use getrandom::SysRng;
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
@@ -6,12 +11,14 @@ use ml_dsa::{
|
||||
};
|
||||
use rand_core::{CryptoRng, UnwrapErr};
|
||||
|
||||
/// Create a random array of the given length.
|
||||
pub fn rand<L: ArraySize, R: CryptoRng + ?Sized>(rng: &mut R) -> Array<u8, L> {
|
||||
let mut val = Array::<u8, L>::default();
|
||||
rng.fill_bytes(&mut val);
|
||||
val
|
||||
}
|
||||
|
||||
/// ML-DSA benchmarks.
|
||||
#[allow(deprecated)] // TODO(tarcieri): stop using expanded signing keys
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
@@ -34,7 +41,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
let kp = MlDsa65::from_seed(&xi);
|
||||
let _sk_bytes = kp.signing_key().to_expanded();
|
||||
let _vk_bytes = kp.verifying_key().encode();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Signing
|
||||
@@ -42,7 +49,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
b.iter(|| {
|
||||
let sk = ExpandedSigningKey::<MlDsa65>::from_expanded(&sk_bytes);
|
||||
let _sig = sk.sign_deterministic(&m, &ctx);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Verifying
|
||||
@@ -51,7 +58,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
let vk = VerifyingKey::<MlDsa65>::decode(&vk_bytes);
|
||||
let sig = Signature::<MlDsa65>::decode(&sig_bytes).unwrap();
|
||||
let _ver = vk.verify_with_context(&m, &ctx, &sig);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
// Round trip
|
||||
@@ -60,7 +67,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
let kp = MlDsa65::from_seed(&xi);
|
||||
let sig = kp.signing_key().sign_deterministic(&m, &ctx).unwrap();
|
||||
let _ver = kp.verifying_key().verify_with_context(&m, &ctx, &sig);
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -69,7 +69,7 @@ pub(crate) trait ConstantTimeDiv: Unsigned {
|
||||
// This gives us floor(x / M) for x < 2^SHIFT / MULTIPLIER * M
|
||||
let x64 = u64::from(x);
|
||||
let quotient = (x64 * Self::CT_DIV_MULTIPLIER) >> Self::CT_DIV_SHIFT;
|
||||
// SAFETY: quotient is guaranteed to fit in u32 because:
|
||||
// Quotient is guaranteed to fit in u32 because:
|
||||
// - x < Q (~2^23), so quotient = x / M < x < 2^23 < 2^32
|
||||
#[allow(clippy::cast_possible_truncation, clippy::as_conversions)]
|
||||
let result = quotient as u32;
|
||||
@@ -183,7 +183,11 @@ impl AlgebraExt for Polynomial {
|
||||
}
|
||||
|
||||
fn infinity_norm(&self) -> u32 {
|
||||
self.0.iter().map(AlgebraExt::infinity_norm).max().unwrap()
|
||||
self.0
|
||||
.iter()
|
||||
.map(AlgebraExt::infinity_norm)
|
||||
.max()
|
||||
.expect("should have a maximum")
|
||||
}
|
||||
|
||||
fn power2round(&self) -> (Self, Self) {
|
||||
@@ -222,7 +226,11 @@ impl<K: ArraySize> AlgebraExt for Vector<K> {
|
||||
}
|
||||
|
||||
fn infinity_norm(&self) -> u32 {
|
||||
self.0.iter().map(AlgebraExt::infinity_norm).max().unwrap()
|
||||
self.0
|
||||
.iter()
|
||||
.map(AlgebraExt::infinity_norm)
|
||||
.max()
|
||||
.expect("should have a maximum")
|
||||
}
|
||||
|
||||
fn power2round(&self) -> (Self, Self) {
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ where
|
||||
let cuts: Array<usize, P::K> = cuts.iter().map(|x| usize::from(*x)).collect();
|
||||
|
||||
let indices: Array<usize, P::Omega> = indices.iter().map(|x| usize::from(*x)).collect();
|
||||
let max_cut: usize = cuts.iter().copied().max().unwrap();
|
||||
let max_cut: usize = cuts.iter().copied().max().expect("should have a maximum");
|
||||
|
||||
// cuts must be monotonic but can repeat
|
||||
if !cuts.windows(2).all(|w| w[0] <= w[1])
|
||||
|
||||
+3
-8
@@ -5,15 +5,10 @@
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![warn(clippy::pedantic)] // Be pedantic by default
|
||||
#![warn(clippy::integer_division_remainder_used)] // Be judicious about using `/` and `%`
|
||||
#![warn(clippy::as_conversions)] // Use proper conversions, not `as`
|
||||
#![allow(non_snake_case)] // Allow notation matching the spec
|
||||
#![allow(clippy::similar_names)] // Allow notation matching the spec
|
||||
#![allow(clippy::many_single_char_names)] // Allow notation matching the spec
|
||||
#![allow(clippy::clone_on_copy)] // Be explicit about moving data
|
||||
#![deny(missing_docs)] // Require all public interfaces to be documented
|
||||
#![warn(unreachable_pub)] // Prevent unexpected interface changes
|
||||
|
||||
//! # Quickstart
|
||||
//!
|
||||
@@ -877,7 +872,7 @@ impl<P: MlDsaParams> DigestVerifier<Shake256, Signature<P>> for VerifyingKey<P>
|
||||
}
|
||||
|
||||
/// `MlDsa44` is the parameter set for security category 2.
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct MlDsa44;
|
||||
|
||||
impl ParameterSet for MlDsa44 {
|
||||
@@ -894,7 +889,7 @@ impl ParameterSet for MlDsa44 {
|
||||
}
|
||||
|
||||
/// `MlDsa65` is the parameter set for security category 3.
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct MlDsa65;
|
||||
|
||||
impl ParameterSet for MlDsa65 {
|
||||
@@ -911,7 +906,7 @@ impl ParameterSet for MlDsa65 {
|
||||
}
|
||||
|
||||
/// `MlDsa87` is the parameter set for security category 5.
|
||||
#[derive(Default, Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
pub struct MlDsa87;
|
||||
|
||||
impl ParameterSet for MlDsa87 {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ pub trait SamplingSize: ArraySize + Len {
|
||||
}
|
||||
|
||||
/// Range of the uniform distribution to be used in sampling.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[allow(unreachable_pub, reason = "MSRV 1.85 complains")]
|
||||
pub enum Eta {
|
||||
Two,
|
||||
|
||||
+5
-5
@@ -99,13 +99,13 @@ where
|
||||
.assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;
|
||||
|
||||
let mut reader = der::SliceReader::new(private_key_info.private_key.as_bytes())?;
|
||||
let seed_string = SeedString::decode_implicit(&mut reader, SEED_TAG_NUMBER)?
|
||||
.ok_or(pkcs8::KeyError::Invalid)?;
|
||||
let seed_string =
|
||||
SeedString::decode_implicit(&mut reader, SEED_TAG_NUMBER)?.ok_or(KeyError::Invalid)?;
|
||||
let seed = seed_string
|
||||
.value
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.map_err(|_| pkcs8::KeyError::Invalid)?;
|
||||
.map_err(|_| KeyError::Invalid)?;
|
||||
reader.finish()?;
|
||||
|
||||
Ok(P::from_seed(&seed))
|
||||
@@ -118,7 +118,7 @@ where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
{
|
||||
fn to_pkcs8_der(&self) -> ::pkcs8::Result<der::SecretDocument> {
|
||||
fn to_pkcs8_der(&self) -> ::pkcs8::Result<SecretDocument> {
|
||||
let seed_der = SeedString {
|
||||
tag_mode: TagMode::Implicit,
|
||||
tag_number: SEED_TAG_NUMBER,
|
||||
@@ -174,7 +174,7 @@ where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
{
|
||||
fn to_public_key_der(&self) -> spki::Result<der::Document> {
|
||||
fn to_public_key_der(&self) -> spki::Result<Document> {
|
||||
let public_key = self.encode();
|
||||
let subject_public_key = BitStringRef::new(0, &public_key)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use ml_dsa::*;
|
||||
//! Key generation tests.
|
||||
|
||||
#![allow(clippy::unwrap_used, reason = "tests")]
|
||||
|
||||
use hybrid_array::Array;
|
||||
use ml_dsa::*;
|
||||
use signature::Keypair;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! PKCS#8 tests (i.e. private key serialization)
|
||||
|
||||
#![cfg(all(feature = "pkcs8", feature = "alloc"))]
|
||||
|
||||
use core::ops::Deref;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use ml_dsa::*;
|
||||
//! Signature generation tests.
|
||||
|
||||
#![allow(clippy::unwrap_used, reason = "tests")]
|
||||
|
||||
use ml_dsa::*;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use ml_dsa::*;
|
||||
//! Signature verification tests.
|
||||
|
||||
#![allow(clippy::unwrap_used, reason = "tests")]
|
||||
|
||||
use ml_dsa::*;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user