silk.crypto.ml_dsa.
Sign and verify with ML-DSA (FIPS 204), the module-lattice signature scheme, at the levels ML-DSA-44, ML-DSA-65, and ML-DSA-87.
When to use#
Use MlDsa for signatures that must hold also against an attacker with a large quantum
computer. Make a key pair with MlDsa.keyPairFromSeed, sign with MlDsa.sign, and verify
with MlDsa.verify. Use silk.crypto.ml_key to read and write the keys in PKCS #8 and
SubjectPublicKeyInfo.
Details#
This is the pure ML-DSA of FIPS 204 section 5, with a context string of up to 255 bytes. A key
pair comes from a 32-byte seed, the form that PKCS #8 stores; the functions of
MlDsaParameters give the sizes. MlDsa.sign is the hedged variant, with 32 bytes from the
ambient Random, and MlDsa.signDeterministic the deterministic one. The external-mu
functions take the 64-byte message representative mu that MlDsa.externalMu computes, so a
caller can hash a long message elsewhere. The caller gives every buffer, so nothing allocates.
Signing does not branch on secret values except in the rejection loop of FIPS 204, whose
rejected attempts reveal nothing.
Errors#
MlDsaErrorfor a buffer of the wrong length, a context over 255 bytes, or a private key whose secret vectors are out of range.
Gotchas#
The verifiers return false for every failure, including wrong lengths. Secrets are not
erased. The pre-hash variant HashML-DSA is not here.
Examples#
Sign and verify#
import silk.core.result { Result }
import silk.crypto.ml_dsa { MlDsa, MlDsaError, MlDsaParameters }
pub fn main() -> i32 {
let parameters = MlDsaParameters.MlDsa44
// Real programs fill the seed from a secure `Random` provider.
let seed: [u8; 32] = [1; 32]
let mut publicKey: [u8; 1312] = [0; 1312]
let mut privateKey: [u8; 2560] = [0; 2560]
match MlDsa.keyPairFromSeed(parameters, &seed, &mut publicKey, &mut privateKey) {
Result<(), MlDsaError>.Success { .. } => {}
Result<(), MlDsaError>.Failure { error: _ } => {
return 1
}
}
let mut signature: [u8; 2420] = [0; 2420]
match MlDsa.signDeterministic(parameters, &privateKey, b"hello", b"", &mut signature) {
Result<(), MlDsaError>.Success { .. } => {}
Result<(), MlDsaError>.Failure { error: _ } => {
return 1
}
}
if !MlDsa.verify(parameters, &publicKey, b"hello", b"", &signature) {
return 1
}
if MlDsa.verify(parameters, &publicKey, b"hullo", b"", &signature) {
return 1
}
return 0
}Import as MlDsa with import silk.crypto.ml_dsa { MlDsa }.
Public declarations: 3.
MlDsaParameters#
pub enum MlDsaParametersAn ML-DSA parameter set of FIPS 204.
MlDsa44#
MlDsa44ML-DSA-44, security category 2.
MlDsa65#
MlDsa65ML-DSA-65, security category 3.
MlDsa87#
MlDsa87ML-DSA-87, security category 5.
Implementation MlDsaParameters#
impl MlDsaParametersMethod publicKeyLength#
pub fn publicKeyLength(self: &Self) -> usizeReturns the length of a public key in bytes: 1312, 1952, or 2592.
Method privateKeyLength#
pub fn privateKeyLength(self: &Self) -> usizeReturns the length of an expanded private key in bytes: 2560, 4032, or 4896.
Method signatureLength#
pub fn signatureLength(self: &Self) -> usizeReturns the length of a signature in bytes: 2420, 3309, or 4627.
Method objectIdentifier#
pub fn objectIdentifier(self: &Self) -> &[u8]Returns the content bytes of the object identifier that names the parameter set, without the
tag and length: id-ml-dsa-44 is 2.16.840.1.101.3.4.3.17, and the others end in 18 and 19.
Implementation Debug for MlDsaParameters#
impl Debug for MlDsaParametersOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as MlDsa65.
MlDsaError#
pub enum MlDsaErrorThe reason that an ML-DSA call failed. It holds no secret bytes.
InvalidLength#
InvalidLengthA seed, key, mu, randomness, or output buffer does not have the length of the parameter set.
ContextTooLong#
ContextTooLongThe context string is longer than 255 bytes.
InvalidPrivateKey#
InvalidPrivateKeyA coefficient of the secret vectors s1 or s2 in the private key is out of range.
Implementation Debug for MlDsaError#
impl Debug for MlDsaErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidLength.
MlDsa#
pub struct MlDsaThe functions of ML-DSA.
When to use#
Make a key pair with MlDsa.keyPairFromSeed, sign with MlDsa.sign or
MlDsa.signDeterministic, and verify with MlDsa.verify.
Details#
Each function takes the parameter set and the caller's buffers, which must have the lengths of
MlDsaParameters.
Implementation MlDsa#
impl MlDsaAssociated function keyPairFromSeed#
pub fn keyPairFromSeed(
parameters: MlDsaParameters,
seed: &[u8],
publicKey: &mut [u8],
privateKey: &mut [u8],
) -> Result<(), MlDsaError>Writes the key pair of ML-DSA.KeyGen_internal for the 32-byte seed into publicKey and
privateKey.
Errors#
InvalidLengthifseedis not 32 bytes, or a key buffer does not have the length of the parameter set. The buffers do not change.
Associated function generateSeed#
pub effect fn generateSeed() -> [u8; 32] ? &mut RandomReturns a new 32-byte seed from the ambient Random, for MlDsa.keyPairFromSeed.
The Random provider must be cryptographically secure.
Associated function externalMu#
pub fn externalMu(parameters: MlDsaParameters, publicKey: &[u8], message: &[u8], context: &[u8]) -> Result<
[u8; 64],
MlDsaError,
>Returns mu, the 64-byte message representative of FIPS 204 for message and context
under publicKey, for the external-mu functions.
Errors#
InvalidLengthifpublicKeydoes not have the length of the parameter set.ContextTooLongifcontextis longer than 255 bytes.
Associated function sign#
pub effect fn sign(
parameters: MlDsaParameters,
privateKey: &[u8],
message: &[u8],
context: &[u8],
signature: &mut [u8],
) -> Result<(), MlDsaError> ? &mut RandomWrites a hedged signature of message with context into signature, with 32 bytes from
the ambient Random.
Errors#
InvalidLengthifprivateKeyorsignaturedoes not have the length of the parameter set.ContextTooLongifcontextis longer than 255 bytes.InvalidPrivateKeyif the secret vectors are out of range.
Associated function signDeterministic#
pub fn signDeterministic(
parameters: MlDsaParameters,
privateKey: &[u8],
message: &[u8],
context: &[u8],
signature: &mut [u8],
) -> Result<(), MlDsaError>Writes the deterministic signature of message with context into signature: FIPS 204
with 32 zero bytes as the randomness.
Errors#
The errors of MlDsa.sign.
Associated function signExternalMu#
pub fn signExternalMu(
parameters: MlDsaParameters,
privateKey: &[u8],
mu: &[u8],
randomness: &[u8],
signature: &mut [u8],
) -> Result<(), MlDsaError>Writes the signature of ML-DSA.Sign_internal for the 64-byte message representative mu
and the 32-byte randomness into signature.
Errors#
InvalidLengthfor a key, mu, randomness, or signature buffer of the wrong length.InvalidPrivateKeyif the secret vectors are out of range.
Gotchas#
Use 32 fresh random bytes, or 32 zero bytes for the deterministic variant. Get mu from
MlDsa.externalMu with the public key of privateKey.
Associated function verify#
pub fn verify(
parameters: MlDsaParameters,
publicKey: &[u8],
message: &[u8],
context: &[u8],
signature: &[u8],
) -> boolReturns whether signature is a valid signature of message with context under
publicKey. Wrong lengths and a context over 255 bytes give false.
Associated function verifyExternalMu#
pub fn verifyExternalMu(parameters: MlDsaParameters, publicKey: &[u8], mu: &[u8], signature: &[u8]) -> boolReturns whether signature is valid under publicKey for the 64-byte message
representative mu, as ML-DSA.Verify_internal checks it. Wrong lengths give false.
Category: Cryptography.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.