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;