diff --git a/Hasher/Features/MainFeature.cs b/Hasher/Features/MainFeature.cs
index dd96903..e23ee34 100644
--- a/Hasher/Features/MainFeature.cs
+++ b/Hasher/Features/MainFeature.cs
@@ -268,6 +268,10 @@ namespace Hasher.Features
"crc64_we" => HashType.CRC64_WE,
"crc64_xz" => HashType.CRC64_XZ,
+#if NET7_0_OR_GREATER
+ "crc82_darc" => HashType.CRC82_DARC,
+#endif
+
"fletcher16" => HashType.Fletcher16,
"fletcher32" => HashType.Fletcher32,
"fletcher64" => HashType.Fletcher64,
diff --git a/README.MD b/README.MD
index a8e5838..de289e5 100644
--- a/README.MD
+++ b/README.MD
@@ -38,7 +38,7 @@ All hash and checksum types here have been written to ensure compatibility acros
| Hash / Checksum Type | Notes |
| --- | --- |
| Adler-32 | Based on the [zlib source code](https://github.com/madler/zlib/blob/v1.2.11/adler32.c) |
-| CRC | All CRC values documented [here](https://reveng.sourceforge.io/crc-catalogue/all.htm) except for CRC-82 due to bit-length restrictions |
+| CRC | All CRC values documented [here](https://reveng.sourceforge.io/crc-catalogue/all.htm), with CRC-82 only supported in `net7.0` and above |
| Fletcher | 16-, 32-, and 64-bit variants |
| FNV | 32-, and 64-bit variants; 0, 1, and 1a algorithms |
| Message Digest | MD2 and MD4 only |
diff --git a/SabreTools.Hashing.Test/TestHelper.cs b/SabreTools.Hashing.Test/TestHelper.cs
index 4712632..ca9e1f9 100644
--- a/SabreTools.Hashing.Test/TestHelper.cs
+++ b/SabreTools.Hashing.Test/TestHelper.cs
@@ -162,6 +162,10 @@ namespace SabreTools.Hashing.Test
{HashType.CRC64_WE, "91812be748f941c4"},
{HashType.CRC64_XZ, "fb49044e8331f6e5"},
+#if NET7_0_OR_GREATER
+ { HashType.CRC82_DARC, "14a892baa6688e66f55f3"},
+#endif
+
{HashType.Fletcher16, "46c1"},
{HashType.Fletcher32, "073f2d94"},
{HashType.Fletcher64, "000b073400002d94"},
diff --git a/SabreTools.Hashing/Checksum/BitOperations.cs b/SabreTools.Hashing/Checksum/BitOperations.cs
index edb14b2..4297a0f 100644
--- a/SabreTools.Hashing/Checksum/BitOperations.cs
+++ b/SabreTools.Hashing/Checksum/BitOperations.cs
@@ -11,7 +11,11 @@ namespace SabreTools.Hashing.Checksum
public static byte[] ClampValueToBytes(ulong value, int bitWidth)
#endif
{
+#if NET7_0_OR_GREATER
+ value &= System.UInt128.MaxValue >> (128 - bitWidth);
+#else
value &= ulong.MaxValue >> (64 - bitWidth);
+#endif
byte[] bytes = new byte[(bitWidth + 7) / 8];
for (int i = 0; i < bytes.Length; i++)
diff --git a/SabreTools.Hashing/Checksum/ChecksumBase.cs b/SabreTools.Hashing/Checksum/ChecksumBase.cs
index 53fa1d8..b4d9f90 100644
--- a/SabreTools.Hashing/Checksum/ChecksumBase.cs
+++ b/SabreTools.Hashing/Checksum/ChecksumBase.cs
@@ -7,7 +7,89 @@ namespace SabreTools.Hashing.Checksum
///
public abstract class ChecksumBase : System.Security.Cryptography.HashAlgorithm
{
- // No common, untyped functionality
+ #if NET7_0_OR_GREATER
+ ///
+ /// Convert an Int64 to a byte array
+ ///
+ /// Reads in little-endian format
+ internal 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;
+ }
+
+ ///
+ /// Convert a UInt64 to a byte array
+ ///
+ /// Reads in little-endian format
+ internal 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;
+ }
+
+ ///
+ /// Convert a byte array at an offset to a UInt128
+ ///
+ /// Reads in little-endian format
+ internal static UInt128 ToUInt128(byte[] value)
+ {
+ return value[0]
+ | ((UInt128)value[1] << 8)
+ | ((UInt128)value[2] << 16)
+ | ((UInt128)value[3] << 24)
+ | ((UInt128)value[4] << 32)
+ | ((UInt128)value[5] << 40)
+ | ((UInt128)value[6] << 48)
+ | ((UInt128)value[7] << 56)
+ | ((UInt128)value[8] << 64)
+ | ((UInt128)value[9] << 72)
+ | ((UInt128)value[10] << 80)
+ | ((UInt128)value[11] << 88)
+ | ((UInt128)value[12] << 96)
+ | ((UInt128)value[13] << 104)
+ | ((UInt128)value[14] << 112)
+ | ((UInt128)value[15] << 120);
+ }
+#endif
}
///
@@ -51,65 +133,5 @@ namespace SabreTools.Hashing.Checksum
Array.Reverse(hashArr);
return hashArr;
}
-
-#if NET7_0_OR_GREATER
- ///
- /// Convert an Int64 to a byte array
- ///
- /// Reads in little-endian format
- 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;
- }
-
- ///
- /// Convert a UInt64 to a byte array
- ///
- /// Reads in little-endian format
- 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
}
}
diff --git a/SabreTools.Hashing/Checksum/Crc.cs b/SabreTools.Hashing/Checksum/Crc.cs
index 1f96019..9ea42de 100644
--- a/SabreTools.Hashing/Checksum/Crc.cs
+++ b/SabreTools.Hashing/Checksum/Crc.cs
@@ -32,7 +32,11 @@ namespace SabreTools.Hashing.Checksum
public Crc(CrcDefinition def)
{
// Check for a valid bit width
+#if NET7_0_OR_GREATER
+ if (def.Width < 0 || def.Width > 128)
+#else
if (def.Width < 0 || def.Width > 64)
+#endif
throw new ArgumentOutOfRangeException(nameof(def));
Def = def;
diff --git a/SabreTools.Hashing/Checksum/CrcTable.cs b/SabreTools.Hashing/Checksum/CrcTable.cs
index b911765..4d13ffb 100644
--- a/SabreTools.Hashing/Checksum/CrcTable.cs
+++ b/SabreTools.Hashing/Checksum/CrcTable.cs
@@ -24,7 +24,7 @@ namespace SabreTools.Hashing.Checksum
/// Bit mask based on the CRC width
///
#if NET7_0_OR_GREATER
- private UInt128 BitMask => 1UL << (_definition.Width - 1);
+ private UInt128 BitMask => UInt128.Parse("1") << (_definition.Width - 1);
#else
private ulong BitMask => 1UL << (_definition.Width - 1);
#endif
@@ -87,7 +87,11 @@ namespace SabreTools.Hashing.Checksum
point = ReverseBits(point, def.Width);
// Shift back to account for storage
+#if NET7_0_OR_GREATER
+ point &= UInt128.MaxValue >> (128 - def.Width);
+#else
point &= ulong.MaxValue >> (64 - def.Width);
+#endif
// Assign to the table
_table[0, i] = point;
diff --git a/SabreTools.Hashing/Checksum/StandardDefinitions.cs b/SabreTools.Hashing/Checksum/StandardDefinitions.cs
index 7e8181b..1a7c680 100644
--- a/SabreTools.Hashing/Checksum/StandardDefinitions.cs
+++ b/SabreTools.Hashing/Checksum/StandardDefinitions.cs
@@ -1700,5 +1700,25 @@ namespace SabreTools.Hashing.Checksum
};
#endregion
+
+ #region CRC-82
+
+#if NET7_0_OR_GREATER
+ ///
+ /// CRC-82/DARC
+ ///
+ public static readonly CrcDefinition CRC82_DARC = new()
+ {
+ Name = "CRC-82/DARC",
+ Width = 82,
+ Poly = ChecksumBase.ToUInt128([0x11, 0x04, 0x44, 0x01, 0x14, 0x01, 0x11, 0x01, 0x8c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+ Init = ChecksumBase.ToUInt128([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+ ReflectIn = true,
+ ReflectOut = true,
+ XorOut = ChecksumBase.ToUInt128([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
+ };
+#endif
+
+ #endregion
}
}
diff --git a/SabreTools.Hashing/HashOperations.cs b/SabreTools.Hashing/HashOperations.cs
index 8cdf0dc..fa499f5 100644
--- a/SabreTools.Hashing/HashOperations.cs
+++ b/SabreTools.Hashing/HashOperations.cs
@@ -50,6 +50,29 @@ namespace SabreTools.Hashing
return result;
}
+#if NET7_0_OR_GREATER
+ ///
+ /// Convert a byte array to a UInt64
+ ///
+ /// Byte array to convert
+ /// UInt64 representing the byte array
+ /// https://stackoverflow.com/questions/66750224/how-to-convert-a-byte-array-of-any-size-to-ulong-in-c
+ public static UInt128 BytesToUInt128(byte[]? bytes)
+ {
+ // If we get null in, we send 0 out
+ if (bytes is null)
+ return default;
+
+ UInt128 result = 0;
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ result |= (UInt128)bytes[i] << (i * 8);
+ }
+
+ return result;
+ }
+#endif
+
#endregion
#region Read Big-Endian
diff --git a/SabreTools.Hashing/HashType.cs b/SabreTools.Hashing/HashType.cs
index 7bcb1ef..d60077a 100644
--- a/SabreTools.Hashing/HashType.cs
+++ b/SabreTools.Hashing/HashType.cs
@@ -1116,6 +1116,20 @@ namespace SabreTools.Hashing
#endregion
+ #region CRC-82
+
+#if NET7_0_OR_GREATER
+ ///
+ /// CRC 82-bit checksum (CRC-82/DARC)
+ ///
+ public static readonly HashType CRC82_DARC = new("CRC-82/DARC",
+ "CRC 82-bit checksum (CRC-82/DARC)",
+ [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+ "000000000000000000000");
+#endif
+
+ #endregion
+
#endregion
#region Fletcher
@@ -1652,6 +1666,10 @@ namespace SabreTools.Hashing
CRC64_WE,
CRC64_XZ,
+#if NET7_0_OR_GREATER
+ CRC82_DARC,
+#endif
+
Fletcher16,
Fletcher32,
Fletcher64,
@@ -2000,6 +2018,11 @@ namespace SabreTools.Hashing
else if (hashType == CRC64_XZ)
return new Crc(StandardDefinitions.CRC64_XZ);
+#if NET7_0_OR_GREATER
+ else if (hashType == CRC82_DARC)
+ return new Crc(StandardDefinitions.CRC82_DARC);
+#endif
+
else if (hashType == Fletcher16)
return new Fletcher16();
else if (hashType == Fletcher32)
diff --git a/SabreTools.Hashing/HashWrapper.cs b/SabreTools.Hashing/HashWrapper.cs
index c86b9d3..b53a6a1 100644
--- a/SabreTools.Hashing/HashWrapper.cs
+++ b/SabreTools.Hashing/HashWrapper.cs
@@ -147,7 +147,11 @@ namespace SabreTools.Hashing
return null;
// Get the total number of characters needed
+#if NET7_0_OR_GREATER
+ UInt128 hash = BytesToUInt128(cr.Hash);
+#else
ulong hash = BytesToUInt64(cr.Hash);
+#endif
int length = (cr.Def.Width / 4) + (cr.Def.Width % 4 > 0 ? 1 : 0);
return hash.ToString($"x{length}");
}