147 Commits
1.2.2 ... 1.3.0

Author SHA1 Message Date
Matt Nadareski
4a9fc1a144 Bump version 2024-11-12 12:15:51 -05:00
Matt Nadareski
563d293f4b Add overarching CRC region 2024-11-11 21:36:04 -05:00
Matt Nadareski
39c2451354 Reduce FNV code for simplicity 2024-11-11 20:51:37 -05:00
Matt Nadareski
b8ec4ac9c4 Make FnvBase public 2024-11-11 04:04:02 -05:00
Matt Nadareski
adc918ea8a Make FNV public 2024-11-11 04:00:56 -05:00
Matt Nadareski
186f8a1ece Add FNV variants 2024-11-11 04:00:46 -05:00
Matt Nadareski
d8cb2e2955 Turn some things into auto-fields for clarity 2024-11-11 02:29:35 -05:00
Matt Nadareski
83f008919c Generalize Fletcher base class for all checksums 2024-11-11 01:57:08 -05:00
Matt Nadareski
72a98e3e03 No-reflect CRC-32 made more efficient 2024-11-11 01:32:57 -05:00
Matt Nadareski
32fe421af4 CRC below 64 can be optimized more 2024-11-11 01:09:23 -05:00
Matt Nadareski
3382c20217 Add MD4 efficient implementation 2024-11-10 23:32:33 -05:00
Matt Nadareski
6700f603f2 Fix efficient MD2 2024-11-10 22:43:38 -05:00
Matt Nadareski
e1c1c8322d Fix missing method from Framework 2024-11-10 22:29:17 -05:00
Matt Nadareski
7b9580c991 Add MD2 to the readme 2024-11-10 22:24:10 -05:00
Matt Nadareski
75e536df4f Create more efficient MD2 implementation 2024-11-10 22:23:46 -05:00
Matt Nadareski
3e18ddce9f Create inefficient MD2 implementation 2024-11-10 21:36:38 -05:00
Matt Nadareski
f4d5e88f0a Fix issue with non-length streams 2024-11-10 20:43:11 -05:00
Matt Nadareski
a5f7e7d91d Shortcut on 0-byte inputs 2024-11-10 20:38:39 -05:00
Matt Nadareski
2e3e16e8ae Add zero byte hash byte arrays 2024-11-10 20:36:30 -05:00
Matt Nadareski
8fa100eb89 Add zero byte hash strings 2024-11-10 19:57:37 -05:00
Matt Nadareski
bf1cfa0e1f Add performance note 2024-11-09 23:45:59 -05:00
Matt Nadareski
4e86e0ef86 Remove now-unused Aaru.Checksums pieces 2024-11-09 23:18:45 -05:00
Matt Nadareski
d57396612f Add Fletcher family checksums 2024-11-09 23:14:31 -05:00
Matt Nadareski
1b06751c68 Move helper to main utility class 2024-11-09 22:06:46 -05:00
Matt Nadareski
89582a56ac Move things to Checksum namespace 2024-11-09 22:03:32 -05:00
Matt Nadareski
ac1cacc247 Add Adler-32 implementation 2024-11-09 22:01:07 -05:00
Matt Nadareski
27276ce05d Fix CRC note 2024-11-09 21:34:41 -05:00
Matt Nadareski
841f5708a3 Update README 2024-11-09 21:32:13 -05:00
Matt Nadareski
6df184fa4e Add Tiger2 variants (0x80 pad start) 2024-11-09 21:32:02 -05:00
Matt Nadareski
d9cf9fd3b2 Use new message digest base class 2024-11-09 21:12:02 -05:00
Matt Nadareski
21b49921ac Create message digest base class 2024-11-09 20:54:58 -05:00
Matt Nadareski
d1b60f7951 Move message digests to new namespace 2024-11-09 20:51:38 -05:00
Matt Nadareski
bb9d4155d2 Add Tiger family hashes 2024-11-09 20:46:05 -05:00
Matt Nadareski
5b66eaf253 Make RIPEMD implementations public 2024-11-09 03:11:35 -05:00
Matt Nadareski
7c4d6a6862 Create and use new HashOperations helper class 2024-11-09 03:11:01 -05:00
Matt Nadareski
79c10cf2fb Add RIPEMD-256 implementation 2024-11-09 02:59:17 -05:00
Matt Nadareski
ffc6bc045d Add RIPEMD-320 implementation 2024-11-09 02:54:04 -05:00
Matt Nadareski
7a43f6c0de Add region in HashType enum for RIPEMD 2024-11-09 02:35:50 -05:00
Matt Nadareski
d096cbf07e Add RIPEMD-128 implementation 2024-11-09 02:33:51 -05:00
Matt Nadareski
bb67c3e2f3 Migrate to internal RIPEMD-160 implementation 2024-11-09 01:18:52 -05:00
Matt Nadareski
f2e5033bb4 Simplify the hash assembly 2024-11-09 01:15:10 -05:00
Matt Nadareski
0f7d373751 Fix RIPEMD-160 hashing 2024-11-09 01:13:46 -05:00
Matt Nadareski
8231ab18a6 Fix order of operations 2024-11-09 01:03:40 -05:00
Matt Nadareski
bd8055b7d5 Rename vars for easier debugging 2024-11-09 00:36:42 -05:00
Matt Nadareski
bd0f76ef08 Consolidate the hash pieces into an array 2024-11-09 00:32:25 -05:00
Matt Nadareski
70e79a68eb Fix little-endian read, again 2024-11-09 00:26:41 -05:00
Matt Nadareski
a087abf3d3 Fix a logic bug (nw) 2024-11-08 23:24:50 -05:00
Matt Nadareski
bd363ca1ec Rename some things to make easier debugging 2024-11-08 23:13:19 -05:00
Matt Nadareski
e4a53f3d62 Minor cleanup (nw) 2024-11-08 21:48:30 -05:00
Matt Nadareski
1401775c15 Unroll main loop 2024-11-08 21:19:33 -05:00
Matt Nadareski
a3ba52adee Split RoundOperation to prepare for flattening 2024-11-08 20:43:49 -05:00
Matt Nadareski
544d6f1cc8 Fix infinite loop bug 2024-11-08 20:31:52 -05:00
Matt Nadareski
62da665c07 Preemptively wire up support for RIPEMD-160 2024-11-08 20:13:14 -05:00
Matt Nadareski
8480ec8d92 Add majority of RIPEMD-160 implementation 2024-11-08 20:10:45 -05:00
Matt Nadareski
c763d402d9 Add RIPEMD constants 2024-11-08 16:11:03 -05:00
Matt Nadareski
7c090b76c0 Make XXH32 and XXH64 implementations public 2024-11-08 15:53:36 -05:00
Matt Nadareski
2be7850b9e Update states to be more like XXH32/64 2024-11-08 14:33:34 -05:00
Matt Nadareski
611a0934ae Add more XXH3 utilities 2024-11-08 14:08:16 -05:00
Matt Nadareski
16826f4c8b Add more XXH3 utilities 2024-11-08 13:47:03 -05:00
Matt Nadareski
4732de1268 Add XXH3 utilities 2024-11-08 13:27:05 -05:00
Matt Nadareski
f74c9ddffd Use internal implementation for XXH64 2024-11-08 13:11:58 -05:00
Matt Nadareski
58f2475099 Fix LE64 bug 2024-11-08 13:09:32 -05:00
Matt Nadareski
1d1fe196cf Minor cleanup (nw) 2024-11-08 12:57:58 -05:00
Matt Nadareski
2af987bb1d Prep the hash wrapper for new XXH64 2024-11-08 12:48:05 -05:00
Matt Nadareski
effb2f9db6 Clean up XXH64 2024-11-08 12:46:31 -05:00
Matt Nadareski
b728aa77c7 Use internal implementation for XXH32 2024-11-08 12:33:43 -05:00
Matt Nadareski
fefdcd72a3 Fix endian reads 2024-11-08 12:30:22 -05:00
Matt Nadareski
5d25a017eb Use Array.Clear instead of a loop 2024-11-08 11:14:00 -05:00
Matt Nadareski
c0643e3bca Just make this a bool 2024-11-08 10:35:27 -05:00
Matt Nadareski
65a57f6c60 Slight tweaks to XXH32 (nw) 2024-11-08 01:05:22 -05:00
Matt Nadareski
9c27523612 xxHash aren't reversed 2024-11-08 00:54:22 -05:00
Matt Nadareski
5ed7ad7802 Rename accumulator so I don't keep losing track 2024-11-08 00:28:51 -05:00
Matt Nadareski
41be02c57d Fix issue in XXH32 updating 2024-11-08 00:23:09 -05:00
Matt Nadareski
0ec9c1f91d Preemptively add wiring in HashWrapper for xxHash 2024-11-07 23:44:06 -05:00
Matt Nadareski
de8e510f71 Reserved isn't used, so remove it 2024-11-07 23:34:42 -05:00
Matt Nadareski
82f051354f Start cleaning up XXH32 code 2024-11-07 23:29:25 -05:00
Matt Nadareski
7559ba2edc Add CRC-1 (parity bit) 2024-11-07 22:25:48 -05:00
Matt Nadareski
4a408ded7e Add xxHash32 hasher class (nw) 2024-11-07 22:15:25 -05:00
Matt Nadareski
3469d424af Rename TransformBlock to Update 2024-11-07 22:00:29 -05:00
Matt Nadareski
3fa04bba65 Add most XXH64 code 2024-11-07 21:53:07 -05:00
Matt Nadareski
f135693c7e Add most XXH32 code 2024-11-07 21:18:13 -05:00
Matt Nadareski
0d6806cf59 Add 128-bit hash struct 2024-11-07 20:04:37 -05:00
Matt Nadareski
4dde900195 Split XXH3State 2024-11-07 20:02:59 -05:00
Matt Nadareski
a383bb39a6 Add skeletons and TODOs to states 2024-11-07 17:06:57 -05:00
Matt Nadareski
92554705cc Add xxHash state classes 2024-11-07 16:40:33 -05:00
Matt Nadareski
c5e4cb1495 Add xxHash constants and enums 2024-11-07 16:20:43 -05:00
Matt Nadareski
9bb8a07c32 Public CrcRunner and related 2024-11-07 15:26:10 -05:00
Matt Nadareski
7878591107 Add CRC-3/4/5/6/7 implementations 2024-11-07 15:18:18 -05:00
Matt Nadareski
6f536b8e2a Add CRC-8 implementations 2024-11-07 14:54:44 -05:00
Matt Nadareski
dee69d1d88 Enable optimization for all reflected checksums 2024-11-07 14:30:12 -05:00
Matt Nadareski
0e8694cc90 Add CRC-10/11/12/13/14/15 implementations 2024-11-07 14:28:08 -05:00
Matt Nadareski
a7f8e0664a Fix reflecting initial value 2024-11-07 13:56:56 -05:00
Matt Nadareski
b1e4546697 Slight tweaks to table generation 2024-11-07 13:28:56 -05:00
Matt Nadareski
51d1a81e08 Add CRC-24 reflected to optimized list 2024-11-07 12:56:18 -05:00
Matt Nadareski
1a941b44fc Fix and reenable CRC-17 2024-11-07 12:49:33 -05:00
Matt Nadareski
ea601eed8d Fix CRC-17 definition 2024-11-07 12:35:13 -05:00
Matt Nadareski
c1a9e007c5 Make test more maintainable 2024-11-07 12:24:12 -05:00
Matt Nadareski
fb83427c91 Add CRC-17 and CRC-21 implementations 2024-11-07 03:36:34 -05:00
Matt Nadareski
57f9aa9133 Add CRC-30 and CRC-31 implementations 2024-11-07 03:13:05 -05:00
Matt Nadareski
dbcb654f8a Add name field for CRC definitions 2024-11-07 03:05:06 -05:00
Matt Nadareski
16d3472fc6 Consolidate cases in fast transform 2024-11-07 02:29:51 -05:00
Matt Nadareski
aced21c9f0 16/32/64 reflect all can share optimization 2024-11-07 02:15:07 -05:00
Matt Nadareski
2a81a65f99 Add CRC-64 reflect 4-byte optimized 2024-11-07 02:01:02 -05:00
Matt Nadareski
9819a5975a Extend no-reflect to 8-bytes 2024-11-07 01:44:03 -05:00
Matt Nadareski
e36cd9bf3c Add fast no-reflect transform implementation 2024-11-07 01:40:05 -05:00
Matt Nadareski
4eec52241e Region up HashType for readability 2024-11-06 22:01:27 -05:00
Matt Nadareski
98c646d579 Bump version 2024-11-06 20:38:06 -05:00
Matt Nadareski
d8da0d6312 Update test packages 2024-11-06 20:36:18 -05:00
Matt Nadareski
d259dca9ab Fix formatting in project files 2024-11-06 20:33:28 -05:00
Matt Nadareski
188483b4d1 Compress hasn't been used for a little 2024-11-06 20:24:33 -05:00
Matt Nadareski
6b33bec6e2 Remove final this reference 2024-11-06 15:23:01 -05:00
Matt Nadareski
1fc4c13683 Add testing comment 2024-11-06 15:19:57 -05:00
Matt Nadareski
2ef3a6f254 Add CRC-24 implementations 2024-11-06 14:45:19 -05:00
Matt Nadareski
827239a08a Add CRC-40 implementation 2024-11-06 14:32:17 -05:00
Matt Nadareski
c1e847c1cf Reenable RIPEMD test 2024-11-06 14:15:55 -05:00
Matt Nadareski
f01d801421 Privatize the table 2024-11-06 14:11:45 -05:00
Matt Nadareski
483a74f8c9 Add first working fast transform 2024-11-06 13:42:12 -05:00
Matt Nadareski
d0660472eb Less hardcoding, I guess? 2024-11-06 12:45:53 -05:00
Matt Nadareski
5718c62157 None of that needs to be public 2024-11-06 12:44:33 -05:00
Matt Nadareski
63eff1ab18 Outsource checksum step 2024-11-06 12:40:43 -05:00
Matt Nadareski
7de1c6464f Reduce allocated tables 2024-11-06 12:03:09 -05:00
Matt Nadareski
f900eca029 Separate checksum step into new method 2024-11-06 12:00:22 -05:00
Matt Nadareski
cb3585ae49 Rename parameter 2024-11-06 11:56:09 -05:00
Matt Nadareski
9610e1756f Add remaining CRC-16 implementations 2024-11-06 06:31:29 -05:00
Matt Nadareski
45d0e2dde1 Replace CRC-16 existing implementations 2024-11-06 05:54:41 -05:00
Matt Nadareski
389c609a9d Comments into summaries 2024-11-06 05:47:09 -05:00
Matt Nadareski
71d88d3467 Add all CRC-16 definitions 2024-11-06 05:42:22 -05:00
Matt Nadareski
3905905301 Make CRC-64/ECMA default 2024-11-06 05:21:39 -05:00
Matt Nadareski
adc03c90eb Remove Aaru CRC-32 2024-11-06 05:20:09 -05:00
Matt Nadareski
4c006317be Add remaining CRC-32 implementations 2024-11-06 05:19:13 -05:00
Matt Nadareski
21498f6d52 Remove Aaru CRC-64 2024-11-06 05:08:48 -05:00
Matt Nadareski
2dcf0e7eea Add remaining CRC-64 implementations 2024-11-06 05:08:21 -05:00
Matt Nadareski
0cf07ae13a Remove external CRC-32 implementations 2024-11-06 04:54:27 -05:00
Matt Nadareski
74d74fdfae Remove note 2024-11-06 04:52:42 -05:00
Matt Nadareski
9e48cca1a3 Add unoptimized generic CRC framework 2024-11-06 04:46:39 -05:00
Matt Nadareski
23679266b4 Finalize CRC64 support names 2024-11-06 02:54:27 -05:00
Matt Nadareski
992e22cc76 ECMA/ISO war 2024-11-06 02:34:59 -05:00
Matt Nadareski
5cfe0dcb09 Remove "CRC64_ECMA" 2024-11-06 02:21:20 -05:00
Matt Nadareski
3ebb489f23 Use correct name for implementation 2024-11-06 02:14:58 -05:00
Matt Nadareski
94b9e91718 Create and use CRC64_ECMA 2024-11-06 00:37:40 -05:00
Matt Nadareski
445c3473d9 Correct comment in README 2024-11-06 00:18:55 -05:00
Matt Nadareski
d8bc77a938 Resync CRC64 just in case 2024-11-06 00:17:10 -05:00
Matt Nadareski
10406fa90c Update seed based on MS documentation 2024-11-06 00:03:26 -05:00
Matt Nadareski
08f5ae5b8b Add TODO after way too much thinking 2024-11-06 00:02:16 -05:00
Matt Nadareski
e5010f1856 Better define polynomials 2024-11-05 23:50:25 -05:00
Matt Nadareski
d6b00b1a42 Fix build 2024-11-05 22:08:03 -05:00
Matt Nadareski
8aa10ff06b Reduce reliance on external packages 2024-11-05 22:02:30 -05:00
83 changed files with 9817 additions and 6499 deletions

View File

@@ -1,14 +1,33 @@
# SabreTools.Hashing
This library comprises of methods and helpers to simplify the process of getting checksums and hashes from both files and streams. See the following table for information about where each of the various components comes from:
This library comprises of methods and helpers to simplify the process of getting checksums and hashes from both files and streams.
## Internal Implementations
All hash and checksum types here have been written to ensure compatibility across all .NET versions. Some may have been adapted to ensure this compatibility. These can be treated as reference implementations, not always optimized.
| 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 |
| Fletcher | 16-, 32-, and 64-bit variants |
| FNV | 32-, and 64-bit variants; 0, 1, and 1a algorithms |
| Message Digest | MD2 and MD4 only |
| RIPEMD | 128-, 160-, 256-, and 320-bit variants |
| Tiger | 128-, 160-, and 192-bit variants; 3- and 4-pass; `0x01` and `0x80` (Tiger2) pad-initialized |
| xxHash | xxHash-32 and xxHash-64 only |
## External Implementations
External implementations of hash and checksum types may not be compatible with all .NET versions. Please see the table below for more information about support.
| Source | Hash / Checksum Types | Notes |
| --- | --- | --- |
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | Adler-32, CRC-16 (CCITT and IBM polynomials), CRC-32, CRC-64 (Normal and Reversed Polynomials), Fletcher-16, Fletcher-32, SpamSum | Some code tweaks made to support older .NET versions, CRC-32 implementation used in `net20`, `net35`, `net40`, and `net452` |
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | SpamSum | Some code tweaks made to support older .NET versions |
| [Blake3.NET](https://github.com/xoofx/Blake3.NET) | BLAKE3 | Used in `net7.0` and above |
| [Compress](https://github.com/RomVault/RVWorld/tree/master/Compress) | N/A | Used for threaded hashing |
| [CRC32](https://gitlab.com/eugene77/CRC32) | CRC-32 (Multiple implementations) | |
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | CRC-32, CRC-64 (Normal Polynomial), xxHash32, xxHash64, XXH3, XXH128 | Used in `net462` and above |
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, RIPEMD160 (.NET Framework only), SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | XXH3, XXH128 | Used in `net462` and above |
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
**Note:** If all you care about is performance, I encourage you to forego this library and use the ones listed above directly instead.
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using Xunit;
@@ -12,14 +13,23 @@ namespace SabreTools.Hashing.Test
private static readonly string _hashFilePath
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin");
#region Known File Information
/// <summary>
/// Get an array of all hash types
/// </summary>
public static List<object[]> AllHashTypes
{
get
{
var values = Enum.GetValues(typeof(HashType));
var set = new List<object[]>();
foreach (var value in values)
{
set.Add([value]);
}
private const long _hashFileSize = 125;
private const string _crc32 = "ba02a660";
private const string _md5 = "b722871eaa950016296184d026c5dec9";
private const string _sha1 = "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f";
#endregion
return set;
}
}
[Fact]
public void GetStandardHashesTest()
@@ -27,24 +37,32 @@ namespace SabreTools.Hashing.Test
bool gotHashes = HashTool.GetStandardHashes(_hashFilePath, out long actualSize, out string? crc32, out string? md5, out string? sha1);
Assert.True(gotHashes);
Assert.Equal(_hashFileSize, actualSize);
Assert.Equal(_crc32, crc32);
Assert.Equal(_md5, md5);
Assert.Equal(_sha1, sha1);
TestHelper.ValidateSize(actualSize);
TestHelper.ValidateHash(HashType.CRC32, crc32);
TestHelper.ValidateHash(HashType.MD5, md5);
TestHelper.ValidateHash(HashType.SHA1, sha1);
}
[Fact]
public void GetFileHashesTest()
public void GetFileHashesParallelTest()
{
var hashDict = HashTool.GetFileHashes(_hashFilePath);
TestHelper.ValidateHashes(hashDict);
}
[Theory]
[MemberData(nameof(AllHashTypes))]
public void GetFileHashesSerialTest(HashType hashType)
{
var hashValue = HashTool.GetFileHash(_hashFilePath, hashType);
TestHelper.ValidateHash(hashType, hashValue);
}
[Fact]
public void GetFileHashesAndSizeTest()
{
var hashDict = HashTool.GetFileHashesAndSize(_hashFilePath, out long actualSize);
Assert.Equal(_hashFileSize, actualSize);
TestHelper.ValidateSize(actualSize);
TestHelper.ValidateHashes(hashDict);
}

View File

@@ -1,44 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;net6.0;net7.0;net8.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>net462;net472;net48;net6.0;net7.0;net8.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
</PropertyGroup>
<ItemGroup>
<None Remove="TestData\*" />
</ItemGroup>
<ItemGroup>
<None Remove="TestData\*" />
</ItemGroup>
<ItemGroup>
<Content Include="TestData\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="TestData\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net462`)) OR $(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -6,44 +6,215 @@ namespace SabreTools.Hashing.Test
/// <summary>
/// Helper class for tests
/// </summary>
/// CRC values confirmed with <see href="https://emn178.github.io/online-tools/crc/"/>
internal static class TestHelper
{
#region Known File Information
private const long _hashFileSize = 125;
private const string _adler32 = "08562d95";
private static readonly Dictionary<HashType, string> _knownHashes = new()
{
{HashType.Adler32, "08562d95"},
#if NET7_0_OR_GREATER
private const string _blake3 = "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc";
{HashType.BLAKE3, "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc"},
#endif
private const string _crc16_ccitt = "482d";
private const string _crc16_ibm = "7573";
private const string _crc32 = "ba02a660";
private const string _crc64 = "a0e0009c18b5338d";
private const string _crc64_reversed = "fb49044e8331f6e5";
private const string _fletcher16 = "46c1";
private const string _fletcher32 = "073f2d94";
private const string _md5 = "b722871eaa950016296184d026c5dec9";
#if NETFRAMEWORK
private const string _ripemd160 = "346361e1d7fdb836650cecdb842b0dbe660eed66";
#endif
private const string _sha1 = "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f";
private const string _sha256 = "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855";
private const string _sha384 = "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074";
private const string _sha512 = "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240";
{HashType.CRC1_ZERO, "0"},
{HashType.CRC1_ONE, "1"},
{HashType.CRC3_GSM, "4"},
{HashType.CRC3_ROHC, "3"},
{HashType.CRC4_G704, "6"},
{HashType.CRC4_INTERLAKEN, "0"},
{HashType.CRC5_EPCC1G2, "1f"},
{HashType.CRC5_G704, "06"},
{HashType.CRC5_USB, "0a"},
{HashType.CRC6_CDMA2000A, "3c"},
{HashType.CRC6_CDMA2000B, "12"},
{HashType.CRC6_DARC, "0f"},
{HashType.CRC6_G704, "09"},
{HashType.CRC6_GSM, "21"},
{HashType.CRC7_MMC, "2f"},
{HashType.CRC7_ROHC, "68"},
{HashType.CRC7_UMTS, "66"},
{HashType.CRC8, "fc"},
{HashType.CRC8_AUTOSAR, "ca"},
{HashType.CRC8_BLUETOOTH, "00"},
{HashType.CRC8_CDMA2000, "2d"},
{HashType.CRC8_DARC, "35"},
{HashType.CRC8_DVBS2, "5c"},
{HashType.CRC8_GSMA, "d8"},
{HashType.CRC8_GSMB, "f3"},
{HashType.CRC8_HITAG, "aa"},
{HashType.CRC8_I4321, "a9"},
{HashType.CRC8_ICODE, "61"},
{HashType.CRC8_LTE, "d7"},
{HashType.CRC8_MAXIMDOW, "bd"},
{HashType.CRC8_MIFAREMAD, "9b"},
{HashType.CRC8_NRSC5, "e2"},
{HashType.CRC8_OPENSAFETY, "fc"},
{HashType.CRC8_ROHC, "17"},
{HashType.CRC8_SAEJ1850, "55"},
{HashType.CRC8_SMBUS, "fc"},
{HashType.CRC8_TECH3250, "7d"},
{HashType.CRC8_WCDMA, "c6"},
{HashType.CRC10_ATM, "26b"},
{HashType.CRC10_CDMA2000, "14f"},
{HashType.CRC10_GSM, "0e7"},
{HashType.CRC11_FLEXRAY, "18b"},
{HashType.CRC11_UMTS, "347"},
{HashType.CRC12_CDMA2000, "f9c"},
{HashType.CRC12_DECT, "d62"},
{HashType.CRC12_GSM, "975"},
{HashType.CRC12_UMTS, "46b"},
{HashType.CRC13_BBC, "074f"},
{HashType.CRC14_DARC, "0add"},
{HashType.CRC14_GSM, "0c7d"},
{HashType.CRC15_CAN, "66c3"},
{HashType.CRC15_MPT1327, "013b"},
{HashType.CRC16, "7573"},
{HashType.CRC16_ARC, "7573"},
{HashType.CRC16_CDMA2000, "8b5f"},
{HashType.CRC16_CMS, "1a37"},
{HashType.CRC16_DDS110, "241d"},
{HashType.CRC16_DECTR, "7390"},
{HashType.CRC16_DECTX, "7391"},
{HashType.CRC16_DNP, "4bbb"},
{HashType.CRC16_EN13757, "e28b"},
{HashType.CRC16_GENIBUS, "b65d"},
{HashType.CRC16_GSM, "482d"},
{HashType.CRC16_IBM3740, "49a2"},
{HashType.CRC16_IBMSDLC, "4f52"},
{HashType.CRC16_ISOIEC144433A, "85cd"},
{HashType.CRC16_KERMIT, "bed2"},
{HashType.CRC16_LJ1200, "3533"},
{HashType.CRC16_M17, "5223"},
{HashType.CRC16_MAXIMDOW, "8a8c"},
{HashType.CRC16_MCRF4XX, "b0ad"},
{HashType.CRC16_MODBUS, "9e54"},
{HashType.CRC16_NRSC5, "4857"},
{HashType.CRC16_OPENSAFETYA, "abcd"},
{HashType.CRC16_OPENSAFETYB, "76f4"},
{HashType.CRC16_PROFIBUS, "3099"},
{HashType.CRC16_RIELLO, "23e0"},
{HashType.CRC16_SPIFUJITSU, "f98b"},
{HashType.CRC16_T10DIF, "2642"},
{HashType.CRC16_TELEDISK, "7e05"},
{HashType.CRC16_TMS37157, "dba0"},
{HashType.CRC16_UMTS, "fee0"},
{HashType.CRC16_USB, "61ab"},
{HashType.CRC16_XMODEM, "b7d2"},
{HashType.CRC17_CANFD, "0706d"},
{HashType.CRC21_CANFD, "117d4b"},
{HashType.CRC24_BLE, "2969f2"},
{HashType.CRC24_FLEXRAYA, "ce9dc7"},
{HashType.CRC24_FLEXRAYB, "0f49d7"},
{HashType.CRC24_INTERLAKEN, "fb4725"},
{HashType.CRC24_LTEA, "675e55"},
{HashType.CRC24_LTEB, "c91203"},
{HashType.CRC24_OPENPGP, "0c6012"},
{HashType.CRC24_OS9, "610e21"},
{HashType.CRC30_CDMA, "2ce682b2"},
{HashType.CRC31_PHILIPS, "247c3cbe"},
{HashType.CRC32, "ba02a660"},
{HashType.CRC32_AIXM, "6174a75a"},
{HashType.CRC32_AUTOSAR, "c050428e"},
{HashType.CRC32_BASE91D, "e741ba25"},
{HashType.CRC32_BZIP2, "18aa4603"},
{HashType.CRC32_CDROMEDC, "b8ced467"},
{HashType.CRC32_CKSUM, "f27b3c27"},
{HashType.CRC32_ISCSI, "544d37db"},
{HashType.CRC32_ISOHDLC, "ba02a660"},
{HashType.CRC32_JAMCRC, "45fd599f"},
{HashType.CRC32_MEF, "d9d98444"},
{HashType.CRC32_MPEG2, "e755b9fc"},
{HashType.CRC32_XFER, "55bdf222"},
{HashType.CRC40_GSM, "c9843306eb"},
{HashType.CRC64, "8d33b5189c00e0a0"},
{HashType.CRC64_ECMA182, "8d33b5189c00e0a0"},
{HashType.CRC64_GOISO, "6c3bf747ccfa1e3b"},
{HashType.CRC64_MS, "799edc0db430d7be"},
{HashType.CRC64_NVME, "9242023bbcf6bbf9"},
{HashType.CRC64_REDIS, "408dab12b9f45dad"},
{HashType.CRC64_WE, "91812be748f941c4"},
{HashType.CRC64_XZ, "fb49044e8331f6e5"},
{HashType.Fletcher16, "46c1"},
{HashType.Fletcher32, "073f2d94"},
{HashType.Fletcher64, "000b073400002d94"},
{HashType.FNV0_32, "33d28b00"},
{HashType.FNV0_64, "778e818addd23280"},
{HashType.FNV1_32, "ac09cbeb"},
{HashType.FNV1_64, "23229308c1f9252b"},
{HashType.FNV1a_32, "9086769b"},
{HashType.FNV1a_64, "399dd1cd965b73db"},
{HashType.MD2, "362e1a6931668e6a9de5c159c52c71b5"},
{HashType.MD4, "61bef59d7a754874fccbd67b4ec2fb10"},
{HashType.MD5, "b722871eaa950016296184d026c5dec9"},
{HashType.RIPEMD128, "6356cc18225245de3ca9afcb4fa22ce6"},
{HashType.RIPEMD160, "346361e1d7fdb836650cecdb842b0dbe660eed66"},
{HashType.RIPEMD256, "c2fe11922529651bc615be3d8a296820b6681ecaed5ce051439c86bf3d942276"},
{HashType.RIPEMD320, "a523bec87b0738f89d8ae5cf0edd3ee9c7b9811f1051e32893e32e820db33841b9d5042e738d20c9"},
{HashType.SHA1, "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f"},
{HashType.SHA256, "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855"},
{HashType.SHA384, "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074"},
{HashType.SHA512, "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240"},
#if NET8_0_OR_GREATER
private const string _sha3_256 = "1d76459e68c865b5911ada5104067cc604c5c60b345c4e81b3905e916a43c868";
private const string _sha3_384 = "1bcbed87b73f25c0adf486c3afbf0ea3105763c387af3f8b2bd79b0a1964d42832b1d7c6a2225f9153ead26f442e8b67";
private const string _sha3_512 = "89852144df37c58d01f5912124f1942dd00bac0346eb3971943416699c3094cff087fb42c356019c3d91f8e8f55b9254c8caec48e9414af6817297d06725ffeb";
private const string _shake128 = "e5f88d0db79a71c39490beb9ebac21eaf4a5d6368438fca20f5e4ce77cfee9aa";
private const string _shake256 = "24d9e83198bbc7baf4dcd293bfc35ae3fff05399786c37318f1b1ef85f41970c66926f8a2a1f912d96e2d8e45535af88a301a1c200697437c1a65d7e980344bc";
{HashType.SHA3_256, "1d76459e68c865b5911ada5104067cc604c5c60b345c4e81b3905e916a43c868"},
{HashType.SHA3_384, "1bcbed87b73f25c0adf486c3afbf0ea3105763c387af3f8b2bd79b0a1964d42832b1d7c6a2225f9153ead26f442e8b67"},
{HashType.SHA3_512, "89852144df37c58d01f5912124f1942dd00bac0346eb3971943416699c3094cff087fb42c356019c3d91f8e8f55b9254c8caec48e9414af6817297d06725ffeb"},
{HashType.SHAKE128, "e5f88d0db79a71c39490beb9ebac21eaf4a5d6368438fca20f5e4ce77cfee9aa"},
{HashType.SHAKE256, "24d9e83198bbc7baf4dcd293bfc35ae3fff05399786c37318f1b1ef85f41970c66926f8a2a1f912d96e2d8e45535af88a301a1c200697437c1a65d7e980344bc"},
#endif
private const string _spamsum = "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL";
{HashType.SpamSum, "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL"},
{HashType.Tiger128_3, "afc7ac1c3c031b675562f917b59f0885"},
{HashType.Tiger128_4, "e7609126923009f733cd0fcbc5a733fa"},
{HashType.Tiger160_3, "afc7ac1c3c031b675562f917b59f088533405e1a"},
{HashType.Tiger160_4, "e7609126923009f733cd0fcbc5a733fa4f4ccf7a"},
{HashType.Tiger192_3, "afc7ac1c3c031b675562f917b59f088533405e1a2f72912d"},
{HashType.Tiger192_4, "e7609126923009f733cd0fcbc5a733fa4f4ccf7ab7c0e2a3"},
{HashType.Tiger2_128_3, "b26271774e66519b1c746f210e0be05c"},
{HashType.Tiger2_128_4, "f1df540d3f2521b87a957c9b2b00fc7c"},
{HashType.Tiger2_160_3, "b26271774e66519b1c746f210e0be05c4fd9efde"},
{HashType.Tiger2_160_4, "f1df540d3f2521b87a957c9b2b00fc7c589306dc"},
{HashType.Tiger2_192_3, "b26271774e66519b1c746f210e0be05c4fd9efde26e46e89"},
{HashType.Tiger2_192_4, "f1df540d3f2521b87a957c9b2b00fc7c589306dcf094acb5"},
{HashType.XxHash32, "aa1d338e"},
{HashType.XxHash64, "181e9ea4f0f62b08"},
#if NET462_OR_GREATER || NETCOREAPP
private const string _xxhash32 = "8e331daa";
private const string _xxhash64 = "082bf6f0a49e1e18";
private const string _xxhash3 = "040474eb0eda9ff2";
private const string _xxhash128 = "d934b4b4a5e1e11baeef8012fbcd11e8";
{HashType.XxHash3, "f29fda0eeb740404"},
{HashType.XxHash128, "e811cdfb1280efae1be1e1a5b4b434d9"},
#endif
};
#endregion
@@ -53,45 +224,22 @@ namespace SabreTools.Hashing.Test
public static void ValidateHashes(Dictionary<HashType, string?>? hashDict)
{
Assert.NotNull(hashDict);
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
#if NET7_0_OR_GREATER
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
#endif
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
Assert.Equal(_md5, hashDict[HashType.MD5]);
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
#if NET8_0_OR_GREATER
if (System.Security.Cryptography.SHA3_256.IsSupported)
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
if (System.Security.Cryptography.SHA3_384.IsSupported)
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
if (System.Security.Cryptography.SHA3_512.IsSupported)
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
if (System.Security.Cryptography.Shake128.IsSupported)
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
if (System.Security.Cryptography.Shake256.IsSupported)
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
#endif
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
#if NET462_OR_GREATER || NETCOREAPP
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
#endif
foreach (var hashType in _knownHashes.Keys)
{
ValidateHash(hashType, hashDict![hashType]);
}
}
/// <summary>
/// Validate a single hash
/// </summary>
public static void ValidateHash(HashType hashType, string? hashValue)
=> Assert.Equal(_knownHashes[hashType], hashValue);
/// <summary>
/// Validate the file size
/// </summary>
public static void ValidateSize(long fileSize)
=> Assert.Equal(_hashFileSize, fileSize);
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace SabreTools.Hashing.Test
{
public class ZeroHashTests
{
/// <summary>
/// Get an array of all hash types
/// </summary>
public static List<object[]> AllHashTypes
{
get
{
var values = Enum.GetValues(typeof(HashType));
var set = new List<object[]>();
foreach (var value in values)
{
set.Add([value]);
}
return set;
}
}
[Theory]
[MemberData(nameof(AllHashTypes))]
public void GetZeroByteHashes(HashType hashType)
{
var expected = ZeroHash.GetBytes(hashType);
var actual = HashTool.GetByteArrayHashArray([], hashType);
Assert.NotNull(actual);
Assert.Equal(expected.Length, actual.Length);
Assert.True(actual.SequenceEqual(expected));
}
[Theory]
[MemberData(nameof(AllHashTypes))]
public void GetZeroStringHashes(HashType hashType)
{
var expected = ZeroHash.GetString(hashType);
var actual = HashTool.GetByteArrayHash([], hashType);
Assert.Equal(expected, actual);
}
}
}

View File

@@ -1,217 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : neon.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// The Chromium Authors
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute Adler32 checksum using NEON vectorization.
//
// --[ License ] --------------------------------------------------------------
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright 2017 The Chromium Authors. All rights reserved.
// ****************************************************************************/
#if NET5_0_OR_GREATER
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
namespace Aaru.Checksums.Adler32;
static class Neon
{
internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len)
{
/*
* Split Adler-32 into component sums.
*/
uint s1 = preSum1;
uint s2 = preSum2;
var bufPos = 0;
/*
* Process the data in blocks.
*/
const uint blockSize = 1 << 5;
uint blocks = len / blockSize;
len -= blocks * blockSize;
while(blocks != 0)
{
uint n = Adler32Context.NMAX / blockSize; /* The NMAX constraint. */
if(n > blocks)
n = blocks;
blocks -= n;
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo ADLER_MODULE.
*/
var vS2 = Vector128.Create(s1 * n, 0, 0, 0);
var vS1 = Vector128.Create(0u, 0, 0, 0);
Vector128<ushort> vColumnSum1 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> vColumnSum2 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> vColumnSum3 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> vColumnSum4 = AdvSimd.DuplicateToVector128((ushort)0);
do
{
/*
* Load 32 input bytes.
*/
var bytes1 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
bufPos += 16;
var bytes2 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
bufPos += 16;
/*
* Add previous block byte sum to v_s2.
*/
vS2 = AdvSimd.Add(vS2, vS1);
/*
* Horizontally add the bytes for s1.
*/
vS1 =
AdvSimd.AddPairwiseWideningAndAdd(vS1,
AdvSimd.
AddPairwiseWideningAndAdd(AdvSimd.AddPairwiseWidening(bytes1),
bytes2));
/*
* Vertically add the bytes for s2.
*/
vColumnSum1 = AdvSimd.AddWideningLower(vColumnSum1, bytes1.GetLower());
vColumnSum2 = AdvSimd.AddWideningLower(vColumnSum2, bytes1.GetUpper());
vColumnSum3 = AdvSimd.AddWideningLower(vColumnSum3, bytes2.GetLower());
vColumnSum4 = AdvSimd.AddWideningLower(vColumnSum4, bytes2.GetUpper());
} while(--n != 0);
vS2 = AdvSimd.ShiftLeftLogical(vS2, 5);
/*
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
*/
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum1.GetLower(),
Vector64.Create((ushort)32, 31, 30, 29));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum1.GetUpper(),
Vector64.Create((ushort)28, 27, 26, 25));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum2.GetLower(),
Vector64.Create((ushort)24, 23, 22, 21));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum2.GetUpper(),
Vector64.Create((ushort)20, 19, 18, 17));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum3.GetLower(),
Vector64.Create((ushort)16, 15, 14, 13));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum3.GetUpper(),
Vector64.Create((ushort)12, 11, 10, 9));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetLower(), Vector64.Create((ushort)8, 7, 6, 5));
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetUpper(), Vector64.Create((ushort)4, 3, 2, 1));
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
Vector64<uint> sum1 = AdvSimd.AddPairwise(vS1.GetLower(), vS1.GetUpper());
Vector64<uint> sum2 = AdvSimd.AddPairwise(vS2.GetLower(), vS2.GetUpper());
Vector64<uint> s1S2 = AdvSimd.AddPairwise(sum1, sum2);
s1 += AdvSimd.Extract(s1S2, 0);
s2 += AdvSimd.Extract(s1S2, 1);
/*
* Reduce.
*/
s1 %= Adler32Context.ADLER_MODULE;
s2 %= Adler32Context.ADLER_MODULE;
}
/*
* Handle leftover data.
*/
if(len != 0)
{
if(len >= 16)
{
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
len -= 16;
}
while(len-- != 0)
s2 += s1 += buf[bufPos++];
if(s1 >= Adler32Context.ADLER_MODULE)
s1 -= Adler32Context.ADLER_MODULE;
s2 %= Adler32Context.ADLER_MODULE;
}
/*
* Return the recombined sums.
*/
preSum1 = (ushort)(s1 & 0xFFFF);
preSum2 = (ushort)(s2 & 0xFFFF);
}
}
#endif

View File

@@ -1,194 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : ssse3.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// The Chromium Authors
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute Adler32 checksum using SSSE3 vectorization.
//
// --[ License ] --------------------------------------------------------------
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright 2017 The Chromium Authors. All rights reserved.
// ****************************************************************************/
#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru.Checksums.Adler32;
static class Ssse3
{
internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len)
{
uint s1 = sum1;
uint s2 = sum2;
var bufPos = 0;
/*
* Process the data in blocks.
*/
const uint blockSize = 1 << 5;
uint blocks = len / blockSize;
len -= blocks * blockSize;
while(blocks != 0)
{
uint n = Adler32Context.NMAX / blockSize; /* The NMAX constraint. */
if(n > blocks)
n = blocks;
blocks -= n;
Vector128<byte> tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17).
AsByte();
Vector128<byte> tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte();
Vector128<byte> zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte();
var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1);
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo BASE.
*/
var vPs = Vector128.Create(s1 * n, 0, 0, 0);
var vS2 = Vector128.Create(s2, 0, 0, 0);
var vS1 = Vector128.Create(0u, 0, 0, 0);
do
{
/*
* Load 32 input bytes.
*/
var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
BitConverter.ToUInt32(buf, bufPos + 4),
BitConverter.ToUInt32(buf, bufPos + 8),
BitConverter.ToUInt32(buf, bufPos + 12));
bufPos += 16;
var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
BitConverter.ToUInt32(buf, bufPos + 4),
BitConverter.ToUInt32(buf, bufPos + 8),
BitConverter.ToUInt32(buf, bufPos + 12));
bufPos += 16;
/*
* Add previous block byte sum to v_ps.
*/
vPs = Sse2.Add(vPs, vS1);
/*
* Horizontally add the bytes for s1, multiply-adds the
* bytes by [ 32, 31, 30, ... ] for s2.
*/
vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32());
Vector128<short> mad1 =
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte());
vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32());
vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32());
Vector128<short> mad2 =
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte());
vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32());
} while(--n != 0);
vS2 = Sse2.Add(vS2, Sse2.ShiftLeftLogical(vPs, 5));
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 177));
vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 78));
s1 += (uint)Sse2.ConvertToInt32(vS1.AsInt32());
vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 177));
vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 78));
s2 = (uint)Sse2.ConvertToInt32(vS2.AsInt32());
/*
* Reduce.
*/
s1 %= Adler32Context.ADLER_MODULE;
s2 %= Adler32Context.ADLER_MODULE;
}
/*
* Handle leftover data.
*/
if(len != 0)
{
if(len >= 16)
{
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
len -= 16;
}
while(len-- != 0)
s2 += s1 += buf[bufPos++];
if(s1 >= Adler32Context.ADLER_MODULE)
s1 -= Adler32Context.ADLER_MODULE;
s2 %= Adler32Context.ADLER_MODULE;
}
/*
* Return the recombined sums.
*/
sum1 = (ushort)(s1 & 0xFFFF);
sum2 = (ushort)(s2 & 0xFFFF);
}
}
#endif

View File

@@ -1,434 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Adler32Context.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements an Adler-32 algorithm.
//
// --[ License ] --------------------------------------------------------------
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright (C) 1995-2011 Mark Adler
// Copyright (C) Jean-loup Gailly
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
#if NET5_0_OR_GREATER
using System.Runtime.Intrinsics.Arm;
#endif
using System.Text;
#if NETCOREAPP3_1_OR_GREATER
using Aaru.Checksums.Adler32;
#endif
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
#if NETCOREAPP3_1_OR_GREATER
using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3;
#endif
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements the Adler-32 algorithm</summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
public sealed class Adler32Context : IChecksum
{
internal const ushort ADLER_MODULE = 65521;
internal const uint NMAX = 5552;
readonly IntPtr _nativeContext;
readonly bool _useNative;
ushort _sum1, _sum2;
/// <summary>Initializes the Adler-32 sums</summary>
public Adler32Context()
{
_sum1 = 1;
_sum2 = 0;
if(!Native.IsSupported)
return;
_nativeContext = adler32_init();
_useNative = _nativeContext != IntPtr.Zero;
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "Adler-32";
/// <inheritdoc />
public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
var finalSum = (uint)(_sum2 << 16 | _sum1);
if(!_useNative)
return BigEndianBitConverter.GetBytes(finalSum);
adler32_final(_nativeContext, ref finalSum);
adler32_free(_nativeContext);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var finalSum = (uint)(_sum2 << 16 | _sum1);
if(_useNative)
{
adler32_final(_nativeContext, ref finalSum);
adler32_free(_nativeContext);
}
var adlerOutput = new StringBuilder();
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return adlerOutput.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr adler32_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int adler32_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int adler32_final(IntPtr ctx, ref uint checksum);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void adler32_free(IntPtr ctx);
static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len, bool useNative,
IntPtr nativeContext)
{
if(useNative)
{
adler32_update(nativeContext, data, len);
return;
}
#if NETCOREAPP3_1_OR_GREATER
if(Ssse3.IsSupported)
{
Adler32.Ssse3.Step(ref preSum1, ref preSum2, data, len);
return;
}
#endif
#if NET5_0_OR_GREATER
if(AdvSimd.IsSupported)
{
Neon.Step(ref preSum1, ref preSum2, data, len);
return;
}
#endif
uint sum1 = preSum1;
uint sum2 = preSum2;
var dataOff = 0;
switch(len)
{
/* in case user likes doing a byte at a time, keep it fast */
case 1:
{
sum1 += data[dataOff];
if(sum1 >= ADLER_MODULE)
sum1 -= ADLER_MODULE;
sum2 += sum1;
if(sum2 >= ADLER_MODULE)
sum2 -= ADLER_MODULE;
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
/* in case short lengths are provided, keep it somewhat fast */
case < 16:
{
while(len-- > 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
if(sum1 >= ADLER_MODULE)
sum1 -= ADLER_MODULE;
sum2 %= ADLER_MODULE; /* only added so many ADLER_MODULE's */
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
}
/* do length NMAX blocks -- requires just one modulo operation */
while(len >= NMAX)
{
len -= NMAX;
uint n = NMAX / 16;
do
{
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2 + 1];
sum2 += sum1;
/* 16 sums unrolled */
dataOff += 16;
} while(--n != 0);
sum1 %= ADLER_MODULE;
sum2 %= ADLER_MODULE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if(len != 0)
{
/* avoid modulos if none remaining */
while(len >= 16)
{
len -= 16;
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2 + 1];
sum2 += sum1;
dataOff += 16;
}
while(len-- != 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
sum1 %= ADLER_MODULE;
sum2 %= ADLER_MODULE;
}
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = adler32_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
var fileStream = new FileStream(filename, FileMode.Open);
ushort localSum1 = 1;
ushort localSum2 = 0;
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.EnsureRead(buffer, 0, 65536);
}
var finalSum = (uint)(localSum2 << 16 | localSum1);
if(useNative)
{
adler32_final(nativeContext, ref finalSum);
adler32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
foreach(byte h in hash)
adlerOutput.Append(h.ToString("x2"));
fileStream.Close();
return adlerOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = adler32_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
ushort localSum1 = 1;
ushort localSum2 = 0;
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
var finalSum = (uint)(localSum2 << 16 | localSum1);
if(useNative)
{
adler32_final(nativeContext, ref finalSum);
adler32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
foreach(byte h in hash)
adlerOutput.Append(h.ToString("x2"));
return adlerOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -1,274 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : CRC16CCITTContext.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements a CRC16 algorithm with the CCITT polynomial.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements the CRC16 algorithm with CCITT polynomial and seed</summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
public sealed class CRC16CcittContext : Crc16Context
{
/// <summary>CCITT CRC16 polynomial</summary>
public const ushort CRC16_CCITT_POLY = 0x8408;
/// <summary>CCITT CRC16 seed</summary>
public const ushort CRC16_CCITT_SEED = 0x0000;
static readonly ushort[][] _ccittCrc16Table =
{
new ushort[]
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C,
0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318,
0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4,
0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630,
0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4,
0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969,
0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF,
0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9,
0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046,
0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2,
0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2,
0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E,
0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E,
0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1,
0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9,
0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
},
new ushort[]
{
0x0000, 0x3331, 0x6662, 0x5553, 0xCCC4, 0xFFF5, 0xAAA6, 0x9997, 0x89A9, 0xBA98, 0xEFCB, 0xDCFA, 0x456D,
0x765C, 0x230F, 0x103E, 0x0373, 0x3042, 0x6511, 0x5620, 0xCFB7, 0xFC86, 0xA9D5, 0x9AE4, 0x8ADA, 0xB9EB,
0xECB8, 0xDF89, 0x461E, 0x752F, 0x207C, 0x134D, 0x06E6, 0x35D7, 0x6084, 0x53B5, 0xCA22, 0xF913, 0xAC40,
0x9F71, 0x8F4F, 0xBC7E, 0xE92D, 0xDA1C, 0x438B, 0x70BA, 0x25E9, 0x16D8, 0x0595, 0x36A4, 0x63F7, 0x50C6,
0xC951, 0xFA60, 0xAF33, 0x9C02, 0x8C3C, 0xBF0D, 0xEA5E, 0xD96F, 0x40F8, 0x73C9, 0x269A, 0x15AB, 0x0DCC,
0x3EFD, 0x6BAE, 0x589F, 0xC108, 0xF239, 0xA76A, 0x945B, 0x8465, 0xB754, 0xE207, 0xD136, 0x48A1, 0x7B90,
0x2EC3, 0x1DF2, 0x0EBF, 0x3D8E, 0x68DD, 0x5BEC, 0xC27B, 0xF14A, 0xA419, 0x9728, 0x8716, 0xB427, 0xE174,
0xD245, 0x4BD2, 0x78E3, 0x2DB0, 0x1E81, 0x0B2A, 0x381B, 0x6D48, 0x5E79, 0xC7EE, 0xF4DF, 0xA18C, 0x92BD,
0x8283, 0xB1B2, 0xE4E1, 0xD7D0, 0x4E47, 0x7D76, 0x2825, 0x1B14, 0x0859, 0x3B68, 0x6E3B, 0x5D0A, 0xC49D,
0xF7AC, 0xA2FF, 0x91CE, 0x81F0, 0xB2C1, 0xE792, 0xD4A3, 0x4D34, 0x7E05, 0x2B56, 0x1867, 0x1B98, 0x28A9,
0x7DFA, 0x4ECB, 0xD75C, 0xE46D, 0xB13E, 0x820F, 0x9231, 0xA100, 0xF453, 0xC762, 0x5EF5, 0x6DC4, 0x3897,
0x0BA6, 0x18EB, 0x2BDA, 0x7E89, 0x4DB8, 0xD42F, 0xE71E, 0xB24D, 0x817C, 0x9142, 0xA273, 0xF720, 0xC411,
0x5D86, 0x6EB7, 0x3BE4, 0x08D5, 0x1D7E, 0x2E4F, 0x7B1C, 0x482D, 0xD1BA, 0xE28B, 0xB7D8, 0x84E9, 0x94D7,
0xA7E6, 0xF2B5, 0xC184, 0x5813, 0x6B22, 0x3E71, 0x0D40, 0x1E0D, 0x2D3C, 0x786F, 0x4B5E, 0xD2C9, 0xE1F8,
0xB4AB, 0x879A, 0x97A4, 0xA495, 0xF1C6, 0xC2F7, 0x5B60, 0x6851, 0x3D02, 0x0E33, 0x1654, 0x2565, 0x7036,
0x4307, 0xDA90, 0xE9A1, 0xBCF2, 0x8FC3, 0x9FFD, 0xACCC, 0xF99F, 0xCAAE, 0x5339, 0x6008, 0x355B, 0x066A,
0x1527, 0x2616, 0x7345, 0x4074, 0xD9E3, 0xEAD2, 0xBF81, 0x8CB0, 0x9C8E, 0xAFBF, 0xFAEC, 0xC9DD, 0x504A,
0x637B, 0x3628, 0x0519, 0x10B2, 0x2383, 0x76D0, 0x45E1, 0xDC76, 0xEF47, 0xBA14, 0x8925, 0x991B, 0xAA2A,
0xFF79, 0xCC48, 0x55DF, 0x66EE, 0x33BD, 0x008C, 0x13C1, 0x20F0, 0x75A3, 0x4692, 0xDF05, 0xEC34, 0xB967,
0x8A56, 0x9A68, 0xA959, 0xFC0A, 0xCF3B, 0x56AC, 0x659D, 0x30CE, 0x03FF
},
new ushort[]
{
0x0000, 0x3730, 0x6E60, 0x5950, 0xDCC0, 0xEBF0, 0xB2A0, 0x8590, 0xA9A1, 0x9E91, 0xC7C1, 0xF0F1, 0x7561,
0x4251, 0x1B01, 0x2C31, 0x4363, 0x7453, 0x2D03, 0x1A33, 0x9FA3, 0xA893, 0xF1C3, 0xC6F3, 0xEAC2, 0xDDF2,
0x84A2, 0xB392, 0x3602, 0x0132, 0x5862, 0x6F52, 0x86C6, 0xB1F6, 0xE8A6, 0xDF96, 0x5A06, 0x6D36, 0x3466,
0x0356, 0x2F67, 0x1857, 0x4107, 0x7637, 0xF3A7, 0xC497, 0x9DC7, 0xAAF7, 0xC5A5, 0xF295, 0xABC5, 0x9CF5,
0x1965, 0x2E55, 0x7705, 0x4035, 0x6C04, 0x5B34, 0x0264, 0x3554, 0xB0C4, 0x87F4, 0xDEA4, 0xE994, 0x1DAD,
0x2A9D, 0x73CD, 0x44FD, 0xC16D, 0xF65D, 0xAF0D, 0x983D, 0xB40C, 0x833C, 0xDA6C, 0xED5C, 0x68CC, 0x5FFC,
0x06AC, 0x319C, 0x5ECE, 0x69FE, 0x30AE, 0x079E, 0x820E, 0xB53E, 0xEC6E, 0xDB5E, 0xF76F, 0xC05F, 0x990F,
0xAE3F, 0x2BAF, 0x1C9F, 0x45CF, 0x72FF, 0x9B6B, 0xAC5B, 0xF50B, 0xC23B, 0x47AB, 0x709B, 0x29CB, 0x1EFB,
0x32CA, 0x05FA, 0x5CAA, 0x6B9A, 0xEE0A, 0xD93A, 0x806A, 0xB75A, 0xD808, 0xEF38, 0xB668, 0x8158, 0x04C8,
0x33F8, 0x6AA8, 0x5D98, 0x71A9, 0x4699, 0x1FC9, 0x28F9, 0xAD69, 0x9A59, 0xC309, 0xF439, 0x3B5A, 0x0C6A,
0x553A, 0x620A, 0xE79A, 0xD0AA, 0x89FA, 0xBECA, 0x92FB, 0xA5CB, 0xFC9B, 0xCBAB, 0x4E3B, 0x790B, 0x205B,
0x176B, 0x7839, 0x4F09, 0x1659, 0x2169, 0xA4F9, 0x93C9, 0xCA99, 0xFDA9, 0xD198, 0xE6A8, 0xBFF8, 0x88C8,
0x0D58, 0x3A68, 0x6338, 0x5408, 0xBD9C, 0x8AAC, 0xD3FC, 0xE4CC, 0x615C, 0x566C, 0x0F3C, 0x380C, 0x143D,
0x230D, 0x7A5D, 0x4D6D, 0xC8FD, 0xFFCD, 0xA69D, 0x91AD, 0xFEFF, 0xC9CF, 0x909F, 0xA7AF, 0x223F, 0x150F,
0x4C5F, 0x7B6F, 0x575E, 0x606E, 0x393E, 0x0E0E, 0x8B9E, 0xBCAE, 0xE5FE, 0xD2CE, 0x26F7, 0x11C7, 0x4897,
0x7FA7, 0xFA37, 0xCD07, 0x9457, 0xA367, 0x8F56, 0xB866, 0xE136, 0xD606, 0x5396, 0x64A6, 0x3DF6, 0x0AC6,
0x6594, 0x52A4, 0x0BF4, 0x3CC4, 0xB954, 0x8E64, 0xD734, 0xE004, 0xCC35, 0xFB05, 0xA255, 0x9565, 0x10F5,
0x27C5, 0x7E95, 0x49A5, 0xA031, 0x9701, 0xCE51, 0xF961, 0x7CF1, 0x4BC1, 0x1291, 0x25A1, 0x0990, 0x3EA0,
0x67F0, 0x50C0, 0xD550, 0xE260, 0xBB30, 0x8C00, 0xE352, 0xD462, 0x8D32, 0xBA02, 0x3F92, 0x08A2, 0x51F2,
0x66C2, 0x4AF3, 0x7DC3, 0x2493, 0x13A3, 0x9633, 0xA103, 0xF853, 0xCF63
},
new ushort[]
{
0x0000, 0x76B4, 0xED68, 0x9BDC, 0xCAF1, 0xBC45, 0x2799, 0x512D, 0x85C3, 0xF377, 0x68AB, 0x1E1F, 0x4F32,
0x3986, 0xA25A, 0xD4EE, 0x1BA7, 0x6D13, 0xF6CF, 0x807B, 0xD156, 0xA7E2, 0x3C3E, 0x4A8A, 0x9E64, 0xE8D0,
0x730C, 0x05B8, 0x5495, 0x2221, 0xB9FD, 0xCF49, 0x374E, 0x41FA, 0xDA26, 0xAC92, 0xFDBF, 0x8B0B, 0x10D7,
0x6663, 0xB28D, 0xC439, 0x5FE5, 0x2951, 0x787C, 0x0EC8, 0x9514, 0xE3A0, 0x2CE9, 0x5A5D, 0xC181, 0xB735,
0xE618, 0x90AC, 0x0B70, 0x7DC4, 0xA92A, 0xDF9E, 0x4442, 0x32F6, 0x63DB, 0x156F, 0x8EB3, 0xF807, 0x6E9C,
0x1828, 0x83F4, 0xF540, 0xA46D, 0xD2D9, 0x4905, 0x3FB1, 0xEB5F, 0x9DEB, 0x0637, 0x7083, 0x21AE, 0x571A,
0xCCC6, 0xBA72, 0x753B, 0x038F, 0x9853, 0xEEE7, 0xBFCA, 0xC97E, 0x52A2, 0x2416, 0xF0F8, 0x864C, 0x1D90,
0x6B24, 0x3A09, 0x4CBD, 0xD761, 0xA1D5, 0x59D2, 0x2F66, 0xB4BA, 0xC20E, 0x9323, 0xE597, 0x7E4B, 0x08FF,
0xDC11, 0xAAA5, 0x3179, 0x47CD, 0x16E0, 0x6054, 0xFB88, 0x8D3C, 0x4275, 0x34C1, 0xAF1D, 0xD9A9, 0x8884,
0xFE30, 0x65EC, 0x1358, 0xC7B6, 0xB102, 0x2ADE, 0x5C6A, 0x0D47, 0x7BF3, 0xE02F, 0x969B, 0xDD38, 0xAB8C,
0x3050, 0x46E4, 0x17C9, 0x617D, 0xFAA1, 0x8C15, 0x58FB, 0x2E4F, 0xB593, 0xC327, 0x920A, 0xE4BE, 0x7F62,
0x09D6, 0xC69F, 0xB02B, 0x2BF7, 0x5D43, 0x0C6E, 0x7ADA, 0xE106, 0x97B2, 0x435C, 0x35E8, 0xAE34, 0xD880,
0x89AD, 0xFF19, 0x64C5, 0x1271, 0xEA76, 0x9CC2, 0x071E, 0x71AA, 0x2087, 0x5633, 0xCDEF, 0xBB5B, 0x6FB5,
0x1901, 0x82DD, 0xF469, 0xA544, 0xD3F0, 0x482C, 0x3E98, 0xF1D1, 0x8765, 0x1CB9, 0x6A0D, 0x3B20, 0x4D94,
0xD648, 0xA0FC, 0x7412, 0x02A6, 0x997A, 0xEFCE, 0xBEE3, 0xC857, 0x538B, 0x253F, 0xB3A4, 0xC510, 0x5ECC,
0x2878, 0x7955, 0x0FE1, 0x943D, 0xE289, 0x3667, 0x40D3, 0xDB0F, 0xADBB, 0xFC96, 0x8A22, 0x11FE, 0x674A,
0xA803, 0xDEB7, 0x456B, 0x33DF, 0x62F2, 0x1446, 0x8F9A, 0xF92E, 0x2DC0, 0x5B74, 0xC0A8, 0xB61C, 0xE731,
0x9185, 0x0A59, 0x7CED, 0x84EA, 0xF25E, 0x6982, 0x1F36, 0x4E1B, 0x38AF, 0xA373, 0xD5C7, 0x0129, 0x779D,
0xEC41, 0x9AF5, 0xCBD8, 0xBD6C, 0x26B0, 0x5004, 0x9F4D, 0xE9F9, 0x7225, 0x0491, 0x55BC, 0x2308, 0xB8D4,
0xCE60, 0x1A8E, 0x6C3A, 0xF7E6, 0x8152, 0xD07F, 0xA6CB, 0x3D17, 0x4BA3
},
new ushort[]
{
0x0000, 0xAA51, 0x4483, 0xEED2, 0x8906, 0x2357, 0xCD85, 0x67D4, 0x022D, 0xA87C, 0x46AE, 0xECFF, 0x8B2B,
0x217A, 0xCFA8, 0x65F9, 0x045A, 0xAE0B, 0x40D9, 0xEA88, 0x8D5C, 0x270D, 0xC9DF, 0x638E, 0x0677, 0xAC26,
0x42F4, 0xE8A5, 0x8F71, 0x2520, 0xCBF2, 0x61A3, 0x08B4, 0xA2E5, 0x4C37, 0xE666, 0x81B2, 0x2BE3, 0xC531,
0x6F60, 0x0A99, 0xA0C8, 0x4E1A, 0xE44B, 0x839F, 0x29CE, 0xC71C, 0x6D4D, 0x0CEE, 0xA6BF, 0x486D, 0xE23C,
0x85E8, 0x2FB9, 0xC16B, 0x6B3A, 0x0EC3, 0xA492, 0x4A40, 0xE011, 0x87C5, 0x2D94, 0xC346, 0x6917, 0x1168,
0xBB39, 0x55EB, 0xFFBA, 0x986E, 0x323F, 0xDCED, 0x76BC, 0x1345, 0xB914, 0x57C6, 0xFD97, 0x9A43, 0x3012,
0xDEC0, 0x7491, 0x1532, 0xBF63, 0x51B1, 0xFBE0, 0x9C34, 0x3665, 0xD8B7, 0x72E6, 0x171F, 0xBD4E, 0x539C,
0xF9CD, 0x9E19, 0x3448, 0xDA9A, 0x70CB, 0x19DC, 0xB38D, 0x5D5F, 0xF70E, 0x90DA, 0x3A8B, 0xD459, 0x7E08,
0x1BF1, 0xB1A0, 0x5F72, 0xF523, 0x92F7, 0x38A6, 0xD674, 0x7C25, 0x1D86, 0xB7D7, 0x5905, 0xF354, 0x9480,
0x3ED1, 0xD003, 0x7A52, 0x1FAB, 0xB5FA, 0x5B28, 0xF179, 0x96AD, 0x3CFC, 0xD22E, 0x787F, 0x22D0, 0x8881,
0x6653, 0xCC02, 0xABD6, 0x0187, 0xEF55, 0x4504, 0x20FD, 0x8AAC, 0x647E, 0xCE2F, 0xA9FB, 0x03AA, 0xED78,
0x4729, 0x268A, 0x8CDB, 0x6209, 0xC858, 0xAF8C, 0x05DD, 0xEB0F, 0x415E, 0x24A7, 0x8EF6, 0x6024, 0xCA75,
0xADA1, 0x07F0, 0xE922, 0x4373, 0x2A64, 0x8035, 0x6EE7, 0xC4B6, 0xA362, 0x0933, 0xE7E1, 0x4DB0, 0x2849,
0x8218, 0x6CCA, 0xC69B, 0xA14F, 0x0B1E, 0xE5CC, 0x4F9D, 0x2E3E, 0x846F, 0x6ABD, 0xC0EC, 0xA738, 0x0D69,
0xE3BB, 0x49EA, 0x2C13, 0x8642, 0x6890, 0xC2C1, 0xA515, 0x0F44, 0xE196, 0x4BC7, 0x33B8, 0x99E9, 0x773B,
0xDD6A, 0xBABE, 0x10EF, 0xFE3D, 0x546C, 0x3195, 0x9BC4, 0x7516, 0xDF47, 0xB893, 0x12C2, 0xFC10, 0x5641,
0x37E2, 0x9DB3, 0x7361, 0xD930, 0xBEE4, 0x14B5, 0xFA67, 0x5036, 0x35CF, 0x9F9E, 0x714C, 0xDB1D, 0xBCC9,
0x1698, 0xF84A, 0x521B, 0x3B0C, 0x915D, 0x7F8F, 0xD5DE, 0xB20A, 0x185B, 0xF689, 0x5CD8, 0x3921, 0x9370,
0x7DA2, 0xD7F3, 0xB027, 0x1A76, 0xF4A4, 0x5EF5, 0x3F56, 0x9507, 0x7BD5, 0xD184, 0xB650, 0x1C01, 0xF2D3,
0x5882, 0x3D7B, 0x972A, 0x79F8, 0xD3A9, 0xB47D, 0x1E2C, 0xF0FE, 0x5AAF
},
new ushort[]
{
0x0000, 0x45A0, 0x8B40, 0xCEE0, 0x06A1, 0x4301, 0x8DE1, 0xC841, 0x0D42, 0x48E2, 0x8602, 0xC3A2, 0x0BE3,
0x4E43, 0x80A3, 0xC503, 0x1A84, 0x5F24, 0x91C4, 0xD464, 0x1C25, 0x5985, 0x9765, 0xD2C5, 0x17C6, 0x5266,
0x9C86, 0xD926, 0x1167, 0x54C7, 0x9A27, 0xDF87, 0x3508, 0x70A8, 0xBE48, 0xFBE8, 0x33A9, 0x7609, 0xB8E9,
0xFD49, 0x384A, 0x7DEA, 0xB30A, 0xF6AA, 0x3EEB, 0x7B4B, 0xB5AB, 0xF00B, 0x2F8C, 0x6A2C, 0xA4CC, 0xE16C,
0x292D, 0x6C8D, 0xA26D, 0xE7CD, 0x22CE, 0x676E, 0xA98E, 0xEC2E, 0x246F, 0x61CF, 0xAF2F, 0xEA8F, 0x6A10,
0x2FB0, 0xE150, 0xA4F0, 0x6CB1, 0x2911, 0xE7F1, 0xA251, 0x6752, 0x22F2, 0xEC12, 0xA9B2, 0x61F3, 0x2453,
0xEAB3, 0xAF13, 0x7094, 0x3534, 0xFBD4, 0xBE74, 0x7635, 0x3395, 0xFD75, 0xB8D5, 0x7DD6, 0x3876, 0xF696,
0xB336, 0x7B77, 0x3ED7, 0xF037, 0xB597, 0x5F18, 0x1AB8, 0xD458, 0x91F8, 0x59B9, 0x1C19, 0xD2F9, 0x9759,
0x525A, 0x17FA, 0xD91A, 0x9CBA, 0x54FB, 0x115B, 0xDFBB, 0x9A1B, 0x459C, 0x003C, 0xCEDC, 0x8B7C, 0x433D,
0x069D, 0xC87D, 0x8DDD, 0x48DE, 0x0D7E, 0xC39E, 0x863E, 0x4E7F, 0x0BDF, 0xC53F, 0x809F, 0xD420, 0x9180,
0x5F60, 0x1AC0, 0xD281, 0x9721, 0x59C1, 0x1C61, 0xD962, 0x9CC2, 0x5222, 0x1782, 0xDFC3, 0x9A63, 0x5483,
0x1123, 0xCEA4, 0x8B04, 0x45E4, 0x0044, 0xC805, 0x8DA5, 0x4345, 0x06E5, 0xC3E6, 0x8646, 0x48A6, 0x0D06,
0xC547, 0x80E7, 0x4E07, 0x0BA7, 0xE128, 0xA488, 0x6A68, 0x2FC8, 0xE789, 0xA229, 0x6CC9, 0x2969, 0xEC6A,
0xA9CA, 0x672A, 0x228A, 0xEACB, 0xAF6B, 0x618B, 0x242B, 0xFBAC, 0xBE0C, 0x70EC, 0x354C, 0xFD0D, 0xB8AD,
0x764D, 0x33ED, 0xF6EE, 0xB34E, 0x7DAE, 0x380E, 0xF04F, 0xB5EF, 0x7B0F, 0x3EAF, 0xBE30, 0xFB90, 0x3570,
0x70D0, 0xB891, 0xFD31, 0x33D1, 0x7671, 0xB372, 0xF6D2, 0x3832, 0x7D92, 0xB5D3, 0xF073, 0x3E93, 0x7B33,
0xA4B4, 0xE114, 0x2FF4, 0x6A54, 0xA215, 0xE7B5, 0x2955, 0x6CF5, 0xA9F6, 0xEC56, 0x22B6, 0x6716, 0xAF57,
0xEAF7, 0x2417, 0x61B7, 0x8B38, 0xCE98, 0x0078, 0x45D8, 0x8D99, 0xC839, 0x06D9, 0x4379, 0x867A, 0xC3DA,
0x0D3A, 0x489A, 0x80DB, 0xC57B, 0x0B9B, 0x4E3B, 0x91BC, 0xD41C, 0x1AFC, 0x5F5C, 0x971D, 0xD2BD, 0x1C5D,
0x59FD, 0x9CFE, 0xD95E, 0x17BE, 0x521E, 0x9A5F, 0xDFFF, 0x111F, 0x54BF
},
new ushort[]
{
0x0000, 0xB861, 0x60E3, 0xD882, 0xC1C6, 0x79A7, 0xA125, 0x1944, 0x93AD, 0x2BCC, 0xF34E, 0x4B2F, 0x526B,
0xEA0A, 0x3288, 0x8AE9, 0x377B, 0x8F1A, 0x5798, 0xEFF9, 0xF6BD, 0x4EDC, 0x965E, 0x2E3F, 0xA4D6, 0x1CB7,
0xC435, 0x7C54, 0x6510, 0xDD71, 0x05F3, 0xBD92, 0x6EF6, 0xD697, 0x0E15, 0xB674, 0xAF30, 0x1751, 0xCFD3,
0x77B2, 0xFD5B, 0x453A, 0x9DB8, 0x25D9, 0x3C9D, 0x84FC, 0x5C7E, 0xE41F, 0x598D, 0xE1EC, 0x396E, 0x810F,
0x984B, 0x202A, 0xF8A8, 0x40C9, 0xCA20, 0x7241, 0xAAC3, 0x12A2, 0x0BE6, 0xB387, 0x6B05, 0xD364, 0xDDEC,
0x658D, 0xBD0F, 0x056E, 0x1C2A, 0xA44B, 0x7CC9, 0xC4A8, 0x4E41, 0xF620, 0x2EA2, 0x96C3, 0x8F87, 0x37E6,
0xEF64, 0x5705, 0xEA97, 0x52F6, 0x8A74, 0x3215, 0x2B51, 0x9330, 0x4BB2, 0xF3D3, 0x793A, 0xC15B, 0x19D9,
0xA1B8, 0xB8FC, 0x009D, 0xD81F, 0x607E, 0xB31A, 0x0B7B, 0xD3F9, 0x6B98, 0x72DC, 0xCABD, 0x123F, 0xAA5E,
0x20B7, 0x98D6, 0x4054, 0xF835, 0xE171, 0x5910, 0x8192, 0x39F3, 0x8461, 0x3C00, 0xE482, 0x5CE3, 0x45A7,
0xFDC6, 0x2544, 0x9D25, 0x17CC, 0xAFAD, 0x772F, 0xCF4E, 0xD60A, 0x6E6B, 0xB6E9, 0x0E88, 0xABF9, 0x1398,
0xCB1A, 0x737B, 0x6A3F, 0xD25E, 0x0ADC, 0xB2BD, 0x3854, 0x8035, 0x58B7, 0xE0D6, 0xF992, 0x41F3, 0x9971,
0x2110, 0x9C82, 0x24E3, 0xFC61, 0x4400, 0x5D44, 0xE525, 0x3DA7, 0x85C6, 0x0F2F, 0xB74E, 0x6FCC, 0xD7AD,
0xCEE9, 0x7688, 0xAE0A, 0x166B, 0xC50F, 0x7D6E, 0xA5EC, 0x1D8D, 0x04C9, 0xBCA8, 0x642A, 0xDC4B, 0x56A2,
0xEEC3, 0x3641, 0x8E20, 0x9764, 0x2F05, 0xF787, 0x4FE6, 0xF274, 0x4A15, 0x9297, 0x2AF6, 0x33B2, 0x8BD3,
0x5351, 0xEB30, 0x61D9, 0xD9B8, 0x013A, 0xB95B, 0xA01F, 0x187E, 0xC0FC, 0x789D, 0x7615, 0xCE74, 0x16F6,
0xAE97, 0xB7D3, 0x0FB2, 0xD730, 0x6F51, 0xE5B8, 0x5DD9, 0x855B, 0x3D3A, 0x247E, 0x9C1F, 0x449D, 0xFCFC,
0x416E, 0xF90F, 0x218D, 0x99EC, 0x80A8, 0x38C9, 0xE04B, 0x582A, 0xD2C3, 0x6AA2, 0xB220, 0x0A41, 0x1305,
0xAB64, 0x73E6, 0xCB87, 0x18E3, 0xA082, 0x7800, 0xC061, 0xD925, 0x6144, 0xB9C6, 0x01A7, 0x8B4E, 0x332F,
0xEBAD, 0x53CC, 0x4A88, 0xF2E9, 0x2A6B, 0x920A, 0x2F98, 0x97F9, 0x4F7B, 0xF71A, 0xEE5E, 0x563F, 0x8EBD,
0x36DC, 0xBC35, 0x0454, 0xDCD6, 0x64B7, 0x7DF3, 0xC592, 0x1D10, 0xA571
},
new ushort[]
{
0x0000, 0x47D3, 0x8FA6, 0xC875, 0x0F6D, 0x48BE, 0x80CB, 0xC718, 0x1EDA, 0x5909, 0x917C, 0xD6AF, 0x11B7,
0x5664, 0x9E11, 0xD9C2, 0x3DB4, 0x7A67, 0xB212, 0xF5C1, 0x32D9, 0x750A, 0xBD7F, 0xFAAC, 0x236E, 0x64BD,
0xACC8, 0xEB1B, 0x2C03, 0x6BD0, 0xA3A5, 0xE476, 0x7B68, 0x3CBB, 0xF4CE, 0xB31D, 0x7405, 0x33D6, 0xFBA3,
0xBC70, 0x65B2, 0x2261, 0xEA14, 0xADC7, 0x6ADF, 0x2D0C, 0xE579, 0xA2AA, 0x46DC, 0x010F, 0xC97A, 0x8EA9,
0x49B1, 0x0E62, 0xC617, 0x81C4, 0x5806, 0x1FD5, 0xD7A0, 0x9073, 0x576B, 0x10B8, 0xD8CD, 0x9F1E, 0xF6D0,
0xB103, 0x7976, 0x3EA5, 0xF9BD, 0xBE6E, 0x761B, 0x31C8, 0xE80A, 0xAFD9, 0x67AC, 0x207F, 0xE767, 0xA0B4,
0x68C1, 0x2F12, 0xCB64, 0x8CB7, 0x44C2, 0x0311, 0xC409, 0x83DA, 0x4BAF, 0x0C7C, 0xD5BE, 0x926D, 0x5A18,
0x1DCB, 0xDAD3, 0x9D00, 0x5575, 0x12A6, 0x8DB8, 0xCA6B, 0x021E, 0x45CD, 0x82D5, 0xC506, 0x0D73, 0x4AA0,
0x9362, 0xD4B1, 0x1CC4, 0x5B17, 0x9C0F, 0xDBDC, 0x13A9, 0x547A, 0xB00C, 0xF7DF, 0x3FAA, 0x7879, 0xBF61,
0xF8B2, 0x30C7, 0x7714, 0xAED6, 0xE905, 0x2170, 0x66A3, 0xA1BB, 0xE668, 0x2E1D, 0x69CE, 0xFD81, 0xBA52,
0x7227, 0x35F4, 0xF2EC, 0xB53F, 0x7D4A, 0x3A99, 0xE35B, 0xA488, 0x6CFD, 0x2B2E, 0xEC36, 0xABE5, 0x6390,
0x2443, 0xC035, 0x87E6, 0x4F93, 0x0840, 0xCF58, 0x888B, 0x40FE, 0x072D, 0xDEEF, 0x993C, 0x5149, 0x169A,
0xD182, 0x9651, 0x5E24, 0x19F7, 0x86E9, 0xC13A, 0x094F, 0x4E9C, 0x8984, 0xCE57, 0x0622, 0x41F1, 0x9833,
0xDFE0, 0x1795, 0x5046, 0x975E, 0xD08D, 0x18F8, 0x5F2B, 0xBB5D, 0xFC8E, 0x34FB, 0x7328, 0xB430, 0xF3E3,
0x3B96, 0x7C45, 0xA587, 0xE254, 0x2A21, 0x6DF2, 0xAAEA, 0xED39, 0x254C, 0x629F, 0x0B51, 0x4C82, 0x84F7,
0xC324, 0x043C, 0x43EF, 0x8B9A, 0xCC49, 0x158B, 0x5258, 0x9A2D, 0xDDFE, 0x1AE6, 0x5D35, 0x9540, 0xD293,
0x36E5, 0x7136, 0xB943, 0xFE90, 0x3988, 0x7E5B, 0xB62E, 0xF1FD, 0x283F, 0x6FEC, 0xA799, 0xE04A, 0x2752,
0x6081, 0xA8F4, 0xEF27, 0x7039, 0x37EA, 0xFF9F, 0xB84C, 0x7F54, 0x3887, 0xF0F2, 0xB721, 0x6EE3, 0x2930,
0xE145, 0xA696, 0x618E, 0x265D, 0xEE28, 0xA9FB, 0x4D8D, 0x0A5E, 0xC22B, 0x85F8, 0x42E0, 0x0533, 0xCD46,
0x8A95, 0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F
}
};
/// <summary>Initializes an instance of the CRC16 with CCITT polynomial and seed.</summary>
/// <inheritdoc />
public CRC16CcittContext() : base(CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true) {}
public new string Name => "CRC-16 (CCITT)";
public new Guid Id => new("4C3BD0D5-24BD-4D45-BC19-A90A5AA5CC9D");
public new string Author => "Natalia Portillo";
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
/// <summary>Calculates the CCITT CRC16 of the specified buffer with the specified parameters</summary>
/// <param name="buffer">Buffer</param>
public static ushort Calculate(byte[] buffer) =>
Calculate(buffer, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
}

View File

@@ -1,649 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : CRC16Context.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements a CRC16 algorithm.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements a CRC16 algorithm</summary>
public class Crc16Context : IChecksum
{
readonly ushort _finalSeed;
readonly bool _inverse;
readonly IntPtr _nativeContext;
readonly ushort[][]? _table;
readonly bool _useCcitt;
readonly bool _useIbm;
readonly bool _useNative;
ushort _hashInt;
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc16Context(ushort polynomial, ushort seed, ushort[][] table, bool inverse)
{
_hashInt = seed;
_finalSeed = seed;
_inverse = inverse;
_useNative = Native.IsSupported;
_useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
inverse;
_useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY && seed == CRC16IbmContext.CRC16_IBM_SEED && !inverse;
if(_useCcitt && _useNative)
{
_nativeContext = crc16_ccitt_init();
_useNative = _nativeContext != IntPtr.Zero;
}
else if(_useIbm && _useNative)
{
_nativeContext = crc16_init();
_useNative = _nativeContext != IntPtr.Zero;
}
else
_useNative = false;
if(!_useNative)
_table = table ?? GenerateTable(polynomial, inverse);
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "CRC-16";
/// <inheritdoc />
public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
switch(_useNative)
{
case true when _useCcitt:
crc16_ccitt_update(_nativeContext, data, len);
break;
case true when _useIbm:
crc16_update(_nativeContext, data, len);
break;
default:
{
if(_inverse)
StepInverse(ref _hashInt, _table!, data, len);
else
Step(ref _hashInt, _table!, data, len);
break;
}
}
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
ushort crc = 0;
switch(_useNative)
{
case true when _useCcitt:
crc16_ccitt_final(_nativeContext, ref crc);
crc16_ccitt_free(_nativeContext);
break;
case true when _useIbm:
crc16_final(_nativeContext, ref crc);
crc16_free(_nativeContext);
break;
default:
{
if(_inverse)
crc = (ushort)~(_hashInt ^ _finalSeed);
else
crc = (ushort)(_hashInt ^ _finalSeed);
break;
}
}
return BigEndianBitConverter.GetBytes(crc);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var crc16Output = new StringBuilder();
ushort final = 0;
switch(_useNative)
{
case true when _useCcitt:
crc16_ccitt_final(_nativeContext, ref final);
crc16_ccitt_free(_nativeContext);
break;
case true when _useIbm:
crc16_final(_nativeContext, ref final);
crc16_free(_nativeContext);
break;
default:
{
if(_inverse)
final = (ushort)~(_hashInt ^ _finalSeed);
else
final = (ushort)(_hashInt ^ _finalSeed);
break;
}
}
byte[] finalBytes = BigEndianBitConverter.GetBytes(final);
foreach(byte t in finalBytes)
crc16Output.Append(t.ToString("x2"));
return crc16Output.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr crc16_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc16_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc16_final(IntPtr ctx, ref ushort crc);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void crc16_free(IntPtr ctx);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr crc16_ccitt_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc16_ccitt_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc16_ccitt_final(IntPtr ctx, ref ushort crc);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void crc16_ccitt_free(IntPtr ctx);
static void Step(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
var currentPos = 0;
const int unroll = 4;
const int bytesAtOnce = 8 * unroll;
ushort crc = previousCrc;
while(len >= bytesAtOnce)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
// TODO: What trick is Microsoft doing here that's faster than arithmetic conversion
uint one = BitConverter.ToUInt32(data, currentPos) ^ crc;
currentPos += 4;
var two = BitConverter.ToUInt32(data, currentPos);
currentPos += 4;
crc = (ushort)(table[0][two >> 24 & 0xFF] ^
table[1][two >> 16 & 0xFF] ^
table[2][two >> 8 & 0xFF] ^
table[3][two & 0xFF] ^
table[4][one >> 24 & 0xFF] ^
table[5][one >> 16 & 0xFF] ^
table[6][one >> 8 & 0xFF] ^
table[7][one & 0xFF]);
}
len -= bytesAtOnce;
}
while(len-- != 0)
crc = (ushort)(crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]]);
previousCrc = crc;
}
static void StepInverse(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
var currentPos = 0;
const int unroll = 4;
const int bytesAtOnce = 8 * unroll;
ushort crc = previousCrc;
while(len >= bytesAtOnce)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
crc = (ushort)(table[7][data[currentPos + 0] ^ crc >> 8] ^
table[6][data[currentPos + 1] ^ crc & 0xFF] ^
table[5][data[currentPos + 2]] ^
table[4][data[currentPos + 3]] ^
table[3][data[currentPos + 4]] ^
table[2][data[currentPos + 5]] ^
table[1][data[currentPos + 6]] ^
table[0][data[currentPos + 7]]);
currentPos += 8;
}
len -= bytesAtOnce;
}
while(len-- != 0)
crc = (ushort)(crc << 8 ^ table[0][crc >> 8 ^ data[currentPos++]]);
previousCrc = crc;
}
static ushort[][] GenerateTable(ushort polynomial, bool inverseTable)
{
var table = new ushort[8][];
for(var i = 0; i < 8; i++)
table[i] = new ushort[256];
if(!inverseTable)
{
for(uint i = 0; i < 256; i++)
{
uint entry = i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry >>= 1;
}
table[0][i] = (ushort)entry;
}
}
else
{
for(uint i = 0; i < 256; i++)
{
uint entry = i << 8;
for(uint j = 0; j < 8; j++)
{
if((entry & 0x8000) > 0)
entry = entry << 1 ^ polynomial;
else
entry <<= 1;
table[0][i] = (ushort)entry;
}
}
}
for(var slice = 1; slice < 8; slice++)
for(var i = 0; i < 256; i++)
{
if(inverseTable)
table[slice][i] = (ushort)(table[slice - 1][i] << 8 ^ table[0][table[slice - 1][i] >> 8]);
else
table[slice][i] = (ushort)(table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF]);
}
return table;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
/// <param name="table">CRC lookup table</param>
/// <param name="inverse">Is CRC inverted?</param>
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
bool inverse)
{
bool useNative = Native.IsSupported;
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
inverse;
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
seed == CRC16IbmContext.CRC16_IBM_SEED &&
!inverse;
IntPtr nativeContext = IntPtr.Zero;
var fileStream = new FileStream(filename, FileMode.Open);
ushort localHashInt = seed;
switch(useNative)
{
case true when useCcitt:
nativeContext = crc16_ccitt_init();
useNative = nativeContext != IntPtr.Zero;
break;
case true when useIbm:
nativeContext = crc16_init();
useNative = nativeContext != IntPtr.Zero;
break;
}
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_update(nativeContext, buffer, (uint)read);
break;
case true when useIbm:
crc16_update(nativeContext, buffer, (uint)read);
break;
default:
{
if(inverse)
StepInverse(ref localHashInt, localTable, buffer, (uint)read);
else
Step(ref localHashInt, localTable, buffer, (uint)read);
break;
}
}
read = fileStream.EnsureRead(buffer, 0, 65536);
}
localHashInt ^= seed;
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_final(nativeContext, ref localHashInt);
crc16_ccitt_free(nativeContext);
break;
case true when useIbm:
crc16_final(nativeContext, ref localHashInt);
crc16_free(nativeContext);
break;
default:
{
if(inverse)
localHashInt = (ushort)~localHashInt;
break;
}
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc16Output = new StringBuilder();
foreach(byte h in hash)
crc16Output.Append(h.ToString("x2"));
fileStream.Close();
return crc16Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
/// <param name="table">CRC lookup table</param>
/// <param name="inverse">Is CRC inverted?</param>
public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
bool inverse)
{
bool useNative = Native.IsSupported;
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
inverse;
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
seed == CRC16IbmContext.CRC16_IBM_SEED &&
!inverse;
IntPtr nativeContext = IntPtr.Zero;
ushort localHashInt = seed;
switch(useNative)
{
case true when useCcitt:
nativeContext = crc16_ccitt_init();
useNative = nativeContext != IntPtr.Zero;
break;
case true when useIbm:
nativeContext = crc16_init();
useNative = nativeContext != IntPtr.Zero;
break;
}
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_update(nativeContext, data, len);
break;
case true when useIbm:
crc16_update(nativeContext, data, len);
break;
default:
{
if(inverse)
StepInverse(ref localHashInt, localTable, data, len);
else
Step(ref localHashInt, localTable, data, len);
break;
}
}
localHashInt ^= seed;
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_final(nativeContext, ref localHashInt);
crc16_ccitt_free(nativeContext);
break;
case true when useIbm:
crc16_final(nativeContext, ref localHashInt);
crc16_free(nativeContext);
break;
default:
{
if(inverse)
localHashInt = (ushort)~localHashInt;
break;
}
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc16Output = new StringBuilder();
foreach(byte h in hash)
crc16Output.Append(h.ToString("x2"));
return crc16Output.ToString();
}
/// <summary>Calculates the CRC16 of the specified buffer with the specified parameters</summary>
/// <param name="buffer">Buffer</param>
/// <param name="polynomial">Polynomial</param>
/// <param name="seed">Seed</param>
/// <param name="table">Pre-generated lookup table</param>
/// <param name="inverse">Inverse CRC</param>
/// <returns>CRC16</returns>
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[][] table, bool inverse)
{
bool useNative = Native.IsSupported;
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
inverse;
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
seed == CRC16IbmContext.CRC16_IBM_SEED &&
!inverse;
IntPtr nativeContext = IntPtr.Zero;
ushort localHashInt = seed;
switch(useNative)
{
case true when useCcitt:
nativeContext = crc16_ccitt_init();
useNative = nativeContext != IntPtr.Zero;
break;
case true when useIbm:
nativeContext = crc16_init();
useNative = nativeContext != IntPtr.Zero;
break;
}
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_update(nativeContext, buffer, (uint)buffer.Length);
break;
case true when useIbm:
crc16_update(nativeContext, buffer, (uint)buffer.Length);
break;
default:
{
if(inverse)
StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length);
else
Step(ref localHashInt, localTable, buffer, (uint)buffer.Length);
break;
}
}
localHashInt ^= seed;
switch(useNative)
{
case true when useCcitt:
crc16_ccitt_final(nativeContext, ref localHashInt);
crc16_ccitt_free(nativeContext);
break;
case true when useIbm:
crc16_final(nativeContext, ref localHashInt);
crc16_free(nativeContext);
break;
default:
{
if(inverse)
localHashInt = (ushort)~localHashInt;
break;
}
}
return localHashInt;
}
}

View File

@@ -1,276 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : CRC16IBMContext.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements a CRC16 algorithm with the IBM polynomial.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements the CRC16 algorithm with IBM polynomial and seed</summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
public sealed class CRC16IbmContext : Crc16Context
{
internal const ushort CRC16_IBM_POLY = 0xA001;
internal const ushort CRC16_IBM_SEED = 0x0000;
static readonly ushort[][] _ibmCrc16Table =
{
new ushort[]
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500,
0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1,
0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81,
0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540,
0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001,
0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0,
0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80,
0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700,
0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0,
0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480,
0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41,
0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01,
0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1,
0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181,
0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901,
0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1,
0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680,
0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
},
new ushort[]
{
0x0000, 0x9001, 0x6001, 0xF000, 0xC002, 0x5003, 0xA003, 0x3002, 0xC007, 0x5006, 0xA006, 0x3007, 0x0005,
0x9004, 0x6004, 0xF005, 0xC00D, 0x500C, 0xA00C, 0x300D, 0x000F, 0x900E, 0x600E, 0xF00F, 0x000A, 0x900B,
0x600B, 0xF00A, 0xC008, 0x5009, 0xA009, 0x3008, 0xC019, 0x5018, 0xA018, 0x3019, 0x001B, 0x901A, 0x601A,
0xF01B, 0x001E, 0x901F, 0x601F, 0xF01E, 0xC01C, 0x501D, 0xA01D, 0x301C, 0x0014, 0x9015, 0x6015, 0xF014,
0xC016, 0x5017, 0xA017, 0x3016, 0xC013, 0x5012, 0xA012, 0x3013, 0x0011, 0x9010, 0x6010, 0xF011, 0xC031,
0x5030, 0xA030, 0x3031, 0x0033, 0x9032, 0x6032, 0xF033, 0x0036, 0x9037, 0x6037, 0xF036, 0xC034, 0x5035,
0xA035, 0x3034, 0x003C, 0x903D, 0x603D, 0xF03C, 0xC03E, 0x503F, 0xA03F, 0x303E, 0xC03B, 0x503A, 0xA03A,
0x303B, 0x0039, 0x9038, 0x6038, 0xF039, 0x0028, 0x9029, 0x6029, 0xF028, 0xC02A, 0x502B, 0xA02B, 0x302A,
0xC02F, 0x502E, 0xA02E, 0x302F, 0x002D, 0x902C, 0x602C, 0xF02D, 0xC025, 0x5024, 0xA024, 0x3025, 0x0027,
0x9026, 0x6026, 0xF027, 0x0022, 0x9023, 0x6023, 0xF022, 0xC020, 0x5021, 0xA021, 0x3020, 0xC061, 0x5060,
0xA060, 0x3061, 0x0063, 0x9062, 0x6062, 0xF063, 0x0066, 0x9067, 0x6067, 0xF066, 0xC064, 0x5065, 0xA065,
0x3064, 0x006C, 0x906D, 0x606D, 0xF06C, 0xC06E, 0x506F, 0xA06F, 0x306E, 0xC06B, 0x506A, 0xA06A, 0x306B,
0x0069, 0x9068, 0x6068, 0xF069, 0x0078, 0x9079, 0x6079, 0xF078, 0xC07A, 0x507B, 0xA07B, 0x307A, 0xC07F,
0x507E, 0xA07E, 0x307F, 0x007D, 0x907C, 0x607C, 0xF07D, 0xC075, 0x5074, 0xA074, 0x3075, 0x0077, 0x9076,
0x6076, 0xF077, 0x0072, 0x9073, 0x6073, 0xF072, 0xC070, 0x5071, 0xA071, 0x3070, 0x0050, 0x9051, 0x6051,
0xF050, 0xC052, 0x5053, 0xA053, 0x3052, 0xC057, 0x5056, 0xA056, 0x3057, 0x0055, 0x9054, 0x6054, 0xF055,
0xC05D, 0x505C, 0xA05C, 0x305D, 0x005F, 0x905E, 0x605E, 0xF05F, 0x005A, 0x905B, 0x605B, 0xF05A, 0xC058,
0x5059, 0xA059, 0x3058, 0xC049, 0x5048, 0xA048, 0x3049, 0x004B, 0x904A, 0x604A, 0xF04B, 0x004E, 0x904F,
0x604F, 0xF04E, 0xC04C, 0x504D, 0xA04D, 0x304C, 0x0044, 0x9045, 0x6045, 0xF044, 0xC046, 0x5047, 0xA047,
0x3046, 0xC043, 0x5042, 0xA042, 0x3043, 0x0041, 0x9040, 0x6040, 0xF041
},
new ushort[]
{
0x0000, 0xC051, 0xC0A1, 0x00F0, 0xC141, 0x0110, 0x01E0, 0xC1B1, 0xC281, 0x02D0, 0x0220, 0xC271, 0x03C0,
0xC391, 0xC361, 0x0330, 0xC501, 0x0550, 0x05A0, 0xC5F1, 0x0440, 0xC411, 0xC4E1, 0x04B0, 0x0780, 0xC7D1,
0xC721, 0x0770, 0xC6C1, 0x0690, 0x0660, 0xC631, 0xCA01, 0x0A50, 0x0AA0, 0xCAF1, 0x0B40, 0xCB11, 0xCBE1,
0x0BB0, 0x0880, 0xC8D1, 0xC821, 0x0870, 0xC9C1, 0x0990, 0x0960, 0xC931, 0x0F00, 0xCF51, 0xCFA1, 0x0FF0,
0xCE41, 0x0E10, 0x0EE0, 0xCEB1, 0xCD81, 0x0DD0, 0x0D20, 0xCD71, 0x0CC0, 0xCC91, 0xCC61, 0x0C30, 0xD401,
0x1450, 0x14A0, 0xD4F1, 0x1540, 0xD511, 0xD5E1, 0x15B0, 0x1680, 0xD6D1, 0xD621, 0x1670, 0xD7C1, 0x1790,
0x1760, 0xD731, 0x1100, 0xD151, 0xD1A1, 0x11F0, 0xD041, 0x1010, 0x10E0, 0xD0B1, 0xD381, 0x13D0, 0x1320,
0xD371, 0x12C0, 0xD291, 0xD261, 0x1230, 0x1E00, 0xDE51, 0xDEA1, 0x1EF0, 0xDF41, 0x1F10, 0x1FE0, 0xDFB1,
0xDC81, 0x1CD0, 0x1C20, 0xDC71, 0x1DC0, 0xDD91, 0xDD61, 0x1D30, 0xDB01, 0x1B50, 0x1BA0, 0xDBF1, 0x1A40,
0xDA11, 0xDAE1, 0x1AB0, 0x1980, 0xD9D1, 0xD921, 0x1970, 0xD8C1, 0x1890, 0x1860, 0xD831, 0xE801, 0x2850,
0x28A0, 0xE8F1, 0x2940, 0xE911, 0xE9E1, 0x29B0, 0x2A80, 0xEAD1, 0xEA21, 0x2A70, 0xEBC1, 0x2B90, 0x2B60,
0xEB31, 0x2D00, 0xED51, 0xEDA1, 0x2DF0, 0xEC41, 0x2C10, 0x2CE0, 0xECB1, 0xEF81, 0x2FD0, 0x2F20, 0xEF71,
0x2EC0, 0xEE91, 0xEE61, 0x2E30, 0x2200, 0xE251, 0xE2A1, 0x22F0, 0xE341, 0x2310, 0x23E0, 0xE3B1, 0xE081,
0x20D0, 0x2020, 0xE071, 0x21C0, 0xE191, 0xE161, 0x2130, 0xE701, 0x2750, 0x27A0, 0xE7F1, 0x2640, 0xE611,
0xE6E1, 0x26B0, 0x2580, 0xE5D1, 0xE521, 0x2570, 0xE4C1, 0x2490, 0x2460, 0xE431, 0x3C00, 0xFC51, 0xFCA1,
0x3CF0, 0xFD41, 0x3D10, 0x3DE0, 0xFDB1, 0xFE81, 0x3ED0, 0x3E20, 0xFE71, 0x3FC0, 0xFF91, 0xFF61, 0x3F30,
0xF901, 0x3950, 0x39A0, 0xF9F1, 0x3840, 0xF811, 0xF8E1, 0x38B0, 0x3B80, 0xFBD1, 0xFB21, 0x3B70, 0xFAC1,
0x3A90, 0x3A60, 0xFA31, 0xF601, 0x3650, 0x36A0, 0xF6F1, 0x3740, 0xF711, 0xF7E1, 0x37B0, 0x3480, 0xF4D1,
0xF421, 0x3470, 0xF5C1, 0x3590, 0x3560, 0xF531, 0x3300, 0xF351, 0xF3A1, 0x33F0, 0xF241, 0x3210, 0x32E0,
0xF2B1, 0xF181, 0x31D0, 0x3120, 0xF171, 0x30C0, 0xF091, 0xF061, 0x3030
},
new ushort[]
{
0x0000, 0xFC01, 0xB801, 0x4400, 0x3001, 0xCC00, 0x8800, 0x7401, 0x6002, 0x9C03, 0xD803, 0x2402, 0x5003,
0xAC02, 0xE802, 0x1403, 0xC004, 0x3C05, 0x7805, 0x8404, 0xF005, 0x0C04, 0x4804, 0xB405, 0xA006, 0x5C07,
0x1807, 0xE406, 0x9007, 0x6C06, 0x2806, 0xD407, 0xC00B, 0x3C0A, 0x780A, 0x840B, 0xF00A, 0x0C0B, 0x480B,
0xB40A, 0xA009, 0x5C08, 0x1808, 0xE409, 0x9008, 0x6C09, 0x2809, 0xD408, 0x000F, 0xFC0E, 0xB80E, 0x440F,
0x300E, 0xCC0F, 0x880F, 0x740E, 0x600D, 0x9C0C, 0xD80C, 0x240D, 0x500C, 0xAC0D, 0xE80D, 0x140C, 0xC015,
0x3C14, 0x7814, 0x8415, 0xF014, 0x0C15, 0x4815, 0xB414, 0xA017, 0x5C16, 0x1816, 0xE417, 0x9016, 0x6C17,
0x2817, 0xD416, 0x0011, 0xFC10, 0xB810, 0x4411, 0x3010, 0xCC11, 0x8811, 0x7410, 0x6013, 0x9C12, 0xD812,
0x2413, 0x5012, 0xAC13, 0xE813, 0x1412, 0x001E, 0xFC1F, 0xB81F, 0x441E, 0x301F, 0xCC1E, 0x881E, 0x741F,
0x601C, 0x9C1D, 0xD81D, 0x241C, 0x501D, 0xAC1C, 0xE81C, 0x141D, 0xC01A, 0x3C1B, 0x781B, 0x841A, 0xF01B,
0x0C1A, 0x481A, 0xB41B, 0xA018, 0x5C19, 0x1819, 0xE418, 0x9019, 0x6C18, 0x2818, 0xD419, 0xC029, 0x3C28,
0x7828, 0x8429, 0xF028, 0x0C29, 0x4829, 0xB428, 0xA02B, 0x5C2A, 0x182A, 0xE42B, 0x902A, 0x6C2B, 0x282B,
0xD42A, 0x002D, 0xFC2C, 0xB82C, 0x442D, 0x302C, 0xCC2D, 0x882D, 0x742C, 0x602F, 0x9C2E, 0xD82E, 0x242F,
0x502E, 0xAC2F, 0xE82F, 0x142E, 0x0022, 0xFC23, 0xB823, 0x4422, 0x3023, 0xCC22, 0x8822, 0x7423, 0x6020,
0x9C21, 0xD821, 0x2420, 0x5021, 0xAC20, 0xE820, 0x1421, 0xC026, 0x3C27, 0x7827, 0x8426, 0xF027, 0x0C26,
0x4826, 0xB427, 0xA024, 0x5C25, 0x1825, 0xE424, 0x9025, 0x6C24, 0x2824, 0xD425, 0x003C, 0xFC3D, 0xB83D,
0x443C, 0x303D, 0xCC3C, 0x883C, 0x743D, 0x603E, 0x9C3F, 0xD83F, 0x243E, 0x503F, 0xAC3E, 0xE83E, 0x143F,
0xC038, 0x3C39, 0x7839, 0x8438, 0xF039, 0x0C38, 0x4838, 0xB439, 0xA03A, 0x5C3B, 0x183B, 0xE43A, 0x903B,
0x6C3A, 0x283A, 0xD43B, 0xC037, 0x3C36, 0x7836, 0x8437, 0xF036, 0x0C37, 0x4837, 0xB436, 0xA035, 0x5C34,
0x1834, 0xE435, 0x9034, 0x6C35, 0x2835, 0xD434, 0x0033, 0xFC32, 0xB832, 0x4433, 0x3032, 0xCC33, 0x8833,
0x7432, 0x6031, 0x9C30, 0xD830, 0x2431, 0x5030, 0xAC31, 0xE831, 0x1430
},
new ushort[]
{
0x0000, 0xC03D, 0xC079, 0x0044, 0xC0F1, 0x00CC, 0x0088, 0xC0B5, 0xC1E1, 0x01DC, 0x0198, 0xC1A5, 0x0110,
0xC12D, 0xC169, 0x0154, 0xC3C1, 0x03FC, 0x03B8, 0xC385, 0x0330, 0xC30D, 0xC349, 0x0374, 0x0220, 0xC21D,
0xC259, 0x0264, 0xC2D1, 0x02EC, 0x02A8, 0xC295, 0xC781, 0x07BC, 0x07F8, 0xC7C5, 0x0770, 0xC74D, 0xC709,
0x0734, 0x0660, 0xC65D, 0xC619, 0x0624, 0xC691, 0x06AC, 0x06E8, 0xC6D5, 0x0440, 0xC47D, 0xC439, 0x0404,
0xC4B1, 0x048C, 0x04C8, 0xC4F5, 0xC5A1, 0x059C, 0x05D8, 0xC5E5, 0x0550, 0xC56D, 0xC529, 0x0514, 0xCF01,
0x0F3C, 0x0F78, 0xCF45, 0x0FF0, 0xCFCD, 0xCF89, 0x0FB4, 0x0EE0, 0xCEDD, 0xCE99, 0x0EA4, 0xCE11, 0x0E2C,
0x0E68, 0xCE55, 0x0CC0, 0xCCFD, 0xCCB9, 0x0C84, 0xCC31, 0x0C0C, 0x0C48, 0xCC75, 0xCD21, 0x0D1C, 0x0D58,
0xCD65, 0x0DD0, 0xCDED, 0xCDA9, 0x0D94, 0x0880, 0xC8BD, 0xC8F9, 0x08C4, 0xC871, 0x084C, 0x0808, 0xC835,
0xC961, 0x095C, 0x0918, 0xC925, 0x0990, 0xC9AD, 0xC9E9, 0x09D4, 0xCB41, 0x0B7C, 0x0B38, 0xCB05, 0x0BB0,
0xCB8D, 0xCBC9, 0x0BF4, 0x0AA0, 0xCA9D, 0xCAD9, 0x0AE4, 0xCA51, 0x0A6C, 0x0A28, 0xCA15, 0xDE01, 0x1E3C,
0x1E78, 0xDE45, 0x1EF0, 0xDECD, 0xDE89, 0x1EB4, 0x1FE0, 0xDFDD, 0xDF99, 0x1FA4, 0xDF11, 0x1F2C, 0x1F68,
0xDF55, 0x1DC0, 0xDDFD, 0xDDB9, 0x1D84, 0xDD31, 0x1D0C, 0x1D48, 0xDD75, 0xDC21, 0x1C1C, 0x1C58, 0xDC65,
0x1CD0, 0xDCED, 0xDCA9, 0x1C94, 0x1980, 0xD9BD, 0xD9F9, 0x19C4, 0xD971, 0x194C, 0x1908, 0xD935, 0xD861,
0x185C, 0x1818, 0xD825, 0x1890, 0xD8AD, 0xD8E9, 0x18D4, 0xDA41, 0x1A7C, 0x1A38, 0xDA05, 0x1AB0, 0xDA8D,
0xDAC9, 0x1AF4, 0x1BA0, 0xDB9D, 0xDBD9, 0x1BE4, 0xDB51, 0x1B6C, 0x1B28, 0xDB15, 0x1100, 0xD13D, 0xD179,
0x1144, 0xD1F1, 0x11CC, 0x1188, 0xD1B5, 0xD0E1, 0x10DC, 0x1098, 0xD0A5, 0x1010, 0xD02D, 0xD069, 0x1054,
0xD2C1, 0x12FC, 0x12B8, 0xD285, 0x1230, 0xD20D, 0xD249, 0x1274, 0x1320, 0xD31D, 0xD359, 0x1364, 0xD3D1,
0x13EC, 0x13A8, 0xD395, 0xD681, 0x16BC, 0x16F8, 0xD6C5, 0x1670, 0xD64D, 0xD609, 0x1634, 0x1760, 0xD75D,
0xD719, 0x1724, 0xD791, 0x17AC, 0x17E8, 0xD7D5, 0x1540, 0xD57D, 0xD539, 0x1504, 0xD5B1, 0x158C, 0x15C8,
0xD5F5, 0xD4A1, 0x149C, 0x14D8, 0xD4E5, 0x1450, 0xD46D, 0xD429, 0x1414
},
new ushort[]
{
0x0000, 0xD101, 0xE201, 0x3300, 0x8401, 0x5500, 0x6600, 0xB701, 0x4801, 0x9900, 0xAA00, 0x7B01, 0xCC00,
0x1D01, 0x2E01, 0xFF00, 0x9002, 0x4103, 0x7203, 0xA302, 0x1403, 0xC502, 0xF602, 0x2703, 0xD803, 0x0902,
0x3A02, 0xEB03, 0x5C02, 0x8D03, 0xBE03, 0x6F02, 0x6007, 0xB106, 0x8206, 0x5307, 0xE406, 0x3507, 0x0607,
0xD706, 0x2806, 0xF907, 0xCA07, 0x1B06, 0xAC07, 0x7D06, 0x4E06, 0x9F07, 0xF005, 0x2104, 0x1204, 0xC305,
0x7404, 0xA505, 0x9605, 0x4704, 0xB804, 0x6905, 0x5A05, 0x8B04, 0x3C05, 0xED04, 0xDE04, 0x0F05, 0xC00E,
0x110F, 0x220F, 0xF30E, 0x440F, 0x950E, 0xA60E, 0x770F, 0x880F, 0x590E, 0x6A0E, 0xBB0F, 0x0C0E, 0xDD0F,
0xEE0F, 0x3F0E, 0x500C, 0x810D, 0xB20D, 0x630C, 0xD40D, 0x050C, 0x360C, 0xE70D, 0x180D, 0xC90C, 0xFA0C,
0x2B0D, 0x9C0C, 0x4D0D, 0x7E0D, 0xAF0C, 0xA009, 0x7108, 0x4208, 0x9309, 0x2408, 0xF509, 0xC609, 0x1708,
0xE808, 0x3909, 0x0A09, 0xDB08, 0x6C09, 0xBD08, 0x8E08, 0x5F09, 0x300B, 0xE10A, 0xD20A, 0x030B, 0xB40A,
0x650B, 0x560B, 0x870A, 0x780A, 0xA90B, 0x9A0B, 0x4B0A, 0xFC0B, 0x2D0A, 0x1E0A, 0xCF0B, 0xC01F, 0x111E,
0x221E, 0xF31F, 0x441E, 0x951F, 0xA61F, 0x771E, 0x881E, 0x591F, 0x6A1F, 0xBB1E, 0x0C1F, 0xDD1E, 0xEE1E,
0x3F1F, 0x501D, 0x811C, 0xB21C, 0x631D, 0xD41C, 0x051D, 0x361D, 0xE71C, 0x181C, 0xC91D, 0xFA1D, 0x2B1C,
0x9C1D, 0x4D1C, 0x7E1C, 0xAF1D, 0xA018, 0x7119, 0x4219, 0x9318, 0x2419, 0xF518, 0xC618, 0x1719, 0xE819,
0x3918, 0x0A18, 0xDB19, 0x6C18, 0xBD19, 0x8E19, 0x5F18, 0x301A, 0xE11B, 0xD21B, 0x031A, 0xB41B, 0x651A,
0x561A, 0x871B, 0x781B, 0xA91A, 0x9A1A, 0x4B1B, 0xFC1A, 0x2D1B, 0x1E1B, 0xCF1A, 0x0011, 0xD110, 0xE210,
0x3311, 0x8410, 0x5511, 0x6611, 0xB710, 0x4810, 0x9911, 0xAA11, 0x7B10, 0xCC11, 0x1D10, 0x2E10, 0xFF11,
0x9013, 0x4112, 0x7212, 0xA313, 0x1412, 0xC513, 0xF613, 0x2712, 0xD812, 0x0913, 0x3A13, 0xEB12, 0x5C13,
0x8D12, 0xBE12, 0x6F13, 0x6016, 0xB117, 0x8217, 0x5316, 0xE417, 0x3516, 0x0616, 0xD717, 0x2817, 0xF916,
0xCA16, 0x1B17, 0xAC16, 0x7D17, 0x4E17, 0x9F16, 0xF014, 0x2115, 0x1215, 0xC314, 0x7415, 0xA514, 0x9614,
0x4715, 0xB815, 0x6914, 0x5A14, 0x8B15, 0x3C14, 0xED15, 0xDE15, 0x0F14
},
new ushort[]
{
0x0000, 0xC010, 0xC023, 0x0033, 0xC045, 0x0055, 0x0066, 0xC076, 0xC089, 0x0099, 0x00AA, 0xC0BA, 0x00CC,
0xC0DC, 0xC0EF, 0x00FF, 0xC111, 0x0101, 0x0132, 0xC122, 0x0154, 0xC144, 0xC177, 0x0167, 0x0198, 0xC188,
0xC1BB, 0x01AB, 0xC1DD, 0x01CD, 0x01FE, 0xC1EE, 0xC221, 0x0231, 0x0202, 0xC212, 0x0264, 0xC274, 0xC247,
0x0257, 0x02A8, 0xC2B8, 0xC28B, 0x029B, 0xC2ED, 0x02FD, 0x02CE, 0xC2DE, 0x0330, 0xC320, 0xC313, 0x0303,
0xC375, 0x0365, 0x0356, 0xC346, 0xC3B9, 0x03A9, 0x039A, 0xC38A, 0x03FC, 0xC3EC, 0xC3DF, 0x03CF, 0xC441,
0x0451, 0x0462, 0xC472, 0x0404, 0xC414, 0xC427, 0x0437, 0x04C8, 0xC4D8, 0xC4EB, 0x04FB, 0xC48D, 0x049D,
0x04AE, 0xC4BE, 0x0550, 0xC540, 0xC573, 0x0563, 0xC515, 0x0505, 0x0536, 0xC526, 0xC5D9, 0x05C9, 0x05FA,
0xC5EA, 0x059C, 0xC58C, 0xC5BF, 0x05AF, 0x0660, 0xC670, 0xC643, 0x0653, 0xC625, 0x0635, 0x0606, 0xC616,
0xC6E9, 0x06F9, 0x06CA, 0xC6DA, 0x06AC, 0xC6BC, 0xC68F, 0x069F, 0xC771, 0x0761, 0x0752, 0xC742, 0x0734,
0xC724, 0xC717, 0x0707, 0x07F8, 0xC7E8, 0xC7DB, 0x07CB, 0xC7BD, 0x07AD, 0x079E, 0xC78E, 0xC881, 0x0891,
0x08A2, 0xC8B2, 0x08C4, 0xC8D4, 0xC8E7, 0x08F7, 0x0808, 0xC818, 0xC82B, 0x083B, 0xC84D, 0x085D, 0x086E,
0xC87E, 0x0990, 0xC980, 0xC9B3, 0x09A3, 0xC9D5, 0x09C5, 0x09F6, 0xC9E6, 0xC919, 0x0909, 0x093A, 0xC92A,
0x095C, 0xC94C, 0xC97F, 0x096F, 0x0AA0, 0xCAB0, 0xCA83, 0x0A93, 0xCAE5, 0x0AF5, 0x0AC6, 0xCAD6, 0xCA29,
0x0A39, 0x0A0A, 0xCA1A, 0x0A6C, 0xCA7C, 0xCA4F, 0x0A5F, 0xCBB1, 0x0BA1, 0x0B92, 0xCB82, 0x0BF4, 0xCBE4,
0xCBD7, 0x0BC7, 0x0B38, 0xCB28, 0xCB1B, 0x0B0B, 0xCB7D, 0x0B6D, 0x0B5E, 0xCB4E, 0x0CC0, 0xCCD0, 0xCCE3,
0x0CF3, 0xCC85, 0x0C95, 0x0CA6, 0xCCB6, 0xCC49, 0x0C59, 0x0C6A, 0xCC7A, 0x0C0C, 0xCC1C, 0xCC2F, 0x0C3F,
0xCDD1, 0x0DC1, 0x0DF2, 0xCDE2, 0x0D94, 0xCD84, 0xCDB7, 0x0DA7, 0x0D58, 0xCD48, 0xCD7B, 0x0D6B, 0xCD1D,
0x0D0D, 0x0D3E, 0xCD2E, 0xCEE1, 0x0EF1, 0x0EC2, 0xCED2, 0x0EA4, 0xCEB4, 0xCE87, 0x0E97, 0x0E68, 0xCE78,
0xCE4B, 0x0E5B, 0xCE2D, 0x0E3D, 0x0E0E, 0xCE1E, 0x0FF0, 0xCFE0, 0xCFD3, 0x0FC3, 0xCFB5, 0x0FA5, 0x0F96,
0xCF86, 0xCF79, 0x0F69, 0x0F5A, 0xCF4A, 0x0F3C, 0xCF2C, 0xCF1F, 0x0F0F
},
new ushort[]
{
0x0000, 0xCCC1, 0xD981, 0x1540, 0xF301, 0x3FC0, 0x2A80, 0xE641, 0xA601, 0x6AC0, 0x7F80, 0xB341, 0x5500,
0x99C1, 0x8C81, 0x4040, 0x0C01, 0xC0C0, 0xD580, 0x1941, 0xFF00, 0x33C1, 0x2681, 0xEA40, 0xAA00, 0x66C1,
0x7381, 0xBF40, 0x5901, 0x95C0, 0x8080, 0x4C41, 0x1802, 0xD4C3, 0xC183, 0x0D42, 0xEB03, 0x27C2, 0x3282,
0xFE43, 0xBE03, 0x72C2, 0x6782, 0xAB43, 0x4D02, 0x81C3, 0x9483, 0x5842, 0x1403, 0xD8C2, 0xCD82, 0x0143,
0xE702, 0x2BC3, 0x3E83, 0xF242, 0xB202, 0x7EC3, 0x6B83, 0xA742, 0x4103, 0x8DC2, 0x9882, 0x5443, 0x3004,
0xFCC5, 0xE985, 0x2544, 0xC305, 0x0FC4, 0x1A84, 0xD645, 0x9605, 0x5AC4, 0x4F84, 0x8345, 0x6504, 0xA9C5,
0xBC85, 0x7044, 0x3C05, 0xF0C4, 0xE584, 0x2945, 0xCF04, 0x03C5, 0x1685, 0xDA44, 0x9A04, 0x56C5, 0x4385,
0x8F44, 0x6905, 0xA5C4, 0xB084, 0x7C45, 0x2806, 0xE4C7, 0xF187, 0x3D46, 0xDB07, 0x17C6, 0x0286, 0xCE47,
0x8E07, 0x42C6, 0x5786, 0x9B47, 0x7D06, 0xB1C7, 0xA487, 0x6846, 0x2407, 0xE8C6, 0xFD86, 0x3147, 0xD706,
0x1BC7, 0x0E87, 0xC246, 0x8206, 0x4EC7, 0x5B87, 0x9746, 0x7107, 0xBDC6, 0xA886, 0x6447, 0x6008, 0xACC9,
0xB989, 0x7548, 0x9309, 0x5FC8, 0x4A88, 0x8649, 0xC609, 0x0AC8, 0x1F88, 0xD349, 0x3508, 0xF9C9, 0xEC89,
0x2048, 0x6C09, 0xA0C8, 0xB588, 0x7949, 0x9F08, 0x53C9, 0x4689, 0x8A48, 0xCA08, 0x06C9, 0x1389, 0xDF48,
0x3909, 0xF5C8, 0xE088, 0x2C49, 0x780A, 0xB4CB, 0xA18B, 0x6D4A, 0x8B0B, 0x47CA, 0x528A, 0x9E4B, 0xDE0B,
0x12CA, 0x078A, 0xCB4B, 0x2D0A, 0xE1CB, 0xF48B, 0x384A, 0x740B, 0xB8CA, 0xAD8A, 0x614B, 0x870A, 0x4BCB,
0x5E8B, 0x924A, 0xD20A, 0x1ECB, 0x0B8B, 0xC74A, 0x210B, 0xEDCA, 0xF88A, 0x344B, 0x500C, 0x9CCD, 0x898D,
0x454C, 0xA30D, 0x6FCC, 0x7A8C, 0xB64D, 0xF60D, 0x3ACC, 0x2F8C, 0xE34D, 0x050C, 0xC9CD, 0xDC8D, 0x104C,
0x5C0D, 0x90CC, 0x858C, 0x494D, 0xAF0C, 0x63CD, 0x768D, 0xBA4C, 0xFA0C, 0x36CD, 0x238D, 0xEF4C, 0x090D,
0xC5CC, 0xD08C, 0x1C4D, 0x480E, 0x84CF, 0x918F, 0x5D4E, 0xBB0F, 0x77CE, 0x628E, 0xAE4F, 0xEE0F, 0x22CE,
0x378E, 0xFB4F, 0x1D0E, 0xD1CF, 0xC48F, 0x084E, 0x440F, 0x88CE, 0x9D8E, 0x514F, 0xB70E, 0x7BCF, 0x6E8F,
0xA24E, 0xE20E, 0x2ECF, 0x3B8F, 0xF74E, 0x110F, 0xDDCE, 0xC88E, 0x044F
}
};
/// <summary>Initializes an instance of the CRC16 with IBM polynomial and seed.</summary>
/// <inheritdoc />
public CRC16IbmContext() : base(CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false) {}
/// <inheritdoc />
public new string Name => "CRC-16 (IBM)";
/// <inheritdoc />
public new Guid Id => new("0470433E-0C78-4C37-8C9F-BD8E72340E78");
/// <inheritdoc />
public new string Author => "Natalia Portillo";
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -1,136 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : arm_simd.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// The Chromium Authors
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute CRC32 checksum using ARM special instructions..
//
// --[ License ] --------------------------------------------------------------
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright 2017 The Chromium Authors. All rights reserved.
// ****************************************************************************/
#if NET5_0_OR_GREATER
using System;
using System.Runtime.Intrinsics.Arm;
namespace Aaru.Checksums.CRC32;
static class ArmSimd
{
internal static uint Step64(byte[] buf, long len, uint crc)
{
uint c = crc;
var bufPos = 0;
while(len >= 64)
{
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
len -= 64;
}
while(len >= 8)
{
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
bufPos += 8;
len -= 8;
}
while(len-- > 0)
c = Crc32.ComputeCrc32(c, buf[bufPos++]);
return c;
}
internal static uint Step32(byte[] buf, long len, uint crc)
{
uint c = crc;
var bufPos = 0;
while(len >= 32)
{
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
len -= 32;
}
while(len >= 4)
{
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
bufPos += 4;
len -= 4;
}
while(len-- > 0)
c = Crc32.ComputeCrc32(c, buf[bufPos++]);
return c;
}
}
#endif

View File

@@ -1,227 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : clmul.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// Wajdi Feghali <wajdi.k.feghali@intel.com>
// Jim Guilford <james.guilford@intel.com>
// Vinodh Gopal <vinodh.gopal@intel.com>
// Erdinc Ozturk <erdinc.ozturk@intel.com>
// Jim Kukunas <james.t.kukunas@linux.intel.com>
// Marian Beermann
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
// instruction.
//
// A white paper describing this algorithm can be found at:
// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
//
// --[ License ] --------------------------------------------------------------
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright (c) 2016 Marian Beermann (add support for initial value, restructuring)
// Copyright (C) 2013 Intel Corporation. All rights reserved.
// ****************************************************************************/
#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru.Checksums.CRC32;
static class Clmul
{
static readonly uint[] _crcK =
{
0xccaa009e, 0x00000000, /* rk1 */ 0x751997d0, 0x00000001, /* rk2 */ 0xccaa009e, 0x00000000, /* rk5 */
0x63cd6124, 0x00000001, /* rk6 */ 0xf7011640, 0x00000001, /* rk7 */ 0xdb710640, 0x00000001 /* rk8 */
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Fold4(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
ref Vector128<uint> xmmCRC3)
{
var xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> xTmp0 = xmmCRC0;
Vector128<uint> xTmp1 = xmmCRC1;
Vector128<uint> xTmp2 = xmmCRC2;
Vector128<uint> xTmp3 = xmmCRC3;
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp0 = Pclmulqdq.CarrylessMultiply(xTmp0.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
Vector128<float> psT0 = xTmp0.AsSingle();
Vector128<float> psRes0 = Sse.Xor(psCRC0, psT0);
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp1 = Pclmulqdq.CarrylessMultiply(xTmp1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC1 = xmmCRC1.AsSingle();
Vector128<float> psT1 = xTmp1.AsSingle();
Vector128<float> psRes1 = Sse.Xor(psCRC1, psT1);
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp2 = Pclmulqdq.CarrylessMultiply(xTmp2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC2 = xmmCRC2.AsSingle();
Vector128<float> psT2 = xTmp2.AsSingle();
Vector128<float> psRes2 = Sse.Xor(psCRC2, psT2);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp3 = Pclmulqdq.CarrylessMultiply(xTmp3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psT3 = xTmp3.AsSingle();
Vector128<float> psRes3 = Sse.Xor(psCRC3, psT3);
xmmCRC0 = psRes0.AsUInt32();
xmmCRC1 = psRes1.AsUInt32();
xmmCRC2 = psRes2.AsUInt32();
xmmCRC3 = psRes3.AsUInt32();
}
internal static uint Step(byte[] src, long len, uint initialCRC)
{
Vector128<uint> xmmInitial = Sse2.ConvertScalarToVector128UInt32(initialCRC);
Vector128<uint> xmmCRC0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487);
Vector128<uint> xmmCRC1 = Vector128<uint>.Zero;
Vector128<uint> xmmCRC2 = Vector128<uint>.Zero;
Vector128<uint> xmmCRC3 = Vector128<uint>.Zero;
var bufPos = 0;
var first = true;
/* fold 512 to 32 step variable declarations for ISO-C90 compat. */
var xmmMask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000);
var xmmMask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
while((len -= 64) >= 0)
{
var xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
var xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
var xmmT2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
var xmmT3 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
}
Fold4(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
xmmCRC0 = Sse2.Xor(xmmCRC0, xmmT0);
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmT1);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT3);
}
/* fold 512 to 32 */
/*
* k1
*/
var crcFold = Vector128.Create(_crcK[0], _crcK[1], _crcK[2], _crcK[3]);
Vector128<uint> xTmp0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC1 = Sse2.Xor(xmmCRC1, xTmp0);
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmCRC0);
Vector128<uint> xTmp1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC2 = Sse2.Xor(xmmCRC2, xTmp1);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmCRC1);
Vector128<uint> xTmp2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xTmp2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
/*
* k5
*/
crcFold = Vector128.Create(_crcK[4], _crcK[5], _crcK[6], _crcK[7]);
xmmCRC0 = xmmCRC3;
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
xmmCRC0 = Sse2.ShiftRightLogical128BitLane(xmmCRC0, 8);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
xmmCRC0 = xmmCRC3;
xmmCRC3 = Sse2.ShiftLeftLogical128BitLane(xmmCRC3, 4);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask2);
/*
* k7
*/
xmmCRC1 = xmmCRC3;
xmmCRC2 = xmmCRC3;
crcFold = Vector128.Create(_crcK[8], _crcK[9], _crcK[10], _crcK[11]);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask);
xmmCRC2 = xmmCRC3;
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC1);
/*
* could just as well write xmm_crc3[2], doing a movaps and truncating, but
* no real advantage - it's a tiny bit slower per call, while no additional CPUs
* would be supported by only requiring SSSE3 and CLMUL instead of SSE4.1 + CLMUL
*/
return ~Sse41.Extract(xmmCRC3, 2);
}
}
#endif

View File

@@ -1,671 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : CRC32Context.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements a CRC32 algorithm.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
#if NET5_0_OR_GREATER
using System.Runtime.Intrinsics.Arm;
#endif
#if NETCOREAPP3_1_OR_GREATER
using System.Runtime.Intrinsics.X86;
#endif
using System.Text;
#if NETCOREAPP3_1_OR_GREATER
using Aaru.Checksums.CRC32;
#endif
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements a CRC32 algorithm</summary>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public sealed class Crc32Context : IChecksum
{
const uint CRC32_ISO_POLY = 0xEDB88320;
const uint CRC32_ISO_SEED = 0xFFFFFFFF;
internal static readonly uint[][] ISOCrc32Table =
{
new uint[]
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
},
new uint[]
{
0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7, 0xC8D98A08,
0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF, 0x4AC21251, 0x53D92310,
0x78F470D3, 0x61EF4192, 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496, 0x821B9859, 0x9B00A918, 0xB02DFADB,
0xA936CB9A, 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761,
0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE,
0x202A5AEF, 0x0B07092C, 0x121C386D, 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6,
0x891C9175, 0x9007A034, 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D,
0x58DE2A3C, 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA, 0xBABB5D54,
0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, 0x7262D75C, 0x6B79E61D,
0x4054B5DE, 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B, 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925,
0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C,
0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768, 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2,
0x52488DB3, 0x7965DE70, 0x607EEF31, 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB,
0xB1BC5478, 0xA8A76539, 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD,
0x74C20E8C, 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, 0xB9980012,
0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, 0xAE07BCE9, 0xB71C8DA8,
0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, 0x66DE36E1, 0x7FC507A0, 0x54E85463,
0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026, 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B,
0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F, 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4,
0x516BD0F5, 0x7A468336, 0x635DB277, 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, 0xB68D230B,
0x9DA070C8, 0x84BB4189, 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0,
0x4C62CB81, 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, 0x5E7EF3EC,
0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B, 0x96A779E4, 0x8FBC48A5,
0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23, 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F,
0x3F91B27E, 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A, 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876,
0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72
},
new uint[]
{
0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685, 0x0E1351B8,
0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D, 0x1C26A370, 0x1DE4C947,
0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, 0x1235F2C8, 0x13F798FF, 0x11B126A6,
0x10734C91, 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D, 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9,
0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065, 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84,
0x3095D5B3, 0x32D36BEA, 0x331101DD, 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B,
0x20E69922, 0x2124F315, 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A,
0x2F37A2AD, 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, 0x6CBC2EB0,
0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835, 0x62AF7F08, 0x636D153F,
0x612BAB66, 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D, 0x48D7CB20, 0x4915A117, 0x4B531F4E,
0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1,
0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D, 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C,
0x523AAABB, 0x507C14E2, 0x51BE7ED5, 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03,
0x5E6F455A, 0x5FAD2F6D, 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, 0xE7FED96B, 0xE5B86732,
0xE47A0D05, 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, 0xF300E948,
0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, 0xD9785D60, 0xD8BA3757,
0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6,
0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D, 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049,
0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895, 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774,
0xCD866D43, 0xCFC0D31A, 0xCE02B92D, 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, 0x976454AB,
0x9522EAF2, 0x94E080C5, 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A,
0x9AF3D17D, 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D, 0xA9E2D0A0,
0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625, 0xA7F18118, 0xA633EB2F,
0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D, 0xB5C473D0, 0xB40619E7, 0xB640A7BE,
0xB782CD89, 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555, 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31,
0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED
},
new uint[]
{
0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9, 0xC5B428EF,
0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056, 0x5019579F, 0xE8A530FA,
0xFA109F14, 0x42ACF871, 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26, 0x95AD7F70, 0x2D111815, 0x3FA4B7FB,
0x8718D09E, 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9, 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0,
0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086,
0x525877E3, 0x40EDD80D, 0xF851BF68, 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893,
0xD540A77D, 0x6DFCC018, 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92,
0xA848E8F7, 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B, 0xCB0D0FA2,
0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B, 0x0EB9274D, 0xB6054028,
0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4, 0x3B26F703, 0x839A9066, 0x912F3F88,
0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002,
0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755, 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB,
0x5CE150AE, 0x4E54FF40, 0xF6E89825, 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841,
0x8BE0D7AF, 0x335CB0CA, 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, 0xDA874609, 0xC832E9E7,
0x708E8E82, 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D, 0x78F4C94B,
0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, 0x4D6B1905, 0xF5D77E60,
0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC, 0x88DF31EA, 0x3063568F, 0x22D6F961,
0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953, 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174,
0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623, 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122,
0xEF189647, 0xFDAD39A9, 0x45115ECC, 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, 0x41931E34,
0x5326B1DA, 0xEB9AD6BF, 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935,
0x2E2EFE50, 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, 0xD67F4138,
0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981, 0x13CB69D7, 0xAB770EB2,
0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E, 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C,
0x94D3B949, 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6,
0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1
},
new uint[]
{
0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10, 0x30704BC1,
0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1, 0x60E09782, 0x5D80BE32,
0x1A20C4E2, 0x2740ED52, 0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92, 0x5090DC43, 0x6DF0F5F3, 0x2A508F23,
0x1730A693, 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053, 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4,
0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314, 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15, 0x0431C205,
0x3951EBB5, 0x7EF19165, 0x4391B8D5, 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, 0x69C137F6,
0x2E614D26, 0x13016496, 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, 0x59B17C37, 0x1E1106E7,
0x23712F57, 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459,
0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, 0x3813CFCB,
0x0573E67B, 0x42D39CAB, 0x7FB3B51B, 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, 0x0863840A, 0x3503ADBA,
0x72A3D76A, 0x4FC3FEDA, 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A, 0x9932774D, 0xA4525EFD, 0xE3F2242D,
0xDE920D9D, 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D, 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C,
0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F,
0x31326FBF, 0x7692156F, 0x4BF23CDF, 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, 0x0142247E,
0x46E25EAE, 0x7B82771E, 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, 0x79063FE2, 0x3EA64532,
0x03C66C82, 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743,
0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0, 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00, 0xE1766CD1,
0xDC164561, 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1, 0x70279F96, 0x4D47B626,
0x0AE7CCF6, 0x3787E546, 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386, 0x4057D457, 0x7D37FDE7, 0x3A978737,
0x07F7AE87, 0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847, 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4,
0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404, 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515,
0xE857CCA5, 0xAFF7B675, 0x92979FC5, 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, 0x1C954E1B, 0x21F567AB,
0x66551D7B, 0x5B3534CB, 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA, 0x2CE505DA, 0x11852C6A, 0x562556BA,
0x6B457F0A, 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589, 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349,
0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888, 0x28D4C7DF,
0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF, 0x18A48C1E, 0x25C4A5AE,
0x6264DF7E, 0x5F04F6CE, 0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E, 0x4834505D, 0x755479ED, 0x32F4033D,
0x0F942A8D, 0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C,
0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C
},
new uint[]
{
0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8, 0xEC53826D,
0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5, 0x03D6029B, 0xC88AD13E,
0x4E1EA390, 0x85427035, 0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223, 0xEF8580F6, 0x24D95353, 0xA24D21FD,
0x6911F258, 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E, 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798,
0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E, 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5, 0x706EC54D,
0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, 0x54B7961E,
0xD223E4B0, 0x197F3715, 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, 0xB8E41473, 0x3E7066DD,
0xF52CB578, 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4,
0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, 0x0C8E08F7,
0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F, 0xE0DD8A9A, 0x2B81593F,
0xAD152B91, 0x6649F834, 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22, 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51,
0x8E607DF4, 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2, 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99,
0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7,
0x5BEF9C72, 0xDD7BEEDC, 0x16273D79, 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, 0xB7BC1E1F,
0x31286CB1, 0xFA74BF14, 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, 0x4E7D856B, 0xC8E9F7C5,
0x03B52460, 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D,
0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED, 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, 0xF135942E,
0x3A69478B, 0xBCFD3525, 0x77A1E680, 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496, 0x191C11EE, 0xD240C24B,
0x54D4B0E5, 0x9F886340, 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156, 0xF54F9383, 0x3E134026, 0xB8873288,
0x73DBE12D, 0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B, 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB,
0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD, 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E,
0xA65400AB, 0x20C07205, 0xEB9CA1A0, 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, 0x8A795CA2, 0x41258F07,
0xC7B1FDA9, 0x0CED2E0C, 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77, 0x662ADECF, 0xAD760D6A, 0x2BE27FC4,
0xE0BEAC61, 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97,
0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, 0x16441B82,
0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A, 0xFA1799EF, 0x314B4A4A,
0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957, 0x15921919, 0xDECECABC, 0x585AB812,
0x93066BB7, 0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1, 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA,
0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC
},
new uint[]
{
0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E, 0x33EF4E67,
0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9, 0x67DE9CCE, 0xC1A9977A,
0xF0418DE7, 0x56368653, 0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240, 0x5431D2A9, 0xF246D91D, 0xC3AEC380,
0x65D9C834, 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27, 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301,
0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8,
0xAE6A585C, 0x9F8242C1, 0x39F54975, 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, 0xFA5B8AF5,
0xCBB39068, 0x6DC49BDC, 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F,
0x5E2BD5BB, 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7,
0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590, 0x23D5E9B7,
0x85A2E203, 0xB44AF89E, 0x123DF32A, 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739, 0x103AA7D0, 0xB64DAC64,
0x87A5B6F9, 0x21D2BD4D, 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E, 0x8BB64CE5, 0x2DC14751, 0x1C295DCC,
0xBA5E5678, 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B, 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F,
0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438,
0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5, 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, 0x8DBFB1EB,
0xBC57AB76, 0x1A20A0C2, 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8,
0x4DB1D47C, 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B,
0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1, 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2, 0xDC27385B,
0x7A5033EF, 0x4BB82972, 0xEDCF22C6, 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5, 0x47ABD36E, 0xE1DCD8DA,
0xD034C247, 0x7643C9F3, 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0, 0x74449D09, 0xD23396BD, 0xE3DB8C20,
0x45AC8794, 0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387, 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D,
0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E, 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4,
0x41A22E60, 0x704A34FD, 0xD63D3F49, 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, 0x3852BB98, 0x9E25B02C,
0xAFCDAAB1, 0x09BAA105, 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71, 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6,
0x3A55EF62, 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB,
0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC, 0x03A0A617,
0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899, 0x304FE870, 0x9638E3C4,
0xA7D0F959, 0x01A7F2ED, 0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE, 0x647E3AD9, 0xC209316D, 0xF3E12BF0,
0x55962044, 0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457, 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23,
0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30
},
new uint[]
{
0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919, 0xD3E51BB5,
0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC, 0x7CBB312B, 0xB01131B5,
0x3E9E3656, 0xF23436C8, 0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832, 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3,
0x21D12D7D, 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387, 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5,
0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00, 0xAED97719,
0x62737787, 0xECFC7064, 0x205670FA, 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, 0xCD2D5D19,
0x43A25AFA, 0x8F085A64, 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, 0x1EC846AC, 0x9047414F,
0x5CED41D1, 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4,
0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, 0x5526F3C6,
0x998CF358, 0x1703F4BB, 0xDBA9F425, 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, 0x86C3E873, 0x4A69E8ED,
0xC4E6EF0E, 0x084CEF90, 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6,
0x5E64A758, 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED,
0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217, 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A,
0xE4B09FF4, 0x6A3F9817, 0xA6959889, 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, 0x37558441,
0xB9DA83A2, 0x7570833C, 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, 0x1BDB8BBE, 0x95548C5D,
0x59FE8CC3, 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776,
0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312, 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, 0xFC65AF44,
0x30CFAFDA, 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, 0xAA4DE78C, 0x66E7E712,
0xE868E0F1, 0x24C2E06F, 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44,
0xF727FBDA, 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520, 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144,
0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE, 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8,
0x4DF3C376, 0xC37CC495, 0x0FD6C40B, 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, 0xFEEC49CD, 0x32464953,
0xBCC94EB0, 0x70634E2E, 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505,
0xA386559B, 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05,
0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, 0x83D02561,
0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78, 0x50353ED4, 0x9C9F3E4A,
0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD, 0xFF6B144A, 0x33C114D4, 0xBD4E1337,
0x71E413A9, 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C,
0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6
}
};
readonly uint _finalSeed;
readonly IntPtr _nativeContext;
readonly uint[][]? _table;
readonly bool _useIso;
readonly bool _useNative;
uint _hashInt;
/// <summary>Initializes the CRC32 table and seed as CRC32-ISO</summary>
public Crc32Context()
{
_hashInt = CRC32_ISO_SEED;
_finalSeed = CRC32_ISO_SEED;
_table = ISOCrc32Table;
_useIso = true;
if(!Native.IsSupported)
return;
_nativeContext = crc32_init();
_useNative = _nativeContext != IntPtr.Zero;
}
/// <summary>Initializes the CRC32 table with a custom polynomial and seed</summary>
public Crc32Context(uint polynomial, uint seed)
{
_hashInt = seed;
_finalSeed = seed;
_useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
if(Native.IsSupported && _useIso)
{
_nativeContext = crc32_init();
_useNative = _nativeContext != IntPtr.Zero;
}
else
_table = GenerateTable(polynomial);
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "CRC-32";
/// <inheritdoc />
public Guid Id => new("BCC4E18A-79CD-4B52-8A57-2B599E5176B3");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) =>
Step(ref _hashInt, _table!, data, len, _useIso, _useNative, _nativeContext);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint crc = _hashInt ^ _finalSeed;
if(!_useNative || !_useIso)
return BigEndianBitConverter.GetBytes(crc);
crc32_final(_nativeContext, ref crc);
crc32_free(_nativeContext);
return BigEndianBitConverter.GetBytes(crc);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
uint crc = _hashInt ^ _finalSeed;
var crc32Output = new StringBuilder();
if(_useNative && _useIso)
{
crc32_final(_nativeContext, ref crc);
crc32_free(_nativeContext);
}
for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
crc32Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
return crc32Output.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr crc32_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc32_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc32_final(IntPtr ctx, ref uint crc);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void crc32_free(IntPtr ctx);
static uint[][] GenerateTable(uint polynomial)
{
var table = new uint[8][];
for(var i = 0; i < 8; i++)
table[i] = new uint[256];
for(var i = 0; i < 256; i++)
{
var entry = (uint)i;
for(var j = 0; j < 8; j++)
{
if((entry & 1) == 1)
entry = entry >> 1 ^ polynomial;
else
entry >>= 1;
}
table[0][i] = entry;
}
for(var slice = 1; slice < 8; slice++)
for(var i = 0; i < 256; i++)
table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF];
return table;
}
static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso, bool useNative,
IntPtr nativeContext)
{
if(useNative && useIso)
{
crc32_update(nativeContext, data, len);
return;
}
var currentPos = 0;
if(useIso)
{
#if NETCOREAPP3_1_OR_GREATER
if(Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported)
{
// Only works in blocks of 16 bytes
uint blocks = len / 64;
if(blocks > 0)
{
previousCrc = ~Clmul.Step(data, blocks * 64, ~previousCrc);
currentPos = (int)(blocks * 64);
len -= blocks * 64;
}
if(len == 0)
return;
}
#endif
#if NET5_0_OR_GREATER
if(Crc32.Arm64.IsSupported)
{
previousCrc = ArmSimd.Step64(data, len, previousCrc);
return;
}
if(Crc32.IsSupported)
{
previousCrc = ArmSimd.Step32(data, len, previousCrc);
return;
}
#endif
}
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
const int unroll = 4;
const int bytesAtOnce = 8 * unroll;
uint crc = previousCrc;
while(len >= bytesAtOnce)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
uint one = BitConverter.ToUInt32(data, currentPos) ^ crc;
currentPos += 4;
var two = BitConverter.ToUInt32(data, currentPos);
currentPos += 4;
crc = table[0][two >> 24 & 0xFF] ^
table[1][two >> 16 & 0xFF] ^
table[2][two >> 8 & 0xFF] ^
table[3][two & 0xFF] ^
table[4][one >> 24 & 0xFF] ^
table[5][one >> 16 & 0xFF] ^
table[6][one >> 8 & 0xFF] ^
table[7][one & 0xFF];
}
len -= bytesAtOnce;
}
while(len-- != 0)
crc = crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]];
previousCrc = crc;
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, uint polynomial, uint seed)
{
bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative && useIso)
{
nativeContext = crc32_init();
useNative = nativeContext != IntPtr.Zero;
}
var fileStream = new FileStream(filename, FileMode.Open);
uint localHashInt = seed;
uint[][] localTable = GenerateTable(polynomial);
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
Step(ref localHashInt, localTable, buffer, (uint)read, useIso, useNative, nativeContext);
read = fileStream.EnsureRead(buffer, 0, 65536);
}
localHashInt ^= seed;
if(useNative && useIso)
{
crc32_final(nativeContext, ref localHashInt);
crc32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash)
crc32Output.Append(h.ToString("x2"));
fileStream.Close();
return crc32Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
{
bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative && useIso)
{
nativeContext = crc32_init();
useNative = nativeContext != IntPtr.Zero;
}
uint localHashInt = seed;
uint[][] localTable = GenerateTable(polynomial);
Step(ref localHashInt, localTable, data, len, useIso, useNative, nativeContext);
localHashInt ^= seed;
if(useNative && useIso)
{
crc32_final(nativeContext, ref localHashInt);
crc32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc32Output = new StringBuilder();
foreach(byte h in hash)
crc32Output.Append(h.ToString("x2"));
return crc32Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -1,111 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : clmul.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute the CRC64 using a parallelized folding approach with the PCLMULQDQ
// instruction.
//
// --[ License ] --------------------------------------------------------------
//
// This file is under the public domain:
// https://github.com/rawrunprotected/crc
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru.Checksums.CRC64;
static class Clmul
{
static readonly byte[] _shuffleMasks =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void ShiftRight128(Vector128<ulong> initial, uint n, out Vector128<ulong> outLeft,
out Vector128<ulong> outRight)
{
uint maskPos = 16 - n;
var maskA = Vector128.Create(_shuffleMasks[maskPos], _shuffleMasks[maskPos + 1], _shuffleMasks[maskPos + 2],
_shuffleMasks[maskPos + 3], _shuffleMasks[maskPos + 4], _shuffleMasks[maskPos + 5],
_shuffleMasks[maskPos + 6], _shuffleMasks[maskPos + 7], _shuffleMasks[maskPos + 8],
_shuffleMasks[maskPos + 9], _shuffleMasks[maskPos + 10],
_shuffleMasks[maskPos + 11], _shuffleMasks[maskPos + 12],
_shuffleMasks[maskPos + 13], _shuffleMasks[maskPos + 14],
_shuffleMasks[maskPos + 15]);
Vector128<byte> maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128<byte>.Zero, Vector128<byte>.Zero));
outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64();
outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Vector128<ulong> Fold(Vector128<ulong> input, Vector128<ulong> foldConstants) =>
Sse2.Xor(Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x00),
Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x11));
internal static ulong Step(ulong crc, byte[] data, uint length)
{
var bufPos = 16;
const ulong k1 = 0xe05dd497ca393ae4;
const ulong k2 = 0xdabe95afc7875f40;
const ulong mu = 0x9c3e466c172963d5;
const ulong pol = 0x92d8af2baf0e1e85;
var foldConstants1 = Vector128.Create(k1, k2);
var foldConstants2 = Vector128.Create(mu, pol);
var initialCrc = Vector128.Create(~crc, 0);
length -= 16;
// Initial CRC can simply be added to data
ShiftRight128(initialCrc, 0, out Vector128<ulong> crc0, out Vector128<ulong> crc1);
Vector128<ulong> accumulator =
Sse2.Xor(Fold(Sse2.Xor(crc0, Vector128.Create(BitConverter.ToUInt64(data, 0), BitConverter.ToUInt64(data, 8))), foldConstants1),
crc1);
while(length >= 32)
{
accumulator =
Fold(Sse2.Xor(Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8)), accumulator),
foldConstants1);
length -= 16;
bufPos += 16;
}
Vector128<ulong> p = Sse2.Xor(accumulator,
Vector128.Create(BitConverter.ToUInt64(data, bufPos),
BitConverter.ToUInt64(data, bufPos + 8)));
Vector128<ulong> r = Sse2.Xor(Pclmulqdq.CarrylessMultiply(p, foldConstants1, 0x10),
Sse2.ShiftRightLogical128BitLane(p, 8));
// Final Barrett reduction
Vector128<ulong> t1 = Pclmulqdq.CarrylessMultiply(r, foldConstants2, 0x00);
Vector128<ulong> t2 =
Sse2.Xor(Sse2.Xor(Pclmulqdq.CarrylessMultiply(t1, foldConstants2, 0x10), Sse2.ShiftLeftLogical128BitLane(t1, 8)),
r);
return ~((ulong)Sse41.Extract(t2.AsUInt32(), 3) << 32 | Sse41.Extract(t2.AsUInt32(), 2));
}
}
#endif

View File

@@ -1,608 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : CRC64Context.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements a CRC64 algorithm.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
#if NETCOREAPP3_1_OR_GREATER
using System.Runtime.Intrinsics.X86;
#endif
using System.Text;
#if NETCOREAPP3_1_OR_GREATER
using Aaru.Checksums.CRC64;
#endif
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements a CRC64 algorithm</summary>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
public sealed class Crc64Context : IChecksum
{
/// <summary>ECMA CRC64 polynomial</summary>
const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42;
/// <summary>ECMA CRC64 seed</summary>
const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF;
static readonly ulong[][] _ecmaCrc64Table =
{
new ulong[]
{
0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33,
0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309,
0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E,
0xCBDB3E64AB761D61, 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D,
0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, 0x8A3A2631AE2DDA2F,
0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73,
0x056ED3E2F9E22447, 0xB6409F5CFA457B28, 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9,
0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95,
0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7,
0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4,
0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3,
0xBAD65A25A73D0BDC, 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989,
0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, 0x64B62BCAEBC387A1,
0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD,
0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C,
0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0,
0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB,
0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1,
0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6,
0xD2F6B4961186FC89, 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407,
0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, 0x6820EEB3B6BBF755,
0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609,
0xE7741B60E174093D, 0x545A57DEE2D35652, 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21,
0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D,
0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F,
0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, 0xC96C5795D7870F42, 0x7A421B2BD420502D,
0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A,
0xF516EEF883EFAE45, 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10,
0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, 0xB4F7F6AD86B4690B,
0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857,
0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536,
0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A,
0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3,
0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9,
0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE,
0xF9802B81DE97DEB1, 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD,
0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, 0xB86133D4DBCC19FF,
0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3,
0x3735C6078C03E797, 0x841B8AB98FA4B8F8, 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8,
0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4,
0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6,
0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5,
0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2,
0xEC3B640A391F4FAD, 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8,
0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, 0x56ED3E2F9E224471,
0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D,
0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C,
0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910,
0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B,
0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, 0xDCD7181E300F9E5E, 0x6FF954A033A8C131,
0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036,
0xE0ADA17364673F59
},
new ulong[]
{
0x0000000000000000, 0x54E979925CD0F10D, 0xA9D2F324B9A1E21A, 0xFD3B8AB6E5711317, 0xC17D4962DC4DDAB1,
0x959430F0809D2BBC, 0x68AFBA4665EC38AB, 0x3C46C3D4393CC9A6, 0x10223DEE1795ABE7, 0x44CB447C4B455AEA,
0xB9F0CECAAE3449FD, 0xED19B758F2E4B8F0, 0xD15F748CCBD87156, 0x85B60D1E9708805B, 0x788D87A87279934C,
0x2C64FE3A2EA96241, 0x20447BDC2F2B57CE, 0x74AD024E73FBA6C3, 0x899688F8968AB5D4, 0xDD7FF16ACA5A44D9,
0xE13932BEF3668D7F, 0xB5D04B2CAFB67C72, 0x48EBC19A4AC76F65, 0x1C02B80816179E68, 0x3066463238BEFC29,
0x648F3FA0646E0D24, 0x99B4B516811F1E33, 0xCD5DCC84DDCFEF3E, 0xF11B0F50E4F32698, 0xA5F276C2B823D795,
0x58C9FC745D52C482, 0x0C2085E60182358F, 0x4088F7B85E56AF9C, 0x14618E2A02865E91, 0xE95A049CE7F74D86,
0xBDB37D0EBB27BC8B, 0x81F5BEDA821B752D, 0xD51CC748DECB8420, 0x28274DFE3BBA9737, 0x7CCE346C676A663A,
0x50AACA5649C3047B, 0x0443B3C41513F576, 0xF9783972F062E661, 0xAD9140E0ACB2176C, 0x91D78334958EDECA,
0xC53EFAA6C95E2FC7, 0x380570102C2F3CD0, 0x6CEC098270FFCDDD, 0x60CC8C64717DF852, 0x3425F5F62DAD095F,
0xC91E7F40C8DC1A48, 0x9DF706D2940CEB45, 0xA1B1C506AD3022E3, 0xF558BC94F1E0D3EE, 0x086336221491C0F9,
0x5C8A4FB0484131F4, 0x70EEB18A66E853B5, 0x2407C8183A38A2B8, 0xD93C42AEDF49B1AF, 0x8DD53B3C839940A2,
0xB193F8E8BAA58904, 0xE57A817AE6757809, 0x18410BCC03046B1E, 0x4CA8725E5FD49A13, 0x8111EF70BCAD5F38,
0xD5F896E2E07DAE35, 0x28C31C54050CBD22, 0x7C2A65C659DC4C2F, 0x406CA61260E08589, 0x1485DF803C307484,
0xE9BE5536D9416793, 0xBD572CA48591969E, 0x9133D29EAB38F4DF, 0xC5DAAB0CF7E805D2, 0x38E121BA129916C5,
0x6C0858284E49E7C8, 0x504E9BFC77752E6E, 0x04A7E26E2BA5DF63, 0xF99C68D8CED4CC74, 0xAD75114A92043D79,
0xA15594AC938608F6, 0xF5BCED3ECF56F9FB, 0x088767882A27EAEC, 0x5C6E1E1A76F71BE1, 0x6028DDCE4FCBD247,
0x34C1A45C131B234A, 0xC9FA2EEAF66A305D, 0x9D135778AABAC150, 0xB177A9428413A311, 0xE59ED0D0D8C3521C,
0x18A55A663DB2410B, 0x4C4C23F46162B006, 0x700AE020585E79A0, 0x24E399B2048E88AD, 0xD9D81304E1FF9BBA,
0x8D316A96BD2F6AB7, 0xC19918C8E2FBF0A4, 0x9570615ABE2B01A9, 0x684BEBEC5B5A12BE, 0x3CA2927E078AE3B3,
0x00E451AA3EB62A15, 0x540D28386266DB18, 0xA936A28E8717C80F, 0xFDDFDB1CDBC73902, 0xD1BB2526F56E5B43,
0x85525CB4A9BEAA4E, 0x7869D6024CCFB959, 0x2C80AF90101F4854, 0x10C66C44292381F2, 0x442F15D675F370FF,
0xB9149F60908263E8, 0xEDFDE6F2CC5292E5, 0xE1DD6314CDD0A76A, 0xB5341A8691005667, 0x480F903074714570,
0x1CE6E9A228A1B47D, 0x20A02A76119D7DDB, 0x744953E44D4D8CD6, 0x8972D952A83C9FC1, 0xDD9BA0C0F4EC6ECC,
0xF1FF5EFADA450C8D, 0xA51627688695FD80, 0x582DADDE63E4EE97, 0x0CC4D44C3F341F9A, 0x308217980608D63C,
0x646B6E0A5AD82731, 0x9950E4BCBFA93426, 0xCDB99D2EE379C52B, 0x90FB71CAD654A0F5, 0xC41208588A8451F8,
0x392982EE6FF542EF, 0x6DC0FB7C3325B3E2, 0x518638A80A197A44, 0x056F413A56C98B49, 0xF854CB8CB3B8985E,
0xACBDB21EEF686953, 0x80D94C24C1C10B12, 0xD43035B69D11FA1F, 0x290BBF007860E908, 0x7DE2C69224B01805,
0x41A405461D8CD1A3, 0x154D7CD4415C20AE, 0xE876F662A42D33B9, 0xBC9F8FF0F8FDC2B4, 0xB0BF0A16F97FF73B,
0xE4567384A5AF0636, 0x196DF93240DE1521, 0x4D8480A01C0EE42C, 0x71C2437425322D8A, 0x252B3AE679E2DC87,
0xD810B0509C93CF90, 0x8CF9C9C2C0433E9D, 0xA09D37F8EEEA5CDC, 0xF4744E6AB23AADD1, 0x094FC4DC574BBEC6,
0x5DA6BD4E0B9B4FCB, 0x61E07E9A32A7866D, 0x350907086E777760, 0xC8328DBE8B066477, 0x9CDBF42CD7D6957A,
0xD073867288020F69, 0x849AFFE0D4D2FE64, 0x79A1755631A3ED73, 0x2D480CC46D731C7E, 0x110ECF10544FD5D8,
0x45E7B682089F24D5, 0xB8DC3C34EDEE37C2, 0xEC3545A6B13EC6CF, 0xC051BB9C9F97A48E, 0x94B8C20EC3475583,
0x698348B826364694, 0x3D6A312A7AE6B799, 0x012CF2FE43DA7E3F, 0x55C58B6C1F0A8F32, 0xA8FE01DAFA7B9C25,
0xFC177848A6AB6D28, 0xF037FDAEA72958A7, 0xA4DE843CFBF9A9AA, 0x59E50E8A1E88BABD, 0x0D0C771842584BB0,
0x314AB4CC7B648216, 0x65A3CD5E27B4731B, 0x989847E8C2C5600C, 0xCC713E7A9E159101, 0xE015C040B0BCF340,
0xB4FCB9D2EC6C024D, 0x49C73364091D115A, 0x1D2E4AF655CDE057, 0x216889226CF129F1, 0x7581F0B03021D8FC,
0x88BA7A06D550CBEB, 0xDC53039489803AE6, 0x11EA9EBA6AF9FFCD, 0x4503E72836290EC0, 0xB8386D9ED3581DD7,
0xECD1140C8F88ECDA, 0xD097D7D8B6B4257C, 0x847EAE4AEA64D471, 0x794524FC0F15C766, 0x2DAC5D6E53C5366B,
0x01C8A3547D6C542A, 0x5521DAC621BCA527, 0xA81A5070C4CDB630, 0xFCF329E2981D473D, 0xC0B5EA36A1218E9B,
0x945C93A4FDF17F96, 0x6967191218806C81, 0x3D8E608044509D8C, 0x31AEE56645D2A803, 0x65479CF41902590E,
0x987C1642FC734A19, 0xCC956FD0A0A3BB14, 0xF0D3AC04999F72B2, 0xA43AD596C54F83BF, 0x59015F20203E90A8,
0x0DE826B27CEE61A5, 0x218CD888524703E4, 0x7565A11A0E97F2E9, 0x885E2BACEBE6E1FE, 0xDCB7523EB73610F3,
0xE0F191EA8E0AD955, 0xB418E878D2DA2858, 0x492362CE37AB3B4F, 0x1DCA1B5C6B7BCA42, 0x5162690234AF5051,
0x058B1090687FA15C, 0xF8B09A268D0EB24B, 0xAC59E3B4D1DE4346, 0x901F2060E8E28AE0, 0xC4F659F2B4327BED,
0x39CDD344514368FA, 0x6D24AAD60D9399F7, 0x414054EC233AFBB6, 0x15A92D7E7FEA0ABB, 0xE892A7C89A9B19AC,
0xBC7BDE5AC64BE8A1, 0x803D1D8EFF772107, 0xD4D4641CA3A7D00A, 0x29EFEEAA46D6C31D, 0x7D0697381A063210,
0x712612DE1B84079F, 0x25CF6B4C4754F692, 0xD8F4E1FAA225E585, 0x8C1D9868FEF51488, 0xB05B5BBCC7C9DD2E,
0xE4B2222E9B192C23, 0x1989A8987E683F34, 0x4D60D10A22B8CE39, 0x61042F300C11AC78, 0x35ED56A250C15D75,
0xC8D6DC14B5B04E62, 0x9C3FA586E960BF6F, 0xA0796652D05C76C9, 0xF4901FC08C8C87C4, 0x09AB957669FD94D3,
0x5D42ECE4352D65DE
},
new ulong[]
{
0x0000000000000000, 0x3F0BE14A916A6DCB, 0x7E17C29522D4DB96, 0x411C23DFB3BEB65D, 0xFC2F852A45A9B72C,
0xC3246460D4C3DAE7, 0x823847BF677D6CBA, 0xBD33A6F5F6170171, 0x6A87A57F245D70DD, 0x558C4435B5371D16,
0x149067EA0689AB4B, 0x2B9B86A097E3C680, 0x96A8205561F4C7F1, 0xA9A3C11FF09EAA3A, 0xE8BFE2C043201C67,
0xD7B4038AD24A71AC, 0xD50F4AFE48BAE1BA, 0xEA04ABB4D9D08C71, 0xAB18886B6A6E3A2C, 0x94136921FB0457E7,
0x2920CFD40D135696, 0x162B2E9E9C793B5D, 0x57370D412FC78D00, 0x683CEC0BBEADE0CB, 0xBF88EF816CE79167,
0x80830ECBFD8DFCAC, 0xC19F2D144E334AF1, 0xFE94CC5EDF59273A, 0x43A76AAB294E264B, 0x7CAC8BE1B8244B80,
0x3DB0A83E0B9AFDDD, 0x02BB49749AF09016, 0x38C63AD73E7BDDF1, 0x07CDDB9DAF11B03A, 0x46D1F8421CAF0667,
0x79DA19088DC56BAC, 0xC4E9BFFD7BD26ADD, 0xFBE25EB7EAB80716, 0xBAFE7D685906B14B, 0x85F59C22C86CDC80,
0x52419FA81A26AD2C, 0x6D4A7EE28B4CC0E7, 0x2C565D3D38F276BA, 0x135DBC77A9981B71, 0xAE6E1A825F8F1A00,
0x9165FBC8CEE577CB, 0xD079D8177D5BC196, 0xEF72395DEC31AC5D, 0xEDC9702976C13C4B, 0xD2C29163E7AB5180,
0x93DEB2BC5415E7DD, 0xACD553F6C57F8A16, 0x11E6F50333688B67, 0x2EED1449A202E6AC, 0x6FF1379611BC50F1,
0x50FAD6DC80D63D3A, 0x874ED556529C4C96, 0xB845341CC3F6215D, 0xF95917C370489700, 0xC652F689E122FACB,
0x7B61507C1735FBBA, 0x446AB136865F9671, 0x057692E935E1202C, 0x3A7D73A3A48B4DE7, 0x718C75AE7CF7BBE2,
0x4E8794E4ED9DD629, 0x0F9BB73B5E236074, 0x30905671CF490DBF, 0x8DA3F084395E0CCE, 0xB2A811CEA8346105,
0xF3B432111B8AD758, 0xCCBFD35B8AE0BA93, 0x1B0BD0D158AACB3F, 0x2400319BC9C0A6F4, 0x651C12447A7E10A9,
0x5A17F30EEB147D62, 0xE72455FB1D037C13, 0xD82FB4B18C6911D8, 0x9933976E3FD7A785, 0xA6387624AEBDCA4E,
0xA4833F50344D5A58, 0x9B88DE1AA5273793, 0xDA94FDC5169981CE, 0xE59F1C8F87F3EC05, 0x58ACBA7A71E4ED74,
0x67A75B30E08E80BF, 0x26BB78EF533036E2, 0x19B099A5C25A5B29, 0xCE049A2F10102A85, 0xF10F7B65817A474E,
0xB01358BA32C4F113, 0x8F18B9F0A3AE9CD8, 0x322B1F0555B99DA9, 0x0D20FE4FC4D3F062, 0x4C3CDD90776D463F,
0x73373CDAE6072BF4, 0x494A4F79428C6613, 0x7641AE33D3E60BD8, 0x375D8DEC6058BD85, 0x08566CA6F132D04E,
0xB565CA530725D13F, 0x8A6E2B19964FBCF4, 0xCB7208C625F10AA9, 0xF479E98CB49B6762, 0x23CDEA0666D116CE,
0x1CC60B4CF7BB7B05, 0x5DDA28934405CD58, 0x62D1C9D9D56FA093, 0xDFE26F2C2378A1E2, 0xE0E98E66B212CC29,
0xA1F5ADB901AC7A74, 0x9EFE4CF390C617BF, 0x9C4505870A3687A9, 0xA34EE4CD9B5CEA62, 0xE252C71228E25C3F,
0xDD592658B98831F4, 0x606A80AD4F9F3085, 0x5F6161E7DEF55D4E, 0x1E7D42386D4BEB13, 0x2176A372FC2186D8,
0xF6C2A0F82E6BF774, 0xC9C941B2BF019ABF, 0x88D5626D0CBF2CE2, 0xB7DE83279DD54129, 0x0AED25D26BC24058,
0x35E6C498FAA82D93, 0x74FAE74749169BCE, 0x4BF1060DD87CF605, 0xE318EB5CF9EF77C4, 0xDC130A1668851A0F,
0x9D0F29C9DB3BAC52, 0xA204C8834A51C199, 0x1F376E76BC46C0E8, 0x203C8F3C2D2CAD23, 0x6120ACE39E921B7E,
0x5E2B4DA90FF876B5, 0x899F4E23DDB20719, 0xB694AF694CD86AD2, 0xF7888CB6FF66DC8F, 0xC8836DFC6E0CB144,
0x75B0CB09981BB035, 0x4ABB2A430971DDFE, 0x0BA7099CBACF6BA3, 0x34ACE8D62BA50668, 0x3617A1A2B155967E,
0x091C40E8203FFBB5, 0x4800633793814DE8, 0x770B827D02EB2023, 0xCA382488F4FC2152, 0xF533C5C265964C99,
0xB42FE61DD628FAC4, 0x8B2407574742970F, 0x5C9004DD9508E6A3, 0x639BE59704628B68, 0x2287C648B7DC3D35,
0x1D8C270226B650FE, 0xA0BF81F7D0A1518F, 0x9FB460BD41CB3C44, 0xDEA84362F2758A19, 0xE1A3A228631FE7D2,
0xDBDED18BC794AA35, 0xE4D530C156FEC7FE, 0xA5C9131EE54071A3, 0x9AC2F254742A1C68, 0x27F154A1823D1D19,
0x18FAB5EB135770D2, 0x59E69634A0E9C68F, 0x66ED777E3183AB44, 0xB15974F4E3C9DAE8, 0x8E5295BE72A3B723,
0xCF4EB661C11D017E, 0xF045572B50776CB5, 0x4D76F1DEA6606DC4, 0x727D1094370A000F, 0x3361334B84B4B652,
0x0C6AD20115DEDB99, 0x0ED19B758F2E4B8F, 0x31DA7A3F1E442644, 0x70C659E0ADFA9019, 0x4FCDB8AA3C90FDD2,
0xF2FE1E5FCA87FCA3, 0xCDF5FF155BED9168, 0x8CE9DCCAE8532735, 0xB3E23D8079394AFE, 0x64563E0AAB733B52,
0x5B5DDF403A195699, 0x1A41FC9F89A7E0C4, 0x254A1DD518CD8D0F, 0x9879BB20EEDA8C7E, 0xA7725A6A7FB0E1B5,
0xE66E79B5CC0E57E8, 0xD96598FF5D643A23, 0x92949EF28518CC26, 0xAD9F7FB81472A1ED, 0xEC835C67A7CC17B0,
0xD388BD2D36A67A7B, 0x6EBB1BD8C0B17B0A, 0x51B0FA9251DB16C1, 0x10ACD94DE265A09C, 0x2FA73807730FCD57,
0xF8133B8DA145BCFB, 0xC718DAC7302FD130, 0x8604F9188391676D, 0xB90F185212FB0AA6, 0x043CBEA7E4EC0BD7,
0x3B375FED7586661C, 0x7A2B7C32C638D041, 0x45209D785752BD8A, 0x479BD40CCDA22D9C, 0x789035465CC84057,
0x398C1699EF76F60A, 0x0687F7D37E1C9BC1, 0xBBB45126880B9AB0, 0x84BFB06C1961F77B, 0xC5A393B3AADF4126,
0xFAA872F93BB52CED, 0x2D1C7173E9FF5D41, 0x121790397895308A, 0x530BB3E6CB2B86D7, 0x6C0052AC5A41EB1C,
0xD133F459AC56EA6D, 0xEE3815133D3C87A6, 0xAF2436CC8E8231FB, 0x902FD7861FE85C30, 0xAA52A425BB6311D7,
0x9559456F2A097C1C, 0xD44566B099B7CA41, 0xEB4E87FA08DDA78A, 0x567D210FFECAA6FB, 0x6976C0456FA0CB30,
0x286AE39ADC1E7D6D, 0x176102D04D7410A6, 0xC0D5015A9F3E610A, 0xFFDEE0100E540CC1, 0xBEC2C3CFBDEABA9C,
0x81C922852C80D757, 0x3CFA8470DA97D626, 0x03F1653A4BFDBBED, 0x42ED46E5F8430DB0, 0x7DE6A7AF6929607B,
0x7F5DEEDBF3D9F06D, 0x40560F9162B39DA6, 0x014A2C4ED10D2BFB, 0x3E41CD0440674630, 0x83726BF1B6704741,
0xBC798ABB271A2A8A, 0xFD65A96494A49CD7, 0xC26E482E05CEF11C, 0x15DA4BA4D78480B0, 0x2AD1AAEE46EEED7B,
0x6BCD8931F5505B26, 0x54C6687B643A36ED, 0xE9F5CE8E922D379C, 0xD6FE2FC403475A57, 0x97E20C1BB0F9EC0A,
0xA8E9ED51219381C1
},
new ulong[]
{
0x0000000000000000, 0x1DEE8A5E222CA1DC, 0x3BDD14BC445943B8, 0x26339EE26675E264, 0x77BA297888B28770,
0x6A54A326AA9E26AC, 0x4C673DC4CCEBC4C8, 0x5189B79AEEC76514, 0xEF7452F111650EE0, 0xF29AD8AF3349AF3C,
0xD4A9464D553C4D58, 0xC947CC137710EC84, 0x98CE7B8999D78990, 0x8520F1D7BBFB284C, 0xA3136F35DD8ECA28,
0xBEFDE56BFFA26BF4, 0x4C300AC98DC40345, 0x51DE8097AFE8A299, 0x77ED1E75C99D40FD, 0x6A03942BEBB1E121,
0x3B8A23B105768435, 0x2664A9EF275A25E9, 0x0057370D412FC78D, 0x1DB9BD5363036651, 0xA34458389CA10DA5,
0xBEAAD266BE8DAC79, 0x98994C84D8F84E1D, 0x8577C6DAFAD4EFC1, 0xD4FE714014138AD5, 0xC910FB1E363F2B09,
0xEF2365FC504AC96D, 0xF2CDEFA2726668B1, 0x986015931B88068A, 0x858E9FCD39A4A756, 0xA3BD012F5FD14532,
0xBE538B717DFDE4EE, 0xEFDA3CEB933A81FA, 0xF234B6B5B1162026, 0xD4072857D763C242, 0xC9E9A209F54F639E,
0x771447620AED086A, 0x6AFACD3C28C1A9B6, 0x4CC953DE4EB44BD2, 0x5127D9806C98EA0E, 0x00AE6E1A825F8F1A,
0x1D40E444A0732EC6, 0x3B737AA6C606CCA2, 0x269DF0F8E42A6D7E, 0xD4501F5A964C05CF, 0xC9BE9504B460A413,
0xEF8D0BE6D2154677, 0xF26381B8F039E7AB, 0xA3EA36221EFE82BF, 0xBE04BC7C3CD22363, 0x9837229E5AA7C107,
0x85D9A8C0788B60DB, 0x3B244DAB87290B2F, 0x26CAC7F5A505AAF3, 0x00F95917C3704897, 0x1D17D349E15CE94B,
0x4C9E64D30F9B8C5F, 0x5170EE8D2DB72D83, 0x7743706F4BC2CFE7, 0x6AADFA3169EE6E3B, 0xA218840D981E1391,
0xBFF60E53BA32B24D, 0x99C590B1DC475029, 0x842B1AEFFE6BF1F5, 0xD5A2AD7510AC94E1, 0xC84C272B3280353D,
0xEE7FB9C954F5D759, 0xF391339776D97685, 0x4D6CD6FC897B1D71, 0x50825CA2AB57BCAD, 0x76B1C240CD225EC9,
0x6B5F481EEF0EFF15, 0x3AD6FF8401C99A01, 0x273875DA23E53BDD, 0x010BEB384590D9B9, 0x1CE5616667BC7865,
0xEE288EC415DA10D4, 0xF3C6049A37F6B108, 0xD5F59A785183536C, 0xC81B102673AFF2B0, 0x9992A7BC9D6897A4,
0x847C2DE2BF443678, 0xA24FB300D931D41C, 0xBFA1395EFB1D75C0, 0x015CDC3504BF1E34, 0x1CB2566B2693BFE8,
0x3A81C88940E65D8C, 0x276F42D762CAFC50, 0x76E6F54D8C0D9944, 0x6B087F13AE213898, 0x4D3BE1F1C854DAFC,
0x50D56BAFEA787B20, 0x3A78919E8396151B, 0x27961BC0A1BAB4C7, 0x01A58522C7CF56A3, 0x1C4B0F7CE5E3F77F,
0x4DC2B8E60B24926B, 0x502C32B8290833B7, 0x761FAC5A4F7DD1D3, 0x6BF126046D51700F, 0xD50CC36F92F31BFB,
0xC8E24931B0DFBA27, 0xEED1D7D3D6AA5843, 0xF33F5D8DF486F99F, 0xA2B6EA171A419C8B, 0xBF586049386D3D57,
0x996BFEAB5E18DF33, 0x848574F57C347EEF, 0x76489B570E52165E, 0x6BA611092C7EB782, 0x4D958FEB4A0B55E6,
0x507B05B56827F43A, 0x01F2B22F86E0912E, 0x1C1C3871A4CC30F2, 0x3A2FA693C2B9D296, 0x27C12CCDE095734A,
0x993CC9A61F3718BE, 0x84D243F83D1BB962, 0xA2E1DD1A5B6E5B06, 0xBF0F57447942FADA, 0xEE86E0DE97859FCE,
0xF3686A80B5A93E12, 0xD55BF462D3DCDC76, 0xC8B57E3CF1F07DAA, 0xD6E9A7309F3239A7, 0xCB072D6EBD1E987B,
0xED34B38CDB6B7A1F, 0xF0DA39D2F947DBC3, 0xA1538E481780BED7, 0xBCBD041635AC1F0B, 0x9A8E9AF453D9FD6F,
0x876010AA71F55CB3, 0x399DF5C18E573747, 0x24737F9FAC7B969B, 0x0240E17DCA0E74FF, 0x1FAE6B23E822D523,
0x4E27DCB906E5B037, 0x53C956E724C911EB, 0x75FAC80542BCF38F, 0x6814425B60905253, 0x9AD9ADF912F63AE2,
0x873727A730DA9B3E, 0xA104B94556AF795A, 0xBCEA331B7483D886, 0xED6384819A44BD92, 0xF08D0EDFB8681C4E,
0xD6BE903DDE1DFE2A, 0xCB501A63FC315FF6, 0x75ADFF0803933402, 0x6843755621BF95DE, 0x4E70EBB447CA77BA,
0x539E61EA65E6D666, 0x0217D6708B21B372, 0x1FF95C2EA90D12AE, 0x39CAC2CCCF78F0CA, 0x24244892ED545116,
0x4E89B2A384BA3F2D, 0x536738FDA6969EF1, 0x7554A61FC0E37C95, 0x68BA2C41E2CFDD49, 0x39339BDB0C08B85D,
0x24DD11852E241981, 0x02EE8F674851FBE5, 0x1F0005396A7D5A39, 0xA1FDE05295DF31CD, 0xBC136A0CB7F39011,
0x9A20F4EED1867275, 0x87CE7EB0F3AAD3A9, 0xD647C92A1D6DB6BD, 0xCBA943743F411761, 0xED9ADD965934F505,
0xF07457C87B1854D9, 0x02B9B86A097E3C68, 0x1F5732342B529DB4, 0x3964ACD64D277FD0, 0x248A26886F0BDE0C,
0x7503911281CCBB18, 0x68ED1B4CA3E01AC4, 0x4EDE85AEC595F8A0, 0x53300FF0E7B9597C, 0xEDCDEA9B181B3288,
0xF02360C53A379354, 0xD610FE275C427130, 0xCBFE74797E6ED0EC, 0x9A77C3E390A9B5F8, 0x879949BDB2851424,
0xA1AAD75FD4F0F640, 0xBC445D01F6DC579C, 0x74F1233D072C2A36, 0x691FA96325008BEA, 0x4F2C37814375698E,
0x52C2BDDF6159C852, 0x034B0A458F9EAD46, 0x1EA5801BADB20C9A, 0x38961EF9CBC7EEFE, 0x257894A7E9EB4F22,
0x9B8571CC164924D6, 0x866BFB923465850A, 0xA05865705210676E, 0xBDB6EF2E703CC6B2, 0xEC3F58B49EFBA3A6,
0xF1D1D2EABCD7027A, 0xD7E24C08DAA2E01E, 0xCA0CC656F88E41C2, 0x38C129F48AE82973, 0x252FA3AAA8C488AF,
0x031C3D48CEB16ACB, 0x1EF2B716EC9DCB17, 0x4F7B008C025AAE03, 0x52958AD220760FDF, 0x74A614304603EDBB,
0x69489E6E642F4C67, 0xD7B57B059B8D2793, 0xCA5BF15BB9A1864F, 0xEC686FB9DFD4642B, 0xF186E5E7FDF8C5F7,
0xA00F527D133FA0E3, 0xBDE1D8233113013F, 0x9BD246C15766E35B, 0x863CCC9F754A4287, 0xEC9136AE1CA42CBC,
0xF17FBCF03E888D60, 0xD74C221258FD6F04, 0xCAA2A84C7AD1CED8, 0x9B2B1FD69416ABCC, 0x86C59588B63A0A10,
0xA0F60B6AD04FE874, 0xBD188134F26349A8, 0x03E5645F0DC1225C, 0x1E0BEE012FED8380, 0x383870E3499861E4,
0x25D6FABD6BB4C038, 0x745F4D278573A52C, 0x69B1C779A75F04F0, 0x4F82599BC12AE694, 0x526CD3C5E3064748,
0xA0A13C6791602FF9, 0xBD4FB639B34C8E25, 0x9B7C28DBD5396C41, 0x8692A285F715CD9D, 0xD71B151F19D2A889,
0xCAF59F413BFE0955, 0xECC601A35D8BEB31, 0xF1288BFD7FA74AED, 0x4FD56E9680052119, 0x523BE4C8A22980C5,
0x74087A2AC45C62A1, 0x69E6F074E670C37D, 0x386F47EE08B7A669, 0x2581CDB02A9B07B5, 0x03B253524CEEE5D1,
0x1E5CD90C6EC2440D
}
};
readonly ulong _finalSeed;
readonly IntPtr _nativeContext;
readonly ulong[][]? _table;
readonly bool _useEcma;
readonly bool _useNative;
ulong _hashInt;
/// <summary>Initializes the CRC64 table and seed as CRC64-ECMA</summary>
public Crc64Context()
{
_hashInt = CRC64_ECMA_SEED;
_table = _ecmaCrc64Table;
_finalSeed = CRC64_ECMA_SEED;
_useEcma = true;
if(!Native.IsSupported)
return;
_nativeContext = crc64_init();
_useNative = _nativeContext != IntPtr.Zero;
}
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc64Context(ulong polynomial, ulong seed)
{
_hashInt = seed;
_finalSeed = seed;
_useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
if(Native.IsSupported && _useEcma)
{
_nativeContext = crc64_init();
_useNative = _nativeContext != IntPtr.Zero;
}
else
_table = GenerateTable(polynomial);
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "CRC-64 (ECMA)";
/// <inheritdoc />
public Guid Id => new("D0C0D902-420A-45DA-A235-9D48BEE4B1CE");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) =>
Step(ref _hashInt, _table!, data, len, _useEcma, _useNative, _nativeContext);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
ulong crc = _hashInt ^ _finalSeed;
if(!_useNative || !_useEcma)
return BigEndianBitConverter.GetBytes(crc);
crc64_final(_nativeContext, ref crc);
crc64_free(_nativeContext);
return BigEndianBitConverter.GetBytes(crc);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
ulong crc = _hashInt ^ _finalSeed;
var crc64Output = new StringBuilder();
if(_useNative && _useEcma)
{
crc64_final(_nativeContext, ref crc);
crc64_free(_nativeContext);
}
for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
crc64Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
return crc64Output.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr crc64_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc64_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int crc64_final(IntPtr ctx, ref ulong crc);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void crc64_free(IntPtr ctx);
static ulong[][] GenerateTable(ulong polynomial)
{
var table = new ulong[8][];
for(var i = 0; i < 8; i++)
table[i] = 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;
}
table[0][i] = entry;
}
for(var slice = 1; slice < 4; slice++)
for(var i = 0; i < 256; i++)
table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF];
return table;
}
static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma, bool useNative,
IntPtr nativeContext)
{
if(useNative && useEcma)
{
crc64_update(nativeContext, data, len);
return;
}
var dataOff = 0;
#if NETCOREAPP3_1_OR_GREATER
if(useEcma && Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported)
{
// Only works in blocks of 32 bytes
uint blocks = len / 32;
if(blocks > 0)
{
previousCrc = ~Clmul.Step(~previousCrc, data, blocks * 32);
dataOff = (int)(blocks * 32);
len -= blocks * 32;
}
if(len == 0)
return;
}
#endif
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ulong crc = previousCrc;
if(len > 4)
{
long limit = dataOff + (len & ~(uint)3);
len &= 3;
while(dataOff < limit)
{
var tmp = (uint)(crc ^ BitConverter.ToUInt32(data, dataOff));
dataOff += 4;
crc = table[3][tmp & 0xFF] ^
table[2][tmp >> 8 & 0xFF] ^
crc >> 32 ^
table[1][tmp >> 16 & 0xFF] ^
table[0][tmp >> 24];
}
}
while(len-- != 0)
crc = table[0][data[dataOff++] ^ crc & 0xFF] ^ crc >> 8;
previousCrc = crc;
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
public static byte[] File(string filename)
{
File(filename, out byte[] localHash);
return localHash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed)
{
bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative && useEcma)
{
nativeContext = crc64_init();
useNative = nativeContext != IntPtr.Zero;
}
var fileStream = new FileStream(filename, FileMode.Open);
ulong localHashInt = seed;
ulong[][] localTable = GenerateTable(polynomial);
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
Step(ref localHashInt, localTable, buffer, (uint)read, useEcma, useNative, nativeContext);
read = fileStream.EnsureRead(buffer, 0, 65536);
}
localHashInt ^= seed;
if(useNative && useEcma)
{
crc64_final(nativeContext, ref localHashInt);
crc64_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash)
crc64Output.Append(h.ToString("x2"));
fileStream.Close();
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
/// <param name="polynomial">CRC polynomial</param>
/// <param name="seed">CRC seed</param>
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
{
bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative && useEcma)
{
nativeContext = crc64_init();
useNative = nativeContext != IntPtr.Zero;
}
ulong localHashInt = seed;
ulong[][] localTable = GenerateTable(polynomial);
Step(ref localHashInt, localTable, data, len, useEcma, useNative, nativeContext);
localHashInt ^= seed;
if(useNative && useEcma)
{
crc64_final(nativeContext, ref localHashInt);
crc64_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc64Output = new StringBuilder();
foreach(byte h in hash)
crc64Output.Append(h.ToString("x2"));
return crc64Output.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -1,219 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : neon.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// The Chromium Authors
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute Fletcher32 checksum using NEON vectorization.
//
// --[ License ] --------------------------------------------------------------
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright 2017 The Chromium Authors. All rights reserved.
// ****************************************************************************/
#if NET5_0_OR_GREATER
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
namespace Aaru.Checksums.Fletcher32;
static class Neon
{
internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len)
{
/*
* Split Fletcher-32 into component sums.
*/
uint s1 = preSum1;
uint s2 = preSum2;
var bufPos = 0;
/*
* Process the data in blocks.
*/
const uint block_Size = 1 << 5;
uint blocks = len / block_Size;
len -= blocks * block_Size;
while(blocks != 0)
{
uint n = Fletcher32Context.NMAX / block_Size; /* The NMAX constraint. */
if(n > blocks)
n = blocks;
blocks -= n;
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo FLETCHER_MODULE.
*/
var v_S2 = Vector128.Create(s1 * n, 0, 0, 0);
var v_S1 = Vector128.Create(0u, 0, 0, 0);
Vector128<ushort> v_Column_Sum_1 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> v_Column_Sum_2 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> v_Column_Sum_3 = AdvSimd.DuplicateToVector128((ushort)0);
Vector128<ushort> v_Column_Sum_4 = AdvSimd.DuplicateToVector128((ushort)0);
do
{
/*
* Load 32 input bytes.
*/
var bytes1 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
bufPos += 16;
var bytes2 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
bufPos += 16;
/*
* Add previous block byte sum to v_s2.
*/
v_S2 = AdvSimd.Add(v_S2, v_S1);
/*
* Horizontally add the bytes for s1.
*/
v_S1 =
AdvSimd.AddPairwiseWideningAndAdd(v_S1,
AdvSimd.
AddPairwiseWideningAndAdd(AdvSimd.AddPairwiseWidening(bytes1),
bytes2));
/*
* Vertically add the bytes for s2.
*/
v_Column_Sum_1 = AdvSimd.AddWideningLower(v_Column_Sum_1, bytes1.GetLower());
v_Column_Sum_2 = AdvSimd.AddWideningLower(v_Column_Sum_2, bytes1.GetUpper());
v_Column_Sum_3 = AdvSimd.AddWideningLower(v_Column_Sum_3, bytes2.GetLower());
v_Column_Sum_4 = AdvSimd.AddWideningLower(v_Column_Sum_4, bytes2.GetUpper());
} while(--n != 0);
v_S2 = AdvSimd.ShiftLeftLogical(v_S2, 5);
/*
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
*/
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_1.GetLower(),
Vector64.Create((ushort)32, 31, 30, 29));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_1.GetUpper(),
Vector64.Create((ushort)28, 27, 26, 25));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_2.GetLower(),
Vector64.Create((ushort)24, 23, 22, 21));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_2.GetUpper(),
Vector64.Create((ushort)20, 19, 18, 17));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_3.GetLower(),
Vector64.Create((ushort)16, 15, 14, 13));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_3.GetUpper(),
Vector64.Create((ushort)12, 11, 10, 9));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_4.GetLower(),
Vector64.Create((ushort)8, 7, 6, 5));
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_4.GetUpper(),
Vector64.Create((ushort)4, 3, 2, 1));
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
Vector64<uint> sum1 = AdvSimd.AddPairwise(v_S1.GetLower(), v_S1.GetUpper());
Vector64<uint> sum2 = AdvSimd.AddPairwise(v_S2.GetLower(), v_S2.GetUpper());
Vector64<uint> s1S2 = AdvSimd.AddPairwise(sum1, sum2);
s1 += AdvSimd.Extract(s1S2, 0);
s2 += AdvSimd.Extract(s1S2, 1);
/*
* Reduce.
*/
s1 %= Fletcher32Context.FLETCHER_MODULE;
s2 %= Fletcher32Context.FLETCHER_MODULE;
}
/*
* Handle leftover data.
*/
if(len != 0)
{
if(len >= 16)
{
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
len -= 16;
}
while(len-- != 0)
s2 += s1 += buf[bufPos++];
if(s1 >= Fletcher32Context.FLETCHER_MODULE)
s1 -= Fletcher32Context.FLETCHER_MODULE;
s2 %= Fletcher32Context.FLETCHER_MODULE;
}
/*
* Return the recombined sums.
*/
preSum1 = (ushort)(s1 & 0xFFFF);
preSum2 = (ushort)(s2 & 0xFFFF);
}
}
#endif

View File

@@ -1,193 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : ssse3.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// The Chromium Authors
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute Fletcher32 checksum using SSSE3 vectorization.
//
// --[ License ] --------------------------------------------------------------
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// Copyright 2017 The Chromium Authors. All rights reserved.
// ****************************************************************************/
#if NETCOREAPP3_1_OR_GREATER
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru.Checksums.Fletcher32;
static class Ssse3
{
internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len)
{
uint s1 = sum1;
uint s2 = sum2;
var bufPos = 0;
/*
* Process the data in blocks.
*/
const uint block_Size = 1 << 5;
uint blocks = len / block_Size;
len -= blocks * block_Size;
while(blocks != 0)
{
uint n = Fletcher32Context.NMAX / block_Size; /* The NMAX constraint. */
if(n > blocks)
n = blocks;
blocks -= n;
Vector128<byte> tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17).
AsByte();
Vector128<byte> tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte();
Vector128<byte> zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte();
var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1);
/*
* Process n blocks of data. At most NMAX data bytes can be
* processed before s2 must be reduced modulo BASE.
*/
var v_Ps = Vector128.Create(s1 * n, 0, 0, 0);
var v_S2 = Vector128.Create(s2, 0, 0, 0);
var v_S1 = Vector128.Create(0u, 0, 0, 0);
do
{
/*
* Load 32 input bytes.
*/
var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
BitConverter.ToUInt32(buf, bufPos + 4),
BitConverter.ToUInt32(buf, bufPos + 8),
BitConverter.ToUInt32(buf, bufPos + 12));
bufPos += 16;
var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
BitConverter.ToUInt32(buf, bufPos + 4),
BitConverter.ToUInt32(buf, bufPos + 8),
BitConverter.ToUInt32(buf, bufPos + 12));
bufPos += 16;
/*
* Add previous block byte sum to v_ps.
*/
v_Ps = Sse2.Add(v_Ps, v_S1);
/*
* Horizontally add the bytes for s1, multiply-adds the
* bytes by [ 32, 31, 30, ... ] for s2.
*/
v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32());
Vector128<short> mad1 =
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte());
v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32());
v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32());
Vector128<short> mad2 =
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte());
v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32());
} while(--n != 0);
v_S2 = Sse2.Add(v_S2, Sse2.ShiftLeftLogical(v_Ps, 5));
/*
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
*/
v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 177));
v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 78));
s1 += (uint)Sse2.ConvertToInt32(v_S1.AsInt32());
v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 177));
v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 78));
s2 = (uint)Sse2.ConvertToInt32(v_S2.AsInt32());
/*
* Reduce.
*/
s1 %= Fletcher32Context.FLETCHER_MODULE;
s2 %= Fletcher32Context.FLETCHER_MODULE;
}
/*
* Handle leftover data.
*/
if(len != 0)
{
if(len >= 16)
{
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
s2 += s1 += buf[bufPos++];
len -= 16;
}
while(len-- != 0)
s2 += s1 += buf[bufPos++];
if(s1 >= Fletcher32Context.FLETCHER_MODULE)
s1 -= Fletcher32Context.FLETCHER_MODULE;
s2 %= Fletcher32Context.FLETCHER_MODULE;
}
/*
* Return the recombined sums.
*/
sum1 = (ushort)(s1 & 0xFFFF);
sum2 = (ushort)(s2 & 0xFFFF);
}
}
#endif

View File

@@ -1,777 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : FletcherContext.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Implements Fletcher-32 and Fletcher-16 algorithms.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
// Disabled because the speed is abnormally slow
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
#if NET5_0_OR_GREATER
using System.Runtime.Intrinsics.Arm;
#endif
using System.Text;
#if NETCOREAPP3_1_OR_GREATER
using Aaru.Checksums.Fletcher32;
#endif
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
#if NETCOREAPP3_1_OR_GREATER
using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3;
#endif
namespace Aaru.Checksums;
/// <inheritdoc />
/// <summary>Implements the Fletcher-32 algorithm</summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public sealed class Fletcher32Context : IChecksum
{
internal const ushort FLETCHER_MODULE = 0xFFFF;
internal const uint NMAX = 5552;
readonly IntPtr _nativeContext;
readonly bool _useNative;
ushort _sum1, _sum2;
/// <summary>Initializes the Fletcher-32 sums</summary>
public Fletcher32Context()
{
_sum1 = 0xFFFF;
_sum2 = 0xFFFF;
if(!Native.IsSupported)
return;
_nativeContext = fletcher32_init();
_useNative = _nativeContext != IntPtr.Zero;
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "Fletcher-32";
/// <inheritdoc />
public Guid Id => new("0E51B39F-C5E6-4CED-9E59-BA5A42B3B2F4");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
var finalSum = (uint)(_sum2 << 16 | _sum1);
if(!_useNative)
return BigEndianBitConverter.GetBytes(finalSum);
fletcher32_final(_nativeContext, ref finalSum);
fletcher32_free(_nativeContext);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var finalSum = (uint)(_sum2 << 16 | _sum1);
if(_useNative)
{
fletcher32_final(_nativeContext, ref finalSum);
fletcher32_free(_nativeContext);
}
var fletcherOutput = new StringBuilder();
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr fletcher32_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int fletcher32_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int fletcher32_final(IntPtr ctx, ref uint crc);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void fletcher32_free(IntPtr ctx);
static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len, bool useNative,
IntPtr nativeContext)
{
if(useNative)
{
fletcher32_update(nativeContext, data, len);
return;
}
#if NETCOREAPP3_1_OR_GREATER
if(Ssse3.IsSupported)
{
Fletcher32.Ssse3.Step(ref previousSum1, ref previousSum2, data, len);
return;
}
#endif
#if NET5_0_OR_GREATER
if(AdvSimd.IsSupported)
{
Neon.Step(ref previousSum1, ref previousSum2, data, len);
return;
}
#endif
uint sum1 = previousSum1;
uint sum2 = previousSum2;
var dataOff = 0;
switch(len)
{
/* in case user likes doing a byte at a time, keep it fast */
case 1:
{
sum1 += data[dataOff];
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 += sum1;
if(sum2 >= FLETCHER_MODULE)
sum2 -= FLETCHER_MODULE;
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
/* in case short lengths are provided, keep it somewhat fast */
case < 16:
{
while(len-- > 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
}
/* do length NMAX blocks -- requires just one modulo operation */
while(len >= NMAX)
{
len -= NMAX;
uint n = NMAX / 16;
do
{
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2 + 1];
sum2 += sum1;
/* 16 sums unrolled */
dataOff += 16;
} while(--n != 0);
sum1 %= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if(len != 0)
{
/* avoid modulos if none remaining */
while(len >= 16)
{
len -= 16;
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 8 + 4 + 2 + 1];
sum2 += sum1;
dataOff += 16;
}
while(len-- != 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
sum1 %= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE;
}
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = fletcher32_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
var fileStream = new FileStream(filename, FileMode.Open);
ushort localSum1 = 0xFFFF;
ushort localSum2 = 0xFFFF;
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.EnsureRead(buffer, 0, 65536);
}
var finalSum = (uint)(localSum2 << 16 | localSum1);
if(useNative)
{
fletcher32_final(nativeContext, ref finalSum);
fletcher32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var fletcherOutput = new StringBuilder();
foreach(byte h in hash)
fletcherOutput.Append(h.ToString("x2"));
fileStream.Close();
return fletcherOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = fletcher32_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
ushort localSum1 = 0xFFFF;
ushort localSum2 = 0xFFFF;
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
var finalSum = (uint)(localSum2 << 16 | localSum1);
if(useNative)
{
fletcher32_final(nativeContext, ref finalSum);
fletcher32_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
foreach(byte h in hash)
adlerOutput.Append(h.ToString("x2"));
return adlerOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}
/// <inheritdoc />
/// <summary>Implements the Fletcher-16 algorithm</summary>
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
public sealed class Fletcher16Context : IChecksum
{
const byte FLETCHER_MODULE = 0xFF;
const byte NMAX = 22;
readonly IntPtr _nativeContext;
readonly bool _useNative;
byte _sum1, _sum2;
/// <summary>Initializes the Fletcher-16 sums</summary>
public Fletcher16Context()
{
_sum1 = 0xFF;
_sum2 = 0xFF;
if(!Native.IsSupported)
return;
_nativeContext = fletcher16_init();
_useNative = _nativeContext != IntPtr.Zero;
}
#region IChecksum Members
/// <inheritdoc />
public string Name => "Fletcher-16";
/// <inheritdoc />
public Guid Id => new("80C51F1D-71F8-4741-A0CF-18FA8102EE4B");
/// <inheritdoc />
public string Author => "Natalia Portillo";
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
var finalSum = (ushort)(_sum2 << 8 | _sum1);
if(!_useNative)
return BigEndianBitConverter.GetBytes(finalSum);
fletcher16_final(_nativeContext, ref finalSum);
fletcher16_free(_nativeContext);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
var finalSum = (ushort)(_sum2 << 8 | _sum1);
if(_useNative)
{
fletcher16_final(_nativeContext, ref finalSum);
fletcher16_free(_nativeContext);
}
var fletcherOutput = new StringBuilder();
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
}
#endregion
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern IntPtr fletcher16_init();
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int fletcher16_update(IntPtr ctx, byte[] data, uint len);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern int fletcher16_final(IntPtr ctx, ref ushort checksum);
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern void fletcher16_free(IntPtr ctx);
static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len, bool useNative,
IntPtr nativeContext)
{
if(useNative)
{
fletcher16_update(nativeContext, data, len);
return;
}
uint sum1 = previousSum1;
uint sum2 = previousSum2;
var dataOff = 0;
switch(len)
{
/* in case user likes doing a byte at a time, keep it fast */
case 1:
{
sum1 += data[dataOff];
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 += sum1;
if(sum2 >= FLETCHER_MODULE)
sum2 -= FLETCHER_MODULE;
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
return;
}
/* in case short lengths are provided, keep it somewhat fast */
case < 11:
{
while(len-- > 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
return;
}
}
/* do length NMAX blocks -- requires just one modulo operation */
while(len >= NMAX)
{
len -= NMAX;
uint n = NMAX / 11;
do
{
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
/* 11 sums unrolled */
dataOff += 11;
} while(--n != 0);
sum1 %= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if(len != 0)
{
/* avoid modulos if none remaining */
while(len >= 11)
{
len -= 11;
sum1 += data[dataOff];
sum2 += sum1;
sum1 += data[dataOff + 1];
sum2 += sum1;
sum1 += data[dataOff + 2];
sum2 += sum1;
sum1 += data[dataOff + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4];
sum2 += sum1;
sum1 += data[dataOff + 4 + 1];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2];
sum2 += sum1;
sum1 += data[dataOff + 4 + 2 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8];
sum2 += sum1;
sum1 += data[dataOff + 8 + 1];
sum2 += sum1;
sum1 += data[dataOff + 8 + 2];
sum2 += sum1;
dataOff += 11;
}
while(len-- != 0)
{
sum1 += data[dataOff++];
sum2 += sum1;
}
sum1 %= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE;
}
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
{
File(filename, out byte[] hash);
return hash;
}
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
/// <param name="filename">File path.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string File(string filename, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = fletcher16_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
var fileStream = new FileStream(filename, FileMode.Open);
byte localSum1 = 0xFF;
byte localSum2 = 0xFF;
var buffer = new byte[65536];
int read = fileStream.EnsureRead(buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.EnsureRead(buffer, 0, 65536);
}
var finalSum = (ushort)(localSum2 << 8 | localSum1);
if(useNative)
{
fletcher16_final(nativeContext, ref finalSum);
fletcher16_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var fletcherOutput = new StringBuilder();
foreach(byte h in hash)
fletcherOutput.Append(h.ToString("x2"));
fileStream.Close();
return fletcherOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash)
{
bool useNative = Native.IsSupported;
IntPtr nativeContext = IntPtr.Zero;
if(useNative)
{
nativeContext = fletcher16_init();
if(nativeContext == IntPtr.Zero)
useNative = false;
}
byte localSum1 = 0xFF;
byte localSum2 = 0xFF;
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
var finalSum = (ushort)(localSum2 << 8 | localSum1);
if(useNative)
{
fletcher16_final(nativeContext, ref finalSum);
fletcher16_free(nativeContext);
}
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
foreach(byte h in hash)
adlerOutput.Append(h.ToString("x2"));
return adlerOutput.ToString();
}
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
}

View File

@@ -1,83 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Native.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Checks that Aaru.Checksums.Native library is available and usable.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System.Runtime.InteropServices;
namespace Aaru.Checksums;
/// <summary>Handles native implementations of compression algorithms</summary>
public static class Native
{
static bool _checked;
static bool _supported;
/// <summary>Set to return native as never supported</summary>
public static bool ForceManaged { get; set; }
/// <summary>
/// If set to <c>true</c> the native library was found and loaded correctly and its reported version is
/// compatible.
/// </summary>
public static bool IsSupported
{
get
{
if(ForceManaged)
return false;
if(_checked)
return _supported;
ulong version;
_checked = true;
try
{
version = get_acn_version();
}
catch
{
_supported = false;
return false;
}
// TODO: Check version compatibility
_supported = version >= 0x06000000;
return _supported;
}
}
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
static extern ulong get_acn_version();
}

View File

@@ -65,7 +65,7 @@ internal sealed class SpamSumContext : IChecksum
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#if NET20 || NET35 || NET40
#if NET20 || NET35 || NET40 || NET452
readonly byte[] _b64 = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
#else
readonly byte[] _b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"u8.ToArray();

View File

@@ -1,324 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : BigEndianBitConverter.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Helpers.
//
// --[ Description ] ----------------------------------------------------------
//
// Override of System.BitConverter that knows how to handle big-endian.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.Linq;
namespace Aaru.Helpers
{
/// <summary>
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
/// </summary>
public static class BigEndianBitConverter
{
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
/// <param name="value">A Boolean value.</param>
/// <returns>An array of bytes with length 1.</returns>
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
/// <param name="value">A character to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
/// <param name="value">The number to convert.</param>
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
/// array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static short ToInt16(byte[] value, int startIndex) =>
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static int ToInt32(byte[] value, int startIndex) =>
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 7, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static long ToInt64(byte[] value, int startIndex) =>
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
/// <summary>
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
/// array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
/// <exception cref="System.ArgumentException">
/// <see cref="startIndex" /> is greater than or equal to the length of value
/// minus 3, and is less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <see cref="startIndex" /> is less than zero or greater than the
/// length of value minus 1.
/// </exception>
public static float ToSingle(byte[] value, int startIndex) =>
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
/// <summary>
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
/// representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static string ToString(byte[] value, int startIndex) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
/// string representation.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <param name="length">The number of array elements in value to convert.</param>
/// <returns>
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
/// element in a subarray of value; for example, "7F-2C-4A".
/// </returns>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex or length is less than zero. -or- startIndex is greater
/// than zero and is greater than or equal to the length of value.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The combination of startIndex and length does not specify a position within
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
/// </exception>
public static string ToString(byte[] value, int startIndex, int length) =>
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
/// <param name="value">The array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ushort ToUInt16(byte[] value, int startIndex) =>
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static uint ToUInt32(byte[] value, int startIndex) =>
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
/// <exception cref="System.ArgumentException">
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
/// </exception>
/// <exception cref="System.ArgumentNullException">value is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value
/// minus 1.
/// </exception>
public static ulong ToUInt64(byte[] value, int startIndex) =>
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
/// <summary>Converts a big endian byte array representation of a GUID into the .NET Guid structure</summary>
/// <param name="value">Byte array containing a GUID in big endian</param>
/// <param name="startIndex">Start of the byte array to process</param>
/// <returns>Processed Guid</returns>
public static Guid ToGuid(byte[] value, int startIndex) => new Guid(ToUInt32(value, 0 + startIndex),
ToUInt16(value, 4 + startIndex),
ToUInt16(value, 6 + startIndex),
value[8 + startIndex + 0],
value[8 + startIndex + 1],
value[8 + startIndex + 2],
value[8 + startIndex + 3],
value[8 + startIndex + 5],
value[8 + startIndex + 5],
value[8 + startIndex + 6],
value[8 + startIndex + 7]);
}
}

View File

@@ -1,72 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Extensions.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Helpers.
//
// --[ Description ] ----------------------------------------------------------
//
// Provides class extensions.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2023 Natalia Portillo
// ****************************************************************************/
using System.IO;
namespace Aaru.Helpers;
public static class Extensions
{
/// <summary>
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the
/// position within the stream by the number of bytes read.<br /> Guarantees the whole count of bytes is read or EOF is
/// found
/// </summary>
/// <param name="s">Stream to extend</param>
/// <param name="buffer">
/// An array of bytes. When this method returns, the buffer contains the specified byte array with the
/// values between <see cref="offset" /> and (<see cref="offset" /> + <see cref="count" /> - 1) replaced by the bytes
/// read from the current source.
/// </param>
/// <param name="offset">
/// The zero-based byte offset in <see cref="buffer" /> at which to begin storing the data read from
/// the current stream.
/// </param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if the end
/// of the stream has been reached.
/// </returns>
public static int EnsureRead(this Stream s, byte[] buffer, int offset, int count)
{
var pos = 0;
int read;
do
{
read = s.Read(buffer, pos + offset, count - pos);
pos += read;
} while(read > 0);
return pos;
}
}

View File

@@ -1,68 +0,0 @@
using System;
namespace CRC32
{
public class NaiveCRC
{
private const uint kPoly = 0xEDB88320;
private const uint kInit = 0xFFFFFFFF;
private static readonly uint[] Table;
static NaiveCRC()
{
unchecked
{
Table = new uint[256];
for (uint i = 0; i < 256; i++)
{
uint r = i;
for (int j = 0; j < 8; j++)
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
Table[i] = r;
}
}
}
private uint value;
public NaiveCRC()
{
Init();
}
public void Init()
{
value = kInit;
}
public int Value
{
get { return (int)~value; }
}
public void UpdateByte(byte b)
{
value = (value >> 8) ^ Table[(byte)value ^ b];
}
public void Update(byte[] data, int offset, int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("count");
while (count-- != 0)
value = (value >> 8) ^ Table[(byte)value ^ data[offset++]];
}
static public int Compute(byte[] data, int offset, int count)
{
var crc = new NaiveCRC();
crc.Update(data, offset, count);
return crc.Value;
}
static public int Compute(byte[] data)
{
return Compute(data, 0, data.Length);
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright (c) 2012-2015 Eugene Larchenko (el6345@gmail.com)
* This code is licensed under the MIT License.
* See the file LICENSE_MIT for the license details.
*/
using System;
namespace CRC32
{
public class OptimizedCRC
{
private const uint kPoly = 0xEDB88320;
private const uint kInit = 0xFFFFFFFF;
private const int NUM_TABLES = 8;
private static readonly uint[] Table;
static OptimizedCRC()
{
unchecked
{
Table = new uint[256 * NUM_TABLES];
int i;
for (i = 0; i < 256; i++)
{
uint r = (uint)i;
for (int j = 0; j < 8; j++)
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
Table[i] = r;
}
for (; i < 256 * NUM_TABLES; i++)
{
uint r = Table[i - 256];
Table[i] = Table[r & 0xFF] ^ (r >> 8);
}
}
}
private uint value;
public OptimizedCRC()
{
Init();
}
public void Init()
{
value = kInit;
}
public int Value
{
get { return (int)~value; }
}
public void Update(byte[] data, int offset, int count)
{
new ArraySegment<byte>(data, offset, count); // check arguments
if (count <= 0) return;
var table = OptimizedCRC.Table;
uint crc = value;
for (; (offset & 7) != 0 && count != 0; count--)
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
if (count >= 8)
{
int end = (count - 8) & ~7;
count -= end;
end += offset;
while (offset != end)
{
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
offset += 8;
crc = table[(byte)crc + 0x700]
^ table[(byte)(crc >>= 8) + 0x600]
^ table[(byte)(crc >>= 8) + 0x500]
^ table[/*(byte)*/(crc >> 8) + 0x400]
^ table[(byte)(high) + 0x300]
^ table[(byte)(high >>= 8) + 0x200]
^ table[(byte)(high >>= 8) + 0x100]
^ table[/*(byte)*/(high >> 8) + 0x000];
}
}
while (count-- != 0)
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
value = crc;
}
static public int Compute(byte[] data, int offset, int count)
{
var crc = new OptimizedCRC();
crc.Update(data, offset, count);
return crc.Value;
}
static public int Compute(byte[] data)
{
return Compute(data, 0, data.Length);
}
}
}

View File

@@ -1,302 +0,0 @@
/*
* Copyright (c) 2012-2015 Eugene Larchenko (el6345@gmail.com)
* This code is licensed under the Microsoft Public License (MS-PL).
* See the file LICENSE_MSPL for the license details.
*/
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace CRC32
{
public class ParallelCRC
{
private const uint kPoly = 0xEDB88320;
private const uint kInit = 0xFFFFFFFF;
private const int NUM_TABLES = 8;
private static readonly uint[] Table;
private const int ThreadCost = 512 * 1024;
private static readonly int ProcessorCount = Environment.ProcessorCount;
static ParallelCRC()
{
unchecked
{
Table = new uint[256 * NUM_TABLES];
int i;
for (i = 0; i < 256; i++)
{
uint r = (uint)i;
for (int j = 0; j < 8; j++)
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
Table[i] = r;
}
for (; i < 256 * NUM_TABLES; i++)
{
uint r = Table[i - 256];
Table[i] = Table[r & 0xFF] ^ (r >> 8);
}
}
}
private uint value;
public ParallelCRC()
{
Init();
}
/// <summary>
/// Reset CRC
/// </summary>
public void Init()
{
value = kInit;
}
public int Value
{
get { return (int)~value; }
}
public void Update(byte[] data, int offset, int count)
{
new ArraySegment<byte>(data, offset, count); // check arguments
// quick elimination
if (count <= ThreadCost || ProcessorCount <= 1)
{
value = ProcessBlock(value, data, offset, count);
return;
}
// choose optimal number of threads to use
int threadCount = ProcessorCount;
L0:
int bytesPerThread = (count + threadCount - 1) / threadCount;
if (bytesPerThread < (ThreadCost >> 1))
{
threadCount--;
goto L0;
}
// create jobs chain
// threadCount >= 2
Job? lastJob = null;
while (count > bytesPerThread)
{
var job = new Job(new ArraySegment<byte>(data, offset, bytesPerThread), this, lastJob);
ThreadPool.QueueUserWorkItem(job.Start);
offset += bytesPerThread;
count -= bytesPerThread;
lastJob = job;
}
// lastJob != null
var lastBlockCRC = ProcessBlock(kInit, data, offset, count);
lastJob?.WaitAndDispose();
value = Combine(value, lastBlockCRC, count);
}
private static uint ProcessBlock(uint crc, byte[] data, int offset, int count)
{
/*
* A copy of OptimizedCRC.cs
*/
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0) return crc;
var table = ParallelCRC.Table;
for (; (offset & 7) != 0 && count != 0; count--)
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
if (count >= 8)
{
int end = (count - 8) & ~7;
count -= end;
end += offset;
while (offset != end)
{
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
offset += 8;
crc = table[(byte)crc + 0x700]
^ table[(byte)(crc >>= 8) + 0x600]
^ table[(byte)(crc >>= 8) + 0x500]
^ table[/*(byte)*/(crc >> 8) + 0x400]
^ table[(byte)(high) + 0x300]
^ table[(byte)(high >>= 8) + 0x200]
^ table[(byte)(high >>= 8) + 0x100]
^ table[/*(byte)*/(high >> 8) + 0x000];
}
}
while (count-- != 0)
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
return crc;
}
static public int Compute(byte[] data, int offset, int count)
{
var crc = new ParallelCRC();
crc.Update(data, offset, count);
return crc.Value;
}
static public int Compute(byte[] data)
{
return Compute(data, 0, data.Length);
}
#region Combining
// Copyright (c) 2011 Dino Chiesa.
// This module is (refactored) part of DotNetZip, a zipfile class library.
// This code is licensed under the Microsoft Public License.
// See the file LICENSE_MSPL for the license details.
// More info on: http://dotnetzip.codeplex.com
/// <summary>
/// Combine sums of two segments.
/// This function is thread-safe.
/// </summary>
private static uint Combine(uint crc1, uint crc2, int length2)
{
// Note: this function is thread-safe even though it references static fields
if (length2 <= 0) return crc1;
if (crc1 == kInit) return crc2;
if (even_cache == null)
{
Prepare_even_odd_Cache();
}
uint[] even = even_cache?.ToArray() ?? [];
uint[] odd = odd_cache?.ToArray() ?? [];
crc1 = ~crc1;
crc2 = ~crc2;
uint len2 = (uint)length2;
// apply len2 zeros to crc1 (first square will put the operator for one
// zero byte, eight zero bits, in even)
do
{
// apply zeros operator for this bit of len2
gf2_matrix_square(even, odd);
if ((len2 & 1) != 0) crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
if (len2 == 0) break;
// another iteration of the loop with odd and even swapped
gf2_matrix_square(odd, even);
if ((len2 & 1) != 0) crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
} while (len2 != 0);
crc1 ^= crc2;
return ~crc1;
}
private static uint[]? even_cache = null;
private static uint[]? odd_cache;
private static void Prepare_even_odd_Cache()
{
var even = new uint[32]; // even-power-of-two zeros operator
var odd = new uint[32]; // odd-power-of-two zeros operator
// put operator for one zero bit in odd
odd[0] = kPoly; // the CRC-32 polynomial
for (int i = 1; i < 32; i++) odd[i] = 1U << (i - 1);
// put operator for two zero bits in even
gf2_matrix_square(even, odd);
// put operator for four zero bits in odd
gf2_matrix_square(odd, even);
odd_cache = odd;
even_cache = even;
}
/// <param name="matrix">will not be modified</param>
private static uint gf2_matrix_times(uint[] matrix, uint vec)
{
uint sum = 0;
int i = 0;
while (vec != 0)
{
if ((vec & 1) != 0) sum ^= matrix[i];
vec >>= 1;
i++;
}
return sum;
}
/// <param name="square">this array will be modified!</param>
/// <param name="mat">will not be modified</param>
private static void gf2_matrix_square(uint[] square, uint[] mat)
{
for (int i = 0; i < 32; i++)
square[i] = gf2_matrix_times(mat, mat[i]);
}
#endregion Combining
class Job
{
private ArraySegment<byte> data;
private Job? previousJob;
private ParallelCRC accumulator;
private ManualResetEvent? finished;
public Job(ArraySegment<byte> data, ParallelCRC accumulator, Job? previousJob)
{
this.data = data;
this.accumulator = accumulator;
this.previousJob = previousJob;
this.finished = new ManualResetEvent(false);
}
public void Start(object? arg)
{
var crc = ProcessBlock(kInit, data.Array!, data.Offset, data.Count);
if (previousJob != null) previousJob.WaitAndDispose();
accumulator.value = Combine(accumulator.value, crc, data.Count);
finished?.Set();
}
public void WaitAndDispose()
{
finished?.WaitOne();
Dispose();
}
public void Dispose()
{
if (finished != null) finished.Close();
finished = null;
}
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
/// <see href="https://github.com/madler/zlib/blob/v1.2.11/adler32.c"/>
public class Adler32 : ChecksumBase<uint>
{
public Adler32()
{
Reset();
}
/// <summary>
/// Reset the internal hashing state
/// </summary>
public override void Reset()
{
_hash = 1;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Split Adler-32 into component sums
uint sum2 = (_hash >> 16) & 0xffff;
_hash &= 0xffff;
// In case user likes doing a byte at a time, keep it fast
if (length == 1)
{
_hash += data[offset];
if (_hash >= A32BASE)
_hash -= A32BASE;
sum2 += _hash;
if (sum2 >= A32BASE)
sum2 -= A32BASE;
_hash |= sum2 << 16;
return;
}
// In case short lengths are provided, keep it somewhat fast
if (length < 16)
{
while (length-- > 0)
{
_hash += data[offset]++;
sum2 += _hash;
}
if (_hash >= A32BASE)
_hash -= A32BASE;
// Only added so many BASE's
sum2 %= A32BASE;
_hash |= sum2 << 16;
return;
}
// Do length NMAX blocks -- requires just one modulo operation
while (length >= A32NMAX)
{
// NMAX is divisible by 16
length -= A32NMAX;
uint n = A32NMAX / 16;
do
{
_hash += data[offset + 0]; sum2 += _hash;
_hash += data[offset + 1]; sum2 += _hash;
_hash += data[offset + 2]; sum2 += _hash;
_hash += data[offset + 3]; sum2 += _hash;
_hash += data[offset + 4]; sum2 += _hash;
_hash += data[offset + 5]; sum2 += _hash;
_hash += data[offset + 6]; sum2 += _hash;
_hash += data[offset + 7]; sum2 += _hash;
_hash += data[offset + 8]; sum2 += _hash;
_hash += data[offset + 9]; sum2 += _hash;
_hash += data[offset + 10]; sum2 += _hash;
_hash += data[offset + 11]; sum2 += _hash;
_hash += data[offset + 12]; sum2 += _hash;
_hash += data[offset + 13]; sum2 += _hash;
_hash += data[offset + 14]; sum2 += _hash;
_hash += data[offset + 15]; sum2 += _hash;
offset += 16;
} while (--n > 0);
}
// Do remaining bytes (less than NMAX, still just one modulo)
if (length > 0)
{
// Avoid modulos if none remaining
while (length >= 16)
{
length -= 16;
_hash += data[offset + 0]; sum2 += _hash;
_hash += data[offset + 1]; sum2 += _hash;
_hash += data[offset + 2]; sum2 += _hash;
_hash += data[offset + 3]; sum2 += _hash;
_hash += data[offset + 4]; sum2 += _hash;
_hash += data[offset + 5]; sum2 += _hash;
_hash += data[offset + 6]; sum2 += _hash;
_hash += data[offset + 7]; sum2 += _hash;
_hash += data[offset + 8]; sum2 += _hash;
_hash += data[offset + 9]; sum2 += _hash;
_hash += data[offset + 10]; sum2 += _hash;
_hash += data[offset + 11]; sum2 += _hash;
_hash += data[offset + 12]; sum2 += _hash;
_hash += data[offset + 13]; sum2 += _hash;
_hash += data[offset + 14]; sum2 += _hash;
_hash += data[offset + 15]; sum2 += _hash;
offset += 16;
}
while (length-- > 0)
{
_hash += data[offset++];
sum2 += _hash;
}
_hash %= A32BASE;
sum2 %= A32BASE;
}
// Return recombined sums
_hash |= sum2 << 16;
}
/// <inheritdoc/>
public override byte[] Finalize()
{
return BitConverter.GetBytes(_hash);
}
}
}

View File

@@ -0,0 +1,22 @@
namespace SabreTools.Hashing.Checksum
{
internal static class BitOperations
{
/// <summary>
/// Clamp a value to a certain bit width and convert to a byte array
/// </summary>
public static byte[] ClampValueToBytes(ulong value, int bitWidth)
{
value &= ulong.MaxValue >> (64 - bitWidth);
byte[] bytes = new byte[(bitWidth + 7) / 8];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)value;
value >>= 8;
}
return bytes;
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
namespace SabreTools.Hashing.Checksum
{
/// <summary>
/// Common base class for Fletcher checksums
/// </summary>
public abstract class ChecksumBase
{
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public abstract void TransformBlock(byte[] data, int offset, int length);
/// <summary>
/// Finalize the hash and return as a byte array
/// </summary>
public abstract byte[] Finalize();
}
/// <summary>
/// Common base class for checksums
/// </summary>
public abstract class ChecksumBase<T> : ChecksumBase where T : struct
{
/// <summary>
/// The current value of the hash
/// </summary>
protected T _hash;
/// <summary>
/// Reset the internal hashing state
/// </summary>
public virtual void Reset()
{
_hash = default;
}
/// <inheritdoc/>
public override byte[] Finalize()
{
return _hash switch
{
short s => BitConverter.GetBytes(s),
ushort s => BitConverter.GetBytes(s),
int i => BitConverter.GetBytes(i),
uint i => BitConverter.GetBytes(i),
long l => BitConverter.GetBytes(l),
ulong l => BitConverter.GetBytes(l),
_ => [],
};
}
}
}

View File

@@ -0,0 +1,39 @@
namespace SabreTools.Hashing.Checksum
{
internal static class Constants
{
#region Adler-32 / Fletcher-32
/// <summary>
/// Largest prime smaller than 65536
/// </summary>
public const ushort A32BASE = 65521;
/// <summary>
/// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(<see cref="A32BASE">-1) <= 2^32-1
/// </summary>
public const ushort A32NMAX = 5552;
/// <summary>
/// Max value for a single half of a Fletcher-32 checksum
/// </summary>
public const ushort F32BASE = 0xffff;
/// <summary>
/// Max value for a single half of a Fletcher-64 checksum
/// </summary>
public const uint F64BASE = 0xffffffff;
#endregion
#region FNV
public const uint FNV32Basis = 0x811c9dc5;
public const ulong FNV64Basis = 0xcbf29ce484222325;
public const uint FNV32Prime = 0x01000193;
public const ulong FNV64Prime = 0x00000100000001b3;
#endregion
}
}

View File

@@ -0,0 +1,56 @@
using System;
using static SabreTools.Hashing.HashOperations;
namespace SabreTools.Hashing.Checksum
{
public class Crc : ChecksumBase<ulong>
{
/// <summary>
/// Definition used to create the runner
/// </summary>
public readonly CrcDefinition Def;
/// <summary>
/// Table used for calculation steps
/// </summary>
private readonly CrcTable _table;
public Crc(CrcDefinition def)
{
// Check for a valid bit width
if (def.Width < 0 || def.Width > 64)
throw new ArgumentOutOfRangeException(nameof(def));
Def = def;
_table = new CrcTable(def);
_hash = def.ReflectIn ? ReverseBits(def.Init, def.Width) : def.Init;
}
/// <inheritdoc/>
public override void Reset()
{
_hash = Def.Init;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
=> _table.TransformBlock(ref _hash, data, offset, length);
/// <inheritdoc/>
public override byte[] Finalize()
{
// Create a copy of the hash
ulong localHash = _hash;
// Handle mutual reflection
if (Def.ReflectIn ^ Def.ReflectOut)
localHash = ReverseBits(localHash, Def.Width);
// Handle XOR
localHash ^= Def.XorOut;
// Process the value and return
return BitOperations.ClampValueToBytes(localHash, Def.Width);
}
}
}

View File

@@ -0,0 +1,65 @@
namespace SabreTools.Hashing.Checksum
{
/// <see href="https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.legend"/>
public class CrcDefinition
{
/// <summary>
/// The name assigned to the model in this Catalogue.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// The number of bit cells in the linear feedback shift register;
/// the degree of the generator polynomial, less one.
/// </summary>
public int Width { get; set; }
/// <summary>
/// The generator polynomial that sets the feedback tap positions of
/// the shift register. poly is written in the hexadecimal, direct
/// notation found in MSB-first code. The least significant bit
/// corresponds to the inward end of the shift register, and is always
/// set. The highest-order term is omitted.
/// </summary>
public ulong Poly { get; set; }
/// <summary>
/// The settings of the bit cells at the start of each calculation,
/// before reading the first message bit. init is written in the
/// hexadecimal, direct notation found in MSB-first code. The least
/// significant bit corresponds to the inward end of the shift register.
/// </summary>
public ulong Init { get; set; }
/// <summary>
/// If equal to false, specifies that the characters of the message
/// are read bit-by-bit, most significant bit (MSB) first; if equal to
/// true, the characters are read bit-by-bit, least significant bit (LSB)
/// first. Each sampled message bit is then XORed with the bit being
/// simultaneously shifted out of the register at the most significant
/// end, and the result is passed to the feedback taps.
/// </summary>
public bool ReflectIn { get; set; }
/// <summary>
/// If equal to false, specifies that the contents of the register after
/// reading the last message bit are unreflected before presentation;
/// if equal to true, it specifies that they are reflected,
/// character-by-character, before presentation. For the purpose of this
/// definition, the reflection is performed by swapping the content of
/// each cell with that of the cell an equal distance from the opposite
/// end of the register; the characters of the CRC are then true images
/// of parts of the reflected register, the character containing the
/// original MSB always appearing first.
/// </summary>
public bool ReflectOut { get; set; }
/// <summary>
/// The XOR value applied to the contents of the register after the last
/// message bit has been read and after the optional reflection. xorout
/// 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>
public ulong XorOut { get; set; }
}
}

View File

@@ -0,0 +1,333 @@
using static SabreTools.Hashing.HashOperations;
namespace SabreTools.Hashing.Checksum
{
internal class CrcTable
{
/// <summary>
/// Indicates if CRC should be processed bitwise instead of bytewise
/// </summary>
private bool Bitwise => _definition.Width < 8;
/// <summary>
/// Number of bits to process at a time
/// </summary>
private int BitsPerStep => Bitwise ? 1 : 8;
/// <summary>
/// Bit shift based on the CRC width
/// </summary>
private int BitShift => _definition.Width - BitsPerStep;
/// <summary>
/// Bit mask based on the CRC width
/// </summary>
private ulong BitMask => 1UL << (_definition.Width - 1);
/// <summary>
/// Mapping table
/// </summary>
private readonly ulong[,] _table;
/// <summary>
/// Definition used to build the table
/// </summary>
private readonly CrcDefinition _definition;
/// <summary>
/// Number of slices in the optimized table
/// </summary>
private const int SliceCount = 8;
public CrcTable(CrcDefinition def)
{
// Initialize the internal
_definition = def;
_table = new ulong[SliceCount, 1 << BitsPerStep];
// Build the standard table
for (uint i = 0; i < (1 << BitsPerStep); i++)
{
// Get the starting value for this index
ulong point = i;
if (!Bitwise && def.ReflectIn)
point = ReverseBits(point, BitsPerStep);
// Shift to account for storage
point <<= _definition.Width - BitsPerStep;
// Accumulate the value
for (int j = 0; j < BitsPerStep; j++)
{
if ((point & BitMask) > 0UL)
point = (point << 1) ^ def.Poly;
else
point <<= 1;
}
// Reflect if necessary
if (def.ReflectIn)
point = ReverseBits(point, def.Width);
// Shift back to account for storage
point &= ulong.MaxValue >> (64 - def.Width);
// Assign to the table
_table[0, i] = point;
}
// Skip building the optimized table for bitwise processing
if (Bitwise)
return;
// Build the optimized table for non-bitwise processing
for (int i = 1; i < SliceCount; i++)
{
// Build each slice from the previous
for (int j = 0; j < 1 << BitsPerStep; j++)
{
ulong last = _table[i - 1, j];
if (_definition.ReflectIn)
_table[i, j] = (last >> BitsPerStep) ^ _table[0, (byte)last];
else
_table[i, j] = (last << BitsPerStep) ^ _table[0, (byte)(last >> BitShift)];
}
}
}
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <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 byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void TransformBlock(ref ulong hash, byte[] data, int offset, int length)
{
// Empty data just returns
if (data.Length == 0)
return;
// Check for valid offset and length
if (offset > data.Length)
throw new System.ArgumentOutOfRangeException(nameof(offset));
else if (offset + length > data.Length)
throw new System.ArgumentOutOfRangeException(nameof(length));
// Try transforming fast first
if (TransformBlockFast(ref hash, data, offset, length))
return;
// Process the data byte-wise
for (int i = offset; i < offset + length; i++)
{
PerformChecksumStep(ref hash, data, i);
}
}
/// <summary>
/// Perform a single checksum step
/// </summary>
/// <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>
private void PerformChecksumStep(ref ulong hash, byte[] data, int offset)
{
// Per-bit processing
if (Bitwise)
{
for (int b = 0; b < 8; b++)
{
if (_definition.ReflectIn)
hash = (hash >> 1) ^ _table[0, (byte)(hash & 1) ^ ((byte)(data[offset] >> b) & 1)];
else
hash = (hash << 1) ^ _table[0, (byte)((hash >> BitShift) & 1) ^ ((byte)(data[offset] >> (7 - b)) & 1)];
}
}
// Per-byte processing
else
{
if (_definition.ReflectIn)
hash = (hash >> 8) ^ _table[0, (byte)hash ^ data[offset]];
else
hash = (hash << 8) ^ _table[0, ((byte)(hash >> BitShift)) ^ data[offset]];
}
}
/// <summary>
/// Perform an optimized transform step
/// </summary>
private bool TransformBlockFast(ref ulong hash, byte[] data, int offset, int length)
{
// Bitwise transformations are not optimized
if (Bitwise)
return false;
// All reflection-in implementations share an optimized path
if (_definition.Width < 64 && _definition.ReflectIn)
{
TransformBlockFast8Reflect(ref hash, data, offset, length);
return true;
}
else if (_definition.Width >= 64 && _definition.ReflectIn)
{
TransformBlockFast4Reflect(ref hash, data, offset, length);
return true;
}
// CRC-32 with no reflection-in has can be optimized
if (_definition.Width == 32 && !_definition.ReflectIn)
{
TransformBlockFast8NoReflect(ref hash, data, offset, length);
return true;
}
return false;
}
/// <summary>
/// Optimized transformation for CRC with reflection
/// </summary>
/// <remarks>Reads 4 bytes at a time</remarks>
private void TransformBlockFast4Reflect(ref ulong hash, byte[] data, int offset, int length)
{
// Process on a copy of the hash
ulong local = hash;
// Process aligned data
if (length > 4)
{
long end = offset + (length & ~(uint)3);
length &= 3;
while (offset < end)
{
ulong low = local ^ (uint)(
(data[offset + 0])
+ (data[offset + 1] << 8)
+ (data[offset + 2] << 16)
+ (data[offset + 3] << 24));
offset += 4;
local = _table[3, (byte)(low)]
^ _table[2, (byte)(low >> 8)]
^ _table[1, (byte)(low >> 16)]
^ _table[0, (byte)(low >> 24)]
^ local >> 32;
}
}
// Process unaligned data
while (length-- != 0)
{
PerformChecksumStep(ref local, data, offset++);
}
// Assign the new hash value
hash = local;
}
/// <summary>
/// Optimized transformation for CRC with reflection
/// </summary>
/// <remarks>Reads 8 bytes at a time</remarks>
private void TransformBlockFast8Reflect(ref ulong hash, byte[] data, int offset, int length)
{
// Process on a copy of the hash
ulong local = hash;
// Process aligned data
if (length > 8)
{
long end = offset + (length & ~(uint)7);
length &= 7;
while (offset < end)
{
ulong low = local ^ (uint)(
(data[offset + 0])
+ (data[offset + 1] << 8)
+ (data[offset + 2] << 16)
+ (data[offset + 3] << 24));
ulong high = (uint)(
(data[offset + 4])
+ (data[offset + 5] << 8)
+ (data[offset + 6] << 16)
+ (data[offset + 7] << 24));
offset += 8;
local = _table[7, (byte)(low)]
^ _table[6, (byte)(low >> 8)]
^ _table[5, (byte)(low >> 16)]
^ _table[4, (byte)(low >> 24)]
^ _table[3, (byte)(high)]
^ _table[2, (byte)(high >> 8)]
^ _table[1, (byte)(high >> 16)]
^ _table[0, (byte)(high >> 24)]
^ local >> 32;
}
}
// Process unaligned data
while (length-- != 0)
{
PerformChecksumStep(ref local, data, offset++);
}
// Assign the new hash value
hash = local;
}
/// <summary>
/// Optimized transformation for 32-bit CRC with no reflection
/// </summary>
/// <remarks>Reads 8 bytes at a time</remarks>
private void TransformBlockFast8NoReflect(ref ulong hash, byte[] data, int offset, int length)
{
// Process on a copy of the hash
ulong local = hash;
// Process aligned data
if (length > 8)
{
long end = offset + (length & ~(uint)7);
length &= 7;
while (offset < end)
{
ulong low = local ^ (uint)(
(data[offset + 3])
+ (data[offset + 2] << 8)
+ (data[offset + 1] << 16)
+ (data[offset + 0] << 24));
ulong high = (uint)(
(data[offset + 7])
+ (data[offset + 6] << 8)
+ (data[offset + 5] << 16)
+ (data[offset + 4] << 24));
offset += 8;
local = _table[4, (byte)(low)]
^ _table[5, (byte)(low >> 8)]
^ _table[6, (byte)(low >> 16)]
^ _table[7, (byte)(low >> 24)]
^ _table[0, (byte)(high)]
^ _table[1, (byte)(high >> 8)]
^ _table[2, (byte)(high >> 16)]
^ _table[3, (byte)(high >> 24)]
^ local << 32;
}
}
// Process unaligned data
while (length-- != 0)
{
PerformChecksumStep(ref local, data, offset++);
}
// Assign the new hash value
hash = local;
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV0_32 : FnvBase<uint>
{
public FNV0_32()
{
_basis = 0;
_prime = FNV32Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash * _prime) ^ data[i];
}
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV0_64 : FnvBase<ulong>
{
public FNV0_64()
{
_basis = 0;
_prime = FNV64Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash * _prime) ^ data[i];
}
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV1_32 : FnvBase<uint>
{
public FNV1_32()
{
_basis = FNV32Basis;
_prime = FNV32Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash * _prime) ^ data[i];
}
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV1_64 : FnvBase<ulong>
{
public FNV1_64()
{
_basis = FNV64Basis;
_prime = FNV64Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash * _prime) ^ data[i];
}
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV1a_32 : FnvBase<uint>
{
public FNV1a_32()
{
_basis = FNV32Basis;
_prime = FNV32Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash ^ data[i]) * _prime;
}
}
}
}

View File

@@ -0,0 +1,23 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
public class FNV1a_64 : FnvBase<ulong>
{
public FNV1a_64()
{
_basis = FNV64Basis;
_prime = FNV64Prime;
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
for (int i = offset; length > 0; i++, length--)
{
_hash = (_hash ^ data[i]) * _prime;
}
}
}
}

View File

@@ -0,0 +1,40 @@
namespace SabreTools.Hashing.Checksum
{
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
public class Fletcher16 : ChecksumBase<ushort>
{
public Fletcher16()
{
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Split the existing hash
uint c0 = (uint)(_hash & 0x00FF);
uint c1 = (uint)(_hash << 16);
// Found by solving for c1 overflow:
// n > 0 and n * (n+1) / 2 * (2^8-1) < (2^32-1).
while (length > 0)
{
int blocklen = length;
if (blocklen > 5802)
blocklen = 5802;
length -= blocklen;
do
{
c0 += data[offset++];
c1 += c0;
} while (--blocklen > 0);
c0 %= 255;
c1 %= 255;
}
_hash = (ushort)(c1 << 8 | c0);
}
}
}

View File

@@ -0,0 +1,125 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
public class Fletcher32 : ChecksumBase<uint>
{
public Fletcher32()
{
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Split Fletcher-32 into component sums
uint c0 = _hash & 0xffff;
uint c1 = (_hash >> 16) & 0xffff;
// In case user likes doing a byte at a time, keep it fast
if (length == 1)
{
c0 += data[offset];
if (c0 >= F32BASE)
c0 -= F32BASE;
c1 += c0;
if (c1 >= F32BASE)
c1 -= F32BASE;
_hash = (uint)((c1 << 16) | c0);
return;
}
// In case short lengths are provided, keep it somewhat fast
if (length < 16)
{
while (length-- > 0)
{
c0 += data[offset]++;
c1 += c0;
}
if (c0 >= F32BASE)
c0 -= F32BASE;
// Only added so many BASE's
c1 %= F32BASE;
_hash = (uint)((c1 << 16) | c0);
return;
}
// Do length NMAX blocks -- requires just one modulo operation
while (length >= A32NMAX)
{
// NMAX is divisible by 16
length -= A32NMAX;
uint n = A32NMAX / 16;
do
{
c0 += data[offset + 0]; c1 += c0;
c0 += data[offset + 1]; c1 += c0;
c0 += data[offset + 2]; c1 += c0;
c0 += data[offset + 3]; c1 += c0;
c0 += data[offset + 4]; c1 += c0;
c0 += data[offset + 5]; c1 += c0;
c0 += data[offset + 6]; c1 += c0;
c0 += data[offset + 7]; c1 += c0;
c0 += data[offset + 8]; c1 += c0;
c0 += data[offset + 9]; c1 += c0;
c0 += data[offset + 10]; c1 += c0;
c0 += data[offset + 11]; c1 += c0;
c0 += data[offset + 12]; c1 += c0;
c0 += data[offset + 13]; c1 += c0;
c0 += data[offset + 14]; c1 += c0;
c0 += data[offset + 15]; c1 += c0;
offset += 16;
} while (--n > 0);
}
// Do remaining bytes (less than NMAX, still just one modulo)
if (length > 0)
{
// Avoid modulos if none remaining
while (length >= 16)
{
length -= 16;
c0 += data[offset + 0]; c1 += c0;
c0 += data[offset + 1]; c1 += c0;
c0 += data[offset + 2]; c1 += c0;
c0 += data[offset + 3]; c1 += c0;
c0 += data[offset + 4]; c1 += c0;
c0 += data[offset + 5]; c1 += c0;
c0 += data[offset + 6]; c1 += c0;
c0 += data[offset + 7]; c1 += c0;
c0 += data[offset + 8]; c1 += c0;
c0 += data[offset + 9]; c1 += c0;
c0 += data[offset + 10]; c1 += c0;
c0 += data[offset + 11]; c1 += c0;
c0 += data[offset + 12]; c1 += c0;
c0 += data[offset + 13]; c1 += c0;
c0 += data[offset + 14]; c1 += c0;
c0 += data[offset + 15]; c1 += c0;
offset += 16;
}
while (length-- > 0)
{
c0 += data[offset++];
c1 += c0;
}
c0 %= F32BASE;
c1 %= F32BASE;
}
// Return recombined sums
_hash = (c1 << 16) | c0;
}
}
}

View File

@@ -0,0 +1,125 @@
using static SabreTools.Hashing.Checksum.Constants;
namespace SabreTools.Hashing.Checksum
{
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
public class Fletcher64 : ChecksumBase<ulong>
{
public Fletcher64()
{
Reset();
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Split Fletcher-64 into component sums
ulong c0 = _hash & 0xffffffff;
ulong c1 = (_hash >> 32) & 0xffffffff;
// In case user likes doing a byte at a time, keep it fast
if (length == 1)
{
c0 += data[offset];
if (c0 >= F64BASE)
c0 -= F64BASE;
c1 += c0;
if (c1 >= F64BASE)
c1 -= F64BASE;
_hash = (c1 << 32) | c0;
return;
}
// In case short lengths are provided, keep it somewhat fast
if (length < 16)
{
while (length-- > 0)
{
c0 += data[offset]++;
c1 += c0;
}
if (c0 >= F64BASE)
c0 -= F64BASE;
// Only added so many BASE's
c1 %= F64BASE;
_hash = (c1 << 32) | c0;
return;
}
// Do length NMAX blocks -- requires just one modulo operation
while (length >= A32NMAX)
{
// NMAX is divisible by 16
length -= A32NMAX;
uint n = A32NMAX / 16;
do
{
c0 += data[offset + 0]; c1 += c0;
c0 += data[offset + 1]; c1 += c0;
c0 += data[offset + 2]; c1 += c0;
c0 += data[offset + 3]; c1 += c0;
c0 += data[offset + 4]; c1 += c0;
c0 += data[offset + 5]; c1 += c0;
c0 += data[offset + 6]; c1 += c0;
c0 += data[offset + 7]; c1 += c0;
c0 += data[offset + 8]; c1 += c0;
c0 += data[offset + 9]; c1 += c0;
c0 += data[offset + 10]; c1 += c0;
c0 += data[offset + 11]; c1 += c0;
c0 += data[offset + 12]; c1 += c0;
c0 += data[offset + 13]; c1 += c0;
c0 += data[offset + 14]; c1 += c0;
c0 += data[offset + 15]; c1 += c0;
offset += 16;
} while (--n > 0);
}
// Do remaining bytes (less than NMAX, still just one modulo)
if (length > 0)
{
// Avoid modulos if none remaining
while (length >= 16)
{
length -= 16;
c0 += data[offset + 0]; c1 += c0;
c0 += data[offset + 1]; c1 += c0;
c0 += data[offset + 2]; c1 += c0;
c0 += data[offset + 3]; c1 += c0;
c0 += data[offset + 4]; c1 += c0;
c0 += data[offset + 5]; c1 += c0;
c0 += data[offset + 6]; c1 += c0;
c0 += data[offset + 7]; c1 += c0;
c0 += data[offset + 8]; c1 += c0;
c0 += data[offset + 9]; c1 += c0;
c0 += data[offset + 10]; c1 += c0;
c0 += data[offset + 11]; c1 += c0;
c0 += data[offset + 12]; c1 += c0;
c0 += data[offset + 13]; c1 += c0;
c0 += data[offset + 14]; c1 += c0;
c0 += data[offset + 15]; c1 += c0;
offset += 16;
}
while (length-- > 0)
{
c0 += data[offset++];
c1 += c0;
}
c0 %= F64BASE;
c1 %= F64BASE;
}
// Return recombined sums
_hash = (c1 << 32) | c0;
}
}
}

View File

@@ -0,0 +1,21 @@
namespace SabreTools.Hashing.Checksum
{
public abstract class FnvBase<T> : ChecksumBase<T> where T : struct
{
/// <summary>
/// Initial value to use
/// </summary>
protected T _basis;
/// <summary>
/// Round prime to use
/// </summary>
protected T _prime;
/// <inheritdoc/>
public override void Reset()
{
_hash = _basis;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,60 +5,6 @@ namespace SabreTools.Hashing
#region 0-byte file constants
public const long SizeZero = 0;
public const string CRCZero = "00000000";
public static readonly byte[] CRCZeroBytes = [0x00, 0x00, 0x00, 0x00];
public const string MD5Zero = "d41d8cd98f00b204e9800998ecf8427e";
public static readonly byte[] MD5ZeroBytes = [ 0xd4, 0x1d, 0x8c, 0xd9,
0x8f, 0x00, 0xb2, 0x04,
0xe9, 0x80, 0x09, 0x98,
0xec, 0xf8, 0x42, 0x7e ];
public const string SHA1Zero = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
public static readonly byte[] SHA1ZeroBytes = [ 0xda, 0x39, 0xa3, 0xee,
0x5e, 0x6b, 0x4b, 0x0d,
0x32, 0x55, 0xbf, 0xef,
0x95, 0x60, 0x18, 0x90,
0xaf, 0xd8, 0x07, 0x09 ];
public const string SHA256Zero = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
public static readonly byte[] SHA256ZeroBytes = [ 0xba, 0x78, 0x16, 0xbf,
0x8f, 0x01, 0xcf, 0xea,
0x41, 0x41, 0x40, 0xde,
0x5d, 0xae, 0x22, 0x23,
0xb0, 0x03, 0x61, 0xa3,
0x96, 0x17, 0x7a, 0x9c,
0xb4, 0x10, 0xff, 0x61,
0xf2, 0x00, 0x15, 0xad ];
public const string SHA384Zero = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
public static readonly byte[] SHA384ZeroBytes = [ 0xcb, 0x00, 0x75, 0x3f,
0x45, 0xa3, 0x5e, 0x8b,
0xb5, 0xa0, 0x3d, 0x69,
0x9a, 0xc6, 0x50, 0x07,
0x27, 0x2c, 0x32, 0xab,
0x0e, 0xde, 0xd1, 0x63,
0x1a, 0x8b, 0x60, 0x5a,
0x43, 0xff, 0x5b, 0xed,
0x80, 0x86, 0x07, 0x2b,
0xa1, 0xe7, 0xcc, 0x23,
0x58, 0xba, 0xec, 0xa1,
0x34, 0xc8, 0x25, 0xa7 ];
public const string SHA512Zero = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
public static readonly byte[] SHA512ZeroBytes = [ 0xdd, 0xaf, 0x35, 0xa1,
0x93, 0x61, 0x7a, 0xba,
0xcc, 0x41, 0x73, 0x49,
0xae, 0x20, 0x41, 0x31,
0x12, 0xe6, 0xfa, 0x4e,
0x89, 0xa9, 0x7e, 0xa2,
0x0a, 0x9e, 0xee, 0xe6,
0x4b, 0x55, 0xd3, 0x9a,
0x21, 0x92, 0x99, 0x2a,
0x27, 0x4f, 0xc1, 0xa8,
0x36, 0xba, 0x3c, 0x23,
0xa3, 0xfe, 0xeb, 0xbd,
0x45, 0x4d, 0x44, 0x23,
0x64, 0x3c, 0xe8, 0x0e,
0x2a, 0x9a, 0xc9, 0x4f,
0xa5, 0x4c, 0xa4, 0x9f ];
public const string SpamSumZero = "QXX";
public static readonly byte[] SpamSumZeroBytes = [0x51, 0x58, 0x58];
#endregion

View File

@@ -0,0 +1,181 @@
using System;
namespace SabreTools.Hashing
{
internal static class HashOperations
{
#region Conversions
/// <summary>
/// Convert a byte array to a hex string
/// </summary>
/// <param name="bytes">Byte array to convert</param>
/// <returns>Hex string representing the byte array</returns>
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
public static string? ByteArrayToString(byte[]? bytes)
{
// If we get null in, we send null out
if (bytes == null)
return null;
try
{
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", string.Empty).ToLowerInvariant();
}
catch
{
return null;
}
}
/// <summary>
/// Convert a byte array to a UInt64
/// </summary>
/// <param name="bytes">Byte array to convert</param>
/// <returns>UInt64 representing the byte array</returns>
/// <link>https://stackoverflow.com/questions/66750224/how-to-convert-a-byte-array-of-any-size-to-ulong-in-c</link>
public static ulong BytesToUInt64(byte[]? bytes)
{
// If we get null in, we send 0 out
if (bytes == null)
return default;
ulong result = 0;
for (int i = 0; i < bytes.Length; i++)
{
result |= (ulong)bytes[i] << (i * 8);
}
return result;
}
#endregion
#region Read Big-Endian
/// <summary>
/// 32-bit big-endian read
/// </summary>
public static uint ReadBE32(byte[] data, int offset)
{
return (uint)(data[offset + 3]
| data[offset + 2] << 8
| data[offset + 1] << 16
| data[offset + 0] << 24);
}
/// <summary>
/// 64-bit big-endian read
/// </summary>
public static ulong ReadBE64(byte[] data, int offset)
{
return data[offset + 7]
| (ulong)data[offset + 6] << 8
| (ulong)data[offset + 5] << 16
| (ulong)data[offset + 4] << 24
| (ulong)data[offset + 3] << 32
| (ulong)data[offset + 2] << 40
| (ulong)data[offset + 1] << 48
| (ulong)data[offset + 0] << 56;
}
#endregion
#region Read Litte-Endian
/// <summary>
/// 32-bit little-endian read
/// </summary>
public static uint ReadLE32(byte[] data, int offset)
{
return (uint)(data[offset + 0]
| data[offset + 1] << 8
| data[offset + 2] << 16
| data[offset + 3] << 24);
}
/// <summary>
/// 64-bit little-endian read
/// </summary>
public static ulong ReadLE64(byte[] data, int offset)
{
return data[offset + 0]
| (ulong)data[offset + 1] << 8
| (ulong)data[offset + 2] << 16
| (ulong)data[offset + 3] << 24
| (ulong)data[offset + 4] << 32
| (ulong)data[offset + 5] << 40
| (ulong)data[offset + 6] << 48
| (ulong)data[offset + 7] << 56;
}
#endregion
#region Reverse
/// <summary>
/// Reverse the endianness of a value
/// </summary>
public static ulong ReverseBits(ulong value, int bitWidth)
{
ulong reverse = 0;
for (int i = 0; i < bitWidth; i++)
{
reverse <<= 1;
reverse |= value & 1;
value >>= 1;
}
return reverse;
}
#endregion
#region Rotate
/// <summary>
/// 32-bit rotate left.
/// </summary>
public static uint RotateLeft32(uint x, int r)
=> (x << r) | (x >> (32 - r));
/// <summary>
/// 64-bit rotate left.
/// </summary>
public static ulong RotateLeft64(ulong x, int r)
=> (x << r) | (x >> (64 - r));
#endregion
#region Swap
/// <summary>
/// A 32-bit byteswap.
/// </summary>
public static uint Swap32(uint x)
{
return ((x << 24) & 0xff000000)
| ((x << 8) & 0x00ff0000)
| ((x >> 8) & 0x0000ff00)
| ((x >> 24) & 0x000000ff);
}
/// <summary>
/// A 64-bit byteswap.
/// </summary>
public static ulong Swap64(ulong x)
{
return ((x << 56) & 0xff00000000000000)
| ((x << 40) & 0x00ff000000000000)
| ((x << 24) & 0x0000ff0000000000)
| ((x << 8) & 0x000000ff00000000)
| ((x >> 8) & 0x00000000ff000000)
| ((x >> 24) & 0x0000000000ff0000)
| ((x >> 40) & 0x000000000000ff00)
| ((x >> 56) & 0x00000000000000ff);
}
#endregion
}
}

View File

@@ -342,6 +342,21 @@ namespace SabreTools.Hashing
// Create the output dictionary
var hashDict = new Dictionary<HashType, string?>();
try
{
// Shortcut if we have a 0-byte input
if (input.Length == 0)
{
foreach (var hashType in hashTypes)
{
hashDict[hashType] = ZeroHash.GetString(hashType);
}
return hashDict;
}
}
catch { }
// Run the hashing
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
if (hashers == null)
@@ -373,6 +388,21 @@ namespace SabreTools.Hashing
// Create the output dictionary
var hashDict = new Dictionary<HashType, byte[]?>();
try
{
// Shortcut if we have a 0-byte input
if (input.Length == 0)
{
foreach (var hashType in hashTypes)
{
hashDict[hashType] = ZeroHash.GetBytes(hashType);
}
return hashDict;
}
}
catch { }
// Run the hashing
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
if (hashers == null)

View File

@@ -17,51 +17,693 @@ namespace SabreTools.Hashing
BLAKE3,
#endif
// <summary>
/// CRC 16-bit checksum using the CCITT polynomial
/// </summary>
CRC16_CCITT,
#region CRC
// <summary>
/// CRC 16-bit checksum using the IBM polynomial
#region CRC-1
/// <summary>
/// CRC 1-bit checksum (CRC-1/ZERO [Parity bit with 0 start])
/// </summary>
CRC16_IBM,
CRC1_ZERO,
/// <summary>
/// CRC 1-bit checksum (CRC-1/ONE [Parity bit with 1 start])
/// </summary>
CRC1_ONE,
#endregion
#region CRC-3
/// <summary>
/// CRC 3-bit checksum (CRC-3/GSM)
/// </summary>
CRC3_GSM,
/// <summary>
/// CRC 3-bit checksum (CRC-3/ROHC)
/// </summary>
CRC3_ROHC,
#endregion
#region CRC-4
/// <summary>
/// CRC 4-bit checksum (CRC-4/G-704 [CRC-4/ITU])
/// </summary>
CRC4_G704,
/// <summary>
/// CRC 4-bit checksum (CRC-4/INTERLAKEN)
/// </summary>
CRC4_INTERLAKEN,
#endregion
#region CRC-5
/// <summary>
/// CRC 5-bit checksum (CRC-5/EPC-C1G2 [CRC-5/EPC])
/// </summary>
CRC5_EPCC1G2,
/// <summary>
/// CRC 5-bit checksum (CRC-5/G-704 [CRC-5/ITU])
/// </summary>
CRC5_G704,
/// <summary>
/// CRC 5-bit checksum (CRC-5/USB)
/// </summary>
CRC5_USB,
#endregion
#region CRC-6
/// <summary>
/// CRC 6-bit checksum (CRC-6/CDMA2000-A)
/// </summary>
CRC6_CDMA2000A,
/// <summary>
/// CRC 6-bit checksum (CRC-6/CDMA2000-B)
/// </summary>
CRC6_CDMA2000B,
/// <summary>
/// CRC 6-bit checksum (CRC-6/DARC)
/// </summary>
CRC6_DARC,
/// <summary>
/// CRC 6-bit checksum (CRC-6/G-704 [CRC-6/ITU])
/// </summary>
CRC6_G704,
/// <summary>
/// CRC 6-bit checksum (CRC-6/GSM)
/// </summary>
CRC6_GSM,
#endregion
#region CRC-7
/// <summary>
/// CRC 7-bit checksum (CRC-7/MMC [CRC-7])
/// </summary>
CRC7_MMC,
/// <summary>
/// CRC 7-bit checksum (CRC-7/ROHC)
/// </summary>
CRC7_ROHC,
/// <summary>
/// CRC 7-bit checksum (CRC-7/UMTS)
/// </summary>
CRC7_UMTS,
#endregion
#region CRC-8
/// <summary>
/// CRC 8-bit checksum
/// </summary>
/// <remarks>Identical to <see cref="CRC8_SMBUS"/>
CRC8,
/// <summary>
/// CRC 8-bit checksum (CRC-8/AUTOSAR)
/// </summary>
CRC8_AUTOSAR,
/// <summary>
/// CRC 8-bit checksum (CRC-8/BLUETOOTH)
/// </summary>
CRC8_BLUETOOTH,
/// <summary>
/// CRC 8-bit checksum (CRC-8/CDMA2000)
/// </summary>
CRC8_CDMA2000,
/// <summary>
/// CRC 8-bit checksum (CRC-8/DARC)
/// </summary>
CRC8_DARC,
/// <summary>
/// CRC 8-bit checksum (CRC-8/DVB-S2)
/// </summary>
CRC8_DVBS2,
/// <summary>
/// CRC 8-bit checksum (CRC-8/GSM-A)
/// </summary>
CRC8_GSMA,
/// <summary>
/// CRC 8-bit checksum (CRC-8/GSM-B)
/// </summary>
CRC8_GSMB,
/// <summary>
/// CRC 8-bit checksum (CRC-8/HITAG)
/// </summary>
CRC8_HITAG,
/// <summary>
/// CRC 8-bit checksum (CRC-8/I-432-1 [CRC-8/ITU])
/// </summary>
CRC8_I4321,
/// <summary>
/// CRC 8-bit checksum (CRC-8/I-CODE)
/// </summary>
CRC8_ICODE,
/// <summary>
/// CRC 8-bit checksum (CRC-8/LTE)
/// </summary>
CRC8_LTE,
/// <summary>
/// CRC 8-bit checksum (CRC-8/MAXIM-DOW [CRC-8/MAXIM, DOW-CRC])
/// </summary>
CRC8_MAXIMDOW,
/// <summary>
/// CRC 8-bit checksum (CRC-8/MIFARE-MAD)
/// </summary>
CRC8_MIFAREMAD,
/// <summary>
/// CRC 8-bit checksum (CRC-8/NRSC-5)
/// </summary>
CRC8_NRSC5,
/// <summary>
/// CRC 8-bit checksum (CRC-8/OPENSAFETY)
/// </summary>
CRC8_OPENSAFETY,
/// <summary>
/// CRC 8-bit checksum (CRC-8/ROHC)
/// </summary>
CRC8_ROHC,
/// <summary>
/// CRC 8-bit checksum (CRC-8/SAE-J1850)
/// </summary>
CRC8_SAEJ1850,
/// <summary>
/// CRC 8-bit checksum (CRC-8/SMBUS [CRC-8])
/// </summary>
CRC8_SMBUS,
/// <summary>
/// CRC 8-bit checksum (CRC-8/TECH-3250 [CRC-8/AES, CRC-8/EBU])
/// </summary>
CRC8_TECH3250,
/// <summary>
/// CRC 8-bit checksum (CRC-8/WCDMA)
/// </summary>
CRC8_WCDMA,
#endregion
#region CRC-10
/// <summary>
/// CRC 10-bit checksum (CRC-10/ATM [CRC-10, CRC-10/I-610])
/// </summary>
CRC10_ATM,
/// <summary>
/// CRC 10-bit checksum (CRC-10/CDMA2000)
/// </summary>
CRC10_CDMA2000,
/// <summary>
/// CRC 10-bit checksum (CRC-10/GSM)
/// </summary>
CRC10_GSM,
#endregion
#region CRC-11
/// <summary>
/// CRC 11-bit checksum (CRC-11/FLEXRAY [CRC-11])
/// </summary>
CRC11_FLEXRAY,
/// <summary>
/// CRC 11-bit checksum (CRC-11/UMTS)
/// </summary>
CRC11_UMTS,
#endregion
#region CRC-12
/// <summary>
/// CRC 12-bit checksum (CRC-12/CDMA2000)
/// </summary>
CRC12_CDMA2000,
/// <summary>
/// CRC 12-bit checksum (CRC-12/DECT [X-CRC-12])
/// </summary>
CRC12_DECT,
/// <summary>
/// CRC 12-bit checksum (CRC-12/GSM)
/// </summary>
CRC12_GSM,
/// <summary>
/// CRC 12-bit checksum (CRC-12/UMTS [CRC-12/3GPP])
/// </summary>
CRC12_UMTS,
#endregion
#region CRC-13
/// <summary>
/// CRC 13-bit checksum (CRC-13/BBC)
/// </summary>
CRC13_BBC,
#endregion
#region CRC-14
/// <summary>
/// CRC 14-bit checksum (CRC-14/DARC)
/// </summary>
CRC14_DARC,
/// <summary>
/// CRC 14-bit checksum (CRC-14/GSM)
/// </summary>
CRC14_GSM,
#endregion
#region CRC-15
/// <summary>
/// CRC 15-bit checksum (CRC-15/CAN [CRC-15])
/// </summary>
CRC15_CAN,
/// <summary>
/// CRC 15-bit checksum (CRC-15/MPT1327)
/// </summary>
CRC15_MPT1327,
#endregion
#region CRC-16
/// <summary>
/// CRC 16-bit checksum
/// </summary>
/// <remarks>Identical to <see cref="CRC16_ARC"/>
CRC16,
/// <summary>
/// CRC 16-bit checksum (CRC-16/ARC [ARC, CRC-16, CRC-16/LHA, CRC-IBM])
/// </summary>
CRC16_ARC,
/// <summary>
/// CRC 16-bit checksum (CRC-16/CDMA2000)
/// </summary>
CRC16_CDMA2000,
/// <summary>
/// CRC 16-bit checksum (CRC-16/CMS)
/// </summary>
CRC16_CMS,
/// <summary>
/// CRC 16-bit checksum (CRC-16/DDS-110)
/// </summary>
CRC16_DDS110,
/// <summary>
/// CRC 16-bit checksum (CRC-16/DECT-R [R-CRC-16])
/// </summary>
CRC16_DECTR,
/// <summary>
/// CRC 16-bit checksum (CRC-16/DECT-X [X-CRC-16])
/// </summary>
CRC16_DECTX,
/// <summary>
/// CRC 16-bit checksum (CRC-16/DNP)
/// </summary>
CRC16_DNP,
/// <summary>
/// CRC 16-bit checksum (CRC-16/EN-13757)
/// </summary>
CRC16_EN13757,
/// <summary>
/// CRC 16-bit checksum (CRC-16/GENIBUS [CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE])
/// </summary>
CRC16_GENIBUS,
/// <summary>
/// CRC 16-bit checksum (CRC-16/GSM)
/// </summary>
CRC16_GSM,
/// <summary>
/// CRC 16-bit checksum (CRC-16/IBM-3740 [CRC-16/AUTOSAR, CRC-16/CCITT-FALSE])
/// </summary>
CRC16_IBM3740,
/// <summary>
/// CRC 16-bit checksum (CRC-16/IBM-SDLC [CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25])
/// </summary>
CRC16_IBMSDLC,
/// <summary>
/// CRC 16-bit checksum (CRC-16/ISO-IEC-14443-3-A [CRC-A])
/// </summary>
CRC16_ISOIEC144433A,
/// <summary>
/// CRC 16-bit checksum (CRC-16/KERMIT [CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT])
/// </summary>
CRC16_KERMIT,
/// <summary>
/// CRC 16-bit checksum (CRC-16/LJ1200)
/// </summary>
CRC16_LJ1200,
/// <summary>
/// CRC 16-bit checksum (CRC-16/M17)
/// </summary>
CRC16_M17,
/// <summary>
/// CRC 16-bit checksum (CRC-16/MAXIM-DOW [CRC-16/MAXIM])
/// </summary>
CRC16_MAXIMDOW,
/// <summary>
/// CRC 16-bit checksum (CRC-16/MCRF4XX)
/// </summary>
CRC16_MCRF4XX,
/// <summary>
/// CRC 16-bit checksum (CRC-16/MODBUS [MODBUS])
/// </summary>
CRC16_MODBUS,
/// <summary>
/// CRC 16-bit checksum (CRC-16/NRSC-5)
/// </summary>
CRC16_NRSC5,
/// <summary>
/// CRC 16-bit checksum (CRC-16/OPENSAFETY-A)
/// </summary>
CRC16_OPENSAFETYA,
/// <summary>
/// CRC 16-bit checksum (CRC-16/OPENSAFETY-B)
/// </summary>
CRC16_OPENSAFETYB,
/// <summary>
/// CRC 16-bit checksum (CRC-16/PROFIBUS [CRC-16/IEC-61158-2])
/// </summary>
CRC16_PROFIBUS,
/// <summary>
/// CRC 16-bit checksum (CRC-16/RIELLO)
/// </summary>
CRC16_RIELLO,
/// <summary>
/// CRC 16-bit checksum (CRC-16/SPI-FUJITSU [CRC-16/AUG-CCITT])
/// </summary>
CRC16_SPIFUJITSU,
/// <summary>
/// CRC 16-bit checksum (CRC-16/T10-DIF)
/// </summary>
CRC16_T10DIF,
/// <summary>
/// CRC 16-bit checksum (CRC-16/TELEDISK)
/// </summary>
CRC16_TELEDISK,
/// <summary>
/// CRC 16-bit checksum (CRC-16/TMS37157)
/// </summary>
CRC16_TMS37157,
/// <summary>
/// CRC 16-bit checksum (CRC-16/UMTS [CRC-16/BUYPASS, CRC-16/VERIFONE])
/// </summary>
CRC16_UMTS,
/// <summary>
/// CRC 16-bit checksum (CRC-16/USB)
/// </summary>
CRC16_USB,
/// <summary>
/// CRC 16-bit checksum (CRC-16/XMODEM [CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM])
/// </summary>
CRC16_XMODEM,
#endregion
#region CRC-17
/// <summary>
/// CRC 17-bit checksum (CRC-17/CAN-FD)
/// </summary>
CRC17_CANFD,
#endregion
#region CRC-21
/// <summary>
/// CRC 21-bit checksum (CRC-21/CAN-FD)
/// </summary>
CRC21_CANFD,
#endregion
#region CRC-24
/// <summary>
/// CRC 24-bit checksum (CRC-24/BLE)
/// </summary>
CRC24_BLE,
/// <summary>
/// CRC 24-bit checksum (CRC-24/FLEXRAY-A)
/// </summary>
CRC24_FLEXRAYA,
/// <summary>
/// CRC 24-bit checksum (CRC-24/FLEXRAY-B)
/// </summary>
CRC24_FLEXRAYB,
/// <summary>
/// CRC 24-bit checksum (CRC-24/INTERLAKEN)
/// </summary>
CRC24_INTERLAKEN,
/// <summary>
/// CRC 24-bit checksum (CRC-24/LTE-A)
/// </summary>
CRC24_LTEA,
/// <summary>
/// CRC 24-bit checksum (CRC-24/LTE-B)
/// </summary>
CRC24_LTEB,
/// <summary>
/// CRC 24-bit checksum (CRC-24/OPENPGP)
/// </summary>
CRC24_OPENPGP,
/// <summary>
/// CRC 24-bit checksum (CRC-24/OS-9)
/// </summary>
CRC24_OS9,
#endregion
#region CRC-30
/// <summary>
/// CRC 30-bit checksum (CRC-30/CDMA)
/// </summary>
CRC30_CDMA,
#endregion
#region CRC-31
/// <summary>
/// CRC 31-bit checksum (CRC-31/PHILIPS)
/// </summary>
CRC31_PHILIPS,
#endregion
#region CRC-32
/// <summary>
/// CRC 32-bit checksum
/// </summary>
/// <remarks>Same as CRC32_ISO in .NET Framework 4.5.2 and lower</remarks>
/// <remarks>Identical to <see cref="CRC32_ISOHDLC"/>
CRC32,
/// <summary>
/// CRC 32-bit checksum (ISO implementation)
/// CRC 32-bit checksum (CRC-32/AIXM)
/// </summary>
CRC32_ISO,
CRC32_AIXM,
/// <summary>
/// CRC 32-bit checksum (NaiveCRC implementation)
/// CRC 32-bit checksum (CRC-32/AUTOSAR)
/// </summary>
CRC32_Naive,
CRC32_AUTOSAR,
/// <summary>
/// CRC 32-bit checksum (OptimizedCRC implementation)
/// CRC 32-bit checksum (CRC-32/BASE91-D)
/// </summary>
CRC32_Optimized,
CRC32_BASE91D,
/// <summary>
/// CRC 32-bit checksum (ParallelCRC implementation)
/// CRC 32-bit checksum (BZIP2)
/// </summary>
CRC32_Parallel,
CRC32_BZIP2,
/// <summary>
/// CRC 64-bit checksum (0x42F0E1EBA9EA3693 polynomial)
/// CRC 32-bit checksum (CRC-32/CD-ROM-EDC)
/// </summary>
CRC32_CDROMEDC,
/// <summary>
/// CRC 32-bit checksum (CRC-32/CKSUM)
/// </summary>
CRC32_CKSUM,
/// <summary>
/// CRC 32-bit checksum (CRC-32/ISCSI)
/// </summary>
CRC32_ISCSI,
/// <summary>
/// CRC 32-bit checksum (CRC-32/ISO-HDLC)
/// </summary>
CRC32_ISOHDLC,
/// <summary>
/// CRC 32-bit checksum (CRC-32/JAMCRC)
/// </summary>
CRC32_JAMCRC,
/// <summary>
/// CRC 32-bit checksum (CRC-32/MEF)
/// </summary>
CRC32_MEF,
/// <summary>
/// CRC 32-bit checksum (CRC-32/MPEG-2)
/// </summary>
CRC32_MPEG2,
/// <summary>
/// CRC 32-bit checksum (CRC-32/XFER)
/// </summary>
CRC32_XFER,
#endregion
#region CRC-40
/// <summary>
/// CRC 40-bit checksum (CRC-40/GSM)
/// </summary>
CRC40_GSM,
#endregion
#region CRC-64
/// <summary>
/// CRC 64-bit checksum
/// </summary>
/// <remarks>Identical to <see cref="CRC64_ECMA182"/>
CRC64,
/// <summary>
/// CRC 64-bit checksum (0xC96C5795D7870F42 polynomial)
/// CRC 64-bit checksum (CRC-64/ECMA-182, Microsoft implementation)
/// </summary>
CRC64_Reversed,
CRC64_ECMA182,
/// <summary>
/// CRC 64-bit checksum (CRC-64/GO-ISO)
/// </summary>
CRC64_GOISO,
/// <summary>
/// CRC 64-bit checksum (CRC-64/MS)
/// </summary>
CRC64_MS,
/// <summary>
/// CRC 64-bit checksum (CRC-64/NVME)
/// </summary>
CRC64_NVME,
/// <summary>
/// CRC 64-bit checksum (CRC-64/REDIS)
/// </summary>
CRC64_REDIS,
/// <summary>
/// CRC 64-bit checksum (CRC-64/WE)
/// </summary>
CRC64_WE,
/// <summary>
/// CRC 64-bit checksum (CRC-64/XZ)
/// </summary>
CRC64_XZ,
#endregion
#endregion
#region Fletcher
/// <summary>
/// John G. Fletcher's 16-bit checksum
@@ -74,16 +716,90 @@ namespace SabreTools.Hashing
Fletcher32,
/// <summary>
/// MD5 hash
/// John G. Fletcher's 64-bit checksum
/// </summary>
Fletcher64,
#endregion
#region FNV
/// <summary>
/// FNV hash (Variant 0, 32-bit)
/// </summary>
FNV0_32,
/// <summary>
/// FNV hash (Variant 0, 64-bit)
/// </summary>
FNV0_64,
/// <summary>
/// FNV hash (Variant 1, 32-bit)
/// </summary>
FNV1_32,
/// <summary>
/// FNV hash (Variant 1, 64-bit)
/// </summary>
FNV1_64,
/// <summary>
/// FNV hash (Variant 1a, 32-bit)
/// </summary>
FNV1a_32,
/// <summary>
/// FNV hash (Variant 1a, 64-bit)
/// </summary>
FNV1a_64,
#endregion
#region Message Digest
/// <summary>
/// MD2 message-digest algorithm
/// </summary>
MD2,
/// <summary>
/// MD4 message-digest algorithm
/// </summary>
MD4,
/// <summary>
/// MD5 message-digest algorithm
/// </summary>
MD5,
#if NETFRAMEWORK
#endregion
#region RIPEMD
/// <summary>
/// RIPEMD160 hash
/// RIPEMD-128 hash
/// </summary>
RIPEMD128,
/// <summary>
/// RIPEMD-160 hash
/// </summary>
RIPEMD160,
#endif
/// <summary>
/// RIPEMD-256 hash
/// </summary>
RIPEMD256,
/// <summary>
/// RIPEMD-320 hash
/// </summary>
RIPEMD320,
#endregion
#region SHA
/// <summary>
/// SHA-1 hash
@@ -134,12 +850,79 @@ namespace SabreTools.Hashing
SHAKE256,
#endif
#endregion
/// <summary>
/// spamsum fuzzy hash
/// </summary>
SpamSum,
#if NET462_OR_GREATER || NETCOREAPP
#region Tiger
/// <summary>
/// Tiger 128-bit hash, 3 passes
/// </summary>
Tiger128_3,
/// <summary>
/// Tiger 128-bit hash, 4 passes
/// </summary>
Tiger128_4,
/// <summary>
/// Tiger 160-bit hash, 3 passes
/// </summary>
Tiger160_3,
/// <summary>
/// Tiger 160-bit hash, 4 passes
/// </summary>
Tiger160_4,
/// <summary>
/// Tiger 192-bit hash, 3 passes
/// </summary>
Tiger192_3,
/// <summary>
/// Tiger 192-bit hash, 4 passes
/// </summary>
Tiger192_4,
/// <summary>
/// Tiger2 128-bit hash, 3 passes
/// </summary>
Tiger2_128_3,
/// <summary>
/// Tiger2 128-bit hash, 4 passes
/// </summary>
Tiger2_128_4,
/// <summary>
/// Tiger2 160-bit hash, 3 passes
/// </summary>
Tiger2_160_3,
/// <summary>
/// Tiger2 160-bit hash, 4 passes
/// </summary>
Tiger2_160_4,
/// <summary>
/// Tiger2 192-bit hash, 3 passes
/// </summary>
Tiger2_192_3,
/// <summary>
/// Tiger2 192-bit hash, 4 passes
/// </summary>
Tiger2_192_4,
#endregion
#region xxHash
/// <summary>
/// xxHash32 hash
/// </summary>
@@ -150,6 +933,7 @@ namespace SabreTools.Hashing
/// </summary>
XxHash64,
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// XXH3 64-bit hash
/// </summary>
@@ -160,5 +944,7 @@ namespace SabreTools.Hashing
/// </summary>
XxHash128,
#endif
#endregion
}
}

View File

@@ -2,14 +2,14 @@ using System;
#if NET462_OR_GREATER || NETCOREAPP
using System.IO.Hashing;
#endif
using System.Linq;
using System.Security.Cryptography;
using Aaru.Checksums;
using Aaru.CommonTypes.Interfaces;
#if NET7_0_OR_GREATER
using Blake3;
#endif
using CRC32;
using SabreTools.Hashing.Checksum;
using static SabreTools.Hashing.HashOperations;
namespace SabreTools.Hashing
{
@@ -32,22 +32,52 @@ namespace SabreTools.Hashing
{
get
{
return _hasher switch
switch (_hasher)
{
HashAlgorithm ha => ha.Hash,
IChecksum ic => ic.Final(),
NaiveCRC ncrc => BitConverter.GetBytes(ncrc.Value).Reverse().ToArray(),
case ChecksumBase cb:
var cbArr = cb.Finalize();
Array.Reverse(cbArr);
return cbArr;
case HashAlgorithm ha:
return ha.Hash;
case IChecksum ic:
return ic.Final();
case MessageDigest.MessageDigestBase mdb:
return mdb.GetHash();
#if NET462_OR_GREATER || NETCOREAPP
NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash().Reverse().ToArray(),
case XxHash3 xxh3:
return xxh3.GetCurrentHash();
case XxHash128 xxh128:
return xxh128.GetCurrentHash();
case NonCryptographicHashAlgorithm ncha:
var nchaArr = ncha.GetCurrentHash();
Array.Reverse(nchaArr);
return nchaArr;
#endif
OptimizedCRC ocrc => BitConverter.GetBytes(ocrc.Value).Reverse().ToArray(),
ParallelCRC pcrc => BitConverter.GetBytes(pcrc.Value).Reverse().ToArray(),
#if NET8_0_OR_GREATER
Shake128 s128 => s128.GetCurrentHash(32),
Shake256 s256 => s256.GetCurrentHash(64),
case Shake128 s128:
return s128.GetCurrentHash(32);
case Shake256 s256:
return s256.GetCurrentHash(64);
#endif
_ => null,
};
case XxHash.XxHash32 xxh32:
var xxh32Arr = xxh32.Finalize();
Array.Reverse(xxh32Arr);
return xxh32Arr;
case XxHash.XxHash64 xxh64:
var xxh64Arr = xxh64.Finalize();
Array.Reverse(xxh64Arr);
return xxh64Arr;
default:
return null;
}
}
}
@@ -58,11 +88,19 @@ namespace SabreTools.Hashing
{
get
{
return _hasher switch
switch (_hasher)
{
IChecksum ic => ic.End(),
_ => ByteArrayToString(CurrentHashBytes),
};
case Crc cr:
var crArr = cr.Finalize();
ulong crHash = BytesToUInt64(crArr);
int length = cr.Def.Width / 4 + (cr.Def.Width % 4 > 0 ? 1 : 0);
return crHash.ToString($"x{length}");
case IChecksum ic:
return ic.End();
default:
return ByteArrayToString(CurrentHashBytes);
}
}
}
@@ -76,11 +114,6 @@ namespace SabreTools.Hashing
/// <remarks>May be either a HashAlgorithm or NonCryptographicHashAlgorithm</remarks>
private object? _hasher;
/// <summary>
/// Non-reversed CRC-64 polynomial
/// </summary>
private const ulong CRC64_ECMA_POLY_NORMAL = 0x42F0E1EBA9EA3693;
#endregion
#region Constructors
@@ -91,7 +124,7 @@ namespace SabreTools.Hashing
/// <param name="hashType">Hash type to instantiate</param>
public HashWrapper(HashType hashType)
{
this.HashType = hashType;
HashType = hashType;
GetHasher();
}
@@ -102,33 +135,172 @@ namespace SabreTools.Hashing
{
_hasher = HashType switch
{
HashType.Adler32 => new Adler32Context(),
HashType.Adler32 => new Adler32(),
#if NET7_0_OR_GREATER
HashType.BLAKE3 => new Blake3HashAlgorithm(),
#endif
HashType.CRC16_CCITT => new CRC16CcittContext(),
HashType.CRC16_IBM => new CRC16IbmContext(),
#if NET462_OR_GREATER || NETCOREAPP
HashType.CRC32 => new Crc32(),
#else
HashType.CRC32 => new Crc32Context(),
#endif
HashType.CRC32_ISO => new Crc32Context(),
HashType.CRC32_Naive => new NaiveCRC(),
HashType.CRC32_Optimized => new OptimizedCRC(),
HashType.CRC32_Parallel => new ParallelCRC(),
#if NET462_OR_GREATER || NETCOREAPP
HashType.CRC64 => new Crc64(),
#else
HashType.CRC64 => new Crc64Context(CRC64_ECMA_POLY_NORMAL, 0xFFFFFFFFFFFFFFFF),
#endif
HashType.CRC64_Reversed => new Crc64Context(),
HashType.Fletcher16 => new Fletcher16Context(),
HashType.Fletcher32 => new Fletcher32Context(),
HashType.CRC1_ZERO => new Crc(StandardDefinitions.CRC1_ZERO),
HashType.CRC1_ONE => new Crc(StandardDefinitions.CRC1_ONE),
HashType.CRC3_GSM => new Crc(StandardDefinitions.CRC3_GSM),
HashType.CRC3_ROHC => new Crc(StandardDefinitions.CRC3_ROHC),
HashType.CRC4_G704 => new Crc(StandardDefinitions.CRC4_G704),
HashType.CRC4_INTERLAKEN => new Crc(StandardDefinitions.CRC4_INTERLAKEN),
HashType.CRC5_EPCC1G2 => new Crc(StandardDefinitions.CRC5_EPCC1G2),
HashType.CRC5_G704 => new Crc(StandardDefinitions.CRC5_G704),
HashType.CRC5_USB => new Crc(StandardDefinitions.CRC5_USB),
HashType.CRC6_CDMA2000A => new Crc(StandardDefinitions.CRC6_CDMA2000A),
HashType.CRC6_CDMA2000B => new Crc(StandardDefinitions.CRC6_CDMA2000B),
HashType.CRC6_DARC => new Crc(StandardDefinitions.CRC6_DARC),
HashType.CRC6_G704 => new Crc(StandardDefinitions.CRC6_G704),
HashType.CRC6_GSM => new Crc(StandardDefinitions.CRC6_GSM),
HashType.CRC7_MMC => new Crc(StandardDefinitions.CRC7_MMC),
HashType.CRC7_ROHC => new Crc(StandardDefinitions.CRC7_ROHC),
HashType.CRC7_UMTS => new Crc(StandardDefinitions.CRC7_UMTS),
HashType.CRC8 => new Crc(StandardDefinitions.CRC8_SMBUS),
HashType.CRC8_AUTOSAR => new Crc(StandardDefinitions.CRC8_AUTOSAR),
HashType.CRC8_BLUETOOTH => new Crc(StandardDefinitions.CRC8_BLUETOOTH),
HashType.CRC8_CDMA2000 => new Crc(StandardDefinitions.CRC8_CDMA2000),
HashType.CRC8_DARC => new Crc(StandardDefinitions.CRC8_DARC),
HashType.CRC8_DVBS2 => new Crc(StandardDefinitions.CRC8_DVBS2),
HashType.CRC8_GSMA => new Crc(StandardDefinitions.CRC8_GSMA),
HashType.CRC8_GSMB => new Crc(StandardDefinitions.CRC8_GSMB),
HashType.CRC8_HITAG => new Crc(StandardDefinitions.CRC8_HITAG),
HashType.CRC8_I4321 => new Crc(StandardDefinitions.CRC8_I4321),
HashType.CRC8_ICODE => new Crc(StandardDefinitions.CRC8_ICODE),
HashType.CRC8_LTE => new Crc(StandardDefinitions.CRC8_LTE),
HashType.CRC8_MAXIMDOW => new Crc(StandardDefinitions.CRC8_MAXIMDOW),
HashType.CRC8_MIFAREMAD => new Crc(StandardDefinitions.CRC8_MIFAREMAD),
HashType.CRC8_NRSC5 => new Crc(StandardDefinitions.CRC8_NRSC5),
HashType.CRC8_OPENSAFETY => new Crc(StandardDefinitions.CRC8_OPENSAFETY),
HashType.CRC8_ROHC => new Crc(StandardDefinitions.CRC8_ROHC),
HashType.CRC8_SAEJ1850 => new Crc(StandardDefinitions.CRC8_SAEJ1850),
HashType.CRC8_SMBUS => new Crc(StandardDefinitions.CRC8_SMBUS),
HashType.CRC8_TECH3250 => new Crc(StandardDefinitions.CRC8_TECH3250),
HashType.CRC8_WCDMA => new Crc(StandardDefinitions.CRC8_WCDMA),
HashType.CRC10_ATM => new Crc(StandardDefinitions.CRC10_ATM),
HashType.CRC10_CDMA2000 => new Crc(StandardDefinitions.CRC10_CDMA2000),
HashType.CRC10_GSM => new Crc(StandardDefinitions.CRC10_GSM),
HashType.CRC11_FLEXRAY => new Crc(StandardDefinitions.CRC11_FLEXRAY),
HashType.CRC11_UMTS => new Crc(StandardDefinitions.CRC11_UMTS),
HashType.CRC12_CDMA2000 => new Crc(StandardDefinitions.CRC12_CDMA2000),
HashType.CRC12_DECT => new Crc(StandardDefinitions.CRC12_DECT),
HashType.CRC12_GSM => new Crc(StandardDefinitions.CRC12_GSM),
HashType.CRC12_UMTS => new Crc(StandardDefinitions.CRC12_UMTS),
HashType.CRC13_BBC => new Crc(StandardDefinitions.CRC13_BBC),
HashType.CRC14_DARC => new Crc(StandardDefinitions.CRC14_DARC),
HashType.CRC14_GSM => new Crc(StandardDefinitions.CRC14_GSM),
HashType.CRC15_CAN => new Crc(StandardDefinitions.CRC15_CAN),
HashType.CRC15_MPT1327 => new Crc(StandardDefinitions.CRC15_MPT1327),
HashType.CRC16 => new Crc(StandardDefinitions.CRC16_ARC),
HashType.CRC16_ARC => new Crc(StandardDefinitions.CRC16_ARC),
HashType.CRC16_CDMA2000 => new Crc(StandardDefinitions.CRC16_CDMA2000),
HashType.CRC16_CMS => new Crc(StandardDefinitions.CRC16_CMS),
HashType.CRC16_DDS110 => new Crc(StandardDefinitions.CRC16_DDS110),
HashType.CRC16_DECTR => new Crc(StandardDefinitions.CRC16_DECTR),
HashType.CRC16_DECTX => new Crc(StandardDefinitions.CRC16_DECTX),
HashType.CRC16_DNP => new Crc(StandardDefinitions.CRC16_DNP),
HashType.CRC16_EN13757 => new Crc(StandardDefinitions.CRC16_EN13757),
HashType.CRC16_GENIBUS => new Crc(StandardDefinitions.CRC16_GENIBUS),
HashType.CRC16_GSM => new Crc(StandardDefinitions.CRC16_GSM),
HashType.CRC16_IBM3740 => new Crc(StandardDefinitions.CRC16_IBM3740),
HashType.CRC16_IBMSDLC => new Crc(StandardDefinitions.CRC16_IBMSDLC),
HashType.CRC16_ISOIEC144433A => new Crc(StandardDefinitions.CRC16_ISOIEC144433A),
HashType.CRC16_KERMIT => new Crc(StandardDefinitions.CRC16_KERMIT),
HashType.CRC16_LJ1200 => new Crc(StandardDefinitions.CRC16_LJ1200),
HashType.CRC16_M17 => new Crc(StandardDefinitions.CRC16_M17),
HashType.CRC16_MAXIMDOW => new Crc(StandardDefinitions.CRC16_MAXIMDOW),
HashType.CRC16_MCRF4XX => new Crc(StandardDefinitions.CRC16_MCRF4XX),
HashType.CRC16_MODBUS => new Crc(StandardDefinitions.CRC16_MODBUS),
HashType.CRC16_NRSC5 => new Crc(StandardDefinitions.CRC16_NRSC5),
HashType.CRC16_OPENSAFETYA => new Crc(StandardDefinitions.CRC16_OPENSAFETYA),
HashType.CRC16_OPENSAFETYB => new Crc(StandardDefinitions.CRC16_OPENSAFETYB),
HashType.CRC16_PROFIBUS => new Crc(StandardDefinitions.CRC16_PROFIBUS),
HashType.CRC16_RIELLO => new Crc(StandardDefinitions.CRC16_RIELLO),
HashType.CRC16_SPIFUJITSU => new Crc(StandardDefinitions.CRC16_SPIFUJITSU),
HashType.CRC16_T10DIF => new Crc(StandardDefinitions.CRC16_T10DIF),
HashType.CRC16_TELEDISK => new Crc(StandardDefinitions.CRC16_TELEDISK),
HashType.CRC16_TMS37157 => new Crc(StandardDefinitions.CRC16_TMS37157),
HashType.CRC16_UMTS => new Crc(StandardDefinitions.CRC16_UMTS),
HashType.CRC16_USB => new Crc(StandardDefinitions.CRC16_USB),
HashType.CRC16_XMODEM => new Crc(StandardDefinitions.CRC16_XMODEM),
HashType.CRC17_CANFD => new Crc(StandardDefinitions.CRC17_CANFD),
HashType.CRC21_CANFD => new Crc(StandardDefinitions.CRC21_CANFD),
HashType.CRC24_BLE => new Crc(StandardDefinitions.CRC24_BLE),
HashType.CRC24_FLEXRAYA => new Crc(StandardDefinitions.CRC24_FLEXRAYA),
HashType.CRC24_FLEXRAYB => new Crc(StandardDefinitions.CRC24_FLEXRAYB),
HashType.CRC24_INTERLAKEN => new Crc(StandardDefinitions.CRC24_INTERLAKEN),
HashType.CRC24_LTEA => new Crc(StandardDefinitions.CRC24_LTEA),
HashType.CRC24_LTEB => new Crc(StandardDefinitions.CRC24_LTEB),
HashType.CRC24_OPENPGP => new Crc(StandardDefinitions.CRC24_OPENPGP),
HashType.CRC24_OS9 => new Crc(StandardDefinitions.CRC24_OS9),
HashType.CRC30_CDMA => new Crc(StandardDefinitions.CRC30_CDMA),
HashType.CRC31_PHILIPS => new Crc(StandardDefinitions.CRC31_PHILIPS),
HashType.CRC32 => new Crc(StandardDefinitions.CRC32_ISOHDLC),
HashType.CRC32_AIXM => new Crc(StandardDefinitions.CRC32_AIXM),
HashType.CRC32_AUTOSAR => new Crc(StandardDefinitions.CRC32_AUTOSAR),
HashType.CRC32_BASE91D => new Crc(StandardDefinitions.CRC32_BASE91D),
HashType.CRC32_BZIP2 => new Crc(StandardDefinitions.CRC32_BZIP2),
HashType.CRC32_CDROMEDC => new Crc(StandardDefinitions.CRC32_CDROMEDC),
HashType.CRC32_CKSUM => new Crc(StandardDefinitions.CRC32_CKSUM),
HashType.CRC32_ISCSI => new Crc(StandardDefinitions.CRC32_ISCSI),
HashType.CRC32_ISOHDLC => new Crc(StandardDefinitions.CRC32_ISOHDLC),
HashType.CRC32_JAMCRC => new Crc(StandardDefinitions.CRC32_JAMCRC),
HashType.CRC32_MEF => new Crc(StandardDefinitions.CRC32_MEF),
HashType.CRC32_MPEG2 => new Crc(StandardDefinitions.CRC32_MPEG2),
HashType.CRC32_XFER => new Crc(StandardDefinitions.CRC32_XFER),
HashType.CRC40_GSM => new Crc(StandardDefinitions.CRC40_GSM),
HashType.CRC64 => new Crc(StandardDefinitions.CRC64_ECMA182),
HashType.CRC64_ECMA182 => new Crc(StandardDefinitions.CRC64_ECMA182),
HashType.CRC64_GOISO => new Crc(StandardDefinitions.CRC64_GOISO),
HashType.CRC64_MS => new Crc(StandardDefinitions.CRC64_MS),
HashType.CRC64_NVME => new Crc(StandardDefinitions.CRC64_NVME),
HashType.CRC64_REDIS => new Crc(StandardDefinitions.CRC64_REDIS),
HashType.CRC64_WE => new Crc(StandardDefinitions.CRC64_WE),
HashType.CRC64_XZ => new Crc(StandardDefinitions.CRC64_XZ),
HashType.Fletcher16 => new Fletcher16(),
HashType.Fletcher32 => new Fletcher32(),
HashType.Fletcher64 => new Fletcher64(),
HashType.FNV0_32 => new FNV0_32(),
HashType.FNV0_64 => new FNV0_64(),
HashType.FNV1_32 => new FNV1_32(),
HashType.FNV1_64 => new FNV1_64(),
HashType.FNV1a_32 => new FNV1a_32(),
HashType.FNV1a_64 => new FNV1a_64(),
HashType.MD2 => new MessageDigest.MD2(),
HashType.MD4 => new MessageDigest.MD4(),
HashType.MD5 => MD5.Create(),
#if NETFRAMEWORK
HashType.RIPEMD160 => RIPEMD160.Create(),
#endif
HashType.RIPEMD128 => new MessageDigest.RipeMD128(),
HashType.RIPEMD160 => new MessageDigest.RipeMD160(),
HashType.RIPEMD256 => new MessageDigest.RipeMD256(),
HashType.RIPEMD320 => new MessageDigest.RipeMD320(),
HashType.SHA1 => SHA1.Create(),
HashType.SHA256 => SHA256.Create(),
HashType.SHA384 => SHA384.Create(),
@@ -140,10 +312,25 @@ namespace SabreTools.Hashing
HashType.SHAKE128 => Shake128.IsSupported ? new Shake128() : null,
HashType.SHAKE256 => Shake256.IsSupported ? new Shake256() : null,
#endif
HashType.SpamSum => new SpamSumContext(),
HashType.Tiger128_3 => new MessageDigest.Tiger128_3(),
HashType.Tiger128_4 => new MessageDigest.Tiger128_4(),
HashType.Tiger160_3 => new MessageDigest.Tiger160_3(),
HashType.Tiger160_4 => new MessageDigest.Tiger160_4(),
HashType.Tiger192_3 => new MessageDigest.Tiger192_3(),
HashType.Tiger192_4 => new MessageDigest.Tiger192_4(),
HashType.Tiger2_128_3 => new MessageDigest.Tiger2_128_3(),
HashType.Tiger2_128_4 => new MessageDigest.Tiger2_128_4(),
HashType.Tiger2_160_3 => new MessageDigest.Tiger2_160_3(),
HashType.Tiger2_160_4 => new MessageDigest.Tiger2_160_4(),
HashType.Tiger2_192_3 => new MessageDigest.Tiger2_192_3(),
HashType.Tiger2_192_4 => new MessageDigest.Tiger2_192_4(),
HashType.XxHash32 => new XxHash.XxHash32(),
HashType.XxHash64 => new XxHash.XxHash64(),
#if NET462_OR_GREATER || NETCOREAPP
HashType.XxHash32 => new XxHash32(),
HashType.XxHash64 => new XxHash64(),
HashType.XxHash3 => new XxHash3(),
HashType.XxHash128 => new XxHash128(),
#endif
@@ -169,17 +356,22 @@ namespace SabreTools.Hashing
{
switch (_hasher)
{
case ChecksumBase cb:
cb.TransformBlock(buffer, offset, size);
break;
case HashAlgorithm ha:
ha.TransformBlock(buffer, offset, size, null, 0);
break;
case IChecksum ic:
byte[] icBuffer = GetArraySegment(buffer, offset, size);
ic.Update(icBuffer);
byte[] icBlock = new byte[size];
Array.Copy(buffer, offset, icBlock, 0, size);
ic.Update(icBlock);
break;
case NaiveCRC nc:
nc.Update(buffer, offset, size);
case MessageDigest.MessageDigestBase mdb:
mdb.TransformBlock(buffer, offset, size);
break;
#if NET462_OR_GREATER || NETCOREAPP
@@ -189,25 +381,23 @@ namespace SabreTools.Hashing
break;
#endif
case OptimizedCRC oc:
oc.Update(buffer, offset, size);
break;
case ParallelCRC pc:
pc.Update(buffer, offset, size);
break;
#if NET8_0_OR_GREATER
case Shake128 s128:
var s128BufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
s128.AppendData(s128BufferSpan);
break;
case Shake256 s256:
var s256BufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
s256.AppendData(s256BufferSpan);
break;
#endif
case XxHash.XxHash32 xxh32:
xxh32.TransformBlock(buffer, offset, size);
break;
case XxHash.XxHash64 xxh64:
xxh64.TransformBlock(buffer, offset, size);
break;
}
}
@@ -224,62 +414,12 @@ namespace SabreTools.Hashing
ha.TransformFinalBlock(emptyBuffer, 0, 0);
break;
case NaiveCRC nc:
nc.Update([], 0, 0);
break;
case OptimizedCRC oc:
oc.Update([], 0, 0);
break;
case ParallelCRC pc:
pc.Update([], 0, 0);
case MessageDigest.MessageDigestBase mdb:
mdb.Terminate();
break;
}
}
#endregion
#region Helpers
/// <summary>
/// Convert a byte array to a hex string
/// </summary>
/// <param name="bytes">Byte array to convert</param>
/// <returns>Hex string representing the byte array</returns>
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
private static string? ByteArrayToString(byte[]? bytes)
{
// If we get null in, we send null out
if (bytes == null)
return null;
try
{
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", string.Empty).ToLowerInvariant();
}
catch
{
return null;
}
}
/// <summary>
/// Get a segment from the array based on an offset and size
/// </summary>
private static byte[] GetArraySegment(byte[] buffer, int offset, int size)
{
#if NET452_OR_GREATER || NETCOREAPP
var icBufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
byte[] trimmedBuffer = icBufferSpan.ToArray();
#else
byte[] trimmedBuffer = new byte[size];
Array.Copy(buffer, offset, trimmedBuffer, 0, size);
#endif
return trimmedBuffer;
}
#endregion
}
}

View File

@@ -1,11 +1,182 @@
namespace SabreTools.Hashing.Tiger
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// Tiger S boxes
/// </summary>
public static class SBoxes
internal static class Constants
{
public static readonly ulong[] Table =
// <see href="https://datatracker.ietf.org/doc/html/rfc1115"/>
#region MD2
/// <summary>
/// S-Boxes
/// </summary>
public static readonly byte[] MD2SBox =
[
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
];
#endregion
// <see href="https://datatracker.ietf.org/doc/html/rfc1320"/>
#region MD4
public const uint MD4SeedA = 0x67452301;
public const uint MD4SeedB = 0xefcdab89;
public const uint MD4SeedC = 0x98badcfe;
public const uint MD4SeedD = 0x10325476;
public const uint MD4Round1 = 0x00000000;
public const uint MD4Round2 = 0x5A827999;
public const uint MD4Round3 = 0x6ED9EBA1;
#endregion
// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
#region RIPEMD-128 / RIPEMD-256
public const uint RMD128Round00To15 = 0x00000000;
public const uint RMD128Round16To31 = 0x5A827999;
public const uint RMD128Round32To47 = 0x6ED9EBA1;
public const uint RMD128Round48To63 = 0x8F1BBCDC;
public const uint RMD128RoundPrime00To15 = 0x50A28BE6;
public const uint RMD128RoundPrime16To31 = 0x5C4DD124;
public const uint RMD128RoundPrime32To47 = 0x6D703EF3;
public const uint RMD128RoundPrime48To63 = 0x00000000;
public const uint RMD128Y0 = 0x67452301;
public const uint RMD128Y1 = 0xEFCDAB89;
public const uint RMD128Y2 = 0x98BADCFE;
public const uint RMD128Y3 = 0x10325476;
public const uint RMD256Y4 = 0x76543210;
public const uint RMD256Y5 = 0xFEDCBA98;
public const uint RMD256Y6 = 0x89ABCDEF;
public const uint RMD256Y7 = 0x01234567;
#endregion
// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
#region RIPEMD-160 / RIPEMD-320
public const uint RMD160Round00To15 = 0x00000000;
public const uint RMD160Round16To31 = 0x5A827999;
public const uint RMD160Round32To47 = 0x6ED9EBA1;
public const uint RMD160Round48To63 = 0x8F1BBCDC;
public const uint RMD160Round64To79 = 0xA953FD4E;
public const uint RMD160RoundPrime00To15 = 0x50A28BE6;
public const uint RMD160RoundPrime16To31 = 0x5C4DD124;
public const uint RMD160RoundPrime32To47 = 0x6D703EF3;
public const uint RMD160RoundPrime48To63 = 0x7A6D76E9;
public const uint RMD160RoundPrime64To79 = 0x00000000;
public const uint RMD160Y0 = 0x67452301;
public const uint RMD160Y1 = 0xEFCDAB89;
public const uint RMD160Y2 = 0x98BADCFE;
public const uint RMD160Y3 = 0x10325476;
public const uint RMD160Y4 = 0xC3D2E1F0;
public const uint RMD320Y5 = 0x76543210;
public const uint RMD320Y6 = 0xFEDCBA98;
public const uint RMD320Y7 = 0x89ABCDEF;
public const uint RMD320Y8 = 0x01234567;
public const uint RMD320Y9 = 0x3C2D1E0F;
/// <summary>
/// t_i
/// </summary>
public static readonly byte[] RMD160Ti =
[
11, 14, 15, 12, 5, 8, 7, 9,
11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15,
7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15,
14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8,
9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12,
5, 12, 13, 14, 11, 8, 5, 6,
];
/// <summary>
/// t'_i
/// </summary>
public static readonly byte[] RMD160Tpi =
[
8, 9, 9, 11, 13, 15, 15, 5,
7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11,
7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14,
12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14,
6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6,
8, 13, 6, 5, 15, 13, 11, 11,
];
/// <summary>
/// a_i
/// </summary>
public static readonly byte[] RMD160Ai =
[
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3,
12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1,
2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4,
13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10,
14, 1, 3, 8, 11, 6, 15, 13,
];
/// <summary>
/// a'_i
/// </summary>
public static readonly byte[] RMD160Api =
[
5, 14, 7, 0, 9, 2, 11, 4,
13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10,
14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9,
11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0,
5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7,
6, 2, 13, 14, 0, 3, 9, 11,
];
#endregion
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger//>
#region Tiger-128 / Tiger-160 / Tiger-192
public const ulong TigerSeedA = 0x0123456789ABCDEF;
public const ulong TigerSeedB = 0xFEDCBA9876543210;
public const ulong TigerSeedC = 0xF096A5B4C3B2E187;
/// <summary>
/// S-Boxes
/// </summary>
public static readonly ulong[] TigerSBox =
[
0x02AAB17CF7E90C5E /* 0 */, 0xAC424B03E243A8EC /* 1 */,
0x72CD5BE30DD5FCD3 /* 2 */, 0x6D019B93F6F97F3A /* 3 */,
@@ -520,5 +691,7 @@ namespace SabreTools.Hashing.Tiger
0xCD56D9430EA8280E /* 1020 */, 0xC12591D7535F5065 /* 1021 */,
0xC83223F1720AEF96 /* 1022 */, 0xC3A0396F7363A51F /* 1023 */
];
#endregion
}
}

View File

@@ -0,0 +1,170 @@
using System;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://datatracker.ietf.org/doc/html/rfc1115"/>
public class MD2 : MessageDigestBase<uint>
{
/// <summary>
/// Buffer for forming digest in
/// </summary>
/// <remarks>At the end, D[0...15] form the message digest</remarks>
private readonly byte[] _digest = new byte[48];
/// <summary>
/// Checksum register
/// </summary>
private readonly byte[] _checksum = new byte[16];
/// <summary>
/// Number of bytes handled, modulo 16
/// </summary>
private byte _byteCount;
/// <summary>
/// Last checksum char saved
/// </summary>
private byte _lastByte;
public MD2() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
Array.Clear(_digest, 0, _digest.Length);
Array.Clear(_checksum, 0, _checksum.Length);
_byteCount = 0;
_lastByte = 0;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = 16 - _byteCount;
// If there is buffer to fill and it will meet the limit
if (_byteCount > 0 && _byteCount + length >= 16)
{
// Fill the buffer from the input
for (int i = 0; i < bufferLen; i++)
{
// Add new character to buffer
_digest[16 + _byteCount] = data[offset + i];
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
// Update checksum register C and value L
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
// Increment i by one modulo 16
_byteCount = (byte)((_byteCount + 1) & 15);
}
// Set the new values
offset += bufferLen;
length -= bufferLen;
// Run the update
Update();
}
/// Process any standalone blocks
while (length >= 16)
{
// Fill the buffer from the input
for (int i = 0; i < 16; i++)
{
// Add new character to buffer
_digest[16 + _byteCount] = data[offset + i];
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
// Update checksum register C and value L
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
// Increment i by one modulo 16
_byteCount = (byte)((_byteCount + 1) & 15);
}
// Set the new values
offset += 16;
length -= 16;
// Run the update
Update();
}
// Save the remainder in the buffer
if (length > 0)
{
// Fill the buffer from the input
for (int i = 0; i < length; i++)
{
// Add new character to buffer
_digest[16 + _byteCount] = data[offset + i];
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
// Update checksum register C and value L
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
// Increment i by one modulo 16
_byteCount = (byte)((_byteCount + 1) & 15);
}
}
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
byte padLength = (byte)(16 - _byteCount);
// Pad the block
byte[] padding = new byte[padLength];
#if NETFRAMEWORK
for (int i = 0; i < padLength; i++)
{
padding[i] = padLength;
}
#else
Array.Fill(padding, padLength);
#endif
TransformBlock(padding, 0, padLength);
TransformBlock(_checksum, 0, _checksum.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[16];
Array.Copy(_digest, hash, 16);
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// The routine MDUPDATE updates the message digest context buffer to
/// account for the presence of the character c in the message whose
/// digest is being computed. This routine will be called for each
/// message byte in turn.
/// </summary>
/// <remarks>The following is a more efficient version of the loop</remarks>
private void Update()
{
byte t = 0;
for (byte j = 0; j < 18; j++)
{
for (byte i = 0; i < 48; i++)
{
t = _digest[i] = (byte)(_digest[i] ^ MD2SBox[t]);
}
t += j;
}
}
}
}

View File

@@ -0,0 +1,216 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://datatracker.ietf.org/doc/html/rfc1320"/>
public class MD4 : MessageDigestBase<uint>
{
/// <summary>
/// Set of 4 32-bit numbers representing the hash state
/// </summary>
private readonly uint[] _state = new uint[4];
public MD4() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = MD4SeedA;
_state[1] = MD4SeedB;
_state[2] = MD4SeedC;
_state[3] = MD4SeedD;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = 0x80;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[16];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 4);
hashOffset += 4;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
private void Round()
{
// Setup values
uint a = _state[0];
uint b = _state[1];
uint c = _state[2];
uint d = _state[3];
// Round 1
a = RotateLeft32(a + F(b, c, d) + _block[0] + MD4Round1, 3);
d = RotateLeft32(d + F(a, b, c) + _block[1] + MD4Round1, 7);
c = RotateLeft32(c + F(d, a, b) + _block[2] + MD4Round1, 11);
b = RotateLeft32(b + F(c, d, a) + _block[3] + MD4Round1, 19);
a = RotateLeft32(a + F(b, c, d) + _block[4] + MD4Round1, 3);
d = RotateLeft32(d + F(a, b, c) + _block[5] + MD4Round1, 7);
c = RotateLeft32(c + F(d, a, b) + _block[6] + MD4Round1, 11);
b = RotateLeft32(b + F(c, d, a) + _block[7] + MD4Round1, 19);
a = RotateLeft32(a + F(b, c, d) + _block[8] + MD4Round1, 3);
d = RotateLeft32(d + F(a, b, c) + _block[9] + MD4Round1, 7);
c = RotateLeft32(c + F(d, a, b) + _block[10] + MD4Round1, 11);
b = RotateLeft32(b + F(c, d, a) + _block[11] + MD4Round1, 19);
a = RotateLeft32(a + F(b, c, d) + _block[12] + MD4Round1, 3);
d = RotateLeft32(d + F(a, b, c) + _block[13] + MD4Round1, 7);
c = RotateLeft32(c + F(d, a, b) + _block[14] + MD4Round1, 11);
b = RotateLeft32(b + F(c, d, a) + _block[15] + MD4Round1, 19);
// Round 2
a = RotateLeft32(a + G(b, c, d) + _block[0] + MD4Round2, 3);
d = RotateLeft32(d + G(a, b, c) + _block[4] + MD4Round2, 5);
c = RotateLeft32(c + G(d, a, b) + _block[8] + MD4Round2, 9);
b = RotateLeft32(b + G(c, d, a) + _block[12] + MD4Round2, 13);
a = RotateLeft32(a + G(b, c, d) + _block[1] + MD4Round2, 3);
d = RotateLeft32(d + G(a, b, c) + _block[5] + MD4Round2, 5);
c = RotateLeft32(c + G(d, a, b) + _block[9] + MD4Round2, 9);
b = RotateLeft32(b + G(c, d, a) + _block[13] + MD4Round2, 13);
a = RotateLeft32(a + G(b, c, d) + _block[2] + MD4Round2, 3);
d = RotateLeft32(d + G(a, b, c) + _block[6] + MD4Round2, 5);
c = RotateLeft32(c + G(d, a, b) + _block[10] + MD4Round2, 9);
b = RotateLeft32(b + G(c, d, a) + _block[14] + MD4Round2, 13);
a = RotateLeft32(a + G(b, c, d) + _block[3] + MD4Round2, 3);
d = RotateLeft32(d + G(a, b, c) + _block[7] + MD4Round2, 5);
c = RotateLeft32(c + G(d, a, b) + _block[11] + MD4Round2, 9);
b = RotateLeft32(b + G(c, d, a) + _block[15] + MD4Round2, 13);
// Round 3
a = RotateLeft32(a + H(b, c, d) + _block[0] + MD4Round3, 3);
d = RotateLeft32(d + H(a, b, c) + _block[8] + MD4Round3, 9);
c = RotateLeft32(c + H(d, a, b) + _block[4] + MD4Round3, 11);
b = RotateLeft32(b + H(c, d, a) + _block[12] + MD4Round3, 15);
a = RotateLeft32(a + H(b, c, d) + _block[2] + MD4Round3, 3);
d = RotateLeft32(d + H(a, b, c) + _block[10] + MD4Round3, 9);
c = RotateLeft32(c + H(d, a, b) + _block[6] + MD4Round3, 11);
b = RotateLeft32(b + H(c, d, a) + _block[14] + MD4Round3, 15);
a = RotateLeft32(a + H(b, c, d) + _block[1] + MD4Round3, 3);
d = RotateLeft32(d + H(a, b, c) + _block[9] + MD4Round3, 9);
c = RotateLeft32(c + H(d, a, b) + _block[5] + MD4Round3, 11);
b = RotateLeft32(b + H(c, d, a) + _block[13] + MD4Round3, 15);
a = RotateLeft32(a + H(b, c, d) + _block[3] + MD4Round3, 3);
d = RotateLeft32(d + H(a, b, c) + _block[11] + MD4Round3, 9);
c = RotateLeft32(c + H(d, a, b) + _block[7] + MD4Round3, 11);
b = RotateLeft32(b + H(c, d, a) + _block[15] + MD4Round3, 15);
// Update stored values
_state[0] += a;
_state[1] += b;
_state[2] += c;
_state[3] += d;
}
/// <summary>
/// Auxiliary function F
/// </summary>
private static uint F(uint x, uint y, uint z) => (x & y) | (~x & z);
/// <summary>
/// Auxiliary function G
/// </summary>
private static uint G(uint x, uint y, uint z) => (x & y) | (x & z) | (y & z);
/// <summary>
/// Auxiliary function H
/// </summary>
private static uint H(uint x, uint y, uint z) => x ^ y ^ z;
}
}

View File

@@ -0,0 +1,85 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
public abstract class MessageDigestBase
{
/// <summary>
/// Total number of bytes processed
/// </summary>
protected long _totalBytes;
/// <summary>
/// Internal byte buffer to accumulate before <see cref="_block"/>
/// </summary>
protected readonly byte[] _buffer = new byte[64];
/// <summary>
/// Reset additional values
/// </summary>
protected abstract void ResetImpl();
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public abstract void TransformBlock(byte[] data, int offset, int length);
/// <summary>
/// End the hashing process
/// </summary>
/// TODO: Combine this when the padding byte can be set by implementing classes
public abstract void Terminate();
/// <summary>
/// Get the current value of the hash
/// </summary>
/// <remarks>
/// If <see cref="Terminate"/> has not been run, this value
/// will not be accurate for the processed bytes so far.
/// </remarks>
/// TODO: Combine this when there's an easier way of passing the state
public abstract byte[] GetHash();
}
public abstract class MessageDigestBase<T> : MessageDigestBase where T : struct
{
/// <summary>
/// Internal buffer for processing
/// </summary>
protected readonly T[] _block;
public MessageDigestBase()
{
if (typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
_block = new T[32];
else if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
_block = new T[16];
else if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
_block = new T[8];
else
throw new InvalidOperationException();
Reset();
}
/// <summary>
/// Reset the internal hashing state
/// </summary>
public void Reset()
{
// Reset the seed values
ResetImpl();
// Reset the byte count
_totalBytes = 0;
// Reset the buffers
Array.Clear(_buffer, 0, _buffer.Length);
Array.Clear(_block, 0, _block.Length);
}
}
}

View File

@@ -0,0 +1,449 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
public class RipeMD128 : MessageDigestBase<uint>
{
/// <summary>
/// Set of 4 32-bit numbers representing the hash state
/// </summary>
private readonly uint[] _state = new uint[4];
public RipeMD128() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = RMD128Y0;
_state[1] = RMD128Y1;
_state[2] = RMD128Y2;
_state[3] = RMD128Y3;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = 0x80;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[16];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 4);
hashOffset += 4;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
/// <remarks>
/// The official specification for RIPEMD-128 includes tables
/// and instructions that represent a loop. Most standard implementations
/// use the unrolled version of that loop to make it more efficient.
///
/// The below code started with the looped version but has been converted
/// to the more standard implementation instead.
/// </remarks>
private void Round()
{
// Setup values
uint x0 = _state[0], xp0 = _state[0];
uint x1 = _state[1], xp1 = _state[1];
uint x2 = _state[2], xp2 = _state[2];
uint x3 = _state[3], xp3 = _state[3];
#region Rounds 0-15
// Round 0
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD128Round00To15, 11);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime00To15, 8);
// Round 1
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[1] + RMD128Round00To15, 14);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime00To15, 9);
// Round 2
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[2] + RMD128Round00To15, 15);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[7] + RMD128RoundPrime00To15, 9);
// Round 3
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[3] + RMD128Round00To15, 12);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime00To15, 11);
// Round 4
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[4] + RMD128Round00To15, 5);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime00To15, 13);
// Round 5
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[5] + RMD128Round00To15, 8);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[2] + RMD128RoundPrime00To15, 15);
// Round 6
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[6] + RMD128Round00To15, 7);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[11] + RMD128RoundPrime00To15, 15);
// Round 7
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[7] + RMD128Round00To15, 9);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[4] + RMD128RoundPrime00To15, 5);
// Round 8
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[8] + RMD128Round00To15, 11);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[13] + RMD128RoundPrime00To15, 7);
// Round 9
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[9] + RMD128Round00To15, 13);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime00To15, 7);
// Round 10
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[10] + RMD128Round00To15, 14);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime00To15, 8);
// Round 11
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[11] + RMD128Round00To15, 15);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[8] + RMD128RoundPrime00To15, 11);
// Round 12
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[12] + RMD128Round00To15, 6);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD128RoundPrime00To15, 14);
// Round 13
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[13] + RMD128Round00To15, 7);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[10] + RMD128RoundPrime00To15, 14);
// Round 14
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[14] + RMD128Round00To15, 9);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime00To15, 12);
// Round 15
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[15] + RMD128Round00To15, 8);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime00To15, 6);
#endregion
#region Rounds 16-31
// Round 16
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[7] + RMD128Round16To31, 7);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[6] + RMD128RoundPrime16To31, 9);
// Round 17
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[4] + RMD128Round16To31, 6);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime16To31, 13);
// Round 18
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[13] + RMD128Round16To31, 8);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime16To31, 15);
// Round 19
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[1] + RMD128Round16To31, 13);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[7] + RMD128RoundPrime16To31, 7);
// Round 20
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD128Round16To31, 11);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD128RoundPrime16To31, 12);
// Round 21
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[6] + RMD128Round16To31, 9);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[13] + RMD128RoundPrime16To31, 8);
// Round 22
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[15] + RMD128Round16To31, 7);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[5] + RMD128RoundPrime16To31, 9);
// Round 23
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[3] + RMD128Round16To31, 15);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[10] + RMD128RoundPrime16To31, 11);
// Round 24
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[12] + RMD128Round16To31, 7);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[14] + RMD128RoundPrime16To31, 7);
// Round 25
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[0] + RMD128Round16To31, 12);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[15] + RMD128RoundPrime16To31, 7);
// Round 26
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[9] + RMD128Round16To31, 15);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[8] + RMD128RoundPrime16To31, 12);
// Round 27
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[5] + RMD128Round16To31, 9);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime16To31, 7);
// Round 28
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[2] + RMD128Round16To31, 11);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[4] + RMD128RoundPrime16To31, 6);
// Round 29
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[14] + RMD128Round16To31, 7);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[9] + RMD128RoundPrime16To31, 15);
// Round 30
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[11] + RMD128Round16To31, 13);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime16To31, 13);
// Round 31
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[8] + RMD128Round16To31, 12);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime16To31, 11);
#endregion
#region Rounds 32-47
// Round 32
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[3] + RMD128Round32To47, 11);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[15] + RMD128RoundPrime32To47, 9);
// Round 33
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[10] + RMD128Round32To47, 13);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[5] + RMD128RoundPrime32To47, 7);
// Round 34
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[14] + RMD128Round32To47, 6);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime32To47, 15);
// Round 35
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[4] + RMD128Round32To47, 7);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[3] + RMD128RoundPrime32To47, 11);
// Round 36
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[9] + RMD128Round32To47, 14);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[7] + RMD128RoundPrime32To47, 8);
// Round 37
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[15] + RMD128Round32To47, 9);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime32To47, 6);
// Round 38
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[8] + RMD128Round32To47, 13);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[6] + RMD128RoundPrime32To47, 6);
// Round 39
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[1] + RMD128Round32To47, 15);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[9] + RMD128RoundPrime32To47, 14);
// Round 40
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD128Round32To47, 14);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[11] + RMD128RoundPrime32To47, 12);
// Round 41
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[7] + RMD128Round32To47, 8);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[8] + RMD128RoundPrime32To47, 13);
// Round 42
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[0] + RMD128Round32To47, 13);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[12] + RMD128RoundPrime32To47, 5);
// Round 43
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[6] + RMD128Round32To47, 6);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime32To47, 14);
// Round 44
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[13] + RMD128Round32To47, 5);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[10] + RMD128RoundPrime32To47, 13);
// Round 45
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[11] + RMD128Round32To47, 12);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[0] + RMD128RoundPrime32To47, 13);
// Round 46
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[5] + RMD128Round32To47, 7);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime32To47, 7);
// Round 47
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[12] + RMD128Round32To47, 5);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime32To47, 5);
#endregion
#region Rounds 48-63
// Round 48
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[1] + RMD128Round48To63, 11);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD128RoundPrime48To63, 15);
// Round 49
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[9] + RMD128Round48To63, 12);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime48To63, 5);
// Round 50
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[11] + RMD128Round48To63, 14);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime48To63, 8);
// Round 51
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[10] + RMD128Round48To63, 15);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[1] + RMD128RoundPrime48To63, 11);
// Round 52
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[0] + RMD128Round48To63, 14);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[3] + RMD128RoundPrime48To63, 14);
// Round 53
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[8] + RMD128Round48To63, 15);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime48To63, 14);
// Round 54
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[12] + RMD128Round48To63, 9);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime48To63, 6);
// Round 55
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[4] + RMD128Round48To63, 8);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime48To63, 14);
// Round 56
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[13] + RMD128Round48To63, 9);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime48To63, 6);
// Round 57
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[3] + RMD128Round48To63, 14);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[12] + RMD128RoundPrime48To63, 9);
// Round 58
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[7] + RMD128Round48To63, 5);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[2] + RMD128RoundPrime48To63, 12);
// Round 59
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[15] + RMD128Round48To63, 6);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime48To63, 9);
// Round 60
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD128Round48To63, 8);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime48To63, 12);
// Round 61
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[5] + RMD128Round48To63, 6);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[7] + RMD128RoundPrime48To63, 5);
// Round 62
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[6] + RMD128Round48To63, 5);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[10] + RMD128RoundPrime48To63, 15);
// Round 63
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[2] + RMD128Round48To63, 12);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[14] + RMD128RoundPrime48To63, 8);
#endregion
// Avalanche values
xp3 += x2 + _state[1];
_state[1] = _state[2] + x3 + xp0;
_state[2] = _state[3] + x0 + xp1;
_state[3] = _state[0] + x1 + xp2;
_state[0] = xp3;
}
/// <summary>
/// Round operation [0, 15]
/// </summary>
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
/// <summary>
/// Round operation [16, 31]
/// </summary>
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
/// <summary>
/// Round operation [32, 47]
/// </summary>
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
/// <summary>
/// Round operation [48, 63]
/// </summary>
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
}
}

View File

@@ -0,0 +1,685 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
public class RipeMD160 : MessageDigestBase<uint>
{
/// <summary>
/// Set of 5 32-bit numbers representing the hash state
/// </summary>
private readonly uint[] _state = new uint[5];
public RipeMD160() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = RMD160Y0;
_state[1] = RMD160Y1;
_state[2] = RMD160Y2;
_state[3] = RMD160Y3;
_state[4] = RMD160Y4;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = 0x80;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8 ) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0 ) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[20];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 4);
hashOffset += 4;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
/// <remarks>
/// The official specification for RIPEMD-160 includes tables
/// and instructions that represent a loop. Most standard implementations
/// use the unrolled version of that loop to make it more efficient.
///
/// The below code started with the looped version but has been converted
/// to the more standard implementation instead.
/// </remarks>
private void Round()
{
// Setup values
uint x0 = _state[0], xp0 = _state[0];
uint x1 = _state[1], xp1 = _state[1];
uint x2 = _state[2], xp2 = _state[2];
uint x3 = _state[3], xp3 = _state[3];
uint x4 = _state[4], xp4 = _state[4];
#region Rounds 0-15
// Round 0
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD160Round00To15, 11) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[5] + RMD160RoundPrime00To15, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 1
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[1] + RMD160Round00To15, 14) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[14] + RMD160RoundPrime00To15, 9) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 2
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[2] + RMD160Round00To15, 15) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[7] + RMD160RoundPrime00To15, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 3
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[3] + RMD160Round00To15, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[0] + RMD160RoundPrime00To15, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 4
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[4] + RMD160Round00To15, 5) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime00To15, 13) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 5
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[5] + RMD160Round00To15, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[2] + RMD160RoundPrime00To15, 15) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 6
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[6] + RMD160Round00To15, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[11] + RMD160RoundPrime00To15, 15) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 7
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[7] + RMD160Round00To15, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime00To15, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 8
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[8] + RMD160Round00To15, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[13] + RMD160RoundPrime00To15, 7) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 9
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[9] + RMD160Round00To15, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime00To15, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 10
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[10] + RMD160Round00To15, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime00To15, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 11
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[11] + RMD160Round00To15, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime00To15, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 12
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[12] + RMD160Round00To15, 6) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[1] + RMD160RoundPrime00To15, 14) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 13
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[13] + RMD160Round00To15, 7) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime00To15, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 14
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[14] + RMD160Round00To15, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[3] + RMD160RoundPrime00To15, 12) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 15
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[15] + RMD160Round00To15, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[12] + RMD160RoundPrime00To15, 6) + xp4;
xp2 = RotateLeft32(xp2, 10);
#endregion
#region Rounds 16-31
// Round 16
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[7] + RMD160Round16To31, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[6] + RMD160RoundPrime16To31, 9) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 17
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[4] + RMD160Round16To31, 6) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[11] + RMD160RoundPrime16To31, 13) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 18
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[13] + RMD160Round16To31, 8) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[3] + RMD160RoundPrime16To31, 15) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 19
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[1] + RMD160Round16To31, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[7] + RMD160RoundPrime16To31, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 20
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD160Round16To31, 11) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime16To31, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 21
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[6] + RMD160Round16To31, 9) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[13] + RMD160RoundPrime16To31, 8) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 22
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[15] + RMD160Round16To31, 7) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[5] + RMD160RoundPrime16To31, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 23
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[3] + RMD160Round16To31, 15) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime16To31, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 24
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[12] + RMD160Round16To31, 7) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[14] + RMD160RoundPrime16To31, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 25
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[0] + RMD160Round16To31, 12) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime16To31, 7) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 26
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[9] + RMD160Round16To31, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime16To31, 12) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 27
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[5] + RMD160Round16To31, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime16To31, 7) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 28
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[2] + RMD160Round16To31, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[4] + RMD160RoundPrime16To31, 6) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 29
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[14] + RMD160Round16To31, 7) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime16To31, 15) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 30
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[11] + RMD160Round16To31, 13) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD160RoundPrime16To31, 13) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 31
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[8] + RMD160Round16To31, 12) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[2] + RMD160RoundPrime16To31, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
#endregion
#region Rounds 32-47
// Round 32
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[3] + RMD160Round32To47, 11) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[15] + RMD160RoundPrime32To47, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 33
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[10] + RMD160Round32To47, 13) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[5] + RMD160RoundPrime32To47, 7) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 34
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[14] + RMD160Round32To47, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[1] + RMD160RoundPrime32To47, 15) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 35
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[4] + RMD160Round32To47, 7) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[3] + RMD160RoundPrime32To47, 11) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 36
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[9] + RMD160Round32To47, 14) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime32To47, 8) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 37
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[15] + RMD160Round32To47, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[14] + RMD160RoundPrime32To47, 6) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 38
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[8] + RMD160Round32To47, 13) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[6] + RMD160RoundPrime32To47, 6) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 39
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[1] + RMD160Round32To47, 15) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime32To47, 14) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 40
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD160Round32To47, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[11] + RMD160RoundPrime32To47, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 41
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[7] + RMD160Round32To47, 8) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime32To47, 13) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 42
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[0] + RMD160Round32To47, 13) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime32To47, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 43
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[6] + RMD160Round32To47, 6) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime32To47, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 44
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[13] + RMD160Round32To47, 5) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[10] + RMD160RoundPrime32To47, 13) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 45
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[11] + RMD160Round32To47, 12) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime32To47, 13) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 46
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[5] + RMD160Round32To47, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[4] + RMD160RoundPrime32To47, 7) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 47
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[12] + RMD160Round32To47, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[13] + RMD160RoundPrime32To47, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
#endregion
#region Rounds 48-63
// Round 48
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[1] + RMD160Round48To63, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[8] + RMD160RoundPrime48To63, 15) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 49
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[9] + RMD160Round48To63, 12) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime48To63, 5) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 50
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[11] + RMD160Round48To63, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[4] + RMD160RoundPrime48To63, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 51
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[10] + RMD160Round48To63, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[1] + RMD160RoundPrime48To63, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 52
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[0] + RMD160Round48To63, 14) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime48To63, 14) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 53
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[8] + RMD160Round48To63, 15) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[11] + RMD160RoundPrime48To63, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 54
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[12] + RMD160Round48To63, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[15] + RMD160RoundPrime48To63, 6) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 55
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[4] + RMD160Round48To63, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime48To63, 14) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 56
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[13] + RMD160Round48To63, 9) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[5] + RMD160RoundPrime48To63, 6) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 57
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[3] + RMD160Round48To63, 14) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime48To63, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 58
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[7] + RMD160Round48To63, 5) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime48To63, 12) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 59
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[15] + RMD160Round48To63, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime48To63, 9) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 60
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD160Round48To63, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[9] + RMD160RoundPrime48To63, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 61
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[5] + RMD160Round48To63, 6) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime48To63, 5) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 62
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[6] + RMD160Round48To63, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[10] + RMD160RoundPrime48To63, 15) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 63
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[2] + RMD160Round48To63, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[14] + RMD160RoundPrime48To63, 8) + xp1;
xp4 = RotateLeft32(xp4, 10);
#endregion
#region Rounds 64-79
// Round 64
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[4] + RMD160Round64To79, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[12] + RMD160RoundPrime64To79, 8) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 65
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[0] + RMD160Round64To79, 15) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime64To79, 5) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 66
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[5] + RMD160Round64To79, 5) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[10] + RMD160RoundPrime64To79, 12) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 67
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[9] + RMD160Round64To79, 11) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime64To79, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 68
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[7] + RMD160Round64To79, 6) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[1] + RMD160RoundPrime64To79, 12) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 69
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[12] + RMD160Round64To79, 8) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[5] + RMD160RoundPrime64To79, 5) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 70
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[2] + RMD160Round64To79, 13) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD160RoundPrime64To79, 14) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 71
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[10] + RMD160Round64To79, 12) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime64To79, 6) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 72
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[14] + RMD160Round64To79, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[6] + RMD160RoundPrime64To79, 8) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 73
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[1] + RMD160Round64To79, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime64To79, 13) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 74
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[3] + RMD160Round64To79, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime64To79, 6) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 75
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[8] + RMD160Round64To79, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[14] + RMD160RoundPrime64To79, 5) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 76
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[11] + RMD160Round64To79, 11) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[0] + RMD160RoundPrime64To79, 15) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 77
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[6] + RMD160Round64To79, 8) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime64To79, 13) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 78
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[15] + RMD160Round64To79, 5) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[9] + RMD160RoundPrime64To79, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 79
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[13] + RMD160Round64To79, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[11] + RMD160RoundPrime64To79, 11) + xp0;
xp3 = RotateLeft32(xp3, 10);
#endregion
// Avalanche values
xp3 += x2 + _state[1];
_state[1] = _state[2] + x3 + xp4;
_state[2] = _state[3] + x4 + xp0;
_state[3] = _state[4] + x0 + xp1;
_state[4] = _state[0] + x1 + xp2;
_state[0] = xp3;
}
/// <summary>
/// Round operation [0, 15]
/// </summary>
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
/// <summary>
/// Round operation [16, 31]
/// </summary>
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
/// <summary>
/// Round operation [32, 47]
/// </summary>
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
/// <summary>
/// Round operation [48, 63]
/// </summary>
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
/// <summary>
/// Round operation [64, 79]
/// </summary>
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
}
}

View File

@@ -0,0 +1,469 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
public class RipeMD256 : MessageDigestBase<uint>
{
/// <summary>
/// Set of 4 32-bit numbers representing the hash state
/// </summary>
private readonly uint[] _state = new uint[8];
public RipeMD256() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = RMD128Y0;
_state[1] = RMD128Y1;
_state[2] = RMD128Y2;
_state[3] = RMD128Y3;
_state[4] = RMD256Y4;
_state[5] = RMD256Y5;
_state[6] = RMD256Y6;
_state[7] = RMD256Y7;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = 0x80;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[32];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 4);
hashOffset += 4;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
/// <remarks>
/// The official specification for RIPEMD-128 includes tables
/// and instructions that represent a loop. Most standard implementations
/// use the unrolled version of that loop to make it more efficient.
///
/// The below code started with the looped version but has been converted
/// to the more standard implementation instead.
/// </remarks>
private void Round()
{
// Setup values
uint x0 = _state[0], xp0 = _state[4];
uint x1 = _state[1], xp1 = _state[5];
uint x2 = _state[2], xp2 = _state[6];
uint x3 = _state[3], xp3 = _state[7];
uint t;
#region Rounds 0-15
// Round 0
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD128Round00To15, 11);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime00To15, 8);
// Round 1
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[1] + RMD128Round00To15, 14);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime00To15, 9);
// Round 2
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[2] + RMD128Round00To15, 15);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[7] + RMD128RoundPrime00To15, 9);
// Round 3
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[3] + RMD128Round00To15, 12);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime00To15, 11);
// Round 4
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[4] + RMD128Round00To15, 5);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime00To15, 13);
// Round 5
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[5] + RMD128Round00To15, 8);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[2] + RMD128RoundPrime00To15, 15);
// Round 6
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[6] + RMD128Round00To15, 7);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[11] + RMD128RoundPrime00To15, 15);
// Round 7
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[7] + RMD128Round00To15, 9);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[4] + RMD128RoundPrime00To15, 5);
// Round 8
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[8] + RMD128Round00To15, 11);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[13] + RMD128RoundPrime00To15, 7);
// Round 9
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[9] + RMD128Round00To15, 13);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime00To15, 7);
// Round 10
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[10] + RMD128Round00To15, 14);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime00To15, 8);
// Round 11
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[11] + RMD128Round00To15, 15);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[8] + RMD128RoundPrime00To15, 11);
// Round 12
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[12] + RMD128Round00To15, 6);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD128RoundPrime00To15, 14);
// Round 13
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[13] + RMD128Round00To15, 7);
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[10] + RMD128RoundPrime00To15, 14);
// Round 14
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[14] + RMD128Round00To15, 9);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime00To15, 12);
// Round 15
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[15] + RMD128Round00To15, 8);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime00To15, 6);
// Swap set 1
t = x0; x0 = xp0; xp0 = t;
#endregion
#region Rounds 16-31
// Round 16
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[7] + RMD128Round16To31, 7);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[6] + RMD128RoundPrime16To31, 9);
// Round 17
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[4] + RMD128Round16To31, 6);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime16To31, 13);
// Round 18
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[13] + RMD128Round16To31, 8);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime16To31, 15);
// Round 19
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[1] + RMD128Round16To31, 13);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[7] + RMD128RoundPrime16To31, 7);
// Round 20
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD128Round16To31, 11);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD128RoundPrime16To31, 12);
// Round 21
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[6] + RMD128Round16To31, 9);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[13] + RMD128RoundPrime16To31, 8);
// Round 22
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[15] + RMD128Round16To31, 7);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[5] + RMD128RoundPrime16To31, 9);
// Round 23
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[3] + RMD128Round16To31, 15);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[10] + RMD128RoundPrime16To31, 11);
// Round 24
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[12] + RMD128Round16To31, 7);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[14] + RMD128RoundPrime16To31, 7);
// Round 25
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[0] + RMD128Round16To31, 12);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[15] + RMD128RoundPrime16To31, 7);
// Round 26
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[9] + RMD128Round16To31, 15);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[8] + RMD128RoundPrime16To31, 12);
// Round 27
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[5] + RMD128Round16To31, 9);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime16To31, 7);
// Round 28
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[2] + RMD128Round16To31, 11);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[4] + RMD128RoundPrime16To31, 6);
// Round 29
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[14] + RMD128Round16To31, 7);
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[9] + RMD128RoundPrime16To31, 15);
// Round 30
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[11] + RMD128Round16To31, 13);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime16To31, 13);
// Round 31
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[8] + RMD128Round16To31, 12);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime16To31, 11);
// Swap set 2
t = x1; x1 = xp1; xp1 = t;
#endregion
#region Rounds 32-47
// Round 32
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[3] + RMD128Round32To47, 11);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[15] + RMD128RoundPrime32To47, 9);
// Round 33
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[10] + RMD128Round32To47, 13);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[5] + RMD128RoundPrime32To47, 7);
// Round 34
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[14] + RMD128Round32To47, 6);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime32To47, 15);
// Round 35
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[4] + RMD128Round32To47, 7);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[3] + RMD128RoundPrime32To47, 11);
// Round 36
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[9] + RMD128Round32To47, 14);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[7] + RMD128RoundPrime32To47, 8);
// Round 37
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[15] + RMD128Round32To47, 9);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime32To47, 6);
// Round 38
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[8] + RMD128Round32To47, 13);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[6] + RMD128RoundPrime32To47, 6);
// Round 39
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[1] + RMD128Round32To47, 15);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[9] + RMD128RoundPrime32To47, 14);
// Round 40
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD128Round32To47, 14);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[11] + RMD128RoundPrime32To47, 12);
// Round 41
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[7] + RMD128Round32To47, 8);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[8] + RMD128RoundPrime32To47, 13);
// Round 42
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[0] + RMD128Round32To47, 13);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[12] + RMD128RoundPrime32To47, 5);
// Round 43
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[6] + RMD128Round32To47, 6);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime32To47, 14);
// Round 44
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[13] + RMD128Round32To47, 5);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[10] + RMD128RoundPrime32To47, 13);
// Round 45
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[11] + RMD128Round32To47, 12);
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[0] + RMD128RoundPrime32To47, 13);
// Round 46
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[5] + RMD128Round32To47, 7);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime32To47, 7);
// Round 47
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[12] + RMD128Round32To47, 5);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime32To47, 5);
// Swap set 3
t = x2; x2 = xp2; xp2 = t;
#endregion
#region Rounds 48-63
// Round 48
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[1] + RMD128Round48To63, 11);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD128RoundPrime48To63, 15);
// Round 49
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[9] + RMD128Round48To63, 12);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime48To63, 5);
// Round 50
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[11] + RMD128Round48To63, 14);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime48To63, 8);
// Round 51
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[10] + RMD128Round48To63, 15);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[1] + RMD128RoundPrime48To63, 11);
// Round 52
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[0] + RMD128Round48To63, 14);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[3] + RMD128RoundPrime48To63, 14);
// Round 53
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[8] + RMD128Round48To63, 15);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime48To63, 14);
// Round 54
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[12] + RMD128Round48To63, 9);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime48To63, 6);
// Round 55
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[4] + RMD128Round48To63, 8);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime48To63, 14);
// Round 56
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[13] + RMD128Round48To63, 9);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime48To63, 6);
// Round 57
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[3] + RMD128Round48To63, 14);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[12] + RMD128RoundPrime48To63, 9);
// Round 58
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[7] + RMD128Round48To63, 5);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[2] + RMD128RoundPrime48To63, 12);
// Round 59
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[15] + RMD128Round48To63, 6);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime48To63, 9);
// Round 60
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD128Round48To63, 8);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime48To63, 12);
// Round 61
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[5] + RMD128Round48To63, 6);
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[7] + RMD128RoundPrime48To63, 5);
// Round 62
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[6] + RMD128Round48To63, 5);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[10] + RMD128RoundPrime48To63, 15);
// Round 63
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[2] + RMD128Round48To63, 12);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[14] + RMD128RoundPrime48To63, 8);
// Swap set 4
t = x3; x3 = xp3; xp3 = t;
#endregion
// Avalanche values
_state[0] += x0;
_state[1] += x1;
_state[2] += x2;
_state[3] += x3;
_state[4] += xp0;
_state[5] += xp1;
_state[6] += xp2;
_state[7] += xp3;
}
/// <summary>
/// Round operation [0, 15]
/// </summary>
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
/// <summary>
/// Round operation [16, 31]
/// </summary>
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
/// <summary>
/// Round operation [32, 47]
/// </summary>
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
/// <summary>
/// Round operation [48, 63]
/// </summary>
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
}
}

View File

@@ -0,0 +1,710 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
public class RipeMD320 : MessageDigestBase<uint>
{
/// <summary>
/// Set of 10 32-bit numbers representing the hash state
/// </summary>
private readonly uint[] _state = new uint[10];
public RipeMD320() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = RMD160Y0;
_state[1] = RMD160Y1;
_state[2] = RMD160Y2;
_state[3] = RMD160Y3;
_state[4] = RMD160Y4;
_state[5] = RMD320Y5;
_state[6] = RMD320Y6;
_state[7] = RMD320Y7;
_state[8] = RMD320Y8;
_state[9] = RMD320Y9;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 16; i++)
{
_block[i] = ReadLE32(_buffer, i * 4);
}
// Run the round
Round();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = 0x80;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8 ) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0 ) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[40];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 4);
hashOffset += 4;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
/// <remarks>
/// The official specification for RIPEMD-160 includes tables
/// and instructions that represent a loop. Most standard implementations
/// use the unrolled version of that loop to make it more efficient.
///
/// The below code started with the looped version but has been converted
/// to the more standard implementation instead.
/// </remarks>
private void Round()
{
// Setup values
uint x0 = _state[0], xp0 = _state[5];
uint x1 = _state[1], xp1 = _state[6];
uint x2 = _state[2], xp2 = _state[7];
uint x3 = _state[3], xp3 = _state[8];
uint x4 = _state[4], xp4 = _state[9];
uint t;
#region Rounds 0-15
// Round 0
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD160Round00To15, 11) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[5] + RMD160RoundPrime00To15, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 1
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[1] + RMD160Round00To15, 14) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[14] + RMD160RoundPrime00To15, 9) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 2
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[2] + RMD160Round00To15, 15) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[7] + RMD160RoundPrime00To15, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 3
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[3] + RMD160Round00To15, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[0] + RMD160RoundPrime00To15, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 4
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[4] + RMD160Round00To15, 5) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime00To15, 13) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 5
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[5] + RMD160Round00To15, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[2] + RMD160RoundPrime00To15, 15) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 6
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[6] + RMD160Round00To15, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[11] + RMD160RoundPrime00To15, 15) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 7
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[7] + RMD160Round00To15, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime00To15, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 8
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[8] + RMD160Round00To15, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[13] + RMD160RoundPrime00To15, 7) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 9
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[9] + RMD160Round00To15, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime00To15, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 10
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[10] + RMD160Round00To15, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime00To15, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 11
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[11] + RMD160Round00To15, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime00To15, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 12
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[12] + RMD160Round00To15, 6) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[1] + RMD160RoundPrime00To15, 14) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 13
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[13] + RMD160Round00To15, 7) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime00To15, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 14
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[14] + RMD160Round00To15, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[3] + RMD160RoundPrime00To15, 12) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 15
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[15] + RMD160Round00To15, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[12] + RMD160RoundPrime00To15, 6) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Swap set 1
t = x0; x0 = xp0; xp0 = t;
#endregion
#region Rounds 16-31
// Round 16
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[7] + RMD160Round16To31, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[6] + RMD160RoundPrime16To31, 9) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 17
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[4] + RMD160Round16To31, 6) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[11] + RMD160RoundPrime16To31, 13) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 18
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[13] + RMD160Round16To31, 8) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[3] + RMD160RoundPrime16To31, 15) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 19
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[1] + RMD160Round16To31, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[7] + RMD160RoundPrime16To31, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 20
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD160Round16To31, 11) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime16To31, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 21
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[6] + RMD160Round16To31, 9) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[13] + RMD160RoundPrime16To31, 8) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 22
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[15] + RMD160Round16To31, 7) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[5] + RMD160RoundPrime16To31, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 23
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[3] + RMD160Round16To31, 15) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime16To31, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 24
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[12] + RMD160Round16To31, 7) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[14] + RMD160RoundPrime16To31, 7) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 25
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[0] + RMD160Round16To31, 12) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime16To31, 7) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 26
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[9] + RMD160Round16To31, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime16To31, 12) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 27
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[5] + RMD160Round16To31, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime16To31, 7) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 28
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[2] + RMD160Round16To31, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[4] + RMD160RoundPrime16To31, 6) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 29
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[14] + RMD160Round16To31, 7) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime16To31, 15) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 30
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[11] + RMD160Round16To31, 13) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD160RoundPrime16To31, 13) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 31
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[8] + RMD160Round16To31, 12) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[2] + RMD160RoundPrime16To31, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Swap set 2
t = x1; x1 = xp1; xp1 = t;
#endregion
#region Rounds 32-47
// Round 32
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[3] + RMD160Round32To47, 11) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[15] + RMD160RoundPrime32To47, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 33
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[10] + RMD160Round32To47, 13) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[5] + RMD160RoundPrime32To47, 7) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 34
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[14] + RMD160Round32To47, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[1] + RMD160RoundPrime32To47, 15) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 35
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[4] + RMD160Round32To47, 7) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[3] + RMD160RoundPrime32To47, 11) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 36
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[9] + RMD160Round32To47, 14) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime32To47, 8) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 37
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[15] + RMD160Round32To47, 9) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[14] + RMD160RoundPrime32To47, 6) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 38
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[8] + RMD160Round32To47, 13) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[6] + RMD160RoundPrime32To47, 6) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 39
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[1] + RMD160Round32To47, 15) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime32To47, 14) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 40
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD160Round32To47, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[11] + RMD160RoundPrime32To47, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 41
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[7] + RMD160Round32To47, 8) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime32To47, 13) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 42
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[0] + RMD160Round32To47, 13) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime32To47, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 43
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[6] + RMD160Round32To47, 6) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime32To47, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 44
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[13] + RMD160Round32To47, 5) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[10] + RMD160RoundPrime32To47, 13) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 45
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[11] + RMD160Round32To47, 12) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime32To47, 13) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 46
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[5] + RMD160Round32To47, 7) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[4] + RMD160RoundPrime32To47, 7) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 47
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[12] + RMD160Round32To47, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[13] + RMD160RoundPrime32To47, 5) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Swap set 3
t = x2; x2 = xp2; xp2 = t;
#endregion
#region Rounds 48-63
// Round 48
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[1] + RMD160Round48To63, 11) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[8] + RMD160RoundPrime48To63, 15) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 49
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[9] + RMD160Round48To63, 12) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime48To63, 5) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 50
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[11] + RMD160Round48To63, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[4] + RMD160RoundPrime48To63, 8) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 51
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[10] + RMD160Round48To63, 15) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[1] + RMD160RoundPrime48To63, 11) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 52
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[0] + RMD160Round48To63, 14) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime48To63, 14) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 53
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[8] + RMD160Round48To63, 15) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[11] + RMD160RoundPrime48To63, 14) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 54
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[12] + RMD160Round48To63, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[15] + RMD160RoundPrime48To63, 6) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 55
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[4] + RMD160Round48To63, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime48To63, 14) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 56
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[13] + RMD160Round48To63, 9) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[5] + RMD160RoundPrime48To63, 6) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 57
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[3] + RMD160Round48To63, 14) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime48To63, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 58
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[7] + RMD160Round48To63, 5) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime48To63, 12) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 59
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[15] + RMD160Round48To63, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime48To63, 9) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 60
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD160Round48To63, 8) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[9] + RMD160RoundPrime48To63, 12) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 61
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[5] + RMD160Round48To63, 6) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime48To63, 5) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 62
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[6] + RMD160Round48To63, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[10] + RMD160RoundPrime48To63, 15) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 63
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[2] + RMD160Round48To63, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[14] + RMD160RoundPrime48To63, 8) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Swap set 4
t = x3; x3 = xp3; xp3 = t;
#endregion
#region Rounds 64-79
// Round 64
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[4] + RMD160Round64To79, 9) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[12] + RMD160RoundPrime64To79, 8) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 65
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[0] + RMD160Round64To79, 15) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime64To79, 5) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 66
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[5] + RMD160Round64To79, 5) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[10] + RMD160RoundPrime64To79, 12) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 67
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[9] + RMD160Round64To79, 11) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime64To79, 9) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 68
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[7] + RMD160Round64To79, 6) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[1] + RMD160RoundPrime64To79, 12) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 69
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[12] + RMD160Round64To79, 8) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[5] + RMD160RoundPrime64To79, 5) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 70
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[2] + RMD160Round64To79, 13) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD160RoundPrime64To79, 14) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 71
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[10] + RMD160Round64To79, 12) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime64To79, 6) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 72
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[14] + RMD160Round64To79, 5) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[6] + RMD160RoundPrime64To79, 8) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 73
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[1] + RMD160Round64To79, 12) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime64To79, 13) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 74
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[3] + RMD160Round64To79, 13) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime64To79, 6) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Round 75
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[8] + RMD160Round64To79, 14) + x4;
x2 = RotateLeft32(x2, 10);
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[14] + RMD160RoundPrime64To79, 5) + xp4;
xp2 = RotateLeft32(xp2, 10);
// Round 76
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[11] + RMD160Round64To79, 11) + x3;
x1 = RotateLeft32(x1, 10);
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[0] + RMD160RoundPrime64To79, 15) + xp3;
xp1 = RotateLeft32(xp1, 10);
// Round 77
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[6] + RMD160Round64To79, 8) + x2;
x0 = RotateLeft32(x0, 10);
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime64To79, 13) + xp2;
xp0 = RotateLeft32(xp0, 10);
// Round 78
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[15] + RMD160Round64To79, 5) + x1;
x4 = RotateLeft32(x4, 10);
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[9] + RMD160RoundPrime64To79, 11) + xp1;
xp4 = RotateLeft32(xp4, 10);
// Round 79
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[13] + RMD160Round64To79, 6) + x0;
x3 = RotateLeft32(x3, 10);
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[11] + RMD160RoundPrime64To79, 11) + xp0;
xp3 = RotateLeft32(xp3, 10);
// Swap set 5
t = x4; x4 = xp4; xp4 = t;
#endregion
// Avalanche values
_state[0] += x0;
_state[1] += x1;
_state[2] += x2;
_state[3] += x3;
_state[4] += x4;
_state[5] += xp0;
_state[6] += xp1;
_state[7] += xp2;
_state[8] += xp3;
_state[9] += xp4;
}
/// <summary>
/// Round operation [0, 15]
/// </summary>
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
/// <summary>
/// Round operation [16, 31]
/// </summary>
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
/// <summary>
/// Round operation [32, 47]
/// </summary>
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
/// <summary>
/// Round operation [48, 63]
/// </summary>
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
/// <summary>
/// Round operation [64, 79]
/// </summary>
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger-128
/// </summary>
public class Tiger128_3 : TigerHashBase
{
public Tiger128_3() : base()
{
_passes = 3;
_padStart = 0x01;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[16];
Array.Copy(hash, trimmedHash, 16);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger-128
/// </summary>
public class Tiger128_4 : TigerHashBase
{
public Tiger128_4() : base()
{
_passes = 4;
_padStart = 0x01;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[16];
Array.Copy(hash, trimmedHash, 16);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger-160
/// </summary>
public class Tiger160_3 : TigerHashBase
{
public Tiger160_3() : base()
{
_passes = 3;
_padStart = 0x01;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[20];
Array.Copy(hash, trimmedHash, 20);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger-160
/// </summary>
public class Tiger160_4 : TigerHashBase
{
public Tiger160_4() : base()
{
_passes = 4;
_padStart = 0x01;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[20];
Array.Copy(hash, trimmedHash, 20);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger-192
/// </summary>
public class Tiger192_3 : TigerHashBase
{
public Tiger192_3() : base()
{
_passes = 3;
_padStart = 0x01;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger-192
/// </summary>
public class Tiger192_4 : TigerHashBase
{
public Tiger192_4() : base()
{
_passes = 4;
_padStart = 0x01;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger2-128
/// </summary>
public class Tiger2_128_3 : TigerHashBase
{
public Tiger2_128_3() : base()
{
_passes = 3;
_padStart = 0x80;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[16];
Array.Copy(hash, trimmedHash, 16);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger2-128
/// </summary>
public class Tiger2_128_4 : TigerHashBase
{
public Tiger2_128_4() : base()
{
_passes = 4;
_padStart = 0x80;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[16];
Array.Copy(hash, trimmedHash, 16);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger2-160
/// </summary>
public class Tiger2_160_3 : TigerHashBase
{
public Tiger2_160_3() : base()
{
_passes = 3;
_padStart = 0x80;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[20];
Array.Copy(hash, trimmedHash, 20);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger2-160
/// </summary>
public class Tiger2_160_4 : TigerHashBase
{
public Tiger2_160_4() : base()
{
_passes = 4;
_padStart = 0x80;
}
/// <inheritdoc/>
public override byte[] GetHash()
{
byte[] hash = base.GetHash();
byte[] trimmedHash = new byte[20];
Array.Copy(hash, trimmedHash, 20);
return trimmedHash;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 3-pass variant of Tiger2-192
/// </summary>
public class Tiger2_192_3 : TigerHashBase
{
public Tiger2_192_3() : base()
{
_passes = 3;
_padStart = 0x80;
}
}
}

View File

@@ -0,0 +1,14 @@
namespace SabreTools.Hashing.MessageDigest
{
/// <summary>
/// 4-pass variant of Tiger2-192
/// </summary>
public class Tiger2_192_4 : TigerHashBase
{
public Tiger2_192_4() : base()
{
_passes = 4;
_padStart = 0x80;
}
}
}

View File

@@ -0,0 +1,242 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.MessageDigest.Constants;
namespace SabreTools.Hashing.MessageDigest
{
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger//>
public abstract class TigerHashBase : MessageDigestBase<ulong>
{
/// <summary>
/// Number of passes (minimum 3)
/// </summary>
protected int _passes;
/// <summary>
/// Byte to start padding with
/// </summary>
protected byte _padStart;
/// <summary>
/// Set of 3 64-bit numbers representing the hash state
/// </summary>
private readonly ulong[] _state = new ulong[3];
public TigerHashBase() : base()
{
}
/// <inheritdoc/>
protected override void ResetImpl()
{
_state[0] = TigerSeedA;
_state[1] = TigerSeedB;
_state[2] = TigerSeedC;
}
/// <inheritdoc/>
public override void TransformBlock(byte[] data, int offset, int length)
{
// Figure out how much buffer is needed
int bufferLen = (int)(_totalBytes & 0x3f);
// Increment the processed byte count
_totalBytes += length;
// If there is buffer to fill and it will meet the limit
if (bufferLen > 0 && bufferLen + length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
// Set the new values
offset += 64 - bufferLen;
length -= 64 - bufferLen;
// Split the buffer for the round
for (int i = 0; i < 8; i++)
{
_block[i] = ReadLE64(_buffer, i * 8);
}
// Run the round
Compress();
bufferLen = 0;
}
/// Process any standalone blocks
while (length >= 64)
{
// Fill the buffer from the input
Array.Copy(data, offset, _buffer, 0, 64);
// Set the new values
offset += 64;
length -= 64;
// Split the buffer for the round
for (int i = 0; i < 8; i++)
{
_block[i] = ReadLE64(_buffer, i * 8);
}
// Run the round
Compress();
}
// Save the remainder in the buffer
if (length > 0)
Array.Copy(data, offset, _buffer, bufferLen, length);
}
/// <inheritdoc/>
public override void Terminate()
{
// Determine the pad length
int padLength = 64 - (int)(_totalBytes & 0x3f);
if (padLength <= 8)
padLength += 64;
// Get the total byte count in bits
long totalBitCount = _totalBytes * 8;
// Prebuild the padding
var padding = new byte[padLength];
padding[0] = _padStart;
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
// Pad the block
TransformBlock(padding, 0, padding.Length);
}
/// <inheritdoc/>
public override byte[] GetHash()
{
var hash = new byte[24];
int hashOffset = 0;
// Assemble the hash array
for (int i = 0; i < _state.Length; i++)
{
byte[] segment = BitConverter.GetBytes(_state[i]);
Array.Copy(segment, 0, hash, hashOffset, 8);
hashOffset += 8;
}
// Reset the state and return
Reset();
return hash;
}
/// <summary>
/// Perform one round of updates on the cached values
/// </summary>
private void Compress()
{
// Save current values [save_abc]
ulong aa = _state[0];
ulong bb = _state[1];
ulong cc = _state[2];
// Pass 1 [pass(a, b, c, 5)]
Pass(ref _state[0], ref _state[1], ref _state[2], 5);
// Avalanche [key_schedule]
KeySchedule();
// Pass 2 [pass(c, a, b, 7)]
Pass(ref _state[2], ref _state[0], ref _state[1], 7);
// Avalanche [key_schedule]
KeySchedule();
// Pass 3 [pass(b, c, a, 9)]
Pass(ref _state[1], ref _state[2], ref _state[0], 9);
// Perform correct set of extra passes
for (int pass_no = 3; pass_no < _passes; pass_no++)
{
// Avalanche [key_schedule]
KeySchedule();
// Pass N [pass(a, b, c, 9)]
Pass(ref _state[0], ref _state[1], ref _state[2], 9);
// Rotate
ulong tmpa = _state[0];
_state[0] = _state[2];
_state[2] = _state[1];
_state[1] = tmpa;
}
// Update stored values [feedforward]
_state[0] ^= aa;
_state[1] -= bb;
_state[2] += cc;
}
/// <summary>
/// pass(a,b,c,mul)
/// </summary>
private void Pass(ref ulong a, ref ulong b, ref ulong c, int mul)
{
Round(ref a, ref b, ref c, _block[0], mul);
Round(ref b, ref c, ref a, _block[1], mul);
Round(ref c, ref a, ref b, _block[2], mul);
Round(ref a, ref b, ref c, _block[3], mul);
Round(ref b, ref c, ref a, _block[4], mul);
Round(ref c, ref a, ref b, _block[5], mul);
Round(ref a, ref b, ref c, _block[6], mul);
Round(ref b, ref c, ref a, _block[7], mul);
}
/// <summary>
/// round(a,b,c,x,mul)
/// </summary>
private static void Round(ref ulong a, ref ulong b, ref ulong c, ulong x, int mul)
{
c ^= x;
a -= TigerSBox[((c >> (0 * 8)) & 0xFF) + (0 * 256)]
^ TigerSBox[((c >> (2 * 8)) & 0xFF) + (1 * 256)]
^ TigerSBox[((c >> (4 * 8)) & 0xFF) + (2 * 256)]
^ TigerSBox[((c >> (6 * 8)) & 0xFF) + (3 * 256)];
b += TigerSBox[((c >> (1 * 8)) & 0xFF) + (3 * 256)]
^ TigerSBox[((c >> (3 * 8)) & 0xFF) + (2 * 256)]
^ TigerSBox[((c >> (5 * 8)) & 0xFF) + (1 * 256)]
^ TigerSBox[((c >> (7 * 8)) & 0xFF) + (0 * 256)];
unchecked { b *= (ulong)mul; }
}
/// <summary>
/// key_schedule
/// </summary>
private void KeySchedule()
{
_block[0] -= _block[7] ^ 0xA5A5A5A5A5A5A5A5;
_block[1] ^= _block[0];
_block[2] += _block[1];
_block[3] -= _block[2] ^ ((~_block[1]) << 19);
_block[4] ^= _block[3];
_block[5] += _block[4];
_block[6] -= _block[5] ^ ((~_block[4]) >> 23);
_block[7] ^= _block[6];
_block[0] += _block[7];
_block[1] -= _block[0] ^ ((~_block[7]) << 19);
_block[2] ^= _block[1];
_block[3] += _block[2];
_block[4] -= _block[3] ^ ((~_block[2]) >> 23);
_block[5] ^= _block[4];
_block[6] += _block[5];
_block[7] -= _block[6] ^ 0x0123456789ABCDEF;
}
}
}

View File

@@ -1,54 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.2.2</Version>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.3.0</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2016-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Hashing</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>hash hashing checksum checksumming crc md5 sha1</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2016-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Hashing</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>hash hashing checksum checksumming crc md5 sha1</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="" />
</ItemGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
</PropertyGroup>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))">
<PackageReference Include="Net30.LinqBridge" Version="1.3.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="MinAsyncBridge" Version="0.12.4" />
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.4" />
<PackageReference Include="MinThreadingBridge" Version="0.11.4" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net45`)) OR $(TargetFramework.StartsWith(`net46`)) OR $(TargetFramework.StartsWith(`net47`)) OR $(TargetFramework.StartsWith(`net48`))">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net45`))">
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
<PackageReference Include="Blake3" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aaru.Checksums.Native" Version="6.0.0-alpha9"/>
</ItemGroup>
<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="" />
</ItemGroup>
</Project>
<!-- Support for old .NET versions -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net45`))">
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
<PackageReference Include="Blake3" Version="1.1.0" />
</ItemGroup>
</Project>

View File

@@ -1,185 +0,0 @@
using System;
using System.Linq;
namespace SabreTools.Hashing.Tiger
{
/// <summary>
/// Reference implementation of the Tiger hash
/// </summary>
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger/"/>
public class TigerHash
{
/// <summary>
/// The number of passes of the hash function.
/// Three passes are recommended.
/// Use four passes when you need extra security.
/// Must be at least three.
/// </summary>
private const int PASSES = 3;
public void tiger(ulong[] str, ulong length)
{
ulong i, j;
byte[] temp = new byte[64];
ulong[] res =
[
0x0123456789ABCDEF,
0xFEDCBA9876543210,
0xF096A5B4C3B2E187
];
int strOffset = 0;
for (i = length; i >= 64; i -= 64)
{
Compress(str, strOffset, res);
strOffset += 8;
}
byte[] strBytes = new byte[str.Length * 8];
Array.ConstrainedCopy(str, 0, strBytes, 0, str.Length);
for (j = 0; j < i; j++)
{
temp[j] = strBytes[j];
}
temp[j++] = 0x01;
for (; (j & 7) > 0; j++)
{
temp[j] = 0;
}
if (j > 56)
{
for (; j < 64; j++)
{
temp[j] = 0;
}
Compress(ref temp, 0, res);
j = 0;
}
for (; j < 56; j++)
{
temp[j] = 0;
}
Compress(ref temp, 0, res, true, length);
}
private static bool Compress(ref byte[] str, int strOffset, ulong[] state, bool shouldSetSeven = false, ulong length = 0)
{
// Create the temp array
ulong[] temp = new ulong[str.Length / 8];
Array.ConstrainedCopy(str, 0, temp, 0, str.Length);
// Set index 7, if required
if (shouldSetSeven)
temp[7] = length << 3;
// Run the compression
bool success = Compress(temp, strOffset, state);
// Copy the values back
Array.ConstrainedCopy(temp, 0, str, 0, temp.Length);
return success;
}
private static bool Compress(ulong[] str, int strOffset, ulong[] state)
{
// Bounds checking
if (state.Length != 3)
return false;
if (str.Length < strOffset + 8)
return false;
ulong[] x = str.Skip(strOffset).Take(8).ToArray();
// save_abc
ulong aa = state[0];
ulong bb = state[1];
ulong cc = state[2];
for (int pass_no = 0; pass_no < PASSES; pass_no++)
{
if (pass_no != 0)
KeySchedule(x);
int mul = pass_no == 0 ? 5 : pass_no == 1 ? 7 : 9;
Pass(state, x, mul);
ulong temp = state[0]; state[0] = state[2]; state[2] = state[1]; state[1] = temp;
}
// feedforward
state[0] ^= aa;
state[1] -= bb;
state[2] += cc;
return true;
}
private static void KeySchedule(ulong[] x)
{
x[0] -= x[7] ^ 0xA5A5A5A5A5A5A5A5;
x[1] ^= x[0];
x[2] += x[1];
x[3] -= x[2] ^ ((~x[1]) << 19);
x[4] ^= x[3];
x[5] += x[4];
x[6] -= x[5] ^ ((~x[4]) >> 23);
x[7] ^= x[6];
x[0] += x[7];
x[1] -= x[0] ^ ((~x[7]) << 19);
x[2] ^= x[1];
x[3] += x[2];
x[4] -= x[3] ^ ((~x[2]) >> 23);
x[5] ^= x[4];
x[6] += x[5];
x[7] -= x[6] ^ 0x0123456789ABCDEF;
}
private static bool Pass(ulong[] state, ulong[] x, int mul)
{
// Bounds checking
if (state.Length != 3)
return false;
Round(state, 0, 1, 2, x[0], mul);
Round(state, 1, 2, 0, x[1], mul);
Round(state, 2, 0, 1, x[2], mul);
Round(state, 0, 1, 2, x[3], mul);
Round(state, 1, 2, 0, x[4], mul);
Round(state, 2, 0, 1, x[5], mul);
Round(state, 0, 1, 2, x[6], mul);
Round(state, 1, 2, 0, x[7], mul);
return true;
}
private static bool Round(ulong[] state, int a, int b, int c, ulong x, int mul)
{
// Bounds checking
if (state.Length != 3)
return false;
state[c] ^= x;
state[a] -= t1((byte)state[c])
^ t2((byte)(((uint)state[c]) >> (2 * 8)))
^ t3((byte)((state[c]) >> (4 * 8)))
^ t4((byte)(((uint)((state[c]) >> (4 * 8))) >> (2 * 8)));
state[b] += t4((byte)(((uint)state[c]) >> (1 * 8)))
^ t3((byte)(((uint)state[c]) >> (3 * 8)))
^ t2((byte)(((uint)((state[c]) >> (4 * 8))) >> (1 * 8)))
^ t1((byte)(((uint)((state[c]) >> (4 * 8))) >> (3 * 8)));
state[b] *= (ulong)mul;
return true;
}
private static ulong t1(int offset) => SBoxes.Table[offset];
private static ulong t2(int offset) => SBoxes.Table[offset + 256];
private static ulong t3(int offset) => SBoxes.Table[offset + 256 * 2];
private static ulong t4(int offset) => SBoxes.Table[offset + 256 * 3];
}
}

View File

@@ -0,0 +1,98 @@
namespace SabreTools.Hashing.XxHash
{
// https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
internal static class Constants
{
#region Version
public const int XXH_VERSION_MAJOR = 0;
public const int XXH_VERSION_MINOR = 8;
public const int XXH_VERSION_RELEASE = 3;
#endregion
#region XXH32
public const uint XXH_PRIME32_1 = 0x9E3779B1;
public const uint XXH_PRIME32_2 = 0x85EBCA77;
public const uint XXH_PRIME32_3 = 0xC2B2AE3D;
public const uint XXH_PRIME32_4 = 0x27D4EB2F;
public const uint XXH_PRIME32_5 = 0x165667B1;
#endregion
#region XXH64
public const ulong XXH_PRIME64_1 = 0x9E3779B185EBCA87;
public const ulong XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4F;
public const ulong XXH_PRIME64_3 = 0x165667B19E3779F9;
public const ulong XXH_PRIME64_4 = 0x85EBCA77C2B2AE63;
public const ulong XXH_PRIME64_5 = 0x27D4EB2F165667C5;
#endregion
#region XXH3
/// <summary>
/// Pseudorandom secret taken directly from FARSH.
/// </summary>
public static readonly byte[] XXH3_kSecret =
[
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
];
public const ulong PRIME_MX1 = 0x165667919E3779F9;
public const ulong PRIME_MX2 = 0x9FB21C651E98DF25;
/// <summary>
/// The size of the internal XXH3 buffer.
/// This is the optimal update size for incremental hashing.
/// </summary>
public const int XXH3_INTERNALBUFFER_SIZE = 256;
/// <summary>
/// The bare minimum size for a custom secret.
/// </summary>
public const int XXH3_SECRET_SIZE_MIN = 136;
/// <summary>
/// Default size of the secret buffer (and <see cref="XXH3_kSecret"/>).
/// This is the size used in <see cref="XXH3_kSecret"/> and the seeded functions.
/// Not to be confused with @ref XXH3_SECRET_SIZE_MIN.
/// </summary>
public const int XXH3_SECRET_DEFAULT_SIZE = 192;
public const int XXH_STRIPE_LEN = 64;
/// <summary>
/// Number of secret bytes consumed at each accumulation
/// </summary>
public const int XXH_SECRET_CONSUME_RATE = 8;
private const int XXH_ACC_NB = XXH_STRIPE_LEN / sizeof(ulong);
#endregion
}
}

View File

@@ -0,0 +1,74 @@
namespace SabreTools.Hashing.XxHash
{
// https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
internal enum ErrorCode
{
/// <summary>
/// OK
/// </summary>
XXH_OK = 0,
/// <summary>
/// Error
/// </summary>
XXH_ERROR,
}
// https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
internal enum Alignment
{
/// <summary>
/// Aligned
/// </summary>
XXH_aligned,
/// <summary>
/// Possibly unaligned
/// </summary>
XXH_unaligned,
}
// https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
internal enum VectorType
{
/// <summary>
/// Portable scalar version
/// </summary>
XXH_SCALAR = 0,
/// <summary>
/// SSE2 for Pentium 4, Opteron, all x86_64.
/// </summary>
/// <remarks>
/// SSE2 is also guaranteed on Windows 10, macOS, and Android x86.
/// </remarks>
XXH_SSE2 = 1,
/// <summary>
/// AVX2 for Haswell and Bulldozer
/// </summary>
XXH_AVX2 = 2,
/// <summary>
/// AVX512 for Skylake and Icelake
/// </summary>
XXH_AVX512 = 3,
/// <summary>
/// NEON for most ARMv7-A, all AArch64, and WASM SIMD128
/// via the SIMDeverywhere polyfill provided with the
/// Emscripten SDK.
/// </summary>
XXH_NEON = 4,
/// <summary>
/// VSX and ZVector for POWER8/z13 (64-bit)
/// </summary>
XXH_VSX = 5,
/// <summary>
/// SVE for some ARMv8-A and ARMv9-A
/// </summary>
XXH_SVE = 6,
}
}

View File

@@ -0,0 +1,251 @@
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.XxHash.Constants;
namespace SabreTools.Hashing.XxHash
{
internal static class Utility
{
#region Multiply and Fold
/// <summary>
/// Calculates a 64-bit to 128-bit multiply, then XOR folds it.
/// </summary>
public static ulong MultiplyTo128Fold64(ulong lhs, ulong rhs)
{
var product = MultiplyTo128(lhs, rhs);
return product.Low ^ product.High;
}
/// <summary>
/// Calculates a 32-bit to 64-bit long multiply.
/// </summary>
public static ulong MultiplyTo64(ulong x, ulong y)
{
return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF);
}
/// <summary>
/// Calculates a 64->128-bit long multiply.
/// </summary>
public static XXH3_128Hash MultiplyTo128(ulong lhs, ulong rhs)
{
// First calculate all of the cross products.
ulong lo_lo = MultiplyTo64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);
ulong hi_lo = MultiplyTo64(lhs >> 32, rhs & 0xFFFFFFFF);
ulong lo_hi = MultiplyTo64(lhs & 0xFFFFFFFF, rhs >> 32);
ulong hi_hi = MultiplyTo64(lhs >> 32, rhs >> 32);
// Now add the products together. These will never overflow.
ulong cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
ulong upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
ulong lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
return new XXH3_128Hash
{
Low = lower,
High = upper,
};
}
#endregion
#region Shift
public static ulong XorShift64(ulong v64, int shift)
{
return v64 ^ (v64 >> shift);
}
#endregion
#region XXH64 Common
/// <summary>
/// Mixes all bits to finalize the hash.
///
/// The final mix ensures that all input bits have a chance to impact any bit in
/// the output digest, resulting in an unbiased distribution.
/// </summary>
public static ulong XXH64Avalanche(ulong hash)
{
hash ^= hash >> 33;
hash *= XXH_PRIME64_2;
hash ^= hash >> 29;
hash *= XXH_PRIME64_3;
hash ^= hash >> 32;
return hash;
}
#endregion
#region XXH3 Common
/// <summary>
/// This is a fast avalanche stage,
/// suitable when input bits are already partially mixed
/// </summary>
public static ulong XXH3Avalanche(ulong hash)
{
hash = XorShift64(hash, 37);
hash *= PRIME_MX1;
hash = XorShift64(hash, 32);
return hash;
}
/// <summary>
/// This is a stronger avalanche,
/// inspired by Pelle Evensen's rrmxmx
/// preferable when input has not been previously mixed
/// </summary>
public static ulong XXH3Rrmxmx(ulong hash, ulong length)
{
// This mix is inspired by Pelle Evensen's rrmxmx
hash ^= RotateLeft64(hash, 49) ^ RotateLeft64(hash, 24);
hash *= PRIME_MX2;
hash ^= (hash >> 35) + length;
hash *= PRIME_MX2;
return XorShift64(hash, 28);
}
/// <summary>
/// Handle length 1 to 3 values
/// </summary>
public static ulong Len1To3Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
byte c1 = data[offset + 0];
byte c2 = data[offset + (length >> 1)];
byte c3 = data[offset + (length - 1)];
uint combined = ((uint)c1 << 16)
| ((uint)c2 << 24)
| ((uint)c3 << 0)
| ((uint)length << 8);
ulong bitflip = (ReadLE32(secret, 0) ^ ReadLE32(secret, 4)) + seed;
ulong keyed = combined ^ bitflip;
return XXH64Avalanche(keyed);
}
/// <summary>
/// Handle length 4 to 8 values
/// </summary>
public static ulong Len4To8Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
seed ^= (ulong)Swap32((uint)seed) << 32;
uint input1 = ReadLE32(data, offset);
uint input2 = ReadLE32(data, offset + length - 4);
ulong bitflip = (ReadLE64(secret, 8) ^ ReadLE64(secret, 16)) - seed;
ulong input64 = input2 + (((ulong)input1) << 32);
ulong keyed = input64 ^ bitflip;
return XXH3Rrmxmx(keyed, (ulong)length);
}
/// <summary>
/// Handle length 9 to 16 values
/// </summary>
public static ulong Len9To16Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
ulong bitflip1 = (ReadLE64(secret, 24) ^ ReadLE64(secret, 32)) + seed;
ulong bitflip2 = (ReadLE64(secret, 40) ^ ReadLE64(secret, 48)) - seed;
ulong input_lo = ReadLE64(data, offset) ^ bitflip1;
ulong input_hi = ReadLE64(data, offset + length - 8) ^ bitflip2;
ulong acc = (ulong)length
+ Swap64(input_lo) + input_hi
+ MultiplyTo128Fold64(input_lo, input_hi);
return XXH3Avalanche(acc);
}
/// <summary>
/// Handle length 0 to 16 values
/// </summary>
public static ulong Len0To16Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
if (length > 8)
return Len9To16Out64(data, offset, length, secret, seed);
if (length >= 4)
return Len4To8Out64(data, offset, length, secret, seed);
if (length > 0)
return Len1To3Out64(data, offset, length, secret, seed);
return XXH64Avalanche(seed ^ (ReadLE64(secret, 56) ^ ReadLE64(secret, 64)));
}
public static ulong Mix16B(byte[] data, int offset, byte[] secret, int secretOffset, ulong seed)
{
ulong input_lo = ReadLE64(data, offset + 0);
ulong input_hi = ReadLE64(data, offset + 8);
return MultiplyTo128Fold64(
input_lo ^ (ReadLE64(secret, secretOffset + 0) + seed),
input_hi ^ (ReadLE64(secret, secretOffset + 8) - seed)
);
}
/// <summary>
/// Handle length 7 to 128 values
/// </summary>
public static ulong Len17To128Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
ulong acc = (ulong)length * XXH_PRIME64_1;
if (length > 32)
{
if (length > 64)
{
if (length > 96)
{
acc += Mix16B(data, offset + 48, secret, 96, seed);
acc += Mix16B(data, offset + length - 64, secret, 112, seed);
}
acc += Mix16B(data, offset + 32, secret, 64, seed);
acc += Mix16B(data, offset + length - 48, secret, 80, seed);
}
acc += Mix16B(data, offset + 16, secret, 32, seed);
acc += Mix16B(data, offset + length - 32, secret, 48, seed);
}
acc += Mix16B(data, offset + 0, secret, 0, seed);
acc += Mix16B(data, offset + length - 16, secret, 16, seed);
return XXH3Avalanche(acc);
}
/// <summary>
/// Handle length 129 to 240 values
/// </summary>
public static ulong Len129To240Out64(byte[] data, int offset, int length, byte[] secret, ulong seed)
{
const int XXH3_MIDSIZE_STARTOFFSET = 3;
const int XXH3_MIDSIZE_LASTOFFSET = 17;
ulong acc = (ulong)length * XXH_PRIME64_1;
ulong acc_end;
uint nbRounds = (uint)length / 16;
uint i;
for (i = 0; i < 8; i++)
{
acc += Mix16B(data, offset + (int)(16 * i), secret, (int)(16 * i), seed);
}
// Last bytes
acc_end = Mix16B(data, offset + length - 16, secret, XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
acc = XXH3Avalanche(acc);
for (i = 8; i < nbRounds; i++)
{
acc_end += Mix16B(data, offset + (int)(16 * i), secret, (int)(16 * (i - 8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
}
return XXH3Avalanche(acc + acc_end);
}
#endregion
}
}

View File

@@ -0,0 +1,204 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.XxHash.Constants;
namespace SabreTools.Hashing.XxHash
{
/// <summary>
/// Structure for XXH32 streaming API.
/// </summary>
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
internal class XXH32State
{
/// <summary>
/// Total length hashed, modulo 2^32
/// </summary>
private uint _totalLen32;
/// <summary>
/// Whether the hash is >= 16 (handles <see cref="_totalLen32"/> overflow)
/// </summary>
private bool _largeLen;
/// <summary>
/// Accumulator lanes
/// </summary>
private readonly uint[] _acc = new uint[4];
/// <summary>
/// Internal buffer for partial reads. Treated as unsigned char[16].
/// </summary>
private readonly byte[] _mem32 = new byte[16];
/// <summary>
/// Amount of data in <see cref="_mem32">
/// </summary>
private int _memsize;
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 32-bit seed to alter the hash result predictably.</param>
public void Reset(uint seed)
{
_totalLen32 = 0;
_largeLen = false;
unchecked
{
_acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
_acc[1] = seed + XXH_PRIME32_2;
_acc[2] = seed + 0;
_acc[3] = seed - XXH_PRIME32_1;
}
Array.Clear(_mem32, 0, _mem32.Length);
_memsize = 0;
}
/// <summary>
/// Consumes a block of input
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void Update(byte[] data, int offset, int length)
{
int bEnd = offset + length;
_totalLen32 += (uint)length;
_largeLen |= (length >= 16) | (_totalLen32 >= 16);
// Fill in tmp buffer
if (_memsize + length < 16)
{
Array.Copy(data, offset, _mem32, _memsize, length);
_memsize += length;
return;
}
// Some data left from previous update
if (_memsize > 0)
{
Array.Copy(data, offset, _mem32, _memsize, 16 - _memsize);
int p32 = 0;
_acc[0] = Round(_acc[0], ReadLE32(_mem32, p32)); p32 += 4;
_acc[1] = Round(_acc[1], ReadLE32(_mem32, p32)); p32 += 4;
_acc[2] = Round(_acc[2], ReadLE32(_mem32, p32)); p32 += 4;
_acc[3] = Round(_acc[3], ReadLE32(_mem32, p32));
offset += 16 - _memsize;
_memsize = 0;
}
if (offset <= bEnd - 16)
{
int limit = bEnd - 16;
do
{
_acc[0] = Round(_acc[0], ReadLE32(data, offset)); offset += 4;
_acc[1] = Round(_acc[1], ReadLE32(data, offset)); offset += 4;
_acc[2] = Round(_acc[2], ReadLE32(data, offset)); offset += 4;
_acc[3] = Round(_acc[3], ReadLE32(data, offset)); offset += 4;
} while (offset <= limit);
}
if (offset < bEnd)
{
Array.Copy(data, offset, _mem32, 0, bEnd - offset);
_memsize = bEnd - offset;
}
}
/// <summary>
/// Returns the calculated hash value
/// </summary>
/// <returns>The calculated 32-bit xxHash32 value from that state.</returns>
public uint Digest()
{
uint hash;
if (_largeLen)
{
hash = RotateLeft32(_acc[0], 1)
+ RotateLeft32(_acc[1], 7)
+ RotateLeft32(_acc[2], 12)
+ RotateLeft32(_acc[3], 18);
}
else
{
hash = _acc[2] /* == seed */ + XXH_PRIME32_5;
}
hash += _totalLen32;
return Finalize(hash, _mem32, 0, _memsize);
}
/// <summary>
/// Normal stripe processing routine.
///
/// This shuffles the bits so that any bit from <paramref name="input"/> impacts
/// several bits in <paramref name="acc"/>.
/// </summary>
/// <param name="acc">The accumulator lane.</param>
/// <param name="input">The stripe of input to mix.</param>
/// <returns>The mixed accumulator lane.</returns>
private static uint Round(uint acc, uint input)
{
acc += input * XXH_PRIME32_2;
acc = RotateLeft32(acc, 13);
acc *= XXH_PRIME32_1;
return acc;
}
/// <summary>
/// Mixes all bits to finalize the hash.
///
/// The final mix ensures that all input bits have a chance to impact any bit in
/// the output digest, resulting in an unbiased distribution.
/// </summary>
private static uint Avalanche(uint hash)
{
hash ^= hash >> 15;
hash *= XXH_PRIME32_2;
hash ^= hash >> 13;
hash *= XXH_PRIME32_3;
hash ^= hash >> 16;
return hash;
}
/// <summary>
/// Processes the last 0-15 bytes of @p ptr.
///
/// There may be up to 15 bytes remaining to consume from the input.
/// This final stage will digest them to ensure that all input bytes are present
/// in the final mix.
/// </summary>
/// <param name="hash">The hash to finalize.</param>
/// <param name="data">The remaining input.</param>
/// <param name="offset">The pointer to the remaining input.</param>
/// <param name="length">The remaining length, modulo 16.</param>
/// <returns>The finalized hash.</returns>
private static uint Finalize(uint hash, byte[] data, int offset, int length)
{
length &= 15;
while (length >= 4)
{
hash += ReadLE32(data, offset) * XXH_PRIME32_3;
offset += 4;
hash = RotateLeft32(hash, 17) * XXH_PRIME32_4;
length -= 4;
}
while (length > 0)
{
hash += data[offset++] * XXH_PRIME32_5;
hash = RotateLeft32(hash, 11) * XXH_PRIME32_1;
--length;
}
return Avalanche(hash);
}
}
}

View File

@@ -0,0 +1,9 @@
namespace SabreTools.Hashing.XxHash
{
internal class XXH3_128Hash
{
public ulong Low { get; set; }
public ulong High { get; set; }
}
}

View File

@@ -0,0 +1,131 @@
namespace SabreTools.Hashing.XxHash
{
// Handle unused private fields
#pragma warning disable CS0169
#pragma warning disable CS0414
#pragma warning disable CS0649
/// <summary>
/// Structure for XXH3 streaming API.
/// </summary>
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
internal class XXH3_128State
{
/// <summary>
/// Accumulator lanes
/// </summary>
private readonly ulong[] _acc = new ulong[8];
/// <summary>
/// Used to store a custom secret generated from a seed.
/// </summary>
private readonly byte[] _customSecret = new byte[Constants.XXH3_SECRET_DEFAULT_SIZE];
/// <summary>
/// The internal buffer. <see cref="XXH32State._mem32"/>
/// </summary>
private readonly byte[] _buffer = new byte[Constants.XXH3_INTERNALBUFFER_SIZE];
/// <summary>
/// The amount of memory in <see cref="_buffer"/>, <see cref="XXH32State._memsize"/>
/// </summary>
private uint _bufferedSize;
/// <summary>
/// Reserved field. Needed for padding on 64-bit.
/// </summary>
private uint _useSeed;
/// <summary>
/// Number or stripes processed.
/// </summary>
private ulong _stripesSoFar;
/// <summary>
/// Total length hashed. 64-bit even on 32-bit targets.
/// </summary>
private ulong _totalLength;
/// <summary>
/// Number of stripes per block.
/// </summary>
private ulong _stripesPerBlock;
/// <summary>
/// Size of <see cref="_customSecret"/> or <see cref="_extSecret">
/// </summary>
private ulong _secretLimit;
/// <summary>
/// Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE()
/// </summary>
private ulong _seed;
/// <summary>
/// Reference to an external secret for the _withSecret variants, NULL
/// for other variants.
/// </summary>
/// <remarks>There may be some padding at the end due to alignment on 64 bytes</remarks>
private byte[]? _extSecret = null;
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public XXH3_128State(ulong seed = 0)
{
// TODO: XXH3_128bits_withSeed
}
/// <param name="secret">The secret data.</param>
public XXH3_128State(byte[] secret)
{
// TODO: XXH3_128bits_withSecret
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public void Reset()
{
// TODO: XXH3_128bits_reset
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public void Reset(ulong seed)
{
// TODO: XXH3_128bits_reset_withSeed
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="secret">The secret data.</param>
public void Reset(byte[] secret)
{
// TODO: XXH3_128bits_reset_withSecret
}
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void TransformBlock(byte[] data, int offset, int length)
{
// TODO: XXH3_128bits_update
}
/// <summary>
/// Returns the calculated hash value
/// </summary>
/// <returns>The calculated 64-bit xxHash64 value from that state.</returns>
public ulong Digest()
{
// TODO: XXH3_128bits_digest
return ulong.MaxValue;
}
}
}

View File

@@ -0,0 +1,136 @@
namespace SabreTools.Hashing.XxHash
{
// Handle unused private fields
#pragma warning disable CS0169
#pragma warning disable CS0414
#pragma warning disable CS0649
/// <summary>
/// Structure for XXH3 streaming API.
/// </summary>
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
internal class XXH3_64State
{
/// <summary>
/// Accumulator lanes
/// </summary>
private readonly ulong[] _acc = new ulong[8];
/// <summary>
/// Used to store a custom secret generated from a seed.
/// </summary>
private readonly byte[] _customSecret = new byte[Constants.XXH3_SECRET_DEFAULT_SIZE];
/// <summary>
/// The internal buffer. <see cref="XXH32State._mem32"/>
/// </summary>
private readonly byte[] _buffer = new byte[Constants.XXH3_INTERNALBUFFER_SIZE];
/// <summary>
/// The amount of memory in <see cref="_buffer"/>, <see cref="XXH32State._memsize"/>
/// </summary>
private uint _bufferedSize;
/// <summary>
/// Reserved field. Needed for padding on 64-bit.
/// </summary>
private uint _useSeed;
/// <summary>
/// Number or stripes processed.
/// </summary>
private ulong _stripesSoFar;
/// <summary>
/// Total length hashed. 64-bit even on 32-bit targets.
/// </summary>
private ulong _totalLength;
/// <summary>
/// Number of stripes per block.
/// </summary>
private ulong _stripesPerBlock;
/// <summary>
/// Size of <see cref="_customSecret"/> or <see cref="_extSecret">
/// </summary>
private ulong _secretLimit;
/// <summary>
/// Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE()
/// </summary>
private ulong _seed;
/// <summary>
/// Reference to an external secret for the _withSecret variants, NULL
/// for other variants.
/// </summary>
/// <remarks>There may be some padding at the end due to alignment on 64 bytes</remarks>
private byte[]? _extSecret = null;
public XXH3_64State()
{
// TODO: XXH3_64bits
}
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public XXH3_64State(ulong seed)
{
// TODO: XXH3_64bits_withSeed
}
/// <param name="secret">The secret data.</param>
public XXH3_64State(byte[] secret)
{
// TODO: XXH3_64bits_withSecret
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public void Reset()
{
// TODO: XXH3_64bits_reset
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public void Reset(ulong seed)
{
// TODO: XXH3_64bits_reset_withSeed
}
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="secret">The secret data.</param>
public void Reset(byte[] secret)
{
// TODO: XXH3_64bits_reset_withSecret
}
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void TransformBlock(byte[] data, int offset, int length)
{
// TODO: XXH3_64bits_update
}
/// <summary>
/// Returns the calculated hash value
/// </summary>
/// <returns>The calculated 64-bit xxHash64 value from that state.</returns>
public ulong Digest()
{
// TODO: XXH3_64bits_digest
return ulong.MaxValue;
}
}
}

View File

@@ -0,0 +1,204 @@
using System;
using static SabreTools.Hashing.HashOperations;
using static SabreTools.Hashing.XxHash.Constants;
using static SabreTools.Hashing.XxHash.Utility;
namespace SabreTools.Hashing.XxHash
{
/// <summary>
/// Structure for XXH64 streaming API.
/// </summary>
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
internal class XXH64State
{
/// <summary>
/// Total length hashed. This is always 64-bit.
/// </summary>
private ulong _totalLen;
/// <summary>
/// Accumulator lanes
/// </summary>
private readonly ulong[] _acc = new ulong[4];
/// <summary>
/// Internal buffer for partial reads. Treated as unsigned char[32].
/// </summary>
private readonly byte[] _mem64 = new byte[32];
/// <summary>
/// Amount of data in <see cref="_mem64">
/// </summary>
private int _memsize;
/// <summary>
/// Resets to begin a new hash
/// </summary>
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
public void Reset(ulong seed)
{
_totalLen = 0;
unchecked
{
_acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
_acc[1] = seed + XXH_PRIME64_2;
_acc[2] = seed + 0;
_acc[3] = seed - XXH_PRIME64_1;
}
Array.Clear(_mem64, 0, _mem64.Length);
_memsize = 0;
}
/// <summary>
/// Consumes a block of input
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void Update(byte[] data, int offset, int length)
{
int bEnd = offset + length;
_totalLen += (ulong)length;
// Fill in tmp buffer
if (_memsize + length < 32)
{
Array.Copy(data, offset, _mem64, _memsize, length);
_memsize += length;
return;
}
// Some data left from previous update
if (_memsize > 0)
{
Array.Copy(data, offset, _mem64, _memsize, 32 - _memsize);
int p64 = 0;
_acc[0] = Round(_acc[0], ReadLE64(_mem64, p64)); p64 += 8;
_acc[1] = Round(_acc[1], ReadLE64(_mem64, p64)); p64 += 8;
_acc[2] = Round(_acc[2], ReadLE64(_mem64, p64)); p64 += 8;
_acc[3] = Round(_acc[3], ReadLE64(_mem64, p64));
offset += 32 - _memsize;
_memsize = 0;
}
if (offset <= bEnd - 32)
{
int limit = bEnd - 32;
do
{
_acc[0] = Round(_acc[0], ReadLE64(data, offset)); offset += 8;
_acc[1] = Round(_acc[1], ReadLE64(data, offset)); offset += 8;
_acc[2] = Round(_acc[2], ReadLE64(data, offset)); offset += 8;
_acc[3] = Round(_acc[3], ReadLE64(data, offset)); offset += 8;
} while (offset <= limit);
}
if (offset < bEnd)
{
Array.Copy(data, offset, _mem64, 0, bEnd - offset);
_memsize = bEnd - offset;
}
}
/// <summary>
/// Returns the calculated hash value
/// </summary>
/// <returns>The calculated 64-bit xxHash64 value from that state.</returns>
public ulong Digest()
{
ulong h64;
if (_totalLen >= 32)
{
h64 = RotateLeft64(_acc[0], 1)
+ RotateLeft64(_acc[1], 7)
+ RotateLeft64(_acc[2], 12)
+ RotateLeft64(_acc[3], 18);
h64 = MergeRound(h64, _acc[0]);
h64 = MergeRound(h64, _acc[1]);
h64 = MergeRound(h64, _acc[2]);
h64 = MergeRound(h64, _acc[3]);
}
else
{
h64 = _acc[2] /*seed*/ + XXH_PRIME64_5;
}
h64 += _totalLen;
return Finalize(h64, _mem64, 0, (int)_totalLen);
}
/// <summary>
/// Normal stripe processing routine.
///
/// This shuffles the bits so that any bit from @p input impacts
/// several bits in @p acc.
/// </summary>
/// <param name="acc">The accumulator lane.</param>
/// <param name="input">The stripe of input to mix.</param>
/// <returns>The mixed accumulator lane.</returns>
private static ulong Round(ulong acc, ulong input)
{
acc += unchecked(input * XXH_PRIME64_2);
acc = RotateLeft64(acc, 31);
acc *= XXH_PRIME64_1;
return acc;
}
private static ulong MergeRound(ulong acc, ulong val)
{
val = Round(0, val);
acc ^= val;
acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4;
return acc;
}
/// <summary>
/// Processes the last 0-31 bytes of @p ptr.
///
/// There may be up to 31 bytes remaining to consume from the input.
/// This final stage will digest them to ensure that all input bytes are present
/// in the final mix.
/// </summary>
/// <param name="hash">The hash to finalize.</param>
/// <param name="data">The pointer to the remaining input.</param>
/// <param name="offset">The pointer to the remaining input.</param>
/// <param name="length">The remaining length, modulo 32.</param>
/// <param name="align">Whether @p ptr is aligned.</param>
/// <returns>The finalized hash</returns>
private static ulong Finalize(ulong hash, byte[] data, int offset, int length)
{
length &= 31;
while (length >= 8)
{
ulong k1 = Round(0, ReadLE64(data, offset));
offset += 8;
hash ^= k1;
hash = RotateLeft64(hash, 27) * XXH_PRIME64_1 + XXH_PRIME64_4;
length -= 8;
}
if (length >= 4)
{
hash ^= ReadLE32(data, offset) * XXH_PRIME64_1;
offset += 4;
hash = RotateLeft64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
length -= 4;
}
while (length > 0)
{
hash ^= data[offset++] * XXH_PRIME64_5;
hash = RotateLeft64(hash, 11) * XXH_PRIME64_1;
--length;
}
return XXH64Avalanche(hash);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
namespace SabreTools.Hashing.XxHash
{
public class XxHash32
{
/// <summary>
/// The 32-bit seed to alter the hash result predictably.
/// </summary>
private readonly uint _seed;
/// <summary>
/// Internal xxHash32 state
/// </summary>
private readonly XXH32State _state;
public XxHash32(uint seed = 0)
{
_seed = seed;
_state = new XXH32State();
_state.Reset(seed);
}
/// <summary>
/// Reset the internal hashing state
/// </summary>
public void Reset()
{
_state.Reset(_seed);
}
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void TransformBlock(byte[] data, int offset, int length)
=> _state.Update(data, offset, length);
/// <summary>
/// Finalize the hash and return as a byte array
/// </summary>
public byte[] Finalize()
{
uint hash = _state.Digest();
return BitConverter.GetBytes(hash);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
namespace SabreTools.Hashing.XxHash
{
public class XxHash64
{
/// <summary>
/// The 64-bit seed to alter the hash result predictably.
/// </summary>
private readonly uint _seed;
/// <summary>
/// Internal xxHash64 state
/// </summary>
private readonly XXH64State _state;
public XxHash64(uint seed = 0)
{
_seed = seed;
_state = new XXH64State();
_state.Reset(seed);
}
/// <summary>
/// Reset the internal hashing state
/// </summary>
public void Reset()
{
_state.Reset(_seed);
}
/// <summary>
/// Hash a block of data and append it to the existing hash
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="offset">Offset in the byte array to include</param>
/// <param name="length">Length of the data to hash</param>
public void TransformBlock(byte[] data, int offset, int length)
=> _state.Update(data, offset, length);
/// <summary>
/// Finalize the hash and return as a byte array
/// </summary>
public byte[] Finalize()
{
ulong hash = _state.Digest();
return BitConverter.GetBytes(hash);
}
}
}

View File

@@ -0,0 +1,623 @@
using System.Collections.Generic;
namespace SabreTools.Hashing
{
/// <summary>
/// Zero-byte / empty hash
/// </summary>
public static class ZeroHash
{
#region Shortcuts for Common Hash Arrays
/// <summary>
/// Zero-byte CRC-32 checksum
/// </summary>
public static byte[] CRC32Arr => _bytes[HashType.CRC32];
/// <summary>
/// Zero-byte MD5 hash
/// </summary>
public static byte[] MD5Arr => _bytes[HashType.MD5];
/// <summary>
/// Zero-byte SHA-1 hash
/// </summary>
public static byte[] SHA1Arr => _bytes[HashType.SHA1];
/// <summary>
/// Zero-byte SHA-256 hash
/// </summary>
public static byte[] SHA256Arr => _bytes[HashType.SHA256];
/// <summary>
/// Zero-byte SHA-384 hash
/// </summary>
public static byte[] SHA384Arr => _bytes[HashType.SHA384];
/// <summary>
/// Zero-byte SHA-512 hash
/// </summary>
public static byte[] SHA512Arr => _bytes[HashType.SHA512];
/// <summary>
/// Zero-byte SpamSum fuzzy hash
/// </summary>
public static byte[] SpamSumArr => _bytes[HashType.SpamSum];
#endregion
#region Shortcuts for Common Hash Strings
/// <summary>
/// Zero-byte CRC-32 checksum
/// </summary>
public static string CRC32Str => _strings[HashType.CRC32];
/// <summary>
/// Zero-byte MD5 hash
/// </summary>
public static string MD5Str => _strings[HashType.MD5];
/// <summary>
/// Zero-byte SHA-1 hash
/// </summary>
public static string SHA1Str => _strings[HashType.SHA1];
/// <summary>
/// Zero-byte SHA-256 hash
/// </summary>
public static string SHA256Str => _strings[HashType.SHA256];
/// <summary>
/// Zero-byte SHA-384 hash
/// </summary>
public static string SHA384Str => _strings[HashType.SHA384];
/// <summary>
/// Zero-byte SHA-512 hash
/// </summary>
public static string SHA512Str => _strings[HashType.SHA512];
/// <summary>
/// Zero-byte SpamSum fuzzy hash
/// </summary>
public static string SpamSumStr => _strings[HashType.SpamSum];
#endregion
/// <summary>
/// Set of all known 0-byte outputs as strings
/// </summary>
private static readonly Dictionary<HashType, byte[]> _bytes = new()
{
{HashType.Adler32, [0x00, 0x00, 0x00, 0x01]},
#if NET7_0_OR_GREATER
{HashType.BLAKE3, [0xaf, 0x13, 0x49, 0xb9, 0xf5, 0xf9, 0xa1, 0xa6,
0xa0, 0x40, 0x4d, 0xea, 0x36, 0xdc, 0xc9, 0x49,
0x9b, 0xcb, 0x25, 0xc9, 0xad, 0xc1, 0x12, 0xb7,
0xcc, 0x9a, 0x93, 0xca, 0xe4, 0x1f, 0x32, 0x62]},
#endif
{HashType.CRC1_ZERO, [0x00]},
{HashType.CRC1_ONE, [0x01]},
{HashType.CRC3_GSM, [0x07]},
{HashType.CRC3_ROHC, [0x07]},
{HashType.CRC4_G704, [0x00]},
{HashType.CRC4_INTERLAKEN, [0x00]},
{HashType.CRC5_EPCC1G2, [0x09]},
{HashType.CRC5_G704, [0x00]},
{HashType.CRC5_USB, [0x00]},
{HashType.CRC6_CDMA2000A, [0x3f]},
{HashType.CRC6_CDMA2000B, [0x3f]},
{HashType.CRC6_DARC, [0x00]},
{HashType.CRC6_G704, [0x00]},
{HashType.CRC6_GSM, [0x3f]},
{HashType.CRC7_MMC, [0x00]},
{HashType.CRC7_ROHC, [0x7f]},
{HashType.CRC7_UMTS, [0x00]},
{HashType.CRC8, [0x00]},
{HashType.CRC8_AUTOSAR, [0x00]},
{HashType.CRC8_BLUETOOTH, [0x00]},
{HashType.CRC8_CDMA2000, [0xff]},
{HashType.CRC8_DARC, [0x00]},
{HashType.CRC8_DVBS2, [0x00]},
{HashType.CRC8_GSMA, [0x00]},
{HashType.CRC8_GSMB, [0xff]},
{HashType.CRC8_HITAG, [0xff]},
{HashType.CRC8_I4321, [0x55]},
{HashType.CRC8_ICODE, [0xfd]},
{HashType.CRC8_LTE, [0x00]},
{HashType.CRC8_MAXIMDOW, [0x00]},
{HashType.CRC8_MIFAREMAD, [0xc7]},
{HashType.CRC8_NRSC5, [0xff]},
{HashType.CRC8_OPENSAFETY, [0x00]},
{HashType.CRC8_ROHC, [0xff]},
{HashType.CRC8_SAEJ1850, [0x00]},
{HashType.CRC8_SMBUS, [0x00]},
{HashType.CRC8_TECH3250, [0xff]},
{HashType.CRC8_WCDMA, [0x00]},
{HashType.CRC10_ATM, [0x00, 0x00]},
{HashType.CRC10_CDMA2000, [0x03, 0xff]},
{HashType.CRC10_GSM, [0x03, 0xff]},
{HashType.CRC11_FLEXRAY, [0x00, 0x1a]},
{HashType.CRC11_UMTS, [0x00, 0x00]},
{HashType.CRC12_CDMA2000, [0x0f, 0xff]},
{HashType.CRC12_DECT, [0x00, 0x00]},
{HashType.CRC12_GSM, [0x0f, 0xff]},
{HashType.CRC12_UMTS, [0x00, 0x00]},
{HashType.CRC13_BBC, [0x00, 0x00]},
{HashType.CRC14_DARC, [0x00, 0x00]},
{HashType.CRC14_GSM, [0x3f, 0xff]},
{HashType.CRC15_CAN, [0x00, 0x00]},
{HashType.CRC15_MPT1327, [0x00, 0x01]},
{HashType.CRC16, [0x00, 0x00]},
{HashType.CRC16_ARC, [0x00, 0x00]},
{HashType.CRC16_CDMA2000, [0xff, 0xff]},
{HashType.CRC16_CMS, [0xff, 0xff]},
{HashType.CRC16_DDS110, [0x80, 0x0d]},
{HashType.CRC16_DECTR, [0x00, 0x01]},
{HashType.CRC16_DECTX, [0x00, 0x00]},
{HashType.CRC16_DNP, [0xff, 0xff]},
{HashType.CRC16_EN13757, [0xff, 0xff]},
{HashType.CRC16_GENIBUS, [0x00, 0x00]},
{HashType.CRC16_GSM, [0xff, 0xff]},
{HashType.CRC16_IBM3740, [0xff, 0xff]},
{HashType.CRC16_IBMSDLC, [0x00, 0x00]},
{HashType.CRC16_ISOIEC144433A, [0x63, 0x63]},
{HashType.CRC16_KERMIT, [0x00, 0x00]},
{HashType.CRC16_LJ1200, [0x00, 0x00]},
{HashType.CRC16_M17, [0xff, 0xff]},
{HashType.CRC16_MAXIMDOW, [0xff, 0xff]},
{HashType.CRC16_MCRF4XX, [0xff, 0xff]},
{HashType.CRC16_MODBUS, [0xff, 0xff]},
{HashType.CRC16_NRSC5, [0xff, 0xff]},
{HashType.CRC16_OPENSAFETYA, [0x00, 0x00]},
{HashType.CRC16_OPENSAFETYB, [0x00, 0x00]},
{HashType.CRC16_PROFIBUS, [0x00, 0x00]},
{HashType.CRC16_RIELLO, [0x55, 0x4d]},
{HashType.CRC16_SPIFUJITSU, [0x1d, 0x0f]},
{HashType.CRC16_T10DIF, [0x00, 0x00]},
{HashType.CRC16_TELEDISK, [0x00, 0x00]},
{HashType.CRC16_TMS37157, [0x37, 0x91]},
{HashType.CRC16_UMTS, [0x00, 0x00]},
{HashType.CRC16_USB, [0x00, 0x00]},
{HashType.CRC16_XMODEM, [0x00, 0x00]},
{HashType.CRC17_CANFD, [0x00, 0x00, 0x00]},
{HashType.CRC21_CANFD, [0x00, 0x00, 0x00]},
{HashType.CRC24_BLE, [0xaa, 0xaa, 0xaa]},
{HashType.CRC24_FLEXRAYA, [0xfe, 0xdc, 0xba]},
{HashType.CRC24_FLEXRAYB, [0xab, 0xcd, 0xef]},
{HashType.CRC24_INTERLAKEN, [0x00, 0x00, 0x00]},
{HashType.CRC24_LTEA, [0x00, 0x00, 0x00]},
{HashType.CRC24_LTEB, [0x00, 0x00, 0x00]},
{HashType.CRC24_OPENPGP, [0xb7, 0x04, 0xce]},
{HashType.CRC24_OS9, [0x00, 0x00, 0x00]},
{HashType.CRC30_CDMA, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC31_PHILIPS, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_AIXM, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_AUTOSAR, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_BASE91D, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_BZIP2, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_CDROMEDC, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_CKSUM, [0xff, 0xff, 0xff, 0xff]},
{HashType.CRC32_ISCSI, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_ISOHDLC, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC32_JAMCRC, [0xff, 0xff, 0xff, 0xff]},
{HashType.CRC32_MEF, [0xff, 0xff, 0xff, 0xff]},
{HashType.CRC32_MPEG2, [0xff, 0xff, 0xff, 0xff]},
{HashType.CRC32_XFER, [0x00, 0x00, 0x00, 0x00]},
{HashType.CRC40_GSM, [0xff, 0xff, 0xff, 0xff, 0xff]},
{HashType.CRC64, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_ECMA182, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_GOISO, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_MS, [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]},
{HashType.CRC64_NVME, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_REDIS, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_WE, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.CRC64_XZ, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.Fletcher16, [0x00, 0x00]},
{HashType.Fletcher32, [0x00, 0x00, 0x00, 0x00]},
{HashType.Fletcher64, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.FNV0_32, [0x00, 0x00, 0x00, 0x00]},
{HashType.FNV0_64, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]},
{HashType.FNV1_32, [0x81, 0x1c, 0x9d, 0xc5]},
{HashType.FNV1_64, [0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25]},
{HashType.FNV1a_32, [0x81, 0x1c, 0x9d, 0xc5]},
{HashType.FNV1a_64, [0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25]},
{HashType.MD2, [0x83, 0x50, 0xe5, 0xa3, 0xe2, 0x4c, 0x15, 0x3d,
0xf2, 0x27, 0x5c, 0x9f, 0x80, 0x69, 0x27, 0x73]},
{HashType.MD4, [0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0]},
{HashType.MD5, [0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e]},
{HashType.RIPEMD128, [0xcd, 0xf2, 0x62, 0x13, 0xa1, 0x50, 0xdc, 0x3e,
0xcb, 0x61, 0x0f, 0x18, 0xf6, 0xb3, 0x8b, 0x46]},
{HashType.RIPEMD160, [0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54,
0x61, 0x28, 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48,
0xb2, 0x25, 0x8d, 0x31]},
{HashType.RIPEMD256, [0x02, 0xba, 0x4c, 0x4e, 0x5f, 0x8e, 0xcd, 0x18,
0x77, 0xfc, 0x52, 0xd6, 0x4d, 0x30, 0xe3, 0x7a,
0x2d, 0x97, 0x74, 0xfb, 0x1e, 0x5d, 0x02, 0x63,
0x80, 0xae, 0x01, 0x68, 0xe3, 0xc5, 0x52, 0x2d]},
{HashType.RIPEMD320, [0x22, 0xd6, 0x5d, 0x56, 0x61, 0x53, 0x6c, 0xdc,
0x75, 0xc1, 0xfd, 0xf5, 0xc6, 0xde, 0x7b, 0x41,
0xb9, 0xf2, 0x73, 0x25, 0xeb, 0xc6, 0x1e, 0x85,
0x57, 0x17, 0x7d, 0x70, 0x5a, 0x0e, 0xc8, 0x80,
0x15, 0x1c, 0x3a, 0x32, 0xa0, 0x08, 0x99, 0xb8]},
{HashType.SHA1, [0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
0xaf, 0xd8, 0x07, 0x09]},
{HashType.SHA256, [0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55]},
{HashType.SHA384, [0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38,
0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a,
0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43,
0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda,
0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb,
0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b]},
{HashType.SHA512, [0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e]},
#if NET8_0_OR_GREATER
{HashType.SHA3_256, [0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66,
0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62,
0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa,
0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a]},
{HashType.SHA3_384, [0x0c, 0x63, 0xa7, 0x5b, 0x84, 0x5e, 0x4f, 0x7d,
0x01, 0x10, 0x7d, 0x85, 0x2e, 0x4c, 0x24, 0x85,
0xc5, 0x1a, 0x50, 0xaa, 0xaa, 0x94, 0xfc, 0x61,
0x99, 0x5e, 0x71, 0xbb, 0xee, 0x98, 0x3a, 0x2a,
0xc3, 0x71, 0x38, 0x31, 0x26, 0x4a, 0xdb, 0x47,
0xfb, 0x6b, 0xd1, 0xe0, 0x58, 0xd5, 0xf0, 0x04]},
{HashType.SHA3_512, [0xa6, 0x9f, 0x73, 0xcc, 0xa2, 0x3a, 0x9a, 0xc5,
0xc8, 0xb5, 0x67, 0xdc, 0x18, 0x5a, 0x75, 0x6e,
0x97, 0xc9, 0x82, 0x16, 0x4f, 0xe2, 0x58, 0x59,
0xe0, 0xd1, 0xdc, 0xc1, 0x47, 0x5c, 0x80, 0xa6,
0x15, 0xb2, 0x12, 0x3a, 0xf1, 0xf5, 0xf9, 0x4c,
0x11, 0xe3, 0xe9, 0x40, 0x2c, 0x3a, 0xc5, 0x58,
0xf5, 0x00, 0x19, 0x9d, 0x95, 0xb6, 0xd3, 0xe3,
0x01, 0x75, 0x85, 0x86, 0x28, 0x1d, 0xcd, 0x26]},
{HashType.SHAKE128, [0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d,
0x61, 0x60, 0x45, 0x50, 0x76, 0x05, 0x85, 0x3e,
0xd7, 0x3b, 0x80, 0x93, 0xf6, 0xef, 0xbc, 0x88,
0xeb, 0x1a, 0x6e, 0xac, 0xfa, 0x66, 0xef, 0x26]},
{HashType.SHAKE256, [0x46, 0xb9, 0xdd, 0x2b, 0x0b, 0xa8, 0x8d, 0x13,
0x23, 0x3b, 0x3f, 0xeb, 0x74, 0x3e, 0xeb, 0x24,
0x3f, 0xcd, 0x52, 0xea, 0x62, 0xb8, 0x1b, 0x82,
0xb5, 0x0c, 0x27, 0x64, 0x6e, 0xd5, 0x76, 0x2f,
0xd7, 0x5d, 0xc4, 0xdd, 0xd8, 0xc0, 0xf2, 0x00,
0xcb, 0x05, 0x01, 0x9d, 0x67, 0xb5, 0x92, 0xf6,
0xfc, 0x82, 0x1c, 0x49, 0x47, 0x9a, 0xb4, 0x86,
0x40, 0x29, 0x2e, 0xac, 0xb3, 0xb7, 0xc4, 0xbe]},
#endif
{HashType.SpamSum, [0x33, 0x3a, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00]},
{HashType.Tiger128_3, [0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24,
0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16]},
{HashType.Tiger128_4, [0x24, 0xcc, 0x78, 0xa7, 0xf6, 0xff, 0x35, 0x46,
0xe7, 0x98, 0x4e, 0x59, 0x69, 0x5c, 0xa1, 0x3d]},
{HashType.Tiger160_3, [0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24,
0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16,
0x7a, 0x4e, 0x58, 0x49]},
{HashType.Tiger160_4, [0x24, 0xcc, 0x78, 0xa7, 0xf6, 0xff, 0x35, 0x46,
0xe7, 0x98, 0x4e, 0x59, 0x69, 0x5c, 0xa1, 0x3d,
0x80, 0x4e, 0x0b, 0x68]},
{HashType.Tiger192_3, [0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24,
0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16,
0x7a, 0x4e, 0x58, 0x49, 0x2d, 0xde, 0x73, 0xf3]},
{HashType.Tiger192_4, [0x24, 0xcc, 0x78, 0xa7, 0xf6, 0xff, 0x35, 0x46,
0xe7, 0x98, 0x4e, 0x59, 0x69, 0x5c, 0xa1, 0x3d,
0x80, 0x4e, 0x0b, 0x68, 0x6e, 0x25, 0x51, 0x94]},
{HashType.Tiger2_128_3, [0x44, 0x41, 0xbe, 0x75, 0xf6, 0x01, 0x87, 0x73,
0xc2, 0x06, 0xc2, 0x27, 0x45, 0x37, 0x4b, 0x92]},
{HashType.Tiger2_128_4, [0x6a, 0x72, 0x01, 0xa4, 0x7a, 0xac, 0x20, 0x65,
0x91, 0x38, 0x11, 0x17, 0x55, 0x53, 0x48, 0x9a]},
{HashType.Tiger2_160_3, [0x44, 0x41, 0xbe, 0x75, 0xf6, 0x01, 0x87, 0x73,
0xc2, 0x06, 0xc2, 0x27, 0x45, 0x37, 0x4b, 0x92,
0x4a, 0xa8, 0x31, 0x3f]},
{HashType.Tiger2_160_4, [0x6a, 0x72, 0x01, 0xa4, 0x7a, 0xac, 0x20, 0x65,
0x91, 0x38, 0x11, 0x17, 0x55, 0x53, 0x48, 0x9a,
0xdd, 0x0f, 0x8b, 0x99]},
{HashType.Tiger2_192_3, [0x44, 0x41, 0xbe, 0x75, 0xf6, 0x01, 0x87, 0x73,
0xc2, 0x06, 0xc2, 0x27, 0x45, 0x37, 0x4b, 0x92,
0x4a, 0xa8, 0x31, 0x3f, 0xef, 0x91, 0x9f, 0x41]},
{HashType.Tiger2_192_4, [0x6a, 0x72, 0x01, 0xa4, 0x7a, 0xac, 0x20, 0x65,
0x91, 0x38, 0x11, 0x17, 0x55, 0x53, 0x48, 0x9a,
0xdd, 0x0f, 0x8b, 0x99, 0xe6, 0x5a, 0x09, 0x55]},
{HashType.XxHash32, [0x02, 0xcc, 0x5d, 0x05]},
{HashType.XxHash64, [0xef, 0x46, 0xdb, 0x37, 0x51, 0xd8, 0xe9, 0x99]},
#if NET462_OR_GREATER || NETCOREAPP
{HashType.XxHash3, [0x2d, 0x06, 0x80, 0x05, 0x38, 0xd3, 0x94, 0xc2]},
{HashType.XxHash128, [0x99, 0xaa, 0x06, 0xd3, 0x01, 0x47, 0x98, 0xd8,
0x60, 0x01, 0xc3, 0x24, 0x46, 0x8d, 0x49, 0x7f]},
#endif
};
/// <summary>
/// Set of all known 0-byte outputs as strings
/// </summary>
private static readonly Dictionary<HashType, string> _strings = new()
{
{HashType.Adler32, "00000001"},
#if NET7_0_OR_GREATER
{HashType.BLAKE3, "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"},
#endif
{HashType.CRC1_ZERO, "0"},
{HashType.CRC1_ONE, "1"},
{HashType.CRC3_GSM, "7"},
{HashType.CRC3_ROHC, "7"},
{HashType.CRC4_G704, "0"},
{HashType.CRC4_INTERLAKEN, "0"},
{HashType.CRC5_EPCC1G2, "09"},
{HashType.CRC5_G704, "00"},
{HashType.CRC5_USB, "00"},
{HashType.CRC6_CDMA2000A, "3f"},
{HashType.CRC6_CDMA2000B, "3f"},
{HashType.CRC6_DARC, "00"},
{HashType.CRC6_G704, "00"},
{HashType.CRC6_GSM, "3f"},
{HashType.CRC7_MMC, "00"},
{HashType.CRC7_ROHC, "7f"},
{HashType.CRC7_UMTS, "00"},
{HashType.CRC8, "00"},
{HashType.CRC8_AUTOSAR, "00"},
{HashType.CRC8_BLUETOOTH, "00"},
{HashType.CRC8_CDMA2000, "ff"},
{HashType.CRC8_DARC, "00"},
{HashType.CRC8_DVBS2, "00"},
{HashType.CRC8_GSMA, "00"},
{HashType.CRC8_GSMB, "ff"},
{HashType.CRC8_HITAG, "ff"},
{HashType.CRC8_I4321, "55"},
{HashType.CRC8_ICODE, "fd"},
{HashType.CRC8_LTE, "00"},
{HashType.CRC8_MAXIMDOW, "00"},
{HashType.CRC8_MIFAREMAD, "c7"},
{HashType.CRC8_NRSC5, "ff"},
{HashType.CRC8_OPENSAFETY, "00"},
{HashType.CRC8_ROHC, "ff"},
{HashType.CRC8_SAEJ1850, "00"},
{HashType.CRC8_SMBUS, "00"},
{HashType.CRC8_TECH3250, "ff"},
{HashType.CRC8_WCDMA, "00"},
{HashType.CRC10_ATM, "000"},
{HashType.CRC10_CDMA2000, "3ff"},
{HashType.CRC10_GSM, "3ff"},
{HashType.CRC11_FLEXRAY, "01a"},
{HashType.CRC11_UMTS, "000"},
{HashType.CRC12_CDMA2000, "fff"},
{HashType.CRC12_DECT, "000"},
{HashType.CRC12_GSM, "fff"},
{HashType.CRC12_UMTS, "000"},
{HashType.CRC13_BBC, "0000"},
{HashType.CRC14_DARC, "0000"},
{HashType.CRC14_GSM, "3fff"},
{HashType.CRC15_CAN, "0000"},
{HashType.CRC15_MPT1327, "0001"},
{HashType.CRC16, "0000"},
{HashType.CRC16_ARC, "0000"},
{HashType.CRC16_CDMA2000, "ffff"},
{HashType.CRC16_CMS, "ffff"},
{HashType.CRC16_DDS110, "800d"},
{HashType.CRC16_DECTR, "0001"},
{HashType.CRC16_DECTX, "0000"},
{HashType.CRC16_DNP, "ffff"},
{HashType.CRC16_EN13757, "ffff"},
{HashType.CRC16_GENIBUS, "0000"},
{HashType.CRC16_GSM, "ffff"},
{HashType.CRC16_IBM3740, "ffff"},
{HashType.CRC16_IBMSDLC, "0000"},
{HashType.CRC16_ISOIEC144433A, "6363"},
{HashType.CRC16_KERMIT, "0000"},
{HashType.CRC16_LJ1200, "0000"},
{HashType.CRC16_M17, "ffff"},
{HashType.CRC16_MAXIMDOW, "ffff"},
{HashType.CRC16_MCRF4XX, "ffff"},
{HashType.CRC16_MODBUS, "ffff"},
{HashType.CRC16_NRSC5, "ffff"},
{HashType.CRC16_OPENSAFETYA, "0000"},
{HashType.CRC16_OPENSAFETYB, "0000"},
{HashType.CRC16_PROFIBUS, "0000"},
{HashType.CRC16_RIELLO, "554d"},
{HashType.CRC16_SPIFUJITSU, "1d0f"},
{HashType.CRC16_T10DIF, "0000"},
{HashType.CRC16_TELEDISK, "0000"},
{HashType.CRC16_TMS37157, "3791"},
{HashType.CRC16_UMTS, "0000"},
{HashType.CRC16_USB, "0000"},
{HashType.CRC16_XMODEM, "0000"},
{HashType.CRC17_CANFD, "00000"},
{HashType.CRC21_CANFD, "000000"},
{HashType.CRC24_BLE, "aaaaaa"},
{HashType.CRC24_FLEXRAYA, "fedcba"},
{HashType.CRC24_FLEXRAYB, "abcdef"},
{HashType.CRC24_INTERLAKEN, "000000"},
{HashType.CRC24_LTEA, "000000"},
{HashType.CRC24_LTEB, "000000"},
{HashType.CRC24_OPENPGP, "b704ce"},
{HashType.CRC24_OS9, "000000"},
{HashType.CRC30_CDMA, "00000000"},
{HashType.CRC31_PHILIPS, "00000000"},
{HashType.CRC32, "00000000"},
{HashType.CRC32_AIXM, "00000000"},
{HashType.CRC32_AUTOSAR, "00000000"},
{HashType.CRC32_BASE91D, "00000000"},
{HashType.CRC32_BZIP2, "00000000"},
{HashType.CRC32_CDROMEDC, "00000000"},
{HashType.CRC32_CKSUM, "ffffffff"},
{HashType.CRC32_ISCSI, "00000000"},
{HashType.CRC32_ISOHDLC, "00000000"},
{HashType.CRC32_JAMCRC, "ffffffff"},
{HashType.CRC32_MEF, "ffffffff"},
{HashType.CRC32_MPEG2, "ffffffff"},
{HashType.CRC32_XFER, "00000000"},
{HashType.CRC40_GSM, "ffffffffff"},
{HashType.CRC64, "0000000000000000"},
{HashType.CRC64_ECMA182, "0000000000000000"},
{HashType.CRC64_GOISO, "0000000000000000"},
{HashType.CRC64_MS, "ffffffffffffffff"},
{HashType.CRC64_NVME, "0000000000000000"},
{HashType.CRC64_REDIS, "0000000000000000"},
{HashType.CRC64_WE, "0000000000000000"},
{HashType.CRC64_XZ, "0000000000000000"},
{HashType.Fletcher16, "0000"},
{HashType.Fletcher32, "00000000"},
{HashType.Fletcher64, "0000000000000000"},
{HashType.FNV0_32, "00000000"},
{HashType.FNV0_64, "0000000000000000"},
{HashType.FNV1_32, "811c9dc5"},
{HashType.FNV1_64, "cbf29ce484222325"},
{HashType.FNV1a_32, "811c9dc5"},
{HashType.FNV1a_64, "cbf29ce484222325"},
{HashType.MD2, "8350e5a3e24c153df2275c9f80692773"},
{HashType.MD4, "31d6cfe0d16ae931b73c59d7e0c089c0"},
{HashType.MD5, "d41d8cd98f00b204e9800998ecf8427e"},
{HashType.RIPEMD128, "cdf26213a150dc3ecb610f18f6b38b46"},
{HashType.RIPEMD160, "9c1185a5c5e9fc54612808977ee8f548b2258d31"},
{HashType.RIPEMD256, "02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d"},
{HashType.RIPEMD320, "22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8"},
{HashType.SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
{HashType.SHA256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
{HashType.SHA384, "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"},
{HashType.SHA512, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"},
#if NET8_0_OR_GREATER
{HashType.SHA3_256, "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"},
{HashType.SHA3_384, "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"},
{HashType.SHA3_512, "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"},
{HashType.SHAKE128, "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26"},
{HashType.SHAKE256, "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be"},
#endif
{HashType.SpamSum, "3::"},
{HashType.Tiger128_3, "3293ac630c13f0245f92bbb1766e1616"},
{HashType.Tiger128_4, "24cc78a7f6ff3546e7984e59695ca13d"},
{HashType.Tiger160_3, "3293ac630c13f0245f92bbb1766e16167a4e5849"},
{HashType.Tiger160_4, "24cc78a7f6ff3546e7984e59695ca13d804e0b68"},
{HashType.Tiger192_3, "3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3"},
{HashType.Tiger192_4, "24cc78a7f6ff3546e7984e59695ca13d804e0b686e255194"},
{HashType.Tiger2_128_3, "4441be75f6018773c206c22745374b92"},
{HashType.Tiger2_128_4, "6a7201a47aac2065913811175553489a"},
{HashType.Tiger2_160_3, "4441be75f6018773c206c22745374b924aa8313f"},
{HashType.Tiger2_160_4, "6a7201a47aac2065913811175553489add0f8b99"},
{HashType.Tiger2_192_3, "4441be75f6018773c206c22745374b924aa8313fef919f41"},
{HashType.Tiger2_192_4, "6a7201a47aac2065913811175553489add0f8b99e65a0955"},
{HashType.XxHash32, "02cc5d05"},
{HashType.XxHash64, "ef46db3751d8e999"},
#if NET462_OR_GREATER || NETCOREAPP
{HashType.XxHash3, "2d06800538d394c2"},
{HashType.XxHash128, "99aa06d3014798d86001c324468d497f"},
#endif
};
/// <summary>
/// Get the 0-byte value for <paramref name="hashType"/> as a byte array
/// </summary>
/// <param name="hashType">Hash type to get the value for</param>
/// <returns>Non-empty array containing the value on success, empty array on failure</returns>
public static byte[] GetBytes(HashType hashType)
{
if (!_strings.ContainsKey(hashType))
return [];
return _bytes[hashType];
}
/// <summary>
/// Get the 0-byte value for <paramref name="hashType"/> as a string
/// </summary>
/// <param name="hashType">Hash type to get the value for</param>
/// <returns>Non-empty string containing the value on success, empty string on failure</returns>
public static string GetString(HashType hashType)
{
if (!_strings.ContainsKey(hashType))
return string.Empty;
return _strings[hashType];
}
}
}