From c83d23fde457c3c57c9e9acb0361014179a1b5b3 Mon Sep 17 00:00:00 2001 From: Konradsop Date: Fri, 8 May 2026 12:57:12 +0200 Subject: [PATCH] docs: add XML documentation for ML-KEM and ML-DSA parameter gaps Closes the documentation gaps left by the initial ML-KEM/ML-DSA documentation pass. Adds class-level summaries citing FIPS 203 / FIPS 204 and per-method , , , and tags for the public API surface of MLKemParameterSet, MLKemKeyParameters, MLKemKeyGenerationParameters, MLDsaParameterSet, MLDsaKeyParameters, MLDsaKeyGenerationParameters, and MLDsaPrivateKeyParameters (including the Format enum and seed/encoding helpers). No behavioural changes. --- .../MLDsaKeyGenerationParameters.cs | 12 ++++ .../crypto/parameters/MLDsaKeyParameters.cs | 5 ++ .../crypto/parameters/MLDsaParameterSet.cs | 10 ++++ .../parameters/MLDsaPrivateKeyParameters.cs | 58 ++++++++++++++++++- .../MLKemKeyGenerationParameters.cs | 12 ++++ .../crypto/parameters/MLKemKeyParameters.cs | 5 ++ .../crypto/parameters/MLKemParameterSet.cs | 12 ++++ 7 files changed, 113 insertions(+), 1 deletion(-) diff --git a/crypto/src/crypto/parameters/MLDsaKeyGenerationParameters.cs b/crypto/src/crypto/parameters/MLDsaKeyGenerationParameters.cs index 4cff0116f..3929a84ce 100644 --- a/crypto/src/crypto/parameters/MLDsaKeyGenerationParameters.cs +++ b/crypto/src/crypto/parameters/MLDsaKeyGenerationParameters.cs @@ -5,17 +5,28 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// Key generation parameters for ML-DSA (FIPS 204). Carries the used to + /// draw the seed material together with the chosen selector. Strength + /// is implied by the parameter set, so the base strength field is left at zero. + /// public sealed class MLDsaKeyGenerationParameters : KeyGenerationParameters { private readonly MLDsaParameters m_parameters; + /// Construct using directly. + /// If is null. public MLDsaKeyGenerationParameters(SecureRandom random, MLDsaParameters parameters) : base(random, 0) { m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); } + /// Construct by looking up the parameter set for . + /// If is null. + /// If is not a recognised + /// ML-DSA parameter OID (pure or HashML-DSA). public MLDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier parametersOid) : base(random, 0) { @@ -25,6 +36,7 @@ public MLDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier par throw new ArgumentException("unrecognised ML-DSA parameters OID", nameof(parametersOid)); } + /// The ML-DSA parameter set the generated key pair will be bound to. public MLDsaParameters Parameters => m_parameters; } } diff --git a/crypto/src/crypto/parameters/MLDsaKeyParameters.cs b/crypto/src/crypto/parameters/MLDsaKeyParameters.cs index d9de3f524..0876bfb45 100644 --- a/crypto/src/crypto/parameters/MLDsaKeyParameters.cs +++ b/crypto/src/crypto/parameters/MLDsaKeyParameters.cs @@ -2,6 +2,10 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// Common base for ML-DSA (FIPS 204) public and private key parameters; carries the + /// selector that the key was generated for. + /// public abstract class MLDsaKeyParameters : AsymmetricKeyParameter { @@ -13,6 +17,7 @@ internal MLDsaKeyParameters(bool isPrivate, MLDsaParameters parameters) m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); } + /// The parameter set this key is bound to. public MLDsaParameters Parameters => m_parameters; } } diff --git a/crypto/src/crypto/parameters/MLDsaParameterSet.cs b/crypto/src/crypto/parameters/MLDsaParameterSet.cs index 19ee92778..4ad35fa68 100644 --- a/crypto/src/crypto/parameters/MLDsaParameterSet.cs +++ b/crypto/src/crypto/parameters/MLDsaParameterSet.cs @@ -7,10 +7,18 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// The three ML-DSA parameter sets defined by FIPS 204, identified by the matrix dimensions + /// (k, ℓ) embedded in the name. Each entry binds the textual name to the engine mode that + /// produces the standardised public-key, private-key and signature sizes. + /// public sealed class MLDsaParameterSet { + /// ML-DSA-44 (NIST Category 2, mode 2). public static readonly MLDsaParameterSet ml_dsa_44 = new MLDsaParameterSet("ML-DSA-44", 2); + /// ML-DSA-65 (NIST Category 3, mode 3). public static readonly MLDsaParameterSet ml_dsa_65 = new MLDsaParameterSet("ML-DSA-65", 3); + /// ML-DSA-87 (NIST Category 5, mode 5). public static readonly MLDsaParameterSet ml_dsa_87 = new MLDsaParameterSet("ML-DSA-87", 5); private static readonly Dictionary ByName = @@ -34,6 +42,7 @@ private MLDsaParameterSet(string name, int mode) internal MLDsaEngine GetEngine(SecureRandom random) => new MLDsaEngine(m_mode, random); + /// The textual name of this parameter set (e.g. "ML-DSA-44"). public string Name => m_name; internal int PrivateKeyLength @@ -68,6 +77,7 @@ internal int PublicKeyLength internal int SeedLength => MLDsaEngine.SeedBytes; + /// public override string ToString() => Name; } } diff --git a/crypto/src/crypto/parameters/MLDsaPrivateKeyParameters.cs b/crypto/src/crypto/parameters/MLDsaPrivateKeyParameters.cs index 34a3bdd30..7cde891bd 100644 --- a/crypto/src/crypto/parameters/MLDsaPrivateKeyParameters.cs +++ b/crypto/src/crypto/parameters/MLDsaPrivateKeyParameters.cs @@ -6,16 +6,43 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// ML-DSA private key (FIPS 204). The expanded key holds (ρ, K, tr, s₁, s₂, t₀) derived from + /// a 32-byte seed; the corresponding t₁ half of the public key is cached for fast public-key + /// recovery. A key built from a seed retains the seed so it can be re-encoded in the seed format. + /// public sealed class MLDsaPrivateKeyParameters : MLDsaKeyParameters { - public enum Format { SeedOnly, EncodingOnly, SeedAndEncoding }; + /// + /// Storage format selector for serialised private keys. Per RFC 9881 §8.1 the seed form is + /// preferred for storage efficiency. + /// + public enum Format + { + /// Serialise as the 32-byte seed only; requires that the seed is available. + SeedOnly, + /// Serialise as the expanded encoding only; works for keys imported by encoding. + EncodingOnly, + /// Carry both the seed and the expanded encoding. + SeedAndEncoding, + }; /* * RFC 9881 8.1. [..] the seed format is RECOMMENDED for storage efficiency. */ + /// Default applied when a key is constructed from a seed. public static readonly Format DefaultFormat = Format.SeedOnly; + /// + /// Decode a private key from its expanded byte representation. The expected length is the + /// parameter set's PrivateKeyLength; the returned key has + /// as its preferred format because the seed is not recoverable from the encoding. + /// + /// If or + /// is null. + /// If length does not match the + /// parameter set's private-key length. public static MLDsaPrivateKeyParameters FromEncoding(MLDsaParameters parameters, byte[] encoding) { if (parameters == null) @@ -56,9 +83,20 @@ public static MLDsaPrivateKeyParameters FromEncoding(MLDsaParameters parameters, return new MLDsaPrivateKeyParameters(parameters, rho, k, tr, s1, s2, t0, t1, seed, Format.EncodingOnly); } + /// + /// Expand a 32-byte seed into a private key, defaulting to + /// (). + /// public static MLDsaPrivateKeyParameters FromSeed(MLDsaParameters parameters, byte[] seed) => FromSeed(parameters, seed, preferredFormat: DefaultFormat); + /// + /// Expand a 32-byte seed into a private key with the supplied . + /// + /// If or + /// is null. + /// If length is not the parameter + /// set's SeedLength, or is unrecognised. public static MLDsaPrivateKeyParameters FromSeed(MLDsaParameters parameters, byte[] seed, Format preferredFormat) { @@ -107,14 +145,24 @@ internal MLDsaPrivateKeyParameters(MLDsaParameters parameters, byte[] rho, byte[ m_preferredFormat = preferredFormat; } + /// + /// Return a fresh copy of the expanded ρ || K || tr || s₁ || s₂ || t₀ encoding. + /// public byte[] GetEncoded() => Arrays.ConcatenateAll(m_rho, m_k, m_tr, m_s1, m_s2, m_t0); + /// Return the public key derived during key expansion. public MLDsaPublicKeyParameters GetPublicKey() => new MLDsaPublicKeyParameters(Parameters, m_rho, m_t1); + /// Return a fresh copy of the public key encoding (ρ || t₁). public byte[] GetPublicKeyEncoded() => Arrays.Concatenate(m_rho, m_t1); + /// + /// Return a fresh copy of the 32-byte seed if one was retained at construction; null for + /// keys imported via . + /// public byte[] GetSeed() => Arrays.Clone(m_seed); + /// The serialisation format this key was last asked to prefer. public Format PreferredFormat => m_preferredFormat; internal byte[] Seed => m_seed; @@ -129,6 +177,14 @@ internal byte[] SignInternal(byte[] rnd, byte[] msg, int msgOff, int msgLen) return sig; } + /// + /// Return a key equivalent to this one but with changed to + /// . Returns the receiver when the format is unchanged. + /// + /// If the requested format requires a seed but no + /// seed is available (i.e. the key was imported via ). + /// If is not a recognised + /// value. public MLDsaPrivateKeyParameters WithPreferredFormat(Format preferredFormat) { if (m_preferredFormat == preferredFormat) diff --git a/crypto/src/crypto/parameters/MLKemKeyGenerationParameters.cs b/crypto/src/crypto/parameters/MLKemKeyGenerationParameters.cs index 694a9eee2..78f4d0943 100644 --- a/crypto/src/crypto/parameters/MLKemKeyGenerationParameters.cs +++ b/crypto/src/crypto/parameters/MLKemKeyGenerationParameters.cs @@ -5,17 +5,28 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// Key generation parameters for ML-KEM (FIPS 203). Carries the used to + /// draw the seed material together with the chosen selector. Strength + /// is implied by the parameter set, so the base strength field is left at zero. + /// public sealed class MLKemKeyGenerationParameters : KeyGenerationParameters { private readonly MLKemParameters m_parameters; + /// Construct using directly. + /// If is null. public MLKemKeyGenerationParameters(SecureRandom random, MLKemParameters parameters) : base(random, 0) { m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); } + /// Construct by looking up the parameter set for . + /// If is null. + /// If is not a recognised + /// ML-KEM parameter OID. public MLKemKeyGenerationParameters(SecureRandom random, DerObjectIdentifier parametersOid) : base(random, 0) { @@ -25,6 +36,7 @@ public MLKemKeyGenerationParameters(SecureRandom random, DerObjectIdentifier par throw new ArgumentException("unrecognised ML-KEM parameters OID", nameof(parametersOid)); } + /// The ML-KEM parameter set the generated key pair will be bound to. public MLKemParameters Parameters => m_parameters; } } diff --git a/crypto/src/crypto/parameters/MLKemKeyParameters.cs b/crypto/src/crypto/parameters/MLKemKeyParameters.cs index 83c578abe..ffb19915f 100644 --- a/crypto/src/crypto/parameters/MLKemKeyParameters.cs +++ b/crypto/src/crypto/parameters/MLKemKeyParameters.cs @@ -2,6 +2,10 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// Common base for ML-KEM (FIPS 203) public and private key parameters; carries the + /// selector that the key was generated for. + /// public abstract class MLKemKeyParameters : AsymmetricKeyParameter { @@ -13,6 +17,7 @@ internal MLKemKeyParameters(bool isPrivate, MLKemParameters parameters) m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); } + /// The parameter set this key is bound to. public MLKemParameters Parameters => m_parameters; } } diff --git a/crypto/src/crypto/parameters/MLKemParameterSet.cs b/crypto/src/crypto/parameters/MLKemParameterSet.cs index 43e13a6a4..47cafdb49 100644 --- a/crypto/src/crypto/parameters/MLKemParameterSet.cs +++ b/crypto/src/crypto/parameters/MLKemParameterSet.cs @@ -6,10 +6,18 @@ namespace Org.BouncyCastle.Crypto.Parameters { + /// + /// The three ML-KEM parameter sets defined by FIPS 203, distinguished by the module-lattice rank + /// k. Each entry binds the textual name to a configured engine that produces the standardised + /// ciphertext and shared-secret sizes. + /// public sealed class MLKemParameterSet { + /// ML-KEM-512 (NIST Category 1, k = 2). public static readonly MLKemParameterSet ml_kem_512 = new MLKemParameterSet("ML-KEM-512", 2); + /// ML-KEM-768 (NIST Category 3, k = 3). public static readonly MLKemParameterSet ml_kem_768 = new MLKemParameterSet("ML-KEM-768", 3); + /// ML-KEM-1024 (NIST Category 5, k = 4). public static readonly MLKemParameterSet ml_kem_1024 = new MLKemParameterSet("ML-KEM-1024", 4); private static readonly Dictionary ByName = @@ -31,14 +39,18 @@ private MLKemParameterSet(string name, int k) m_engine = new MLKemEngine(k); } + /// Length in bytes of an ML-KEM encapsulation (ciphertext) for this parameter set. public int EncapsulationLength => m_engine.CipherTextBytes; internal MLKemEngine Engine => m_engine; + /// Length in bytes of the shared secret produced by encapsulation/decapsulation (32). public int SecretLength => MLKemEngine.SharedSecretBytes; + /// The textual name of this parameter set (e.g. "ML-KEM-512"). public string Name => m_name; + /// public override string ToString() => Name; } }