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#

  • MlDsaError for 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#

silk
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#

silk
pub enum MlDsaParameters

An ML-DSA parameter set of FIPS 204.

MlDsa44#

silk
MlDsa44

ML-DSA-44, security category 2.

MlDsa65#

silk
MlDsa65

ML-DSA-65, security category 3.

MlDsa87#

silk
MlDsa87

ML-DSA-87, security category 5.

Implementation MlDsaParameters#

silk
impl MlDsaParameters

Method publicKeyLength#

silk
pub fn publicKeyLength(self: &Self) -> usize

Returns the length of a public key in bytes: 1312, 1952, or 2592.

Method privateKeyLength#

silk
pub fn privateKeyLength(self: &Self) -> usize

Returns the length of an expanded private key in bytes: 2560, 4032, or 4896.

Method signatureLength#

silk
pub fn signatureLength(self: &Self) -> usize

Returns the length of a signature in bytes: 2420, 3309, or 4627.

Method objectIdentifier#

silk
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#

silk
impl Debug for MlDsaParameters

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as MlDsa65.

MlDsaError#

silk
pub enum MlDsaError

The reason that an ML-DSA call failed. It holds no secret bytes.

InvalidLength#

silk
InvalidLength

A seed, key, mu, randomness, or output buffer does not have the length of the parameter set.

ContextTooLong#

silk
ContextTooLong

The context string is longer than 255 bytes.

InvalidPrivateKey#

silk
InvalidPrivateKey

A coefficient of the secret vectors s1 or s2 in the private key is out of range.

Implementation Debug for MlDsaError#

silk
impl Debug for MlDsaError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as InvalidLength.

MlDsa#

silk
pub struct MlDsa

The 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#

silk
impl MlDsa

Associated function keyPairFromSeed#

silk
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#

  • InvalidLength if seed is not 32 bytes, or a key buffer does not have the length of the parameter set. The buffers do not change.

Associated function generateSeed#

silk
pub effect fn generateSeed() -> [u8; 32] ? &mut Random

Returns a new 32-byte seed from the ambient Random, for MlDsa.keyPairFromSeed.

The Random provider must be cryptographically secure.

Associated function externalMu#

silk
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#

  • InvalidLength if publicKey does not have the length of the parameter set.

  • ContextTooLong if context is longer than 255 bytes.

Associated function sign#

silk
pub effect fn sign(
    parameters: MlDsaParameters,
    privateKey: &[u8],
    message: &[u8],
    context: &[u8],
    signature: &mut [u8],
  ) -> Result<(), MlDsaError> ? &mut Random

Writes a hedged signature of message with context into signature, with 32 bytes from the ambient Random.

Errors#

  • InvalidLength if privateKey or signature does not have the length of the parameter set.

  • ContextTooLong if context is longer than 255 bytes.

  • InvalidPrivateKey if the secret vectors are out of range.

Associated function signDeterministic#

silk
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#

silk
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#

  • InvalidLength for a key, mu, randomness, or signature buffer of the wrong length.

  • InvalidPrivateKey if 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#

silk
pub fn verify(
    parameters: MlDsaParameters,
    publicKey: &[u8],
    message: &[u8],
    context: &[u8],
    signature: &[u8],
  ) -> bool

Returns 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#

silk
pub fn verifyExternalMu(parameters: MlDsaParameters, publicKey: &[u8], mu: &[u8], signature: &[u8]) -> bool

Returns 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.

View the source of this page