using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Masuit.Tools.Security; /// /// 64-bit CRC 实现 /// /// /// 支持ISO 3309标准 /// public class Crc64 : HashAlgorithm { ~Crc64() { Dispose(); } public const ulong DefaultSeed = 0x0; private readonly ulong[] _table; private readonly ulong _seed; private ulong _hash; internal static ulong[] Table; public const ulong Iso3309Polynomial = 0xD800000000000000; public override int HashSize => 64; public Crc64() : this(Iso3309Polynomial) { } public Crc64(ulong polynomial) : this(polynomial, DefaultSeed) { } public Crc64(ulong polynomial, ulong seed) { if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException("Big Endian 处理程序不支持"); } _table = InitializeTable(polynomial); _seed = _hash = seed; } public override void Initialize() { _hash = _seed; } protected override void HashCore(byte[] array, int ibStart, int cbSize) { _hash = CalculateHash(_hash, _table, array, ibStart, cbSize); } protected override byte[] HashFinal() { var hashBuffer = UInt64ToBigEndianBytes(_hash); HashValue = hashBuffer; return hashBuffer; } protected static ulong CalculateHash(ulong seed, ulong[] table, IList buffer, int start, int size) { var hash = seed; for (var i = start; i < start + size; i++) { unchecked { hash = (hash >> 8) ^ table[(buffer[i] ^ hash) & 0xff]; } } return hash; } private static byte[] UInt64ToBigEndianBytes(ulong value) { var result = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) { Array.Reverse(result); } return result; } private static ulong[] InitializeTable(ulong polynomial) { if (polynomial == Iso3309Polynomial && Table != null) { return Table; } var createTable = CreateTable(polynomial); if (polynomial == Iso3309Polynomial) { Table = createTable; } return createTable; } protected static ulong[] CreateTable(ulong polynomial) { var createTable = new ulong[256]; for (var i = 0; i < 256; ++i) { var entry = (ulong)i; for (var j = 0; j < 8; ++j) { if ((entry & 1) == 1) { entry = (entry >> 1) ^ polynomial; } else { entry >>= 1; } } createTable[i] = entry; } return createTable; } public static ulong Compute(byte[] buffer) { return Compute(DefaultSeed, buffer); } public static ulong Compute(ulong seed, byte[] buffer) { Table ??= CreateTable(Iso3309Polynomial); return CalculateHash(seed, Table, buffer, 0, buffer.Length); } }