<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.0" />

MLDsaSigner

public sealed class MLDsaSigner : ISigner
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium; using Org.BouncyCastle.Security; using System; namespace Org.BouncyCastle.Crypto.Signers { public sealed class MLDsaSigner : ISigner { private readonly ShakeDigest m_msgRepDigest = DilithiumEngine.MsgRepCreateDigest(); private readonly MLDsaParameters m_parameters; private readonly bool m_deterministic; private byte[] m_context; private MLDsaPrivateKeyParameters m_privateKey; private MLDsaPublicKeyParameters m_publicKey; private DilithiumEngine m_engine; public string AlgorithmName => m_parameters.Name; public MLDsaSigner(MLDsaParameters parameters, bool deterministic) { if (parameters == null) throw new ArgumentNullException("parameters"); if (parameters.PreHashOid != null) throw new ArgumentException("cannot be used for HashML-DSA", "parameters"); m_parameters = parameters; m_deterministic = deterministic; } public void Init(bool forSigning, ICipherParameters parameters) { byte[] array = null; ParametersWithContext parametersWithContext = parameters as ParametersWithContext; if (parametersWithContext != null) { if (parametersWithContext.ContextLength > 255) throw new ArgumentOutOfRangeException("context too long", "parameters"); array = parametersWithContext.GetContext(); parameters = parametersWithContext.Parameters; } m_context = (array ?? Array.Empty<byte>()); if (forSigning) { SecureRandom secureRandom = null; ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; if (parametersWithRandom != null) { secureRandom = parametersWithRandom.Random; parameters = parametersWithRandom.Parameters; } m_privateKey = (MLDsaPrivateKeyParameters)parameters; m_publicKey = null; SecureRandom random = m_deterministic ? null : CryptoServicesRegistrar.GetSecureRandom(secureRandom); m_engine = GetEngine(m_privateKey.Parameters, random); } else { m_privateKey = null; m_publicKey = (MLDsaPublicKeyParameters)parameters; m_engine = GetEngine(m_publicKey.Parameters, null); } Reset(); } public void Update(byte input) { m_msgRepDigest.Update(input); } public void BlockUpdate(byte[] input, int inOff, int inLen) { m_msgRepDigest.BlockUpdate(input, inOff, inLen); } public void BlockUpdate(ReadOnlySpan<byte> input) { m_msgRepDigest.BlockUpdate(input); } public int GetMaxSignatureSize() { return m_engine.CryptoBytes; } public byte[] GenerateSignature() { if (m_privateKey == null) throw new InvalidOperationException("MLDsaSigner not initialised for signature generation."); byte[] array = new byte[m_engine.CryptoBytes]; m_engine.MsgRepEndSign(m_msgRepDigest, array, array.Length, m_privateKey.m_rho, m_privateKey.m_k, m_privateKey.m_t0, m_privateKey.m_s1, m_privateKey.m_s2, false); Reset(); return array; } public bool VerifySignature(byte[] signature) { if (m_publicKey == null) throw new InvalidOperationException("MLDsaSigner not initialised for verification"); bool result = m_engine.MsgRepEndVerifyInternal(m_msgRepDigest, signature, signature.Length, m_publicKey.m_rho, m_publicKey.m_t1); Reset(); return result; } public void Reset() { m_msgRepDigest.Reset(); byte[] tr = (m_privateKey != null) ? m_privateKey.m_tr : m_publicKey.GetPublicKeyHash(); m_engine.MsgRepBegin(m_msgRepDigest, tr); m_msgRepDigest.Update(0); m_msgRepDigest.Update((byte)m_context.Length); m_msgRepDigest.BlockUpdate(m_context, 0, m_context.Length); } private DilithiumEngine GetEngine(MLDsaParameters keyParameters, SecureRandom random) { MLDsaParameterSet parameterSet = keyParameters.ParameterSet; if (keyParameters.ParameterSet != m_parameters.ParameterSet) throw new ArgumentException("Mismatching key parameter set", "keyParameters"); return parameterSet.GetEngine(random); } } }