Skip to content

Commit bbd3a8f

Browse files
Merge branch 'main' into release
2 parents b42d50b + 632271e commit bbd3a8f

File tree

3 files changed

+174
-32
lines changed

3 files changed

+174
-32
lines changed

Directory.Build.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>9.5.0</Version>
4-
<PackageVersion>9.5.0</PackageVersion>
5-
<AssemblyVersion>9.5.0</AssemblyVersion>
3+
<Version>9.5.1</Version>
4+
<PackageVersion>9.5.1</PackageVersion>
5+
<AssemblyVersion>9.5.1</AssemblyVersion>
66
</PropertyGroup>
77
</Project>

OnixLabs.Security.Cryptography.UnitTests/Sha3Tests.cs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
using System.Security.Cryptography;
16+
using OnixLabs.Core;
1617
using Xunit;
1718

1819
namespace OnixLabs.Security.Cryptography.UnitTests;
@@ -598,4 +599,148 @@ public void Sha3Shake256ShouldProduceExpectedResult(char character, int length,
598599
// Then
599600
Assert.Equal(expected, actual);
600601
}
602+
603+
[Theory(DisplayName = "Sha3Hash224 multiple block transforms should produce the expected result")]
604+
[InlineData("abcdef", "", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
605+
[InlineData("abcde", "f", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
606+
[InlineData("abcd", "ef", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
607+
[InlineData("abc", "def", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
608+
[InlineData("ab", "cdef", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
609+
[InlineData("a", "bcdef", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
610+
[InlineData("", "abcdef", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d")]
611+
public void Sha3Hash224MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
612+
{
613+
// Given
614+
using HashAlgorithm algorithm = Sha3.CreateSha3Hash224();
615+
byte[] firstBlockBytes = firstBlock.ToByteArray();
616+
byte[] lastBlockBytes = lastBlock.ToByteArray();
617+
618+
// When
619+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
620+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
621+
string actual = new Hash(algorithm.Hash).ToString();
622+
623+
// Then
624+
Assert.Equal(expected, actual);
625+
}
626+
627+
[Theory(DisplayName = "Sha3Hash256 multiple block transforms should produce the expected result")]
628+
[InlineData("abcdef", "", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
629+
[InlineData("abcde", "f", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
630+
[InlineData("abcd", "ef", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
631+
[InlineData("abc", "def", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
632+
[InlineData("ab", "cdef", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
633+
[InlineData("a", "bcdef", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
634+
[InlineData("", "abcdef", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5")]
635+
public void Sha3Hash256MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
636+
{
637+
// Given
638+
using HashAlgorithm algorithm = Sha3.CreateSha3Hash256();
639+
byte[] firstBlockBytes = firstBlock.ToByteArray();
640+
byte[] lastBlockBytes = lastBlock.ToByteArray();
641+
642+
// When
643+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
644+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
645+
string actual = new Hash(algorithm.Hash).ToString();
646+
647+
// Then
648+
Assert.Equal(expected, actual);
649+
}
650+
651+
[Theory(DisplayName = "Sha3Hash384 multiple block transforms should produce the expected result")]
652+
[InlineData("abcdef", "", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
653+
[InlineData("abcde", "f", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
654+
[InlineData("abcd", "ef", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
655+
[InlineData("abc", "def", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
656+
[InlineData("ab", "cdef", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
657+
[InlineData("a", "bcdef", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
658+
[InlineData("", "abcdef", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805")]
659+
public void Sha3Hash384MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
660+
{
661+
// Given
662+
using HashAlgorithm algorithm = Sha3.CreateSha3Hash384();
663+
byte[] firstBlockBytes = firstBlock.ToByteArray();
664+
byte[] lastBlockBytes = lastBlock.ToByteArray();
665+
666+
// When
667+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
668+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
669+
string actual = new Hash(algorithm.Hash).ToString();
670+
671+
// Then
672+
Assert.Equal(expected, actual);
673+
}
674+
675+
[Theory(DisplayName = "Sha3Hash512 multiple block transforms should produce the expected result")]
676+
[InlineData("abcdef", "", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
677+
[InlineData("abcde", "f", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
678+
[InlineData("abcd", "ef", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
679+
[InlineData("abc", "def", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
680+
[InlineData("ab", "cdef", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
681+
[InlineData("a", "bcdef", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
682+
[InlineData("", "abcdef", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a")]
683+
public void Sha3Hash512MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
684+
{
685+
// Given
686+
using HashAlgorithm algorithm = Sha3.CreateSha3Hash512();
687+
byte[] firstBlockBytes = firstBlock.ToByteArray();
688+
byte[] lastBlockBytes = lastBlock.ToByteArray();
689+
690+
// When
691+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
692+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
693+
string actual = new Hash(algorithm.Hash).ToString();
694+
695+
// Then
696+
Assert.Equal(expected, actual);
697+
}
698+
699+
[Theory(DisplayName = "Sha3Shake128 multiple block transforms should produce the expected result")]
700+
[InlineData("abcdef", "", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
701+
[InlineData("abcde", "f", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
702+
[InlineData("abcd", "ef", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
703+
[InlineData("abc", "def", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
704+
[InlineData("ab", "cdef", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
705+
[InlineData("a", "bcdef", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
706+
[InlineData("", "abcdef", "9428dbf9493c942630c0618d8a0983d518e828a7c0f4a39c2a54e013f64ebc125475308324e864c2617062639263a24bd58c26379342b40bad4a81e6f3e2c32e41bcd52927971ad0374c88f3244b6d229652a454fdc4fa422838eab19aa2fac7ddf457d66122ea674424e534b529e65684b2b4e3404914ad814a53")]
707+
public void Sha3Shake128MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
708+
{
709+
// Given
710+
using HashAlgorithm algorithm = Sha3.CreateSha3Shake128(123);
711+
byte[] firstBlockBytes = firstBlock.ToByteArray();
712+
byte[] lastBlockBytes = lastBlock.ToByteArray();
713+
714+
// When
715+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
716+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
717+
string actual = new Hash(algorithm.Hash).ToString();
718+
719+
// Then
720+
Assert.Equal(expected, actual);
721+
}
722+
723+
[Theory(DisplayName = "Sha3Shake256 multiple block transforms should produce the expected result")]
724+
[InlineData("abcdef", "", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
725+
[InlineData("abcde", "f", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
726+
[InlineData("abcd", "ef", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
727+
[InlineData("abc", "def", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
728+
[InlineData("ab", "cdef", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
729+
[InlineData("a", "bcdef", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
730+
[InlineData("", "abcdef", "81d5e45d095acf3c0decf25bcc63f6ee16c689b909b48040ad91c7c67dfe4e9fec910fa73b44e84541600b5a5736b7b0869c89b1e403e35e550158e09bdb7430a6617cff69c0f10fdaf1035ac62ab6277cd267616c06b9ce4d888543ba5771eecf12df031e9add88f314de262dc1bb0c4aae43c9b5316fea1af11d")]
731+
public void Sha3Shake256MultipleBlockTransformsShouldProduceExpectedResult(string firstBlock, string lastBlock, string expected)
732+
{
733+
// Given
734+
using HashAlgorithm algorithm = Sha3.CreateSha3Shake256(123);
735+
byte[] firstBlockBytes = firstBlock.ToByteArray();
736+
byte[] lastBlockBytes = lastBlock.ToByteArray();
737+
738+
// When
739+
algorithm.TransformBlock(firstBlockBytes, 0, firstBlockBytes.Length, null, 0);
740+
algorithm.TransformFinalBlock(lastBlockBytes, 0, lastBlockBytes.Length);
741+
string actual = new Hash(algorithm.Hash).ToString();
742+
743+
// Then
744+
Assert.Equal(expected, actual);
745+
}
601746
}

OnixLabs.Security.Cryptography/Sha3.cs

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,11 @@ public abstract partial class Sha3 : HashAlgorithm
4242
/// </summary>
4343
private readonly int delimiter;
4444

45-
// /// <summary>
46-
// /// The length of the hash in bits.
47-
// /// </summary>
48-
// private readonly int bitLength;
49-
5045
/// <summary>
5146
/// The state block size.
5247
/// </summary>
5348
private int blockSize;
5449

55-
/// <summary>
56-
/// The state input pointer.
57-
/// </summary>
58-
private int inputPointer;
59-
60-
/// <summary>
61-
/// The state output pointer.
62-
/// </summary>
63-
private int outputPointer;
64-
6550
/// <summary>
6651
/// The permutable sponge state.
6752
/// </summary>
@@ -83,17 +68,17 @@ protected Sha3(int rateBytes, int delimiter, int bitLength)
8368
this.rateBytes = rateBytes;
8469
this.delimiter = delimiter;
8570
HashSizeValue = bitLength;
71+
72+
Initialize();
8673
}
8774

8875
/// <summary>
8976
/// Initializes an implementation of the <see cref="Sha3"/> class.
9077
/// </summary>
91-
public override void Initialize()
78+
public sealed override void Initialize()
9279
{
9380
// ReSharper disable HeapView.ObjectAllocation.Evident
9481
blockSize = default;
95-
inputPointer = default;
96-
outputPointer = default;
9782
state = new ulong[25];
9883
result = new byte[HashSize / 8];
9984
}
@@ -106,23 +91,30 @@ public override void Initialize()
10691
/// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
10792
protected override void HashCore(byte[] array, int ibStart, int cbSize)
10893
{
109-
Initialize();
94+
int offset = ibStart;
11095

11196
while (cbSize > 0)
11297
{
113-
blockSize = Math.Min(cbSize, rateBytes);
98+
// Calculate the number of bytes we can process in this iteration
99+
int bytesToProcess = Math.Min(cbSize, rateBytes - blockSize);
114100

115-
for (int index = ibStart; index < blockSize; index++)
101+
// Absorb the input into the state
102+
for (int i = 0; i < bytesToProcess; i++)
116103
{
117-
byte value = Convert.ToByte(Buffer.GetByte(state, index) ^ array[index + inputPointer]);
118-
Buffer.SetByte(state, index, value);
104+
int stateIndex = blockSize + i;
105+
byte value = Convert.ToByte(Buffer.GetByte(state, stateIndex) ^ array[offset + i]);
106+
Buffer.SetByte(state, stateIndex, value);
119107
}
120108

121-
inputPointer += blockSize;
122-
cbSize -= blockSize;
109+
// Update the block size and offsets
110+
blockSize += bytesToProcess;
111+
offset += bytesToProcess;
112+
cbSize -= bytesToProcess;
123113

114+
// If the block isn't full, continue...
124115
if (blockSize != rateBytes) continue;
125116

117+
// ...otherwise, permute the state
126118
Permute(state);
127119
blockSize = 0;
128120
}
@@ -134,23 +126,28 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize)
134126
/// <returns>The computed hash code.</returns>
135127
protected override byte[] HashFinal()
136128
{
129+
// Apply padding to the current block
137130
byte pad = Convert.ToByte(Buffer.GetByte(state, blockSize) ^ delimiter);
138131
Buffer.SetByte(state, blockSize, pad);
139132

133+
// If the delimiter has its highest bit set, and we're at the last byte of the block, permute the state
140134
if ((delimiter & 0x80) != 0 && blockSize == rateBytes - 1) Permute(state);
141135

136+
// Apply final padding and permute the state
142137
pad = Convert.ToByte(Buffer.GetByte(state, rateBytes - 1) ^ 0x80);
143138
Buffer.SetByte(state, rateBytes - 1, pad);
144139
Permute(state);
145140

146141
int outputBytesLeft = HashSize / 8;
142+
int outputOffset = 0; // Local variable to track the offset in the result array
147143

144+
// Extract the hash output from the state
148145
while (outputBytesLeft > 0)
149146
{
150-
blockSize = Math.Min(outputBytesLeft, rateBytes);
151-
Buffer.BlockCopy(state, 0, result, outputPointer, blockSize);
152-
outputPointer += blockSize;
153-
outputBytesLeft -= blockSize;
147+
int bytesToOutput = Math.Min(outputBytesLeft, rateBytes);
148+
Buffer.BlockCopy(state, 0, result, outputOffset, bytesToOutput);
149+
outputOffset += bytesToOutput;
150+
outputBytesLeft -= bytesToOutput;
154151

155152
if (outputBytesLeft > 0) Permute(state);
156153
}

0 commit comments

Comments
 (0)