diff --git a/crypto/src/crypto/parameters/SlhDsaKeyGenerationParameters.cs b/crypto/src/crypto/parameters/SlhDsaKeyGenerationParameters.cs
index 1a2f02f65..92ca33520 100644
--- a/crypto/src/crypto/parameters/SlhDsaKeyGenerationParameters.cs
+++ b/crypto/src/crypto/parameters/SlhDsaKeyGenerationParameters.cs
@@ -5,17 +5,28 @@
namespace Org.BouncyCastle.Crypto.Parameters
{
+ ///
+ /// Key generation parameters for SLH-DSA (FIPS 205). 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 SlhDsaKeyGenerationParameters
: KeyGenerationParameters
{
private readonly SlhDsaParameters m_parameters;
+ /// Construct using directly.
+ /// If is null.
public SlhDsaKeyGenerationParameters(SecureRandom random, SlhDsaParameters 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
+ /// SLH-DSA parameter OID.
public SlhDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier parametersOid)
: base(random, 0)
{
@@ -25,6 +36,7 @@ public SlhDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier pa
throw new ArgumentException("unrecognised SLH-DSA parameters OID", nameof(parametersOid));
}
+ /// The SLH-DSA parameter set the generated key pair will be bound to.
public SlhDsaParameters Parameters => m_parameters;
}
}
diff --git a/crypto/src/crypto/parameters/SlhDsaKeyParameters.cs b/crypto/src/crypto/parameters/SlhDsaKeyParameters.cs
index 775bf1a60..cb7834967 100644
--- a/crypto/src/crypto/parameters/SlhDsaKeyParameters.cs
+++ b/crypto/src/crypto/parameters/SlhDsaKeyParameters.cs
@@ -2,6 +2,10 @@
namespace Org.BouncyCastle.Crypto.Parameters
{
+ ///
+ /// Common base for SLH-DSA public and private key parameters; carries the
+ /// selector that the key was generated for.
+ ///
public abstract class SlhDsaKeyParameters
: AsymmetricKeyParameter
{
@@ -13,6 +17,7 @@ internal SlhDsaKeyParameters(bool isPrivate, SlhDsaParameters parameters)
m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
}
+ /// The parameter set this key is bound to.
public SlhDsaParameters Parameters => m_parameters;
}
}
diff --git a/crypto/src/crypto/parameters/SlhDsaParameterSet.cs b/crypto/src/crypto/parameters/SlhDsaParameterSet.cs
index 3adea9a3f..a55c05d5f 100644
--- a/crypto/src/crypto/parameters/SlhDsaParameterSet.cs
+++ b/crypto/src/crypto/parameters/SlhDsaParameterSet.cs
@@ -13,35 +13,52 @@ internal interface ISlhDsaEngineProvider
SlhDsaEngine Get();
}
+ ///
+ /// The 12 SLH-DSA tree parameter sets defined by FIPS 205, identifying the WOTS+ (w),
+ /// hypertree (d, h) and FORS (a, k) shape together with the security
+ /// parameter n and the underlying hash family (SHA-2 or SHAKE-256).
+ ///
public sealed class SlhDsaParameterSet
{
+ /// SLH-DSA-SHA2-128s tree parameters (n=16, h=63, d=7, k=14, a=12).
public static readonly SlhDsaParameterSet slh_dsa_sha2_128s = new SlhDsaParameterSet("SLH-DSA-SHA2-128s",
new Sha2EngineProvider(n: 16, w: 16, d: 7, a: 12, k: 14, h: 63));
+ /// SLH-DSA-SHAKE-128s tree parameters (n=16, h=63, d=7, k=14, a=12).
public static readonly SlhDsaParameterSet slh_dsa_shake_128s = new SlhDsaParameterSet("SLH-DSA-SHAKE-128s",
new Shake256EngineProvider(n: 16, w: 16, d: 7, a: 12, k: 14, h: 63));
+ /// SLH-DSA-SHA2-128f tree parameters (n=16, h=66, d=22, k=33, a=6).
public static readonly SlhDsaParameterSet slh_dsa_sha2_128f = new SlhDsaParameterSet("SLH-DSA-SHA2-128f",
new Sha2EngineProvider(n: 16, w: 16, d: 22, a: 6, k: 33, h: 66));
+ /// SLH-DSA-SHAKE-128f tree parameters (n=16, h=66, d=22, k=33, a=6).
public static readonly SlhDsaParameterSet slh_dsa_shake_128f = new SlhDsaParameterSet("SLH-DSA-SHAKE-128f",
new Shake256EngineProvider(n: 16, w: 16, d: 22, a: 6, k: 33, h: 66));
+ /// SLH-DSA-SHA2-192s tree parameters (n=24, h=63, d=7, k=17, a=14).
public static readonly SlhDsaParameterSet slh_dsa_sha2_192s = new SlhDsaParameterSet("SLH-DSA-SHA2-192s",
new Sha2EngineProvider(n: 24, w: 16, d: 7, a: 14, k: 17, h: 63));
+ /// SLH-DSA-SHAKE-192s tree parameters (n=24, h=63, d=7, k=17, a=14).
public static readonly SlhDsaParameterSet slh_dsa_shake_192s = new SlhDsaParameterSet("SLH-DSA-SHAKE-192s",
new Shake256EngineProvider(n: 24, w: 16, d: 7, a: 14, k: 17, h: 63));
+ /// SLH-DSA-SHA2-192f tree parameters (n=24, h=66, d=22, k=33, a=8).
public static readonly SlhDsaParameterSet slh_dsa_sha2_192f = new SlhDsaParameterSet("SLH-DSA-SHA2-192f",
new Sha2EngineProvider(n: 24, w: 16, d: 22, a: 8, k: 33, h: 66));
+ /// SLH-DSA-SHAKE-192f tree parameters (n=24, h=66, d=22, k=33, a=8).
public static readonly SlhDsaParameterSet slh_dsa_shake_192f = new SlhDsaParameterSet("SLH-DSA-SHAKE-192f",
new Shake256EngineProvider(n: 24, w: 16, d: 22, a: 8, k: 33, h: 66));
+ /// SLH-DSA-SHA2-256s tree parameters (n=32, h=64, d=8, k=22, a=14).
public static readonly SlhDsaParameterSet slh_dsa_sha2_256s = new SlhDsaParameterSet("SLH-DSA-SHA2-256s",
new Sha2EngineProvider(n: 32, w: 16, d: 8, a: 14, k: 22, h: 64));
+ /// SLH-DSA-SHAKE-256s tree parameters (n=32, h=64, d=8, k=22, a=14).
public static readonly SlhDsaParameterSet slh_dsa_shake_256s = new SlhDsaParameterSet("SLH-DSA-SHAKE-256s",
new Shake256EngineProvider(n: 32, w: 16, d: 8, a: 14, k: 22, h: 64));
+ /// SLH-DSA-SHA2-256f tree parameters (n=32, h=68, d=17, k=35, a=9).
public static readonly SlhDsaParameterSet slh_dsa_sha2_256f = new SlhDsaParameterSet("SLH-DSA-SHA2-256f",
new Sha2EngineProvider(n: 32, w: 16, d: 17, a: 9, k: 35, h: 68));
+ /// SLH-DSA-SHAKE-256f tree parameters (n=32, h=68, d=17, k=35, a=9).
public static readonly SlhDsaParameterSet slh_dsa_shake_256f = new SlhDsaParameterSet("SLH-DSA-SHAKE-256f",
new Shake256EngineProvider(n: 32, w: 16, d: 17, a: 9, k: 35, h: 68));
@@ -73,12 +90,14 @@ private SlhDsaParameterSet(string name, ISlhDsaEngineProvider engineProvider)
m_engineProvider = engineProvider;
}
+ /// The textual name of this parameter set (e.g. "SLH-DSA-SHA2-128s").
public string Name => m_name;
internal int PrivateKeyLength => 4 * N;
internal int PublicKeyLength => 2 * N;
+ ///
public override string ToString() => Name;
internal int N => m_engineProvider.N;
diff --git a/crypto/src/crypto/parameters/SlhDsaParameters.cs b/crypto/src/crypto/parameters/SlhDsaParameters.cs
index 487a2ef94..bb93a116d 100644
--- a/crypto/src/crypto/parameters/SlhDsaParameters.cs
+++ b/crypto/src/crypto/parameters/SlhDsaParameters.cs
@@ -7,76 +7,111 @@
namespace Org.BouncyCastle.Crypto.Parameters
{
+ ///
+ /// Parameter selector for SLH-DSA, the stateless hash-based signature scheme standardised by NIST in
+ /// FIPS 205. Each instance binds a parameter set (security level, fast/small variant, hash family) to
+ /// its NIST OID; the WITH variants additionally pre-hash the message with the indicated digest
+ /// (HashSLH-DSA, FIPS 205 §10.2).
+ ///
+ ///
+ /// Naming follows the FIPS 205 convention SLH-DSA-{HASH}-{SECURITY}{S|F}, where S selects
+ /// the small-signature variant (slower signing, smaller signatures) and F the fast variant
+ /// (faster signing, larger signatures).
+ ///
public sealed class SlhDsaParameters
{
+ /// SLH-DSA-SHA2-128s (Category 1, small variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_128s = new SlhDsaParameters("SLH-DSA-SHA2-128S",
SlhDsaParameterSet.slh_dsa_sha2_128s, NistObjectIdentifiers.id_slh_dsa_sha2_128s, preHashOid: null);
+ /// SLH-DSA-SHAKE-128s (Category 1, small variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_128s = new SlhDsaParameters("SLH-DSA-SHAKE-128S",
SlhDsaParameterSet.slh_dsa_shake_128s, NistObjectIdentifiers.id_slh_dsa_shake_128s, preHashOid: null);
+ /// SLH-DSA-SHA2-128f (Category 1, fast variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_128f = new SlhDsaParameters("SLH-DSA-SHA2-128F",
SlhDsaParameterSet.slh_dsa_sha2_128f, NistObjectIdentifiers.id_slh_dsa_sha2_128f, preHashOid: null);
+ /// SLH-DSA-SHAKE-128f (Category 1, fast variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_128f = new SlhDsaParameters("SLH-DSA-SHAKE-128F",
SlhDsaParameterSet.slh_dsa_shake_128f, NistObjectIdentifiers.id_slh_dsa_shake_128f, preHashOid: null);
+ /// SLH-DSA-SHA2-192s (Category 3, small variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_192s = new SlhDsaParameters("SLH-DSA-SHA2-192S",
SlhDsaParameterSet.slh_dsa_sha2_192s, NistObjectIdentifiers.id_slh_dsa_sha2_192s, preHashOid: null);
+ /// SLH-DSA-SHAKE-192s (Category 3, small variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_192s = new SlhDsaParameters("SLH-DSA-SHAKE-192S",
SlhDsaParameterSet.slh_dsa_shake_192s, NistObjectIdentifiers.id_slh_dsa_shake_192s, preHashOid: null);
+ /// SLH-DSA-SHA2-192f (Category 3, fast variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_192f = new SlhDsaParameters("SLH-DSA-SHA2-192F",
SlhDsaParameterSet.slh_dsa_sha2_192f, NistObjectIdentifiers.id_slh_dsa_sha2_192f, preHashOid: null);
+ /// SLH-DSA-SHAKE-192f (Category 3, fast variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_192f = new SlhDsaParameters("SLH-DSA-SHAKE-192F",
SlhDsaParameterSet.slh_dsa_shake_192f, NistObjectIdentifiers.id_slh_dsa_shake_192f, preHashOid: null);
+ /// SLH-DSA-SHA2-256s (Category 5, small variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_256s = new SlhDsaParameters("SLH-DSA-SHA2-256S",
SlhDsaParameterSet.slh_dsa_sha2_256s, NistObjectIdentifiers.id_slh_dsa_sha2_256s, preHashOid: null);
+ /// SLH-DSA-SHAKE-256s (Category 5, small variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_256s = new SlhDsaParameters("SLH-DSA-SHAKE-256S",
SlhDsaParameterSet.slh_dsa_shake_256s, NistObjectIdentifiers.id_slh_dsa_shake_256s, preHashOid: null);
+ /// SLH-DSA-SHA2-256f (Category 5, fast variant, SHA-2 family).
public static readonly SlhDsaParameters slh_dsa_sha2_256f = new SlhDsaParameters("SLH-DSA-SHA2-256F",
SlhDsaParameterSet.slh_dsa_sha2_256f, NistObjectIdentifiers.id_slh_dsa_sha2_256f, preHashOid: null);
+ /// SLH-DSA-SHAKE-256f (Category 5, fast variant, SHAKE family).
public static readonly SlhDsaParameters slh_dsa_shake_256f = new SlhDsaParameters("SLH-DSA-SHAKE-256F",
SlhDsaParameterSet.slh_dsa_shake_256f, NistObjectIdentifiers.id_slh_dsa_shake_256f, preHashOid: null);
+ /// HashSLH-DSA-SHA2-128s with SHA-256 pre-hash (Category 1, small).
public static readonly SlhDsaParameters slh_dsa_sha2_128s_with_sha256 = new SlhDsaParameters(
"SLH-DSA-SHA2-128S-WITH-SHA256", SlhDsaParameterSet.slh_dsa_sha2_128s,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, NistObjectIdentifiers.IdSha256);
+ /// HashSLH-DSA-SHAKE-128s with SHAKE128 pre-hash (Category 1, small).
public static readonly SlhDsaParameters slh_dsa_shake_128s_with_shake128 = new SlhDsaParameters(
"SLH-DSA-SHAKE-128S-WITH-SHAKE128", SlhDsaParameterSet.slh_dsa_shake_128s,
NistObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, NistObjectIdentifiers.IdShake128);
+ /// HashSLH-DSA-SHA2-128f with SHA-256 pre-hash (Category 1, fast).
public static readonly SlhDsaParameters slh_dsa_sha2_128f_with_sha256 = new SlhDsaParameters(
"SLH-DSA-SHA2-128F-WITH-SHA256", SlhDsaParameterSet.slh_dsa_sha2_128f,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, NistObjectIdentifiers.IdSha256);
+ /// HashSLH-DSA-SHAKE-128f with SHAKE128 pre-hash (Category 1, fast).
public static readonly SlhDsaParameters slh_dsa_shake_128f_with_shake128 = new SlhDsaParameters(
"SLH-DSA-SHAKE-128F-WITH-SHAKE128", SlhDsaParameterSet.slh_dsa_shake_128f,
NistObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, NistObjectIdentifiers.IdShake128);
+ /// HashSLH-DSA-SHA2-192s with SHA-512 pre-hash (Category 3, small).
public static readonly SlhDsaParameters slh_dsa_sha2_192s_with_sha512 = new SlhDsaParameters(
"SLH-DSA-SHA2-192S-WITH-SHA512", SlhDsaParameterSet.slh_dsa_sha2_192s,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, NistObjectIdentifiers.IdSha512);
+ /// HashSLH-DSA-SHAKE-192s with SHAKE256 pre-hash (Category 3, small).
public static readonly SlhDsaParameters slh_dsa_shake_192s_with_shake256 = new SlhDsaParameters(
"SLH-DSA-SHAKE-192S-WITH-SHAKE256", SlhDsaParameterSet.slh_dsa_shake_192s,
NistObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, NistObjectIdentifiers.IdShake256);
+ /// HashSLH-DSA-SHA2-192f with SHA-512 pre-hash (Category 3, fast).
public static readonly SlhDsaParameters slh_dsa_sha2_192f_with_sha512 = new SlhDsaParameters(
"SLH-DSA-SHA2-192F-WITH-SHA512", SlhDsaParameterSet.slh_dsa_sha2_192f,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, NistObjectIdentifiers.IdSha512);
+ /// HashSLH-DSA-SHAKE-192f with SHAKE256 pre-hash (Category 3, fast).
public static readonly SlhDsaParameters slh_dsa_shake_192f_with_shake256 = new SlhDsaParameters(
"SLH-DSA-SHAKE-192F-WITH-SHAKE256", SlhDsaParameterSet.slh_dsa_shake_192f,
NistObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, NistObjectIdentifiers.IdShake256);
+ /// HashSLH-DSA-SHA2-256s with SHA-512 pre-hash (Category 5, small).
public static readonly SlhDsaParameters slh_dsa_sha2_256s_with_sha512 = new SlhDsaParameters(
"SLH-DSA-SHA2-256S-WITH-SHA512", SlhDsaParameterSet.slh_dsa_sha2_256s,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, NistObjectIdentifiers.IdSha512);
+ /// HashSLH-DSA-SHAKE-256s with SHAKE256 pre-hash (Category 5, small).
public static readonly SlhDsaParameters slh_dsa_shake_256s_with_shake256 = new SlhDsaParameters(
"SLH-DSA-SHAKE-256S-WITH-SHAKE256", SlhDsaParameterSet.slh_dsa_shake_256s,
NistObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, NistObjectIdentifiers.IdShake256);
+ /// HashSLH-DSA-SHA2-256f with SHA-512 pre-hash (Category 5, fast).
public static readonly SlhDsaParameters slh_dsa_sha2_256f_with_sha512 = new SlhDsaParameters(
"SLH-DSA-SHA2-256F-WITH-SHA512", SlhDsaParameterSet.slh_dsa_sha2_256f,
NistObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, NistObjectIdentifiers.IdSha512);
+ /// HashSLH-DSA-SHAKE-256f with SHAKE256 pre-hash (Category 5, fast).
public static readonly SlhDsaParameters slh_dsa_shake_256f_with_shake256 = new SlhDsaParameters(
"SLH-DSA-SHAKE-256F-WITH-SHAKE256", SlhDsaParameterSet.slh_dsa_shake_256f,
NistObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, NistObjectIdentifiers.IdShake256);
@@ -153,16 +188,23 @@ private SlhDsaParameters(string name, SlhDsaParameterSet parameterSet, DerObject
m_preHashOid = preHashOid;
}
+ ///
+ /// true for the HashSLH-DSA variants (FIPS 205 §10.2) that pre-hash the message before
+ /// signing; false for pure SLH-DSA.
+ ///
public bool IsPreHash => m_preHashOid != null;
+ /// The textual name of this parameter set (e.g. "SLH-DSA-SHA2-128S").
public string Name => m_name;
internal DerObjectIdentifier Oid => m_oid;
internal DerObjectIdentifier PreHashOid => m_preHashOid;
+ /// The underlying tree/Winternitz parameter set this entry binds to its OID.
public SlhDsaParameterSet ParameterSet => m_parameterSet;
+ ///
public override string ToString() => Name;
}
}
diff --git a/crypto/src/crypto/parameters/SlhDsaPrivateKeyParameters.cs b/crypto/src/crypto/parameters/SlhDsaPrivateKeyParameters.cs
index da536faa9..4f7453e37 100644
--- a/crypto/src/crypto/parameters/SlhDsaPrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/SlhDsaPrivateKeyParameters.cs
@@ -5,9 +5,22 @@
namespace Org.BouncyCastle.Crypto.Parameters
{
+ ///
+ /// SLH-DSA private key (FIPS 205). Holds the (SK.seed, SK.prf, PK.seed, PK.root) tuple — the
+ /// signing seed and PRF key together with a copy of the public key needed for hypertree
+ /// verification during signing.
+ ///
public sealed class SlhDsaPrivateKeyParameters
: SlhDsaKeyParameters
{
+ ///
+ /// Decode a private key from its concatenated SK.seed || SK.prf || PK.seed || PK.root
+ /// byte representation. The expected length is 4 * n for the chosen parameter set.
+ ///
+ /// If or
+ /// is null.
+ /// If length does not match the
+ /// parameter set's private-key length.
public static SlhDsaPrivateKeyParameters FromEncoding(SlhDsaParameters parameters, byte[] encoding)
{
if (parameters == null)
@@ -33,10 +46,16 @@ internal SlhDsaPrivateKeyParameters(SlhDsaParameters parameters, SK sk, PK pk)
m_pk = pk;
}
+ ///
+ /// Return a fresh copy of the concatenated SK.seed || SK.prf || PK.seed || PK.root
+ /// encoding.
+ ///
public byte[] GetEncoded() => Arrays.ConcatenateAll(m_sk.Seed, m_sk.Prf, m_pk.Seed, m_pk.Root);
+ /// Return the public key embedded in this private key.
public SlhDsaPublicKeyParameters GetPublicKey() => new SlhDsaPublicKeyParameters(Parameters, m_pk);
+ /// Return a fresh copy of the public key portion (seed || root).
public byte[] GetPublicKeyEncoded() => Arrays.Concatenate(m_pk.Seed, m_pk.Root);
internal PK PK => m_pk;
diff --git a/crypto/src/crypto/parameters/SlhDsaPublicKeyParameters.cs b/crypto/src/crypto/parameters/SlhDsaPublicKeyParameters.cs
index d63452169..ef047f398 100644
--- a/crypto/src/crypto/parameters/SlhDsaPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/SlhDsaPublicKeyParameters.cs
@@ -5,9 +5,21 @@
namespace Org.BouncyCastle.Crypto.Parameters
{
+ ///
+ /// SLH-DSA public key (FIPS 205). Wraps the (PK.seed, PK.root) tuple that anchors signature
+ /// verification.
+ ///
public sealed class SlhDsaPublicKeyParameters
: SlhDsaKeyParameters
{
+ ///
+ /// Decode a public key from its concatenated seed || root byte representation.
+ /// The expected length is 2 * n for the chosen parameter set.
+ ///
+ /// If or
+ /// is null.
+ /// If length does not match the
+ /// parameter set's public-key length.
public static SlhDsaPublicKeyParameters FromEncoding(SlhDsaParameters parameters, byte[] encoding)
{
if (parameters == null)
@@ -30,6 +42,7 @@ internal SlhDsaPublicKeyParameters(SlhDsaParameters parameters, PK pk)
m_pk = pk;
}
+ /// Return a fresh copy of the concatenated seed || root encoding.
public byte[] GetEncoded() => Arrays.Concatenate(m_pk.Seed, m_pk.Root);
internal PK PK => m_pk;