From 9cec06a7de7d1f329e1673dc37f9cce2b71495a0 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 07:15:11 -0700 Subject: [PATCH 01/29] Update csproj for v7 changes Signed-off-by: Xen --- HashifyNet/HashifyNet.csproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HashifyNet/HashifyNet.csproj b/HashifyNet/HashifyNet.csproj index d265ad5..fbaa1f1 100644 --- a/HashifyNet/HashifyNet.csproj +++ b/HashifyNet/HashifyNet.csproj @@ -94,15 +94,19 @@ + + + + Deskasoft International HashifyNET Copyright © Deskasoft International - 6.1.0 + 7.0.0 hashing;hash;algorithms;security;crypto;non-crypto;CLS-compliant;VB.NET;F# True False - False + True none git https://github.com/Deskasoft/HashifyNET @@ -117,5 +121,3 @@ - - From 051e14e37483763b2c62c3e3b5a3041b7d9c24ec Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 17:33:51 +0300 Subject: [PATCH 02/29] Upload v7 Signed-off-by: Xen --- .../Adler32/Adler32_Implementation.cs | 21 +- .../Algorithms/Argon2id/Argon2idConfig.cs | 2 +- .../Argon2id/Argon2id_Implementation.cs | 16 +- .../Algorithms/Argon2id/IArgon2idConfig.cs | 2 +- .../BernsteinHash_Implementation.cs | 15 +- .../ModifiedBernsteinHash_Implementation.cs | 15 +- .../Blake2/Blake2B_Implementation.cs | 57 +- .../Blake3/Blake3_Implementation.cs | 53 +- .../BuzHash/BuzHash_Implementation.cs | 60 +- .../Algorithms/CRC/CRC_Implementation.cs | 54 +- .../CRC/ConfigProfiles/CRCConfigProfileARC.cs | 4 +- .../ConfigProfiles/CRCConfigProfileCRC10.cs | 4 +- .../CityHash/CityHash_Implementation.cs | 285 ++- .../Algorithms/ELF64/ELF64_Implementation.cs | 15 +- HashifyNet/Algorithms/FNV/FNV1Base.cs | 17 +- .../Algorithms/FNV/FNV1_Implementation.cs | 30 +- .../Algorithms/FNV/FNV1a_Implementation.cs | 30 +- .../FarmHashFingerprint_Implementation.cs | 302 ++- .../Algorithms/Gost/Gost_Implementation.cs | 94 +- .../Algorithms/MD5/IMD5Config.cs | 5 + .../Algorithms/MD5/MD5Config.cs | 25 +- .../Algorithms/MD5/MD5_Implementation.cs | 3 +- .../Algorithms/SHA1/ISHA1Config.cs | 5 + .../Algorithms/SHA1/SHA1Config.cs | 25 +- .../Algorithms/SHA1/SHA1_Implementation.cs | 3 +- .../Algorithms/SHA256/ISHA256Config.cs | 5 + .../Algorithms/SHA256/SHA256Config.cs | 25 +- .../SHA256/SHA256_Implementation.cs | 3 +- .../Algorithms/SHA384/ISHA384Config.cs | 5 + .../Algorithms/SHA384/SHA384Config.cs | 25 +- .../SHA384/SHA384_Implementation.cs | 3 +- .../Algorithms/SHA3_256/ISHA3_256Config.cs | 5 + .../Algorithms/SHA3_256/SHA3_256Config.cs | 25 +- .../SHA3_256/SHA3_256_Implementation.cs | 5 +- .../Algorithms/SHA3_384/ISHA3_384Config.cs | 5 + .../Algorithms/SHA3_384/SHA3_384Config.cs | 25 +- .../SHA3_384/SHA3_384_Implementation.cs | 5 +- .../Algorithms/SHA3_512/ISHA3_512Config.cs | 5 + .../Algorithms/SHA3_512/SHA3_512Config.cs | 25 +- .../SHA3_512/SHA3_512_Implementation.cs | 5 +- .../Algorithms/SHA512/ISHA512Config.cs | 5 + .../Algorithms/SHA512/SHA512Config.cs | 25 +- .../SHA512/SHA512_Implementation.cs | 3 +- .../HighwayHash/HighwayHash_Implementation.cs | 29 +- .../Jenkins/JenkinsLookup2_Implementation.cs | 54 +- .../Jenkins/JenkinsLookup3_Implementation.cs | 46 +- .../JenkinsOneAtATime_Implementation.cs | 15 +- .../Keccak/Keccak_Implementation.cs | 24 +- .../MetroHash/MetroHash_Implementation.cs | 80 +- .../MurmurHash/MurmurHash1_Implementation.cs | 25 +- .../MurmurHash/MurmurHash2_Implementation.cs | 58 +- .../MurmurHash/MurmurHash3_Implementation.cs | 79 +- .../Pearson/Pearson_Implementation.cs | 18 +- .../RapidHash/RapidHash_Implementation.cs | 252 +-- .../Algorithms/SM3/SM3_Implementation.cs | 30 +- .../SipHash/SipHash_Implementation.cs | 24 +- .../SpookyHash/SpookyHashV1_Implementation.cs | 57 +- .../SpookyHash/SpookyHashV2_Implementation.cs | 56 +- .../Algorithms/Tiger/Tiger_Implementation.cs | 24 +- .../Whirlpool/Whirlpool_Implementation.cs | 25 +- .../XxHash/XxHash3_Implementation.cs | 15 +- .../XxHash/XxHash_Implementation.cs | 61 +- HashifyNet/Core/BlockTransformerBase.cs | 245 +-- .../Core/DataType/Base32/Base32Helper.cs | 89 + .../Core/DataType/Base32/Base32Variant.cs | 46 + .../Core/DataType/Base58/Base58Helper.cs | 101 + .../Core/DataType/Base58/Base58Variant.cs | 53 + .../Core/DataType/Base85/Base85Helper.cs | 118 ++ .../Core/DataType/Base85/Base85Variant.cs | 64 + HashifyNet/Core/DataType/EncodedHashValue.cs | 5 +- HashifyNet/Core/DataType/HashValue.cs | 233 ++- HashifyNet/Core/DataType/HashValueOptions.cs | 42 + HashifyNet/Core/DataType/IHashValue.cs | 55 +- HashifyNet/Core/DataType/ValueEndianness.cs | 52 + .../Core/Factory/HashFactory.Extensions.cs | 11 +- .../HashAlgorithmWrapperBase.cs | 3 +- .../HashAlgorithmWrapperConfig.cs | 4 +- .../HashAlgorithmWrapper_Implementation.cs | 40 +- .../IHashAlgorithmWrapperConfig.cs | 4 +- ...orithmWrapperPlatformDependentAlgorithm.cs | 2 +- HashifyNet/Core/HashFunctionBase.cs | 89 +- HashifyNet/Core/IBlockTransformer.cs | 8 +- HashifyNet/Core/IHashFunctionBase.cs | 16 +- HashifyNet/Core/IHashFunction_Extensions.cs | 55 +- HashifyNet/Core/StreamableHashFunctionBase.cs | 13 +- HashifyNet/Core/Utilities/Endianness.cs | 1822 ++++++++++++++++- 86 files changed, 3868 insertions(+), 1620 deletions(-) create mode 100644 HashifyNet/Core/DataType/Base32/Base32Helper.cs create mode 100644 HashifyNet/Core/DataType/Base32/Base32Variant.cs create mode 100644 HashifyNet/Core/DataType/Base58/Base58Helper.cs create mode 100644 HashifyNet/Core/DataType/Base58/Base58Variant.cs create mode 100644 HashifyNet/Core/DataType/Base85/Base85Helper.cs create mode 100644 HashifyNet/Core/DataType/Base85/Base85Variant.cs create mode 100644 HashifyNet/Core/DataType/HashValueOptions.cs create mode 100644 HashifyNet/Core/DataType/ValueEndianness.cs diff --git a/HashifyNet/Algorithms/Adler32/Adler32_Implementation.cs b/HashifyNet/Algorithms/Adler32/Adler32_Implementation.cs index 9e6bbbc..84f8999 100644 --- a/HashifyNet/Algorithms/Adler32/Adler32_Implementation.cs +++ b/HashifyNet/Algorithms/Adler32/Adler32_Implementation.cs @@ -94,17 +94,14 @@ protected override void CopyStateTo(BlockTransformer other) other._s2 = _s2; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { uint s1 = _s1; uint s2 = _s2; - var dataArray = data.Array; - var endOffset = data.Offset + data.Count; - - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - s1 = (s1 + dataArray[currentOffset]) % MOD_ADLER; + s1 = (s1 + data[currentOffset]) % MOD_ADLER; s2 = (s2 + s1) % MOD_ADLER; } @@ -112,13 +109,12 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _s2 = s2; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - if (remainder != null && remainder.Length > 0) + if (leftover.Length > 0) { // Process the final remaining bytes - TransformByteGroupsInternal(new ArraySegment(remainder)); + TransformByteGroupsInternal(leftover); } cancellationToken.ThrowIfCancellationRequested(); @@ -126,9 +122,8 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel // Combine s2 and s1 into the final 32-bit checksum uint finalValue = (_s2 << 16) | _s1; - return new HashValue(Endianness.GetBytesBigEndian(finalValue), 32); + return new HashValue(ValueEndianness.BigEndian, Endianness.GetBytesBigEndian(finalValue), 32); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Argon2id/Argon2idConfig.cs b/HashifyNet/Algorithms/Argon2id/Argon2idConfig.cs index 306f8ec..4b983c4 100644 --- a/HashifyNet/Algorithms/Argon2id/Argon2idConfig.cs +++ b/HashifyNet/Algorithms/Argon2id/Argon2idConfig.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International diff --git a/HashifyNet/Algorithms/Argon2id/Argon2id_Implementation.cs b/HashifyNet/Algorithms/Argon2id/Argon2id_Implementation.cs index ae3a696..ca4ec17 100644 --- a/HashifyNet/Algorithms/Argon2id/Argon2id_Implementation.cs +++ b/HashifyNet/Algorithms/Argon2id/Argon2id_Implementation.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -80,20 +80,24 @@ public Argon2id_Implementation(IArgon2idConfig config) } } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { byte[] salt; if (_config.Salt != null) + { salt = _config.Salt; + } else + { salt = Argon2idHelpers.GenerateSalt(); + } return ComputeHashWithSaltInternal(data, salt); } - internal IHashValue ComputeHashWithSaltInternal(ArraySegment data, byte[] salt) + internal IHashValue ComputeHashWithSaltInternal(ReadOnlySpan data, byte[] salt) { - Argon2Config config = Argon2idHelpers.GetArgon2Config(_config, data.Array, salt); + Argon2Config config = Argon2idHelpers.GetArgon2Config(_config, data.ToArray(), salt); string hash = Argon2.Hash(config); byte[] encodedHash = Argon2idSerializer.Serialize(hash); @@ -105,7 +109,7 @@ internal IHashValue ComputeHashWithSaltInternal(ArraySegment data, byte[] try { - return new EncodedHashValue(encodedHash, (i) => Argon2idSerializer.Deserialize((byte[])i), buffer.Buffer, _config.HashSizeInBits); + return new EncodedHashValue(ValueEndianness.NotApplicable, encodedHash, (i) => Argon2idSerializer.Deserialize((byte[])i), buffer.Buffer, _config.HashSizeInBits); } finally { @@ -113,4 +117,4 @@ internal IHashValue ComputeHashWithSaltInternal(ArraySegment data, byte[] } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Argon2id/IArgon2idConfig.cs b/HashifyNet/Algorithms/Argon2id/IArgon2idConfig.cs index 29e9309..f47f103 100644 --- a/HashifyNet/Algorithms/Argon2id/IArgon2idConfig.cs +++ b/HashifyNet/Algorithms/Argon2id/IArgon2idConfig.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International diff --git a/HashifyNet/Algorithms/BernsteinHash/BernsteinHash_Implementation.cs b/HashifyNet/Algorithms/BernsteinHash/BernsteinHash_Implementation.cs index 889a16c..22be008 100644 --- a/HashifyNet/Algorithms/BernsteinHash/BernsteinHash_Implementation.cs +++ b/HashifyNet/Algorithms/BernsteinHash/BernsteinHash_Implementation.cs @@ -73,28 +73,25 @@ protected override void CopyStateTo(BlockTransformer other) other._hashValue = _hashValue; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var endOffset = data.Offset + data.Count; - var tempHashValue = _hashValue; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = (33 * tempHashValue) + dataArray[currentOffset]; + tempHashValue = (33 * tempHashValue) + data[currentOffset]; } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 32); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/BernsteinHash/ModifiedBernsteinHash_Implementation.cs b/HashifyNet/Algorithms/BernsteinHash/ModifiedBernsteinHash_Implementation.cs index cf299a1..8c76a23 100644 --- a/HashifyNet/Algorithms/BernsteinHash/ModifiedBernsteinHash_Implementation.cs +++ b/HashifyNet/Algorithms/BernsteinHash/ModifiedBernsteinHash_Implementation.cs @@ -74,28 +74,25 @@ protected override void CopyStateTo(BlockTransformer other) other._hashValue = _hashValue; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var endOffset = data.Offset + data.Count; - var tempHashValue = _hashValue; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = (33 * tempHashValue) ^ dataArray[currentOffset]; + tempHashValue = (33 * tempHashValue) ^ data[currentOffset]; } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 32); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs b/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs index 47922ad..eb0afec 100644 --- a/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs +++ b/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs @@ -205,11 +205,9 @@ protected override void CopyStateTo(BlockTransformer other) other._delayedInputBuffer = _delayedInputBuffer; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; + var len = data.Length; var tempA = _a; var tempB = _b; @@ -230,31 +228,29 @@ protected override void TransformByteGroupsInternal(ArraySegment data) Compress( ref tempA, ref tempB, ref tempC, ref tempD, ref tempE, ref tempF, ref tempG, ref tempH, tempCounter, - _delayedInputBuffer, 0, + _delayedInputBuffer.AsSpan(), false); } // Delay the last 128 bytes of input { _delayedInputBuffer = new byte[128]; - Array.Copy(dataArray, dataOffset + dataCount - 128, _delayedInputBuffer, 0, 128); - dataCount -= 128; + len -= 128; + data.Slice(len, 128).CopyTo(_delayedInputBuffer.AsSpan()); } // Process all non-delayed input - if (dataCount > 0) + if (len > 0) { - var endOffset = dataOffset + dataCount; - - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 128) + for (var currentOffset = 0; currentOffset < len; currentOffset += 128) { tempCounter += new UInt128(0, 128); Compress( ref tempA, ref tempB, ref tempC, ref tempD, ref tempE, ref tempF, ref tempG, ref tempH, tempCounter, - dataArray, currentOffset, + data.Slice(currentOffset, 128), false); } } @@ -271,11 +267,8 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _counter = tempCounter; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - var remainderCount = (remainder?.Length).GetValueOrDefault(); - var tempA = _a; var tempB = _b; var tempC = _c; @@ -296,27 +289,27 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Compress( ref tempA, ref tempB, ref tempC, ref tempD, ref tempE, ref tempF, ref tempG, ref tempH, tempCounter, - _delayedInputBuffer, 0, - remainderCount == 0); + _delayedInputBuffer.AsSpan(), + leftover.Length == 0); } - if (remainderCount > 0 || _delayedInputBuffer == null) + if (leftover.Length > 0 || _delayedInputBuffer == null) { cancellationToken.ThrowIfCancellationRequested(); - var finalBuffer = new byte[128]; + //var finalBuffer = new byte[128]; - if (remainderCount > 0) - { - Array.Copy(remainder, 0, finalBuffer, 0, remainderCount); - } + //if (leftover > 0) + //{ + // Array.Copy(remainder, 0, finalBuffer, 0, remainderCount); + //} - tempCounter += new UInt128(0, (ulong)remainderCount); + tempCounter += new UInt128(0, (ulong)leftover.Length); Compress( ref tempA, ref tempB, ref tempC, ref tempD, ref tempE, ref tempF, ref tempG, ref tempH, tempCounter, - finalBuffer, 0, + leftover, true); } @@ -331,17 +324,20 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel .Take(_hashSizeInBits / 8) .ToArray(); - return new HashValue(hashValueBytes, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, _hashSizeInBits); } private static void Compress( ref ulong a, ref ulong b, ref ulong c, ref ulong d, ref ulong e, ref ulong f, ref ulong g, ref ulong h, UInt128 counter, - byte[] dataArray, int dataOffset, + ReadOnlySpan data, bool isFinal) { var reinterpretedData = new ulong[16]; - Buffer.BlockCopy(dataArray, dataOffset, reinterpretedData, 0, BlockSizeBytes); + for (int i = 0; i < 16; i++) + { + reinterpretedData[i] = Endianness.ToUInt64LittleEndianSafe(data, i * 8); + } var v = new ulong[16] { a, b, c, d, e, f, g, h, @@ -370,5 +366,4 @@ private static void Compress( } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs b/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs index 065d7b8..f61dd2d 100644 --- a/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs +++ b/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs @@ -250,39 +250,23 @@ private void ResetState() _singleChunkCv = null; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - if (dataArray == null || dataCount == 0) - { - return; - } - - // Base ensures dataCount is a multiple of inputBlockSize (CHUNK_LEN) - int endOffset = dataOffset + dataCount; - for (int currentOffset = dataOffset; currentOffset < endOffset; currentOffset += CHUNK_LEN) + for (int currentOffset = 0; currentOffset < data.Length; currentOffset += CHUNK_LEN) { - EmitFullChunk(dataArray, currentOffset); + EmitFullChunk(data.Slice(currentOffset, CHUNK_LEN)); } } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); - - var remainder = FinalizeInputBuffer; - int remainderCount = (remainder?.Length).GetValueOrDefault(); - byte[] result; int outLen = _hashSizeInBits / 8; // Case A: no full chunks were emitted if (_chunkCvs.Count == 0) { - int totalLen = remainderCount; + int totalLen = leftover.Length; int blocks = (totalLen + BLOCK_LEN - 1) / BLOCK_LEN; if (totalLen == 0) { @@ -310,7 +294,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel flags |= CHUNK_END; } - var m = LoadBlockWords(remainder ?? Array.Empty(), blockOffset, blockLen); + var m = LoadBlockWords(leftover, blockOffset, blockLen); if (b == blocks - 1) { @@ -329,11 +313,11 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel FillXof(cv, lastBlockWords ?? new uint[16], chunkCounter, lastBlockLen, lastFlags, result); ResetState(); - return new HashValue(result, _hashSizeInBits); + return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); } // Case B: exactly one full chunk emitted and no remainder - if (_chunkCvs.Count == 1 && remainderCount == 0) + if (_chunkCvs.Count == 1 && leftover.Length == 0) { if (_singleChunkCv == null || _singleChunkLastBlockWords == null) { @@ -344,15 +328,15 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel FillXof(_singleChunkCv, _singleChunkLastBlockWords, _singleChunkCounter, _singleChunkLastBlockLen, _singleChunkLastBlockFlags, result); ResetState(); - return new HashValue(result, _hashSizeInBits); + return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); } // Case C: true multi-chunk (>=2), or 1 chunk + tail (will become >=2 after tail) var cvList = new List(_chunkCvs); - if (remainderCount > 0) + if (leftover.Length > 0) { - var lastCv = CompressChunkToCv(_currentIV, remainder, 0, remainderCount, _chunkCounter); + var lastCv = CompressChunkToCv(_currentIV, leftover, 0, leftover.Length, _chunkCounter); cvList.Add(lastCv); _chunkCounter++; } @@ -369,17 +353,17 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel FillXof(_currentIV, rootMessageBlock, 0UL, BLOCK_LEN, PARENT, result); ResetState(); - return new HashValue(result, _hashSizeInBits); + return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); } - private void EmitFullChunk(byte[] src, int offset) + private void EmitFullChunk(ReadOnlySpan src) { - var cv = CompressChunkToCv(_currentIV, src, offset, CHUNK_LEN, _chunkCounter); + var cv = CompressChunkToCv(_currentIV, src, 0, CHUNK_LEN, _chunkCounter); _chunkCvs.Add(cv); if (_chunkCvs.Count == 1) { - _singleChunkLastBlockWords = LoadBlockWords(src, offset + CHUNK_LEN - BLOCK_LEN, BLOCK_LEN); + _singleChunkLastBlockWords = LoadBlockWords(src, CHUNK_LEN - BLOCK_LEN, BLOCK_LEN); _singleChunkLastBlockLen = BLOCK_LEN; _singleChunkLastBlockFlags = CHUNK_END; _singleChunkCounter = _chunkCounter; @@ -479,7 +463,7 @@ private static uint[] Compress(uint[] cv, uint[] m, ulong counter, uint blockLen return outWords; } - private static uint[] LoadBlockWords(byte[] input, int offset, int blockLen) + private static uint[] LoadBlockWords(ReadOnlySpan input, int offset, int blockLen) { uint[] m = new uint[16]; int i = 0, pos = offset; @@ -518,7 +502,7 @@ private static void WordsToBytes(uint[] words, Span outBytes) } // Derive chunk CV: iterate blocks, updating CV for every block; return final CV. - private static uint[] CompressChunkToCv(uint[] key, byte[] input, int offset, int length, ulong chunkCounter) + private static uint[] CompressChunkToCv(uint[] key, ReadOnlySpan input, int offset, int length, ulong chunkCounter) { uint[] cv = (uint[])key.Clone(); int blocks = (length + BLOCK_LEN - 1) / BLOCK_LEN; @@ -621,5 +605,4 @@ private static void FillXof(uint[] inputCv, uint[] messageBlock, ulong counter, } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/BuzHash/BuzHash_Implementation.cs b/HashifyNet/Algorithms/BuzHash/BuzHash_Implementation.cs index 2b1df1b..35edb98 100644 --- a/HashifyNet/Algorithms/BuzHash/BuzHash_Implementation.cs +++ b/HashifyNet/Algorithms/BuzHash/BuzHash_Implementation.cs @@ -131,24 +131,22 @@ protected override void CopyStateTo(BlockTransformer_8Bit other) other._hashValue = _hashValue; other._rtab = _rtab; } - protected override void TransformByteGroupsInternal(ArraySegment data) - { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; + protected override void TransformByteGroupsInternal(ReadOnlySpan data) + { var tempHashValue = _hashValue; var tempRtab = _rtab; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = (byte)(CShift(tempHashValue, 1, _shiftDirection) ^ (byte)tempRtab[dataArray[currentOffset]]); + tempHashValue = (byte)(CShift(tempHashValue, 1, _shiftDirection) ^ (byte)tempRtab[data[currentOffset]]); } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(new byte[] { _hashValue }, 8); + + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.NotApplicable, new byte[] { _hashValue }, 8); } private class BlockTransformer_16Bit @@ -180,24 +178,20 @@ protected override void CopyStateTo(BlockTransformer_16Bit other) other._rtab = _rtab; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempRtab = _rtab; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = (ushort)(CShift(tempHashValue, 1, _shiftDirection) ^ (ushort)tempRtab[dataArray[currentOffset]]); + tempHashValue = (ushort)(CShift(tempHashValue, 1, _shiftDirection) ^ (ushort)tempRtab[data[currentOffset]]); } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(Endianness.GetBytesLittleEndian(_hashValue), 16); + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 16); } private class BlockTransformer_32Bit : BlockTransformerBase @@ -228,25 +222,21 @@ protected override void CopyStateTo(BlockTransformer_32Bit other) other._rtab = _rtab; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempRtab = _rtab; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = CShift(tempHashValue, 1, _shiftDirection) ^ (uint)tempRtab[dataArray[currentOffset]]; + tempHashValue = CShift(tempHashValue, 1, _shiftDirection) ^ (uint)tempRtab[data[currentOffset]]; } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(Endianness.GetBytesLittleEndian(_hashValue), 32); + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 32); } private class BlockTransformer_64Bit @@ -278,24 +268,20 @@ protected override void CopyStateTo(BlockTransformer_64Bit other) other._rtab = _rtab; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempRtab = _rtab; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue = CShift(tempHashValue, 1, _shiftDirection) ^ tempRtab[dataArray[currentOffset]]; + tempHashValue = CShift(tempHashValue, 1, _shiftDirection) ^ tempRtab[data[currentOffset]]; } _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(Endianness.GetBytesLittleEndian(_hashValue), 64); + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 64); } #region CShift @@ -422,4 +408,4 @@ private static ulong RotateRight(ulong operand, int shiftCount) #endregion } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/CRC/CRC_Implementation.cs b/HashifyNet/Algorithms/CRC/CRC_Implementation.cs index 7bec9ec..53a9733 100644 --- a/HashifyNet/Algorithms/CRC/CRC_Implementation.cs +++ b/HashifyNet/Algorithms/CRC/CRC_Implementation.cs @@ -137,12 +137,8 @@ protected override void CopyStateTo(BlockTransformer other) other._hashValue = _hashValue; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var endOffset = dataOffset + data.Count; - var tempHashValue = _hashValue; var tempHashSizeInBits = _hashSizeInBits; @@ -150,18 +146,18 @@ protected override void TransformByteGroupsInternal(ArraySegment data) var tempCrcTable = _crcTable; var tempMostSignificantShift = _mostSignificantShift; - for (var currentOffset = dataOffset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { if (tempHashSizeInBits >= 8) { // Process per byte, treating hash differently based on input endianness if (tempReflectIn) { - tempHashValue = (tempHashValue >> 8) ^ tempCrcTable[(byte)tempHashValue ^ dataArray[currentOffset]]; + tempHashValue = (tempHashValue >> 8) ^ tempCrcTable[(byte)tempHashValue ^ data[currentOffset]]; } else { - tempHashValue = (tempHashValue << 8) ^ tempCrcTable[((byte)(tempHashValue >> tempMostSignificantShift)) ^ dataArray[currentOffset]]; + tempHashValue = (tempHashValue << 8) ^ tempCrcTable[((byte)(tempHashValue >> tempMostSignificantShift)) ^ data[currentOffset]]; } } else @@ -171,11 +167,11 @@ protected override void TransformByteGroupsInternal(ArraySegment data) { if (tempReflectIn) { - tempHashValue = (tempHashValue >> 1) ^ tempCrcTable[(byte)(tempHashValue & 1) ^ ((byte)(dataArray[currentOffset] >> currentBit) & 1)]; + tempHashValue = (tempHashValue >> 1) ^ tempCrcTable[(byte)(tempHashValue & 1) ^ ((byte)(data[currentOffset] >> currentBit) & 1)]; } else { - tempHashValue = (tempHashValue << 1) ^ tempCrcTable[(byte)((tempHashValue >> tempMostSignificantShift) & 1) ^ ((byte)(dataArray[currentOffset] >> (7 - currentBit)) & 1)]; + tempHashValue = (tempHashValue << 1) ^ tempCrcTable[(byte)((tempHashValue >> tempMostSignificantShift) & 1) ^ ((byte)(data[currentOffset] >> (7 - currentBit)) & 1)]; } } } @@ -184,11 +180,9 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var finalHashValue = _hashValue; - - // Account for mixed-endianness if (_reflectIn ^ _reflectOut) { finalHashValue = ReflectBits(finalHashValue, _hashSizeInBits); @@ -196,8 +190,11 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel finalHashValue ^= _xOrOut; + ValueEndianness resultEndianness = _reflectOut ? ValueEndianness.LittleEndian : ValueEndianness.BigEndian; + return new HashValue( - ToBytes(finalHashValue, _hashSizeInBits), + resultEndianness, + ToBytes(finalHashValue, _hashSizeInBits, resultEndianness), _hashSizeInBits); } @@ -274,22 +271,33 @@ private static IReadOnlyList GetDataDivisionTableInternal((int, ulong, bo return crcTable; } - private static byte[] ToBytes(ulong value, int bitLength) + private static byte[] ToBytes(ulong value, int bitLength, ValueEndianness endianness) { value &= ulong.MaxValue >> (64 - bitLength); - var valueBytes = new byte[(bitLength + 7) / 8]; + var byteCount = (bitLength + 7) / 8; + var valueBytes = new byte[byteCount]; - for (int x = 0; x < valueBytes.Length; ++x) + if (endianness == ValueEndianness.LittleEndian) { - valueBytes[x] = (byte)value; - value >>= 8; + for (int x = 0; x < valueBytes.Length; ++x) + { + valueBytes[x] = (byte)value; + value >>= 8; + } + } + else // BigEndian + { + for (int x = valueBytes.Length - 1; x >= 0; --x) + { + valueBytes[x] = (byte)value; + value >>= 8; + } } - if (valueBytes.Length != (bitLength + 7) / 8) + if (bitLength % 8 != 0) { - byte[] result = ArrayHelpers.CoerceToArray(valueBytes, bitLength); - return result; + return valueBytes; } return valueBytes; @@ -312,4 +320,4 @@ private static ulong ReflectBits(ulong value, int bitLength) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileARC.cs b/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileARC.cs index 25e831d..44e2e60 100644 --- a/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileARC.cs +++ b/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileARC.cs @@ -44,10 +44,10 @@ public CRCConfigProfileARC() { HashSizeInBits = 16; Polynomial = 0x8005; - InitialValue = unchecked((long)0x0); + InitialValue = unchecked(0x0); ReflectIn = true; ReflectOut = true; - XOrOut = unchecked((long)0x0); + XOrOut = unchecked(0x0); } } } diff --git a/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileCRC10.cs b/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileCRC10.cs index af65277..8827b78 100644 --- a/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileCRC10.cs +++ b/HashifyNet/Algorithms/CRC/ConfigProfiles/CRCConfigProfileCRC10.cs @@ -44,10 +44,10 @@ public CRCConfigProfileCRC10() { HashSizeInBits = 10; Polynomial = 0x233; - InitialValue = unchecked((long)0x0); + InitialValue = unchecked(0x0); ReflectIn = false; ReflectOut = false; - XOrOut = unchecked((long)0x0); + XOrOut = unchecked(0x0); } } } diff --git a/HashifyNet/Algorithms/CityHash/CityHash_Implementation.cs b/HashifyNet/Algorithms/CityHash/CityHash_Implementation.cs index 4125272..9164ec2 100644 --- a/HashifyNet/Algorithms/CityHash/CityHash_Implementation.cs +++ b/HashifyNet/Algorithms/CityHash/CityHash_Implementation.cs @@ -78,7 +78,7 @@ public CityHash_Implementation(ICityHashConfig config) throw new ArgumentOutOfRangeException($"{nameof(config)}.{nameof(config.HashSizeInBits)}", _config.HashSizeInBits, $"{nameof(config)}.{nameof(config.HashSizeInBits)} must be contained within CityHash.ValidHashSizes."); } } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { switch (_config.HashSizeInBits) { @@ -98,11 +98,11 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance #region ComputeHash32 - private IHashValue ComputeHash32(ArraySegment data, CancellationToken cancellationToken) + private IHashValue ComputeHash32(ReadOnlySpan data, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var dataCount = data.Count; + var dataCount = data.Length; uint hashValue; @@ -127,36 +127,29 @@ private IHashValue ComputeHash32(ArraySegment data, CancellationToken canc } return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 32); } - private uint Hash32Len0to4(ArraySegment data) + private uint Hash32Len0to4(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; - uint b = 0; uint c = 9; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 1) + for (var currentOffset = 0; currentOffset < data.Length; currentOffset += 1) { - b = (b * C1) + dataArray[currentOffset]; + b = (b * C1) + data[currentOffset]; c ^= b; } - return Mix(Mur(b, Mur((uint)dataCount, c))); + return Mix(Mur(b, Mur((uint)data.Length, c))); } - private uint Hash32Len5to12(ArraySegment data) + private uint Hash32Len5to12(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; + var dataCount = data.Length; uint a = (uint)dataCount; uint b = (uint)dataCount * 5; @@ -164,52 +157,41 @@ private uint Hash32Len5to12(ArraySegment data) uint c = 9; uint d = b; - a += Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - b += Endianness.ToUInt32LittleEndian(dataArray, dataOffset + dataCount - 4); - c += Endianness.ToUInt32LittleEndian(dataArray, dataOffset + ((dataCount >> 1) & 4)); + a += Endianness.ToUInt32LittleEndian(data, 0); + b += Endianness.ToUInt32LittleEndian(data, dataCount - 4); + c += Endianness.ToUInt32LittleEndian(data, (dataCount >> 1) & 4); return Mix(Mur(c, Mur(b, Mur(a, d)))); } - private uint Hash32Len13to24(ArraySegment data) + private uint Hash32Len13to24(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - - uint a = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + (dataCount >> 1) - 4); - uint b = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + 4); - uint c = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + dataCount - 8); - uint d = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + (dataCount >> 1)); - uint e = Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - uint f = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + dataCount - 4); + var dataCount = data.Length; + uint a = Endianness.ToUInt32LittleEndian(data, (dataCount >> 1) - 4); + uint b = Endianness.ToUInt32LittleEndian(data, 4); + uint c = Endianness.ToUInt32LittleEndian(data, dataCount - 8); + uint d = Endianness.ToUInt32LittleEndian(data, dataCount >> 1); + uint e = Endianness.ToUInt32LittleEndian(data, 0); + uint f = Endianness.ToUInt32LittleEndian(data, dataCount - 4); uint h = (uint)dataCount; return Mix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); } - private uint Hash32Len25Plus(ArraySegment data, CancellationToken cancellationToken) + private uint Hash32Len25Plus(ReadOnlySpan data, CancellationToken cancellationToken) { - - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; - - cancellationToken.ThrowIfCancellationRequested(); + var dataCount = data.Length; // dataCount > 24 uint h = (uint)dataCount; uint g = (uint)dataCount * C1; uint f = g; { - uint a0 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4) * C1, 17) * C2; - uint a1 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 8) * C1, 17) * C2; - uint a2 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 16) * C1, 17) * C2; - uint a3 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 12) * C1, 17) * C2; - uint a4 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 20) * C1, 17) * C2; + uint a0 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 4) * C1, 17) * C2; + uint a1 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 8) * C1, 17) * C2; + uint a2 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 16) * C1, 17) * C2; + uint a3 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 12) * C1, 17) * C2; + uint a4 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 20) * C1, 17) * C2; h ^= a0; h = RotateRight(h, 19); @@ -232,17 +214,17 @@ private uint Hash32Len25Plus(ArraySegment data, CancellationToken cancella var groupsToProcess = (dataCount - 1) / 20; - var groupEndOffset = dataOffset + (groupsToProcess * 20); + var groupEndOffset = groupsToProcess * 20; - for (int groupOffset = dataOffset; groupOffset < groupEndOffset; groupOffset += 20) + for (int groupOffset = 0; groupOffset < groupEndOffset; groupOffset += 20) { cancellationToken.ThrowIfCancellationRequested(); - uint a0 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, groupOffset + 0) * C1, 17) * C2; - uint a1 = Endianness.ToUInt32LittleEndian(dataArray, groupOffset + 4); - uint a2 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, groupOffset + 8) * C1, 17) * C2; - uint a3 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, groupOffset + 12) * C1, 17) * C2; - uint a4 = Endianness.ToUInt32LittleEndian(dataArray, groupOffset + 16); + uint a0 = RotateRight(Endianness.ToUInt32LittleEndian(data, groupOffset + 0) * C1, 17) * C2; + uint a1 = Endianness.ToUInt32LittleEndian(data, groupOffset + 4); + uint a2 = RotateRight(Endianness.ToUInt32LittleEndian(data, groupOffset + 8) * C1, 17) * C2; + uint a3 = RotateRight(Endianness.ToUInt32LittleEndian(data, groupOffset + 12) * C1, 17) * C2; + uint a4 = Endianness.ToUInt32LittleEndian(data, groupOffset + 16); h ^= a0; h = RotateRight(h, 18); @@ -292,11 +274,9 @@ private uint Hash32Len25Plus(ArraySegment data, CancellationToken cancella #endregion #region ComputeHash64 - private IHashValue ComputeHash64(ArraySegment data, CancellationToken cancellationToken) + private IHashValue ComputeHash64(ReadOnlySpan data, CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); - - var dataCount = data.Count; + var dataCount = data.Length; ulong hashValue; if (dataCount > 64) @@ -320,9 +300,11 @@ private IHashValue ComputeHash64(ArraySegment data, CancellationToken canc } return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 64); } + private ulong Hash64Len16(ulong u, ulong v) { return Hash128to64( @@ -341,19 +323,15 @@ private static ulong Hash64Len16(ulong u, ulong v, ulong mul) return b; } - private ulong Hash64Len0to16(ArraySegment data) + private ulong Hash64Len0to16(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; if (dataCount >= 8) { ulong mul = K2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) + K2; - ulong b = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8); + ulong a = Endianness.ToUInt64LittleEndian(data, 0) + K2; + ulong b = Endianness.ToUInt64LittleEndian(data, dataCount - 8); ulong c = (RotateRight(b, 37) * mul) + a; ulong d = (RotateRight(a, 25) + b) * mul; @@ -363,15 +341,15 @@ private ulong Hash64Len0to16(ArraySegment data) if (dataCount >= 4) { ulong mul = K2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - return Hash64Len16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4), mul); + ulong a = Endianness.ToUInt32LittleEndian(data, 0); + return Hash64Len16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(data, dataCount - 4), mul); } if (dataCount > 0) { - byte a = dataArray[dataOffset]; - byte b = dataArray[dataOffset + (dataCount >> 1)]; - byte c = dataArray[endOffset - 1]; + byte a = data[0]; + byte b = data[dataCount >> 1]; + byte c = data[dataCount - 1]; uint y = a + ((uint)b << 8); uint z = (uint)dataCount + ((uint)c << 2); @@ -384,19 +362,15 @@ private ulong Hash64Len0to16(ArraySegment data) // This probably works well for 16-byte strings as well, but it may be overkill // in that case. - private static ulong Hash64Len17to32(ArraySegment data) + private static ulong Hash64Len17to32(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; ulong mul = K2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) * K1; - ulong b = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8); - ulong c = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8) * mul; - ulong d = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16) * K2; + ulong a = Endianness.ToUInt64LittleEndian(data, 0) * K1; + ulong b = Endianness.ToUInt64LittleEndian(data, 8); + ulong c = Endianness.ToUInt64LittleEndian(data, dataCount - 8) * mul; + ulong d = Endianness.ToUInt64LittleEndian(data, dataCount - 16) * K2; return Hash64Len16( RotateRight(a + b, 43) + @@ -423,7 +397,7 @@ private UInt128 WeakHashLen32WithSeeds( } // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. - private UInt128 WeakHashLen32WithSeeds(byte[] data, int startIndex, ulong a, ulong b) + private UInt128 WeakHashLen32WithSeeds(ReadOnlySpan data, int startIndex, ulong a, ulong b) { return WeakHashLen32WithSeeds( Endianness.ToUInt64LittleEndian(data, startIndex), @@ -435,23 +409,19 @@ private UInt128 WeakHashLen32WithSeeds(byte[] data, int startIndex, ulong a, ulo } // Return an 8-byte hash for 33 to 64 bytes. - private ulong Hash64Len33to64(ArraySegment data) + private ulong Hash64Len33to64(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; ulong mul = K2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) * K2; - ulong b = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8); - ulong c = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 24); - ulong d = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 32); - ulong e = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 16) * K2; - ulong f = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 24) * 9; - ulong g = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8); - ulong h = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16) * mul; + ulong a = Endianness.ToUInt64LittleEndian(data, 0) * K2; + ulong b = Endianness.ToUInt64LittleEndian(data, 8); + ulong c = Endianness.ToUInt64LittleEndian(data, dataCount - 24); + ulong d = Endianness.ToUInt64LittleEndian(data, dataCount - 32); + ulong e = Endianness.ToUInt64LittleEndian(data, 16) * K2; + ulong f = Endianness.ToUInt64LittleEndian(data, 24) * 9; + ulong g = Endianness.ToUInt64LittleEndian(data, dataCount - 8); + ulong h = Endianness.ToUInt64LittleEndian(data, dataCount - 16) * mul; ulong u = RotateRight(a + g, 43) + ((RotateRight(b, 30) + c) * 9); ulong v = ((a + g) ^ d) + f + 1; @@ -465,41 +435,37 @@ private ulong Hash64Len33to64(ArraySegment data) return b + x; } - private ulong Hash64Len65Plus(ArraySegment data, CancellationToken cancellationToken) + private ulong Hash64Len65Plus(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; // For strings over 64 bytes we hash the end first, and then as we // loop we keep 56 bytes of state: v, w, x, y, and z. - ulong x = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 40); - ulong y = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16) + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 56); + ulong x = Endianness.ToUInt64LittleEndian(data, dataCount - 40); + ulong y = Endianness.ToUInt64LittleEndian(data, dataCount - 16) + Endianness.ToUInt64LittleEndian(data, dataCount - 56); ulong z = Hash64Len16( - Endianness.ToUInt64LittleEndian(dataArray, endOffset - 48) + (ulong)dataCount, - Endianness.ToUInt64LittleEndian(dataArray, endOffset - 24)); + Endianness.ToUInt64LittleEndian(data, dataCount - 48) + (ulong)dataCount, + Endianness.ToUInt64LittleEndian(data, dataCount - 24)); - UInt128 v = WeakHashLen32WithSeeds(dataArray, endOffset - 64, (ulong)dataCount, z); - UInt128 w = WeakHashLen32WithSeeds(dataArray, endOffset - 32, y + K1, x); + UInt128 v = WeakHashLen32WithSeeds(data, dataCount - 64, (ulong)dataCount, z); + UInt128 w = WeakHashLen32WithSeeds(data, dataCount - 32, y + K1, x); - x = (x * K1) + Endianness.ToUInt64LittleEndian(dataArray, 0); + x = (x * K1) + Endianness.ToUInt64LittleEndian(data, 0); // For each 64-byte chunk - var groupEndOffset = dataOffset + ((dataCount - 1) - ((dataCount - 1) % 64)); + var groupEndOffset = dataCount - 1 - ((dataCount - 1) % 64); - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 64) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 64) { cancellationToken.ThrowIfCancellationRequested(); - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 8), 37) * K1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 48), 42) * K1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, currentOffset + 8), 37) * K1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, currentOffset + 48), 42) * K1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 40); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, currentOffset + 40); z = RotateRight(z + w.GetLower(), 33) * K1; - v = WeakHashLen32WithSeeds(dataArray, currentOffset, v.GetUpper() * K1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, currentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 16)); + v = WeakHashLen32WithSeeds(data, currentOffset, v.GetUpper() * K1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, currentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, currentOffset + 16)); ulong temp = x; x = z; @@ -514,22 +480,19 @@ private ulong Hash64Len65Plus(ArraySegment data, CancellationToken cancell #region ComputeHash128 - private IHashValue ComputeHash128(ArraySegment data, CancellationToken cancellationToken) + private IHashValue ComputeHash128(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataCount = data.Count; + var dataCount = data.Length; UInt128 hashValue; if (dataCount >= 16) { - var dataArray = data.Array; - var dataOffset = data.Offset; - hashValue = CityHash128WithSeed( - new ArraySegment(dataArray, dataOffset + 16, dataCount - 16), + data.Slice(16, dataCount - 16), new UInt128( - Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8) + K0, - Endianness.ToUInt64LittleEndian(dataArray, dataOffset)), + Endianness.ToUInt64LittleEndian(data, 8) + K0, + Endianness.ToUInt64LittleEndian(data, 0)), cancellationToken); } @@ -541,37 +504,29 @@ private IHashValue ComputeHash128(ArraySegment data, CancellationToken can var hashValueBytes = Endianness.GetBytesLittleEndian(hashValue.GetLower()) .Concat(Endianness.GetBytesLittleEndian(hashValue.GetUpper())); - return new HashValue(hashValueBytes, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, 128); } - private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, CancellationToken cancellationToken) + private UInt128 CityHash128WithSeed(ReadOnlySpan data, UInt128 seed, CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); - - var dataCount = data.Count; - + var dataCount = data.Length; if (dataCount < 128) { return CityMurmur(data, seed); } - var dataArray = data.Array; - var dataOffset = data.Offset; - - var endOffset = dataOffset + dataCount; - // We expect len >= 128 to be the common case. Keep 56 bytes of state: // v, w, x, y, and z. UInt128 v; { - var vLow = (RotateRight(seed.GetUpper() ^ K1, 49) * K1) + Endianness.ToUInt64LittleEndian(dataArray, dataOffset); + var vLow = (RotateRight(seed.GetUpper() ^ K1, 49) * K1) + Endianness.ToUInt64LittleEndian(data, 0); v = new UInt128( - (RotateRight(vLow, 42) * K1) + Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8), + (RotateRight(vLow, 42) * K1) + Endianness.ToUInt64LittleEndian(data, 8), vLow); } UInt128 w = new UInt128( - RotateRight(seed.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 88), 53) * K1, + RotateRight(seed.GetLower() + Endianness.ToUInt64LittleEndian(data, 88), 53) * K1, (RotateRight(seed.GetUpper() + ((ulong)dataCount * K1), 35) * K1) + seed.GetLower()); ulong x = seed.GetLower(); @@ -581,19 +536,19 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance // This is the same inner loop as CityHash64() int lastGroupEndOffset; { - var groupEndOffset = dataOffset + (dataCount - (dataCount % 128)); + var groupEndOffset = dataCount - (dataCount % 128); - for (var groupCurrentOffset = dataOffset; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 128) + for (var groupCurrentOffset = 0; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 128) { cancellationToken.ThrowIfCancellationRequested(); - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 8), 37) * K1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 48), 42) * K1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 8), 37) * K1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 48), 42) * K1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 40); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 40); z = RotateRight(z + w.GetLower(), 33) * K1; - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset, v.GetUpper() * K1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 16)); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset, v.GetUpper() * K1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, groupCurrentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 16)); { ulong temp = z; @@ -601,13 +556,13 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance x = temp; } - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 72), 37) * K1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 112), 42) * K1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 72), 37) * K1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 112), 42) * K1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 104); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 104); z = RotateRight(z + w.GetLower(), 33) * K1; - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 64, v.GetUpper() * K1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 96, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 80)); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset + 64, v.GetUpper() * K1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, groupCurrentOffset + 96, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 80)); { ulong temp = z; @@ -631,16 +586,16 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance { var groupEndOffset = lastGroupEndOffset - 32; - for (var groupCurrentOffset = endOffset - 32; groupCurrentOffset > groupEndOffset; groupCurrentOffset -= 32) + for (var groupCurrentOffset = dataCount - 32; groupCurrentOffset > groupEndOffset; groupCurrentOffset -= 32) { cancellationToken.ThrowIfCancellationRequested(); y = (RotateRight(x + y, 42) * K0) + v.GetUpper(); - w = new UInt128(w.GetUpper(), w.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 16)); + w = new UInt128(w.GetUpper(), w.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 16)); x = (x * K0) + w.GetLower(); - z += w.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset); + z += w.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset); w = new UInt128(w.GetUpper() + v.GetLower(), w.GetLower()); - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset, v.GetLower() + z, v.GetUpper()); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset, v.GetLower() + z, v.GetUpper()); v = new UInt128(v.GetUpper(), v.GetLower() * K0); } } @@ -659,13 +614,9 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings // of any length representable in signed long. Based on City and Murmur. - private UInt128 CityMurmur(ArraySegment data, UInt128 seed) + private UInt128 CityMurmur(ReadOnlySpan data, UInt128 seed) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; ulong a = seed.GetLower(); ulong b = seed.GetUpper(); @@ -677,24 +628,24 @@ private UInt128 CityMurmur(ArraySegment data, UInt128 seed) // len <= 16 a = Mix(a * K1) * K1; c = (b * K1) + Hash64Len0to16(data); - d = Mix(a + (dataCount >= 8 ? Endianness.ToUInt64LittleEndian(dataArray, dataOffset) : c)); + d = Mix(a + (dataCount >= 8 ? Endianness.ToUInt64LittleEndian(data, 0) : c)); } else { // len > 16 - c = Hash64Len16(Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8) + K1, a); - d = Hash64Len16(b + (ulong)dataCount, c + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16)); + c = Hash64Len16(Endianness.ToUInt64LittleEndian(data, dataCount - 8) + K1, a); + d = Hash64Len16(b + (ulong)dataCount, c + Endianness.ToUInt64LittleEndian(data, dataCount - 16)); a += d; - var groupEndOffset = dataOffset + dataCount - 16; + var groupEndOffset = dataCount - 16; - for (var groupCurrentOffset = dataOffset; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 16) + for (var groupCurrentOffset = 0; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 16) { - a ^= Mix(Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset) * K1) * K1; + a ^= Mix(Endianness.ToUInt64LittleEndian(data, groupCurrentOffset) * K1) * K1; a *= K1; b ^= a; - c ^= Mix(Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 8) * K1) * K1; + c ^= Mix(Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 8) * K1) * K1; c *= K1; d ^= c; } @@ -796,4 +747,4 @@ private static ulong ReverseByteOrder(ulong operand) } #endregion } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/ELF64/ELF64_Implementation.cs b/HashifyNet/Algorithms/ELF64/ELF64_Implementation.cs index b701752..9282b4f 100644 --- a/HashifyNet/Algorithms/ELF64/ELF64_Implementation.cs +++ b/HashifyNet/Algorithms/ELF64/ELF64_Implementation.cs @@ -72,17 +72,14 @@ protected override void CopyStateTo(BlockTransformer other) other._hashValue = _hashValue; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var endOffset = data.Offset + data.Count; - var tempHashValue = _hashValue; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { tempHashValue <<= 4; - tempHashValue += dataArray[currentOffset]; + tempHashValue += data[currentOffset]; var tmp = tempHashValue & 0xF0000000; @@ -96,13 +93,13 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 32); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/FNV/FNV1Base.cs b/HashifyNet/Algorithms/FNV/FNV1Base.cs index 8f4cee3..abe09b9 100644 --- a/HashifyNet/Algorithms/FNV/FNV1Base.cs +++ b/HashifyNet/Algorithms/FNV/FNV1Base.cs @@ -92,14 +92,16 @@ public BlockTransformer_32BitBase(FNVPrimeOffset fnvPrimeOffset) _prime = fnvPrimeOffset.Prime[0]; _hashValue = fnvPrimeOffset.Offset[0]; } + protected override void CopyStateTo(TSelf other) { base.CopyStateTo(other); other._prime = _prime; other._hashValue = _hashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(Endianness.GetBytesLittleEndian(_hashValue), 32); + + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 32); } protected abstract class BlockTransformer_64BitBase @@ -111,6 +113,7 @@ protected abstract class BlockTransformer_64BitBase public BlockTransformer_64BitBase() { } + public BlockTransformer_64BitBase(FNVPrimeOffset fnvPrimeOffset) : this() { @@ -125,8 +128,8 @@ protected override void CopyStateTo(TSelf other) other._hashValue = _hashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(Endianness.GetBytesLittleEndian(_hashValue), 64); + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(_hashValue), 64); } protected abstract class BlockTransformer_ExtendedBase @@ -158,8 +161,8 @@ protected override void CopyStateTo(TSelf other) other._hashSizeInBytes = _hashSizeInBytes; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) => - new HashValue(UInt32ArrayToBytes(_hashValue), _hashSizeInBytes * 8); + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) => + new HashValue(ValueEndianness.LittleEndian, UInt32ArrayToBytes(_hashValue), _hashSizeInBytes * 8); } /// @@ -210,4 +213,4 @@ private static IEnumerable UInt32ArrayToBytes(IEnumerable values) return values.SelectMany(v => Endianness.GetBytesLittleEndian(v)); } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/FNV/FNV1_Implementation.cs b/HashifyNet/Algorithms/FNV/FNV1_Implementation.cs index 78e8e68..a66b49e 100644 --- a/HashifyNet/Algorithms/FNV/FNV1_Implementation.cs +++ b/HashifyNet/Algorithms/FNV/FNV1_Implementation.cs @@ -78,19 +78,15 @@ public BlockTransformer_32Bit(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { tempHashValue *= tempPrime; - tempHashValue ^= dataArray[currentOffset]; + tempHashValue ^= data[currentOffset]; } _hashValue = tempHashValue; @@ -110,19 +106,15 @@ public BlockTransformer_64Bit(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { tempHashValue *= tempPrime; - tempHashValue ^= dataArray[currentOffset]; + tempHashValue ^= data[currentOffset]; } _hashValue = tempHashValue; @@ -141,21 +133,17 @@ public BlockTransformer_Extended(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; var tempHashSizeInBytes = _hashSizeInBytes; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { tempHashValue = ExtendedMultiply(tempHashValue, tempPrime, tempHashSizeInBytes); - tempHashValue[0] ^= dataArray[currentOffset]; + tempHashValue[0] ^= data[currentOffset]; } _hashValue = tempHashValue; diff --git a/HashifyNet/Algorithms/FNV/FNV1a_Implementation.cs b/HashifyNet/Algorithms/FNV/FNV1a_Implementation.cs index 5d796da..3818a1d 100644 --- a/HashifyNet/Algorithms/FNV/FNV1a_Implementation.cs +++ b/HashifyNet/Algorithms/FNV/FNV1a_Implementation.cs @@ -77,18 +77,14 @@ public BlockTransformer_32Bit(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue ^= dataArray[currentOffset]; + tempHashValue ^= data[currentOffset]; tempHashValue *= tempPrime; } @@ -109,18 +105,14 @@ public BlockTransformer_64Bit(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue ^= dataArray[currentOffset]; + tempHashValue ^= data[currentOffset]; tempHashValue *= tempPrime; } @@ -141,21 +133,17 @@ public BlockTransformer_Extended(FNVPrimeOffset fnvPrimeOffset) { } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; - var tempHashValue = _hashValue; var tempPrime = _prime; var tempHashSizeInBytes = _hashSizeInBytes; - for (int currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (int currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue[0] ^= dataArray[currentOffset]; + tempHashValue[0] ^= data[currentOffset]; tempHashValue = ExtendedMultiply(tempHashValue, tempPrime, tempHashSizeInBytes); } diff --git a/HashifyNet/Algorithms/FarmHash/FarmHashFingerprint_Implementation.cs b/HashifyNet/Algorithms/FarmHash/FarmHashFingerprint_Implementation.cs index a541404..c48f017 100644 --- a/HashifyNet/Algorithms/FarmHash/FarmHashFingerprint_Implementation.cs +++ b/HashifyNet/Algorithms/FarmHash/FarmHashFingerprint_Implementation.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -75,14 +75,14 @@ public FarmHashFingerprint_Implementation(IFarmHashConfig config) } } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { return _impl.ComputeHashInternal(data, cancellationToken); } private interface IFarmHashFingerprintInternal { - IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken); + IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken); } private class FarmHashFingerprint32 : IFarmHashFingerprintInternal @@ -90,9 +90,9 @@ private class FarmHashFingerprint32 : IFarmHashFingerprintInternal private const uint c1 = 0xcc9e2d51; private const uint c2 = 0x1b873593; - public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + public IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataCount = data.Count; + var dataCount = data.Length; uint hashValue; if (dataCount > 24) @@ -116,28 +116,24 @@ public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken } return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 32); } - private static uint ComputeHash25Plus(ArraySegment data, CancellationToken cancellationToken) + private static uint ComputeHash25Plus(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; - + var dataCount = data.Length; var h = (uint)dataCount; var g = (uint)(c1 * dataCount); var f = g; - var a0 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4) * c1, 17) * c2; - var a1 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 8) * c1, 17) * c2; - var a2 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 16) * c1, 17) * c2; - var a3 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 12) * c1, 17) * c2; - var a4 = RotateRight(Endianness.ToUInt32LittleEndian(dataArray, endOffset - 20) * c1, 17) * c2; + var a0 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 4) * c1, 17) * c2; + var a1 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 8) * c1, 17) * c2; + var a2 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 16) * c1, 17) * c2; + var a3 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 12) * c1, 17) * c2; + var a4 = RotateRight(Endianness.ToUInt32LittleEndian(data, dataCount - 20) * c1, 17) * c2; h ^= a0; h = RotateRight(h, 19); @@ -156,16 +152,16 @@ private static uint ComputeHash25Plus(ArraySegment data, CancellationToken // Process groups of 20 bytes, leaving 1 to 20 bytes remaining. { - var groupEndOffset = endOffset - 20; + var groupEndOffset = dataCount - 20; - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 20) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 20) { - var a = Endianness.ToUInt32LittleEndian(dataArray, currentOffset); - var b = Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 4); - var c = Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 8); - var d = Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 12); - var e = Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 16); + var a = Endianness.ToUInt32LittleEndian(data, currentOffset); + var b = Endianness.ToUInt32LittleEndian(data, currentOffset + 4); + var c = Endianness.ToUInt32LittleEndian(data, currentOffset + 8); + var d = Endianness.ToUInt32LittleEndian(data, currentOffset + 12); + var e = Endianness.ToUInt32LittleEndian(data, currentOffset + 16); h += a; g += b; @@ -193,20 +189,16 @@ private static uint ComputeHash25Plus(ArraySegment data, CancellationToken return h; } - private static uint ComputeHash13To24(ArraySegment data) + private static uint ComputeHash13To24(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; - - var a = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + (dataCount >> 1) - 4); - var b = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + 4); - var c = Endianness.ToUInt32LittleEndian(dataArray, endOffset - 8); - var d = Endianness.ToUInt32LittleEndian(dataArray, dataOffset + (dataCount >> 1)); - var e = Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - var f = Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4); + var dataCount = data.Length; + + var a = Endianness.ToUInt32LittleEndian(data, (dataCount >> 1) - 4); + var b = Endianness.ToUInt32LittleEndian(data, 4); + var c = Endianness.ToUInt32LittleEndian(data, dataCount - 8); + var d = Endianness.ToUInt32LittleEndian(data, dataCount >> 1); + var e = Endianness.ToUInt32LittleEndian(data, 0); + var f = Endianness.ToUInt32LittleEndian(data, dataCount - 4); var h = (d * c1) + (uint)dataCount; a = RotateRight(a, 12) + f; @@ -219,40 +211,32 @@ private static uint ComputeHash13To24(ArraySegment data) return FMix(h); } - private static uint ComputeHash5To12(ArraySegment data) + private static uint ComputeHash5To12(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var a = (uint)dataCount; var b = (uint)(dataCount * 5); var c = 9U; var d = b; - a += Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - b += Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4); - c += Endianness.ToUInt32LittleEndian(dataArray, dataOffset + ((dataCount >> 1) & 4)); + a += Endianness.ToUInt32LittleEndian(data, 0); + b += Endianness.ToUInt32LittleEndian(data, dataCount - 4); + c += Endianness.ToUInt32LittleEndian(data, (dataCount >> 1) & 4); return FMix(Mur(c, Mur(b, Mur(a, d)))); } - private static uint ComputeHash0To4(ArraySegment data) + private static uint ComputeHash0To4(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var b = 0U; var c = 9U; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 1) + for (var currentOffset = 0; currentOffset < data.Length; currentOffset += 1) { - var v = (sbyte)dataArray[currentOffset]; + var v = (sbyte)data[currentOffset]; b = (uint)((b * c1) + v); c ^= b; @@ -305,9 +289,9 @@ private class FarmHashFingerprint64 : IFarmHashFingerprintInternal private const ulong _k2 = 0x9ae16a3b2f90404fUL; private const ulong _seed = 81UL; - public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + public IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataCount = data.Count; + var dataCount = data.Length; ulong hashValue; if (dataCount > 64) @@ -331,6 +315,7 @@ public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken } return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 64); } @@ -347,19 +332,15 @@ private static ulong ComputeHash16(ulong u, ulong v, ulong mul) return b; } - private static ulong ComputeHash0To16(ArraySegment data) + private static ulong ComputeHash0To16(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; if (dataCount >= 8) { var mul = _k2 + (ulong)(dataCount * 2); - var a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) + _k2; - var b = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8); + var a = Endianness.ToUInt64LittleEndian(data, 0) + _k2; + var b = Endianness.ToUInt64LittleEndian(data, dataCount - 8); var c = (RotateRight(b, 37) * mul) + a; var d = (RotateRight(a, 25) + b) * mul; @@ -369,16 +350,16 @@ private static ulong ComputeHash0To16(ArraySegment data) if (dataCount >= 4) { var mul = _k2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt32LittleEndian(dataArray, dataOffset); + ulong a = Endianness.ToUInt32LittleEndian(data, 0); - return ComputeHash16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4), mul); + return ComputeHash16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(data, dataCount - 4), mul); } if (dataCount > 0) { - var a = dataArray[dataOffset]; - var b = dataArray[dataOffset + (dataCount >> 1)]; - var c = dataArray[endOffset - 1]; + var a = data[0]; + var b = data[dataCount >> 1]; + var c = data[dataCount - 1]; var y = a + (((uint)b) << 8); var z = (uint)dataCount + (((uint)c) << 2); @@ -389,19 +370,15 @@ private static ulong ComputeHash0To16(ArraySegment data) return _k2; } - private static ulong ComputeHash17To32(ArraySegment data) + private static ulong ComputeHash17To32(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var mul = _k2 + ((ulong)dataCount * 2); - var a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) * _k1; - var b = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8); - var c = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8) * mul; - var d = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16) * _k2; + var a = Endianness.ToUInt64LittleEndian(data, 0) * _k1; + var b = Endianness.ToUInt64LittleEndian(data, 8); + var c = Endianness.ToUInt64LittleEndian(data, dataCount - 8) * mul; + var d = Endianness.ToUInt64LittleEndian(data, dataCount - 16) * _k2; return ComputeHash16( RotateRight(a + b, 43) + RotateRight(c, 30) + d, @@ -423,7 +400,7 @@ private static UInt128 WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z return new UInt128(b + c, a + z); } - private static UInt128 WeakHashLen32WithSeeds(byte[] dataArray, int dataOffset, ulong a, ulong b) => + private static UInt128 WeakHashLen32WithSeeds(ReadOnlySpan dataArray, int dataOffset, ulong a, ulong b) => WeakHashLen32WithSeeds( Endianness.ToUInt64LittleEndian(dataArray, dataOffset), Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8), @@ -432,27 +409,23 @@ private static UInt128 WeakHashLen32WithSeeds(byte[] dataArray, int dataOffset, a, b); - private static ulong ComputeHash33To64(ArraySegment data) + private static ulong ComputeHash33To64(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var mul = _k2 + ((ulong)dataCount * 2); - var a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) * _k2; - var b = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8); - var c = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8) * mul; - var d = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16) * _k2; + var a = Endianness.ToUInt64LittleEndian(data, 0) * _k2; + var b = Endianness.ToUInt64LittleEndian(data, 8); + var c = Endianness.ToUInt64LittleEndian(data, dataCount - 8) * mul; + var d = Endianness.ToUInt64LittleEndian(data, dataCount - 16) * _k2; var y = RotateRight(a + b, 43) + RotateRight(c, 30) + d; var z = ComputeHash16(y, a + RotateRight(b + _k2, 18) + c, mul); - var e = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 16) * mul; - var f = Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 24); - var g = (y + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 32)) * mul; - var h = (z + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 24)) * mul; + var e = Endianness.ToUInt64LittleEndian(data, 16) * mul; + var f = Endianness.ToUInt64LittleEndian(data, 24); + var g = (y + Endianness.ToUInt64LittleEndian(data, dataCount - 32)) * mul; + var h = (z + Endianness.ToUInt64LittleEndian(data, dataCount - 24)) * mul; return ComputeHash16( RotateRight(e + f, 43) + RotateRight(g, 30) + h, @@ -460,13 +433,9 @@ private static ulong ComputeHash33To64(ArraySegment data) mul); } - private static ulong ComputeHash65Plus(ArraySegment data, CancellationToken cancellationToken) + private static ulong ComputeHash65Plus(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var x = _seed; var y = unchecked(_seed * _k1) + 113; @@ -475,23 +444,23 @@ private static ulong ComputeHash65Plus(ArraySegment data, CancellationToke var v = new UInt128(); var w = new UInt128(); - x = (x * _k2) + Endianness.ToUInt64LittleEndian(dataArray, dataOffset); + x = (x * _k2) + Endianness.ToUInt64LittleEndian(data, 0); // Process 64-byte groups, leaving a final group of 1-64 bytes in size. { - var groupEndOffset = endOffset - 64; + var groupEndOffset = dataCount - 64; - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 64) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 64) { cancellationToken.ThrowIfCancellationRequested(); - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 8), 37) * _k1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 48), 42) * _k1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, currentOffset + 8), 37) * _k1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, currentOffset + 48), 42) * _k1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 40); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, currentOffset + 40); z = RotateRight(z + w.GetLower(), 33) * _k1; - v = WeakHashLen32WithSeeds(dataArray, currentOffset, v.GetUpper() * _k1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, currentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 16)); + v = WeakHashLen32WithSeeds(data, currentOffset, v.GetUpper() * _k1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, currentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, currentOffset + 16)); Swap(ref z, ref x); } @@ -505,15 +474,15 @@ private static ulong ComputeHash65Plus(ArraySegment data, CancellationToke v = new UInt128(v.GetUpper(), v.GetLower() + w.GetLower()); w = new UInt128(w.GetUpper(), w.GetLower() + v.GetLower()); - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 56), 37) * mul; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16), 42) * mul; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, dataCount - 56), 37) * mul; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, dataCount - 16), 42) * mul; x ^= w.GetUpper() * 9; - y += (v.GetLower() * 9) + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 24); + y += (v.GetLower() * 9) + Endianness.ToUInt64LittleEndian(data, dataCount - 24); z = RotateRight(z + w.GetLower(), 33) * mul; - v = WeakHashLen32WithSeeds(dataArray, endOffset - 64, v.GetUpper() * mul, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, endOffset - 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 48)); + v = WeakHashLen32WithSeeds(data, dataCount - 64, v.GetUpper() * mul, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, dataCount - 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, dataCount - 48)); Swap(ref z, ref x); @@ -556,22 +525,19 @@ private class FarmHashFingerprint128 : IFarmHashFingerprintInternal private const ulong k1 = 0xb492b66fbe98f273UL; private const ulong k2 = 0x9ae16a3b2f90404fUL; - public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + public IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataCount = data.Count; + var dataCount = data.Length; UInt128 hashValue; if (dataCount >= 16) { - var dataArray = data.Array; - var dataOffset = data.Offset; - hashValue = CityHash128WithSeed( - new ArraySegment(dataArray, dataOffset + 16, dataCount - 16), + data.Slice(16, dataCount - 16), new UInt128( - Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8) + k0, - Endianness.ToUInt64LittleEndian(dataArray, dataOffset)), + Endianness.ToUInt64LittleEndian(data, 8) + k0, + Endianness.ToUInt64LittleEndian(data, 0)), cancellationToken); } @@ -583,37 +549,32 @@ public IHashValue ComputeHashInternal(ArraySegment data, CancellationToken var hashValueBytes = Endianness.GetBytesLittleEndian(hashValue.GetLower()) .Concat(Endianness.GetBytesLittleEndian(hashValue.GetUpper())); - return new HashValue(hashValueBytes, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, 128); } - private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, CancellationToken cancellationToken) + private UInt128 CityHash128WithSeed(ReadOnlySpan data, UInt128 seed, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var dataCount = data.Count; + var dataCount = data.Length; if (dataCount < 128) { return CityMurmur(data, seed); } - var dataArray = data.Array; - var dataOffset = data.Offset; - - var endOffset = dataOffset + dataCount; - // We expect len >= 128 to be the common case. Keep 56 bytes of state: // v, w, x, y, and z. UInt128 v; { - var vLow = (RotateRight(seed.GetUpper() ^ k1, 49) * k1) + Endianness.ToUInt64LittleEndian(dataArray, dataOffset); + var vLow = (RotateRight(seed.GetUpper() ^ k1, 49) * k1) + Endianness.ToUInt64LittleEndian(data, 0); v = new UInt128( - (RotateRight(vLow, 42) * k1) + Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 8), + (RotateRight(vLow, 42) * k1) + Endianness.ToUInt64LittleEndian(data, 8), vLow); } UInt128 w = new UInt128( - RotateRight(seed.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, dataOffset + 88), 53) * k1, + RotateRight(seed.GetLower() + Endianness.ToUInt64LittleEndian(data, 88), 53) * k1, (RotateRight(seed.GetUpper() + ((ulong)dataCount * k1), 35) * k1) + seed.GetLower()); ulong x = seed.GetLower(); @@ -623,19 +584,19 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance // This is the same inner loop as CityHash64() int lastGroupEndOffset; { - var groupEndOffset = dataOffset + (dataCount - (dataCount % 128)); + var groupEndOffset = dataCount - (dataCount % 128); - for (var groupCurrentOffset = dataOffset; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 128) + for (var groupCurrentOffset = 0; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 128) { cancellationToken.ThrowIfCancellationRequested(); - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 8), 37) * k1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 48), 42) * k1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 8), 37) * k1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 48), 42) * k1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 40); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 40); z = RotateRight(z + w.GetLower(), 33) * k1; - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset, v.GetUpper() * k1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 16)); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset, v.GetUpper() * k1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, groupCurrentOffset + 32, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 16)); { ulong temp = z; @@ -643,13 +604,13 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance x = temp; } - x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 72), 37) * k1; - y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 112), 42) * k1; + x = RotateRight(x + y + v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 72), 37) * k1; + y = RotateRight(y + v.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 112), 42) * k1; x ^= w.GetUpper(); - y += v.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 104); + y += v.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 104); z = RotateRight(z + w.GetLower(), 33) * k1; - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 64, v.GetUpper() * k1, x + w.GetLower()); - w = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset + 96, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 80)); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset + 64, v.GetUpper() * k1, x + w.GetLower()); + w = WeakHashLen32WithSeeds(data, groupCurrentOffset + 96, z + w.GetUpper(), y + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 80)); { ulong temp = z; @@ -673,16 +634,16 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance { var groupEndOffset = lastGroupEndOffset - 32; - for (var groupCurrentOffset = endOffset - 32; groupCurrentOffset > groupEndOffset; groupCurrentOffset -= 32) + for (var groupCurrentOffset = dataCount - 32; groupCurrentOffset > groupEndOffset; groupCurrentOffset -= 32) { cancellationToken.ThrowIfCancellationRequested(); y = (RotateRight(x + y, 42) * k0) + v.GetUpper(); - w = new UInt128(w.GetUpper(), w.GetLower() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 16)); + w = new UInt128(w.GetUpper(), w.GetLower() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 16)); x = (x * k0) + w.GetLower(); - z += w.GetUpper() + Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset); + z += w.GetUpper() + Endianness.ToUInt64LittleEndian(data, groupCurrentOffset); w = new UInt128(w.GetUpper() + v.GetLower(), w.GetLower()); - v = WeakHashLen32WithSeeds(dataArray, groupCurrentOffset, v.GetLower() + z, v.GetUpper()); + v = WeakHashLen32WithSeeds(data, groupCurrentOffset, v.GetLower() + z, v.GetUpper()); v = new UInt128(v.GetUpper(), v.GetLower() * k0); } } @@ -700,13 +661,9 @@ private UInt128 CityHash128WithSeed(ArraySegment data, UInt128 seed, Cance // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings // of any length representable in signed long. Based on City and Murmur. - private static UInt128 CityMurmur(ArraySegment data, UInt128 seed) + private static UInt128 CityMurmur(ReadOnlySpan data, UInt128 seed) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; ulong a = seed.GetLower(); ulong b = seed.GetUpper(); @@ -718,23 +675,23 @@ private static UInt128 CityMurmur(ArraySegment data, UInt128 seed) // len <= 16 a = Mix(a * k1) * k1; c = (b * k1) + HashLen0to16(data); - d = Mix(a + (dataCount >= 8 ? Endianness.ToUInt64LittleEndian(dataArray, dataOffset) : c)); + d = Mix(a + (dataCount >= 8 ? Endianness.ToUInt64LittleEndian(data, 0) : c)); } else { // len > 16 - c = HashLen16(Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8) + k1, a); - d = HashLen16(b + (ulong)dataCount, c + Endianness.ToUInt64LittleEndian(dataArray, endOffset - 16)); + c = HashLen16(Endianness.ToUInt64LittleEndian(data, dataCount - 8) + k1, a); + d = HashLen16(b + (ulong)dataCount, c + Endianness.ToUInt64LittleEndian(data, dataCount - 16)); a += d; - var groupEndOffset = dataOffset + dataCount - 16; + var groupEndOffset = dataCount - 16; - for (var groupCurrentOffset = dataOffset; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 16) + for (var groupCurrentOffset = 0; groupCurrentOffset < groupEndOffset; groupCurrentOffset += 16) { - a ^= Mix(Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset) * k1) * k1; + a ^= Mix(Endianness.ToUInt64LittleEndian(data, groupCurrentOffset) * k1) * k1; a *= k1; b ^= a; - c ^= Mix(Endianness.ToUInt64LittleEndian(dataArray, groupCurrentOffset + 8) * k1) * k1; + c ^= Mix(Endianness.ToUInt64LittleEndian(data, groupCurrentOffset + 8) * k1) * k1; c *= k1; d ^= c; } @@ -763,18 +720,15 @@ private static ulong HashLen16(ulong u, ulong v, ulong mul) return b; } - private static ulong HashLen0to16(ArraySegment data) + private static ulong HashLen0to16(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; if (dataCount >= 8) { ulong mul = k2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt64LittleEndian(dataArray, dataOffset) + k2; - ulong b = Endianness.ToUInt64LittleEndian(dataArray, endOffset - 8); + ulong a = Endianness.ToUInt64LittleEndian(data, 0) + k2; + ulong b = Endianness.ToUInt64LittleEndian(data, dataCount - 8); ulong c = (RotateRight(b, 37) * mul) + a; ulong d = (RotateRight(a, 25) + b) * mul; @@ -784,15 +738,15 @@ private static ulong HashLen0to16(ArraySegment data) if (dataCount >= 4) { ulong mul = k2 + ((ulong)dataCount * 2); - ulong a = Endianness.ToUInt32LittleEndian(dataArray, dataOffset); - return HashLen16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(dataArray, endOffset - 4), mul); + ulong a = Endianness.ToUInt32LittleEndian(data, 0); + return HashLen16((ulong)dataCount + (a << 3), Endianness.ToUInt32LittleEndian(data, dataCount - 4), mul); } if (dataCount > 0) { - byte a = dataArray[dataOffset]; - byte b = dataArray[dataOffset + (dataCount >> 1)]; - byte c = dataArray[endOffset - 1]; + byte a = data[0]; + byte b = data[dataCount >> 1]; + byte c = data[dataCount - 1]; uint y = a + ((uint)b << 8); uint z = (uint)dataCount + ((uint)c << 2); @@ -835,7 +789,7 @@ private static UInt128 WeakHashLen32WithSeeds( } // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. - private static UInt128 WeakHashLen32WithSeeds(byte[] data, int startIndex, ulong a, ulong b) + private static UInt128 WeakHashLen32WithSeeds(ReadOnlySpan data, int startIndex, ulong a, ulong b) { return WeakHashLen32WithSeeds( Endianness.ToUInt64LittleEndian(data, startIndex), diff --git a/HashifyNet/Algorithms/Gost/Gost_Implementation.cs b/HashifyNet/Algorithms/Gost/Gost_Implementation.cs index d509235..15f5dae 100644 --- a/HashifyNet/Algorithms/Gost/Gost_Implementation.cs +++ b/HashifyNet/Algorithms/Gost/Gost_Implementation.cs @@ -638,83 +638,74 @@ private void Initialize() if (_hashSizeInBits == 256) { - Array.Copy(IV256, _h, 8); + Array.Copy(IV256, 0, _h, 0, 8); } else { - Array.Copy(IV512, _h, 8); + Array.Copy(IV512, 0, _h, 0, 8); } } protected override void CopyStateTo(BlockTransformer other) { - Array.Copy(_h, other._h, _h.Length); - Array.Copy(_n, other._n, _n.Length); - Array.Copy(_s, other._s, _s.Length); + Array.Copy(_h, 0, other._h, 0, _h.Length); + Array.Copy(_n, 0, other._n, 0, _n.Length); + Array.Copy(_s, 0, other._s, 0, _s.Length); base.CopyStateTo(other); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - int offset = data.Offset; - int count = data.Count; - - var m = new ulong[8]; - while (count >= 64) - { - BytesToUlongsLE(dataArray, offset, m); - ProcessBlock(m); - - offset += 64; - count -= 64; - } + Span m = stackalloc ulong[8]; + BytesToUlongsLE(data, 0, m); + ProcessBlock(m); } - private void ProcessBlock(ulong[] m) + private void ProcessBlock(Span m) { GN(_n, _h, m); Add512(_n, Stage2Constant_512); Add512(_s, m); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - byte[] tail = FinalizeInputBuffer ?? Array.Empty(); + Span finalM = stackalloc ulong[8]; + Span finalBlock = stackalloc byte[64]; + finalBlock.Clear(); + + leftover.CopyTo(finalBlock); - var finalBuffer = new byte[64]; - tail.CopyTo(finalBuffer, 0); - finalBuffer[tail.Length] = 0x01; + finalBlock[leftover.Length] = 0x01; - var finalM = new ulong[8]; - BytesToUlongsLE(finalBuffer, finalM); + BytesToUlongsLE(finalBlock, 0, finalM); - GN(_n, _h, finalM); + GN(_n.AsSpan(), _h.AsSpan(), finalM); - ulong[] unprocessedBitsCount = { (ulong)tail.Length * 8, 0, 0, 0, 0, 0, 0, 0 }; + ulong[] unprocessedBitsCount = { (ulong)leftover.Length * 8, 0, 0, 0, 0, 0, 0, 0 }; Add512(_n, unprocessedBitsCount); Add512(_s, finalM); - GN(IV512, _h, _n); - GN(IV512, _h, _s); + GN(IV512, _h.AsSpan(), _n.AsSpan()); + GN(IV512, _h.AsSpan(), _s.AsSpan()); - var hBytes = new byte[64]; + Span hBytes = stackalloc byte[64]; UlongsToBytesLE(_h, hBytes); - var finalHashBytes = new byte[_hashSizeInBits / 8]; - Buffer.BlockCopy(hBytes, 64 - finalHashBytes.Length, finalHashBytes, 0, finalHashBytes.Length); + byte[] finalHashBytes = new byte[_hashSizeInBits / 8]; + hBytes.Slice(hBytes.Length - finalHashBytes.Length).CopyTo(finalHashBytes); - return new HashValue(finalHashBytes, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, finalHashBytes, _hashSizeInBits); } - private void GN(ulong[] n, ulong[] h, ulong[] m) + private void GN(Span n, Span h, Span m) { - ulong[] k = new ulong[8]; - ulong[] state = new ulong[8]; - ulong[] temp = new ulong[8]; + Span k = stackalloc ulong[8]; + Span state = stackalloc ulong[8]; + Span temp = stackalloc ulong[8]; - ulong[] h_in = new ulong[8]; - Array.Copy(h, h_in, 8); + Span h_in = stackalloc ulong[8]; + h.CopyTo(h_in); Xor512(h_in, n, temp); LPS(temp, k); @@ -738,7 +729,7 @@ private void GN(ulong[] n, ulong[] h, ulong[] m) Xor512(state, m, h); } - private static void LPS(ulong[] input, ulong[] output) + private static void LPS(Span input, Span output) { ulong r0 = input[0]; ulong r1 = input[1]; @@ -763,7 +754,7 @@ private static void LPS(ulong[] input, ulong[] output) } } - private static void Xor512(ulong[] a, ulong[] b, ulong[] result) + private static void Xor512(Span a, Span b, Span result) { for (int i = 0; i < 8; i++) { @@ -771,7 +762,7 @@ private static void Xor512(ulong[] a, ulong[] b, ulong[] result) } } - private static void Add512(ulong[] a, ulong[] b) + private static void Add512(Span a, Span b) { ulong carry = 0; for (int i = 0; i < 8; i++) @@ -785,12 +776,7 @@ private static void Add512(ulong[] a, ulong[] b) } } - private static void BytesToUlongsLE(byte[] input, ulong[] output) - { - BytesToUlongsLE(input, 0, output); - } - - private static void BytesToUlongsLE(byte[] input, int offset, ulong[] output) + private static void BytesToUlongsLE(ReadOnlySpan input, int offset, Span output) { for (int i = 0; i < 8; i++) { @@ -798,15 +784,13 @@ private static void BytesToUlongsLE(byte[] input, int offset, ulong[] output) } } - private static void UlongsToBytesLE(ulong[] input, byte[] output) + private static void UlongsToBytesLE(ulong[] input, Span output) { for (int i = 0; i < 8; i++) { - var bytes = Endianness.GetBytesLittleEndian(input[i]); - Array.Copy(bytes, 0, output, i * 8, 8); + Endianness.ToLittleEndianBytes(input[i], output, i * 8); } } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/IMD5Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/IMD5Config.cs index 6420eea..1772a4b 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/IMD5Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/IMD5Config.cs @@ -42,5 +42,10 @@ public interface IMD5Config : ICryptographicHashConfig /// For MD5, this is always fixed at 128 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5Config.cs index 54bf3ab..ac9d641 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5Config.cs @@ -27,6 +27,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.MD5 { /// @@ -51,13 +53,29 @@ public MD5Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public IMD5Config Clone() { - return new MD5Config(); + return new MD5Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -73,7 +91,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5_Implementation.cs index cdb1c1e..265a2d6 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/MD5/MD5_Implementation.cs @@ -28,6 +28,7 @@ // * using HashifyNet.Core; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.MD5 { @@ -38,7 +39,7 @@ namespace HashifyNet.Algorithms.MD5 internal class MD5_Implementation : HashAlgorithmWrapperBase, IMD5 { - public MD5_Implementation(IMD5Config config) : base(config, () => System.Security.Cryptography.MD5.Create()) + public MD5_Implementation(IMD5Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.MD5) : IncrementalHash.CreateHMAC(HashAlgorithmName.MD5, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/ISHA1Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/ISHA1Config.cs index 4d4221a..05fb9b9 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/ISHA1Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/ISHA1Config.cs @@ -42,5 +42,10 @@ public interface ISHA1Config : ICryptographicHashConfig /// For SHA1, this is always fixed at 160 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1Config.cs index cb0ace1..6ffb731 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1Config.cs @@ -27,6 +27,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA1 { /// @@ -51,13 +53,29 @@ public SHA1Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA1Config Clone() { - return new SHA1Config(); + return new SHA1Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -73,7 +91,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1_Implementation.cs index fb7a718..e8f5051 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA1/SHA1_Implementation.cs @@ -28,6 +28,7 @@ // * using HashifyNet.Core; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA1 { @@ -38,7 +39,7 @@ namespace HashifyNet.Algorithms.SHA1 internal class SHA1_Implementation : HashAlgorithmWrapperBase, ISHA1 { - public SHA1_Implementation(ISHA1Config config) : base(config, () => System.Security.Cryptography.SHA1.Create()) + public SHA1_Implementation(ISHA1Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA1) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA1, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/ISHA256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/ISHA256Config.cs index 1c826bc..da036c0 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/ISHA256Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/ISHA256Config.cs @@ -42,5 +42,10 @@ public interface ISHA256Config : ICryptographicHashConfig /// For SHA256, this is always fixed at 256 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256Config.cs index 6688d49..8b462d3 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256Config.cs @@ -27,6 +27,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA256 { /// @@ -51,13 +53,29 @@ public SHA256Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA256Config Clone() { - return new SHA256Config(); + return new SHA256Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -73,7 +91,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256_Implementation.cs index 44e0244..ed0e9a2 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA256/SHA256_Implementation.cs @@ -28,6 +28,7 @@ // * using HashifyNet.Core; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA256 { @@ -38,7 +39,7 @@ namespace HashifyNet.Algorithms.SHA256 internal class SHA256_Implementation : HashAlgorithmWrapperBase, ISHA256 { - public SHA256_Implementation(ISHA256Config config) : base(config, () => System.Security.Cryptography.SHA256.Create()) + public SHA256_Implementation(ISHA256Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA256) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA256, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/ISHA384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/ISHA384Config.cs index 7fa09d6..60c8d53 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/ISHA384Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/ISHA384Config.cs @@ -42,5 +42,10 @@ public interface ISHA384Config : ICryptographicHashConfig /// For SHA384, this is always fixed at 384 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384Config.cs index 07701be..e1f84e0 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384Config.cs @@ -27,6 +27,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA384 { /// @@ -51,13 +53,29 @@ public SHA384Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA384Config Clone() { - return new SHA384Config(); + return new SHA384Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -73,7 +91,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384_Implementation.cs index 7b80702..081da45 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA384/SHA384_Implementation.cs @@ -28,6 +28,7 @@ // * using HashifyNet.Core; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA384 { @@ -38,7 +39,7 @@ namespace HashifyNet.Algorithms.SHA384 internal class SHA384_Implementation : HashAlgorithmWrapperBase, ISHA384 { - public SHA384_Implementation(ISHA384Config config) : base(config, () => System.Security.Cryptography.SHA384.Create()) + public SHA384_Implementation(ISHA384Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA384) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA384, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/ISHA3_256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/ISHA3_256Config.cs index 0cc2ba3..9686d87 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/ISHA3_256Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/ISHA3_256Config.cs @@ -44,6 +44,11 @@ public interface ISHA3_256Config : ICryptographicHashConfig /// For SHA3_256, this is always fixed at 256 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256Config.cs index 9444b37..f41c5d6 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256Config.cs @@ -29,6 +29,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA3_256 { /// @@ -53,13 +55,29 @@ public SHA3_256Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA3_256Config Clone() { - return new SHA3_256Config(); + return new SHA3_256Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -75,7 +93,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256_Implementation.cs index 416c22d..5d11da0 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_256/SHA3_256_Implementation.cs @@ -30,8 +30,7 @@ // * using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA3_256 { @@ -42,7 +41,7 @@ namespace HashifyNet.Algorithms.SHA3_256 internal class SHA3_256_Implementation : HashAlgorithmWrapperBase, ISHA3_256 { - public SHA3_256_Implementation(ISHA3_256Config config) : base(config, () => System.Security.Cryptography.SHA3_256.Create()) + public SHA3_256_Implementation(ISHA3_256Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA3_256) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA3_256, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/ISHA3_384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/ISHA3_384Config.cs index 7470d63..836b9f0 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/ISHA3_384Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/ISHA3_384Config.cs @@ -44,6 +44,11 @@ public interface ISHA3_384Config : ICryptographicHashConfig /// For SHA3_384, this is always fixed at 384 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384Config.cs index 320f1f8..13f17ec 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384Config.cs @@ -29,6 +29,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA3_384 { /// @@ -53,13 +55,29 @@ public SHA3_384Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA3_384Config Clone() { - return new SHA3_384Config(); + return new SHA3_384Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -75,7 +93,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384_Implementation.cs index 0a2a7ea..23227aa 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_384/SHA3_384_Implementation.cs @@ -30,8 +30,7 @@ // * using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA3_384 { @@ -42,7 +41,7 @@ namespace HashifyNet.Algorithms.SHA3_384 internal class SHA3_384_Implementation : HashAlgorithmWrapperBase, ISHA3_384 { - public SHA3_384_Implementation(ISHA3_384Config config) : base(config, () => System.Security.Cryptography.SHA3_384.Create()) + public SHA3_384_Implementation(ISHA3_384Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA3_384) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA3_384, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/ISHA3_512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/ISHA3_512Config.cs index d0613cb..646dcb1 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/ISHA3_512Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/ISHA3_512Config.cs @@ -44,6 +44,11 @@ public interface ISHA3_512Config : ICryptographicHashConfig /// For SHA3_512, this is always fixed at 512 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512Config.cs index a6663f5..1faef8f 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512Config.cs @@ -29,6 +29,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA3_512 { /// @@ -53,13 +55,29 @@ public SHA3_512Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA3_512Config Clone() { - return new SHA3_512Config(); + return new SHA3_512Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -75,7 +93,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512_Implementation.cs index 9092046..70cd4ac 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA3_512/SHA3_512_Implementation.cs @@ -30,8 +30,7 @@ // * using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA3_512 { @@ -42,7 +41,7 @@ namespace HashifyNet.Algorithms.SHA3_512 internal class SHA3_512_Implementation : HashAlgorithmWrapperBase, ISHA3_512 { - public SHA3_512_Implementation(ISHA3_512Config config) : base(config, () => System.Security.Cryptography.SHA3_512.Create()) + public SHA3_512_Implementation(ISHA3_512Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA3_512) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA3_512, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/ISHA512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/ISHA512Config.cs index 336169d..dd9e639 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/ISHA512Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/ISHA512Config.cs @@ -42,5 +42,10 @@ public interface ISHA512Config : ICryptographicHashConfig /// For SHA512, this is always fixed at 512 bits. /// new int HashSizeInBits { get; } + + /// + /// Gets the secret key for the hash algorithm. + /// + byte[] Key { get; } } } diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512Config.cs index bc5a395..929af28 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512Config.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512Config.cs @@ -27,6 +27,8 @@ // ****************************************************************************** // * +using HashifyNet.Core.Utilities; + namespace HashifyNet.Algorithms.SHA512 { /// @@ -51,13 +53,29 @@ public SHA512Config() /// public int HashSizeInBits { get; private set; } + /// + /// Gets or sets the secret key for the hash algorithm. + /// +#if NET8_0_OR_GREATER +#nullable enable + public byte[]? +#nullable restore +#else + public byte[] +#endif // NET8_0_OR_GREATER + Key + { get; set; } = null; + /// /// Creates a deep copy of the current instance. /// /// A new instance with the same settings. public ISHA512Config Clone() { - return new SHA512Config(); + return new SHA512Config() + { + Key = (byte[])Key?.Clone(), + }; } /// @@ -73,7 +91,10 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - // Nothing to dispose. + if (Key != null) + { + ArrayHelpers.ZeroFill(Key); + } } // TODO: free unmanaged resources (unmanaged objects) and override finalizer diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512_Implementation.cs index 839a9e0..742d9cb 100644 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512_Implementation.cs +++ b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/SHA512/SHA512_Implementation.cs @@ -28,6 +28,7 @@ // * using HashifyNet.Core; +using System.Security.Cryptography; namespace HashifyNet.Algorithms.SHA512 { @@ -38,7 +39,7 @@ namespace HashifyNet.Algorithms.SHA512 internal class SHA512_Implementation : HashAlgorithmWrapperBase, ISHA512 { - public SHA512_Implementation(ISHA512Config config) : base(config, () => System.Security.Cryptography.SHA512.Create()) + public SHA512_Implementation(ISHA512Config config) : base(config, () => config.Key == null ? IncrementalHash.CreateHash(HashAlgorithmName.SHA512) : IncrementalHash.CreateHMAC(HashAlgorithmName.SHA512, config.Key)) { } } diff --git a/HashifyNet/Algorithms/HighwayHash/HighwayHash_Implementation.cs b/HashifyNet/Algorithms/HighwayHash/HighwayHash_Implementation.cs index 95a1d0e..779d556 100644 --- a/HashifyNet/Algorithms/HighwayHash/HighwayHash_Implementation.cs +++ b/HashifyNet/Algorithms/HighwayHash/HighwayHash_Implementation.cs @@ -143,7 +143,7 @@ public BlockTransformer(ulong[] key, int hashSizeInBits) _v0[1] = key[1] ^ _mul0[1]; _v0[2] = key[2] ^ _mul0[2]; _v0[3] = key[3] ^ _mul0[3]; - + _v1[0] = ((key[0] >> 32) | (key[0] << 32)) ^ _mul1[0]; _v1[1] = ((key[1] >> 32) | (key[1] << 32)) ^ _mul1[1]; _v1[2] = ((key[2] >> 32) | (key[2] << 32)) ^ _mul1[2]; @@ -159,19 +159,19 @@ protected override void CopyStateTo(BlockTransformer other) other._mul1 = (ulong[])_mul1.Clone(); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - if (data.Count != 32) + if (data.Length != 32) { - throw new ArgumentException("Data segment must be exactly 32 bytes for HighwayHash block processing. The current is " + data.Count + " bytes."); + throw new ArgumentException("Data segment must be exactly 32 bytes for HighwayHash block processing. The current is " + data.Length + " bytes."); } - var span = new ReadOnlySpan(data.Array, data.Offset, data.Count); Span packet = stackalloc ulong[4]; for (int i = 0; i < 4; i++) { - packet[i] = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(i * 8, 8)); + packet[i] = BinaryPrimitives.ReadUInt64LittleEndian(data.Slice(i * 8, 8)); } + Update(packet); } @@ -229,12 +229,9 @@ private static ulong Rotate32Wise(ulong v, int r) return ((ulong)hi << 32) | lo; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - ReadOnlySpan rem = (FinalizeInputBuffer == null || FinalizeInputBuffer.Length < 1) - ? ReadOnlySpan.Empty - : FinalizeInputBuffer.AsSpan(); - + ReadOnlySpan rem = leftover; int r = rem.Length; if (r > 0) @@ -307,7 +304,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel ulong h0 = _v0[0] + _v1[0] + _mul0[0] + _mul1[0]; Span out64 = stackalloc byte[8]; BinaryPrimitives.WriteUInt64LittleEndian(out64, h0); - return new HashValue(out64.ToArray(), 64); + return new HashValue(ValueEndianness.LittleEndian, out64.ToArray(), 64); } if (_hashSizeInBits == 128) @@ -317,7 +314,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Span out128 = stackalloc byte[16]; BinaryPrimitives.WriteUInt64LittleEndian(out128.Slice(0, 8), h0); BinaryPrimitives.WriteUInt64LittleEndian(out128.Slice(8, 8), h1); - return new HashValue(out128.ToArray(), 128); + return new HashValue(ValueEndianness.LittleEndian, out128.ToArray(), 128); } // 256-bit hash @@ -341,11 +338,9 @@ void MR(out ulong hash1, out ulong hash2, ulong v1, ulong m1, ulong v2, ulong m2 BinaryPrimitives.WriteUInt64LittleEndian(out256.Slice(8, 8), h1); BinaryPrimitives.WriteUInt64LittleEndian(out256.Slice(16, 8), h2); BinaryPrimitives.WriteUInt64LittleEndian(out256.Slice(24, 8), h3); - return new HashValue(out256.ToArray(), 256); + return new HashValue(ValueEndianness.LittleEndian, out256.ToArray(), 256); } } } } - -} - +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Jenkins/JenkinsLookup2_Implementation.cs b/HashifyNet/Algorithms/Jenkins/JenkinsLookup2_Implementation.cs index f5da8e9..46c6a3f 100644 --- a/HashifyNet/Algorithms/Jenkins/JenkinsLookup2_Implementation.cs +++ b/HashifyNet/Algorithms/Jenkins/JenkinsLookup2_Implementation.cs @@ -30,7 +30,6 @@ using HashifyNet.Core; using HashifyNet.Core.Utilities; using System; -using System.Diagnostics; using System.Threading; namespace HashifyNet.Algorithms.Jenkins @@ -98,23 +97,19 @@ protected override void CopyStateTo(BlockTransformer other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - Debug.Assert(data.Count % 12 == 0); - - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; + var dataCount = data.Length; var tempA = _a; var tempB = _b; var tempC = _c; - for (var currentOffset = data.Offset; currentOffset < endOffset; currentOffset += 12) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 12) { - tempA += Endianness.ToUInt32LittleEndian(dataArray, currentOffset); - tempB += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 4); - tempC += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 8); + tempA += Endianness.ToUInt32LittleEndian(data, currentOffset); + tempB += Endianness.ToUInt32LittleEndian(data, currentOffset + 4); + tempC += Endianness.ToUInt32LittleEndian(data, currentOffset + 8); Mix(ref tempA, ref tempB, ref tempC); } @@ -126,50 +121,45 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += (uint)dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - var remainderLength = (remainder?.Length).GetValueOrDefault(); - - Debug.Assert(remainderLength >= 0); - Debug.Assert(remainderLength < 12); - var finalA = _a; var finalB = _b; var finalC = _c; // All the case statements fall through on purpose - switch (remainderLength) + switch (leftover.Length) { - case 11: finalC += (uint)remainder[10] << 24; goto case 10; - case 10: finalC += (uint)remainder[9] << 16; goto case 9; - case 9: finalC += (uint)remainder[8] << 8; goto case 8; + case 11: finalC += (uint)leftover[10] << 24; goto case 10; + case 10: finalC += (uint)leftover[9] << 16; goto case 9; + case 9: finalC += (uint)leftover[8] << 8; goto case 8; // the first byte of c is reserved for the length case 8: - finalB += Endianness.ToUInt32LittleEndian(remainder, 4); + finalB += Endianness.ToUInt32LittleEndian(leftover, 4); goto case 4; - case 7: finalB += (uint)remainder[6] << 16; goto case 6; - case 6: finalB += (uint)remainder[5] << 8; goto case 5; - case 5: finalB += remainder[4]; goto case 4; + case 7: finalB += (uint)leftover[6] << 16; goto case 6; + case 6: finalB += (uint)leftover[5] << 8; goto case 5; + case 5: finalB += leftover[4]; goto case 4; case 4: - finalA += Endianness.ToUInt32LittleEndian(remainder, 0); + finalA += Endianness.ToUInt32LittleEndian(leftover, 0); break; - case 3: finalA += (uint)remainder[2] << 16; goto case 2; - case 2: finalA += (uint)remainder[1] << 8; goto case 1; + case 3: finalA += (uint)leftover[2] << 16; goto case 2; + case 2: finalA += (uint)leftover[1] << 8; goto case 1; case 1: - finalA += remainder[0]; + finalA += leftover[0]; break; } - finalC += _bytesProcessed + (uint)remainderLength; + finalC += _bytesProcessed + (uint)leftover.Length; Mix(ref finalA, ref finalB, ref finalC); return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(finalC), 32); } @@ -190,4 +180,4 @@ private static void Mix(ref uint a, ref uint b, ref uint c) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Jenkins/JenkinsLookup3_Implementation.cs b/HashifyNet/Algorithms/Jenkins/JenkinsLookup3_Implementation.cs index 757b675..3e37fbd 100644 --- a/HashifyNet/Algorithms/Jenkins/JenkinsLookup3_Implementation.cs +++ b/HashifyNet/Algorithms/Jenkins/JenkinsLookup3_Implementation.cs @@ -69,9 +69,9 @@ public JenkinsLookup3_Implementation(IJenkinsLookup3Config config) } } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - uint a = 0xdeadbeef + (uint)data.Count + (uint)_config.Seed; + uint a = 0xdeadbeef + (uint)data.Length + (uint)_config.Seed; uint b = a; uint c = a; @@ -80,9 +80,7 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance c += (uint)_config.Seed2; } - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; + var dataCount = data.Length; var remainderCount = dataCount % 12; { @@ -92,16 +90,16 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance } } - var remainderOffset = dataOffset + dataCount - remainderCount; + var remainderOffset = dataCount - remainderCount; // Main group processing - int currentOffset = dataOffset; + int currentOffset = 0; { while (currentOffset < remainderOffset) { - a += Endianness.ToUInt32LittleEndian(dataArray, currentOffset); - b += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 4); - c += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 8); + a += Endianness.ToUInt32LittleEndian(data, currentOffset); + b += Endianness.ToUInt32LittleEndian(data, currentOffset + 4); + c += Endianness.ToUInt32LittleEndian(data, currentOffset + 8); Mix(ref a, ref b, ref c); @@ -117,31 +115,31 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance switch (remainderCount) { case 12: - c += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 8); + c += Endianness.ToUInt32LittleEndian(data, currentOffset + 8); goto case 8; - case 11: c += (uint)dataArray[currentOffset + 10] << 16; goto case 10; - case 10: c += (uint)dataArray[currentOffset + 9] << 8; goto case 9; - case 9: c += dataArray[currentOffset + 8]; goto case 8; + case 11: c += (uint)data[currentOffset + 10] << 16; goto case 10; + case 10: c += (uint)data[currentOffset + 9] << 8; goto case 9; + case 9: c += data[currentOffset + 8]; goto case 8; case 8: - b += Endianness.ToUInt32LittleEndian(dataArray, currentOffset + 4); + b += Endianness.ToUInt32LittleEndian(data, currentOffset + 4); goto case 4; - case 7: b += (uint)dataArray[currentOffset + 6] << 16; goto case 6; - case 6: b += (uint)dataArray[currentOffset + 5] << 8; goto case 5; - case 5: b += dataArray[currentOffset + 4]; goto case 4; + case 7: b += (uint)data[currentOffset + 6] << 16; goto case 6; + case 6: b += (uint)data[currentOffset + 5] << 8; goto case 5; + case 5: b += data[currentOffset + 4]; goto case 4; case 4: - a += Endianness.ToUInt32LittleEndian(dataArray, currentOffset); + a += Endianness.ToUInt32LittleEndian(data, currentOffset); Final(ref a, ref b, ref c); break; - case 3: a += (uint)dataArray[currentOffset + 2] << 16; goto case 2; - case 2: a += (uint)dataArray[currentOffset + 1] << 8; goto case 1; + case 3: a += (uint)data[currentOffset + 2] << 16; goto case 2; + case 2: a += (uint)data[currentOffset + 1] << 8; goto case 1; case 1: - a += dataArray[currentOffset]; + a += data[currentOffset]; Final(ref a, ref b, ref c); break; @@ -164,7 +162,7 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance throw new NotImplementedException(); } - return new HashValue(hash, _config.HashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, hash, _config.HashSizeInBits); } private void Mix(ref uint a, ref uint b, ref uint c) @@ -199,4 +197,4 @@ private static uint RotateLeft(uint operand, int shiftCount) (operand >> (32 - shiftCount)); } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Jenkins/JenkinsOneAtATime_Implementation.cs b/HashifyNet/Algorithms/Jenkins/JenkinsOneAtATime_Implementation.cs index 5ae5a2e..3bf57c9 100644 --- a/HashifyNet/Algorithms/Jenkins/JenkinsOneAtATime_Implementation.cs +++ b/HashifyNet/Algorithms/Jenkins/JenkinsOneAtATime_Implementation.cs @@ -76,16 +76,13 @@ protected override void CopyStateTo(BlockTransformer other) other._hashValue = _hashValue; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var endOffset = data.Offset + data.Count; - var tempHashValue = _hashValue; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < data.Length; ++currentOffset) { - tempHashValue += dataArray[currentOffset]; + tempHashValue += data[currentOffset]; tempHashValue += tempHashValue << 10; tempHashValue ^= tempHashValue >> 6; } @@ -93,7 +90,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _hashValue = tempHashValue; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var finalHashValue = _hashValue; finalHashValue += finalHashValue << 3; @@ -101,10 +98,10 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel finalHashValue += finalHashValue << 15; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(finalHashValue), 32); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs b/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs index 24b3d8d..406cf97 100644 --- a/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs +++ b/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs @@ -104,30 +104,28 @@ protected override void CopyStateTo(BlockTransformer other) Buffer.BlockCopy(_state, 0, other._state, 0, 25 * sizeof(ulong)); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - Absorb(data.Array, data.Offset); + Absorb(data); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - byte[] remainder = FinalizeInputBuffer ?? Array.Empty(); byte paddingByte = _useSha3Padding ? (byte)0x06 : (byte)0x01; - - byte[] padded = new byte[_rateInBytes]; - Buffer.BlockCopy(remainder, 0, padded, 0, remainder.Length); - padded[remainder.Length] = paddingByte; + Span padded = stackalloc byte[_rateInBytes]; + leftover.CopyTo(padded); + padded[leftover.Length] = paddingByte; padded[_rateInBytes - 1] |= 0x80; - Absorb(padded, 0); + Absorb(padded); int bytesToSqueeze = (_hashSizeInBits + 7) / 8; byte[] hash = Squeeze(bytesToSqueeze); - return new HashValue(hash, _hashSizeInBits); + return new HashValue(ValueEndianness.NotApplicable, hash, _hashSizeInBits); } - private void Absorb(byte[] data, int offset) + private void Absorb(ReadOnlySpan data) { int byteIndex = 0; for (int y = 0; y < 5; y++) @@ -136,7 +134,7 @@ private void Absorb(byte[] data, int offset) { if (byteIndex < _rateInBytes) { - _state[x, y] ^= Endianness.ToUInt64LittleEndian(data, offset + byteIndex); + _state[x, y] ^= Endianness.ToUInt64LittleEndian(data, byteIndex); byteIndex += 8; } else @@ -261,4 +259,4 @@ private void KeccakF1600_Permute() #endregion } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/MetroHash/MetroHash_Implementation.cs b/HashifyNet/Algorithms/MetroHash/MetroHash_Implementation.cs index f7eaed1..260b7e7 100644 --- a/HashifyNet/Algorithms/MetroHash/MetroHash_Implementation.cs +++ b/HashifyNet/Algorithms/MetroHash/MetroHash_Implementation.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -120,31 +120,27 @@ protected override void CopyStateTo(BlockTransformer128 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var tempA = _a; var tempB = _b; var tempC = _c; var tempD = _d; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 32) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 32) { - tempA += Endianness.ToUInt64LittleEndian(dataArray, currentOffset) * _k0; + tempA += Endianness.ToUInt64LittleEndian(data, currentOffset) * _k0; tempA = RotateRight(tempA, 29) + tempC; - tempB += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 8) * _k1; + tempB += Endianness.ToUInt64LittleEndian(data, currentOffset + 8) * _k1; tempB = RotateRight(tempB, 29) + tempD; - tempC += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 16) * _k2; + tempC += Endianness.ToUInt64LittleEndian(data, currentOffset + 16) * _k2; tempC = RotateRight(tempC, 29) + tempA; - tempD += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 24) * _k3; + tempD += Endianness.ToUInt64LittleEndian(data, currentOffset + 24) * _k3; tempD = RotateRight(tempD, 29) + tempB; } @@ -156,7 +152,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += (ulong)dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var tempA = _a; var tempB = _b; @@ -171,16 +167,14 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel tempB ^= RotateRight(((tempB + tempD) * _k1) + tempC, 21) * _k0; } - var remainder = FinalizeInputBuffer; var remainderOffset = 0; - var remainderCount = (remainder?.Length).GetValueOrDefault(); - + var remainderCount = leftover.Length; if (remainderCount >= 16) { - tempA += Endianness.ToUInt64LittleEndian(remainder, remainderOffset) * _k2; + tempA += Endianness.ToUInt64LittleEndian(leftover, remainderOffset) * _k2; tempA = RotateRight(tempA, 33) * _k3; - tempB += Endianness.ToUInt64LittleEndian(remainder, remainderOffset + 8) * _k2; + tempB += Endianness.ToUInt64LittleEndian(leftover, remainderOffset + 8) * _k2; tempB = RotateRight(tempB, 33) * _k3; tempA ^= RotateRight((tempA * _k2) + tempB, 45) * _k1; @@ -192,7 +186,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 8) { - tempA += Endianness.ToUInt64LittleEndian(remainder, remainderOffset) * _k2; + tempA += Endianness.ToUInt64LittleEndian(leftover, remainderOffset) * _k2; tempA = RotateRight(tempA, 33) * _k3; tempA ^= RotateRight((tempA * _k2) + tempB, 27) * _k1; @@ -202,7 +196,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 4) { - tempB += Endianness.ToUInt32LittleEndian(remainder, remainderOffset) * _k2; + tempB += Endianness.ToUInt32LittleEndian(leftover, remainderOffset) * _k2; tempB = RotateRight(tempB, 33) * _k3; tempB ^= RotateRight((tempB * _k3) + tempA, 46) * _k0; @@ -212,7 +206,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 2) { - tempA += Endianness.ToUInt16LittleEndian(remainder, remainderOffset) * _k2; + tempA += Endianness.ToUInt16LittleEndian(leftover, remainderOffset) * _k2; tempA = RotateRight(tempA, 33) * _k3; tempA ^= RotateRight((tempA * _k2) + tempB, 22) * _k1; @@ -222,7 +216,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 1) { - tempB += remainder[remainderOffset] * _k2; + tempB += leftover[remainderOffset] * _k2; tempB = RotateRight(tempB, 33) * _k3; tempB ^= RotateRight((tempB * _k3) + tempA, 58) * _k0; } @@ -234,10 +228,10 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel var hashValueBytes = new byte[16]; - Array.Copy(Endianness.GetBytesLittleEndian(tempA), 0, hashValueBytes, 0, 8); - Array.Copy(Endianness.GetBytesLittleEndian(tempB), 0, hashValueBytes, 8, 8); + Buffer.BlockCopy(Endianness.GetBytesLittleEndian(tempA), 0, hashValueBytes, 0, 8); + Buffer.BlockCopy(Endianness.GetBytesLittleEndian(tempB), 0, hashValueBytes, 8, 8); - return new HashValue(hashValueBytes, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, 128); } private static ulong RotateRight(ulong operand, int shiftCount) @@ -299,31 +293,27 @@ protected override void CopyStateTo(BlockTransformer64 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var tempA = _a; var tempB = _b; var tempC = _c; var tempD = _d; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 32) + for (var currentOffset = 0; currentOffset < data.Length; currentOffset += 32) { - tempA += Endianness.ToUInt64LittleEndian(dataArray, currentOffset) * _k0; + tempA += Endianness.ToUInt64LittleEndian(data, currentOffset) * _k0; tempA = RotateRight(tempA, 29) + tempC; - tempB += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 8) * _k1; + tempB += Endianness.ToUInt64LittleEndian(data, currentOffset + 8) * _k1; tempB = RotateRight(tempB, 29) + tempD; - tempC += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 16) * _k2; + tempC += Endianness.ToUInt64LittleEndian(data, currentOffset + 16) * _k2; tempC = RotateRight(tempC, 29) + tempA; - tempD += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 24) * _k3; + tempD += Endianness.ToUInt64LittleEndian(data, currentOffset + 24) * _k3; tempD = RotateRight(tempD, 29) + tempB; } @@ -335,7 +325,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += (ulong)dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var tempA = _a; var tempB = _b; @@ -353,16 +343,15 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel tempA = _initialValue + (tempA ^ tempB); } - var remainder = FinalizeInputBuffer; var remainderOffset = 0; - var remainderCount = (remainder?.Length).GetValueOrDefault(); + var remainderCount = leftover.Length; if (remainderCount >= 16) { - tempB = tempA + (Endianness.ToUInt64LittleEndian(remainder, remainderOffset) * _k2); + tempB = tempA + (Endianness.ToUInt64LittleEndian(leftover, remainderOffset) * _k2); tempB = RotateRight(tempB, 29) * _k3; - tempC = tempA + (Endianness.ToUInt64LittleEndian(remainder, remainderOffset + 8) * _k2); + tempC = tempA + (Endianness.ToUInt64LittleEndian(leftover, remainderOffset + 8) * _k2); tempC = RotateRight(tempC, 29) * _k3; tempB ^= RotateRight(tempB * _k0, 21) + tempC; @@ -376,7 +365,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 8) { - tempA += Endianness.ToUInt64LittleEndian(remainder, remainderOffset) * _k3; + tempA += Endianness.ToUInt64LittleEndian(leftover, remainderOffset) * _k3; tempA ^= RotateRight(tempA, 55) * _k1; remainderOffset += 8; @@ -385,7 +374,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 4) { - tempA += Endianness.ToUInt32LittleEndian(remainder, remainderOffset) * _k3; + tempA += Endianness.ToUInt32LittleEndian(leftover, remainderOffset) * _k3; tempA ^= RotateRight(tempA, 26) * _k1; remainderOffset += 4; @@ -394,7 +383,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 2) { - tempA += Endianness.ToUInt16LittleEndian(remainder, remainderOffset) * _k3; + tempA += Endianness.ToUInt16LittleEndian(leftover, remainderOffset) * _k3; tempA ^= RotateRight(tempA, 48) * _k1; remainderOffset += 2; @@ -403,7 +392,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (remainderCount >= 1) { - tempA += remainder[remainderOffset] * _k3; + tempA += leftover[remainderOffset] * _k3; tempA ^= RotateRight(tempA, 37) * _k1; } @@ -412,6 +401,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel tempA ^= RotateRight(tempA, 29); return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(tempA), 64); } diff --git a/HashifyNet/Algorithms/MurmurHash/MurmurHash1_Implementation.cs b/HashifyNet/Algorithms/MurmurHash/MurmurHash1_Implementation.cs index e0e0c72..9f49a61 100644 --- a/HashifyNet/Algorithms/MurmurHash/MurmurHash1_Implementation.cs +++ b/HashifyNet/Algorithms/MurmurHash/MurmurHash1_Implementation.cs @@ -63,24 +63,20 @@ public MurmurHash1_Implementation(IMurmurHash1Config config) _config = config.Clone(); } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var remainderCount = dataCount % 4; uint hashValue = (uint)_config.Seed ^ ((uint)dataCount * _m); // Process 4-byte groups { - var groupEndOffset = endOffset - remainderCount; + var groupEndOffset = dataCount - remainderCount; - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 4) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 4) { - hashValue += Endianness.ToUInt32LittleEndian(dataArray, currentOffset); + hashValue += Endianness.ToUInt32LittleEndian(data, currentOffset); hashValue *= _m; hashValue ^= hashValue >> 16; } @@ -89,14 +85,14 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance // Process remainder if (remainderCount > 0) { - var remainderOffset = endOffset - remainderCount; + var remainderOffset = dataCount - remainderCount; switch (remainderCount) { - case 3: hashValue += (uint)dataArray[remainderOffset + 2] << 16; goto case 2; - case 2: hashValue += (uint)dataArray[remainderOffset + 1] << 8; goto case 1; + case 3: hashValue += (uint)data[remainderOffset + 2] << 16; goto case 2; + case 2: hashValue += (uint)data[remainderOffset + 1] << 8; goto case 1; case 1: - hashValue += dataArray[remainderOffset]; + hashValue += data[remainderOffset]; break; } ; @@ -112,8 +108,9 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance hashValue ^= hashValue >> 17; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 32); } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/MurmurHash/MurmurHash2_Implementation.cs b/HashifyNet/Algorithms/MurmurHash/MurmurHash2_Implementation.cs index d29d984..385fb5d 100644 --- a/HashifyNet/Algorithms/MurmurHash/MurmurHash2_Implementation.cs +++ b/HashifyNet/Algorithms/MurmurHash/MurmurHash2_Implementation.cs @@ -74,7 +74,7 @@ public MurmurHash2_Implementation(IMurmurHash2Config config) } } - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { switch (_config.HashSizeInBits) { @@ -89,24 +89,20 @@ protected override IHashValue ComputeHashInternal(ArraySegment data, Cance } } - protected IHashValue ComputeHash32(ArraySegment data, CancellationToken cancellationToken) + protected IHashValue ComputeHash32(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var remainderCount = dataCount % 4; uint hashValue = (uint)_config.Seed ^ (uint)dataCount; // Process 4-byte groups { - var groupEndOffset = endOffset - remainderCount; + var groupEndOffset = dataCount - remainderCount; - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 4) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 4) { - uint k = Endianness.ToUInt32LittleEndian(dataArray, currentOffset); + uint k = Endianness.ToUInt32LittleEndian(data, currentOffset); k *= _mixConstant32; k ^= k >> 24; @@ -120,14 +116,14 @@ protected IHashValue ComputeHash32(ArraySegment data, CancellationToken ca // Process remainder if (remainderCount > 0) { - var remainderOffset = endOffset - remainderCount; + var remainderOffset = dataCount - remainderCount; switch (remainderCount) { - case 3: hashValue ^= (uint)dataArray[remainderOffset + 2] << 16; goto case 2; - case 2: hashValue ^= (uint)dataArray[remainderOffset + 1] << 8; goto case 1; + case 3: hashValue ^= (uint)data[remainderOffset + 2] << 16; goto case 2; + case 2: hashValue ^= (uint)data[remainderOffset + 1] << 8; goto case 1; case 1: - hashValue ^= dataArray[remainderOffset]; + hashValue ^= data[remainderOffset]; break; } ; @@ -140,28 +136,25 @@ protected IHashValue ComputeHash32(ArraySegment data, CancellationToken ca hashValue ^= hashValue >> 15; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 32); } - protected IHashValue ComputeHash64(ArraySegment data, CancellationToken cancellationToken) + protected IHashValue ComputeHash64(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var remainderCount = dataCount % 8; ulong hashValue = (ulong)_config.Seed ^ ((ulong)dataCount * _mixConstant64); // Process 8-byte groups { - var groupEndOffset = endOffset - remainderCount; + var groupEndOffset = dataCount - remainderCount; - for (var currentOffset = dataOffset; currentOffset < groupEndOffset; currentOffset += 8) + for (var currentOffset = 0; currentOffset < groupEndOffset; currentOffset += 8) { - ulong k = Endianness.ToUInt64LittleEndian(dataArray, currentOffset); + ulong k = Endianness.ToUInt64LittleEndian(data, currentOffset); k *= _mixConstant64; k ^= k >> 47; @@ -175,21 +168,21 @@ protected IHashValue ComputeHash64(ArraySegment data, CancellationToken ca // Process remainder if (remainderCount > 0) { - var remainderOffset = endOffset - remainderCount; + var remainderOffset = dataCount - remainderCount; switch (remainderCount) { - case 7: hashValue ^= (ulong)dataArray[remainderOffset + 6] << 48; goto case 6; - case 6: hashValue ^= (ulong)dataArray[remainderOffset + 5] << 40; goto case 5; - case 5: hashValue ^= (ulong)dataArray[remainderOffset + 4] << 32; goto case 4; + case 7: hashValue ^= (ulong)data[remainderOffset + 6] << 48; goto case 6; + case 6: hashValue ^= (ulong)data[remainderOffset + 5] << 40; goto case 5; + case 5: hashValue ^= (ulong)data[remainderOffset + 4] << 32; goto case 4; case 4: - hashValue ^= Endianness.ToUInt32LittleEndian(dataArray, remainderOffset); + hashValue ^= Endianness.ToUInt32LittleEndian(data, remainderOffset); break; - case 3: hashValue ^= (ulong)dataArray[remainderOffset + 2] << 16; goto case 2; - case 2: hashValue ^= (ulong)dataArray[remainderOffset + 1] << 8; goto case 1; + case 3: hashValue ^= (ulong)data[remainderOffset + 2] << 16; goto case 2; + case 2: hashValue ^= (ulong)data[remainderOffset + 1] << 8; goto case 1; case 1: - hashValue ^= dataArray[remainderOffset]; + hashValue ^= data[remainderOffset]; break; } ; @@ -202,8 +195,9 @@ protected IHashValue ComputeHash64(ArraySegment data, CancellationToken ca hashValue ^= hashValue >> 47; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 64); } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/MurmurHash/MurmurHash3_Implementation.cs b/HashifyNet/Algorithms/MurmurHash/MurmurHash3_Implementation.cs index cfbeb9a..7ca2683 100644 --- a/HashifyNet/Algorithms/MurmurHash/MurmurHash3_Implementation.cs +++ b/HashifyNet/Algorithms/MurmurHash/MurmurHash3_Implementation.cs @@ -117,19 +117,14 @@ protected override void CopyStateTo(BlockTransformer32 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; - + var dataCount = data.Length; var tempHashValue = _hashValue; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 4) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 4) { - uint k1 = Endianness.ToUInt32LittleEndian(dataArray, currentOffset); + uint k1 = Endianness.ToUInt32LittleEndian(data, currentOffset); k1 *= c1_32; k1 = RotateLeft(k1, 15); @@ -145,11 +140,9 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - var remainderCount = (remainder?.Length).GetValueOrDefault(); - + var remainderCount = leftover.Length; var tempHashValue = _hashValue; var tempBytesProcessed = _bytesProcessed; @@ -160,10 +153,10 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel switch (remainderCount) { - case 3: k2 ^= (uint)remainder[2] << 16; goto case 2; - case 2: k2 ^= (uint)remainder[1] << 8; goto case 1; + case 3: k2 ^= (uint)leftover[2] << 16; goto case 2; + case 2: k2 ^= (uint)leftover[1] << 8; goto case 1; case 1: - k2 ^= remainder[0]; + k2 ^= leftover[0]; break; } @@ -179,6 +172,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Mix(ref tempHashValue); return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(tempHashValue), 32); } @@ -232,21 +226,17 @@ protected override void CopyStateTo(BlockTransformer128 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var tempHashValue1 = _hashValue1; var tempHashValue2 = _hashValue2; - for (var currentOffset = dataOffset; currentOffset < endOffset; currentOffset += 16) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 16) { - ulong k1 = Endianness.ToUInt64LittleEndian(dataArray, currentOffset); - ulong k2 = Endianness.ToUInt64LittleEndian(dataArray, currentOffset + 8); + ulong k1 = Endianness.ToUInt64LittleEndian(data, currentOffset); + ulong k2 = Endianness.ToUInt64LittleEndian(data, currentOffset + 8); k1 *= c1_128; k1 = RotateLeft(k1, 31); @@ -273,10 +263,9 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - var remainderCount = (remainder?.Length).GetValueOrDefault(); + var remainderCount = leftover.Length; var tempHashValue1 = _hashValue1; var tempHashValue2 = _hashValue2; @@ -290,14 +279,14 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel switch (remainderCount) { - case 15: k2 ^= (ulong)remainder[14] << 48; goto case 14; - case 14: k2 ^= (ulong)remainder[13] << 40; goto case 13; - case 13: k2 ^= (ulong)remainder[12] << 32; goto case 12; - case 12: k2 ^= (ulong)remainder[11] << 24; goto case 11; - case 11: k2 ^= (ulong)remainder[10] << 16; goto case 10; - case 10: k2 ^= (ulong)remainder[9] << 8; goto case 9; + case 15: k2 ^= (ulong)leftover[14] << 48; goto case 14; + case 14: k2 ^= (ulong)leftover[13] << 40; goto case 13; + case 13: k2 ^= (ulong)leftover[12] << 32; goto case 12; + case 12: k2 ^= (ulong)leftover[11] << 24; goto case 11; + case 11: k2 ^= (ulong)leftover[10] << 16; goto case 10; + case 10: k2 ^= (ulong)leftover[9] << 8; goto case 9; case 9: - k2 ^= remainder[8]; + k2 ^= leftover[8]; k2 *= c2_128; k2 = RotateLeft(k2, 33); k2 *= c1_128; @@ -306,17 +295,17 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel goto case 8; case 8: - k1 ^= Endianness.ToUInt64LittleEndian(remainder, 0); + k1 ^= Endianness.ToUInt64LittleEndian(leftover, 0); break; - case 7: k1 ^= (ulong)remainder[6] << 48; goto case 6; - case 6: k1 ^= (ulong)remainder[5] << 40; goto case 5; - case 5: k1 ^= (ulong)remainder[4] << 32; goto case 4; - case 4: k1 ^= (ulong)remainder[3] << 24; goto case 3; - case 3: k1 ^= (ulong)remainder[2] << 16; goto case 2; - case 2: k1 ^= (ulong)remainder[1] << 8; goto case 1; + case 7: k1 ^= (ulong)leftover[6] << 48; goto case 6; + case 6: k1 ^= (ulong)leftover[5] << 40; goto case 5; + case 5: k1 ^= (ulong)leftover[4] << 32; goto case 4; + case 4: k1 ^= (ulong)leftover[3] << 24; goto case 3; + case 3: k1 ^= (ulong)leftover[2] << 16; goto case 2; + case 2: k1 ^= (ulong)leftover[1] << 8; goto case 1; case 1: - k1 ^= remainder[0]; + k1 ^= leftover[0]; break; } @@ -344,7 +333,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel .Concat(Endianness.GetBytesLittleEndian(tempHashValue2)) .ToArray(); - return new HashValue(hashValueBytes, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, 128); } private static void Mix(ref ulong k) @@ -366,4 +355,4 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Pearson/Pearson_Implementation.cs b/HashifyNet/Algorithms/Pearson/Pearson_Implementation.cs index 8318dc7..a1acd0d 100644 --- a/HashifyNet/Algorithms/Pearson/Pearson_Implementation.cs +++ b/HashifyNet/Algorithms/Pearson/Pearson_Implementation.cs @@ -117,11 +117,9 @@ protected override void CopyStateTo(BlockTransformer other) } } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; + var dataCount = data.Length; var tempHashValue = _hashValue; var tempAnyBytesProcessed = _anyBytesProcessed; @@ -129,17 +127,17 @@ protected override void TransformByteGroupsInternal(ArraySegment data) var tempTable = _table; var tempHashValueLength = tempHashValue.Length; - for (var currentOffset = data.Offset; currentOffset < endOffset; ++currentOffset) + for (var currentOffset = 0; currentOffset < dataCount; ++currentOffset) { for (int y = 0; y < tempHashValueLength; ++y) { if (tempAnyBytesProcessed) { - tempHashValue[y] = tempTable[tempHashValue[y] ^ dataArray[currentOffset]]; + tempHashValue[y] = tempTable[tempHashValue[y] ^ data[currentOffset]]; } else { - tempHashValue[y] = tempTable[(dataArray[currentOffset] + y) & 0xff]; + tempHashValue[y] = tempTable[(data[currentOffset] + y) & 0xff]; } } @@ -149,10 +147,10 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _anyBytesProcessed = tempAnyBytesProcessed; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - return new HashValue(_hashValue, _hashValue.Length * 8); + return new HashValue(ValueEndianness.NotApplicable, _hashValue, _hashValue.Length * 8); } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/RapidHash/RapidHash_Implementation.cs b/HashifyNet/Algorithms/RapidHash/RapidHash_Implementation.cs index 145a6d3..f5a4444 100644 --- a/HashifyNet/Algorithms/RapidHash/RapidHash_Implementation.cs +++ b/HashifyNet/Algorithms/RapidHash/RapidHash_Implementation.cs @@ -114,18 +114,6 @@ public static ulong RapidMix(ulong a, ulong b) RapidMum(ref a, ref b); return a ^ b; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong RapidRead64(byte[] p, int offset) - { - return Endianness.ToUInt64LittleEndian(p, offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint RapidRead32(byte[] p, int offset) - { - return Endianness.ToUInt32LittleEndian(p, offset); - } } private class BlockTransformer_MMicro @@ -174,7 +162,9 @@ protected override void CopyStateTo(BlockTransformer_MMicro other) other._hasPendingBlock = _hasPendingBlock; if (_hasPendingBlock) + { Buffer.BlockCopy(_pendingBlock, 0, other._pendingBlock, 0, RAPID_BLOCK_SIZE); + } } private void ProcessBlock(byte[] p, int offset) @@ -183,51 +173,51 @@ private void ProcessBlock(byte[] p, int offset) _hasProcessedBlocks = true; _seed = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(p, offset) ^ RapidHashShared.Secret[0], - RapidHashShared.RapidRead64(p, offset + 8) ^ _seed); + Endianness.ToUInt64LittleEndian(p, offset) ^ RapidHashShared.Secret[0], + Endianness.ToUInt64LittleEndian(p, offset + 8) ^ _seed); _see1 = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(p, offset + 16) ^ RapidHashShared.Secret[1], - RapidHashShared.RapidRead64(p, offset + 24) ^ _see1); + Endianness.ToUInt64LittleEndian(p, offset + 16) ^ RapidHashShared.Secret[1], + Endianness.ToUInt64LittleEndian(p, offset + 24) ^ _see1); _see2 = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(p, offset + 32) ^ RapidHashShared.Secret[2], - RapidHashShared.RapidRead64(p, offset + 40) ^ _see2); + Endianness.ToUInt64LittleEndian(p, offset + 32) ^ RapidHashShared.Secret[2], + Endianness.ToUInt64LittleEndian(p, offset + 40) ^ _see2); _see3 = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(p, offset + 48) ^ RapidHashShared.Secret[3], - RapidHashShared.RapidRead64(p, offset + 56) ^ _see3); + Endianness.ToUInt64LittleEndian(p, offset + 48) ^ RapidHashShared.Secret[3], + Endianness.ToUInt64LittleEndian(p, offset + 56) ^ _see3); _see4 = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(p, offset + 64) ^ RapidHashShared.Secret[4], - RapidHashShared.RapidRead64(p, offset + 72) ^ _see4); + Endianness.ToUInt64LittleEndian(p, offset + 64) ^ RapidHashShared.Secret[4], + Endianness.ToUInt64LittleEndian(p, offset + 72) ^ _see4); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { + Span pendingBlock = _pendingBlock.AsSpan(); if (!_hasPendingBlock) { - Buffer.BlockCopy(data.Array, data.Offset, _pendingBlock, 0, RAPID_BLOCK_SIZE); + data.CopyTo(pendingBlock); _hasPendingBlock = true; } else { ProcessBlock(_pendingBlock, 0); - Buffer.BlockCopy(data.Array, data.Offset, _pendingBlock, 0, RAPID_BLOCK_SIZE); + data.CopyTo(pendingBlock); } - _totalLength += (ulong)data.Count; + _totalLength += (ulong)data.Length; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var tailSeg = new ArraySegment(FinalizeInputBuffer ?? Array.Empty()); - _totalLength += (ulong)tailSeg.Count; - byte[] remainderArray; + _totalLength += (ulong)leftover.Length; + ReadOnlySpan remainder; int pOffset; int i; - if (tailSeg.Count > 0) + if (leftover.Length > 0) { if (_hasPendingBlock) { @@ -235,20 +225,20 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel _hasPendingBlock = false; } - remainderArray = tailSeg.Array ?? Array.Empty(); - pOffset = tailSeg.Offset; - i = tailSeg.Count; + remainder = leftover; + pOffset = 0; + i = leftover.Length; } else if (_hasPendingBlock) { - remainderArray = _pendingBlock; + remainder = _pendingBlock.AsSpan(); pOffset = 0; i = RAPID_BLOCK_SIZE; // 80 // Do NOT call ProcessBlock on this pending block; it's the "i=80" tail. } else { - remainderArray = Array.Empty(); + remainder = ReadOnlySpan.Empty; pOffset = 0; i = 0; } @@ -264,19 +254,19 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel _seed ^= _totalLength; if (_totalLength >= 8) { - a = RapidHashShared.RapidRead64(remainderArray, pOffset); - b = RapidHashShared.RapidRead64(remainderArray, pOffset + i - 8); + a = Endianness.ToUInt64LittleEndian(remainder, pOffset); + b = Endianness.ToUInt64LittleEndian(remainder, pOffset + i - 8); } else { - a = RapidHashShared.RapidRead32(remainderArray, pOffset); - b = RapidHashShared.RapidRead32(remainderArray, pOffset + i - 4); + a = Endianness.ToUInt32LittleEndian(remainder, pOffset); + b = Endianness.ToUInt32LittleEndian(remainder, pOffset + i - 4); } } else if (_totalLength > 0) { - a = ((ulong)remainderArray[pOffset] << 45) | remainderArray[pOffset + i - 1]; - b = remainderArray[pOffset + (i >> 1)]; + a = ((ulong)remainder[pOffset] << 45) | remainder[pOffset + i - 1]; + b = remainder[pOffset + (i >> 1)]; } } else @@ -294,52 +284,55 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (i > 16) { _seed = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(remainderArray, pOffset) ^ RapidHashShared.Secret[2], - RapidHashShared.RapidRead64(remainderArray, pOffset + 8) ^ _seed); + Endianness.ToUInt64LittleEndian(remainder, pOffset) ^ RapidHashShared.Secret[2], + Endianness.ToUInt64LittleEndian(remainder, pOffset + 8) ^ _seed); if (i > 32) { _seed = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(remainderArray, pOffset + 16) ^ RapidHashShared.Secret[2], - RapidHashShared.RapidRead64(remainderArray, pOffset + 24) ^ _seed); + Endianness.ToUInt64LittleEndian(remainder, pOffset + 16) ^ RapidHashShared.Secret[2], + Endianness.ToUInt64LittleEndian(remainder, pOffset + 24) ^ _seed); if (i > 48) { _seed = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(remainderArray, pOffset + 32) ^ RapidHashShared.Secret[1], - RapidHashShared.RapidRead64(remainderArray, pOffset + 40) ^ _seed); + Endianness.ToUInt64LittleEndian(remainder, pOffset + 32) ^ RapidHashShared.Secret[1], + Endianness.ToUInt64LittleEndian(remainder, pOffset + 40) ^ _seed); if (i > 64) { _seed = RapidHashShared.RapidMix( - RapidHashShared.RapidRead64(remainderArray, pOffset + 48) ^ RapidHashShared.Secret[1], - RapidHashShared.RapidRead64(remainderArray, pOffset + 56) ^ _seed); + Endianness.ToUInt64LittleEndian(remainder, pOffset + 48) ^ RapidHashShared.Secret[1], + Endianness.ToUInt64LittleEndian(remainder, pOffset + 56) ^ _seed); } } } } - byte[] last16Bytes = new byte[16]; + Span last16Bytes = stackalloc byte[16]; if (i >= 16) { - Buffer.BlockCopy(remainderArray, pOffset + i - 16, last16Bytes, 0, 16); + remainder.Slice(pOffset + i - 16, 16).CopyTo(last16Bytes); } else { if (_hasProcessedBlocks) { int from_tail = 16 - i; - Buffer.BlockCopy(_tailBuffer, 16 - from_tail, last16Bytes, 0, from_tail); - if (i > 0) Buffer.BlockCopy(remainderArray, pOffset, last16Bytes, from_tail, i); + _tailBuffer.AsSpan(16 - from_tail, from_tail).CopyTo(last16Bytes); + if (i > 0) + { + remainder.Slice(pOffset, i).CopyTo(last16Bytes.Slice(from_tail, i)); + } } else { - Buffer.BlockCopy(remainderArray, pOffset, last16Bytes, 16 - i, i); + remainder.Slice(pOffset, i).CopyTo(last16Bytes.Slice(16 - i, i)); } } - a = RapidHashShared.RapidRead64(last16Bytes, 0) ^ length_to_mix; - b = RapidHashShared.RapidRead64(last16Bytes, 8); + a = Endianness.ToUInt64LittleEndian(last16Bytes, 0) ^ length_to_mix; + b = Endianness.ToUInt64LittleEndian(last16Bytes, 8); } a ^= RapidHashShared.Secret[1]; @@ -352,7 +345,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel byte[] result = new byte[8]; Endianness.ToLittleEndianBytes(finalHash, result, 0); - return new HashValue(result, 64); + return new HashValue(ValueEndianness.LittleEndian, result, 64); } } @@ -394,30 +387,31 @@ protected override void CopyStateTo(BlockTransformer_MNano other) Buffer.BlockCopy(_tailBuffer, 0, other._tailBuffer, 0, 16); } - private void ProcessBlock(byte[] p, int offset) + private void ProcessBlock(ReadOnlySpan p) { - Buffer.BlockCopy(p, offset + RAPID_BLOCK_SIZE - 16, _tailBuffer, 0, 16); + Span tailBuffer = _tailBuffer.AsSpan(); + p.Slice(RAPID_BLOCK_SIZE - 16, 16).CopyTo(tailBuffer); + _hasProcessedBlocks = true; - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset) ^ RapidHashShared.Secret[0], RapidHashShared.RapidRead64(p, offset + 8) ^ _seed); - _see1 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 16) ^ RapidHashShared.Secret[1], RapidHashShared.RapidRead64(p, offset + 24) ^ _see1); - _see2 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 32) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(p, offset + 40) ^ _see2); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 0) ^ RapidHashShared.Secret[0], Endianness.ToUInt64LittleEndian(p, 8) ^ _seed); + _see1 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 16) ^ RapidHashShared.Secret[1], Endianness.ToUInt64LittleEndian(p, 24) ^ _see1); + _see2 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 32) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(p, 40) ^ _see2); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - ProcessBlock(data.Array, data.Offset); - _totalLength += (ulong)data.Count; + ProcessBlock(data); + _totalLength += (ulong)data.Length; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - ArraySegment remainder = new ArraySegment(FinalizeInputBuffer ?? new byte[0]); - _totalLength += (ulong)remainder.Count; + _totalLength += (ulong)leftover.Length; ulong a = 0, b = 0; - int pOffset = remainder.Offset; - int i = remainder.Count; + int pOffset = 0; + int i = leftover.Length; ulong length_to_mix; if (_totalLength <= 16) @@ -428,19 +422,19 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel _seed ^= _totalLength; if (_totalLength >= 8) { - a = RapidHashShared.RapidRead64(remainder.Array, pOffset); - b = RapidHashShared.RapidRead64(remainder.Array, pOffset + i - 8); + a = Endianness.ToUInt64LittleEndian(leftover, pOffset); + b = Endianness.ToUInt64LittleEndian(leftover, pOffset + i - 8); } else { - a = RapidHashShared.RapidRead32(remainder.Array, pOffset); - b = RapidHashShared.RapidRead32(remainder.Array, pOffset + i - 4); + a = Endianness.ToUInt32LittleEndian(leftover, pOffset); + b = Endianness.ToUInt32LittleEndian(leftover, pOffset + i - 4); } } else if (_totalLength > 0) { - a = ((ulong)remainder.Array[pOffset] << 45) | remainder.Array[pOffset + i - 1]; - b = remainder.Array[pOffset + (i >> 1)]; + a = ((ulong)leftover[pOffset] << 45) | leftover[pOffset + i - 1]; + b = leftover[pOffset + (i >> 1)]; } } else @@ -454,34 +448,37 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (i > 16) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(remainder.Array, pOffset + 8) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(leftover, pOffset + 8) ^ _seed); if (i > 32) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 16) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(remainder.Array, pOffset + 24) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 16) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(leftover, pOffset + 24) ^ _seed); } } - byte[] last16Bytes = new byte[16]; + Span last16Bytes = stackalloc byte[16]; if (i >= 16) { - Buffer.BlockCopy(remainder.Array, pOffset + i - 16, last16Bytes, 0, 16); + leftover.Slice(pOffset + i - 16, 16).CopyTo(last16Bytes); } else { if (_hasProcessedBlocks) { int from_tail = 16 - i; - Buffer.BlockCopy(_tailBuffer, 16 - from_tail, last16Bytes, 0, from_tail); - if (i > 0) Buffer.BlockCopy(remainder.Array, pOffset, last16Bytes, from_tail, i); + _tailBuffer.AsSpan(16 - from_tail, from_tail).CopyTo(last16Bytes); + if (i > 0) + { + leftover.Slice(pOffset, i).CopyTo(last16Bytes.Slice(from_tail, i)); + } } else { - Buffer.BlockCopy(remainder.Array, pOffset, last16Bytes, 16 - i, i); + leftover.Slice(pOffset, i).CopyTo(last16Bytes.Slice(16 - i, i)); } } - a = RapidHashShared.RapidRead64(last16Bytes, 0) ^ (ulong)i; - b = RapidHashShared.RapidRead64(last16Bytes, 8); + a = Endianness.ToUInt64LittleEndian(last16Bytes, 0) ^ (ulong)i; + b = Endianness.ToUInt64LittleEndian(last16Bytes, 8); } a ^= RapidHashShared.Secret[1]; @@ -493,7 +490,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel byte[] result = new byte[8]; Endianness.ToLittleEndianBytes(finalHash, result, 0); - return new HashValue(result, 64); + return new HashValue(ValueEndianness.LittleEndian, result, 64); } } @@ -543,34 +540,35 @@ protected override void CopyStateTo(BlockTransformer_MOriginal other) Buffer.BlockCopy(_tailBuffer, 0, other._tailBuffer, 0, 16); } - private void ProcessBlock(byte[] p, int offset) + private void ProcessBlock(ReadOnlySpan p) { - Buffer.BlockCopy(p, offset + RAPID_BLOCK_SIZE - 16, _tailBuffer, 0, 16); + Span tailBuffer = _tailBuffer.AsSpan(); + p.Slice(RAPID_BLOCK_SIZE - 16, 16).CopyTo(tailBuffer); + _hasProcessedBlocks = true; - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset) ^ RapidHashShared.Secret[0], RapidHashShared.RapidRead64(p, offset + 8) ^ _seed); - _see1 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 16) ^ RapidHashShared.Secret[1], RapidHashShared.RapidRead64(p, offset + 24) ^ _see1); - _see2 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 32) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(p, offset + 40) ^ _see2); - _see3 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 48) ^ RapidHashShared.Secret[3], RapidHashShared.RapidRead64(p, offset + 56) ^ _see3); - _see4 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 64) ^ RapidHashShared.Secret[4], RapidHashShared.RapidRead64(p, offset + 72) ^ _see4); - _see5 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 80) ^ RapidHashShared.Secret[5], RapidHashShared.RapidRead64(p, offset + 88) ^ _see5); - _see6 = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(p, offset + 96) ^ RapidHashShared.Secret[6], RapidHashShared.RapidRead64(p, offset + 104) ^ _see6); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 0) ^ RapidHashShared.Secret[0], Endianness.ToUInt64LittleEndian(p, 8) ^ _seed); + _see1 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 16) ^ RapidHashShared.Secret[1], Endianness.ToUInt64LittleEndian(p, 24) ^ _see1); + _see2 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 32) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(p, 40) ^ _see2); + _see3 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 48) ^ RapidHashShared.Secret[3], Endianness.ToUInt64LittleEndian(p, 56) ^ _see3); + _see4 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 64) ^ RapidHashShared.Secret[4], Endianness.ToUInt64LittleEndian(p, 72) ^ _see4); + _see5 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 80) ^ RapidHashShared.Secret[5], Endianness.ToUInt64LittleEndian(p, 88) ^ _see5); + _see6 = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(p, 96) ^ RapidHashShared.Secret[6], Endianness.ToUInt64LittleEndian(p, 104) ^ _see6); } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - ProcessBlock(data.Array, data.Offset); - _totalLength += (ulong)data.Count; + ProcessBlock(data); + _totalLength += (ulong)data.Length; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - ArraySegment remainder = new ArraySegment(FinalizeInputBuffer ?? new byte[0]); - _totalLength += (ulong)remainder.Count; + _totalLength += (ulong)leftover.Length; ulong a = 0, b = 0; - int pOffset = remainder.Offset; - int i = remainder.Count; + int pOffset = 0; + int i = leftover.Length; ulong length_to_mix; if (_totalLength <= 16) @@ -581,19 +579,19 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel _seed ^= _totalLength; if (_totalLength >= 8) { - a = RapidHashShared.RapidRead64(remainder.Array, pOffset); - b = RapidHashShared.RapidRead64(remainder.Array, pOffset + i - 8); + a = Endianness.ToUInt64LittleEndian(leftover, pOffset); + b = Endianness.ToUInt64LittleEndian(leftover, pOffset + i - 8); } else { - a = RapidHashShared.RapidRead32(remainder.Array, pOffset); - b = RapidHashShared.RapidRead32(remainder.Array, pOffset + i - 4); + a = Endianness.ToUInt32LittleEndian(leftover, pOffset); + b = Endianness.ToUInt32LittleEndian(leftover, pOffset + i - 4); } } else if (_totalLength > 0) { - a = ((ulong)remainder.Array[pOffset] << 45) | remainder.Array[pOffset + i - 1]; - b = remainder.Array[pOffset + (i >> 1)]; + a = ((ulong)leftover[pOffset] << 45) | leftover[pOffset + i - 1]; + b = leftover[pOffset + (i >> 1)]; } } else @@ -611,22 +609,22 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel if (i > 16) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(remainder.Array, pOffset + 8) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(leftover, pOffset + 8) ^ _seed); if (i > 32) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 16) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(remainder.Array, pOffset + 24) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 16) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(leftover, pOffset + 24) ^ _seed); if (i > 48) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 32) ^ RapidHashShared.Secret[1], RapidHashShared.RapidRead64(remainder.Array, pOffset + 40) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 32) ^ RapidHashShared.Secret[1], Endianness.ToUInt64LittleEndian(leftover, pOffset + 40) ^ _seed); if (i > 64) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 48) ^ RapidHashShared.Secret[1], RapidHashShared.RapidRead64(remainder.Array, pOffset + 56) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 48) ^ RapidHashShared.Secret[1], Endianness.ToUInt64LittleEndian(leftover, pOffset + 56) ^ _seed); if (i > 80) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 64) ^ RapidHashShared.Secret[2], RapidHashShared.RapidRead64(remainder.Array, pOffset + 72) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 64) ^ RapidHashShared.Secret[2], Endianness.ToUInt64LittleEndian(leftover, pOffset + 72) ^ _seed); if (i > 96) { - _seed = RapidHashShared.RapidMix(RapidHashShared.RapidRead64(remainder.Array, pOffset + 80) ^ RapidHashShared.Secret[1], RapidHashShared.RapidRead64(remainder.Array, pOffset + 88) ^ _seed); + _seed = RapidHashShared.RapidMix(Endianness.ToUInt64LittleEndian(leftover, pOffset + 80) ^ RapidHashShared.Secret[1], Endianness.ToUInt64LittleEndian(leftover, pOffset + 88) ^ _seed); } } } @@ -634,28 +632,31 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel } } - byte[] last16Bytes = new byte[16]; + Span last16Bytes = stackalloc byte[16]; if (i >= 16) { - Buffer.BlockCopy(remainder.Array, pOffset + i - 16, last16Bytes, 0, 16); + leftover.Slice(pOffset + i - 16, 16).CopyTo(last16Bytes); } else { if (_hasProcessedBlocks) { int from_tail = 16 - i; - Buffer.BlockCopy(_tailBuffer, 16 - from_tail, last16Bytes, 0, from_tail); - if (i > 0) Buffer.BlockCopy(remainder.Array, pOffset, last16Bytes, from_tail, i); + _tailBuffer.AsSpan(16 - from_tail, from_tail).CopyTo(last16Bytes); + if (i > 0) + { + leftover.Slice(pOffset, i).CopyTo(last16Bytes.Slice(from_tail, i)); + } } else { // This branch is unreachable if _totalLength > 16, but kept for safety. - Buffer.BlockCopy(remainder.Array, pOffset, last16Bytes, 16 - i, i); + leftover.Slice(pOffset, i).CopyTo(last16Bytes.Slice(16 - i, i)); } } - a = RapidHashShared.RapidRead64(last16Bytes, 0) ^ (ulong)i; - b = RapidHashShared.RapidRead64(last16Bytes, 8); + a = Endianness.ToUInt64LittleEndian(last16Bytes, 0) ^ (ulong)i; + b = Endianness.ToUInt64LittleEndian(last16Bytes, 8); } a ^= RapidHashShared.Secret[1]; @@ -667,9 +668,8 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel byte[] result = new byte[8]; Endianness.ToLittleEndianBytes(finalHash, result, 0); - return new HashValue(result, 64); + return new HashValue(ValueEndianness.LittleEndian, result, 64); } } } - -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/SM3/SM3_Implementation.cs b/HashifyNet/Algorithms/SM3/SM3_Implementation.cs index 7f91164..c71b406 100644 --- a/HashifyNet/Algorithms/SM3/SM3_Implementation.cs +++ b/HashifyNet/Algorithms/SM3/SM3_Implementation.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -103,20 +103,19 @@ protected override void CopyStateTo(BlockTransformer other) other._messageLength = _messageLength; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - _messageLength += data.Count; - ProcessBlock(data.Array, data.Offset); + _messageLength += data.Length; + ProcessBlock(data); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - byte[] remainder = FinalizeInputBuffer ?? Array.Empty(); - byte[] finalBlock = CreatePaddedBlock(remainder); + ReadOnlySpan finalBlock = CreatePaddedBlock(leftover); for (int i = 0; i < finalBlock.Length; i += 64) { - ProcessBlock(finalBlock, i); + ProcessBlock(finalBlock.Slice(i, 64)); } byte[] hash = new byte[32]; @@ -126,35 +125,34 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Buffer.BlockCopy(wordBytes, 0, hash, i * 4, 4); } - return new HashValue(hash, 256); + return new HashValue(ValueEndianness.BigEndian, hash, 256); } - private byte[] CreatePaddedBlock(byte[] remainder) + private ReadOnlySpan CreatePaddedBlock(ReadOnlySpan remainder) { long totalBits = (_messageLength + remainder.Length) * 8; int remainderLen = remainder.Length; int paddingLen = (remainderLen < 56) ? (56 - remainderLen) : (120 - remainderLen); - byte[] padded = new byte[remainderLen + paddingLen + 8]; - - Buffer.BlockCopy(remainder, 0, padded, 0, remainderLen); + Span padded = new Span(new byte[remainderLen + paddingLen + 8]); + remainder.CopyTo(padded.Slice(0, remainderLen)); padded[remainderLen] = 0x80; byte[] lengthBytes = Endianness.GetBytesBigEndian((ulong)totalBits); - Buffer.BlockCopy(lengthBytes, 0, padded, padded.Length - 8, 8); + lengthBytes.AsSpan().CopyTo(padded.Slice(padded.Length - 8, 8)); return padded; } - private void ProcessBlock(byte[] block, int offset) + private void ProcessBlock(ReadOnlySpan block) { uint[] W = new uint[68]; uint[] W_prime = new uint[64]; for (int i = 0; i < 16; i++) { - W[i] = Endianness.ToUInt32BigEndian(block, offset + (i * 4)); + W[i] = Endianness.ToUInt32BigEndian(block, i * 4); } for (int j = 16; j < 68; j++) diff --git a/HashifyNet/Algorithms/SipHash/SipHash_Implementation.cs b/HashifyNet/Algorithms/SipHash/SipHash_Implementation.cs index 158effa..de667b3 100644 --- a/HashifyNet/Algorithms/SipHash/SipHash_Implementation.cs +++ b/HashifyNet/Algorithms/SipHash/SipHash_Implementation.cs @@ -125,15 +125,15 @@ protected override void CopyStateTo(BlockTransformer other) other._messageLength = _messageLength; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - if (data.Count != 8) + if (data.Length != 8) { throw new InvalidOperationException("Expected 8 bytes per byte group."); } - _messageLength += (ulong)data.Count; - ulong m = Endianness.ToUInt64LittleEndian(data.Array, data.Offset); + _messageLength += (ulong)data.Length; + ulong m = Endianness.ToUInt64LittleEndian(data, 0); _v3 ^= m; for (int i = 0; i < _cRounds; ++i) @@ -143,20 +143,16 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _v0 ^= m; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - int remainderCount = remainder?.Length ?? 0; + int remainderCount = leftover.Length; _messageLength += (ulong)remainderCount; // Pad the final block with zeros and append message length ulong finalBlock = _messageLength << 56; - if (remainder != null) + for (int i = 0; i < remainderCount; ++i) { - for (int i = 0; i < remainderCount; ++i) - { - finalBlock |= (ulong)remainder[i] << (i * 8); - } + finalBlock |= (ulong)leftover[i] << (i * 8); } cancellationToken.ThrowIfCancellationRequested(); @@ -179,7 +175,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel ulong finalHash = _v0 ^ _v1 ^ _v2 ^ _v3; var hashValueBytes = Endianness.GetBytesLittleEndian(finalHash); - return new HashValue(hashValueBytes, 64); + return new HashValue(ValueEndianness.LittleEndian, hashValueBytes, 64); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -211,4 +207,4 @@ private static ulong RotateLeft(ulong value, int bits) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs b/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs index 43bc574..0a30aa4 100644 --- a/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs +++ b/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs @@ -31,7 +31,6 @@ using HashifyNet.Core.Utilities; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; @@ -163,13 +162,12 @@ protected override void CopyStateTo(BlockTransformer other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { // Handle buffering for short hash if (_bytesProcessed < 192) { - var dataArray = data.Array; - var dataCount = data.Count; + var dataCount = data.Length; if (dataCount + _bytesProcessed < 192) { @@ -178,7 +176,8 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _shortHashBuffer = new byte[192]; } - Array.Copy(dataArray, data.Offset, _shortHashBuffer, _bytesProcessed, dataCount); + //Array.Copy(dataArray, data.Offset, _shortHashBuffer, _bytesProcessed, dataCount); + data.CopyTo(new Span(_shortHashBuffer, _bytesProcessed, dataCount)); _bytesProcessed += dataCount; return; @@ -186,8 +185,6 @@ protected override void TransformByteGroupsInternal(ArraySegment data) if (_shortHashBuffer != null) { - Debug.Assert(_bytesProcessed == 96 || _bytesProcessed == 192); - Mix(_hashValue, new ArraySegment(_shortHashBuffer, 0, _bytesProcessed)); _shortHashBuffer = null; @@ -195,30 +192,25 @@ protected override void TransformByteGroupsInternal(ArraySegment data) } Mix(_hashValue, data); - _bytesProcessed += data.Count; + _bytesProcessed += data.Length; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { // ShortHash if (_bytesProcessed < 192) { - return ComputeShortHashInternal(cancellationToken); + return ComputeShortHashInternal(leftover, cancellationToken); } var finalHashValue = _hashValue.ToArray(); var finalMixBuffer = new byte[96]; - var remainder = FinalizeInputBuffer; + var remainderCount = leftover.Length; - if (remainder != null) - { - var remainderCount = remainder.Length; + leftover.CopyTo(new Span(finalMixBuffer, 0, remainderCount)); - Array.Copy(remainder, 0, finalMixBuffer, 0, remainderCount); - - finalMixBuffer[95] = (byte)remainderCount; - } + finalMixBuffer[95] = (byte)remainderCount; Mix(finalHashValue, new ArraySegment(finalMixBuffer, 0, 96)); End(finalHashValue); @@ -227,11 +219,13 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel { case 32: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian((uint)finalHashValue[0]), 32); case 64: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(finalHashValue[0]), 64); @@ -244,14 +238,14 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Endianness.GetBytesLittleEndian(finalHashValue[1]) .CopyTo(hashValueResult, 8); - return new HashValue(hashValueResult, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueResult, 128); default: throw new NotImplementedException(); } } - private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) + private IHashValue ComputeShortHashInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var tempHashValue = new ulong[4] { _hashValue[0], @@ -264,7 +258,7 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) int dataCount; { var shortHashBufferLength = _bytesProcessed; - var finalizeInputBufferLength = (FinalizeInputBuffer?.Length).GetValueOrDefault(); + var finalizeInputBufferLength = leftover.Length; dataCount = shortHashBufferLength + finalizeInputBufferLength; @@ -274,12 +268,12 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) if (shortHashBufferLength > 0) { - Array.Copy(_shortHashBuffer, 0, dataArray, 0, shortHashBufferLength); + new Span(_shortHashBuffer, 0, shortHashBufferLength).CopyTo(new Span(dataArray, 0, shortHashBufferLength)); } if (finalizeInputBufferLength > 0) { - Array.Copy(FinalizeInputBuffer, 0, dataArray, shortHashBufferLength, finalizeInputBufferLength); + leftover.CopyTo(new Span(dataArray, shortHashBufferLength, finalizeInputBufferLength)); } } } @@ -350,11 +344,13 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) { case 32: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian((uint)tempHashValue[0]), 32); case 64: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(tempHashValue[0]), 64); @@ -368,6 +364,7 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) .CopyTo(finalHashValue, 8); return new HashValue( + ValueEndianness.LittleEndian, finalHashValue, 128); @@ -376,19 +373,15 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) } } - private static void Mix(ulong[] hashValue, ArraySegment data) + private static void Mix(ulong[] hashValue, ReadOnlySpan data) { - Debug.Assert(data.Count % 96 == 0); - - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; + var dataCount = data.Length; - for (var currentOffset = data.Offset; currentOffset < endOffset; currentOffset += 96) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 96) { for (var i = 0; i < 12; ++i) { - hashValue[i] += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + (i * 8)); + hashValue[i] += Endianness.ToUInt64LittleEndian(data, currentOffset + (i * 8)); hashValue[(i + 2) % 12] ^= hashValue[(i + 10) % 12]; hashValue[(i + 11) % 12] ^= hashValue[i]; hashValue[i] = RotateLeft(hashValue[i], _MixRotationParameters[i]); @@ -445,4 +438,4 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs b/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs index 3c65134..b0c5e06 100644 --- a/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs +++ b/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs @@ -31,7 +31,6 @@ using HashifyNet.Core.Utilities; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; @@ -159,13 +158,12 @@ protected override void CopyStateTo(BlockTransformer other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { // Handle buffering for short hash if (_bytesProcessed < 192) { - var dataArray = data.Array; - var dataCount = data.Count; + var dataCount = data.Length; if (dataCount + _bytesProcessed < 192) { @@ -174,7 +172,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _shortHashBuffer = new byte[192]; } - Array.Copy(dataArray, data.Offset, _shortHashBuffer, _bytesProcessed, dataCount); + data.CopyTo(new Span(_shortHashBuffer, _bytesProcessed, dataCount)); _bytesProcessed += dataCount; return; @@ -182,8 +180,6 @@ protected override void TransformByteGroupsInternal(ArraySegment data) if (_shortHashBuffer != null) { - Debug.Assert(_bytesProcessed == 96 || _bytesProcessed == 192); - Mix(_hashValue, new ArraySegment(_shortHashBuffer, 0, _bytesProcessed)); _shortHashBuffer = null; @@ -191,30 +187,25 @@ protected override void TransformByteGroupsInternal(ArraySegment data) } Mix(_hashValue, data); - _bytesProcessed += data.Count; + _bytesProcessed += data.Length; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { // ShortHash if (_bytesProcessed < 192) { - return ComputeShortHashInternal(cancellationToken); + return ComputeShortHashInternal(leftover, cancellationToken); } var finalHashValue = _hashValue.ToArray(); var finalMixBuffer = new byte[96]; - var remainder = FinalizeInputBuffer; + var remainderCount = leftover.Length; - if (remainder != null) - { - var remainderCount = remainder.Length; + leftover.CopyTo(finalMixBuffer.AsSpan(0, remainderCount)); - Array.Copy(remainder, 0, finalMixBuffer, 0, remainderCount); - - finalMixBuffer[95] = (byte)remainderCount; - } + finalMixBuffer[95] = (byte)remainderCount; End(finalHashValue, finalMixBuffer); @@ -222,11 +213,13 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel { case 32: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian((uint)finalHashValue[0]), 32); case 64: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(finalHashValue[0]), 64); @@ -239,14 +232,14 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel Endianness.GetBytesLittleEndian(finalHashValue[1]) .CopyTo(hashValueResult, 8); - return new HashValue(hashValueResult, 128); + return new HashValue(ValueEndianness.LittleEndian, hashValueResult, 128); default: throw new NotImplementedException(); } } - private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) + private IHashValue ComputeShortHashInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { var tempHashValue = new ulong[4] { _hashValue[0], @@ -259,7 +252,7 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) int dataCount; { var shortHashBufferLength = _bytesProcessed; - var finalizeInputBufferLength = (FinalizeInputBuffer?.Length).GetValueOrDefault(); + var finalizeInputBufferLength = leftover.Length; dataCount = shortHashBufferLength + finalizeInputBufferLength; @@ -269,12 +262,12 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) if (shortHashBufferLength > 0) { - Array.Copy(_shortHashBuffer, 0, dataArray, 0, shortHashBufferLength); + new Span(_shortHashBuffer, 0, shortHashBufferLength).CopyTo(new Span(dataArray, 0, shortHashBufferLength)); } if (finalizeInputBufferLength > 0) { - Array.Copy(FinalizeInputBuffer, 0, dataArray, shortHashBufferLength, finalizeInputBufferLength); + leftover.CopyTo(new Span(dataArray, shortHashBufferLength, finalizeInputBufferLength)); } } } @@ -342,11 +335,13 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) { case 32: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian((uint)tempHashValue[0]), 32); case 64: return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(tempHashValue[0]), 64); @@ -360,6 +355,7 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) .CopyTo(finalHashValue, 8); return new HashValue( + ValueEndianness.LittleEndian, finalHashValue, 128); @@ -368,19 +364,15 @@ private IHashValue ComputeShortHashInternal(CancellationToken cancellationToken) } } - private static void Mix(ulong[] hashValue, ArraySegment data) + private static void Mix(ulong[] hashValue, ReadOnlySpan data) { - Debug.Assert(data.Count % 96 == 0); - - var dataArray = data.Array; - var dataCount = data.Count; - var endOffset = data.Offset + dataCount; + var dataCount = data.Length; - for (var currentOffset = data.Offset; currentOffset < endOffset; currentOffset += 96) + for (var currentOffset = 0; currentOffset < dataCount; currentOffset += 96) { for (var i = 0; i < 12; ++i) { - hashValue[i] += Endianness.ToUInt64LittleEndian(dataArray, currentOffset + (i * 8)); + hashValue[i] += Endianness.ToUInt64LittleEndian(data, currentOffset + (i * 8)); hashValue[(i + 2) % 12] ^= hashValue[(i + 10) % 12]; hashValue[(i + 11) % 12] ^= hashValue[i]; hashValue[i] = RotateLeft(hashValue[i], _MixRotationParameters[i]); @@ -442,4 +434,4 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Tiger/Tiger_Implementation.cs b/HashifyNet/Algorithms/Tiger/Tiger_Implementation.cs index a2cee5e..0dd0bc4 100644 --- a/HashifyNet/Algorithms/Tiger/Tiger_Implementation.cs +++ b/HashifyNet/Algorithms/Tiger/Tiger_Implementation.cs @@ -113,31 +113,25 @@ protected override void CopyStateTo(BlockTransformer other) other._messageLength = _messageLength; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - if (data.Count != 64) - { - throw new InvalidOperationException("Expected 64 bytes per byte group."); - } - - _messageLength += (ulong)data.Count; + _messageLength += (ulong)data.Length; var block = new ulong[8]; for (int i = 0; i < 8; i++) { - block[i] = Endianness.ToUInt64LittleEndian(data.Array, data.Offset + (i * 8)); + block[i] = Endianness.ToUInt64LittleEndian(data, i * 8); } ProcessBlock(block); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer ?? Array.Empty(); - int remainderCount = remainder.Length; + int remainderCount = leftover.Length; ulong totalBytesProcessed = _messageLength + (ulong)remainderCount; var finalData = new byte[128]; - Buffer.BlockCopy(remainder, 0, finalData, 0, remainderCount); + leftover.CopyTo(finalData.AsSpan()); finalData[remainderCount] = _padding; @@ -181,10 +175,10 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel { var truncated = new byte[bytesNeeded]; Array.Copy(fullHash, 0, truncated, 0, bytesNeeded); - return new HashValue(truncated, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, truncated, _hashSizeInBits); } - return new HashValue(fullHash, 192); + return new HashValue(ValueEndianness.LittleEndian, fullHash, 192); } private void ProcessBlock(ulong[] x) @@ -531,4 +525,4 @@ private static class S } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/Whirlpool/Whirlpool_Implementation.cs b/HashifyNet/Algorithms/Whirlpool/Whirlpool_Implementation.cs index 19679be..860cc14 100644 --- a/HashifyNet/Algorithms/Whirlpool/Whirlpool_Implementation.cs +++ b/HashifyNet/Algorithms/Whirlpool/Whirlpool_Implementation.cs @@ -86,14 +86,9 @@ protected override void CopyStateTo(BlockTransformer other) other._processedBytes = _processedBytes; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - if (data.Count != 64) - { - throw new ArgumentException($"Data must be exactly 64 bytes for Whirlpool.", nameof(data)); - } - - _processedBytes += (ulong)data.Count; + _processedBytes += (ulong)data.Length; var block = new ulong[8]; for (int i = 0; i < 8; i++) @@ -101,17 +96,16 @@ protected override void TransformByteGroupsInternal(ArraySegment data) block[i] = 0; for (int j = 0; j < 8; j++) { - block[i] = (block[i] << 8) | data.Array[data.Offset + (i * 8) + j]; + block[i] = (block[i] << 8) | data[(i * 8) + j]; } } ProcessBlock(block); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - var remainder = FinalizeInputBuffer; - int remainderCount = remainder?.Length ?? 0; + int remainderCount = leftover.Length; int padIndex; if (remainderCount > 31) @@ -139,9 +133,10 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel var finalData = new byte[remainderCount + pad.Length]; if (remainderCount > 0) { - Buffer.BlockCopy(remainder, 0, finalData, 0, remainderCount); + leftover.CopyTo(finalData); } - Buffer.BlockCopy(pad, 0, finalData, remainderCount, pad.Length); + + pad.CopyTo(finalData.AsSpan(remainderCount)); for (int offset = 0; offset < finalData.Length; offset += 64) { @@ -166,7 +161,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel } } - return new HashValue(hashValueBytes, 512); + return new HashValue(ValueEndianness.BigEndian, hashValueBytes, 512); } private void ProcessBlock(ulong[] data) @@ -300,4 +295,4 @@ private static uint MaskWithReductionPolynomial(uint input) } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/XxHash/XxHash3_Implementation.cs b/HashifyNet/Algorithms/XxHash/XxHash3_Implementation.cs index 3d89cfe..3955b37 100644 --- a/HashifyNet/Algorithms/XxHash/XxHash3_Implementation.cs +++ b/HashifyNet/Algorithms/XxHash/XxHash3_Implementation.cs @@ -95,21 +95,18 @@ protected override void CopyStateTo(BlockTransformer3 other) other._hash = _hash; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - _hash.Append(data.AsSpan()); + _hash.Append(data); } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - Span last = FinalizeInputBuffer == null ? Span.Empty : FinalizeInputBuffer.AsSpan(); - _hash.Append(last); + _hash.Append(leftover); byte[] output = _hash.GetCurrentHash(); - return new HashValue(output, _hash.HashLengthInBytes * 8); + return new HashValue(ValueEndianness.BigEndian, output, _hash.HashLengthInBytes * 8); } } } - -} - +} \ No newline at end of file diff --git a/HashifyNet/Algorithms/XxHash/XxHash_Implementation.cs b/HashifyNet/Algorithms/XxHash/XxHash_Implementation.cs index d4ca6f1..4d7c88e 100644 --- a/HashifyNet/Algorithms/XxHash/XxHash_Implementation.cs +++ b/HashifyNet/Algorithms/XxHash/XxHash_Implementation.cs @@ -134,13 +134,9 @@ protected override void CopyStateTo(BlockTransformer32 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var tempA = _a; var tempB = _b; @@ -150,21 +146,21 @@ protected override void TransformByteGroupsInternal(ArraySegment data) var tempPrime0 = _primes32[0]; var tempPrime1 = _primes32[1]; - for (var currentIndex = dataOffset; currentIndex < endOffset; currentIndex += 16) + for (var currentIndex = 0; currentIndex < dataCount; currentIndex += 16) { - tempA += Endianness.ToUInt32LittleEndian(dataArray, currentIndex) * tempPrime1; + tempA += Endianness.ToUInt32LittleEndian(data, currentIndex) * tempPrime1; tempA = RotateLeft(tempA, 13); tempA *= tempPrime0; - tempB += Endianness.ToUInt32LittleEndian(dataArray, currentIndex + 4) * tempPrime1; + tempB += Endianness.ToUInt32LittleEndian(data, currentIndex + 4) * tempPrime1; tempB = RotateLeft(tempB, 13); tempB *= tempPrime0; - tempC += Endianness.ToUInt32LittleEndian(dataArray, currentIndex + 8) * tempPrime1; + tempC += Endianness.ToUInt32LittleEndian(data, currentIndex + 8) * tempPrime1; tempC = RotateLeft(tempC, 13); tempC *= tempPrime0; - tempD += Endianness.ToUInt32LittleEndian(dataArray, currentIndex + 12) * tempPrime1; + tempD += Endianness.ToUInt32LittleEndian(data, currentIndex + 12) * tempPrime1; tempD = RotateLeft(tempD, 13); tempD *= tempPrime0; } @@ -177,7 +173,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += (ulong)dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { uint hashValue; { @@ -191,8 +187,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel } } - var remainder = FinalizeInputBuffer; - var remainderLength = (remainder?.Length).GetValueOrDefault(); + var remainderLength = leftover.Length; hashValue += (uint)(_bytesProcessed + (ulong)remainderLength); @@ -204,7 +199,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel for (var currentOffset = 0; currentOffset < endOffset; currentOffset += 4) { - hashValue += Endianness.ToUInt32LittleEndian(remainder, currentOffset) * _primes32[2]; + hashValue += Endianness.ToUInt32LittleEndian(leftover, currentOffset) * _primes32[2]; hashValue = RotateLeft(hashValue, 17) * _primes32[3]; } } @@ -216,7 +211,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel for (var currentOffset = startOffset; currentOffset < endOffset; currentOffset += 1) { - hashValue += remainder[currentOffset] * _primes32[4]; + hashValue += leftover[currentOffset] * _primes32[4]; hashValue = RotateLeft(hashValue, 11) * _primes32[0]; } } @@ -229,6 +224,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel hashValue ^= hashValue >> 16; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 32); } @@ -294,13 +290,9 @@ protected override void CopyStateTo(BlockTransformer64 other) other._bytesProcessed = _bytesProcessed; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - var dataArray = data.Array; - var dataOffset = data.Offset; - var dataCount = data.Count; - - var endOffset = dataOffset + dataCount; + var dataCount = data.Length; var tempA = _a; var tempB = _b; @@ -310,21 +302,21 @@ protected override void TransformByteGroupsInternal(ArraySegment data) var tempPrime0 = _primes64[0]; var tempPrime1 = _primes64[1]; - for (var currentIndex = dataOffset; currentIndex < endOffset; currentIndex += 32) + for (var currentIndex = 0; currentIndex < dataCount; currentIndex += 32) { - tempA += Endianness.ToUInt64LittleEndian(dataArray, currentIndex) * tempPrime1; + tempA += Endianness.ToUInt64LittleEndian(data, currentIndex) * tempPrime1; tempA = RotateLeft(tempA, 31); tempA *= tempPrime0; - tempB += Endianness.ToUInt64LittleEndian(dataArray, currentIndex + 8) * tempPrime1; + tempB += Endianness.ToUInt64LittleEndian(data, currentIndex + 8) * tempPrime1; tempB = RotateLeft(tempB, 31); tempB *= tempPrime0; - tempC += Endianness.ToUInt64LittleEndian(dataArray, currentIndex + 16) * tempPrime1; + tempC += Endianness.ToUInt64LittleEndian(data, currentIndex + 16) * tempPrime1; tempC = RotateLeft(tempC, 31); tempC *= tempPrime0; - tempD += Endianness.ToUInt64LittleEndian(dataArray, currentIndex + 24) * tempPrime1; + tempD += Endianness.ToUInt64LittleEndian(data, currentIndex + 24) * tempPrime1; tempD = RotateLeft(tempD, 31); tempD *= tempPrime0; } @@ -337,7 +329,7 @@ protected override void TransformByteGroupsInternal(ArraySegment data) _bytesProcessed += (ulong)dataCount; } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { ulong hashValue; { @@ -388,17 +380,16 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel } } - var remainder = FinalizeInputBuffer; - var remainderLength = (remainder?.Length).GetValueOrDefault(); + var remainderLength = leftover.Length; hashValue += _bytesProcessed + (ulong)remainderLength; if (remainderLength > 0) { // In 8-byte chunks, process all full chunks - for (int x = 0; x < remainder.Length / 8; ++x) + for (int x = 0; x < leftover.Length / 8; ++x) { - hashValue ^= RotateLeft(Endianness.ToUInt64LittleEndian(remainder, x * 8) * _primes64[1], 31) * _primes64[0]; + hashValue ^= RotateLeft(Endianness.ToUInt64LittleEndian(leftover, x * 8) * _primes64[1], 31) * _primes64[0]; hashValue = (RotateLeft(hashValue, 27) * _primes64[0]) + _primes64[3]; } @@ -407,7 +398,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel { var startOffset = remainderLength - (remainderLength % 8); - hashValue ^= Endianness.ToUInt32LittleEndian(remainder, startOffset) * _primes64[0]; + hashValue ^= Endianness.ToUInt32LittleEndian(leftover, startOffset) * _primes64[0]; hashValue = (RotateLeft(hashValue, 23) * _primes64[1]) + _primes64[2]; } @@ -418,7 +409,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel for (var currentOffset = startOffset; currentOffset < endOffset; currentOffset += 1) { - hashValue ^= remainder[currentOffset] * _primes64[4]; + hashValue ^= leftover[currentOffset] * _primes64[4]; hashValue = RotateLeft(hashValue, 11) * _primes64[0]; } } @@ -431,6 +422,7 @@ protected override IHashValue FinalizeHashValueInternal(CancellationToken cancel hashValue ^= hashValue >> 32; return new HashValue( + ValueEndianness.LittleEndian, Endianness.GetBytesLittleEndian(hashValue), 64); } @@ -446,4 +438,3 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } - diff --git a/HashifyNet/Core/BlockTransformerBase.cs b/HashifyNet/Core/BlockTransformerBase.cs index c4b1efd..fa97c5e 100644 --- a/HashifyNet/Core/BlockTransformerBase.cs +++ b/HashifyNet/Core/BlockTransformerBase.cs @@ -28,7 +28,6 @@ // * using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -49,31 +48,29 @@ public abstract partial class BlockTransformerBase protected const int DefaultCancellationBatchSize = 4096; /// - /// The default block size to pass to . + /// The default block size to pass to . /// protected const int DefaultInputBlockSize = 1; - /// - /// The input buffer that should be fetched during the methods. - /// - protected byte[] FinalizeInputBuffer { get => _inputBuffer; } - private readonly int _cancellationBatchSize; private readonly int _inputBlockSize; - private byte[] _inputBuffer = null; + private readonly byte[] _leftover = null; + private int _leftoverCount = 0; private bool _isCorrupted = false; /// /// Construct with optional parameters to configure features. /// /// Maximum number of bytes to process before re-checking the cancellation token. - /// Block size to pass to . + /// Block size to pass to . protected BlockTransformerBase(int cancellationBatchSize = DefaultCancellationBatchSize, int inputBlockSize = DefaultInputBlockSize) { _cancellationBatchSize = cancellationBatchSize; _inputBlockSize = inputBlockSize; + _leftover = new byte[_inputBlockSize]; + // Ensure _cancellationBatchSize is a multiple of _inputBlockSize, preferrably rounding down. { var blockSizeRemainder = _cancellationBatchSize % _inputBlockSize; @@ -91,21 +88,17 @@ protected BlockTransformerBase(int cancellationBatchSize = DefaultCancellationBa } /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// - /// A previous transformation cancellation has resulted in an undefined internal state. + /// public void TransformBytes(byte[] data) => TransformBytes(data, CancellationToken.None); /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// A to cease processing of the provided data. - /// - /// The was canceled. - /// A previous transformation cancellation has resulted in an undefined internal state. + /// + /// + /// public void TransformBytes(byte[] data, CancellationToken cancellationToken) { ThrowIfCorrupted(); @@ -119,30 +112,24 @@ public void TransformBytes(byte[] data, CancellationToken cancellationToken) } /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// The offset from which to begin using the data. - /// The number of bytes to use as data. - /// - /// ;Offset must be a value greater than or equal to zero and less than the length of the array minus one. - /// ;Count must be a value greater than zero and less than the the remaining length of the array after the offset value. - /// A previous transformation cancellation has resulted in an undefined internal state. + /// + /// + /// public void TransformBytes(byte[] data, int offset, int count) => TransformBytes(data, 0, data.Length, CancellationToken.None); /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// The offset from which to begin using the data. - /// The number of bytes to use as data. - /// A to cease processing of the provided data. - /// - /// ;Offset must be a value greater than or equal to zero and less than the length of the array minus one. - /// ;Count must be a value greater than zero and less than the the remaining length of the array after the offset value. - /// The was canceled. - /// A previous transformation cancellation has resulted in an undefined internal state. + /// + /// + /// + /// + /// + /// + /// public void TransformBytes(byte[] data, int offset, int count, CancellationToken cancellationToken) { ThrowIfCorrupted(); @@ -167,68 +154,60 @@ public void TransformBytes(byte[] data, int offset, int count, CancellationToken throw new ArgumentOutOfRangeException(nameof(count), "Count must be a value greater than zero and less than the remaining length of the array after the offset value."); } - TransformBytes(new ArraySegment(data, offset, count), cancellationToken); + TransformBytes(new ReadOnlySpan(data, offset, count), cancellationToken); } /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// data must be an ArraySegment of Count > 0.; - /// A previous transformation cancellation has resulted in an undefined internal state. - public void TransformBytes(ArraySegment data) => + /// + public void TransformBytes(ReadOnlySpan data) => TransformBytes(data, CancellationToken.None); /// - /// Updates the internal state of this transformer with the given data. + /// /// - /// The data to process into this transformer's internal state. - /// A to cease processing of the provided data. - /// data must be an ArraySegment of Count > 0.; - /// The was canceled. - /// A previous transformation cancellation has resulted in an undefined internal state. - public void TransformBytes(ArraySegment data, CancellationToken cancellationToken) + /// + /// + /// + public void TransformBytes(ReadOnlySpan data, CancellationToken cancellationToken) { - if (data.Count == 0) + if (data.IsEmpty) { - throw new ArgumentException("data must be an ArraySegment of Count > 0.", nameof(data)); + throw new ArgumentException("data must point to a non-empty valid ReadOnlySpan.", nameof(data)); } TransformBytesInternal(data, cancellationToken); } /// - /// Completes any finalization processing and returns the resulting . + /// /// - /// Internal state will remain unmodified, therefore this method will not invalidate future calls to any other TransformBytes or FinalizeTransformation calls. - /// A previous transformation cancellation has resulted in an undefined internal state. + /// public IHashValue FinalizeHashValue() => FinalizeHashValue(CancellationToken.None); /// - /// Completes any finalization processing and returns the resulting . + /// /// - /// A to cease any final processing. - /// Internal state will remain unmodified, therefore this method will not invalidate future calls to any other TransformBytes or FinalizeTransformation calls. - /// The was canceled. - /// A previous transformation cancellation has resulted in an undefined internal state. + /// + /// public IHashValue FinalizeHashValue(CancellationToken cancellationToken) { ThrowIfCorrupted(); - return FinalizeHashValueInternal(cancellationToken); + return FinalizeHashValueInternal(FinalizeInputBuffer(), cancellationToken); } /// - /// Clones this transformer's internal state to a new, unassociated instance of this transformer. + /// /// - /// A new, unassociated instance of this transformer. + /// public IBlockTransformer Clone() { ThrowIfCorrupted(); var clone = new TSelf(); - CopyStateTo(clone); return clone; @@ -241,7 +220,10 @@ public IBlockTransformer Clone() /// All overriders should ensure base.CopyStateTo(other) is called. protected virtual void CopyStateTo(TSelf other) { - other._inputBuffer = _inputBuffer; + if (_leftover != null && _leftover.Length > 0) + { + Buffer.BlockCopy(_leftover, 0, other._leftover, 0, _leftoverCount); + } } /// @@ -269,100 +251,79 @@ protected void MarkSelfCorrupted() /// /// The data to process into this transformer's internal state. /// A to cease processing of the provided data. - protected void TransformBytesInternal(ArraySegment data, CancellationToken cancellationToken) + protected void TransformBytesInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - var dataArray = data.Array; - var dataCurrentOffset = data.Offset; - var dataRemainingCount = data.Count; - - var totalBytesToProcess = (_inputBuffer?.Length).GetValueOrDefault() + dataRemainingCount; - var processingRemainder = totalBytesToProcess % _inputBlockSize; - - // Determine how many bytes will inevitably be rolled over into the next input buffer and prepare that buffer. - byte[] nextInputBuffer = null; + try { - if (processingRemainder > 0) + if (_leftoverCount > 0) { - nextInputBuffer = new byte[processingRemainder]; + int fit = _inputBlockSize - _leftoverCount; - if (dataRemainingCount >= processingRemainder) + Span newLeftOverS = _leftover.AsSpan().Slice(_leftoverCount, fit); + if (data.Length >= fit) { - // All of the data can be fetched from newest data - var copyFromOffset = dataCurrentOffset + dataRemainingCount - processingRemainder; - - Array.Copy(dataArray, copyFromOffset, nextInputBuffer, 0, processingRemainder); - - dataRemainingCount -= processingRemainder; + ReadOnlySpan fill = data.Slice(0, fit); + fill.CopyTo(newLeftOverS); + TransformByteGroupsInternal(new ReadOnlySpan(_leftover, 0, _inputBlockSize)); + _leftoverCount = 0; + data = data.Slice(fit); + + // If no more data, return now. + if (data.IsEmpty) + { + return; + } } else { - var bytesRolledOver = 0; - - if (_inputBuffer != null) - { - Array.Copy(_inputBuffer, nextInputBuffer, _inputBuffer.Length); - - bytesRolledOver = _inputBuffer.Length; - } - - Array.Copy(dataArray, 0, nextInputBuffer, bytesRolledOver, processingRemainder - bytesRolledOver); - - dataRemainingCount = 0; + data.CopyTo(newLeftOverS); + _leftoverCount += data.Length; + return; } } - } - // Process the full groups available - if (dataRemainingCount > 0) - { - try + int bytesSinceLastCancelCheck = 0; + while (data.Length >= _inputBlockSize) { - if (_inputBuffer != null) - { - var overrideInputBuffer = new byte[_inputBlockSize]; - var dataBytesToRead = overrideInputBuffer.Length - _inputBuffer.Length; - - Array.Copy(_inputBuffer, overrideInputBuffer, _inputBuffer.Length); - Array.Copy(dataArray, dataCurrentOffset, overrideInputBuffer, _inputBuffer.Length, dataBytesToRead); - - dataCurrentOffset += dataBytesToRead; - dataRemainingCount -= dataBytesToRead; - - TransformByteGroupsInternal(new ArraySegment(overrideInputBuffer, 0, overrideInputBuffer.Length)); - } + ReadOnlySpan blockToProcess = data.Slice(0, _inputBlockSize); + TransformByteGroupsInternal(blockToProcess); - while (dataRemainingCount > 0) + bytesSinceLastCancelCheck += _inputBlockSize; + if (bytesSinceLastCancelCheck >= _cancellationBatchSize) { - if (((dataCurrentOffset - data.Offset) / _cancellationBatchSize) > (((dataCurrentOffset - data.Offset) - _inputBlockSize) / _cancellationBatchSize)) - { - if (dataCurrentOffset > data.Offset) - { - cancellationToken.ThrowIfCancellationRequested(); - } - } - - var bytesToProcess = Math.Min(dataRemainingCount, _inputBlockSize); - - TransformByteGroupsInternal(new ArraySegment(data.Array, dataCurrentOffset, bytesToProcess)); - - dataCurrentOffset += bytesToProcess; - dataRemainingCount -= bytesToProcess; + cancellationToken.ThrowIfCancellationRequested(); + bytesSinceLastCancelCheck = 0; } - // Ensure a single call at least to make sure no cancellation is requested. - cancellationToken.ThrowIfCancellationRequested(); - - Debug.Assert(dataRemainingCount == 0); + data = data.Slice(_inputBlockSize); } - catch (TaskCanceledException) + + // Ensure a single call at least to make sure no cancellation is requested. + cancellationToken.ThrowIfCancellationRequested(); + + if (data.Length > 0) { - MarkSelfCorrupted(); - throw; + data.CopyTo(_leftover); + _leftoverCount = data.Length; } } + catch (TaskCanceledException) + { + MarkSelfCorrupted(); + throw; + } + } + + private ReadOnlySpan FinalizeInputBuffer() + { + if (_leftoverCount < 1) + { + return ReadOnlySpan.Empty; + } - // Update input buffer - _inputBuffer = nextInputBuffer; + var result = new ReadOnlySpan(_leftover, 0, _leftoverCount); + _leftoverCount = 0; + return result; } /// @@ -371,15 +332,13 @@ protected void TransformBytesInternal(ArraySegment data, CancellationToken /// The data's size will be a multiple of the provided inputBlockSize in the constructor. /// /// The data to process into this transformer's internal state. - protected abstract void TransformByteGroupsInternal(ArraySegment data); + protected abstract void TransformByteGroupsInternal(ReadOnlySpan data); /// /// Completes any finalization processing and returns the resulting . /// /// Internal state will remain unmodified, therefore this method will not invalidate future calls to any other TransformBytes or FinalizeTransformation calls. /// A previous transformation cancellation has resulted in an undefined internal state. - protected abstract IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken); + protected abstract IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken); } - -} - +} \ No newline at end of file diff --git a/HashifyNet/Core/DataType/Base32/Base32Helper.cs b/HashifyNet/Core/DataType/Base32/Base32Helper.cs new file mode 100644 index 0000000..ae00ee6 --- /dev/null +++ b/HashifyNet/Core/DataType/Base32/Base32Helper.cs @@ -0,0 +1,89 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +using System.Text; + +namespace HashifyNet +{ + internal static class Base32Helper + { + public static string AsBase32String(byte[] data, Base32Variant variant) + { + string alphabet; + bool usePadding; + + switch (variant) + { + case Base32Variant.Crockford: + alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + usePadding = false; + break; + + case Base32Variant.Rfc4648: + alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + usePadding = true; + break; + + default: + throw new System.NotSupportedException($"Unsupported base32 variant '{variant}'."); + } + + var builder = new StringBuilder(); + int bitsRead = 0; + ulong buffer = 0; + + foreach (byte b in data) + { + buffer = (buffer << 8) | b; + bitsRead += 8; + + while (bitsRead >= 5) + { + int index = (int)(buffer >> (bitsRead - 5)) & 31; + builder.Append(alphabet[index]); + bitsRead -= 5; + } + } + + if (bitsRead > 0) + { + int index = (int)(buffer << (5 - bitsRead)) & 31; + builder.Append(alphabet[index]); + } + + if (usePadding) + { + int padding = (8 - (builder.Length % 8)) % 8; + builder.Append('=', padding); + } + + return builder.ToString(); + } + } +} diff --git a/HashifyNet/Core/DataType/Base32/Base32Variant.cs b/HashifyNet/Core/DataType/Base32/Base32Variant.cs new file mode 100644 index 0000000..dbd442c --- /dev/null +++ b/HashifyNet/Core/DataType/Base32/Base32Variant.cs @@ -0,0 +1,46 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +namespace HashifyNet +{ + /// + /// The variant of Base32 encoding to use. + /// + public enum Base32Variant + { + /// + /// The RFC 4648 variant, using the alphabet A-Z2-7 and padding with '='. + /// + Rfc4648, + /// + /// The Crockford variant, using the alphabet 0-9A-Z without padding. + /// + Crockford + } +} diff --git a/HashifyNet/Core/DataType/Base58/Base58Helper.cs b/HashifyNet/Core/DataType/Base58/Base58Helper.cs new file mode 100644 index 0000000..c77b0d7 --- /dev/null +++ b/HashifyNet/Core/DataType/Base58/Base58Helper.cs @@ -0,0 +1,101 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +using HashifyNet.Algorithms.Blake2; +using HashifyNet.Algorithms.SHA256; +using HashifyNet.Core.Utilities; +using System; +using System.Linq; +using System.Numerics; +using System.Text; + +namespace HashifyNet +{ + internal static class Base58Helper + { + public static string AsBase58String(byte[] data, Base58Variant variant) + { + _ = data ?? throw new ArgumentNullException(nameof(data)); + + string alphabet = GetAlphabet(variant); + char leadingZeroChar = alphabet[0]; + + byte[] lilEndianData = data.Reverse().ToArray(); + byte[] dataForBigInt = lilEndianData; + if (dataForBigInt.Length > 0 && (dataForBigInt[0] & 0x80) != 0) + { + dataForBigInt = new byte[lilEndianData.Length + 1]; + Array.Copy(lilEndianData, 0, dataForBigInt, 1, lilEndianData.Length); + dataForBigInt[0] = 0; + } + + var intData = new BigInteger(dataForBigInt); + var builder = new StringBuilder(); + + if (intData == 0) + { + builder.Append(leadingZeroChar); + } + + while (intData > 0) + { + intData = BigInteger.DivRem(intData, 58, out BigInteger remainder); + builder.Insert(0, alphabet[(int)remainder]); + } + + int leadingZeros = 0; + for (int i = 0; i < data.Length && data[i] == 0; i++) + { + leadingZeros++; + } + + for (int i = 0; i < leadingZeros; i++) + { + builder.Insert(0, leadingZeroChar); + } + + return builder.ToString(); + } + + private static string GetAlphabet(Base58Variant variant) + { + switch (variant) + { + case Base58Variant.Bitcoin: + return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + case Base58Variant.Flickr: + return "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; + case Base58Variant.Ripple: + return "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"; + default: + throw new NotSupportedException($"Unsupported base58 variant '{variant}'."); + } + } + } +} diff --git a/HashifyNet/Core/DataType/Base58/Base58Variant.cs b/HashifyNet/Core/DataType/Base58/Base58Variant.cs new file mode 100644 index 0000000..bb435ed --- /dev/null +++ b/HashifyNet/Core/DataType/Base58/Base58Variant.cs @@ -0,0 +1,53 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +namespace HashifyNet +{ + /// + /// A list of supported base58 variants. + /// + public enum Base58Variant + { + /// + /// The Bitcoin variant. + /// Alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz + /// + Bitcoin, + /// + /// The Flickr variant. + /// Alphabet: 123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ + /// + Flickr, + /// + /// The Ripple variant. + /// Alphabet: rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz + /// + Ripple + } +} diff --git a/HashifyNet/Core/DataType/Base85/Base85Helper.cs b/HashifyNet/Core/DataType/Base85/Base85Helper.cs new file mode 100644 index 0000000..9359a93 --- /dev/null +++ b/HashifyNet/Core/DataType/Base85/Base85Helper.cs @@ -0,0 +1,118 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +using System; +using System.Text; + +namespace HashifyNet +{ + internal static class Base85Helper + { + private const string Ascii85Alphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"; + private const string Z85Alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; + private const string Rfc1924Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; + + private static readonly uint[] Powers = { 52200625, 614125, 7225, 85, 1 }; + + public static string AsBase85String(byte[] data, Base85Variant variant) + { + if (data == null || data.Length == 0) + { + return variant == Base85Variant.AdobeAscii85 ? "<~~>" : ""; + } + + var builder = new StringBuilder(); + string alphabet = GetAlphabet(variant); + int dataIndex = 0; + + while (dataIndex + 3 < data.Length) + { + uint value = ((uint)data[dataIndex++] << 24) | + ((uint)data[dataIndex++] << 16) | + ((uint)data[dataIndex++] << 8) | + data[dataIndex++]; + + if (value == 0 && (variant == Base85Variant.Ascii85 || variant == Base85Variant.AdobeAscii85)) + { + builder.Append('z'); + continue; + } + + for (int i = 0; i < 5; i++) + { + builder.Append(alphabet[(int)(value / Powers[i] % 85)]); + } + } + + int remainingBytes = data.Length - dataIndex; + if (remainingBytes > 0) + { + uint value = 0; + for (int i = 0; i < remainingBytes; i++) + { + value |= (uint)data[dataIndex + i] << (24 - (i * 8)); + } + + var finalChars = new char[5]; + for (int i = 0; i < 5; i++) + { + finalChars[i] = alphabet[(int)(value / Powers[i] % 85)]; + } + + for (int i = 0; i < remainingBytes + 1; i++) + { + builder.Append(finalChars[i]); + } + } + + if (variant == Base85Variant.AdobeAscii85) + { + return $"<~{builder.ToString()}~>"; + } + + return builder.ToString(); + } + + private static string GetAlphabet(Base85Variant variant) + { + switch (variant) + { + case Base85Variant.Ascii85: + case Base85Variant.AdobeAscii85: + return Ascii85Alphabet; + case Base85Variant.Z85: + return Z85Alphabet; + case Base85Variant.Rfc1924: + return Rfc1924Alphabet; + default: + throw new ArgumentException("Unsupported Base85 variant.", nameof(variant)); + } + } + } +} diff --git a/HashifyNet/Core/DataType/Base85/Base85Variant.cs b/HashifyNet/Core/DataType/Base85/Base85Variant.cs new file mode 100644 index 0000000..edd1a32 --- /dev/null +++ b/HashifyNet/Core/DataType/Base85/Base85Variant.cs @@ -0,0 +1,64 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +namespace HashifyNet +{ + /// + /// Specifies the supported Base85 encoding variants. + /// + /// Base85 encoding is a binary-to-text encoding scheme that represents binary data in an ASCII-safe + /// format. This enumeration defines the available variants of Base85 encoding, each with its own specific use case and + /// encoding rules: The Adobe standard used + /// in PostScript and PDF, with '<~' and '~>' delimiters. The ZeroMQ standard (RFC 32/Z85), designed to be safe for inclusion in source + /// code. The variant defined in RFC 1924, + /// originally created for encoding IPv6 addresses. + public enum Base85Variant + { + /// + /// The default Base85 encoding variant. + /// + Ascii85, + + /// + /// The Adobe standard used in PostScript and PDF, with '<~' and '~>' delimiters. + /// + AdobeAscii85, + + /// + /// The ZeroMQ standard (RFC 32/Z85), designed to be safe for source code. + /// + Z85, + + /// + /// The standard defined in RFC 1924, originally for IPv6 addresses. + /// + Rfc1924 + } +} diff --git a/HashifyNet/Core/DataType/EncodedHashValue.cs b/HashifyNet/Core/DataType/EncodedHashValue.cs index 69592ae..cbea5e6 100644 --- a/HashifyNet/Core/DataType/EncodedHashValue.cs +++ b/HashifyNet/Core/DataType/EncodedHashValue.cs @@ -49,11 +49,12 @@ public sealed class EncodedHashValue /// /// Initializes a new instance of the class with an encoded hash value and its bit length. /// + /// The endianness of the hash value. /// The encoded hash value as a sequence of bytes. /// The function to be called for decoding the encoded hash into a string. /// The hash value as a sequence of bytes. /// The length of the hash value in bits. - public EncodedHashValue(IEnumerable encodedHash, Func, string> decodeOp, IEnumerable actualHash, int bitLength) : base(actualHash, bitLength) + public EncodedHashValue(ValueEndianness endianness, IEnumerable encodedHash, Func, string> decodeOp, IEnumerable actualHash, int bitLength) : base(endianness, actualHash, bitLength) { _ = encodedHash ?? throw new ArgumentNullException(nameof(encodedHash)); _decodeOp = decodeOp ?? throw new ArgumentNullException(nameof(decodeOp)); @@ -78,7 +79,7 @@ public string Decode() public override IHashValue Coerce(int bitLength) { IHashValue val = base.Coerce(bitLength); - return new EncodedHashValue(EncodedHash, _decodeOp, val.AsByteArray(), bitLength); + return new EncodedHashValue(Endianness, EncodedHash, _decodeOp, val.AsByteArray(), bitLength); } } } \ No newline at end of file diff --git a/HashifyNet/Core/DataType/HashValue.cs b/HashifyNet/Core/DataType/HashValue.cs index 90553c5..63fcad2 100644 --- a/HashifyNet/Core/DataType/HashValue.cs +++ b/HashifyNet/Core/DataType/HashValue.cs @@ -34,6 +34,7 @@ using System.Linq; using System.Numerics; using System.Text; +using EndianHelper = HashifyNet.Core.Utilities.Endianness; namespace HashifyNet.Core.Utilities { @@ -55,20 +56,18 @@ public class HashValue /// /// /// - public int BitLength { get; } + public ValueEndianness Endianness { get; } /// - /// Creates a new instance of the class that is a representation of a hash value and its bit length computed by a hasher. + /// /// - /// The hash computed by a hasher. - /// The expected bit length of the given . - /// Thrown if the given hash is . - /// Thrown if the parameter is smaller than 1. - public HashValue(IEnumerable hash, int bitLength) + public int BitLength { get; } + + private HashValue(ValueEndianness endianness, ImmutableArray hash, int bitLength) { - if (hash == null) + if (hash.IsDefaultOrEmpty) { - throw new ArgumentNullException(nameof(hash)); + throw new ArgumentException("Expected a valid populated immutable array containing the hash result, got an empty or default ImmutableArray instance.", nameof(hash)); } if (bitLength < 1) @@ -76,14 +75,53 @@ public HashValue(IEnumerable hash, int bitLength) throw new ArgumentOutOfRangeException(nameof(bitLength), $"{nameof(bitLength)} must be greater than or equal to 1."); } - ImmutableArray immutableHash = hash.ToImmutableArray(); - if (immutableHash.Length != (bitLength + 7) / 8) + if (hash.Length != (bitLength + 7) / 8) { - throw new ArgumentOutOfRangeException(nameof(hash), $"The length of {nameof(hash)} in bits must be equal to {nameof(bitLength)}. Bytes: {immutableHash.Length} Expected: {immutableHash.Length * 8}, Got: {bitLength}"); + throw new ArgumentOutOfRangeException(nameof(hash), $"The length of {nameof(hash)} in bits must be equal to {nameof(bitLength)}. Bytes: {hash.Length} Expected: {hash.Length * 8}, Got: {bitLength}"); } - Hash = immutableHash; + if (endianness != ValueEndianness.NotApplicable) + { + if (HashValueOptions.FixedEndianness.HasValue) + { + ValueEndianness fixedEndianness = HashValueOptions.FixedEndianness.Value; + if (endianness != fixedEndianness) + { + hash = hash.Reverse().ToImmutableArray(); + endianness = fixedEndianness; + } + } + } + + Hash = hash; BitLength = bitLength; + Endianness = endianness; + } + + /// + /// Creates a new instance of the class that is a representation of a hash value and its bit length computed by a hasher. + /// + /// The endianness of the given . + /// The hash computed by a hasher. + /// The expected bit length of the given . + /// Thrown if the given hash is . + /// Thrown if the parameter is smaller than 1. + public HashValue(ValueEndianness endianness, IEnumerable hash, int bitLength) : this(endianness, hash?.ToImmutableArray() ?? ImmutableArray.Empty, bitLength) + { + } + + /// + /// Creates a new instance of the class that is a representation of a hash value and its bit length computed by a hasher. + /// + /// The endianness of the given . + /// The hash computed by a hasher. + /// The expected bit length of the given . + /// A new instance of the class. + /// Thrown if the given hash is . + /// Thrown if the parameter is smaller than 1. + public static HashValue FromSpan(ValueEndianness endianness, ReadOnlySpan hash, int bitLength) + { + return new HashValue(endianness, hash.ToImmutableArray(), bitLength); } /// @@ -226,11 +264,6 @@ public decimal AsDecimal() private decimal AsNumber128_96() { - if (BitLength < 1) - { - throw new ArgumentException("Bit Length cannot be smaller than 1."); - } - if (BitLength > 96) { throw new NotSupportedException("Bit Length greater than 96 is not supported."); @@ -241,19 +274,14 @@ private decimal AsNumber128_96() byte[] dataPadded = new byte[12]; Array.Copy(data, dataPadded, data.Length); - int lo = (int)Endianness.ToUInt32LittleEndian(dataPadded, 0); - int mid = (int)Endianness.ToUInt32LittleEndian(dataPadded, 4); - int hi = (int)Endianness.ToUInt32LittleEndian(dataPadded, 8); + int lo = (int)EndianHelper.ToUInt32LittleEndian(dataPadded, 0); + int mid = (int)EndianHelper.ToUInt32LittleEndian(dataPadded, 4); + int hi = (int)EndianHelper.ToUInt32LittleEndian(dataPadded, 8); return new decimal(lo, mid, hi, false, 0); } private long AsNumber64() { - if (BitLength < 1) - { - throw new ArgumentException("Bit Length cannot be smaller than 1."); - } - if (BitLength > 64) { throw new NotSupportedException("Bit Length greater than 64 is not supported."); @@ -404,7 +432,7 @@ public string AsBinaryString() /// public string AsBase85String() { - return AsBase85String(Base85Variant.Rfc1924); + return AsBase85String(Base85Variant.Ascii85); } /// @@ -414,11 +442,6 @@ public string AsBase85String() /// public string AsBase85String(Base85Variant variant) { - if (BitLength < 1) - { - return ""; - } - return Base85Helper.AsBase85String(AsByteArray(), variant); } @@ -429,7 +452,7 @@ public string AsBase85String(Base85Variant variant) /// public string AsBase64String(Base64FormattingOptions formattingOptions = Base64FormattingOptions.None) { - return Convert.ToBase64String(Hash.ToArray(), formattingOptions); + return Convert.ToBase64String(AsBigEndian().AsByteArray(), formattingOptions); } /// @@ -438,31 +461,17 @@ public string AsBase64String(Base64FormattingOptions formattingOptions = Base64F /// public string AsBase58String() { - if (BitLength < 1) - { - return ""; - } - - const string Base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - byte[] data = AsByteArray(); - - byte[] dataPadded = new byte[data.Length + 1]; - Array.Copy(data, dataPadded, data.Length); - var intData = new BigInteger(dataPadded); - - var builder = new StringBuilder(); - while (intData > 0) - { - intData = BigInteger.DivRem(intData, 58, out BigInteger remainder); - builder.Insert(0, Base58Alphabet[(int)remainder]); - } - - for (int i = data.Length - 1; i >= 0 && data[i] == 0; i--) - { - builder.Insert(0, '1'); - } + return AsBase58String(Base58Variant.Bitcoin); + } - return builder.ToString(); + /// + /// + /// + /// + /// + public string AsBase58String(Base58Variant variant) + { + return Base58Helper.AsBase58String(AsBigEndian().AsByteArray(), variant); } /// @@ -471,60 +480,31 @@ public string AsBase58String() /// public string AsBase32String() { - if (BitLength < 1) - { - return ""; - } - - const string Base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - byte[] data = AsByteArray(); - - var builder = new StringBuilder(); - int bitsRead = 0; - int buffer = 0; - - foreach (byte b in data) - { - buffer = (buffer << 8) | b; - bitsRead += 8; - - while (bitsRead >= 5) - { - int index = (buffer >> (bitsRead - 5)) & 31; - builder.Append(Base32Alphabet[index]); - bitsRead -= 5; - } - } - - if (bitsRead > 0) - { - int index = (buffer << (5 - bitsRead)) & 31; - builder.Append(Base32Alphabet[index]); - } - - int padding = (8 - (builder.Length % 8)) % 8; - builder.Append('=', padding); - - return builder.ToString(); + return AsBase32String(Base32Variant.Rfc4648); } /// /// /// + /// /// - public string AsHexString() => AsHexString(false); + public string AsBase32String(Base32Variant variant) + { + return Base32Helper.AsBase32String(AsBigEndian().AsByteArray(), variant); + } /// /// /// - /// /// - public string AsHexString(bool uppercase) + public string AsHexString() { - var stringBuilder = new StringBuilder(Hash.Length); - var formatString = uppercase ? "X2" : "x2"; + ImmutableArray hash = AsBigEndian().Hash; + + var stringBuilder = new StringBuilder(hash.Length); + var formatString = "X2"; - foreach (var byteValue in Hash) + foreach (var byteValue in hash) { stringBuilder.Append(byteValue.ToString(formatString)); } @@ -561,12 +541,56 @@ public byte[] AsByteArray() /// public virtual IHashValue Coerce(int bitLength) { - if (bitLength < 1) - { - throw new ArgumentOutOfRangeException(nameof(bitLength), $"{nameof(bitLength)} must be greater than or equal to 1."); - } + return new HashValue(Endianness, ArrayHelpers.CoerceToArray(Hash.ToArray(), bitLength), bitLength); + } - return new HashValue(ArrayHelpers.CoerceToArray(Hash.ToArray(), bitLength), bitLength); + /// + /// + /// + /// + public IHashValue AsLittleEndian() + { + if (Endianness != ValueEndianness.BigEndian) + return this; + + return new HashValue(ValueEndianness.LittleEndian, Hash.Reverse().ToImmutableArray(), BitLength); + } + + /// + /// + /// + /// + public IHashValue AsBigEndian() + { + if (Endianness != ValueEndianness.LittleEndian) + return this; + + return new HashValue(ValueEndianness.BigEndian, Hash.Reverse().ToImmutableArray(), BitLength); + } + + /// + /// + /// + /// + /// + public IHashValue ToEndianness(ValueEndianness endianness) + { + if (Endianness == ValueEndianness.NotApplicable || endianness == ValueEndianness.NotApplicable || Endianness == endianness) + return this; + + return endianness == ValueEndianness.BigEndian ? AsBigEndian() : AsLittleEndian(); + } + + /// + /// + /// + /// + public IHashValue ReverseEndianness() + { + if (Endianness == ValueEndianness.NotApplicable) + return this; + + return new HashValue(Endianness == ValueEndianness.BigEndian ? ValueEndianness.LittleEndian : ValueEndianness.BigEndian, Hash.Reverse().ToImmutableArray(), BitLength); } /// @@ -678,5 +702,4 @@ public int CompareTo(IHashValue other) return 0; } } -} - +} \ No newline at end of file diff --git a/HashifyNet/Core/DataType/HashValueOptions.cs b/HashifyNet/Core/DataType/HashValueOptions.cs new file mode 100644 index 0000000..f518d72 --- /dev/null +++ b/HashifyNet/Core/DataType/HashValueOptions.cs @@ -0,0 +1,42 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +namespace HashifyNet +{ + /// + /// Contains a set of options for modifying the global behaviour of aka . + /// + public static class HashValueOptions + { + /// + /// Gets or sets a fixed endianness for all instances. + /// + public static ValueEndianness? FixedEndianness { get; set; } = null; + } +} diff --git a/HashifyNet/Core/DataType/IHashValue.cs b/HashifyNet/Core/DataType/IHashValue.cs index 0fdd46c..54b2e3a 100644 --- a/HashifyNet/Core/DataType/IHashValue.cs +++ b/HashifyNet/Core/DataType/IHashValue.cs @@ -45,6 +45,11 @@ public interface IHashValue /// int BitLength { get; } + /// + /// Gets the endianness of the hash value. + /// + ValueEndianness Endianness { get; } + /// /// Gets the hash value as an immutable array of bytes. /// @@ -130,7 +135,7 @@ public interface IHashValue string AsBinaryString(); /// - /// Gets the hash value as a Base85-encoded string. If the bit length is not a multiple of 8, the last byte is padded with zeros. + /// Gets the hash value as a Base85-encoded string in the standard. If the bit length is not a multiple of 8, the last byte is padded with zeros. /// /// The generated base85 string. string AsBase85String(); @@ -150,29 +155,34 @@ public interface IHashValue string AsBase64String(Base64FormattingOptions formattingOptions = Base64FormattingOptions.None); /// - /// Gets the hash value as a Base58-encoded string. If the bit length is not a multiple of 8, the last byte is padded with zeros. + /// Gets the hash value as a Base58-encoded string using the variant. If the bit length is not a multiple of 8, the last byte is padded with zeros. /// /// The generated base58 string. string AsBase58String(); /// - /// Gets the hash value as a Base32-encoded string. If the bit length is not a multiple of 8, the last byte is padded with zeros. + /// Encodes the current data as a Base58-encoded string using the specified variant. + /// + /// The generated base58 string in the specified variant. + string AsBase58String(Base58Variant variant); + + /// + /// Gets the hash value as a Base32-encoded string in the standard. If the bit length is not a multiple of 8, the last byte is padded with zeros. /// /// The generated base32 string. string AsBase32String(); /// - /// Gets the hash value as a hexadecimal string, using lowercase letters for 'a' to 'f'. + /// Gets the hash value as a Base32-encoded string in the specified standard. If the bit length is not a multiple of 8, the last byte is padded with zeros. /// - /// The hexadecimal string. - string AsHexString(); + /// The generated base32 string. + string AsBase32String(Base32Variant variant); /// - /// Gets the hash value as a hexadecimal string. + /// Gets the hash value as a hexadecimal string, using uppercase letters for 'a' to 'f'. /// - /// Indicating to use uppercase letters. /// The hexadecimal string. - string AsHexString(bool uppercase); + string AsHexString(); /// /// Gets the hash value as a . @@ -193,5 +203,30 @@ public interface IHashValue /// An instance representing the hash value coerced to the specified bit length. /// Thrown if is less than 1. IHashValue Coerce(int bitLength); + + /// + /// Converts the current hash value to a new representation with the specified endianness of little-endian. + /// + /// The new instance with little-endian byte order. If the current instance is already in little-endian format, it returns the same instance. + IHashValue AsLittleEndian(); + + /// + /// Converts the current hash value to a new representation with the specified endianness of big-endian. + /// + /// The new instance with big-endian byte order. If the current instance is already in big-endian format, it returns the same instance. + IHashValue AsBigEndian(); + + /// + /// Converts the current hash value to a new representation with the specified endianness. + /// + /// The desired of the resulting hash value. + /// The new instance with the specified byte order. If the current instance is already in the specified format, it returns the same instance. + IHashValue ToEndianness(ValueEndianness endianness); + + /// + /// Reverses the endianness of the current hash value. If the current endianness is , no changes are made. + /// + /// The new instance with reversed byte order. If the current instance has , it returns the same instance. + IHashValue ReverseEndianness(); } -} +} \ No newline at end of file diff --git a/HashifyNet/Core/DataType/ValueEndianness.cs b/HashifyNet/Core/DataType/ValueEndianness.cs new file mode 100644 index 0000000..4fe8ca8 --- /dev/null +++ b/HashifyNet/Core/DataType/ValueEndianness.cs @@ -0,0 +1,52 @@ +// * +// ***************************************************************************** +// * +// * Copyright (c) 2025 Deskasoft International +// * +// * Permission is hereby granted, free of charge, to any person obtaining a copy +// * of this software and associated documentation files (the ""Software""), to deal +// * in the Software without restriction, including without limitation the rights +// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// * copies of the Software, and to permit persons to whom the Software is +// * furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included in all +// * copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// * SOFTWARE. +// * +// * +// * Please refer to LICENSE file. +// * +// ****************************************************************************** +// * + +namespace HashifyNet +{ + /// + /// The endianness of a value when represented as a sequence of bytes. + /// + public enum ValueEndianness + { + /// + /// The endianness is not applicable, as the hash is typically treated only as a byte sequence. + /// + NotApplicable = 0, + + /// + /// Indicates that the value is in little-endian format (least significant byte first). + /// + LittleEndian, + + /// + /// Indicates that the value is in big-endian format (most significant byte first). + /// + BigEndian + } +} diff --git a/HashifyNet/Core/Factory/HashFactory.Extensions.cs b/HashifyNet/Core/Factory/HashFactory.Extensions.cs index 1393ecc..8299d70 100644 --- a/HashifyNet/Core/Factory/HashFactory.Extensions.cs +++ b/HashifyNet/Core/Factory/HashFactory.Extensions.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -30,12 +30,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; #if NET8_0_OR_GREATER -using HashifyNet.Algorithms.HMACSHA3_256; -using HashifyNet.Algorithms.HMACSHA3_384; -using HashifyNet.Algorithms.HMACSHA3_512; using HashifyNet.Algorithms.SHA3_256; using HashifyNet.Algorithms.SHA3_384; using HashifyNet.Algorithms.SHA3_512; @@ -139,10 +135,6 @@ public static Type[] GetUnavailableHashAlgorithms() { List> possibleUnavailableAlgorithms = new List>() { - Tuple.Create(typeof(IHMACSHA3_256), IHMACSHA3_256.IsSupported), - Tuple.Create(typeof(IHMACSHA3_384), IHMACSHA3_384.IsSupported), - Tuple.Create(typeof(IHMACSHA3_512), IHMACSHA3_512.IsSupported), - Tuple.Create(typeof(ISHA3_256), ISHA3_256.IsSupported), Tuple.Create(typeof(ISHA3_384), ISHA3_384.IsSupported), Tuple.Create(typeof(ISHA3_512), ISHA3_512.IsSupported), @@ -337,4 +329,3 @@ private static Type[] GetAllNonCryptographicHashAlgorithms() } } } - diff --git a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperBase.cs b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperBase.cs index 7382efa..eb89a51 100644 --- a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperBase.cs +++ b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperBase.cs @@ -30,6 +30,7 @@ using HashifyNet.Core; using HashifyNet.Core.HashAlgorithm; using System; +using System.Security.Cryptography; namespace HashifyNet { @@ -40,7 +41,7 @@ internal abstract class HashAlgorithmWrapperBase : CryptographicStreama private readonly TConfig _config; private readonly IHashAlgorithmWrapper _wrapper; - public HashAlgorithmWrapperBase(TConfig config, Func factory) + public HashAlgorithmWrapperBase(TConfig config, Func factory) { if (config == null) { diff --git a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperConfig.cs b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperConfig.cs index 227dd83..8bc9e03 100644 --- a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperConfig.cs +++ b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapperConfig.cs @@ -28,7 +28,7 @@ // * using System; -using SystemHashAlgorithm = System.Security.Cryptography.HashAlgorithm; +using SystemHashAlgorithm = System.Security.Cryptography.IncrementalHash; namespace HashifyNet.Core.HashAlgorithm { @@ -78,4 +78,4 @@ public void Dispose() InstanceFactory = null; } } -} +} \ No newline at end of file diff --git a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapper_Implementation.cs b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapper_Implementation.cs index 1049886..c678236 100644 --- a/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapper_Implementation.cs +++ b/HashifyNet/Core/HashAlgorithmWrapper/HashAlgorithmWrapper_Implementation.cs @@ -29,6 +29,7 @@ using HashifyNet.Core.Utilities; using System; +using System.Security.Cryptography; using System.Threading; namespace HashifyNet.Core.HashAlgorithm @@ -40,7 +41,7 @@ internal class HashAlgorithmWrapper_Implementation public override IHashAlgorithmWrapperConfig Config => _config.Clone(); private readonly IHashAlgorithmWrapperConfig _config; - private readonly System.Security.Cryptography.HashAlgorithm hashAlgorithm; + private readonly IncrementalHash hashAlgorithm; public HashAlgorithmWrapper_Implementation(IHashAlgorithmWrapperConfig config) { if (config == null) @@ -56,15 +57,15 @@ public HashAlgorithmWrapper_Implementation(IHashAlgorithmWrapperConfig config) hashAlgorithm = _config.InstanceFactory() ?? throw new InvalidOperationException("The hash algorithm factory returned null."); - if (_config.HashSizeInBits != hashAlgorithm.HashSize) + if (_config.HashSizeInBits < 1) { - throw new InvalidOperationException($"{nameof(_config)}.{nameof(_config.HashSizeInBits)} does not match the underlying {nameof(_config.InstanceFactory)} hash algorithm's size. Expected {_config.HashSizeInBits} bits but got {hashAlgorithm.HashSize} bits."); + throw new InvalidOperationException($"{nameof(_config)}.{nameof(_config.HashSizeInBits)} must be greater than 0."); } } public override IBlockTransformer CreateBlockTransformer() { - return new BlockTransformer(hashAlgorithm); + return new BlockTransformer(hashAlgorithm, _config.HashSizeInBits); } protected override void Dispose(bool disposing) @@ -83,9 +84,11 @@ public BlockTransformer() { } - private System.Security.Cryptography.HashAlgorithm _algo; - public BlockTransformer(System.Security.Cryptography.HashAlgorithm algorithm) : this() + private IncrementalHash _algo; + private readonly int _hashSizeInBits; + public BlockTransformer(IncrementalHash algorithm, int hashSizeInBits) : this() { + _hashSizeInBits = hashSizeInBits; _algo = algorithm ?? throw new ArgumentNullException(nameof(algorithm)); } @@ -94,25 +97,26 @@ protected override void CopyStateTo(BlockTransformer other) other._algo = _algo; } - protected override void TransformByteGroupsInternal(ArraySegment data) + protected override void TransformByteGroupsInternal(ReadOnlySpan data) { - if (_algo.TransformBlock(data.Array, data.Offset, data.Count, null, 0) != data.Count) - { - throw new Exception("Hash algorithm did not process all input data."); - } +#if NET8_0_OR_GREATER + _algo.AppendData(data); +#else + byte[] dataArray = data.ToArray(); + _algo.AppendData(dataArray); +#endif } - protected override IHashValue FinalizeHashValueInternal(CancellationToken cancellationToken) + protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken) { - byte[] lastBytes = FinalizeInputBuffer ?? Array.Empty(); - byte[] lastResult = _algo.TransformFinalBlock(lastBytes, 0, lastBytes.Length); - if (lastResult == null || lastResult.Length != lastBytes.Length) + if (leftover.Length > 0) { - throw new Exception("Hash algorithm did not process all input data."); + TransformByteGroupsInternal(leftover); } - return new HashValue(_algo.Hash, _algo.HashSize); + byte[] result = _algo.GetHashAndReset(); + return new HashValue(_algo.AlgorithmName == HashAlgorithmName.MD5 ? ValueEndianness.LittleEndian : ValueEndianness.BigEndian, result, _hashSizeInBits); } } } -} +} \ No newline at end of file diff --git a/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperConfig.cs b/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperConfig.cs index 69609d0..5ecda20 100644 --- a/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperConfig.cs +++ b/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperConfig.cs @@ -28,7 +28,7 @@ // * using System; -using SystemHashAlgorithm = System.Security.Cryptography.HashAlgorithm; +using SystemHashAlgorithm = System.Security.Cryptography.IncrementalHash; namespace HashifyNet.Core.HashAlgorithm { @@ -50,4 +50,4 @@ internal interface IHashAlgorithmWrapperConfig : ICryptographicHashConfig Func InstanceFactory { get; } } -} +} \ No newline at end of file diff --git a/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperPlatformDependentAlgorithm.cs b/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperPlatformDependentAlgorithm.cs index d45ac63..a790414 100644 --- a/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperPlatformDependentAlgorithm.cs +++ b/HashifyNet/Core/HashAlgorithmWrapper/IHashAlgorithmWrapperPlatformDependentAlgorithm.cs @@ -1,4 +1,4 @@ -#if NET8_0_OR_GREATER +#if NET8_0_OR_GREATER // * // ***************************************************************************** // * diff --git a/HashifyNet/Core/HashFunctionBase.cs b/HashifyNet/Core/HashFunctionBase.cs index 2491cbc..e8cb836 100644 --- a/HashifyNet/Core/HashFunctionBase.cs +++ b/HashifyNet/Core/HashFunctionBase.cs @@ -41,31 +41,25 @@ public abstract class HashFunctionBase : IHashFunction where CName : IHashConfig { /// - /// Gets the configuration settings used for hashing operations. + /// /// public abstract CName Config { get; } /// - /// Computes hash value for given byte array. + /// /// - /// Array of data to hash. - /// - /// Hash value of the data. - /// - /// + /// + /// public IHashValue ComputeHash(byte[] data) => ComputeHash(data, CancellationToken.None); /// - /// Computes hash value for given byte array. + /// /// - /// Array of data to hash. - /// A cancellation token to observe while calculating the hash value. - /// - /// Hash value of the data. - /// - /// - /// The was canceled. + /// + /// + /// + /// public IHashValue ComputeHash(byte[] data, CancellationToken cancellationToken) { if (data == null) @@ -77,34 +71,25 @@ public IHashValue ComputeHash(byte[] data, CancellationToken cancellationToken) } /// - /// Computes hash value for given byte array. + /// /// - /// Array of data to hash. - /// The offset from which to begin using the data. - /// The number of bytes to use as data. - /// - /// Hash value of the data. - /// - /// - /// ;Offset must be a value greater than or equal to zero and less than or equal to the length of the array. - /// ;Count must be a value greater than zero and less than the the remaining length of the array after the offset value. + /// + /// + /// + /// public IHashValue ComputeHash(byte[] data, int offset, int count) => ComputeHash(data, offset, count, CancellationToken.None); /// - /// Computes hash value for given byte array. + /// /// - /// Array of data to hash. - /// The offset from which to begin using the data. - /// The number of bytes to use as data. - /// A cancellation token to observe while calculating the hash value. - /// - /// Hash value of the data. - /// - /// - /// ;Offset must be a value greater than or equal to zero and less than or equal to the length of the array. - /// ;Count must be a value greater than or equal to zero and less than the the remaining length of the array after the offset value. - /// The was canceled. + /// + /// + /// + /// + /// + /// + /// public IHashValue ComputeHash(byte[] data, int offset, int count, CancellationToken cancellationToken) { if (data == null) @@ -122,40 +107,38 @@ public IHashValue ComputeHash(byte[] data, int offset, int count, CancellationTo throw new ArgumentOutOfRangeException(nameof(count), "Count must be a value greater than or equal to zero and less than the the remaining length of the array after the offset value."); } - return ComputeHash(new ArraySegment(data, offset, count), cancellationToken); + return ComputeHash(new ReadOnlySpan(data, offset, count), cancellationToken); } /// - /// Computes hash value for given byte array. + /// /// - /// Array of data to hash. - /// - /// Hash value of the data. - /// - public IHashValue ComputeHash(ArraySegment data) => + /// + /// + public IHashValue ComputeHash(ReadOnlySpan data) => ComputeHash(data, CancellationToken.None); /// - /// Computes hash value for given array segment. + /// /// - /// Array segment of data to hash. - /// A cancellation token to observe while calculating the hash value. + /// + /// /// - /// Hash value of the data. + /// /// - /// The was canceled. - public IHashValue ComputeHash(ArraySegment data, CancellationToken cancellationToken) => + /// + public IHashValue ComputeHash(ReadOnlySpan data, CancellationToken cancellationToken) => ComputeHashInternal(data, cancellationToken); /// - /// Computes hash value for given array segment. + /// Computes hash value for given read-only span. /// - /// Array segment of data to hash. + /// Span of the data to hash. /// A cancellation token to observe while calculating the hash value. /// /// Hash value of the data. /// /// The was canceled. - protected abstract IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken); + protected abstract IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/HashifyNet/Core/IBlockTransformer.cs b/HashifyNet/Core/IBlockTransformer.cs index 009a77d..c756fb1 100644 --- a/HashifyNet/Core/IBlockTransformer.cs +++ b/HashifyNet/Core/IBlockTransformer.cs @@ -92,19 +92,19 @@ public interface IBlockTransformer /// Updates the internal state of this transformer with the given data. /// /// The data to process into this transformer's internal state. - /// data must be an ArraySegment of Count > 0.; + /// must point to a non-empty valid . /// A previous transformation cancellation has resulted in an undefined internal state. - void TransformBytes(ArraySegment data); + void TransformBytes(ReadOnlySpan data); /// /// Updates the internal state of this transformer with the given data. /// /// The data to process into this transformer's internal state. /// A to cease processing of the provided data. - /// data must be an ArraySegment of Count > 0.; + /// must point to a non-empty valid . /// The was canceled. /// A previous transformation cancellation has resulted in an undefined internal state. - void TransformBytes(ArraySegment data, CancellationToken cancellationToken); + void TransformBytes(ReadOnlySpan data, CancellationToken cancellationToken); /// /// Completes any finalization processing and returns the resulting . diff --git a/HashifyNet/Core/IHashFunctionBase.cs b/HashifyNet/Core/IHashFunctionBase.cs index 42fdfd7..6c0d78b 100644 --- a/HashifyNet/Core/IHashFunctionBase.cs +++ b/HashifyNet/Core/IHashFunctionBase.cs @@ -94,23 +94,21 @@ public interface IHashFunctionBase IHashValue ComputeHash(byte[] data, int offset, int count, CancellationToken cancellationToken); /// - /// Computes hash value for given array segment. + /// Computes hash value for given read-only span of bytes. /// - /// Array segment of data to hash. + /// Read-only span of data to hash. /// /// Hash value of the data. /// - IHashValue ComputeHash(ArraySegment data); + IHashValue ComputeHash(ReadOnlySpan data); /// - /// Computes hash value for given array segment. + /// Computes hash value for given read-only span of bytes. /// - /// Array segment of data to hash. + /// Read-only span of data to hash. /// A to observe while calculating the hash value. - /// - /// Hash value of the data. - /// + /// Hash value of the data. /// The was canceled. - IHashValue ComputeHash(ArraySegment data, CancellationToken cancellationToken); + IHashValue ComputeHash(ReadOnlySpan data, CancellationToken cancellationToken); } } diff --git a/HashifyNet/Core/IHashFunction_Extensions.cs b/HashifyNet/Core/IHashFunction_Extensions.cs index e95a68a..db2547b 100644 --- a/HashifyNet/Core/IHashFunction_Extensions.cs +++ b/HashifyNet/Core/IHashFunction_Extensions.cs @@ -55,7 +55,7 @@ public static class IHashFunction_Extensions public static IHashValue ComputeHash(this IHashFunction hashFunction, bool data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + new byte[1] { data ? (byte)1 : (byte)0 }); } /// @@ -83,7 +83,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, char data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -97,7 +97,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, double data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -111,7 +111,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, float data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -125,7 +125,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, int data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -139,7 +139,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, long data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -168,7 +168,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, short data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -200,7 +200,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, uint data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -215,7 +215,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, ulong data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } /// @@ -230,7 +230,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, ushort data) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data)); + Endianness.GetBytesLittleEndian(data)); } #endregion @@ -249,8 +249,8 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, bool data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), - desiredHashSize); + new byte[1] { data ? (byte)1 : (byte)0 }, + desiredHashSize); } /// @@ -281,7 +281,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, char data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -297,7 +297,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, double data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -313,7 +313,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, float data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -329,7 +329,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, int data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -345,7 +345,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, long data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -378,7 +378,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, short data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -414,7 +414,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, uint data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -431,7 +431,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, ulong data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -448,7 +448,7 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti public static IHashValue ComputeHash(this IHashFunction hashFunction, ushort data, int desiredHashSize) where CName : IHashConfig { return hashFunction.ComputeHash( - BitConverter.GetBytes(data), + Endianness.GetBytesLittleEndian(data), desiredHashSize); } @@ -478,13 +478,14 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti var hashesNeeded = (desiredHashSize + (config.HashSizeInBits - 1)) / config.HashSizeInBits; // Compute as many hashes as needed + ValueEndianness? endianness = null; for (int x = 0; x < Math.Max(hashesNeeded, 1); ++x) { byte[] currentData; if (x != 0) { - Array.Copy(BitConverter.GetBytes(x), seededData, 4); + Array.Copy(Endianness.GetBytesLittleEndian(x), seededData, 4); currentData = seededData; } @@ -494,9 +495,13 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti currentData = data; } + var result = hashFunction.ComputeHash(currentData); + + if (!endianness.HasValue) + endianness = result.Endianness; var elementHash = new BigInteger( - hashFunction.ComputeHash(currentData) + result .Hash .Concat(new[] { (byte)0 }) .ToArray()); @@ -526,11 +531,11 @@ public static IHashValue ComputeHash(this IHashFunction hashFuncti hashBytes = buffer; } - return new HashValue(hashBytes, desiredHashSize); + return new HashValue(endianness.Value, hashBytes, desiredHashSize); } #endregion #endregion } -} +} \ No newline at end of file diff --git a/HashifyNet/Core/StreamableHashFunctionBase.cs b/HashifyNet/Core/StreamableHashFunctionBase.cs index 85110c6..637029e 100644 --- a/HashifyNet/Core/StreamableHashFunctionBase.cs +++ b/HashifyNet/Core/StreamableHashFunctionBase.cs @@ -141,14 +141,16 @@ public Task ComputeHashAsync(Stream data, CancellationToken cancella /// Hash value of the data. /// /// The was canceled. - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - cancellationToken.ThrowIfCancellationRequested(); + var blockTransformer = CreateBlockTransformer(); - using (var memoryStream = new MemoryStream(data.Array, data.Offset, data.Count, false)) + if (!data.IsEmpty) { - return ComputeHashInternal(memoryStream, cancellationToken); + blockTransformer.TransformBytes(data, cancellationToken); } + + return blockTransformer.FinalizeHashValue(cancellationToken); } /// @@ -170,10 +172,7 @@ protected IHashValue ComputeHashInternal(Stream data, CancellationToken cancella while (true) { - cancellationToken.ThrowIfCancellationRequested(); - var bytesRead = data.Read(buffer, 0, 4096); - if (bytesRead == 0) { break; diff --git a/HashifyNet/Core/Utilities/Endianness.cs b/HashifyNet/Core/Utilities/Endianness.cs index db7f930..c8e5500 100644 --- a/HashifyNet/Core/Utilities/Endianness.cs +++ b/HashifyNet/Core/Utilities/Endianness.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -54,12 +54,70 @@ internal static class Endianness [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToLittleEndianBytes(uint value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)value; + buffer[offset + 1] = (byte)(value >> 8); + buffer[offset + 2] = (byte)(value >> 16); + buffer[offset + 3] = (byte)(value >> 24); + } + + /// + /// Converts the specified 32-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit signed integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(int value, byte[] buffer, int offset) + { + ToLittleEndianBytes((uint)value, buffer, offset); + } + + /// + /// Converts the specified 32-bit unsigned integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit unsigned integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(uint value, Span buffer, int offset) + { + if (buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)value; buffer[offset + 1] = (byte)(value >> 8); buffer[offset + 2] = (byte)(value >> 16); buffer[offset + 3] = (byte)(value >> 24); } + /// + /// Converts the specified 32-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit signed integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(int value, Span buffer, int offset) + { + ToLittleEndianBytes((uint)value, buffer, offset); + } + /// /// Converts the specified 16-bit unsigned integer to its little-endian byte representation and writes the result to /// the specified buffer at the given offset. @@ -72,10 +130,66 @@ public static void ToLittleEndianBytes(uint value, byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToLittleEndianBytes(ushort value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)value; + buffer[offset + 1] = (byte)(value >> 8); + } + + /// + /// Converts the specified 16-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit signed integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(short value, byte[] buffer, int offset) + { + ToLittleEndianBytes((ushort)value, buffer, offset); + } + + /// + /// Converts the specified 16-bit unsigned integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit unsigned integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(ushort value, Span buffer, int offset) + { + if (buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)value; buffer[offset + 1] = (byte)(value >> 8); } + /// + /// Converts the specified 16-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit signed integer to convert. + /// The byte array to which the little-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(short value, Span buffer, int offset) + { + ToLittleEndianBytes((ushort)value, buffer, offset); + } + /// /// Converts the specified 64-bit unsigned integer to its little-endian byte representation and writes the result to /// the specified buffer at the given offset. @@ -89,6 +203,55 @@ public static void ToLittleEndianBytes(ushort value, byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToLittleEndianBytes(ulong value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)value; + buffer[offset + 1] = (byte)(value >> 8); + buffer[offset + 2] = (byte)(value >> 16); + buffer[offset + 3] = (byte)(value >> 24); + buffer[offset + 4] = (byte)(value >> 32); + buffer[offset + 5] = (byte)(value >> 40); + buffer[offset + 6] = (byte)(value >> 48); + buffer[offset + 7] = (byte)(value >> 56); + } + + /// + /// Converts the specified 64-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes the least significant byte of to at the specified , followed by the remaining bytes in increasing order + /// of significance. + /// The 64-bit signed integer to convert. + /// The byte array to which the little-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(long value, byte[] buffer, int offset) + { + ToLittleEndianBytes((ulong)value, buffer, offset); + } + + /// + /// Converts the specified 64-bit unsigned integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes the least significant byte of to at the specified , followed by the remaining bytes in increasing order + /// of significance. + /// The 64-bit unsigned integer to convert. + /// The byte array to which the little-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(ulong value, Span buffer, int offset) + { + if (buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)value; buffer[offset + 1] = (byte)(value >> 8); buffer[offset + 2] = (byte)(value >> 16); @@ -99,6 +262,22 @@ public static void ToLittleEndianBytes(ulong value, byte[] buffer, int offset) buffer[offset + 7] = (byte)(value >> 56); } + /// + /// Converts the specified 64-bit signed integer to its little-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes the least significant byte of to at the specified , followed by the remaining bytes in increasing order + /// of significance. + /// The 64-bit signed integer to convert. + /// The byte array to which the little-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToLittleEndianBytes(long value, Span buffer, int offset) + { + ToLittleEndianBytes((ulong)value, buffer, offset); + } + /// /// Converts the specified 16-bit unsigned integer to its big-endian byte representation and writes the result to /// the specified buffer at the given offset. @@ -111,10 +290,66 @@ public static void ToLittleEndianBytes(ulong value, byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToBigEndianBytes(ushort value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)(value >> 8); + buffer[offset + 1] = (byte)value; + } + + /// + /// Converts the specified 16-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit signed integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(short value, byte[] buffer, int offset) + { + ToBigEndianBytes((ushort)value, buffer, offset); + } + + /// + /// Converts the specified 16-bit unsigned integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit unsigned integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(ushort value, Span buffer, int offset) + { + if (buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)(value >> 8); buffer[offset + 1] = (byte)value; } + /// + /// Converts the specified 16-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 2 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 16-bit signed integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(short value, Span buffer, int offset) + { + ToBigEndianBytes((ushort)value, buffer, offset); + } + /// /// Converts the specified 32-bit unsigned integer to its big-endian byte representation and writes the result to /// the specified buffer at the given offset. @@ -127,12 +362,70 @@ public static void ToBigEndianBytes(ushort value, byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToBigEndianBytes(uint value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)value; + } + + /// + /// Converts the specified 32-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit signed integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(int value, byte[] buffer, int offset) + { + ToBigEndianBytes((uint)value, buffer, offset); + } + + /// + /// Converts the specified 32-bit unsigned integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit unsigned integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(uint value, Span buffer, int offset) + { + if (buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)(value >> 24); buffer[offset + 1] = (byte)(value >> 16); buffer[offset + 2] = (byte)(value >> 8); buffer[offset + 3] = (byte)value; } + /// + /// Converts the specified 32-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes exactly 4 bytes to the buffer, starting at the specified offset. Ensure that + /// the buffer has sufficient capacity to accommodate the bytes being written. + /// The 32-bit signed integer to convert. + /// The byte array to which the big-endian representation will be written. + /// The zero-based index in the buffer at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(int value, Span buffer, int offset) + { + ToBigEndianBytes((uint)value, buffer, offset); + } + /// /// Converts the specified 64-bit unsigned integer to its big-endian byte representation and writes the result to /// the specified buffer at the given offset. @@ -146,6 +439,11 @@ public static void ToBigEndianBytes(uint value, byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToBigEndianBytes(ulong value, byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + buffer[offset] = (byte)(value >> 56); buffer[offset + 1] = (byte)(value >> 48); buffer[offset + 2] = (byte)(value >> 40); @@ -157,28 +455,109 @@ public static void ToBigEndianBytes(ulong value, byte[] buffer, int offset) } /// - /// Converts the specified 64-bit unsigned integer to little-endian format. + /// Converts the specified 64-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. /// - /// This method ensures that the returned value is in little-endian format, regardless of the - /// system's endianness. It is optimized for performance and uses aggressive inlining. - /// The 64-bit unsigned integer to convert. - /// The value in little-endian format. If the system architecture is already little-endian, the original value is - /// returned unchanged. Otherwise, the byte order is reversed. + /// This method writes the most significant byte of to at the specified , followed by the remaining bytes in decreasing order + /// of significance. + /// The 64-bit signed integer to convert. + /// The byte array to which the big-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong ToLittleEndian(ulong value) + public static void ToBigEndianBytes(long value, byte[] buffer, int offset) { - // If the system architecture is already little-endian, the value doesn't need to be changed. - if (BitConverter.IsLittleEndian) - { - return value; - } - - // If the system is big-endian, we must reverse the byte order to make it little-endian. - return BinaryPrimitives.ReverseEndianness(value); + ToBigEndianBytes((ulong)value, buffer, offset); } /// - /// Converts the specified 32-bit unsigned integer to little-endian format. + /// Converts the specified 64-bit unsigned integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes the most significant byte of to at the specified , followed by the remaining bytes in decreasing order + /// of significance. + /// The 64-bit unsigned integer to convert. + /// The byte array to which the big-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(ulong value, Span buffer, int offset) + { + if (buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + + buffer[offset] = (byte)(value >> 56); + buffer[offset + 1] = (byte)(value >> 48); + buffer[offset + 2] = (byte)(value >> 40); + buffer[offset + 3] = (byte)(value >> 32); + buffer[offset + 4] = (byte)(value >> 24); + buffer[offset + 5] = (byte)(value >> 16); + buffer[offset + 6] = (byte)(value >> 8); + buffer[offset + 7] = (byte)value; + } + + /// + /// Converts the specified 64-bit signed integer to its big-endian byte representation and writes the result to + /// the specified buffer at the given offset. + /// + /// This method writes the most significant byte of to at the specified , followed by the remaining bytes in decreasing order + /// of significance. + /// The 64-bit signed integer to convert. + /// The byte array to which the big-endian representation of will be written. + /// The zero-based index in at which to begin writing the bytes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToBigEndianBytes(long value, Span buffer, int offset) + { + ToBigEndianBytes((ulong)value, buffer, offset); + } + + /// + /// Converts the specified 64-bit unsigned integer to little-endian format. + /// + /// This method ensures that the returned value is in little-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 64-bit unsigned integer to convert. + /// The value in little-endian format. If the system architecture is already little-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToLittleEndian(ulong value) + { + // If the system architecture is already little-endian, the value doesn't need to be changed. + if (BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is big-endian, we must reverse the byte order to make it little-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + + /// + /// Converts the specified 64-bit signed integer to little-endian format. + /// + /// This method ensures that the returned value is in little-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 64-bit signed integer to convert. + /// The value in little-endian format. If the system architecture is already little-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToLittleEndian(long value) + { + // If the system architecture is already little-endian, the value doesn't need to be changed. + if (BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is big-endian, we must reverse the byte order to make it little-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + + /// + /// Converts the specified 32-bit unsigned integer to little-endian format. /// /// This method ensures that the returned value is in little-endian format, regardless of the /// system's endianness. It is optimized for performance and uses aggressive inlining. @@ -198,6 +577,27 @@ public static uint ToLittleEndian(uint value) return BinaryPrimitives.ReverseEndianness(value); } + /// + /// Converts the specified 32-bit signed integer to little-endian format. + /// + /// This method ensures that the returned value is in little-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 32-bit signed integer to convert. + /// The value in little-endian format. If the system architecture is already little-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToLittleEndian(int value) + { + // If the system architecture is already little-endian, the value doesn't need to be changed. + if (BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is big-endian, we must reverse the byte order to make it little-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + /// /// Converts the specified 16-bit unsigned integer to little-endian format. /// @@ -219,6 +619,27 @@ public static ushort ToLittleEndian(ushort value) return BinaryPrimitives.ReverseEndianness(value); } + /// + /// Converts the specified 16-bit signed integer to little-endian format. + /// + /// This method ensures that the returned value is in little-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 16-bit signed integer to convert. + /// The value in little-endian format. If the system architecture is already little-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToLittleEndian(short value) + { + // If the system architecture is already little-endian, the value doesn't need to be changed. + if (BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is big-endian, we must reverse the byte order to make it little-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + /// /// Converts the specified 64-bit unsigned integer to big-endian format. /// @@ -240,6 +661,27 @@ public static ulong ToBigEndian(ulong value) return BinaryPrimitives.ReverseEndianness(value); } + /// + /// Converts the specified 64-bit signed integer to big-endian format. + /// + /// This method ensures that the returned value is in big-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 64-bit signed integer to convert. + /// The value in big-endian format. If the system architecture is already big-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToBigEndian(long value) + { + // If the system architecture is already big-endian, the value doesn't need to be changed. + if (!BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is little-endian, we must reverse the byte order to make it big-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + /// /// Converts the specified 16-bit unsigned integer to big-endian format. /// @@ -261,6 +703,27 @@ public static ushort ToBigEndian(ushort value) return BinaryPrimitives.ReverseEndianness(value); } + /// + /// Converts the specified 16-bit signed integer to big-endian format. + /// + /// This method ensures that the returned value is in big-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 16-bit signed integer to convert. + /// The value in big-endian format. If the system architecture is already big-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToBigEndian(short value) + { + // If the system architecture is already big-endian, the value doesn't need to be changed. + if (!BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is little-endian, we must reverse the byte order to make it big-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + /// /// Converts the specified 32-bit unsigned integer to big-endian format. /// @@ -282,6 +745,27 @@ public static uint ToBigEndian(uint value) return BinaryPrimitives.ReverseEndianness(value); } + /// + /// Converts the specified 32-bit signed integer to big-endian format. + /// + /// This method ensures that the returned value is in big-endian format, regardless of the + /// system's endianness. It is optimized for performance and uses aggressive inlining. + /// The 32-bit signed integer to convert. + /// The value in big-endian format. If the system architecture is already big-endian, the original value is + /// returned unchanged. Otherwise, the byte order is reversed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToBigEndian(int value) + { + // If the system architecture is already big-endian, the value doesn't need to be changed. + if (!BitConverter.IsLittleEndian) + { + return value; + } + + // If the system is little-endian, we must reverse the byte order to make it big-endian. + return BinaryPrimitives.ReverseEndianness(value); + } + /// /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned /// integer using little-endian byte order. @@ -294,9 +778,75 @@ public static uint ToBigEndian(uint value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ToUInt64LittleEndian(byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 8) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer must contain at least 8 bytes starting from the specified offset."); + } + return ToUInt64LittleEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], buffer[offset + 4], buffer[offset + 5], buffer[offset + 6], buffer[offset + 7]); } + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using little-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the little-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64LittleEndian(byte[] buffer, int offset) + { + return (long)ToUInt64LittleEndian(buffer, offset); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit unsigned integer representing the little-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToUInt64LittleEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + byte b5 = offset + 4 < len ? buffer[offset + 4] : (byte)0; + byte b6 = offset + 5 < len ? buffer[offset + 5] : (byte)0; + byte b7 = offset + 6 < len ? buffer[offset + 6] : (byte)0; + byte b8 = offset + 7 < len ? buffer[offset + 7] : (byte)0; + return ToUInt64LittleEndian(b1, b2, b3, b4, b5, b6, b7, b8); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the little-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64LittleEndianSafe(byte[] buffer, int offset) + { + return (long)ToUInt64LittleEndianSafe(buffer, offset); + } + /// /// Combines eight bytes into a 64-bit unsigned integer, interpreting the bytes in little-endian order. /// @@ -323,7 +873,25 @@ public static ulong ToUInt64LittleEndian(byte v1, byte v2, byte v3, byte v4, byt } /// - /// Converts a sequence of bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned + /// Combines eight bytes into a 64-bit signed integer, interpreting the bytes in little-endian order. + /// + /// The least significant byte of the resulting 64-bit integer. + /// The second least significant byte of the resulting 64-bit integer. + /// The third least significant byte of the resulting 64-bit integer. + /// The fourth least significant byte of the resulting 64-bit integer. + /// The fifth least significant byte of the resulting 64-bit integer. + /// The sixth least significant byte of the resulting 64-bit integer. + /// The seventh least significant byte of the resulting 64-bit integer. + /// The most significant byte of the resulting 64-bit integer. + /// A 64-bit signed integer constructed from the specified bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64LittleEndian(byte v1, byte v2, byte v3, byte v4, byte v5, byte v6, byte v7, byte v8) + { + return (long)ToUInt64LittleEndian(v1, v2, v3, v4, v5, v6, v7, v8); + } + + /// + /// Converts a sequence of bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned /// integer using little-endian byte order. /// /// This method assumes that the bytes in the buffer are stored in little-endian format, where the @@ -336,44 +904,252 @@ public static ulong ToUInt64LittleEndian(byte v1, byte v2, byte v3, byte v4, byt [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ToUInt64LittleEndian(ReadOnlySpan buffer, int offset) { + if (buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + return ToUInt64LittleEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], buffer[offset + 4], buffer[offset + 5], buffer[offset + 6], buffer[offset + 7]); } /// - /// Converts two bytes to a 16-bit unsigned integer, assuming little-endian byte order. + /// Converts a sequence of bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using little-endian byte order. /// - /// The least significant byte of the 16-bit unsigned integer. - /// The most significant byte of the 16-bit unsigned integer. - /// A 16-bit unsigned integer constructed from the specified bytes in little-endian order. + /// This method assumes that the bytes in the buffer are stored in little-endian format, where the + /// least significant byte comes first. + /// The buffer containing the bytes to convert. Must have at least 8 bytes available starting from . + /// The zero-based index in at which to begin reading the bytes. + /// A 64-bit signed integer constructed from the 8 bytes starting at in little-endian + /// order. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ToUInt16LittleEndian(byte v1, byte v2) + public static long ToInt64LittleEndian(ReadOnlySpan buffer, int offset) { - return (ushort)(v1 | (v2 << 8)); + return (long)ToUInt64LittleEndian(buffer, offset); } /// - /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned - /// integer using little-endian byte order. + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. /// - /// The byte array containing the data to convert. Must contain at least two bytes starting from The buffer containing the data to convert. Must contain at least 8 bytes starting from . - /// The zero-based index in at which to begin reading the two bytes. - /// A 16-bit unsigned integer representing the value of the two bytes in little-endian order. + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit unsigned integer representing the little-endian interpretation of the 8 bytes starting at . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ToUInt16LittleEndian(byte[] buffer, int offset) + public static ulong ToUInt64LittleEndianSafe(ReadOnlySpan buffer, int offset) { - return ToUInt16LittleEndian(buffer[offset], buffer[offset + 1]); + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + byte b5 = offset + 4 < len ? buffer[offset + 4] : (byte)0; + byte b6 = offset + 5 < len ? buffer[offset + 5] : (byte)0; + byte b7 = offset + 6 < len ? buffer[offset + 6] : (byte)0; + byte b8 = offset + 7 < len ? buffer[offset + 7] : (byte)0; + return ToUInt64LittleEndian(b1, b2, b3, b4, b5, b6, b7, b8); } /// - /// Converts four bytes to a 32-bit unsigned integer using little-endian byte order. + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. /// - /// The least significant byte of the resulting integer. - /// The second least significant byte of the resulting integer. - /// The second most significant byte of the resulting integer. - /// The most significant byte of the resulting integer. - /// A 32-bit unsigned integer constructed from the specified bytes in little-endian order. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// The buffer containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the little-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64LittleEndianSafe(ReadOnlySpan buffer, int offset) + { + return (long)ToUInt64LittleEndianSafe(buffer, offset); + } + + /// + /// Converts two bytes to a 16-bit unsigned integer, assuming little-endian byte order. + /// + /// The least significant byte of the 16-bit unsigned integer. + /// The most significant byte of the 16-bit unsigned integer. + /// A 16-bit unsigned integer constructed from the specified bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ToUInt16LittleEndian(byte v1, byte v2) + { + return (ushort)(v1 | (v2 << 8)); + } + + /// + /// Converts two bytes to a 16-bit signed integer, assuming little-endian byte order. + /// + /// The least significant byte of the 16-bit unsigned integer. + /// The most significant byte of the 16-bit unsigned integer. + /// A 16-bit signed integer constructed from the specified bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16LittleEndian(byte v1, byte v2) + { + return (short)ToUInt16LittleEndian(v1, v2); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using little-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ToUInt16LittleEndian(byte[] buffer, int offset) + { + if (buffer == null || buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + + return ToUInt16LittleEndian(buffer[offset], buffer[offset + 1]); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using little-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16LittleEndian(byte[] buffer, int offset) + { + return (short)ToUInt16LittleEndian(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using little-endian byte order. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ToUInt16LittleEndian(ReadOnlySpan buffer, int offset) + { + if (buffer.Length - offset < 2) + { + throw new ArgumentException("Buffer must be at least 2 bytes long starting from the specified offset.", nameof(buffer)); + } + + return ToUInt16LittleEndian(buffer[offset], buffer[offset + 1]); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using little-endian byte order. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16LittleEndian(ReadOnlySpan buffer, int offset) + { + return (short)ToUInt16LittleEndian(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ToUInt16LittleEndianSafe(ReadOnlySpan buffer, int offset) + { + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + return ToUInt16LittleEndian(b1, b2); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16LittleEndianSafe(ReadOnlySpan buffer, int offset) + { + return (short)ToUInt16LittleEndianSafe(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ToUInt16LittleEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + return ToUInt16LittleEndian(b1, b2); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16LittleEndianSafe(byte[] buffer, int offset) + { + return (short)ToUInt16LittleEndianSafe(buffer, offset); + } + + /// + /// Converts four bytes to a 32-bit unsigned integer using little-endian byte order. + /// + /// The least significant byte of the resulting integer. + /// The second least significant byte of the resulting integer. + /// The second most significant byte of the resulting integer. + /// The most significant byte of the resulting integer. + /// A 32-bit unsigned integer constructed from the specified bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt32LittleEndian(byte v1, byte v2, byte v3, byte v4) { return v1 | @@ -382,6 +1158,20 @@ public static uint ToUInt32LittleEndian(byte v1, byte v2, byte v3, byte v4) ((uint)v4 << 24); } + /// + /// Converts four bytes to a 32-bit signed integer using little-endian byte order. + /// + /// The least significant byte of the resulting integer. + /// The second least significant byte of the resulting integer. + /// The second most significant byte of the resulting integer. + /// The most significant byte of the resulting integer. + /// A 32-bit signed integer constructed from the specified bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32LittleEndian(byte v1, byte v2, byte v3, byte v4) + { + return (int)ToUInt32LittleEndian(v1, v2, v3, v4); + } + /// /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit unsigned /// integer using little-endian byte order. @@ -393,9 +1183,68 @@ public static uint ToUInt32LittleEndian(byte v1, byte v2, byte v3, byte v4) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt32LittleEndian(byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + return ToUInt32LittleEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]); } + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit signed + /// integer using little-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit signed integer representing the value of the four bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32LittleEndian(byte[] buffer, int offset) + { + return (int)ToUInt32LittleEndian(buffer, offset); + } + + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit unsigned integer representing the value of the four bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ToUInt32LittleEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + return ToUInt32LittleEndian(b1, b2, b3, b4); + } + + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit signed integer representing the value of the four bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32LittleEndianSafe(byte[] buffer, int offset) + { + return (int)ToUInt32LittleEndianSafe(buffer, offset); + } + /// /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit unsigned integer, assuming /// little-endian byte order. @@ -408,9 +1257,69 @@ public static uint ToUInt32LittleEndian(byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt32LittleEndian(ReadOnlySpan buffer, int offset) { + if (buffer.Length - offset < 4) + { + throw new ArgumentException("Buffer must be at least 4 bytes long starting from the specified offset.", nameof(buffer)); + } + return ToUInt32LittleEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]); } + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit signed integer, assuming + /// little-endian byte order. + /// + /// The buffer containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit signed integer representing the value of the four bytes starting at the specified offset, interpreted + /// as little-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32LittleEndian(ReadOnlySpan buffer, int offset) + { + return (int)ToUInt32LittleEndian(buffer, offset); + } + + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit unsigned + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit unsigned integer representing the value of the four bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ToUInt32LittleEndianSafe(ReadOnlySpan buffer, int offset) + { + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + return ToUInt32LittleEndian(b1, b2, b3, b4); + } + + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit signed + /// integer using little-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit signed integer representing the value of the four bytes in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32LittleEndianSafe(ReadOnlySpan buffer, int offset) + { + return (int)ToUInt32LittleEndianSafe(buffer, offset); + } + /// /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned /// integer using big-endian byte order. @@ -423,9 +1332,29 @@ public static uint ToUInt32LittleEndian(ReadOnlySpan buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ToUInt64BigEndian(byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must contain at least 8 bytes starting from the specified offset.", nameof(buffer)); + } + return ToUInt64BigEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], buffer[offset + 4], buffer[offset + 5], buffer[offset + 6], buffer[offset + 7]); } + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using big-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the big-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64BigEndian(byte[] buffer, int offset) + { + return (long)ToUInt64BigEndian(buffer, offset); + } + /// /// Converts a sequence of bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned /// integer using big-endian byte order. @@ -440,9 +1369,123 @@ public static ulong ToUInt64BigEndian(byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ToUInt64BigEndian(ReadOnlySpan buffer, int offset) { + if (buffer.Length - offset < 8) + { + throw new ArgumentException("Buffer must be at least 8 bytes long starting from the specified offset.", nameof(buffer)); + } + return ToUInt64BigEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3], buffer[offset + 4], buffer[offset + 5], buffer[offset + 6], buffer[offset + 7]); } + /// + /// Converts a sequence of bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using big-endian byte order. + /// + /// This method assumes that the bytes in the buffer are stored in big-endian format, where the + /// most significant byte comes first. + /// The buffer containing the bytes to convert. Must have at least 8 bytes available starting from . + /// The zero-based index in at which to begin reading the bytes. + /// A 64-bit signed integer constructed from the 8 bytes starting at in big-endian + /// order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64BigEndian(ReadOnlySpan buffer, int offset) + { + return (long)ToUInt64BigEndian(buffer, offset); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit unsigned integer representing the big-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToUInt64BigEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + byte b5 = offset + 4 < len ? buffer[offset + 4] : (byte)0; + byte b6 = offset + 5 < len ? buffer[offset + 5] : (byte)0; + byte b7 = offset + 6 < len ? buffer[offset + 6] : (byte)0; + byte b8 = offset + 7 < len ? buffer[offset + 7] : (byte)0; + return ToUInt64BigEndian(b1, b2, b3, b4, b5, b6, b7, b8); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the big-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64BigEndianSafe(byte[] buffer, int offset) + { + return (long)ToUInt64BigEndianSafe(buffer, offset); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit unsigned + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit unsigned integer representing the big-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToUInt64BigEndianSafe(ReadOnlySpan buffer, int offset) + { + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset + 0 < len ? buffer[offset + 0] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + byte b5 = offset + 4 < len ? buffer[offset + 4] : (byte)0; + byte b6 = offset + 5 < len ? buffer[offset + 5] : (byte)0; + byte b7 = offset + 6 < len ? buffer[offset + 6] : (byte)0; + byte b8 = offset + 7 < len ? buffer[offset + 7] : (byte)0; + return ToUInt64BigEndian(b1, b2, b3, b4, b5, b6, b7, b8); + } + + /// + /// Converts a sequence of 8 bytes from the specified buffer, starting at the given offset, into a 64-bit signed + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least 8 bytes starting from . + /// The zero-based index in at which to begin reading the 8 bytes. + /// A 64-bit signed integer representing the big-endian interpretation of the 8 bytes starting at . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64BigEndianSafe(ReadOnlySpan buffer, int offset) + { + return (long)ToUInt64BigEndianSafe(buffer, offset); + } + /// /// Combines eight bytes into a single 64-bit unsigned integer, interpreting the bytes in big-endian order. /// @@ -471,6 +1514,27 @@ public static ulong ToUInt64BigEndian(byte v1, byte v2, byte v3, byte v4, byte v v8; } + /// + /// Combines eight bytes into a single 64-bit signed integer, interpreting the bytes in big-endian order. + /// + /// This method shifts each byte to its appropriate position in the 64-bit integer, with the most + /// significant byte placed at the highest position. It is optimized for performance and assumes the caller provides + /// all eight bytes in the correct order. + /// The most significant byte of the resulting 64-bit unsigned integer. + /// The second most significant byte of the resulting 64-bit unsigned integer. + /// The third most significant byte of the resulting 64-bit unsigned integer. + /// The fourth most significant byte of the resulting 64-bit unsigned integer. + /// The fifth most significant byte of the resulting 64-bit unsigned integer. + /// The sixth most significant byte of the resulting 64-bit unsigned integer. + /// The seventh most significant byte of the resulting 64-bit unsigned integer. + /// The least significant byte of the resulting 64-bit unsigned integer. + /// A 64-bit signed integer constructed from the specified bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt64BigEndian(byte v1, byte v2, byte v3, byte v4, byte v5, byte v6, byte v7, byte v8) + { + return (long)ToUInt64BigEndian(v1, v2, v3, v4, v5, v6, v7, v8); + } + /// /// Converts two bytes to a 16-bit unsigned integer, interpreting the bytes in big-endian order. /// @@ -483,6 +1547,18 @@ public static ushort ToUInt16BigEndian(byte v1, byte v2) return (ushort)((v1 << 8) | v2); } + /// + /// Converts two bytes to a 16-bit signed integer, interpreting the bytes in big-endian order. + /// + /// The most significant byte of the 16-bit unsigned integer. + /// The least significant byte of the 16-bit unsigned integer. + /// A 16-bit signed integer constructed from the specified bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short ToInt16BigEndian(byte v1, byte v2) + { + return (short)ToUInt16BigEndian(v1, v2); + } + /// /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned /// integer using big-endian byte order. @@ -494,9 +1570,137 @@ public static ushort ToUInt16BigEndian(byte v1, byte v2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt16BigEndian(byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 2) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer must contain at least two bytes starting from the specified offset."); + } + + return ToUInt16BigEndian(buffer[offset], buffer[offset + 1]); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using big-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt16BigEndian(byte[] buffer, int offset) + { + return (int)ToUInt16BigEndian(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using big-endian byte order. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ToUInt16BigEndian(ReadOnlySpan buffer, int offset) + { + if (buffer.Length - offset < 2) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer must contain at least two bytes starting from the specified offset."); + } + return ToUInt16BigEndian(buffer[offset], buffer[offset + 1]); } + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using big-endian byte order. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt16BigEndian(ReadOnlySpan buffer, int offset) + { + return (int)ToUInt16BigEndian(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToUInt16BigEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset < len ? buffer[offset] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + return ToUInt16BigEndian(b1, b2); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt16BigEndianSafe(byte[] buffer, int offset) + { + return (long)ToUInt16BigEndianSafe(buffer, offset); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit unsigned + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit unsigned integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong ToUInt16BigEndianSafe(ReadOnlySpan buffer, int offset) + { + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset < len ? buffer[offset] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + return ToUInt16BigEndian(b1, b2); + } + + /// + /// Converts a sequence of two bytes from the specified buffer, starting at the given offset, into a 16-bit signed + /// integer using big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the data to convert. Must contain at least two bytes starting from . + /// The zero-based index in at which to begin reading the two bytes. + /// A 16-bit signed integer representing the value of the two bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long ToInt16BigEndianSafe(ReadOnlySpan buffer, int offset) + { + return (long)ToUInt16BigEndianSafe(buffer, offset); + } + /// /// Converts four bytes to a 32-bit unsigned integer, interpreting the bytes in big-endian order. /// @@ -516,6 +1720,22 @@ public static uint ToUInt32BigEndian(byte v1, byte v2, byte v3, byte v4) v4; } + /// + /// Converts four bytes to a 32-bit signed integer, interpreting the bytes in big-endian order. + /// + /// This method assumes the input bytes are provided in big-endian order, where the most significant + /// byte is first and the least significant byte is last. + /// The most significant byte of the 32-bit unsigned integer. + /// The second most significant byte of the 32-bit unsigned integer. + /// The third most significant byte of the 32-bit unsigned integer. + /// The least significant byte of the 32-bit unsigned integer. + /// A 32-bit signed integer constructed from the specified bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32BigEndian(byte v1, byte v2, byte v3, byte v4) + { + return (int)ToUInt32BigEndian(v1, v2, v3, v4); + } + /// /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit unsigned /// integer using big-endian byte order. @@ -527,9 +1747,28 @@ public static uint ToUInt32BigEndian(byte v1, byte v2, byte v3, byte v4) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt32BigEndian(byte[] buffer, int offset) { + if (buffer == null || buffer.Length - offset < 4) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer must contain at least four bytes starting from the specified offset."); + } + return ToUInt32BigEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]); } + /// + /// Converts a sequence of four bytes from the specified buffer, starting at the given offset, into a 32-bit signed + /// integer using big-endian byte order. + /// + /// The byte array containing the data to convert. Must contain at least four bytes starting from . + /// The zero-based index in at which to begin reading the four bytes. + /// A 32-bit signed integer representing the value of the four bytes in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32BigEndian(byte[] buffer, int offset) + { + return (int)ToUInt32BigEndian(buffer, offset); + } + /// /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit unsigned integer, assuming /// big-endian byte order. @@ -542,16 +1781,133 @@ public static uint ToUInt32BigEndian(byte[] buffer, int offset) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ToUInt32BigEndian(ReadOnlySpan buffer, int offset) { + if (buffer.Length - offset < 4) + { + throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer must contain at least four bytes starting from the specified offset."); + } + return ToUInt32BigEndian(buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]); } + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit signed integer, assuming + /// big-endian byte order. + /// + /// The buffer containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit signed integer representing the value of the four bytes starting at the specified offset, interpreted + /// as big-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32BigEndian(ReadOnlySpan buffer, int offset) + { + return (int)ToUInt32BigEndian(buffer, offset); + } + + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit unsigned integer, assuming + /// big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit unsigned integer representing the value of the four bytes starting at the specified offset, interpreted + /// as big-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ToUInt32BigEndianSafe(ReadOnlySpan buffer, int offset) + { + if (buffer.IsEmpty) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset < len ? buffer[offset] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + return ToUInt32BigEndian(b1, b2, b3, b4); + } + + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit signed integer, assuming + /// big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The buffer containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit signed integer representing the value of the four bytes starting at the specified offset, interpreted + /// as big-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32BigEndianSafe(ReadOnlySpan buffer, int offset) + { + return (int)ToUInt32BigEndianSafe(buffer, offset); + } + + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit unsigned integer, assuming + /// big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit unsigned integer representing the value of the four bytes starting at the specified offset, interpreted + /// as big-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ToUInt32BigEndianSafe(byte[] buffer, int offset) + { + if (buffer == null) + { + return 0; + } + + int len = buffer.Length; + byte b1 = offset < len ? buffer[offset] : (byte)0; + byte b2 = offset + 1 < len ? buffer[offset + 1] : (byte)0; + byte b3 = offset + 2 < len ? buffer[offset + 2] : (byte)0; + byte b4 = offset + 3 < len ? buffer[offset + 3] : (byte)0; + return ToUInt32BigEndian(b1, b2, b3, b4); + } + + /// + /// Converts a sequence of bytes from a specified offset in a buffer to a 32-bit signed integer, assuming + /// big-endian byte order. This never throws an exception, but will apply 0 to any byte + /// that is out of range of the provided buffer. + /// + /// The byte array containing the bytes to convert. Must have at least four bytes available starting at the specified + /// offset. + /// The zero-based index in the buffer at which to begin reading the bytes. + /// A 32-bit signed integer representing the value of the four bytes starting at the specified offset, interpreted + /// as big-endian. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ToInt32BigEndianSafe(byte[] buffer, int offset) + { + return (int)ToUInt32BigEndianSafe(buffer, offset); + } + /// /// Converts the specified 64-bit unsigned integer to an array of bytes in little-endian order. /// - /// The 64-bit unsigned integer to convert. + /// The 64-bit unsigned integer to convert. + /// An array of 8 bytes representing the in little-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(ulong value) + { + byte[] bytes = new byte[8]; + ToLittleEndianBytes(value, bytes, 0); + return bytes; + } + + /// + /// Converts the specified 64-bit signed integer to an array of bytes in little-endian order. + /// + /// The 64-bit signed integer to convert. /// An array of 8 bytes representing the in little-endian order. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] GetBytesLittleEndian(ulong value) + public static byte[] GetBytesLittleEndian(long value) { byte[] bytes = new byte[8]; ToLittleEndianBytes(value, bytes, 0); @@ -571,6 +1927,19 @@ public static byte[] GetBytesLittleEndian(uint value) return bytes; } + /// + /// Converts the specified 32-bit signed integer to a byte array in little-endian format. + /// + /// The 32-bit signed integer to convert. + /// A byte array containing the little-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(int value) + { + byte[] bytes = new byte[4]; + ToLittleEndianBytes(value, bytes, 0); + return bytes; + } + /// /// Converts the specified 16-bit unsigned integer to a byte array in little-endian format. /// @@ -584,6 +1953,51 @@ public static byte[] GetBytesLittleEndian(ushort value) return bytes; } + /// + /// Converts the specified 16-bit signed integer to a byte array in little-endian format. + /// + /// The 16-bit signed integer to convert. + /// A byte array containing the little-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(short value) + { + byte[] bytes = new byte[2]; + ToLittleEndianBytes(value, bytes, 0); + return bytes; + } + + /// + /// Converts the specified 64-bit double-precision floating point number to a byte array in little-endian format. + /// + /// The 64-bit double-precision floating point number to convert. + /// A byte array containing the little-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(double value) + { + byte[] bytes = new byte[8]; + unsafe + { + ToLittleEndianBytes(*(ulong*)&value, bytes, 0); + } + return bytes; + } + + /// + /// Converts the specified 32-bit single-precision floating point number to a byte array in little-endian format. + /// + /// The 32-bit single-precision floating point number to convert. + /// A byte array containing the little-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(float value) + { + byte[] bytes = new byte[4]; + unsafe + { + ToLittleEndianBytes(*(uint*)&value, bytes, 0); + } + return bytes; + } + /// /// Converts an array of 64-bit unsigned integers to their little-endian byte representation. /// @@ -595,6 +2009,8 @@ public static byte[] GetBytesLittleEndian(ushort value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesLittleEndian(params ulong[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(ulong)]; for (int i = 0; i < values.Length; ++i) { @@ -616,6 +2032,8 @@ public static byte[] GetBytesLittleEndian(params ulong[] values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesLittleEndian(params uint[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(uint)]; for (int i = 0; i < values.Length; ++i) { @@ -637,6 +2055,8 @@ public static byte[] GetBytesLittleEndian(params uint[] values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesLittleEndian(params ushort[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(ushort)]; for (int i = 0; i < values.Length; ++i) { @@ -646,6 +2066,128 @@ public static byte[] GetBytesLittleEndian(params ushort[] values) return bytes; } + /// + /// Converts an array of 64-bit signed integers to their little-endian byte representation. + /// + /// This method ensures that each value is converted to its little-endian byte + /// order, regardless of the system's endianness. + /// An array of values to convert. Each value is represented as 8 bytes in the resulting array. + /// A byte array containing the little-endian representation of the input values. The length of the array is + /// values.Length * sizeof(long). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(params long[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(long)]; + for (int i = 0; i < values.Length; ++i) + { + ToLittleEndianBytes(values[i], bytes, i * sizeof(long)); + } + + return bytes; + } + + /// + /// Converts an array of signed 32-bit integers to their little-endian byte representation. + /// + /// Each integer in the input array is converted to its little-endian byte representation and stored + /// sequentially in the resulting byte array. The method ensures that the byte order is consistent with little-endian + /// format, regardless of the system's endianness. + /// An array of signed 32-bit integers to convert. Cannot be null. + /// A byte array containing the little-endian representation of the input integers. The length of the returned array + /// is values.Length * sizeof(int). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(params int[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(int)]; + for (int i = 0; i < values.Length; ++i) + { + ToLittleEndianBytes(values[i], bytes, i * sizeof(int)); + } + + return bytes; + } + + /// + /// Converts an array of 16-bit signed integers to a byte array in little-endian order. + /// + /// Each value in the input array is converted to its little-endian byte + /// representation and stored sequentially in the resulting byte array. The method ensures that the byte order is + /// consistent with little-endian systems, regardless of the platform's native endianness. + /// An array of values to convert to little-endian byte representation. + /// A byte array containing the little-endian representation of the input values. The length of the array is + /// values.Length * 2. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(params short[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(short)]; + for (int i = 0; i < values.Length; ++i) + { + ToLittleEndianBytes(values[i], bytes, i * sizeof(short)); + } + + return bytes; + } + + /// + /// Converts an array of 64-bit double-precision floating point number to a little-endian byte array. + /// + /// Each value in the input array is converted to its little-endian representation + /// and appended to the resulting byte array. The caller is responsible for ensuring the input array is not + /// null. + /// An array of values to convert. Cannot be null. + /// A byte array representing the input values in little-endian format. The length of the array is twice the number of + /// input values. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(params double[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(double)]; + for (int i = 0; i < values.Length; ++i) + { + unsafe + { + double d = values[i]; + ToLittleEndianBytes(*(ulong*)&d, bytes, i * sizeof(double)); + } + } + + return bytes; + } + + /// + /// Converts an array of 32-bit single-precision floating point number to a little-endian byte array. + /// + /// Each value in the input array is converted to its little-endian representation + /// and appended to the resulting byte array. The caller is responsible for ensuring the input array is not + /// null. + /// An array of values to convert. Cannot be null. + /// A byte array representing the input values in little-endian format. The length of the array is twice the number of + /// input values. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesLittleEndian(params float[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(float)]; + for (int i = 0; i < values.Length; ++i) + { + unsafe + { + float d = values[i]; + ToLittleEndianBytes(*(uint*)&d, bytes, i * sizeof(float)); + } + } + + return bytes; + } + /// /// Converts an array of 64-bit unsigned integers to their big-endian byte representation. /// @@ -658,6 +2200,8 @@ public static byte[] GetBytesLittleEndian(params ushort[] values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesBigEndian(params ulong[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(ulong)]; for (int i = 0; i < values.Length; ++i) { @@ -679,6 +2223,8 @@ public static byte[] GetBytesBigEndian(params ulong[] values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesBigEndian(params uint[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(uint)]; for (int i = 0; i < values.Length; ++i) { @@ -700,6 +2246,8 @@ public static byte[] GetBytesBigEndian(params uint[] values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] GetBytesBigEndian(params ushort[] values) { + _ = values ?? throw new ArgumentNullException(nameof(values)); + byte[] bytes = new byte[values.Length * sizeof(ushort)]; for (int i = 0; i < values.Length; ++i) { @@ -709,6 +2257,129 @@ public static byte[] GetBytesBigEndian(params ushort[] values) return bytes; } + /// + /// Converts an array of 64-bit signed integers to their big-endian byte representation. + /// + /// Each value in the input array is converted to an 8-byte big-endian sequence + /// and written sequentially into the returned byte array. The caller is responsible for ensuring that the input array + /// is not null. + /// An array of values to convert. Cannot be null. + /// A byte array containing the big-endian representation of the input values. The length of the returned array is + /// equal to values.Length * sizeof(long). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(params long[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(long)]; + for (int i = 0; i < values.Length; ++i) + { + ToBigEndianBytes(values[i], bytes, i * sizeof(long)); + } + + return bytes; + } + + /// + /// Converts an array of 32-bit signed integers to their big-endian byte representation. + /// + /// Each 32-bit signed integer in the input array is converted to a sequence of 4 bytes in + /// big-endian order (most significant byte first). The resulting bytes are concatenated into a single + /// array. + /// An array of 32-bit signed integers to convert. + /// A byte array containing the big-endian representation of the input values. The length of the returned array is + /// values.Length * sizeof(int). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(params int[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(int)]; + for (int i = 0; i < values.Length; ++i) + { + ToBigEndianBytes(values[i], bytes, i * sizeof(int)); + } + + return bytes; + } + + /// + /// Converts an array of 16-bit signed integers to a big-endian byte array. + /// + /// Each value in the input array is converted to its big-endian representation + /// and appended to the resulting byte array. The caller is responsible for ensuring the input array is not + /// null. + /// An array of values to convert. Cannot be null. + /// A byte array representing the input values in big-endian format. The length of the array is twice the number of + /// input values. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(params short[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(short)]; + for (int i = 0; i < values.Length; ++i) + { + ToBigEndianBytes(values[i], bytes, i * sizeof(short)); + } + + return bytes; + } + + /// + /// Converts an array of 64-bit double-precision floating point number to a big-endian byte array. + /// + /// Each value in the input array is converted to its big-endian representation + /// and appended to the resulting byte array. The caller is responsible for ensuring the input array is not + /// null. + /// An array of values to convert. Cannot be null. + /// A byte array representing the input values in big-endian format. The length of the array is twice the number of + /// input values. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(params double[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(double)]; + for (int i = 0; i < values.Length; ++i) + { + unsafe + { + double d = values[i]; + ToBigEndianBytes(*(ulong*)&d, bytes, i * sizeof(double)); + } + } + + return bytes; + } + + /// + /// Converts an array of 32-bit single-precision floating point number to a big-endian byte array. + /// + /// Each value in the input array is converted to its big-endian representation + /// and appended to the resulting byte array. The caller is responsible for ensuring the input array is not + /// null. + /// An array of values to convert. Cannot be null. + /// A byte array representing the input values in big-endian format. The length of the array is twice the number of + /// input values. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(params float[] values) + { + _ = values ?? throw new ArgumentNullException(nameof(values)); + + byte[] bytes = new byte[values.Length * sizeof(float)]; + for (int i = 0; i < values.Length; ++i) + { + unsafe + { + float d = values[i]; + ToBigEndianBytes(*(ulong*)&d, bytes, i * sizeof(float)); + } + } + + return bytes; + } + /// /// Converts the specified 64-bit unsigned integer to an array of bytes in big-endian order. /// @@ -747,5 +2418,76 @@ public static byte[] GetBytesBigEndian(ushort value) ToBigEndianBytes(value, bytes, 0); return bytes; } + + /// + /// Converts the specified 64-bit signed integer to an array of bytes in big-endian order. + /// + /// The 64-bit signed integer to convert. + /// An array of 8 bytes representing the in big-endian order. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(long value) + { + byte[] bytes = new byte[8]; + ToBigEndianBytes(value, bytes, 0); + return bytes; + } + + /// + /// Converts the specified 32-bit signed integer to a byte array in big-endian format. + /// + /// The 32-bit signed integer to convert. + /// A byte array containing the big-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(int value) + { + byte[] bytes = new byte[4]; + ToBigEndianBytes(value, bytes, 0); + return bytes; + } + + /// + /// Converts the specified 16-bit signed integer to a byte array in big-endian format. + /// + /// The 16-bit signed integer to convert. + /// A byte array containing the big-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(short value) + { + byte[] bytes = new byte[2]; + ToBigEndianBytes(value, bytes, 0); + return bytes; + } + + /// + /// Converts the specified 64-bit double-precision floating point number to a byte array in big-endian format. + /// + /// The 64-bit double-precision floating point number to convert. + /// A byte array containing the big-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(double value) + { + byte[] bytes = new byte[8]; + unsafe + { + ToBigEndianBytes(*(ulong*)&value, bytes, 0); + } + return bytes; + } + + /// + /// Converts the specified 32-bit single-precision floating point number to a byte array in big-endian format. + /// + /// The 32-bit single-precision floating point number to convert. + /// A byte array containing the big-endian representation of the specified value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetBytesBigEndian(float value) + { + byte[] bytes = new byte[4]; + unsafe + { + ToBigEndianBytes(*(uint*)&value, bytes, 0); + } + return bytes; + } } } From faa32b63d8ceaf4c09092ce086590dff8dba88cb Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 17:34:26 +0300 Subject: [PATCH 03/29] Upload V7 unit tests Signed-off-by: Xen --- .../Algorithms/CRC/CRCConfig_Tests.cs | 3 +- .../CRC/CRC_Implementation_Tests.cs | 73 ++- .../Algorithms/HashAlgorithmWrapper/Tests.cs | 434 ------------------ .../Core/HashAlgorithmWrapperConfig_Tests.cs | 2 +- .../Core/IHashFunction_Extensions_Tests.cs | 4 +- .../Core/IHashFunction_TestBase.cs | 24 +- .../Core/IStreamableHashFunction_TestBase.cs | 8 +- HashifyNet.UnitTests/Core/UniversalTest.cs | 8 +- .../Mocks/HashFunctionImpl.cs | 9 +- .../Utilities/HashValue_Tests.cs | 246 ++++++++-- 10 files changed, 312 insertions(+), 499 deletions(-) diff --git a/HashifyNet.UnitTests/Algorithms/CRC/CRCConfig_Tests.cs b/HashifyNet.UnitTests/Algorithms/CRC/CRCConfig_Tests.cs index 8d634f5..50943af 100644 --- a/HashifyNet.UnitTests/Algorithms/CRC/CRCConfig_Tests.cs +++ b/HashifyNet.UnitTests/Algorithms/CRC/CRCConfig_Tests.cs @@ -865,5 +865,4 @@ public void CRCConfig_Clone_Works() ), }; } -} - +} \ No newline at end of file diff --git a/HashifyNet.UnitTests/Algorithms/CRC/CRC_Implementation_Tests.cs b/HashifyNet.UnitTests/Algorithms/CRC/CRC_Implementation_Tests.cs index 5de97ac..1af4a16 100644 --- a/HashifyNet.UnitTests/Algorithms/CRC/CRC_Implementation_Tests.cs +++ b/HashifyNet.UnitTests/Algorithms/CRC/CRC_Implementation_Tests.cs @@ -188,6 +188,7 @@ public void CRC_Implementation_HashSizeInBits_MatchesConfig() public class IStreamableHashFunction_Tests_CRC3_ROHC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(3, "123456789", 0x6), @@ -200,6 +201,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC4_ITU : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(4, "123456789", 0x7), @@ -212,6 +214,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC5_EPC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues => new KnownValue[] { new KnownValue(5, "123456789", 0x00), @@ -224,6 +227,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC5_ITU : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues => new KnownValue[] { new KnownValue(5, "123456789", 0x07), @@ -236,6 +240,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC5_USB : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(5, "123456789", 0x19), @@ -248,6 +253,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC6_CDMA2000A : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(6, "123456789", 0x0d), @@ -260,6 +266,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC6_CDMA2000B : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(6, "123456789", 0x3b), @@ -272,6 +279,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC6_DARC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(6, "123456789", 0x26), @@ -284,6 +292,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC6_ITU : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(6, "123456789", 0x06), @@ -296,6 +305,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC7 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(7, "123456789", 0x75), @@ -308,6 +318,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC7_ROHC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(7, "123456789", 0x53), @@ -320,6 +331,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xf4), @@ -332,6 +344,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_CDMA2000 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xda), @@ -344,6 +357,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_DARC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0x15), @@ -356,6 +370,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_DVBS2 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xbc), @@ -368,6 +383,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_EBU : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0x97), @@ -380,6 +396,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_ICODE : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0x7e), @@ -392,6 +409,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_ITU : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xa1), @@ -404,6 +422,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_MAXIM : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xa1), @@ -416,6 +435,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_ROHC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0xd0), @@ -428,6 +448,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC8_WCDMA : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(8, "123456789", 0x25), @@ -440,6 +461,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC10 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(10, "123456789", 0x199), @@ -452,6 +474,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC10_CDMA2000 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(10, "123456789", 0x233), @@ -464,6 +487,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC11 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(11, "123456789", 0x5a3), @@ -476,6 +500,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC12_3GPP : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(12, "123456789", 0xdaf), @@ -488,6 +513,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC12_CDMA2000 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(12, "123456789", 0xd4d), @@ -500,6 +526,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC12_DECT : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(12, "123456789", 0xf5b), @@ -512,6 +539,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC13_BBC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(13, "123456789", 0x04fa), @@ -524,6 +552,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC14_DARC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(14, "123456789", 0x082d), @@ -536,6 +565,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC15 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(15, "123456789", 0x059e), @@ -548,6 +578,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC15_MPT1327 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(15, "123456789", 0x2566), @@ -560,6 +591,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_ARC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xbb3d), @@ -572,6 +604,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_AUGCCITT : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xe5cc), @@ -584,6 +617,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_BUYPASS : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xfee8), @@ -596,6 +630,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_CCITTFALSE : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x29b1), @@ -608,6 +643,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_CDMA2000 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x4c06), @@ -620,6 +656,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_DDS110 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x9ecf), @@ -632,6 +669,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_DECTR : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x007e), @@ -644,6 +682,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_DECTX : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x007f), @@ -656,6 +695,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_DNP : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xea82), @@ -668,6 +708,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_EN13757 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xc2b7), @@ -680,6 +721,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_GENIBUS : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xd64e), @@ -692,6 +734,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_MAXIM : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x44c2), @@ -704,6 +747,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_MCRF4XX : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x6f91), @@ -716,6 +760,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_RIELLO : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x63d0), @@ -728,6 +773,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_T10DIF : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xd0db), @@ -740,6 +786,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_TELEDISK : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x0fb3), @@ -752,6 +799,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_TMS37157 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x26b1), @@ -764,6 +812,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC16_USB : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xb4c8), @@ -776,6 +825,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRCA : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0xbf05), @@ -788,6 +838,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_KERMIT : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x2189), @@ -800,6 +851,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_MODBUS : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x4b37), @@ -812,6 +864,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_X25 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x906e), @@ -824,6 +877,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_XMODEM : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(16, "123456789", 0x31c3), @@ -836,6 +890,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC24 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(24, "123456789", 0x21cf02), @@ -848,6 +903,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC24_FLEXRAYA : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(24, "123456789", 0x7979bd), @@ -860,6 +916,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC24_FLEXRAYB : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(24, "123456789", 0x1f23b8), @@ -872,6 +929,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC31_PHILIPS : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(31, "123456789", 0x0ce9e46c), @@ -884,6 +942,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0xcbf43926), @@ -896,6 +955,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32_BZIP2 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0xfc891918), @@ -908,6 +968,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32C : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0xe3069283), @@ -920,6 +981,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32D : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0x87315576), @@ -932,6 +994,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32_MPEG2 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0x0376e6e7), @@ -944,6 +1007,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32_POSIX : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0x765e7680), @@ -956,6 +1020,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC32Q : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0x3010bf7f), @@ -968,6 +1033,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_JAMCRC : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0x340bc6d9), @@ -980,6 +1046,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_XFER : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(32, "123456789", 0xbd0be338), @@ -992,6 +1059,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC40_GSM : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(40, "123456789", 0xd4164fc646), @@ -1004,6 +1072,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC64 : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(64, "123456789", 0x6c40df5f0b497347), @@ -1016,6 +1085,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC64_WE : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(64, "123456789", 0x62ec59e3f1a4f00a), @@ -1028,6 +1098,7 @@ protected override ICRC CreateHashFunction(int hashSize) => public class IStreamableHashFunction_Tests_CRC64_XZ : IStreamableHashFunction_TestBase { + protected override ValueEndianness? FixedEndianness => ValueEndianness.LittleEndian; protected override IEnumerable KnownValues { get; } = new KnownValue[] { new KnownValue(64, "123456789", 0x995dc9bbdf1939fa), @@ -1037,4 +1108,4 @@ protected override ICRC CreateHashFunction(int hashSize) => new CRC_Implementation(new CRCConfigProfileCRC64_XZ()); } } -} +} \ No newline at end of file diff --git a/HashifyNet.UnitTests/Algorithms/HashAlgorithmWrapper/Tests.cs b/HashifyNet.UnitTests/Algorithms/HashAlgorithmWrapper/Tests.cs index 892ed3b..e33ea73 100644 --- a/HashifyNet.UnitTests/Algorithms/HashAlgorithmWrapper/Tests.cs +++ b/HashifyNet.UnitTests/Algorithms/HashAlgorithmWrapper/Tests.cs @@ -28,14 +28,6 @@ // * using Moq; -using HashifyNet.Algorithms.HMACMD5; -using HashifyNet.Algorithms.HMACSHA1; -using HashifyNet.Algorithms.HMACSHA256; -using HashifyNet.Algorithms.HMACSHA384; -using HashifyNet.Algorithms.HMACSHA512; -using HashifyNet.Algorithms.HMACSHA3_256; -using HashifyNet.Algorithms.HMACSHA3_384; -using HashifyNet.Algorithms.HMACSHA3_512; using HashifyNet.Algorithms.MD5; using HashifyNet.Algorithms.SHA1; using HashifyNet.Algorithms.SHA256; @@ -49,432 +41,6 @@ namespace HashifyNet.UnitTests.Algorithms.HashAlgorithmWrapper { public class Tests { -#region HMACMD5_Tests - -#region HMACMD5_Constructor - -#region HMACMD5_Config - - [Fact] - public void HMACMD5_Implementation_Constructor_Config_IsNull_Throws() - { - Assert.Equal( - "config", - Assert.Throws( - () => new HMACMD5_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACMD5_Implementation_Constructor_Config_IsCloned() - { - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(128); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACMD5Config()); - } - - GC.KeepAlive( - new HMACMD5_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACMD5_Config - -#endregion // HMACMD5_Constructor - -#region HMACMD5_ConfigValidation - [Fact] - public void HMACMD5Config_Defaults_HaventChanged() - { - var config = new HMACMD5Config(); - Assert.Equal(128, config.HashSizeInBits); - } -#endregion // HMACMD5_ConfigValidation - -#endregion // HMACMD5_Tests - -#region HMACSHA1_Tests - -#region HMACSHA1_Constructor - -#region HMACSHA1_Config - - [Fact] - public void HMACSHA1_Implementation_Constructor_Config_IsNull_Throws() - { - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA1_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA1_Implementation_Constructor_Config_IsCloned() - { - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(160); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA1Config()); - } - - GC.KeepAlive( - new HMACSHA1_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA1_Config - -#endregion // HMACSHA1_Constructor - -#region HMACSHA1_ConfigValidation - [Fact] - public void HMACSHA1Config_Defaults_HaventChanged() - { - var config = new HMACSHA1Config(); - Assert.Equal(160, config.HashSizeInBits); - } -#endregion // HMACSHA1_ConfigValidation - -#endregion // HMACSHA1_Tests - -#region HMACSHA256_Tests - -#region HMACSHA256_Constructor - -#region HMACSHA256_Config - - [Fact] - public void HMACSHA256_Implementation_Constructor_Config_IsNull_Throws() - { - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA256_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA256_Implementation_Constructor_Config_IsCloned() - { - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(256); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA256Config()); - } - - GC.KeepAlive( - new HMACSHA256_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA256_Config - -#endregion // HMACSHA256_Constructor - -#region HMACSHA256_ConfigValidation - [Fact] - public void HMACSHA256Config_Defaults_HaventChanged() - { - var config = new HMACSHA256Config(); - Assert.Equal(256, config.HashSizeInBits); - } -#endregion // HMACSHA256_ConfigValidation - -#endregion // HMACSHA256_Tests - -#region HMACSHA384_Tests - -#region HMACSHA384_Constructor - -#region HMACSHA384_Config - - [Fact] - public void HMACSHA384_Implementation_Constructor_Config_IsNull_Throws() - { - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA384_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA384_Implementation_Constructor_Config_IsCloned() - { - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(384); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA384Config()); - } - - GC.KeepAlive( - new HMACSHA384_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA384_Config - -#endregion // HMACSHA384_Constructor - -#region HMACSHA384_ConfigValidation - [Fact] - public void HMACSHA384Config_Defaults_HaventChanged() - { - var config = new HMACSHA384Config(); - Assert.Equal(384, config.HashSizeInBits); - } -#endregion // HMACSHA384_ConfigValidation - -#endregion // HMACSHA384_Tests - -#region HMACSHA512_Tests - -#region HMACSHA512_Constructor - -#region HMACSHA512_Config - - [Fact] - public void HMACSHA512_Implementation_Constructor_Config_IsNull_Throws() - { - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA512_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA512_Implementation_Constructor_Config_IsCloned() - { - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(512); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA512Config()); - } - - GC.KeepAlive( - new HMACSHA512_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA512_Config - -#endregion // HMACSHA512_Constructor - -#region HMACSHA512_ConfigValidation - [Fact] - public void HMACSHA512Config_Defaults_HaventChanged() - { - var config = new HMACSHA512Config(); - Assert.Equal(512, config.HashSizeInBits); - } -#endregion // HMACSHA512_ConfigValidation - -#endregion // HMACSHA512_Tests - -#region HMACSHA3_256_Tests - -#region HMACSHA3_256_Constructor - -#region HMACSHA3_256_Config - - [Fact] - public void HMACSHA3_256_Implementation_Constructor_Config_IsNull_Throws() - { - if (!IHMACSHA3_256.IsSupported) return; - - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA3_256_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA3_256_Implementation_Constructor_Config_IsCloned() - { - if (!IHMACSHA3_256.IsSupported) return; - - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(256); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA3_256Config()); - } - - GC.KeepAlive( - new HMACSHA3_256_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA3_256_Config - -#endregion // HMACSHA3_256_Constructor - -#region HMACSHA3_256_ConfigValidation - [Fact] - public void HMACSHA3_256Config_Defaults_HaventChanged() - { - if (!IHMACSHA3_256.IsSupported) return; - - var config = new HMACSHA3_256Config(); - Assert.Equal(256, config.HashSizeInBits); - } -#endregion // HMACSHA3_256_ConfigValidation - -#endregion // HMACSHA3_256_Tests - -#region HMACSHA3_384_Tests - -#region HMACSHA3_384_Constructor - -#region HMACSHA3_384_Config - - [Fact] - public void HMACSHA3_384_Implementation_Constructor_Config_IsNull_Throws() - { - if (!IHMACSHA3_384.IsSupported) return; - - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA3_384_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA3_384_Implementation_Constructor_Config_IsCloned() - { - if (!IHMACSHA3_384.IsSupported) return; - - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(384); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA3_384Config()); - } - - GC.KeepAlive( - new HMACSHA3_384_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA3_384_Config - -#endregion // HMACSHA3_384_Constructor - -#region HMACSHA3_384_ConfigValidation - [Fact] - public void HMACSHA3_384Config_Defaults_HaventChanged() - { - if (!IHMACSHA3_384.IsSupported) return; - - var config = new HMACSHA3_384Config(); - Assert.Equal(384, config.HashSizeInBits); - } -#endregion // HMACSHA3_384_ConfigValidation - -#endregion // HMACSHA3_384_Tests - -#region HMACSHA3_512_Tests - -#region HMACSHA3_512_Constructor - -#region HMACSHA3_512_Config - - [Fact] - public void HMACSHA3_512_Implementation_Constructor_Config_IsNull_Throws() - { - if (!IHMACSHA3_512.IsSupported) return; - - Assert.Equal( - "config", - Assert.Throws( - () => new HMACSHA3_512_Implementation(null)) - .ParamName); - } - - [Fact] - public void HMACSHA3_512_Implementation_Constructor_Config_IsCloned() - { - if (!IHMACSHA3_512.IsSupported) return; - - var configMock = new Mock(); - { - configMock.Setup(bc => bc.HashSizeInBits) - .Returns(512); - - configMock.Setup(bc => bc.Clone()) - .Returns(new HMACSHA3_512Config()); - } - - GC.KeepAlive( - new HMACSHA3_512_Implementation(configMock.Object)); - - configMock.Verify(bc => bc.Clone(), Times.Once); - - configMock.VerifyGet(bc => bc.HashSizeInBits, Times.Never); - } - -#endregion // HMACSHA3_512_Config - -#endregion // HMACSHA3_512_Constructor - -#region HMACSHA3_512_ConfigValidation - [Fact] - public void HMACSHA3_512Config_Defaults_HaventChanged() - { - if (!IHMACSHA3_512.IsSupported) return; - - var config = new HMACSHA3_512Config(); - Assert.Equal(512, config.HashSizeInBits); - } -#endregion // HMACSHA3_512_ConfigValidation - -#endregion // HMACSHA3_512_Tests - #region MD5_Tests #region MD5_Constructor diff --git a/HashifyNet.UnitTests/Core/HashAlgorithmWrapperConfig_Tests.cs b/HashifyNet.UnitTests/Core/HashAlgorithmWrapperConfig_Tests.cs index 4eb1aa1..706dd04 100644 --- a/HashifyNet.UnitTests/Core/HashAlgorithmWrapperConfig_Tests.cs +++ b/HashifyNet.UnitTests/Core/HashAlgorithmWrapperConfig_Tests.cs @@ -45,7 +45,7 @@ public void HashAlgorithmWrapperConfig_Defaults_HaventChanged() [Fact] public void HashAlgorithmWrapperConfig_Clone_Works() { - var hashAlgorithmWrapperConfig = new HashAlgorithmWrapperConfig(static () => SHA1.Create(), 160); + var hashAlgorithmWrapperConfig = new HashAlgorithmWrapperConfig(static () => IncrementalHash.CreateHash(HashAlgorithmName.SHA1), 160); var hashAlgorithmWrapperConfigClone = hashAlgorithmWrapperConfig.Clone(); diff --git a/HashifyNet.UnitTests/Core/IHashFunction_Extensions_Tests.cs b/HashifyNet.UnitTests/Core/IHashFunction_Extensions_Tests.cs index 36595c5..52732df 100644 --- a/HashifyNet.UnitTests/Core/IHashFunction_Extensions_Tests.cs +++ b/HashifyNet.UnitTests/Core/IHashFunction_Extensions_Tests.cs @@ -389,6 +389,4 @@ public void IHashFunction_Extensions_ComputeHash_WithDesiredBits_byteArray() } } } - -} - +} \ No newline at end of file diff --git a/HashifyNet.UnitTests/Core/IHashFunction_TestBase.cs b/HashifyNet.UnitTests/Core/IHashFunction_TestBase.cs index 835bacb..0485c16 100644 --- a/HashifyNet.UnitTests/Core/IHashFunction_TestBase.cs +++ b/HashifyNet.UnitTests/Core/IHashFunction_TestBase.cs @@ -35,19 +35,36 @@ namespace HashifyNet.UnitTests public abstract class IHashFunction_TestBase where THashFunction : IHashFunction where CName : IHashConfig { + protected virtual ValueEndianness? FixedEndianness => null; protected abstract IEnumerable KnownValues { get; } + protected IHashValue GetResult(IHashValue result) + { + if (result.Endianness != ValueEndianness.NotApplicable) + { + if (FixedEndianness.HasValue) + { + if (result.Endianness != FixedEndianness.Value) + { + result = result.ReverseEndianness(); + } + } + } + + return result; + } + [Fact] public void IHashFunction_ComputeHash_ByteArray_MatchesKnownValues() { foreach (var knownValue in KnownValues) { var hf = CreateHashFunction(knownValue.HashSize); - var hashResults = ComputeHash(hf, knownValue.TestValue); + var hashResults = GetResult(ComputeHash(hf, knownValue.TestValue)); IHashConfig config = hf.Config; Assert.Equal( - new HashValue(knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), + new HashValue(ValueEndianness.NotApplicable, knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), hashResults); } } @@ -110,5 +127,4 @@ private static byte[] ToBytes(ulong value, int bitLength) return valueBytes; } } - -} +} \ No newline at end of file diff --git a/HashifyNet.UnitTests/Core/IStreamableHashFunction_TestBase.cs b/HashifyNet.UnitTests/Core/IStreamableHashFunction_TestBase.cs index 060b738..34f2deb 100644 --- a/HashifyNet.UnitTests/Core/IStreamableHashFunction_TestBase.cs +++ b/HashifyNet.UnitTests/Core/IStreamableHashFunction_TestBase.cs @@ -47,10 +47,10 @@ public async Task IStreamableHashFunction_ComputeHashAsync_Stream_Seekable_Match using (var ms = new SlowAsyncStream(new MemoryStream(knownValue.TestValue))) { - var hashResults = await hf.ComputeHashAsync(ms); + var hashResults = GetResult(await hf.ComputeHashAsync(ms)); Assert.Equal( - new HashValue(knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), + new HashValue(ValueEndianness.NotApplicable, knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), hashResults); } } @@ -67,10 +67,10 @@ public async Task IStreamableHashFunction_ComputeHashAsync_Stream_Seekable_Match using (var ms = new SlowAsyncStream(new MemoryStream(knownValue.TestValue))) { - var hashResults = await hf.ComputeHashAsync(ms); + var hashResults = GetResult(await hf.ComputeHashAsync(ms)); Assert.Equal( - new HashValue(knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), + new HashValue(ValueEndianness.NotApplicable, knownValue.ExpectedValue.Take((config.HashSizeInBits + 7) / 8), config.HashSizeInBits), hashResults); } } diff --git a/HashifyNet.UnitTests/Core/UniversalTest.cs b/HashifyNet.UnitTests/Core/UniversalTest.cs index dc01478..cc477d2 100644 --- a/HashifyNet.UnitTests/Core/UniversalTest.cs +++ b/HashifyNet.UnitTests/Core/UniversalTest.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -31,9 +31,6 @@ using HashifyNet.Algorithms.BuzHash; using HashifyNet.Algorithms.CRC; using HashifyNet.Algorithms.FNV; -using HashifyNet.Algorithms.HMACSHA3_256; -using HashifyNet.Algorithms.HMACSHA3_384; -using HashifyNet.Algorithms.HMACSHA3_512; using HashifyNet.Algorithms.Pearson; using HashifyNet.Algorithms.SHA3_256; using HashifyNet.Algorithms.SHA3_384; @@ -697,6 +694,3 @@ public void RunUniversalTest() } } } - - - diff --git a/HashifyNet.UnitTests/Mocks/HashFunctionImpl.cs b/HashifyNet.UnitTests/Mocks/HashFunctionImpl.cs index 26c9a15..6047f35 100644 --- a/HashifyNet.UnitTests/Mocks/HashFunctionImpl.cs +++ b/HashifyNet.UnitTests/Mocks/HashFunctionImpl.cs @@ -33,9 +33,8 @@ namespace HashifyNet.UnitTests.Mocks { public class HashFunctionImpl - : HashFunctionBase where CName : IHashConfig + : HashFunctionBase where CName : IHashConfig, new() { - public Func, CancellationToken, IHashValue> OnComputeHashInternal { get; set; } = (_, __) => new HashValue(new byte[1], 1); private readonly CName _config; public override CName Config => _config.Clone(); @@ -43,10 +42,10 @@ public HashFunctionImpl(CName cname) { _config = cname; } - - protected override IHashValue ComputeHashInternal(ArraySegment data, CancellationToken cancellationToken) + + protected override IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken) { - return OnComputeHashInternal(data, cancellationToken); + return new HashValue(ValueEndianness.NotApplicable, new byte[1], 1); } } } \ No newline at end of file diff --git a/HashifyNet.UnitTests/Utilities/HashValue_Tests.cs b/HashifyNet.UnitTests/Utilities/HashValue_Tests.cs index 73fd99c..97d1ecb 100644 --- a/HashifyNet.UnitTests/Utilities/HashValue_Tests.cs +++ b/HashifyNet.UnitTests/Utilities/HashValue_Tests.cs @@ -27,6 +27,7 @@ // ****************************************************************************** // * +using HashifyNet.Algorithms.Blake2; using HashifyNet.Core.Utilities; using Moq; using System.Collections.Immutable; @@ -43,11 +44,11 @@ public void HashValue_Constructor_ValidParameters_Works() { // Enumerable GC.KeepAlive( - new HashValue(Enumerable.Range(0, 1).Select(i => (byte)i), 8)); + new HashValue(ValueEndianness.NotApplicable, Enumerable.Range(0, 1).Select(i => (byte)i), 8)); // Non-enumerable GC.KeepAlive( - new HashValue(new byte[1], 8)); + new HashValue(ValueEndianness.NotApplicable, new byte[1], 8)); } [Fact] @@ -65,11 +66,11 @@ public void HashValue_Constructor_CoerceToArray_WorksAsExpected() foreach (var underlyingHashValue in underlyingHashValues) { var hashValues = new[] { - new HashValue(ArrayHelpers.CoerceToArray(underlyingHashValue, 8), 8), - new HashValue(ArrayHelpers.CoerceToArray(underlyingHashValue, 9), 9), - new HashValue(ArrayHelpers.CoerceToArray(underlyingHashValue, 10), 10), - new HashValue(ArrayHelpers.CoerceToArray(underlyingHashValue, 16), 16), - new HashValue(ArrayHelpers.CoerceToArray(underlyingHashValue, 24), 24) + new HashValue(ValueEndianness.NotApplicable, ArrayHelpers.CoerceToArray(underlyingHashValue, 8), 8), + new HashValue(ValueEndianness.NotApplicable, ArrayHelpers.CoerceToArray(underlyingHashValue, 9), 9), + new HashValue(ValueEndianness.NotApplicable, ArrayHelpers.CoerceToArray(underlyingHashValue, 10), 10), + new HashValue(ValueEndianness.NotApplicable, ArrayHelpers.CoerceToArray(underlyingHashValue, 16), 16), + new HashValue(ValueEndianness.NotApplicable, ArrayHelpers.CoerceToArray(underlyingHashValue, 24), 24) }; Assert.Equal(new byte[] { 1 }, hashValues[0].Hash); @@ -87,8 +88,8 @@ public void HashValue_Constructor_Hash_IsNull_Throws() { Assert.Equal( "hash", - Assert.Throws(() => - new HashValue(null, 8)) + Assert.Throws(() => + new HashValue(ValueEndianness.NotApplicable, null, 8)) .ParamName); } @@ -106,7 +107,7 @@ public void HashValue_Constructor_BitLength_IsInvalid_Throws() Assert.Equal( "bitLength", Assert.Throws(() => - new HashValue(new byte[1], invalidBitLength)) + new HashValue(ValueEndianness.NotApplicable, new byte[1], invalidBitLength)) .ParamName); } } @@ -124,7 +125,7 @@ public void HashValue_Hash_IsCopyOfConstructorValue() { var enumerableValue = Enumerable.Range(2, 1).Select(i => (byte)i); - var hashValue = new HashValue(enumerableValue, 8); + var hashValue = new HashValue(ValueEndianness.NotApplicable, enumerableValue, 8); Assert.NotStrictEqual(enumerableValue, hashValue.AsByteArray()); Assert.Equal(enumerableValue, hashValue.AsByteArray()); @@ -134,7 +135,7 @@ public void HashValue_Hash_IsCopyOfConstructorValue() { var arrayValue = new byte[] { 2 }; - var hashValue = new HashValue(arrayValue, 8); + var hashValue = new HashValue(ValueEndianness.NotApplicable, arrayValue, 8); Assert.NotStrictEqual(arrayValue, hashValue.AsByteArray()); Assert.Equal(arrayValue, hashValue.AsByteArray()); @@ -154,7 +155,7 @@ public void HashValue_BitLength_IsSameAsConstructorValue() { byte[] orig = new byte[2]; byte[] coerced = ArrayHelpers.CoerceToArray(orig, validBitLength); - var hashValue = new HashValue(coerced, validBitLength); + var hashValue = new HashValue(ValueEndianness.NotApplicable, coerced, validBitLength); Assert.Equal(validBitLength, hashValue.BitLength); } @@ -168,12 +169,12 @@ public void HashValue_BitLength_IsSameAsConstructorValue() public void HashValue_AsBase64String_ExpectedValues() { var knownValues = new[] { - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("f"), 8), Base64String = "Zg==" }, - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("fo"), 16), Base64String = "Zm8=" }, - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("foo"), 24), Base64String = "Zm9v" }, - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("foob"), 32), Base64String = "Zm9vYg==" }, - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("fooba"), 40), Base64String = "Zm9vYmE=" }, - new { HashValue = new HashValue(Encoding.ASCII.GetBytes("foobar"), 48), Base64String = "Zm9vYmFy" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("f"), 8), Base64String = "Zg==" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("fo"), 16), Base64String = "Zm8=" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("foo"), 24), Base64String = "Zm9v" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("foob"), 32), Base64String = "Zm9vYg==" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("fooba"), 40), Base64String = "Zm9vYmE=" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, Encoding.ASCII.GetBytes("foobar"), 48), Base64String = "Zm9vYmFy" }, }; foreach (var knownValue in knownValues) @@ -191,7 +192,7 @@ public void HashValue_AsBase64String_ExpectedValues() [Fact] public void HashValue_AsBitArray_ExpectedValues() { - var hashValue = new HashValue(new byte[] { 173 }, 8); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173 }, 8); var bitArray = hashValue.AsBitArray(); Assert.True(bitArray[0]); @@ -211,19 +212,189 @@ public void HashValue_AsBitArray_ExpectedValues() [Fact] public void HashValue_AsHexString_ExpectedValue() { - var hashValue = new HashValue(new byte[] { 173, 0, 255 }, 24); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 255 }, 24); Assert.Equal( - "ad00ff", + "AD00FF", hashValue.AsHexString()); + } + #endregion - Assert.Equal( - "ad00ff", - hashValue.AsHexString(false)); + #region AsByteArray + [Fact] + public void HashValue_AsByteArray_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0 }, 8), ByteArray = new byte[] { 0 } }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0, 0 }, 16), ByteArray = new byte[] { 0, 0 } }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 255 }, 24), ByteArray = new byte[] { 173, 0, 255 } }, + }; - Assert.Equal( - "AD00FF", - hashValue.AsHexString(true)); + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.ByteArray, + knownValue.HashValue.AsByteArray()); + } + } + #endregion + + #region AsBase32String + [Fact] + public void HashValue_AsBase32String_Rfc4648_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base32String = "MZXW6YTBOI======" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base32String = "KRUGKIDROVUWG2ZAMJZG653OEBTG66BANJ2W24DTEBXXMZLSEB2GQZJANRQXU6JAMRXWO===" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base32String = "JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3THEBSWY2LUFYQCAVLUEBXXE3TBOJSSAYLMNFYXKYLNEBWWC5LSNFZSYIDBOQQHM33MOV2HAYLUEBWWC43TMEXCAICQNBQXGZLMNR2XGIDQOVWHM2LOMFZCA4DVOJ2XGIDFOUQHMZLOMVXGC5DJOMQGG33NNVXWI3ZO" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base32String, + knownValue.HashValue.AsBase32String()); + } + } + + [Fact] + public void HashValue_AsBase32String_Crockford_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base32String = "CSQPYRK1E8" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base32String = "AHM6A83HENMP6TS0C9S6YXVE41K6YY10D9TPTW3K41QQCSBJ41T6GS90DHGQMY90CHQPE" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base32String = "9HQQ4SBD41MQ0WVNDMG68VVCDXS20WV9EGG62VB5EGP20RVFDSSPARVMCNT7AWH0C5J6JW39EDHPJVK741JPRTBM5RG20NBM41QQ4VK1E9JJ0RBCD5RQARBD41PP2XBJD5SJR831EGG7CVVCENT70RBM41PP2WVKC4Q2082GD1GQ6SBCDHTQ683GENP7CTBEC5S20W3NE9TQ6835EMG7CSBECNQ62X39ECG66VVDDNQP8VSE" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base32String, + knownValue.HashValue.AsBase32String(Base32Variant.Crockford)); + } + } + #endregion + + #region AsBase58String + [Fact] + public void HashValue_AsBase58String_Bitcoin_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base58String = "t1Zv2yaZ" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base58String = "7DdiPPYtxLjCD3wA1po2rvZHTDYjkZYiEtazrfiwJcwnKCizhGFhBGHeRdx" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base58String = "ANTbBh3nk9K3wfs1J43pynEbvAQiZP4k1uVXJhQZdBpEv9MncAngn1BFz3sCykR9GDwBfvLXJgds29L8r3ogWWPpxEBZeHnsF7pVXdfkQwTueyLc8Rf5FKZe7fFYmLwsTnYTS8jsAYWGqKnL3QsJTiuZgUAF9NKRyyG3Tz4Fn2MHrtTXyMYPq9q4msyo35fxivnkf9WXzRrzH" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base58String, + knownValue.HashValue.AsBase58String()); // Base58Variant.Bitcoin + } + } + + [Fact] + public void HashValue_AsBase58String_Flickr_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base58String = "T1yV2Yzy" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base58String = "7dCHooxTXkJcd3Wa1PN2RVyhsdxJKyxHeTzZREHWiBWMjcHZGgfGbghDqCX" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base58String = "ansAbG3MK9j3WES1i43PYMeAVapHyo4K1UuwiGpyCbPeV9mMBaMFM1bfZ3ScYKq9gdWbEVkwiFCS29k8R3NFvvoPXebyDhMSf7PuwCEKpWsUDYkB8qE5fjyD7EfxLkWSsMxsr8JSaxvgQjMk3pSisHUyFtaf9njqYYg3sZ4fM2mhRTswYmxoQ9Q4LSYN35EXHVMKE9vwZqRZh" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base58String, + knownValue.HashValue.AsBase58String(Base58Variant.Flickr)); + } + } + + [Fact] + public void HashValue_AsBase58String_Ripple_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base58String = "trZvpy2Z" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base58String = "fDd5PPYtxLjUDsAwrFopivZHTDYjkZY5Nt2ziC5AJcA8KU5z6GE6BGHeRdx" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base58String = "w4TbB6s8k9KsAC1rJhsFy8NbvwQ5ZPhkruVXJ6QZdBFNv9M8cw8g8rBEzs1UykR9GDABCvLXJgd1p9L3isogWWPFxNBZeH81EfFVXdCkQATueyLc3RCnEKZefCEYmLA1T8YTS3j1wYWGqK8LsQ1JT5uZg7wE94KRyyGsTzhE8pMHitTXyMYPq9qhm1yosnCx5v8kC9WXzRizH" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base58String, + knownValue.HashValue.AsBase58String(Base58Variant.Ripple)); + } + } + #endregion + + #region AsBase85String + [Fact] + public void HashValue_AsBase85String_Ascii85_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base85String = "AoDTs@<)" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base85String = "<+ohcEHPu*CER),Dg-(AAoDo:C3=B4F!,CEATAo8BOr<&@=!2AA8c)" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base85String = "9Q+r_D'3P3F*2=BA8c:&EZfF;F" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base85String, + knownValue.HashValue.AsBase85String(Base85Variant.AdobeAscii85)); + } + } + + [Fact] + public void HashValue_AsBase85String_Z85_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base85String = "w]zP%vr8" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base85String = "ra]?=ADL#9yAN8bz*c7ww]z]pyisxjB0byAwPw]nxK@r5vs0hwwn=8" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base85String = "oMa@.z6iLiB9hsxwn=p5AV/BqBrC1ewPPECv@DmawN/*[BAIQDvpT7>x(^=#zF786y?W#zarTWaaA8prvrb{4vqGT$BZYbfzddNcx(+*FvrrSnz!%MrAa9&hzddHbvj&VBp?ToUwO=g9B0bBAy<6Jgvr9GfB-IRCaz2WrC4CM5zEET3B0a$hzeBi4z.q" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base85String, + knownValue.HashValue.AsBase85String(Base85Variant.Z85)); + } + } + + [Fact] + public void HashValue_AsBase85String_Rfc1924_ExpectedValues() + { + var knownValues = new[] { + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.FooBar, TestConstants.FooBar.Length * 8), Base85String = "W^Zp|VR8" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.QuickBrownFox, TestConstants.QuickBrownFox.Length * 8), Base85String = "RA^-&adl~9Yan8BZ+C7WW^Z^PYISXJb0BYaWpW^NXk{R5VS0HWWN&8" }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, TestConstants.LoremIpsum, TestConstants.LoremIpsum.Length * 8), Base85String = "OmA{!Z6IlIb9HSXWN&P5av*bQbRc1EWppecV{dMAWn*+@baiqdVPt7=X>(&~Zf786Y-w~ZARtwAAa8PRVRB_4VQgt}bzyBFZDDnCX>%+fVRRsNZ)|mRaA9;HZDDhBVJ;vbP-tOuWo&G9b0BbaY<6jGVR9gFb#ircAZ2wRc4cm5Zeet3b0A}HZEbI4Z!Q" }, + }; + + foreach (var knownValue in knownValues) + { + Assert.Equal( + knownValue.Base85String, + knownValue.HashValue.AsBase85String(Base85Variant.Rfc1924)); + } } #endregion @@ -233,10 +404,10 @@ public void HashValue_AsHexString_ExpectedValue() public void HashValue_GetHashCode_ExpectedValues() { var knownValues = new[] { - new { HashValue = new HashValue(new byte[] { 0 }, 4), HashCode = 16213 }, - new { HashValue = new HashValue(new byte[] { 0 }, 8), HashCode = 16089 }, - new { HashValue = new HashValue(new byte[] { 0, 0 }, 12), HashCode = 494915 }, - new { HashValue = new HashValue(new byte[] { 0, 0 }, 16), HashCode = 521823 }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0 }, 4), HashCode = 16213 }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0 }, 8), HashCode = 16089 }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0, 0 }, 12), HashCode = 494915 }, + new { HashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 0, 0 }, 16), HashCode = 521823 }, }; foreach (var knownValue in knownValues) @@ -255,7 +426,7 @@ public void HashValue_GetHashCode_ExpectedValues() public void HashValue_Equals_Works() { { - var hashValue = new HashValue(new byte[] { 173, 0, 255 }, 24); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 255 }, 24); Assert.False(hashValue.Equals(null)); Assert.False(hashValue.Equals((object)null)); @@ -268,21 +439,21 @@ public void HashValue_Equals_Works() } { - var hashValue = new HashValue(new byte[] { 173, 0, 254 }, 24); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 254 }, 24); var mockValue = Mock.Of(hv => hv.BitLength == 24 && hv.Hash == new byte[] { 173, 0, 255 }.ToImmutableArray()); Assert.False(hashValue.Equals(mockValue)); } { - var hashValue = new HashValue(new byte[] { 173, 0, 254 }, 23); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 254 }, 23); var mockValue = Mock.Of(hv => hv.BitLength == 24 && hv.Hash == new byte[] { 173, 0, 254 }.ToImmutableArray()); Assert.False(hashValue.Equals(mockValue)); } { - var hashValue = new HashValue(new byte[] { 173, 0, 255 }, 24); + var hashValue = new HashValue(ValueEndianness.NotApplicable, new byte[] { 173, 0, 255 }, 24); var mockValue = Mock.Of(hv => hv.BitLength == 23 && hv.Hash == new byte[] { 173, 0, 127 }.ToImmutableArray()); Assert.False(hashValue.Equals(mockValue)); @@ -291,5 +462,4 @@ public void HashValue_Equals_Works() #endregion } - -} +} \ No newline at end of file From 4655f3fafc565e9d2feec4de83c4a9d340efb355 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:08:30 -0700 Subject: [PATCH 04/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5 directory Signed-off-by: Xen --- .../Algorithms/HMACMD5/HMACMD5Config.cs | 123 ------------------ .../HMACMD5/HMACMD5_Implementation.cs | 45 ------- .../Algorithms/HMACMD5/IHMACMD5.cs | 39 ------ .../Algorithms/HMACMD5/IHMACMD5Config.cs | 51 -------- 4 files changed, 258 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5Config.cs deleted file mode 100644 index c5c5db0..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5Config.cs +++ /dev/null @@ -1,123 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACMD5 -{ - /// - /// Represents the configuration settings for the HMACMD5 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACMD5 algorithm, which always produces a 128-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACMD5Config : IHMACMD5Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACMD5Config() - { - HashSizeInBits = 128; // HMACMD5 produces a fixed 128-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACMD5, this is always fixed at 128 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACMD5Config Clone() - { - return new HMACMD5Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACMD5Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5_Implementation.cs deleted file mode 100644 index c7f7502..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/HMACMD5_Implementation.cs +++ /dev/null @@ -1,45 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; - -namespace HashifyNet.Algorithms.HMACMD5 -{ - /// - /// Provides an implementation of the HMACMD5 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACMD5), typeof(HMACMD5Config))] - internal class HMACMD5_Implementation : HashAlgorithmWrapperBase, - IHMACMD5 - { - public HMACMD5_Implementation(IHMACMD5Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACMD5() : new System.Security.Cryptography.HMACMD5(config.Key)) - { - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5.cs deleted file mode 100644 index 1e2715f..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5.cs +++ /dev/null @@ -1,39 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACMD5 -{ - /// - /// Represents the HMACMD5 cryptographic hash function, providing functionality to compute HMACMD5 hashes for data streams and - /// other inputs. - /// - public interface IHMACMD5 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperAlgorithm - { - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5Config.cs deleted file mode 100644 index 26ba248..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACMD5/IHMACMD5Config.cs +++ /dev/null @@ -1,51 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACMD5 -{ - /// - /// Represents the configuration settings for the HMACMD5 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACMD5 algorithm. The property is fixed at 128 bits, as defined by the HMACMD5 - /// standard. - public interface IHMACMD5Config : ICryptographicHashConfig - { - /// - /// - /// For HMACMD5, this is always fixed at 128 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} From 4f1ef3b9971bf3fbbcb74c960f41a7f9763702f2 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:08:36 -0700 Subject: [PATCH 05/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1 directory Signed-off-by: Xen --- .../Algorithms/HMACSHA1/HMACSHA1Config.cs | 123 ------------------ .../HMACSHA1/HMACSHA1_Implementation.cs | 45 ------- .../Algorithms/HMACSHA1/IHMACSHA1.cs | 39 ------ .../Algorithms/HMACSHA1/IHMACSHA1Config.cs | 51 -------- 4 files changed, 258 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1Config.cs deleted file mode 100644 index 0ef4804..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1Config.cs +++ /dev/null @@ -1,123 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA1 -{ - /// - /// Represents the configuration settings for the HMACSHA1 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA1 algorithm, which always produces a 160-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA1Config : IHMACSHA1Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA1Config() - { - HashSizeInBits = 160; // HMACSHA1 produces a fixed 160-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA1, this is always fixed at 160 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA1Config Clone() - { - return new HMACSHA1Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA1Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1_Implementation.cs deleted file mode 100644 index 5e1c13f..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/HMACSHA1_Implementation.cs +++ /dev/null @@ -1,45 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; - -namespace HashifyNet.Algorithms.HMACSHA1 -{ - /// - /// Provides an implementation of the HMACSHA1 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA1), typeof(HMACSHA1Config))] - internal class HMACSHA1_Implementation : HashAlgorithmWrapperBase, - IHMACSHA1 - { - public HMACSHA1_Implementation(IHMACSHA1Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA1() : new System.Security.Cryptography.HMACSHA1(config.Key)) - { - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1.cs deleted file mode 100644 index b89456c..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1.cs +++ /dev/null @@ -1,39 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA1 -{ - /// - /// Represents the HMACSHA1 cryptographic hash function, providing functionality to compute HMACSHA1 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA1 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperAlgorithm - { - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1Config.cs deleted file mode 100644 index 49b689a..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA1/IHMACSHA1Config.cs +++ /dev/null @@ -1,51 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA1 -{ - /// - /// Represents the configuration settings for the HMACSHA1 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA1 algorithm. The property is fixed at 160 bits, as defined by the HMACSHA1 - /// standard. - public interface IHMACSHA1Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA1, this is always fixed at 160 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} From 6af8a9028960647ce790fd99ea47acf08455895b Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:08:43 -0700 Subject: [PATCH 06/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256 directory Signed-off-by: Xen --- .../Algorithms/HMACSHA256/HMACSHA256Config.cs | 123 ------------------ .../HMACSHA256/HMACSHA256_Implementation.cs | 45 ------- .../Algorithms/HMACSHA256/IHMACSHA256.cs | 39 ------ .../HMACSHA256/IHMACSHA256Config.cs | 51 -------- 4 files changed, 258 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256Config.cs deleted file mode 100644 index e69a08d..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256Config.cs +++ /dev/null @@ -1,123 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA256 -{ - /// - /// Represents the configuration settings for the HMACSHA256 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA256 algorithm, which always produces a 256-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA256Config : IHMACSHA256Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA256Config() - { - HashSizeInBits = 256; // HMACSHA256 produces a fixed 256-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA256, this is always fixed at 256 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA256Config Clone() - { - return new HMACSHA256Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA256Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256_Implementation.cs deleted file mode 100644 index 93e7980..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/HMACSHA256_Implementation.cs +++ /dev/null @@ -1,45 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; - -namespace HashifyNet.Algorithms.HMACSHA256 -{ - /// - /// Provides an implementation of the HMACSHA256 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA256), typeof(HMACSHA256Config))] - internal class HMACSHA256_Implementation : HashAlgorithmWrapperBase, - IHMACSHA256 - { - public HMACSHA256_Implementation(IHMACSHA256Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA256() : new System.Security.Cryptography.HMACSHA256(config.Key)) - { - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256.cs deleted file mode 100644 index 4de40f7..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256.cs +++ /dev/null @@ -1,39 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA256 -{ - /// - /// Represents the HMACSHA256 cryptographic hash function, providing functionality to compute HMACSHA256 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA256 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperAlgorithm - { - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256Config.cs deleted file mode 100644 index c9b41c6..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA256/IHMACSHA256Config.cs +++ /dev/null @@ -1,51 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA256 -{ - /// - /// Represents the configuration settings for the HMACSHA256 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA256 algorithm. The property is fixed at 256 bits, as defined by the HMACSHA256 - /// standard. - public interface IHMACSHA256Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA256, this is always fixed at 256 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} From b87c00228694bfec8ce73027e5189e718de12d77 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:08:50 -0700 Subject: [PATCH 07/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384 directory Signed-off-by: Xen --- .../Algorithms/HMACSHA384/HMACSHA384Config.cs | 123 ------------------ .../HMACSHA384/HMACSHA384_Implementation.cs | 45 ------- .../Algorithms/HMACSHA384/IHMACSHA384.cs | 39 ------ .../HMACSHA384/IHMACSHA384Config.cs | 51 -------- 4 files changed, 258 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384Config.cs deleted file mode 100644 index b571f86..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384Config.cs +++ /dev/null @@ -1,123 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA384 -{ - /// - /// Represents the configuration settings for the HMACSHA384 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA384 algorithm, which always produces a 384-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA384Config : IHMACSHA384Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA384Config() - { - HashSizeInBits = 384; // HMACSHA384 produces a fixed 384-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA384, this is always fixed at 384 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA384Config Clone() - { - return new HMACSHA384Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA384Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384_Implementation.cs deleted file mode 100644 index 8be7cfe..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/HMACSHA384_Implementation.cs +++ /dev/null @@ -1,45 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; - -namespace HashifyNet.Algorithms.HMACSHA384 -{ - /// - /// Provides an implementation of the HMACSHA384 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA384), typeof(HMACSHA384Config))] - internal class HMACSHA384_Implementation : HashAlgorithmWrapperBase, - IHMACSHA384 - { - public HMACSHA384_Implementation(IHMACSHA384Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA384() : new System.Security.Cryptography.HMACSHA384(config.Key)) - { - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384.cs deleted file mode 100644 index cc32ebd..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384.cs +++ /dev/null @@ -1,39 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA384 -{ - /// - /// Represents the HMACSHA384 cryptographic hash function, providing functionality to compute HMACSHA384 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA384 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperAlgorithm - { - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384Config.cs deleted file mode 100644 index 4a0034c..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA384/IHMACSHA384Config.cs +++ /dev/null @@ -1,51 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA384 -{ - /// - /// Represents the configuration settings for the HMACSHA384 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA384 algorithm. The property is fixed at 384 bits, as defined by the HMACSHA384 - /// standard. - public interface IHMACSHA384Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA384, this is always fixed at 384 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} From 5a06e81d6ebb505541f1077018ad416cd73d6481 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:08:56 -0700 Subject: [PATCH 08/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256 directory Signed-off-by: Xen --- .../HMACSHA3_256/HMACSHA3_256Config.cs | 127 ------------------ .../HMACSHA3_256_Implementation.cs | 51 ------- .../Algorithms/HMACSHA3_256/IHMACSHA3_256.cs | 43 ------ .../HMACSHA3_256/IHMACSHA3_256Config.cs | 55 -------- 4 files changed, 276 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256Config.cs deleted file mode 100644 index 3888a01..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256Config.cs +++ /dev/null @@ -1,127 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA3_256 -{ - /// - /// Represents the configuration settings for the HMACSHA3_256 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA3_256 algorithm, which always produces a 256-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA3_256Config : IHMACSHA3_256Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA3_256Config() - { - HashSizeInBits = 256; // HMACSHA3_256 produces a fixed 256-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA3_256, this is always fixed at 256 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA3_256Config Clone() - { - return new HMACSHA3_256Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA3_256Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256_Implementation.cs deleted file mode 100644 index 1e4345b..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/HMACSHA3_256_Implementation.cs +++ /dev/null @@ -1,51 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; - -namespace HashifyNet.Algorithms.HMACSHA3_256 -{ - /// - /// Provides an implementation of the HMACSHA3_256 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA3_256), typeof(HMACSHA3_256Config))] - internal class HMACSHA3_256_Implementation : HashAlgorithmWrapperBase, - IHMACSHA3_256 - { - public HMACSHA3_256_Implementation(IHMACSHA3_256Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA3_256() : new System.Security.Cryptography.HMACSHA3_256(config.Key)) - { - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256.cs deleted file mode 100644 index 2337e5e..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_256 -{ - /// - /// Represents the HMACSHA3_256 cryptographic hash function, providing functionality to compute HMACSHA3_256 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA3_256 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperPlatformDependentAlgorithm - { - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256Config.cs deleted file mode 100644 index b8b4df5..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_256/IHMACSHA3_256Config.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_256 -{ - /// - /// Represents the configuration settings for the HMACSHA3_256 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA3_256 algorithm. The property is fixed at 256 bits, as defined by the HMACSHA3_256 - /// standard. - public interface IHMACSHA3_256Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA3_256, this is always fixed at 256 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} - -#endif // NET8_0_OR_GREATER From f98e389a4643b09bf09177e2ca424433899de177 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:09:02 -0700 Subject: [PATCH 09/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384 directory Signed-off-by: Xen --- .../HMACSHA3_384/HMACSHA3_384Config.cs | 127 ------------------ .../HMACSHA3_384_Implementation.cs | 51 ------- .../Algorithms/HMACSHA3_384/IHMACSHA3_384.cs | 43 ------ .../HMACSHA3_384/IHMACSHA3_384Config.cs | 55 -------- 4 files changed, 276 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384Config.cs deleted file mode 100644 index bafbb54..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384Config.cs +++ /dev/null @@ -1,127 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA3_384 -{ - /// - /// Represents the configuration settings for the HMACSHA3_384 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA3_384 algorithm, which always produces a 384-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA3_384Config : IHMACSHA3_384Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA3_384Config() - { - HashSizeInBits = 384; // HMACSHA3_384 produces a fixed 384-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA3_384, this is always fixed at 384 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA3_384Config Clone() - { - return new HMACSHA3_384Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA3_384Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384_Implementation.cs deleted file mode 100644 index 262a454..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/HMACSHA3_384_Implementation.cs +++ /dev/null @@ -1,51 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; - -namespace HashifyNet.Algorithms.HMACSHA3_384 -{ - /// - /// Provides an implementation of the HMACSHA3_384 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA3_384), typeof(HMACSHA3_384Config))] - internal class HMACSHA3_384_Implementation : HashAlgorithmWrapperBase, - IHMACSHA3_384 - { - public HMACSHA3_384_Implementation(IHMACSHA3_384Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA3_384() : new System.Security.Cryptography.HMACSHA3_384(config.Key)) - { - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384.cs deleted file mode 100644 index ace01a5..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_384 -{ - /// - /// Represents the HMACSHA3_384 cryptographic hash function, providing functionality to compute HMACSHA3_384 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA3_384 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperPlatformDependentAlgorithm - { - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384Config.cs deleted file mode 100644 index 1f2b3f8..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_384/IHMACSHA3_384Config.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_384 -{ - /// - /// Represents the configuration settings for the HMACSHA3_384 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA3_384 algorithm. The property is fixed at 384 bits, as defined by the HMACSHA3_384 - /// standard. - public interface IHMACSHA3_384Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA3_384, this is always fixed at 384 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} - -#endif // NET8_0_OR_GREATER From 365633b263dacba632cebd86f44adae8b9e04e1b Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:09:09 -0700 Subject: [PATCH 10/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512 directory Signed-off-by: Xen --- .../HMACSHA3_512/HMACSHA3_512Config.cs | 127 ------------------ .../HMACSHA3_512_Implementation.cs | 51 ------- .../Algorithms/HMACSHA3_512/IHMACSHA3_512.cs | 43 ------ .../HMACSHA3_512/IHMACSHA3_512Config.cs | 55 -------- 4 files changed, 276 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512Config.cs deleted file mode 100644 index 5b6fa02..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512Config.cs +++ /dev/null @@ -1,127 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA3_512 -{ - /// - /// Represents the configuration settings for the HMACSHA3_512 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA3_512 algorithm, which always produces a 512-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA3_512Config : IHMACSHA3_512Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA3_512Config() - { - HashSizeInBits = 512; // HMACSHA3_512 produces a fixed 512-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA3_512, this is always fixed at 512 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA3_512Config Clone() - { - return new HMACSHA3_512Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA3_512Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512_Implementation.cs deleted file mode 100644 index ba932f7..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/HMACSHA3_512_Implementation.cs +++ /dev/null @@ -1,51 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; -using HashifyNet.Core.HashAlgorithm; -using System; - -namespace HashifyNet.Algorithms.HMACSHA3_512 -{ - /// - /// Provides an implementation of the HMACSHA3_512 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA3_512), typeof(HMACSHA3_512Config))] - internal class HMACSHA3_512_Implementation : HashAlgorithmWrapperBase, - IHMACSHA3_512 - { - public HMACSHA3_512_Implementation(IHMACSHA3_512Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA3_512() : new System.Security.Cryptography.HMACSHA3_512(config.Key)) - { - } - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512.cs deleted file mode 100644 index de79aa7..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_512 -{ - /// - /// Represents the HMACSHA3_512 cryptographic hash function, providing functionality to compute HMACSHA3_512 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA3_512 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperPlatformDependentAlgorithm - { - } -} - -#endif // NET8_0_OR_GREATER diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512Config.cs deleted file mode 100644 index 910d4fc..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA3_512/IHMACSHA3_512Config.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if NET8_0_OR_GREATER - -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA3_512 -{ - /// - /// Represents the configuration settings for the HMACSHA3_512 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA3_512 algorithm. The property is fixed at 512 bits, as defined by the HMACSHA3_512 - /// standard. - public interface IHMACSHA3_512Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA3_512, this is always fixed at 512 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} - -#endif // NET8_0_OR_GREATER From f50e25d6783bdecb70cbd0c62f4dc34ea5585761 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:09:16 -0700 Subject: [PATCH 11/29] Delete HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512 directory Signed-off-by: Xen --- .../Algorithms/HMACSHA512/HMACSHA512Config.cs | 123 ------------------ .../HMACSHA512/HMACSHA512_Implementation.cs | 45 ------- .../Algorithms/HMACSHA512/IHMACSHA512.cs | 39 ------ .../HMACSHA512/IHMACSHA512Config.cs | 51 -------- 4 files changed, 258 deletions(-) delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512Config.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512_Implementation.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512.cs delete mode 100644 HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512Config.cs diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512Config.cs deleted file mode 100644 index 6a40cc3..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512Config.cs +++ /dev/null @@ -1,123 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core.Utilities; - -namespace HashifyNet.Algorithms.HMACSHA512 -{ - /// - /// Represents the configuration settings for the HMACSHA512 hashing algorithm. - /// - /// This class provides a fixed configuration for the HMACSHA512 algorithm, which always produces a 512-bit - /// hash. It includes the hash size and supports cloning to create independent copies of the configuration. - public class HMACSHA512Config : IHMACSHA512Config - { - private bool disposedValue; - - /// - /// Initializes a new instance of the class with default settings. - /// - public HMACSHA512Config() - { - HashSizeInBits = 512; // HMACSHA512 produces a fixed 512-bit hash - } - - /// - /// Gets the size of the hash in bits. For HMACSHA512, this is always fixed at 512 bits. - /// - public int HashSizeInBits { get; private set; } - - /// - /// Gets or sets the secret key for the hash algorithm. - /// -#if NET8_0_OR_GREATER -#nullable enable - public byte[]? -#nullable restore -#else - public byte[] -#endif // NET8_0_OR_GREATER - Key - { get; set; } = null; - - /// - /// Creates a deep copy of the current instance. - /// - /// A new instance with the same settings. - public IHMACSHA512Config Clone() - { - return new HMACSHA512Config() - { - Key = (byte[])Key?.Clone(), - }; - } - - /// - /// Releases the resources used by the current instance of the class. - /// - /// This method is called to release both managed and unmanaged resources. Override this method in a - /// derived class to provide custom cleanup logic. - /// to release both managed and unmanaged resources; to release only - /// unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (Key != null) - { - ArrayHelpers.ZeroFill(Key); - } - } - - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null - disposedValue = true; - } - } - - // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources - // ~HMACSHA512Config() - // { - // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - // Dispose(disposing: false); - // } - - /// - /// - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - System.GC.SuppressFinalize(this); - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512_Implementation.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512_Implementation.cs deleted file mode 100644 index a93dadb..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/HMACSHA512_Implementation.cs +++ /dev/null @@ -1,45 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using HashifyNet.Core; - -namespace HashifyNet.Algorithms.HMACSHA512 -{ - /// - /// Provides an implementation of the HMACSHA512 cryptographic hash function. - /// - [HashAlgorithmImplementation(typeof(IHMACSHA512), typeof(HMACSHA512Config))] - internal class HMACSHA512_Implementation : HashAlgorithmWrapperBase, - IHMACSHA512 - { - public HMACSHA512_Implementation(IHMACSHA512Config config) : base(config, () => config.Key == null ? new System.Security.Cryptography.HMACSHA512() : new System.Security.Cryptography.HMACSHA512(config.Key)) - { - } - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512.cs deleted file mode 100644 index 860cb56..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512.cs +++ /dev/null @@ -1,39 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA512 -{ - /// - /// Represents the HMACSHA512 cryptographic hash function, providing functionality to compute HMACSHA512 hashes for data streams and - /// other inputs. - /// - public interface IHMACSHA512 : ICryptographicStreamableHashFunction, IHashAlgorithmWrapperAlgorithm - { - } -} diff --git a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512Config.cs b/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512Config.cs deleted file mode 100644 index 1a3e99e..0000000 --- a/HashifyNet/Algorithms/HashAlgorithmWrapper/Algorithms/HMACSHA512/IHMACSHA512Config.cs +++ /dev/null @@ -1,51 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet.Algorithms.HMACSHA512 -{ - /// - /// Represents the configuration settings for the HMACSHA512 cryptographic hash algorithm. - /// - /// This interface extends to provide configuration specific - /// to the HMACSHA512 algorithm. The property is fixed at 512 bits, as defined by the HMACSHA512 - /// standard. - public interface IHMACSHA512Config : ICryptographicHashConfig - { - /// - /// - /// For HMACSHA512, this is always fixed at 512 bits. - /// - new int HashSizeInBits { get; } - - /// - /// Gets the secret key for the hash algorithm. - /// - byte[] Key { get; } - } -} From 2f4c54f962d0a0782074ada783978817248d8b52 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:13:30 -0700 Subject: [PATCH 12/29] Fix README having duplicate implementations Signed-off-by: Xen --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 887e839..c669ffd 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,6 @@ The following hash functions have been implemented from the most reliable refere * [Whirlpool](https://en.wikipedia.org/wiki/Whirlpool_(hash_function)) * [xxHash](https://code.google.com/p/xxhash/) * xxHash - Original and 64-bit version. - * xxHash3 - Wraps around System.IO.Hashes. - * xxHash128 - Wraps around System.IO.Hashes. Wrapped Implementations ----------------------- @@ -294,3 +292,4 @@ HashifyNET is released under the terms of the MIT license. See [LICENSE](https:/ + From a582971c6800965ae68e7fadd632a7cff8cebcab Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:24:47 -0700 Subject: [PATCH 13/29] Remove old Base85Variant Signed-off-by: Xen --- HashifyNet/Core/DataType/Base85Variant.cs | 59 ----------------------- 1 file changed, 59 deletions(-) delete mode 100644 HashifyNet/Core/DataType/Base85Variant.cs diff --git a/HashifyNet/Core/DataType/Base85Variant.cs b/HashifyNet/Core/DataType/Base85Variant.cs deleted file mode 100644 index 242ed3c..0000000 --- a/HashifyNet/Core/DataType/Base85Variant.cs +++ /dev/null @@ -1,59 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -namespace HashifyNet -{ - /// - /// Specifies the supported Base85 encoding variants. - /// - /// Base85 encoding is a binary-to-text encoding scheme that represents binary data in an ASCII-safe - /// format. This enumeration defines the available variants of Base85 encoding, each with its own specific use case and - /// encoding rules: The Adobe standard used - /// in PostScript and PDF, with '<~' and '~>' delimiters. The ZeroMQ standard (RFC 32/Z85), designed to be safe for inclusion in source - /// code. The variant defined in RFC 1924, - /// originally created for encoding IPv6 addresses. - public enum Base85Variant - { - /// - /// The Adobe standard used in PostScript and PDF, with '<~' and '~>' delimiters. - /// - Ascii85, - - /// - /// The ZeroMQ standard (RFC 32/Z85), designed to be safe for source code. - /// - Z85, - - /// - /// The standard defined in RFC 1924, originally for IPv6 addresses. - /// - Rfc1924 - } -} From 52eb07bd4c7a6c139d3dfe48d75225dd77b699d3 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 09:25:00 -0700 Subject: [PATCH 14/29] Remove the old Base85Helper.cs Signed-off-by: Xen --- HashifyNet/Core/DataType/Base85Helper.cs | 109 ----------------------- 1 file changed, 109 deletions(-) delete mode 100644 HashifyNet/Core/DataType/Base85Helper.cs diff --git a/HashifyNet/Core/DataType/Base85Helper.cs b/HashifyNet/Core/DataType/Base85Helper.cs deleted file mode 100644 index d5d9ba7..0000000 --- a/HashifyNet/Core/DataType/Base85Helper.cs +++ /dev/null @@ -1,109 +0,0 @@ -// * -// ***************************************************************************** -// * -// * Copyright (c) 2025 Deskasoft International -// * -// * Permission is hereby granted, free of charge, to any person obtaining a copy -// * of this software and associated documentation files (the ""Software""), to deal -// * in the Software without restriction, including without limitation the rights -// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// * copies of the Software, and to permit persons to whom the Software is -// * furnished to do so, subject to the following conditions: -// * -// * The above copyright notice and this permission notice shall be included in all -// * copies or substantial portions of the Software. -// * -// * THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// * SOFTWARE. -// * -// * -// * Please refer to LICENSE file. -// * -// ****************************************************************************** -// * - -using System; -using System.Text; - -namespace HashifyNet -{ - internal static class Base85Helper - { - private const string Ascii85Alphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"; - private const string Z85Alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; - private const string Rfc1924Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; - private static readonly uint[] Powers = { 52200625, 614125, 7225, 85, 1 }; - - public static string AsBase85String(byte[] data, Base85Variant variant) - { - if (data == null || data.Length == 0) - { - return variant == Base85Variant.Ascii85 ? "<~~>" : ""; - } - - var builder = new StringBuilder(); - string alphabet = GetAlphabet(variant); - int dataIndex = 0; - while (dataIndex + 3 < data.Length) - { - uint value = ((uint)data[dataIndex++] << 24) | - ((uint)data[dataIndex++] << 16) | - ((uint)data[dataIndex++] << 8) | - data[dataIndex++]; - - if (variant == Base85Variant.Ascii85 && value == 0) - { - builder.Append('z'); - continue; - } - - for (int i = 0; i < 5; i++) - { - builder.Append(alphabet[(int)(value / Powers[i] % 85)]); - } - } - - int remainingBytes = data.Length - dataIndex; - if (remainingBytes > 0) - { - uint value = 0; - for (int i = 0; i < remainingBytes; i++) - { - value |= (uint)data[dataIndex + i] << (24 - i * 8); - } - - for (int i = 0; i < remainingBytes + 1; i++) - { - builder.Append(alphabet[(int)(value / Powers[i] % 85)]); - } - } - - if (variant == Base85Variant.Ascii85) - { - return $"<~{builder.ToString()}~>"; - } - - return builder.ToString(); - } - - private static string GetAlphabet(Base85Variant variant) - { - switch (variant) - { - case Base85Variant.Ascii85: - return Ascii85Alphabet; - case Base85Variant.Z85: - return Z85Alphabet; - case Base85Variant.Rfc1924: - return Rfc1924Alphabet; - default: - throw new ArgumentException("Unsupported Base85 variant.", nameof(variant)); - } - } - } -} From 500b2fdf80b3410b41d0e6fd7ae788429278377e Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 11:41:59 -0700 Subject: [PATCH 15/29] Add read-only span deserializer to Argon2idSerializer Signed-off-by: Xen --- .../Algorithms/Argon2id/Argon2idSerializer.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/HashifyNet/Algorithms/Argon2id/Argon2idSerializer.cs b/HashifyNet/Algorithms/Argon2id/Argon2idSerializer.cs index d03dd3e..21c3aec 100644 --- a/HashifyNet/Algorithms/Argon2id/Argon2idSerializer.cs +++ b/HashifyNet/Algorithms/Argon2id/Argon2idSerializer.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -71,5 +71,17 @@ public static string Deserialize(byte[] data) return Encoding.UTF8.GetString(data); } + +#if NET8_0_OR_GREATER + /// + /// Converts the specified string to a UTF-8 encoded byte array. + /// + /// The read-only span of bytes to convert. + /// The string representation of the byte array. + public static string Deserialize(ReadOnlySpan data) + { + return Encoding.UTF8.GetString(data); + } +#endif } } From 13e7d7d65cb2ec5d06be7f7b30814152f32a7183 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 11:45:16 -0700 Subject: [PATCH 16/29] Update Argon2idDecoder to use ReadOnlySpan over ArraySegment Signed-off-by: Xen --- .../Algorithms/Argon2id/Argon2idDecoder.cs | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/HashifyNet/Algorithms/Argon2id/Argon2idDecoder.cs b/HashifyNet/Algorithms/Argon2id/Argon2idDecoder.cs index eb49a82..6c4fb3f 100644 --- a/HashifyNet/Algorithms/Argon2id/Argon2idDecoder.cs +++ b/HashifyNet/Algorithms/Argon2id/Argon2idDecoder.cs @@ -1,4 +1,4 @@ -// * +// * // ***************************************************************************** // * // * Copyright (c) 2025 Deskasoft International @@ -41,14 +41,14 @@ namespace HashifyNet.Algorithms.Argon2id public static class Argon2idDecoder { /// - /// Decodes the specified segment of a byte array into its original form. + /// Decodes the specified byte array and returns the resulting data. /// - /// The segment of the byte array to decode. The segment must not be empty. - /// A byte array containing the decoded data. - public static byte[] Decode(ArraySegment data) + /// The byte array to decode. Cannot be . + /// The decoded byte array, or if decoding fails. + public static byte[] Decode(byte[] data) { Argon2Config config = new Argon2Config(); - if (!DecodeExtension.DecodeString(config, Argon2idSerializer.Deserialize(data.Array), out var buffer)) + if (!DecodeExtension.DecodeString(config, Argon2idSerializer.Deserialize(data), out var buffer)) { return null; } @@ -56,20 +56,23 @@ public static byte[] Decode(ArraySegment data) return buffer.Buffer; } +#if NET8_0_OR_GREATER /// - /// Decodes the specified byte array and returns the resulting data. + /// Decodes the specified read-only span of bytes and returns the resulting data. /// - /// The byte array to decode. Cannot be null. - /// A byte array containing the decoded data. - public static byte[] Decode(byte[] data) + /// The read-only span of bytes to decode. + /// The decoded byte array, or if decoding fails. + public static byte[] Decode(ReadOnlySpan data) { - if (data == null) + Argon2Config config = new Argon2Config(); + if (!DecodeExtension.DecodeString(config, Argon2idSerializer.Deserialize(data), out var buffer)) { - throw new ArgumentNullException(nameof(data)); + return null; } - return Decode(new ArraySegment(data)); + return buffer.Buffer; } +#endif /// /// Decodes the hash value of an Argon2id hash into its raw byte representation. @@ -88,4 +91,3 @@ public static byte[] DecodeArgon2id(this IHashValue val) } } } - From 10b18c0db44a4d339bc112d42f5504a6409cb119 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 11:53:02 -0700 Subject: [PATCH 17/29] Update SpookyHash to fully use Span Signed-off-by: Xen --- .../Algorithms/SpookyHash/SpookyHashV1_Implementation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs b/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs index 0a30aa4..6ec8e61 100644 --- a/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs +++ b/HashifyNet/Algorithms/SpookyHash/SpookyHashV1_Implementation.cs @@ -185,7 +185,7 @@ protected override void TransformByteGroupsInternal(ReadOnlySpan data) if (_shortHashBuffer != null) { - Mix(_hashValue, new ArraySegment(_shortHashBuffer, 0, _bytesProcessed)); + Mix(_hashValue, _shortHashBuffer.AsSpan(0, _bytesProcessed)); _shortHashBuffer = null; } @@ -212,7 +212,7 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto finalMixBuffer[95] = (byte)remainderCount; - Mix(finalHashValue, new ArraySegment(finalMixBuffer, 0, 96)); + Mix(finalHashValue, finalMixBuffer.AsSpan(0, finalMixBuffer.Length)); End(finalHashValue); switch (_hashSizeInBits) @@ -438,4 +438,4 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } -} \ No newline at end of file +} From 8c5e494a4185e34af72c7a5739e92d9880486cda Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 11:53:30 -0700 Subject: [PATCH 18/29] Remove unused ArraySegment zero fill helper method from ArrayHelpers Signed-off-by: Xen --- HashifyNet/Core/Utilities/ArrayHelpers.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/HashifyNet/Core/Utilities/ArrayHelpers.cs b/HashifyNet/Core/Utilities/ArrayHelpers.cs index f480412..c35c01b 100644 --- a/HashifyNet/Core/Utilities/ArrayHelpers.cs +++ b/HashifyNet/Core/Utilities/ArrayHelpers.cs @@ -44,11 +44,6 @@ public static void ZeroFill(byte[] array) Array.Clear(array, 0, array.Length); } - - public static void ZeroFill(ArraySegment array) - { - ZeroFill(array.Array); - } /// /// Coerces the given to a byte array with significant bits. @@ -114,3 +109,4 @@ public static byte[] CoerceToArray(IEnumerable hash, int bitLength) } + From 5729fd5fe0cc4248b54829798a4e0e75398f296b Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 11:54:32 -0700 Subject: [PATCH 19/29] Update SpookyHashV2 to fully use Span Signed-off-by: Xen --- .../Algorithms/SpookyHash/SpookyHashV2_Implementation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs b/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs index b0c5e06..d6ce9bc 100644 --- a/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs +++ b/HashifyNet/Algorithms/SpookyHash/SpookyHashV2_Implementation.cs @@ -180,7 +180,7 @@ protected override void TransformByteGroupsInternal(ReadOnlySpan data) if (_shortHashBuffer != null) { - Mix(_hashValue, new ArraySegment(_shortHashBuffer, 0, _bytesProcessed)); + Mix(_hashValue, _shortHashBuffer.AsSpan(0, _bytesProcessed)); _shortHashBuffer = null; } @@ -434,4 +434,4 @@ private static ulong RotateLeft(ulong operand, int shiftCount) } } } -} \ No newline at end of file +} From dc4ec354d920fd2e67cb7e90da39e4ac62486b33 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 12:20:58 -0700 Subject: [PATCH 20/29] Fix CopyStateTo internal buffer condition in BlockTransformerBase Signed-off-by: Xen --- HashifyNet/Core/BlockTransformerBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashifyNet/Core/BlockTransformerBase.cs b/HashifyNet/Core/BlockTransformerBase.cs index fa97c5e..0dd2419 100644 --- a/HashifyNet/Core/BlockTransformerBase.cs +++ b/HashifyNet/Core/BlockTransformerBase.cs @@ -220,7 +220,7 @@ public IBlockTransformer Clone() /// All overriders should ensure base.CopyStateTo(other) is called. protected virtual void CopyStateTo(TSelf other) { - if (_leftover != null && _leftover.Length > 0) + if (_leftoverCount > 0) { Buffer.BlockCopy(_leftover, 0, other._leftover, 0, _leftoverCount); } @@ -341,4 +341,4 @@ private ReadOnlySpan FinalizeInputBuffer() /// A previous transformation cancellation has resulted in an undefined internal state. protected abstract IHashValue FinalizeHashValueInternal(ReadOnlySpan leftover, CancellationToken cancellationToken); } -} \ No newline at end of file +} From 68e00f2ca76ffa63204d32a81cde39b78296c747 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 12:31:26 -0700 Subject: [PATCH 21/29] Leave validations to span in BlockTransformerBase:TransformBytes Signed-off-by: Xen --- HashifyNet/Core/BlockTransformerBase.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/HashifyNet/Core/BlockTransformerBase.cs b/HashifyNet/Core/BlockTransformerBase.cs index 0dd2419..60a2e60 100644 --- a/HashifyNet/Core/BlockTransformerBase.cs +++ b/HashifyNet/Core/BlockTransformerBase.cs @@ -139,22 +139,7 @@ public void TransformBytes(byte[] data, int offset, int count, CancellationToken throw new ArgumentNullException(nameof(data)); } - if (data.Length == 0) - { - throw new ArgumentException("data.Length must be greater than 0.", nameof(data)); - } - - if (offset < 0 || offset >= data.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset must be a value greater than or equal to zero and less than the length of the array minus one."); - } - - if (count <= 0 || count > data.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(count), "Count must be a value greater than zero and less than the remaining length of the array after the offset value."); - } - - TransformBytes(new ReadOnlySpan(data, offset, count), cancellationToken); + TransformBytes(data.AsSpan(offset, count), cancellationToken); } /// From 3ad1a5a7a0a8c7b90c104fa8091bd84e9ceab6e8 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 12:34:55 -0700 Subject: [PATCH 22/29] Leave validations to span in HashFunctionBase:ComputeHash Signed-off-by: Xen --- HashifyNet/Core/HashFunctionBase.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/HashifyNet/Core/HashFunctionBase.cs b/HashifyNet/Core/HashFunctionBase.cs index e8cb836..45480cc 100644 --- a/HashifyNet/Core/HashFunctionBase.cs +++ b/HashifyNet/Core/HashFunctionBase.cs @@ -97,17 +97,7 @@ public IHashValue ComputeHash(byte[] data, int offset, int count, CancellationTo throw new ArgumentNullException(nameof(data)); } - if (offset < 0 || offset > data.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset must be a value greater than or equal to zero and less than or equal to the length of the array."); - } - - if (count < 0 || count > data.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(count), "Count must be a value greater than or equal to zero and less than the the remaining length of the array after the offset value."); - } - - return ComputeHash(new ReadOnlySpan(data, offset, count), cancellationToken); + return ComputeHash(data.AsSpan(offset, count), cancellationToken); } /// @@ -141,4 +131,4 @@ public IHashValue ComputeHash(ReadOnlySpan data, CancellationToken cancell /// The was canceled. protected abstract IHashValue ComputeHashInternal(ReadOnlySpan data, CancellationToken cancellationToken); } -} \ No newline at end of file +} From 19e06ebd0706dc1919372336f6a0a61828478eb0 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 12:55:05 -0700 Subject: [PATCH 23/29] Update Keccak with ValueEndianness fo BigEndian Signed-off-by: Xen --- HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs b/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs index 406cf97..4d72ffc 100644 --- a/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs +++ b/HashifyNet/Algorithms/Keccak/Keccak_Implementation.cs @@ -122,7 +122,7 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto int bytesToSqueeze = (_hashSizeInBits + 7) / 8; byte[] hash = Squeeze(bytesToSqueeze); - return new HashValue(ValueEndianness.NotApplicable, hash, _hashSizeInBits); + return new HashValue(ValueEndianness.BigEndian, hash, _hashSizeInBits); } private void Absorb(ReadOnlySpan data) @@ -259,4 +259,4 @@ private void KeccakF1600_Permute() #endregion } } -} \ No newline at end of file +} From 76b0df3fc07285a2e3dc0fd519cdeb562050b49f Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:04:18 -0700 Subject: [PATCH 24/29] Remove cancellationToken check in FinalizeHashValue of Blake2b and remove comments Signed-off-by: Xen --- .../Algorithms/Blake2/Blake2B_Implementation.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs b/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs index eb0afec..2496084 100644 --- a/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs +++ b/HashifyNet/Algorithms/Blake2/Blake2B_Implementation.cs @@ -282,8 +282,6 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto if (_delayedInputBuffer != null) { - cancellationToken.ThrowIfCancellationRequested(); - tempCounter += new UInt128(0, 128); Compress( @@ -295,15 +293,6 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto if (leftover.Length > 0 || _delayedInputBuffer == null) { - cancellationToken.ThrowIfCancellationRequested(); - - //var finalBuffer = new byte[128]; - - //if (leftover > 0) - //{ - // Array.Copy(remainder, 0, finalBuffer, 0, remainderCount); - //} - tempCounter += new UInt128(0, (ulong)leftover.Length); Compress( @@ -366,4 +355,4 @@ private static void Compress( } } } -} \ No newline at end of file +} From b037c9d1cf92b0d7371d9fb2d37e1c989a115fde Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:05:16 -0700 Subject: [PATCH 25/29] Update blake3 implementation as little endian Signed-off-by: Xen --- HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs b/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs index f61dd2d..6df0e63 100644 --- a/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs +++ b/HashifyNet/Algorithms/Blake3/Blake3_Implementation.cs @@ -313,7 +313,7 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto FillXof(cv, lastBlockWords ?? new uint[16], chunkCounter, lastBlockLen, lastFlags, result); ResetState(); - return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, result, _hashSizeInBits); } // Case B: exactly one full chunk emitted and no remainder @@ -328,7 +328,7 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto FillXof(_singleChunkCv, _singleChunkLastBlockWords, _singleChunkCounter, _singleChunkLastBlockLen, _singleChunkLastBlockFlags, result); ResetState(); - return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, result, _hashSizeInBits); } // Case C: true multi-chunk (>=2), or 1 chunk + tail (will become >=2 after tail) @@ -353,7 +353,7 @@ protected override IHashValue FinalizeHashValueInternal(ReadOnlySpan lefto FillXof(_currentIV, rootMessageBlock, 0UL, BLOCK_LEN, PARENT, result); ResetState(); - return new HashValue(ValueEndianness.NotApplicable, result, _hashSizeInBits); + return new HashValue(ValueEndianness.LittleEndian, result, _hashSizeInBits); } private void EmitFullChunk(ReadOnlySpan src) @@ -605,4 +605,4 @@ private static void FillXof(uint[] inputCv, uint[] messageBlock, ulong counter, } } } -} \ No newline at end of file +} From e51f3591c3ce68cd4c963db5b2101137e6321c52 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:07:10 -0700 Subject: [PATCH 26/29] Add cancellation token validation into FinalizeHashValue in BlockTransformerBase Signed-off-by: Xen --- HashifyNet/Core/BlockTransformerBase.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/HashifyNet/Core/BlockTransformerBase.cs b/HashifyNet/Core/BlockTransformerBase.cs index 60a2e60..f864d1a 100644 --- a/HashifyNet/Core/BlockTransformerBase.cs +++ b/HashifyNet/Core/BlockTransformerBase.cs @@ -181,7 +181,23 @@ public IHashValue FinalizeHashValue(CancellationToken cancellationToken) { ThrowIfCorrupted(); - return FinalizeHashValueInternal(FinalizeInputBuffer(), cancellationToken); + try + { + cancellationToken.ThrowIfCancellationRequested(); + try + { + return FinalizeHashValueInternal(FinalizeInputBuffer(), cancellationToken); + } + finally + { + cancellationToken.ThrowIfCancellationRequested(); + } + } + catch (TaskCanceledException) + { + MarkSelfCorrupted(); + throw; + } } /// From d73911b9606fa36c803d9ee386277dd8be5d4fe2 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:28:51 -0700 Subject: [PATCH 27/29] Add new methods to IHashValue Signed-off-by: Xen --- HashifyNet/Core/DataType/IHashValue.cs | 38 +++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/HashifyNet/Core/DataType/IHashValue.cs b/HashifyNet/Core/DataType/IHashValue.cs index 54b2e3a..066ea96 100644 --- a/HashifyNet/Core/DataType/IHashValue.cs +++ b/HashifyNet/Core/DataType/IHashValue.cs @@ -196,6 +196,42 @@ public interface IHashValue /// The modifiable byte array. byte[] AsByteArray(); + /// + /// Gets the hash value as a read-only span of bytes. + /// + /// The zero-based byte index at which to begin the span. Must be greater than or equal to 0 and less than .Length. + /// The number of bytes to include in the span. Must be greater than or equal to 0 and less than or equal to .Length - . + /// The read-only span of bytes. + ReadOnlySpan AsSpan(int start, int length); + + /// + /// Gets the hash value as a read-only span of bytes of the specified length from the start. + /// + /// The number of bytes to include in the span. Must be greater than or equal to 0 and less than or equal to .Length. + /// The read-only span of bytes. + ReadOnlySpan AsSpan(int length); + + /// + /// Gets the hash value as a read-only span of bytes. + /// + /// The read-only span of bytes. + ReadOnlySpan AsSpan(); + + /// + /// Slices a portion of the hash value starting from the specified bit index and spanning the specified number of bits. + /// + /// The zero-based bit index at which to begin the slice. Must be greater than or equal to 0 and less than . + /// The number of bits to include in the slice. Must be greater than or equal to 1 and less than or equal to - . + /// The sliced instance. + IHashValue Slice(int start, int length); + + /// + /// Slices the hash value to the specified length in bits, starting from the beginning of the hash. + /// + /// The number of bits to include in the slice. Must be greater than or equal to 1 and less than or equal to . + /// The sliced instance. + IHashValue Slice(int length); + /// /// Converts the current hash value to a new representation with the specified bit length. /// @@ -229,4 +265,4 @@ public interface IHashValue /// The new instance with reversed byte order. If the current instance has , it returns the same instance. IHashValue ReverseEndianness(); } -} \ No newline at end of file +} From 183202db0c74411b49fe64fb656703f7889b01f5 Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:29:17 -0700 Subject: [PATCH 28/29] Add new methods to HashValue Signed-off-by: Xen --- HashifyNet/Core/DataType/HashValue.cs | 53 ++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/HashifyNet/Core/DataType/HashValue.cs b/HashifyNet/Core/DataType/HashValue.cs index 63fcad2..d44f170 100644 --- a/HashifyNet/Core/DataType/HashValue.cs +++ b/HashifyNet/Core/DataType/HashValue.cs @@ -533,6 +533,57 @@ public byte[] AsByteArray() return Hash.ToArray(); } + /// + /// + /// + /// + /// + /// + public ReadOnlySpan AsSpan(int start, int length) + { + return Hash.AsSpan(start, length); + } + + /// + /// + /// + /// + /// + public ReadOnlySpan AsSpan(int length) + { + return AsSpan(0, length); + } + + /// + /// + /// + /// + public ReadOnlySpan AsSpan() + { + return AsSpan(0, Hash.Length); + } + + /// + /// + /// + /// + /// + /// + public IHashValue Slice(int start, int length) + { + return new HashValue(Endianness, Hash.AsSpan(start, length).ToImmutableArray(), length * 8); + } + + /// + /// + /// + /// + /// + public IHashValue Slice(int length) + { + return Slice(0, length); + } + /// /// /// @@ -702,4 +753,4 @@ public int CompareTo(IHashValue other) return 0; } } -} \ No newline at end of file +} From d9c62ff6be90c329208321c18f63d24c4bf9fa3d Mon Sep 17 00:00:00 2001 From: Xen Date: Fri, 19 Sep 2025 13:47:32 -0700 Subject: [PATCH 29/29] Return the current instance if the requested bit length in Coerce equals the current bit length Signed-off-by: Xen --- HashifyNet/Core/DataType/HashValue.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HashifyNet/Core/DataType/HashValue.cs b/HashifyNet/Core/DataType/HashValue.cs index d44f170..97e8c2d 100644 --- a/HashifyNet/Core/DataType/HashValue.cs +++ b/HashifyNet/Core/DataType/HashValue.cs @@ -592,6 +592,9 @@ public IHashValue Slice(int length) /// public virtual IHashValue Coerce(int bitLength) { + if (BitLength == bitLength) + return this; + return new HashValue(Endianness, ArrayHelpers.CoerceToArray(Hash.ToArray(), bitLength), bitLength); }