mirror of
https://github.com/SabreTools/SabreTools.Hashing.git
synced 2026-07-08 18:06:40 +00:00
Internally use 128-bit integers for CRCs on .NET 7 and above
This commit is contained in:
@@ -5,7 +5,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <summary>
|
||||
/// Clamp a value to a certain bit width and convert to a byte array
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
public static byte[] ClampValueToBytes(System.UInt128 value, int bitWidth)
|
||||
#else
|
||||
public static byte[] ClampValueToBytes(ulong value, int bitWidth)
|
||||
#endif
|
||||
{
|
||||
value &= ulong.MaxValue >> (64 - bitWidth);
|
||||
byte[] bytes = new byte[(bitWidth + 7) / 8];
|
||||
|
||||
@@ -40,11 +40,76 @@ namespace SabreTools.Hashing.Checksum
|
||||
long l => BitConverter.GetBytes(l),
|
||||
ulong l => BitConverter.GetBytes(l),
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
Int128 i => GetBytes(i),
|
||||
UInt128 i => GetBytes(i),
|
||||
#endif
|
||||
|
||||
_ => [],
|
||||
};
|
||||
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// Convert an Int64 to a byte array
|
||||
/// </summary>
|
||||
/// <remarks>Reads in little-endian format</remarks>
|
||||
private static byte[] GetBytes(Int128 value)
|
||||
{
|
||||
byte[] output =
|
||||
[
|
||||
(byte)(value & 0xFF),
|
||||
(byte)((value >> 8) & 0xFF),
|
||||
(byte)((value >> 16) & 0xFF),
|
||||
(byte)((value >> 24) & 0xFF),
|
||||
(byte)((value >> 32) & 0xFF),
|
||||
(byte)((value >> 40) & 0xFF),
|
||||
(byte)((value >> 48) & 0xFF),
|
||||
(byte)((value >> 56) & 0xFF),
|
||||
(byte)((value >> 64) & 0xFF),
|
||||
(byte)((value >> 72) & 0xFF),
|
||||
(byte)((value >> 80) & 0xFF),
|
||||
(byte)((value >> 88) & 0xFF),
|
||||
(byte)((value >> 96) & 0xFF),
|
||||
(byte)((value >> 104) & 0xFF),
|
||||
(byte)((value >> 112) & 0xFF),
|
||||
(byte)((value >> 120) & 0xFF),
|
||||
];
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a UInt64 to a byte array
|
||||
/// </summary>
|
||||
/// <remarks>Reads in little-endian format</remarks>
|
||||
private static byte[] GetBytes(UInt128 value)
|
||||
{
|
||||
byte[] output =
|
||||
[
|
||||
(byte)(value & 0xFF),
|
||||
(byte)((value >> 8) & 0xFF),
|
||||
(byte)((value >> 16) & 0xFF),
|
||||
(byte)((value >> 24) & 0xFF),
|
||||
(byte)((value >> 32) & 0xFF),
|
||||
(byte)((value >> 40) & 0xFF),
|
||||
(byte)((value >> 48) & 0xFF),
|
||||
(byte)((value >> 56) & 0xFF),
|
||||
(byte)((value >> 64) & 0xFF),
|
||||
(byte)((value >> 72) & 0xFF),
|
||||
(byte)((value >> 80) & 0xFF),
|
||||
(byte)((value >> 88) & 0xFF),
|
||||
(byte)((value >> 96) & 0xFF),
|
||||
(byte)((value >> 104) & 0xFF),
|
||||
(byte)((value >> 112) & 0xFF),
|
||||
(byte)((value >> 120) & 0xFF),
|
||||
];
|
||||
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@ using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
public class Crc : ChecksumBase<UInt128>
|
||||
#else
|
||||
public class Crc : ChecksumBase<ulong>
|
||||
#endif
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => Def.Width;
|
||||
@@ -50,7 +54,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Create a copy of the hash
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 localHash = _hash;
|
||||
#else
|
||||
ulong localHash = _hash;
|
||||
#endif
|
||||
|
||||
// Handle mutual reflection
|
||||
if (Def.ReflectIn ^ Def.ReflectOut)
|
||||
|
||||
@@ -21,7 +21,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// corresponds to the inward end of the shift register, and is always
|
||||
/// set. The highest-order term is omitted.
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
public System.UInt128 Poly { get; set; }
|
||||
#else
|
||||
public ulong Poly { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The settings of the bit cells at the start of each calculation,
|
||||
@@ -29,7 +33,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// hexadecimal, direct notation found in MSB-first code. The least
|
||||
/// significant bit corresponds to the inward end of the shift register.
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
public System.UInt128 Init { get; set; }
|
||||
#else
|
||||
public ulong Init { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// If equal to false, specifies that the characters of the message
|
||||
@@ -60,6 +68,10 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// is written in hexadecimal notation, having the same endianness as
|
||||
/// the CRC such that its true image appears in the characters of the CRC.
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
public System.UInt128 XorOut { get; set; }
|
||||
#else
|
||||
public ulong XorOut { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,20 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <summary>
|
||||
/// Bit mask based on the CRC width
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
private UInt128 BitMask => 1UL << (_definition.Width - 1);
|
||||
#else
|
||||
private ulong BitMask => 1UL << (_definition.Width - 1);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Mapping table
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
private readonly UInt128[,] _table;
|
||||
#else
|
||||
private readonly ulong[,] _table;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Definition used to build the table
|
||||
@@ -44,13 +52,21 @@ namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
// Initialize the internal
|
||||
_definition = def;
|
||||
#if NET7_0_OR_GREATER
|
||||
_table = new UInt128[SliceCount, 1 << BitsPerStep];
|
||||
#else
|
||||
_table = new ulong[SliceCount, 1 << BitsPerStep];
|
||||
#endif
|
||||
|
||||
// Build the standard table
|
||||
for (uint i = 0; i < (1 << BitsPerStep); i++)
|
||||
{
|
||||
// Get the starting value for this index
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 point = i;
|
||||
#else
|
||||
ulong point = i;
|
||||
#endif
|
||||
if (!Bitwise && def.ReflectIn)
|
||||
point = ReverseBits(point, BitsPerStep);
|
||||
|
||||
@@ -87,7 +103,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
// Build each slice from the previous
|
||||
for (int j = 0; j < 1 << BitsPerStep; j++)
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 last = _table[i - 1, j];
|
||||
#else
|
||||
ulong last = _table[i - 1, j];
|
||||
#endif
|
||||
if (_definition.ReflectIn)
|
||||
_table[i, j] = (last >> BitsPerStep) ^ _table[0, (byte)last];
|
||||
else
|
||||
@@ -108,7 +128,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// or when <paramref name="offset"/> + <paramref name="length"/> is greater
|
||||
/// than the data length.
|
||||
/// </exception>
|
||||
#if NET7_0_OR_GREATER
|
||||
public void TransformBlock(ref UInt128 hash, byte[] data, int offset, int length)
|
||||
#else
|
||||
public void TransformBlock(ref ulong hash, byte[] data, int offset, int length)
|
||||
#endif
|
||||
{
|
||||
// Empty data just returns
|
||||
if (data.Length == 0)
|
||||
@@ -137,7 +161,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <param name="hash">Current hash value, updated on run</param>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the data to process</param>
|
||||
#if NET7_0_OR_GREATER
|
||||
private void PerformChecksumStep(ref UInt128 hash, byte[] data, int offset)
|
||||
#else
|
||||
private void PerformChecksumStep(ref ulong hash, byte[] data, int offset)
|
||||
#endif
|
||||
{
|
||||
// Per-bit processing
|
||||
if (Bitwise)
|
||||
@@ -164,7 +192,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <summary>
|
||||
/// Perform an optimized transform step
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
private bool TransformBlockFast(ref UInt128 hash, byte[] data, int offset, int length)
|
||||
#else
|
||||
private bool TransformBlockFast(ref ulong hash, byte[] data, int offset, int length)
|
||||
#endif
|
||||
{
|
||||
// Bitwise transformations are not optimized
|
||||
if (Bitwise)
|
||||
@@ -196,10 +228,18 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// Optimized transformation for CRC with reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 4 bytes at a time</remarks>
|
||||
#if NET7_0_OR_GREATER
|
||||
private void TransformBlockFast4Reflect(ref UInt128 hash, byte[] data, int offset, int length)
|
||||
#else
|
||||
private void TransformBlockFast4Reflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
#endif
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 local = hash;
|
||||
#else
|
||||
ulong local = hash;
|
||||
#endif
|
||||
|
||||
// Process aligned data
|
||||
if (length > 4)
|
||||
@@ -209,11 +249,20 @@ namespace SabreTools.Hashing.Checksum
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
+ (data[offset + 2] << 16)
|
||||
+ (data[offset + 3] << 24));
|
||||
#else
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
+ (data[offset + 2] << 16)
|
||||
+ (data[offset + 3] << 24));
|
||||
#endif
|
||||
|
||||
offset += 4;
|
||||
|
||||
local = _table[3, (byte)low]
|
||||
@@ -238,10 +287,18 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// Optimized transformation for CRC with reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 8 bytes at a time</remarks>
|
||||
#if NET7_0_OR_GREATER
|
||||
private void TransformBlockFast8Reflect(ref UInt128 hash, byte[] data, int offset, int length)
|
||||
#else
|
||||
private void TransformBlockFast8Reflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
#endif
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 local = hash;
|
||||
#else
|
||||
ulong local = hash;
|
||||
#endif
|
||||
|
||||
// Process aligned data
|
||||
if (length > 8)
|
||||
@@ -251,6 +308,18 @@ namespace SabreTools.Hashing.Checksum
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
+ (data[offset + 2] << 16)
|
||||
+ (data[offset + 3] << 24));
|
||||
UInt128 high = (uint)(
|
||||
data[offset + 4]
|
||||
+ (data[offset + 5] << 8)
|
||||
+ (data[offset + 6] << 16)
|
||||
+ (data[offset + 7] << 24));
|
||||
#else
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
@@ -261,6 +330,7 @@ namespace SabreTools.Hashing.Checksum
|
||||
+ (data[offset + 5] << 8)
|
||||
+ (data[offset + 6] << 16)
|
||||
+ (data[offset + 7] << 24));
|
||||
#endif
|
||||
offset += 8;
|
||||
|
||||
local = _table[7, (byte)low]
|
||||
@@ -289,10 +359,18 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// Optimized transformation for 32-bit CRC with no reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 8 bytes at a time</remarks>
|
||||
#if NET7_0_OR_GREATER
|
||||
private void TransformBlockFast8NoReflect(ref UInt128 hash, byte[] data, int offset, int length)
|
||||
#else
|
||||
private void TransformBlockFast8NoReflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
#endif
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 local = hash;
|
||||
#else
|
||||
ulong local = hash;
|
||||
#endif
|
||||
|
||||
// Process aligned data
|
||||
if (length > 8)
|
||||
@@ -302,6 +380,18 @@ namespace SabreTools.Hashing.Checksum
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 low = local ^ (uint)(
|
||||
data[offset + 3]
|
||||
+ (data[offset + 2] << 8)
|
||||
+ (data[offset + 1] << 16)
|
||||
+ (data[offset + 0] << 24));
|
||||
UInt128 high = (uint)(
|
||||
data[offset + 7]
|
||||
+ (data[offset + 6] << 8)
|
||||
+ (data[offset + 5] << 16)
|
||||
+ (data[offset + 4] << 24));
|
||||
#else
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 3]
|
||||
+ (data[offset + 2] << 8)
|
||||
@@ -312,6 +402,7 @@ namespace SabreTools.Hashing.Checksum
|
||||
+ (data[offset + 6] << 8)
|
||||
+ (data[offset + 5] << 16)
|
||||
+ (data[offset + 4] << 24));
|
||||
#endif
|
||||
offset += 8;
|
||||
|
||||
local = _table[4, (byte)low]
|
||||
|
||||
@@ -117,9 +117,17 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// Reverse the endianness of a value
|
||||
/// </summary>
|
||||
#if NET7_0_OR_GREATER
|
||||
public static UInt128 ReverseBits(UInt128 value, int bitWidth)
|
||||
#else
|
||||
public static ulong ReverseBits(ulong value, int bitWidth)
|
||||
#endif
|
||||
{
|
||||
#if NET7_0_OR_GREATER
|
||||
UInt128 reverse = 0;
|
||||
#else
|
||||
ulong reverse = 0;
|
||||
#endif
|
||||
for (int i = 0; i < bitWidth; i++)
|
||||
{
|
||||
reverse <<= 1;
|
||||
|
||||
Reference in New Issue
Block a user