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

Sha3Digest

public class Sha3Digest : KeccakDigest
Implementation of SHA-3 based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Digests { public class Sha3Digest : KeccakDigest { public override string AlgorithmName => "SHA3-" + fixedOutputLength.ToString(); internal static void CalculateDigest(ulong[] input, int inputOffset, int inputLengthBits, byte[] output, int outputOffset, int outputLengthBits) { int num = inputLengthBits + 63 >> 6; Check.DataLength(inputOffset > input.Length - num, "input buffer too short"); int len = outputLengthBits + 7 >> 3; Check.OutputLength(output, outputOffset, len, "output buffer too short"); if ((inputLengthBits & 7) != 0) throw new ArgumentOutOfRangeException("inputLengthBits"); switch (outputLengthBits) { default: throw new ArgumentOutOfRangeException("outputLengthBits"); case 224: case 256: case 384: case 512: { int num2 = 1600 - (outputLengthBits << 1); int num3 = num2 >> 6; ulong[] array = new ulong[25]; while (inputLengthBits >= num2) { Nat.XorTo64(num3, input, inputOffset, array, 0); inputOffset += num3; inputLengthBits -= num2; KeccakDigest.KeccakPermutation(array); } int num4 = inputLengthBits >> 6; int num5 = inputLengthBits & 63; Nat.XorTo64(num4, input, inputOffset, array, 0); ulong num6 = 6; if (num5 != 0) { num6 <<= num5; num6 = (ulong)((long)num6 | ((long)input[inputOffset + num4] & ~(-1 << num5))); } array[num4] ^= num6; array[num3 - 1] ^= 9223372036854775808; KeccakDigest.KeccakPermutation(array); int num7 = outputLengthBits >> 6; Pack.UInt64_To_LE(array, 0, num7, output, outputOffset); if ((outputLengthBits & 32) != 0) Pack.UInt32_To_LE((uint)array[num7], output, outputOffset + (num7 << 3)); break; } } } internal unsafe static void CalculateDigest(ReadOnlySpan<ulong> input, int inputLengthBits, Span<byte> output, int outputLengthBits) { int len = inputLengthBits + 63 >> 6; Check.DataLength(input, len, "input buffer too short"); int len2 = outputLengthBits + 7 >> 3; Check.OutputLength(output, len2, "output buffer too short"); if ((inputLengthBits & 7) != 0) throw new ArgumentOutOfRangeException("inputLengthBits"); switch (outputLengthBits) { default: throw new ArgumentOutOfRangeException("outputLengthBits"); case 224: case 256: case 384: case 512: { int num = 1600 - (outputLengthBits << 1); int num2 = num >> 6; Span<ulong> span = new Span<ulong>(stackalloc byte[200], 25); while (inputLengthBits >= num) { Nat.XorTo64(num2, input, span); int num3 = num2; input = input.Slice(num3, input.Length - num3); inputLengthBits -= num; KeccakDigest.KeccakPermutation(span); } int num4 = inputLengthBits >> 6; int num5 = inputLengthBits & 63; Nat.XorTo64(num4, input, span); ulong num6 = 6; if (num5 != 0) { num6 <<= num5; num6 = (ulong)((long)num6 | ((long)input[num4] & ~(-1 << num5))); } span[num4] ^= num6; span[num2 - 1] ^= 9223372036854775808; KeccakDigest.KeccakPermutation(span); int num7 = outputLengthBits >> 6; Pack.UInt64_To_LE(span.Slice(0, num7), output); if ((outputLengthBits & 32) != 0) { int n = (int)span[num7]; int num3 = num7 << 3; Pack.UInt32_To_LE((uint)n, output.Slice(num3, output.Length - num3)); } break; } } } private static int CheckBitLength(int bitLength) { switch (bitLength) { case 224: case 256: case 384: case 512: return bitLength; default: throw new ArgumentException(bitLength.ToString() + " not supported for SHA-3", "bitLength"); } } public Sha3Digest() : this(256) { } public Sha3Digest(int bitLength) : base(CheckBitLength(bitLength)) { } public Sha3Digest(Sha3Digest source) : base(source) { } public override int DoFinal(byte[] output, int outOff) { AbsorbBits(2, 2); return base.DoFinal(output, outOff); } public override int DoFinal(Span<byte> output) { AbsorbBits(2, 2); return base.DoFinal(output); } protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits) { if (partialBits < 0 || partialBits > 7) throw new ArgumentException("must be in the range [0,7]", "partialBits"); int num = (partialByte & ((1 << partialBits) - 1)) | (2 << partialBits); int num2 = partialBits + 2; if (num2 >= 8) { Absorb((byte)num); num2 -= 8; num >>= 8; } return base.DoFinal(output, outOff, (byte)num, num2); } public override IMemoable Copy() { return new Sha3Digest(this); } } }