Symmetric
using Org.BouncyCastle.Crypto.Digests;
using System;
namespace Org.BouncyCastle.Crypto.Kems.MLKem
{
internal abstract class Symmetric
{
internal sealed class ShakeSymmetric : Symmetric
{
private readonly ShakeDigest xof;
private readonly Sha3Digest sha3Digest512;
private readonly Sha3Digest sha3Digest256;
private readonly ShakeDigest shakeDigest;
internal ShakeSymmetric()
: base(164)
{
xof = new ShakeDigest(128);
shakeDigest = new ShakeDigest(256);
sha3Digest256 = new Sha3Digest(256);
sha3Digest512 = new Sha3Digest(512);
}
internal override void Hash_h(ReadOnlySpan<byte> input, Span<byte> output)
{
DoDigest(sha3Digest256, input, output);
}
internal override void Hash_g(ReadOnlySpan<byte> input, Span<byte> output)
{
DoDigest(sha3Digest512, input, output);
}
internal override void Kdf(ReadOnlySpan<byte> input, Span<byte> output)
{
DoDigest(shakeDigest, input, output);
}
internal override void Prf(ReadOnlySpan<byte> seed, byte nonce, Span<byte> output)
{
shakeDigest.BlockUpdate(seed);
shakeDigest.Update(nonce);
shakeDigest.OutputFinal(output);
}
internal unsafe override void XofAbsorb(ReadOnlySpan<byte> seed, byte x, byte y)
{
byte* intPtr = stackalloc byte[2];
*intPtr = x;
intPtr[1] = y;
Span<byte> span = new Span<byte>(intPtr, 2);
xof.Reset();
xof.BlockUpdate(seed);
xof.BlockUpdate(span);
}
internal override void XofSqueezeBlocks(Span<byte> output)
{
xof.Output(output);
}
}
internal readonly int XofBlockBytes;
internal abstract void Hash_h(ReadOnlySpan<byte> input, Span<byte> output);
internal abstract void Hash_g(ReadOnlySpan<byte> input, Span<byte> output);
internal abstract void Kdf(ReadOnlySpan<byte> input, Span<byte> output);
internal abstract void Prf(ReadOnlySpan<byte> seed, byte nonce, Span<byte> output);
internal abstract void XofAbsorb(ReadOnlySpan<byte> seed, byte x, byte y);
internal abstract void XofSqueezeBlocks(Span<byte> output);
internal Symmetric(int xofBlockBytes)
{
XofBlockBytes = xofBlockBytes;
}
internal static void DoDigest(IDigest digest, ReadOnlySpan<byte> input, Span<byte> output)
{
digest.BlockUpdate(input);
digest.DoFinal(output);
}
}
}