using System; using System.Buffers; using System.Security.Cryptography; namespace FrostFS.SDK.Cryptography; public static class DataHasher { private const int LargeBlockSize = 1024 * 1024; private const int SmallBlockSize = 256; public static byte[] Hash(this ReadOnlyMemory bytes, HashAlgorithm algorithm) { if (algorithm is null) { throw new ArgumentNullException(nameof(algorithm)); } if (bytes.Length == 0) { return algorithm.ComputeHash([]); } int rest, pos = 0; var blockSize = bytes.Length <= SmallBlockSize ? SmallBlockSize : LargeBlockSize; byte[] buffer = ArrayPool.Shared.Rent(blockSize); try { while ((rest = bytes.Length - pos) > 0) { var size = Math.Min(rest, blockSize); bytes.Slice(pos, size).CopyTo(buffer); algorithm.TransformBlock(buffer, 0, size, buffer, 0); pos += size; } algorithm.TransformFinalBlock([], 0, 0); return algorithm.Hash; } finally { if (buffer != null) { ArrayPool.Shared.Return(buffer); } } } public static byte[] Hash(this ReadOnlySpan bytes, HashAlgorithm algorithm) { if (algorithm is null) { throw new ArgumentNullException(nameof(algorithm)); } if (bytes.Length == 0) { return algorithm.ComputeHash([]); } int rest, pos = 0; var blockSize = bytes.Length <= SmallBlockSize ? SmallBlockSize : LargeBlockSize; byte[] buffer = ArrayPool.Shared.Rent(blockSize); try { while ((rest = bytes.Length - pos) > 0) { var size = Math.Min(rest, blockSize); bytes.Slice(pos, size).CopyTo(buffer); algorithm.TransformBlock(buffer, 0, size, buffer, 0); pos += size; } algorithm.TransformFinalBlock([], 0, 0); return algorithm.Hash; } finally { if (buffer != null) { ArrayPool.Shared.Return(buffer); } } } public static byte[] Sha256(ReadOnlyMemory value) { using SHA256 sha = SHA256.Create(); return Hash(value, sha); } public static byte[] Sha256(ReadOnlySpan value) { using SHA256 sha = SHA256.Create(); return Hash(value, sha); } public static byte[] Sha512(ReadOnlyMemory value) { using SHA512 sha = SHA512.Create(); return Hash(value, sha); } public static byte[] Sha512(ReadOnlySpan value) { using SHA512 sha = SHA512.Create(); return Hash(value, sha); } }