Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions crypto/src/crypto/parameters/SlhDsaKeyGenerationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,28 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Key generation parameters for SLH-DSA (FIPS 205). Carries the <see cref="SecureRandom"/> used to
/// draw the seed material together with the chosen <see cref="SlhDsaParameters"/> selector. Strength
/// is implied by the parameter set, so the base <c>strength</c> field is left at zero.
/// </summary>
public sealed class SlhDsaKeyGenerationParameters
: KeyGenerationParameters
{
private readonly SlhDsaParameters m_parameters;

/// <summary>Construct using <paramref name="parameters"/> directly.</summary>
/// <exception cref="ArgumentNullException">If <paramref name="parameters"/> is <c>null</c>.</exception>
public SlhDsaKeyGenerationParameters(SecureRandom random, SlhDsaParameters parameters)
: base(random, 0)
{
m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
}

/// <summary>Construct by looking up the parameter set for <paramref name="parametersOid"/>.</summary>
/// <exception cref="ArgumentNullException">If <paramref name="parametersOid"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="parametersOid"/> is not a recognised
/// SLH-DSA parameter OID.</exception>
public SlhDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier parametersOid)
: base(random, 0)
{
Expand All @@ -25,6 +36,7 @@ public SlhDsaKeyGenerationParameters(SecureRandom random, DerObjectIdentifier pa
throw new ArgumentException("unrecognised SLH-DSA parameters OID", nameof(parametersOid));
}

/// <summary>The SLH-DSA parameter set the generated key pair will be bound to.</summary>
public SlhDsaParameters Parameters => m_parameters;
}
}
5 changes: 5 additions & 0 deletions crypto/src/crypto/parameters/SlhDsaKeyParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Common base for SLH-DSA public and private key parameters; carries the
/// <see cref="SlhDsaParameters"/> selector that the key was generated for.
/// </summary>
public abstract class SlhDsaKeyParameters
: AsymmetricKeyParameter
{
Expand All @@ -13,6 +17,7 @@ internal SlhDsaKeyParameters(bool isPrivate, SlhDsaParameters parameters)
m_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
}

/// <summary>The parameter set this key is bound to.</summary>
public SlhDsaParameters Parameters => m_parameters;
}
}
19 changes: 19 additions & 0 deletions crypto/src/crypto/parameters/SlhDsaParameterSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,52 @@ internal interface ISlhDsaEngineProvider
SlhDsaEngine Get();
}

/// <summary>
/// The 12 SLH-DSA tree parameter sets defined by FIPS 205, identifying the WOTS+ (<c>w</c>),
/// hypertree (<c>d</c>, <c>h</c>) and FORS (<c>a</c>, <c>k</c>) shape together with the security
/// parameter <c>n</c> and the underlying hash family (SHA-2 or SHAKE-256).
/// </summary>
public sealed class SlhDsaParameterSet
{
/// <summary>SLH-DSA-SHA2-128s tree parameters (<c>n=16, h=63, d=7, k=14, a=12</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-128s tree parameters (<c>n=16, h=63, d=7, k=14, a=12</c>).</summary>
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));

/// <summary>SLH-DSA-SHA2-128f tree parameters (<c>n=16, h=66, d=22, k=33, a=6</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-128f tree parameters (<c>n=16, h=66, d=22, k=33, a=6</c>).</summary>
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));

/// <summary>SLH-DSA-SHA2-192s tree parameters (<c>n=24, h=63, d=7, k=17, a=14</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-192s tree parameters (<c>n=24, h=63, d=7, k=17, a=14</c>).</summary>
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));

/// <summary>SLH-DSA-SHA2-192f tree parameters (<c>n=24, h=66, d=22, k=33, a=8</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-192f tree parameters (<c>n=24, h=66, d=22, k=33, a=8</c>).</summary>
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));

/// <summary>SLH-DSA-SHA2-256s tree parameters (<c>n=32, h=64, d=8, k=22, a=14</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-256s tree parameters (<c>n=32, h=64, d=8, k=22, a=14</c>).</summary>
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));

/// <summary>SLH-DSA-SHA2-256f tree parameters (<c>n=32, h=68, d=17, k=35, a=9</c>).</summary>
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));
/// <summary>SLH-DSA-SHAKE-256f tree parameters (<c>n=32, h=68, d=17, k=35, a=9</c>).</summary>
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));

Expand Down Expand Up @@ -73,12 +90,14 @@ private SlhDsaParameterSet(string name, ISlhDsaEngineProvider engineProvider)
m_engineProvider = engineProvider;
}

/// <summary>The textual name of this parameter set (e.g. <c>"SLH-DSA-SHA2-128s"</c>).</summary>
public string Name => m_name;

internal int PrivateKeyLength => 4 * N;

internal int PublicKeyLength => 2 * N;

/// <inheritdoc/>
public override string ToString() => Name;

internal int N => m_engineProvider.N;
Expand Down
42 changes: 42 additions & 0 deletions crypto/src/crypto/parameters/SlhDsaParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,111 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// 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 <c>WITH</c> variants additionally pre-hash the message with the indicated digest
/// (HashSLH-DSA, FIPS 205 §10.2).
/// </summary>
/// <remarks>
/// Naming follows the FIPS 205 convention <c>SLH-DSA-{HASH}-{SECURITY}{S|F}</c>, where <c>S</c> selects
/// the small-signature variant (slower signing, smaller signatures) and <c>F</c> the fast variant
/// (faster signing, larger signatures).
/// </remarks>
public sealed class SlhDsaParameters
{
/// <summary>SLH-DSA-SHA2-128s (Category 1, small variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-128s (Category 1, small variant, SHAKE family).</summary>
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);

/// <summary>SLH-DSA-SHA2-128f (Category 1, fast variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-128f (Category 1, fast variant, SHAKE family).</summary>
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);

/// <summary>SLH-DSA-SHA2-192s (Category 3, small variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-192s (Category 3, small variant, SHAKE family).</summary>
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);

/// <summary>SLH-DSA-SHA2-192f (Category 3, fast variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-192f (Category 3, fast variant, SHAKE family).</summary>
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);

/// <summary>SLH-DSA-SHA2-256s (Category 5, small variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-256s (Category 5, small variant, SHAKE family).</summary>
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);

/// <summary>SLH-DSA-SHA2-256f (Category 5, fast variant, SHA-2 family).</summary>
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);
/// <summary>SLH-DSA-SHAKE-256f (Category 5, fast variant, SHAKE family).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-128s with SHA-256 pre-hash (Category 1, small).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-128s with SHAKE128 pre-hash (Category 1, small).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-128f with SHA-256 pre-hash (Category 1, fast).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-128f with SHAKE128 pre-hash (Category 1, fast).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-192s with SHA-512 pre-hash (Category 3, small).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-192s with SHAKE256 pre-hash (Category 3, small).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-192f with SHA-512 pre-hash (Category 3, fast).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-192f with SHAKE256 pre-hash (Category 3, fast).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-256s with SHA-512 pre-hash (Category 5, small).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-256s with SHAKE256 pre-hash (Category 5, small).</summary>
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);

/// <summary>HashSLH-DSA-SHA2-256f with SHA-512 pre-hash (Category 5, fast).</summary>
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);
/// <summary>HashSLH-DSA-SHAKE-256f with SHAKE256 pre-hash (Category 5, fast).</summary>
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);
Expand Down Expand Up @@ -153,16 +188,23 @@ private SlhDsaParameters(string name, SlhDsaParameterSet parameterSet, DerObject
m_preHashOid = preHashOid;
}

/// <summary>
/// <c>true</c> for the HashSLH-DSA variants (FIPS 205 §10.2) that pre-hash the message before
/// signing; <c>false</c> for pure SLH-DSA.
/// </summary>
public bool IsPreHash => m_preHashOid != null;

/// <summary>The textual name of this parameter set (e.g. <c>"SLH-DSA-SHA2-128S"</c>).</summary>
public string Name => m_name;

internal DerObjectIdentifier Oid => m_oid;

internal DerObjectIdentifier PreHashOid => m_preHashOid;

/// <summary>The underlying tree/Winternitz parameter set this entry binds to its OID.</summary>
public SlhDsaParameterSet ParameterSet => m_parameterSet;

/// <inheritdoc/>
public override string ToString() => Name;
}
}
19 changes: 19 additions & 0 deletions crypto/src/crypto/parameters/SlhDsaPrivateKeyParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// 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.
/// </summary>
public sealed class SlhDsaPrivateKeyParameters
: SlhDsaKeyParameters
{
/// <summary>
/// Decode a private key from its concatenated <c>SK.seed || SK.prf || PK.seed || PK.root</c>
/// byte representation. The expected length is <c>4 * n</c> for the chosen parameter set.
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="parameters"/> or
/// <paramref name="encoding"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">If <paramref name="encoding"/> length does not match the
/// parameter set's private-key length.</exception>
public static SlhDsaPrivateKeyParameters FromEncoding(SlhDsaParameters parameters, byte[] encoding)
{
if (parameters == null)
Expand All @@ -33,10 +46,16 @@ internal SlhDsaPrivateKeyParameters(SlhDsaParameters parameters, SK sk, PK pk)
m_pk = pk;
}

/// <summary>
/// Return a fresh copy of the concatenated <c>SK.seed || SK.prf || PK.seed || PK.root</c>
/// encoding.
/// </summary>
public byte[] GetEncoded() => Arrays.ConcatenateAll(m_sk.Seed, m_sk.Prf, m_pk.Seed, m_pk.Root);

/// <summary>Return the public key embedded in this private key.</summary>
public SlhDsaPublicKeyParameters GetPublicKey() => new SlhDsaPublicKeyParameters(Parameters, m_pk);

/// <summary>Return a fresh copy of the public key portion (<c>seed || root</c>).</summary>
public byte[] GetPublicKeyEncoded() => Arrays.Concatenate(m_pk.Seed, m_pk.Root);

internal PK PK => m_pk;
Expand Down
Loading