88 Commits
1.1.2 ... 1.2.3

Author SHA1 Message Date
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
Matt Nadareski
7eeb11261b Bump version 2024-10-24 17:22:24 -04:00
Matt Nadareski
a0fc83b617 Add publish scripts 2024-10-24 17:21:55 -04:00
Matt Nadareski
fbc81459ee Reduce framework-dependent code 2024-10-24 17:17:39 -04:00
Matt Nadareski
7d53e07e90 Simplify internal hashing method
This may fix a bug with some compressed streams that, if no bytes were read, may cause odd issues when passed to the hashers, leading to inconsistent values.
2024-10-24 16:45:02 -04:00
Matt Nadareski
e83c31b89c Increase to 50 files in zip 2024-07-19 11:03:27 -04:00
Matt Nadareski
ca08f97336 Increase to 20 files in zip 2024-07-19 10:59:36 -04:00
Matt Nadareski
bd1e23dad4 Add gzip stream test, just in case 2024-07-19 10:54:54 -04:00
Matt Nadareski
b22f3d2743 Better documentation in tests 2024-07-19 10:50:46 -04:00
Matt Nadareski
23ed4e9849 Ensure multiple files hash correctly from archives 2024-07-19 10:47:42 -04:00
Matt Nadareski
4bc26b824f Bump version 2024-07-16 00:05:33 -04:00
Matt Nadareski
d5b0b2ad02 Don't rely on stream size; read until nothing left 2024-07-16 00:02:49 -04:00
Matt Nadareski
3fa3ece655 All unsafe setting of length in hashing 2024-07-15 23:38:12 -04:00
Matt Nadareski
87fb62d772 Start adding Tiger hash (nw) 2024-06-25 13:54:07 -04:00
Matt Nadareski
ce9887ef19 Bump version 2024-03-25 14:21:26 -04:00
Matt Nadareski
dcd4555027 Link to documentation around SHA3 family hashes 2024-03-24 20:15:32 -04:00
Matt Nadareski
b11ded8756 Fix errant build issue 2024-03-24 20:09:05 -04:00
Matt Nadareski
28b33b67f8 Enable SHAKE128 and SHAKE256 processing 2024-03-24 20:07:03 -04:00
Matt Nadareski
cb7c84293d Fix copy-paste issue in tests 2024-03-24 19:59:06 -04:00
Matt Nadareski
83c6346114 Disable verbose test output 2024-03-24 19:57:16 -04:00
Matt Nadareski
eef5fdc29b Use verbose output for tests temporarily 2024-03-24 19:50:52 -04:00
Matt Nadareski
84d319867c Add SHA3 implementations for supported platforms 2024-03-24 19:45:27 -04:00
Matt Nadareski
83c69f895c Add SHAKE128 and SHAKE256 for supported platforms 2024-03-24 19:38:48 -04:00
Matt Nadareski
826d629d98 Update README for CRC-32 changes 2024-03-24 18:46:44 -04:00
Matt Nadareski
6e8f13089e Update README for CRC-64 changes 2024-03-24 18:45:34 -04:00
Matt Nadareski
632b11ef2b Correctly label CRC64 implementations, extend to old .NET 2024-03-24 18:35:04 -04:00
Matt Nadareski
c8f7497bf3 Suppress Nuget warning as error 2024-03-24 02:34:17 -04:00
Matt Nadareski
7dc19b8127 Add CRC-32 implementation from Aaru.Checksums 2024-03-24 02:30:10 -04:00
Matt Nadareski
a3bca2abb4 Add CRC64 from Aaru.Checksums 2024-03-24 02:22:28 -04:00
Matt Nadareski
c19509944b Add CRC-16 variants from Aaru.Checksums 2024-03-24 02:09:32 -04:00
Matt Nadareski
076686bc04 Version gate some constants for consistency 2024-03-24 01:59:52 -04:00
Matt Nadareski
1aea60880a Add Adler-32, Fletcher-16, and Fletcher-32 from Aaru.Checksums 2024-03-24 01:58:23 -04:00
Matt Nadareski
9e5cadd8d2 Add BLAKE3 for net7.0 and above 2024-03-24 00:15:56 -04:00
Matt Nadareski
11c03d8a08 Update summaries in HashType 2024-03-08 12:50:25 -05:00
Matt Nadareski
ff113dfcad Hook up all 3 implementations for choice 2024-03-08 12:48:30 -05:00
Matt Nadareski
fe9fe268c9 Add other CRC32 implementations (unused) 2024-03-08 12:41:22 -05:00
Matt Nadareski
71a45e5cd9 Update README 2024-03-08 10:26:00 -05:00
Matt Nadareski
f0c42d3707 Add optimized CRC for newer .NET versions 2024-03-08 10:22:35 -05:00
Matt Nadareski
3c31839ee2 Remove some needless version gating 2024-03-08 09:36:18 -05:00
Matt Nadareski
3ddc4397de Remove net452 from tests for GHA 2024-03-08 09:34:00 -05:00
Matt Nadareski
bf0cc50ded Update README 2024-03-08 09:26:48 -05:00
Matt Nadareski
99d4b5d62f Add RIPEMD160 for .NET Framework 2024-03-08 09:20:28 -05:00
Matt Nadareski
45adf3a8cd Bump version 2024-03-06 10:55:44 -05:00
Matt Nadareski
b5fc196018 Fix OptimizedCRC, extend tests 2024-03-06 01:33:00 -05:00
Matt Nadareski
fac3a5ab43 Add constants from SabreTools 2024-03-05 14:47:16 -05:00
Matt Nadareski
8face3e4ed Bump version 2024-03-05 13:09:38 -05:00
Matt Nadareski
047463f726 Add byte array variants (fixes #1) 2024-03-05 13:05:42 -05:00
Matt Nadareski
7ab41ce096 Add leave open parameter for stream hashing (fixes #2) 2024-03-05 12:58:06 -05:00
35 changed files with 5664 additions and 488 deletions

View File

@@ -4,10 +4,9 @@ This library comprises of methods and helpers to simplify the process of getting
| Source | Hash / Checksum Types | Notes |
| --- | --- | --- |
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | SpamSum | Some code tweaks made to support older .NET versions |
| [Compress](https://github.com/RomVault/RVWorld/tree/master/Compress) | N/A | Used for threaded hashing |
| [CRC32 / OptimizedCRC](https://gitlab.com/eugene77/CRC32) | CRC-32 | Used in `net20`, `net35`, `net40`, and `net452` |
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | CRC-32, CRC-64, xxHash32, xxHash64, 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 | Built-in library |
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | Adler-32, Fletcher-16, Fletcher-32, 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 |
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | 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) |
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).

View File

@@ -0,0 +1,58 @@
using System;
using System.IO;
using System.IO.Compression;
using Xunit;
namespace SabreTools.Hashing.Test
{
public class CompressedStreamTests
{
/// <summary>
/// Path to PKZIP archive containing a single compressed file to hash
/// </summary>
private static readonly string _singleGzipFilePath
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin.gz");
/// <summary>
/// Path to PKZIP archive containing a single compressed file to hash
/// </summary>
private static readonly string _singleZipFilePath
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.zip");
/// <summary>
/// Path to PKZIP archive containing a multiple compressed files to hash
/// </summary>
private static readonly string _multiZipFilePath
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash-multi.zip");
[Fact]
public void GetSingleGzipStreamHashesTest()
{
var gzipStream = new GZipStream(File.OpenRead(_singleGzipFilePath), CompressionMode.Decompress);
var hashDict = HashTool.GetStreamHashes(gzipStream);
TestHelper.ValidateHashes(hashDict);
}
[Fact]
public void GetSingleDeflateStreamHashesTest()
{
var zipFile = ZipFile.OpenRead(_singleZipFilePath);
var fileStream = zipFile.Entries[0].Open();
var hashDict = HashTool.GetStreamHashes(fileStream);
TestHelper.ValidateHashes(hashDict);
}
[Fact]
public void GetMultiDeflateStreamHashesTest()
{
var zipFile = ZipFile.OpenRead(_multiZipFilePath);
for (int i = 0; i < zipFile.Entries.Count; i++)
{
var fileStream = zipFile.Entries[i].Open();
var hashDict = HashTool.GetStreamHashes(fileStream);
TestHelper.ValidateHashes(hashDict);
}
}
}
}

View File

@@ -6,23 +6,18 @@ namespace SabreTools.Hashing.Test
{
public class HashToolTests
{
private static readonly string _hashFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin");
/// <summary>
/// Path to the uncompressed file to hash
/// </summary>
private static readonly string _hashFilePath
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin");
#region Known File Information
private const long _hashFileSize = 125;
private const string _crc32 = "ba02a660";
private const string _crc64 = "a0e0009c18b5338d";
private const string _md5 = "b722871eaa950016296184d026c5dec9";
private const string _sha1 = "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f";
private const string _sha256 = "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855";
private const string _sha384 = "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074";
private const string _sha512 = "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240";
private const string _spamsum = "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL";
private const string _xxhash32 = "8e331daa";
private const string _xxhash64 = "082bf6f0a49e1e18";
private const string _xxhash3 = "040474eb0eda9ff2";
private const string _xxhash128 = "d934b4b4a5e1e11baeef8012fbcd11e8";
#endregion
@@ -42,63 +37,23 @@ namespace SabreTools.Hashing.Test
public void GetFileHashesTest()
{
var hashDict = HashTool.GetFileHashes(_hashFilePath);
Assert.NotNull(hashDict);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
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]);
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
TestHelper.ValidateHashes(hashDict);
}
[Fact]
public void GetFileHashesAndSizeTest()
{
var hashDict = HashTool.GetFileHashesAndSize(_hashFilePath, out long actualSize);
Assert.Equal(_hashFileSize, actualSize);
Assert.NotNull(hashDict);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
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]);
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
TestHelper.ValidateHashes(hashDict);
}
[Fact]
public void GetByteArrayHashesTest()
{
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
var hashDict = HashTool.GetByteArrayHashes(fileBytes);
Assert.NotNull(hashDict);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
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]);
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
TestHelper.ValidateHashes(hashDict);
}
[Fact]
@@ -106,20 +61,7 @@ namespace SabreTools.Hashing.Test
{
var fileStream = File.OpenRead(_hashFilePath);
var hashDict = HashTool.GetStreamHashes(fileStream);
Assert.NotNull(hashDict);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
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]);
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
TestHelper.ValidateHashes(hashDict);
}
}
}

View File

@@ -1,36 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</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>
<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" />
<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>
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
</ItemGroup>
</Project>
</Project>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,223 @@
using System.Collections.Generic;
using Xunit;
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";
#if NET7_0_OR_GREATER
private const string _blake3 = "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc";
#endif
private const string _crc16 = "7573";
private const string _crc16_arc = "7573";
private const string _crc16_cdma2000 = "8b5f";
private const string _crc16_cms = "1a37";
private const string _crc16_dds110 = "241d";
private const string _crc16_dectr = "7390";
private const string _crc16_dectx = "7391";
private const string _crc16_dnp = "4bbb";
private const string _crc16_en13757 = "e28b";
private const string _crc16_genibus = "b65d";
private const string _crc16_gsm = "482d";
private const string _crc16_ibm3740 = "49a2";
private const string _crc16_ibmsdlc = "4f52";
private const string _crc16_isoiec144433a = "85cd";
private const string _crc16_kermit = "bed2";
private const string _crc16_lj1200 = "3533";
private const string _crc16_m17 = "5223";
private const string _crc16_maximdow = "8a8c";
private const string _crc16_mcrf4xx = "b0ad";
private const string _crc16_modbus = "9e54";
private const string _crc16_nrsc5 = "4857";
private const string _crc16_opensafetya = "abcd";
private const string _crc16_opensafetyb = "76f4";
private const string _crc16_profibus = "3099";
private const string _crc16_riello = "23e0";
private const string _crc16_spifujitsu = "f98b";
private const string _crc16_t10dif = "2642";
private const string _crc16_teledisk = "7e05";
private const string _crc16_tms37157 = "dba0";
private const string _crc16_umts = "fee0";
private const string _crc16_usb = "61ab";
private const string _crc16_xmodem = "b7d2";
private const string _crc24_ble = "2969f2";
private const string _crc24_flexraya = "ce9dc7";
private const string _crc24_flexrayb = "0f49d7";
private const string _crc24_interlaken = "fb4725";
private const string _crc24_ltea = "675e55";
private const string _crc24_lteb = "c91203";
private const string _crc24_openpgp = "0c6012";
private const string _crc24_os9 = "610e21";
private const string _crc32 = "ba02a660";
private const string _crc32_aixm = "6174a75a";
private const string _crc32_autosar = "c050428e";
private const string _crc32_base91d = "e741ba25";
private const string _crc32_bzip2 = "18aa4603";
private const string _crc32_cdromedc = "b8ced467";
private const string _crc32_cksum = "f27b3c27";
private const string _crc32_iscsi = "544d37db";
private const string _crc32_isohdlc = "ba02a660";
private const string _crc32_jamcrc = "45fd599f";
private const string _crc32_mef = "d9d98444";
private const string _crc32_mpeg2 = "e755b9fc";
private const string _crc32_xfer = "55bdf222";
private const string _crc40_gsm = "c9843306eb";
private const string _crc64 = "8d33b5189c00e0a0";
private const string _crc64_ecma182 = "8d33b5189c00e0a0";
private const string _crc64_goiso = "6c3bf747ccfa1e3b";
private const string _crc64_ms = "799edc0db430d7be";
private const string _crc64_nvme = "9242023bbcf6bbf9";
private const string _crc64_redis = "408dab12b9f45dad";
private const string _crc64_we = "91812be748f941c4";
private const string _crc64_xz = "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";
#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";
#endif
private const string _spamsum = "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL";
#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";
#endif
#endregion
/// <summary>
/// Validate the hashes in a hash dictionary
/// </summary>
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, hashDict[HashType.CRC16]);
Assert.Equal(_crc16_arc, hashDict[HashType.CRC16_ARC]);
Assert.Equal(_crc16_cdma2000, hashDict[HashType.CRC16_CDMA2000]);
Assert.Equal(_crc16_cms, hashDict[HashType.CRC16_CMS]);
Assert.Equal(_crc16_dds110, hashDict[HashType.CRC16_DDS110]);
Assert.Equal(_crc16_dectr, hashDict[HashType.CRC16_DECTR]);
Assert.Equal(_crc16_dectx, hashDict[HashType.CRC16_DECTX]);
Assert.Equal(_crc16_dnp, hashDict[HashType.CRC16_DNP]);
Assert.Equal(_crc16_en13757, hashDict[HashType.CRC16_EN13757]);
Assert.Equal(_crc16_genibus, hashDict[HashType.CRC16_GENIBUS]);
Assert.Equal(_crc16_gsm, hashDict[HashType.CRC16_GSM]);
Assert.Equal(_crc16_ibm3740, hashDict[HashType.CRC16_IBM3740]);
Assert.Equal(_crc16_ibmsdlc, hashDict[HashType.CRC16_IBMSDLC]);
//Assert.Equal(_crc16_isoiec144433a, hashDict[HashType.CRC16_ISOIEC144433A]);
Assert.Equal(_crc16_kermit, hashDict[HashType.CRC16_KERMIT]);
Assert.Equal(_crc16_lj1200, hashDict[HashType.CRC16_LJ1200]);
Assert.Equal(_crc16_m17, hashDict[HashType.CRC16_M17]);
Assert.Equal(_crc16_maximdow, hashDict[HashType.CRC16_MAXIMDOW]);
Assert.Equal(_crc16_mcrf4xx, hashDict[HashType.CRC16_MCRF4XX]);
Assert.Equal(_crc16_modbus, hashDict[HashType.CRC16_MODBUS]);
Assert.Equal(_crc16_nrsc5, hashDict[HashType.CRC16_NRSC5]);
Assert.Equal(_crc16_opensafetya, hashDict[HashType.CRC16_OPENSAFETYA]);
Assert.Equal(_crc16_opensafetyb, hashDict[HashType.CRC16_OPENSAFETYB]);
Assert.Equal(_crc16_profibus, hashDict[HashType.CRC16_PROFIBUS]);
//Assert.Equal(_crc16_riello, hashDict[HashType.CRC16_RIELLO]);
Assert.Equal(_crc16_spifujitsu, hashDict[HashType.CRC16_SPIFUJITSU]);
Assert.Equal(_crc16_t10dif, hashDict[HashType.CRC16_T10DIF]);
Assert.Equal(_crc16_teledisk, hashDict[HashType.CRC16_TELEDISK]);
//Assert.Equal(_crc16_tms37157, hashDict[HashType.CRC16_TMS37157]);
Assert.Equal(_crc16_umts, hashDict[HashType.CRC16_UMTS]);
Assert.Equal(_crc16_usb, hashDict[HashType.CRC16_USB]);
Assert.Equal(_crc16_xmodem, hashDict[HashType.CRC16_XMODEM]);
//Assert.Equal(_crc24_ble, hashDict[HashType.CRC24_BLE]);
Assert.Equal(_crc24_flexraya, hashDict[HashType.CRC24_FLEXRAYA]);
Assert.Equal(_crc24_flexrayb, hashDict[HashType.CRC24_FLEXRAYB]);
Assert.Equal(_crc24_interlaken, hashDict[HashType.CRC24_INTERLAKEN]);
Assert.Equal(_crc24_ltea, hashDict[HashType.CRC24_LTEA]);
Assert.Equal(_crc24_lteb, hashDict[HashType.CRC24_LTEB]);
Assert.Equal(_crc24_openpgp, hashDict[HashType.CRC24_OPENPGP]);
Assert.Equal(_crc24_os9, hashDict[HashType.CRC24_OS9]);
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
Assert.Equal(_crc32_aixm, hashDict[HashType.CRC32_AIXM]);
Assert.Equal(_crc32_autosar, hashDict[HashType.CRC32_AUTOSAR]);
Assert.Equal(_crc32_base91d, hashDict[HashType.CRC32_BASE91D]);
Assert.Equal(_crc32_bzip2, hashDict[HashType.CRC32_BZIP2]);
Assert.Equal(_crc32_cdromedc, hashDict[HashType.CRC32_CDROMEDC]);
Assert.Equal(_crc32_cksum, hashDict[HashType.CRC32_CKSUM]);
Assert.Equal(_crc32_iscsi, hashDict[HashType.CRC32_ISCSI]);
Assert.Equal(_crc32_isohdlc, hashDict[HashType.CRC32_ISOHDLC]);
Assert.Equal(_crc32_jamcrc, hashDict[HashType.CRC32_JAMCRC]);
Assert.Equal(_crc32_mef, hashDict[HashType.CRC32_MEF]);
Assert.Equal(_crc32_mpeg2, hashDict[HashType.CRC32_MPEG2]);
Assert.Equal(_crc32_xfer, hashDict[HashType.CRC32_XFER]);
Assert.Equal(_crc40_gsm, hashDict[HashType.CRC40_GSM]);
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
Assert.Equal(_crc64_ecma182, hashDict[HashType.CRC64_ECMA182]);
Assert.Equal(_crc64_goiso, hashDict[HashType.CRC64_GOISO]);
Assert.Equal(_crc64_ms, hashDict[HashType.CRC64_MS]);
Assert.Equal(_crc64_nvme, hashDict[HashType.CRC64_NVME]);
Assert.Equal(_crc64_redis, hashDict[HashType.CRC64_REDIS]);
Assert.Equal(_crc64_we, hashDict[HashType.CRC64_WE]);
Assert.Equal(_crc64_xz, hashDict[HashType.CRC64_XZ]);
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
Assert.Equal(_md5, hashDict[HashType.MD5]);
#if NETFRAMEWORK
Assert.Equal(_ripemd160, hashDict[HashType.RIPEMD160]);
#endif
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
}
}
}

View File

@@ -0,0 +1,217 @@
// /***************************************************************************
// 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

@@ -0,0 +1,194 @@
// /***************************************************************************
// 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

@@ -0,0 +1,435 @@
// /***************************************************************************
// 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
using static Aaru.Helpers.Extensions;
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 = EnsureRead(fileStream, buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = EnsureRead(fileStream, 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

@@ -0,0 +1,219 @@
// /***************************************************************************
// 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

@@ -0,0 +1,193 @@
// /***************************************************************************
// 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

@@ -0,0 +1,778 @@
// /***************************************************************************
// 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
using static Aaru.Helpers.Extensions;
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 = EnsureRead(fileStream, buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = EnsureRead(fileStream, 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 = EnsureRead(fileStream, buffer, 0, 65536);
while(read > 0)
{
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = EnsureRead(fileStream, 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

@@ -0,0 +1,83 @@
// /***************************************************************************
// 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

@@ -0,0 +1,331 @@
// /***************************************************************************
// 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;
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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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) => Reverse(BitConverter.GetBytes(value));
/// <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(Reverse(value), 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(Reverse(value), 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(Reverse(value), 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(Reverse(value), 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(Reverse(value));
/// <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(Reverse(value), 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(Reverse(value), 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(Reverse(value), 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(Reverse(value), 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(Reverse(value), 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]);
// Additional helper method to replace single Linq use
private static T[] Reverse<T>(T[] value)
{
Array.Reverse(value);
return value;
}
}
}

View File

@@ -0,0 +1,72 @@
// /***************************************************************************
// 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(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,80 +0,0 @@
using System;
using System.IO;
using System.Threading;
namespace Compress.ThreadReaders
{
internal sealed class ThreadLoadBuffer : IDisposable
{
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
private byte[]? _buffer;
private int _size;
private readonly Stream _ds;
private bool _finished;
public bool errorState;
public int SizeRead;
public ThreadLoadBuffer(Stream ds)
{
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);
_finished = false;
_ds = ds;
errorState = false;
_tWorker = new Thread(MainLoop);
_tWorker.Start();
}
public void Dispose()
{
_waitEvent.Close();
_outEvent.Close();
}
private void MainLoop()
{
while (true)
{
_waitEvent.WaitOne();
if (_finished)
{
break;
}
try
{
if (_buffer != null)
SizeRead = _ds.Read(_buffer, 0, _size);
}
catch (Exception)
{
errorState = true;
}
_outEvent.Set();
}
}
public void Trigger(byte[] buffer, int size)
{
_buffer = buffer;
_size = size;
_waitEvent.Set();
}
public void Wait()
{
_outEvent.WaitOne();
}
public void Finish()
{
_finished = true;
_waitEvent.Set();
_tWorker.Join();
}
}
}

View File

@@ -0,0 +1,76 @@
namespace SabreTools.Hashing
{
public static class Constants
{
#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
#region Hash string length constants
public const int CRCLength = 8;
public const int MD5Length = 32;
public const int SHA1Length = 40;
public const int SHA256Length = 64;
public const int SHA384Length = 96;
public const int SHA512Length = 128;
#endregion
}
}

View File

@@ -0,0 +1,38 @@
namespace SabreTools.Hashing.Crc
{
internal static class BitOperations
{
/// <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;
}
/// <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 @@
namespace SabreTools.Hashing.Crc
{
/// <see href="https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.legend"/>
internal class CrcDefinition
{
/// <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,69 @@
using System;
namespace SabreTools.Hashing.Crc
{
internal class CrcRunner
{
/// <summary>
/// Definition used to create the runner
/// </summary>
private readonly CrcDefinition _definition;
/// <summary>
/// Table used for calculation steps
/// </summary>
private readonly CrcTable _table;
/// <summary>
/// The current value of the hash
/// </summary>
private ulong _hash;
public CrcRunner(CrcDefinition def)
{
// Check for a valid bit width
if (def.Width < 0 || def.Width > 64)
throw new ArgumentOutOfRangeException(nameof(def));
_definition = def;
_table = new CrcTable(def);
_hash = def.Init;
}
/// <summary>
/// Reset the internal hashing state
/// </summary>
public void Reset()
{
_hash = _definition.Init;
}
/// <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)
=> _table.TransformBlock(ref _hash, data, offset, length);
/// <summary>
/// Finalize the hash and return as a byte array
/// </summary>
public byte[] Finalize()
{
// Create a copy of the hash
ulong localHash = _hash;
// Handle mutual reflection
if (_definition.ReflectIn ^ _definition.ReflectOut)
localHash = BitOperations.ReverseBits(localHash, _definition.Width);
// Handle XOR
localHash ^= _definition.XorOut;
// Process the value and return
return BitOperations.ClampValueToBytes(localHash, _definition.Width);
}
}
}

View File

@@ -0,0 +1,230 @@
namespace SabreTools.Hashing.Crc
{
internal class CrcTable
{
/// <summary>
/// Indicates if CRC should be processed bitwise instead of bytewise
/// </summary>
private readonly bool _processBitwise;
/// <summary>
/// Number of bits to process at a time
/// </summary>
private readonly int _processBits;
/// <summary>
/// Bit shift based on the CRC width
/// </summary>
private readonly int _bitShift;
/// <summary>
/// Bit mask based on the CRC width
/// </summary>
private readonly ulong _bitMask;
/// <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)
{
// Set the accessible fields
_definition = def;
_processBitwise = _definition.Width < 8;
_processBits = _processBitwise ? 1 : 8;
_bitShift = _definition.Width - _processBits;
_bitMask = 1UL << (_definition.Width - 1);
// Initialize the internal
_table = new ulong[SliceCount, 1 << _processBits];
// Build the standard table
for (int i = 0; i < 1 << _processBits; i++)
{
// Get the starting value for this index
ulong point = (ulong)i;
if (!_processBitwise && def.ReflectIn)
point = BitOperations.ReverseBits(point, _processBits);
// Shift to account for storage
point <<= _definition.Width - _processBits;
// Accumulate the value
for (int j = 0; j < 8; j++)
{
if ((point & _bitMask) > 0)
point = (point << 1) ^ def.Poly;
else
point <<= 1;
}
// Reflect if necessary
if (def.ReflectIn)
point = BitOperations.ReverseBits(point, def.Width);
// Shift back to account for storage
point &= ulong.MaxValue >> (64 - def.Width);
// Assign to both tables
_table[0, i] = point;
}
// Skip building the optimized table for bitwise processing
if (_processBitwise)
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 << _processBits; j++)
{
ulong last = _table[i - 1, j];
if (_definition.ReflectIn)
_table[i, j] = (last >> _processBits) ^ _table[0, (byte)last];
else
_table[i, j] = (last << _processBits) ^ _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 (_processBitwise)
{
for (int b = 0; b < 8; b++)
{
if (_definition.ReflectIn)
hash = (hash >> _processBits) ^ _table[0, (byte)(hash & 1) ^ ((byte)(data[offset] >> b) & 1)];
else
hash = (hash << _processBits) ^ _table[0, (byte)((hash >> _bitShift) & 1) ^ ((byte)(data[offset] >> (7 - b)) & 1)];
}
}
// Per-byte processing
else
{
if (_definition.ReflectIn)
hash = (hash >> _processBits) ^ _table[0, (byte)hash ^ data[offset]];
else
hash = (hash << _processBits) ^ _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 (_processBitwise)
return false;
// Check for optimizable transformations
if (_definition.Width == 32 && _definition.ReflectIn)
{
TransformBlockFast32Reflect(ref hash, data, offset, length);
return true;
}
return false;
}
/// <summary>
/// Optimized transformation for 32-bit CRC with reflection
/// </summary>
private void TransformBlockFast32Reflect(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] << 32)
+ (data[offset + 5] << 40)
+ (data[offset + 6] << 48)
+ (data[offset + 7] << 56));
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)];
}
}
// Process unaligned data
while (length-- != 0)
{
PerformChecksumStep(ref local, data, offset++);
}
// Assign the new hash value
hash = local;
}
}
}

View File

@@ -0,0 +1,793 @@
namespace SabreTools.Hashing.Crc
{
/// <see href="https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.legend"/>
internal static class StandardDefinitions
{
#region CRC-16
/// <summary>
/// CRC-16/ARC [ARC, CRC-16, CRC-16/LHA, CRC-IBM]
/// </summary>
public static readonly CrcDefinition CRC16_ARC = new()
{
Width = 16,
Poly = 0x8005,
Init = 0x0000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/CDMA2000
/// </summary>
public static readonly CrcDefinition CRC16_CDMA2000 = new()
{
Width = 16,
Poly = 0xc867,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/CMS
/// </summary>
public static readonly CrcDefinition CRC16_CMS = new()
{
Width = 16,
Poly = 0x8005,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/DDS-110
/// </summary>
public static readonly CrcDefinition CRC16_DDS110 = new()
{
Width = 16,
Poly = 0x8005,
Init = 0x800d,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/DECT-R [R-CRC-16]
/// </summary>
public static readonly CrcDefinition CRC16_DECTR = new()
{
Width = 16,
Poly = 0x0589,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0001,
};
/// <summary>
/// CRC-16/DECT-X [X-CRC-16]
/// </summary>
public static readonly CrcDefinition CRC16_DECTX = new()
{
Width = 16,
Poly = 0x0589,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/DNP
/// </summary>
public static readonly CrcDefinition CRC16_DNP = new()
{
Width = 16,
Poly = 0x3d65,
Init = 0x0000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/EN-13757
/// </summary>
public static readonly CrcDefinition CRC16_EN13757 = new()
{
Width = 16,
Poly = 0x3d65,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/GENIBUS [CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE]
/// </summary>
public static readonly CrcDefinition CRC16_GENIBUS = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/GSM
/// </summary>
public static readonly CrcDefinition CRC16_GSM = new()
{
Width = 16,
Poly = 0x1021,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/IBM-3740 [CRC-16/AUTOSAR, CRC-16/CCITT-FALSE]
/// </summary>
public static readonly CrcDefinition CRC16_IBM3740 = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/IBM-SDLC [CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25]
/// </summary>
public static readonly CrcDefinition CRC16_IBMSDLC = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/ISO-IEC-14443-3-A [CRC-A]
/// </summary>
public static readonly CrcDefinition CRC16_ISOIEC144433A = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xc6c6,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/KERMIT [CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT]
/// </summary>
public static readonly CrcDefinition CRC16_KERMIT = new()
{
Width = 16,
Poly = 0x1021,
Init = 0x0000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/LJ1200
/// </summary>
public static readonly CrcDefinition CRC16_LJ1200 = new()
{
Width = 16,
Poly = 0x6f63,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/M17
/// </summary>
public static readonly CrcDefinition CRC16_M17 = new()
{
Width = 16,
Poly = 0x5935,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/MAXIM-DOW [CRC-16/MAXIM]
/// </summary>
public static readonly CrcDefinition CRC16_MAXIMDOW = new()
{
Width = 16,
Poly = 0x8005,
Init = 0x0000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/MCRF4XX
/// </summary>
public static readonly CrcDefinition CRC16_MCRF4XX = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/MODBUS [MODBUS]
/// </summary>
public static readonly CrcDefinition CRC16_MODBUS = new()
{
Width = 16,
Poly = 0x8005,
Init = 0xffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/NRSC-5
/// </summary>
public static readonly CrcDefinition CRC16_NRSC5 = new()
{
Width = 16,
Poly = 0x080b,
Init = 0xffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/OPENSAFETY-A
/// </summary>
public static readonly CrcDefinition CRC16_OPENSAFETYA = new()
{
Width = 16,
Poly = 0x5935,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/OPENSAFETY-B
/// </summary>
public static readonly CrcDefinition CRC16_OPENSAFETYB = new()
{
Width = 16,
Poly = 0x755b,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/PROFIBUS [CRC-16/IEC-61158-2]
/// </summary>
public static readonly CrcDefinition CRC16_PROFIBUS = new()
{
Width = 16,
Poly = 0x1dcf,
Init = 0xffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/RIELLO
/// </summary>
public static readonly CrcDefinition CRC16_RIELLO = new()
{
Width = 16,
Poly = 0x1021,
Init = 0xb2aa,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/SPI-FUJITSU [CRC-16/AUG-CCITT]
/// </summary>
public static readonly CrcDefinition CRC16_SPIFUJITSU = new()
{
Width = 16,
Poly = 0x1021,
Init = 0x1d0f,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/T10-DIF
/// </summary>
public static readonly CrcDefinition CRC16_T10DIF = new()
{
Width = 16,
Poly = 0x8bb7,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/TELEDISK
/// </summary>
public static readonly CrcDefinition CRC16_TELEDISK = new()
{
Width = 16,
Poly = 0xa097,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/TMS37157
/// </summary>
public static readonly CrcDefinition CRC16_TMS37157 = new()
{
Width = 16,
Poly = 0x1021,
Init = 0x89ec,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/UMTS [CRC-16/BUYPASS, CRC-16/VERIFONE]
/// </summary>
public static readonly CrcDefinition CRC16_UMTS = new()
{
Width = 16,
Poly = 0x8005,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
/// <summary>
/// CRC-16/USB
/// </summary>
public static readonly CrcDefinition CRC16_USB = new()
{
Width = 16,
Poly = 0x8005,
Init = 0xffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffff,
};
/// <summary>
/// CRC-16/XMODEM [CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM]
/// </summary>
public static readonly CrcDefinition CRC16_XMODEM = new()
{
Width = 16,
Poly = 0x1021,
Init = 0x0000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000,
};
#endregion
#region CRC-24
/// <summary>
/// CRC-24/BLE
/// </summary>
public static readonly CrcDefinition CRC24_BLE = new()
{
Width = 24,
Poly = 0x00065b,
Init = 0x555555,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/FLEXRAY-A
/// </summary>
public static readonly CrcDefinition CRC24_FLEXRAYA = new()
{
Width = 24,
Poly = 0x5d6dcb,
Init = 0xfedcba,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/FLEXRAY-B
/// </summary>
public static readonly CrcDefinition CRC24_FLEXRAYB = new()
{
Width = 24,
Poly = 0x5d6dcb,
Init = 0xabcdef,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/INTERLAKEN
/// </summary>
public static readonly CrcDefinition CRC24_INTERLAKEN = new()
{
Width = 24,
Poly = 0x328b63,
Init = 0xffffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffff,
};
/// <summary>
/// CRC-24/LTE-A
/// </summary>
public static readonly CrcDefinition CRC24_LTEA = new()
{
Width = 24,
Poly = 0x864cfb,
Init = 0x000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/LTE-B
/// </summary>
public static readonly CrcDefinition CRC24_LTEB = new()
{
Width = 24,
Poly = 0x800063,
Init = 0x000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/OPENPGP
/// </summary>
public static readonly CrcDefinition CRC24_OPENPGP = new()
{
Width = 24,
Poly = 0x864cfb,
Init = 0xb704ce,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x000000,
};
/// <summary>
/// CRC-24/OS-9
/// </summary>
public static readonly CrcDefinition CRC24_OS9 = new()
{
Width = 24,
Poly = 0x800063,
Init = 0xffffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffff,
};
#endregion
#region CRC-32
/// <summary>
/// CRC-32/AIXM
/// </summary>
public static readonly CrcDefinition CRC32_AIXM = new()
{
Width = 32,
Poly = 0x814141ab,
Init = 0x00000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x00000000,
};
/// <summary>
/// CRC-32/AUTOSAR
/// </summary>
public static readonly CrcDefinition CRC32_AUTOSAR = new()
{
Width = 32,
Poly = 0xf4acfb13,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/BASE91-D
/// </summary>
public static readonly CrcDefinition CRC32_BASE91D = new()
{
Width = 32,
Poly = 0xa833982b,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/BZIP2
/// </summary>
public static readonly CrcDefinition CRC32_BZIP2 = new()
{
Width = 32,
Poly = 0x04c11db7,
Init = 0xffffffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/CD-ROM-EDC
/// </summary>
public static readonly CrcDefinition CRC32_CDROMEDC = new()
{
Width = 32,
Poly = 0x8001801b,
Init = 0x00000000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x00000000,
};
/// <summary>
/// CRC-32/CKSUM
/// </summary>
public static readonly CrcDefinition CRC32_CKSUM = new()
{
Width = 32,
Poly = 0x04c11db7,
Init = 0x00000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/ISCSI
/// </summary>
public static readonly CrcDefinition CRC32_ISCSI = new()
{
Width = 32,
Poly = 0x1edc6f41,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/ISO-HDLC
/// </summary>
public static readonly CrcDefinition CRC32_ISOHDLC = new()
{
Width = 32,
Poly = 0x04c11db7,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffff,
};
/// <summary>
/// CRC-32/JAMCRC
/// </summary>
public static readonly CrcDefinition CRC32_JAMCRC = new()
{
Width = 32,
Poly = 0x04c11db7,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x00000000,
};
/// <summary>
/// CRC-32/MEF
/// </summary>
public static readonly CrcDefinition CRC32_MEF = new()
{
Width = 32,
Poly = 0x741b8cd7,
Init = 0xffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x00000000,
};
/// <summary>
/// CRC-32/MPEG-2
/// </summary>
public static readonly CrcDefinition CRC32_MPEG2 = new()
{
Width = 32,
Poly = 0x04c11db7,
Init = 0xffffffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x00000000,
};
/// <summary>
/// CRC-32/XFER
/// </summary>
public static readonly CrcDefinition CRC32_XFER = new()
{
Width = 32,
Poly = 0x000000af,
Init = 0x00000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x00000000,
};
#endregion
#region CRC-40
/// <summary>
/// CRC-40/GSM
/// </summary>
public static readonly CrcDefinition CRC40_GSM = new()
{
Width = 40,
Poly = 0x0004820009,
Init = 0x0000000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffffffff,
};
#endregion
#region CRC-64
/// <summary>
/// CRC-64/ECMA-182
/// </summary>
public static readonly CrcDefinition CRC64_ECMA182 = new()
{
Width = 64,
Poly = 0x42f0e1eba9ea3693,
Init = 0x0000000000000000,
ReflectIn = false,
ReflectOut = false,
XorOut = 0x0000000000000000,
};
/// <summary>
/// CRC-64/GO-ISO
/// </summary>
public static readonly CrcDefinition CRC64_GOISO = new()
{
Width = 64,
Poly = 0x000000000000001b,
Init = 0xffffffffffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffffffffffff,
};
/// <summary>
/// CRC-64/MS
/// </summary>
public static readonly CrcDefinition CRC64_MS = new()
{
Width = 64,
Poly = 0x259c84cba6426349,
Init = 0xffffffffffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000000000000000,
};
/// <summary>
/// CRC-64/NVME
/// </summary>
public static readonly CrcDefinition CRC64_NVME = new()
{
Width = 64,
Poly = 0xad93d23594c93659,
Init = 0xffffffffffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffffffffffff,
};
/// <summary>
/// CRC-64/REDIS
/// </summary>
public static readonly CrcDefinition CRC64_REDIS = new()
{
Width = 64,
Poly = 0xad93d23594c935a9,
Init = 0x0000000000000000,
ReflectIn = true,
ReflectOut = true,
XorOut = 0x0000000000000000,
};
/// <summary>
/// CRC-64/WE
/// </summary>
public static readonly CrcDefinition CRC64_WE = new()
{
Width = 64,
Poly = 0x42f0e1eba9ea3693,
Init = 0xffffffffffffffff,
ReflectIn = false,
ReflectOut = false,
XorOut = 0xffffffffffffffff,
};
/// <summary>
/// CRC-64/XZ
/// </summary>
public static readonly CrcDefinition CRC64_XZ = new()
{
Width = 64,
Poly = 0x42f0e1eba9ea3693,
Init = 0xffffffffffffffff,
ReflectIn = true,
ReflectOut = true,
XorOut = 0xffffffffffffffff,
};
#endregion
}
}

View File

@@ -4,7 +4,6 @@ using System.IO;
#if NET40_OR_GREATER || NETCOREAPP
using System.Threading.Tasks;
#endif
using Compress.ThreadReaders;
namespace SabreTools.Hashing
{
@@ -46,18 +45,38 @@ namespace SabreTools.Hashing
public static Dictionary<HashType, string?>? GetFileHashes(string filename)
=> GetFileHashesAndSize(filename, out _);
/// <summary>
/// Get hashes from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetFileHashArrays(string filename)
=> GetFileHashArraysAndSize(filename, out _);
/// <summary>
/// Get a hash from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
/// <returns>Hash on success, null on error</returns>
public static string? GetFileHash(string filename, HashType hashType)
{
var hashes = GetFileHashes(filename, [hashType]);
return hashes?[hashType];
}
/// <summary>
/// Get a hash from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Hash on success, null on error</returns>
public static byte[]? GetFileHashArray(string filename, HashType hashType)
{
var hashes = GetFileHashArrays(filename, [hashType]);
return hashes?[hashType];
}
/// <summary>
/// Get hashes from an input file path
/// </summary>
@@ -67,6 +86,15 @@ namespace SabreTools.Hashing
public static Dictionary<HashType, string?>? GetFileHashes(string filename, HashType[] hashTypes)
=> GetFileHashesAndSize(filename, hashTypes, out _);
/// <summary>
/// Get hashes from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashTypes">Array of hash types to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetFileHashArrays(string filename, HashType[] hashTypes)
=> GetFileHashArraysAndSize(filename, hashTypes, out _);
#endregion
#region File Hashes With Size
@@ -85,18 +113,44 @@ namespace SabreTools.Hashing
return GetFileHashesAndSize(filename, hashTypes, out size);
}
/// <summary>
/// Get hashes and size from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, out long size)
{
// Create a hash array for all entries
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
// Return the hashes from the stream
return GetFileHashArraysAndSize(filename, hashTypes, out size);
}
/// <summary>
/// Get a hash and size from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
/// <returns>Hash and size on success, null on error</returns>
public static string? GetFileHashAndSize(string filename, HashType hashType, out long size)
{
var hashes = GetFileHashesAndSize(filename, [hashType], out size);
return hashes?[hashType];
}
/// <summary>
/// Get a hash and size from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Hash and size on success, null on error</returns>
public static byte[]? GetFileHashArrayAndSize(string filename, HashType hashType, out long size)
{
var hashes = GetFileHashArraysAndSize(filename, [hashType], out size);
return hashes?[hashType];
}
/// <summary>
/// Get hashes and size from an input file path
/// </summary>
@@ -122,6 +176,31 @@ namespace SabreTools.Hashing
return GetStreamHashes(input, hashTypes);
}
/// <summary>
/// Get hashes and size from an input file path
/// </summary>
/// <param name="filename">Path to the input file</param>
/// <param name="hashTypes">Array of hash types to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, HashType[] hashTypes, out long size)
{
// If the file doesn't exist, we can't do anything
if (!File.Exists(filename))
{
size = -1;
return null;
}
// Set the file size
size = new FileInfo(filename).Length;
// Open the input file
var input = File.OpenRead(filename);
// Return the hashes from the stream
return GetStreamHashArrays(input, hashTypes);
}
#endregion
#region Byte Array Hashes
@@ -140,18 +219,44 @@ namespace SabreTools.Hashing
return GetStreamHashes(new MemoryStream(input), hashTypes);
}
/// <summary>
/// Get hashes from an input byte array
/// </summary>
/// <param name="input">Byte array to hash</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArrays(byte[] input)
{
// Create a hash array for all entries
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
// Return the hashes from the stream
return GetStreamHashArrays(new MemoryStream(input), hashTypes);
}
/// <summary>
/// Get a hash from an input byte array
/// </summary>
/// <param name="input">Byte array to hash</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
/// <returns>Hash on success, null on error</returns>
public static string? GetByteArrayHash(byte[] input, HashType hashType)
{
var hashes = GetStreamHashes(new MemoryStream(input), [hashType]);
return hashes?[hashType];
}
/// <summary>
/// Get a hash from an input byte array
/// </summary>
/// <param name="input">Byte array to hash</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Hash on success, null on error</returns>
public static byte[]? GetByteArrayHashArray(byte[] input, HashType hashType)
{
var hashes = GetStreamHashArrays(new MemoryStream(input), [hashType]);
return hashes?[hashType];
}
/// <summary>
/// Get hashes from an input byte array
/// </summary>
@@ -161,6 +266,15 @@ namespace SabreTools.Hashing
public static Dictionary<HashType, string?>? GetByteArrayHashes(byte[] input, HashType[] hashTypes)
=> GetStreamHashes(new MemoryStream(input), hashTypes);
/// <summary>
/// Get hashes from an input byte array
/// </summary>
/// <param name="input">Byte array to hash</param>
/// <param name="hashTypes">Array of hash types to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArrays(byte[] input, HashType[] hashTypes)
=> GetStreamHashArrays(new MemoryStream(input), hashTypes);
#endregion
#region Stream Hashes
@@ -170,13 +284,27 @@ namespace SabreTools.Hashing
/// </summary>
/// <param name="input">Stream to hash</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input)
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, bool leaveOpen = false)
{
// Create a hash array for all entries
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
// Get the output hashes
return GetStreamHashes(input, hashTypes);
return GetStreamHashes(input, hashTypes, leaveOpen);
}
/// <summary>
/// Get hashes from an input Stream
/// </summary>
/// <param name="input">Stream to hash</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, bool leaveOpen = false)
{
// Create a hash array for all entries
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
// Get the output hashes
return GetStreamHashArrays(input, hashTypes, leaveOpen);
}
/// <summary>
@@ -184,10 +312,22 @@ namespace SabreTools.Hashing
/// </summary>
/// <param name="input">Stream to hash</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static string? GetStreamHash(Stream input, HashType hashType)
/// <returns>Hash on success, null on error</returns>
public static string? GetStreamHash(Stream input, HashType hashType, bool leaveOpen = false)
{
var hashes = GetStreamHashes(input, [hashType]);
var hashes = GetStreamHashes(input, [hashType], leaveOpen);
return hashes?[hashType];
}
/// <summary>
/// Get a hash and size from an input Stream
/// </summary>
/// <param name="input">Stream to hash</param>
/// <param name="hashType">Hash type to get from the file</param>
/// <returns>Hash on success, null on error</returns>
public static byte[]? GetStreamHashArray(Stream input, HashType hashType, bool leaveOpen = false)
{
var hashes = GetStreamHashArrays(input, [hashType], leaveOpen);
return hashes?[hashType];
}
@@ -197,7 +337,70 @@ namespace SabreTools.Hashing
/// <param name="input">Stream to hash</param>
/// <param name="hashTypes">Array of hash types to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, HashType[] hashTypes)
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, HashType[] hashTypes, bool leaveOpen = false)
{
// Create the output dictionary
var hashDict = new Dictionary<HashType, string?>();
// Run the hashing
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
if (hashers == null)
return null;
// Get the results
foreach (var hasher in hashers)
{
hashDict[hasher.Key] = hasher.Value.CurrentHashString;
}
// Dispose of the hashers
foreach (var hasher in hashers.Values)
{
hasher.Dispose();
}
return hashDict;
}
/// <summary>
/// Get hashes from an input Stream
/// </summary>
/// <param name="input">Stream to hash</param>
/// <param name="hashTypes">Array of hash types to get from the file</param>
/// <returns>Dictionary containing hashes on success, null on error</returns>
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, HashType[] hashTypes, bool leaveOpen = false)
{
// Create the output dictionary
var hashDict = new Dictionary<HashType, byte[]?>();
// Run the hashing
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
if (hashers == null)
return null;
// Get the results
foreach (var hasher in hashers)
{
hashDict[hasher.Key] = hasher.Value.CurrentHashBytes;
}
// Dispose of the hashers
foreach (var hasher in hashers.Values)
{
hasher.Dispose();
}
return hashDict;
}
/// <summary>
/// Get hashes from an input stream
/// </summary>
/// <param name="input"></param>
/// <param name="hashTypes"></param>
/// <param name="leaveOpen"></param>
/// <returns></returns>
private static Dictionary<HashType, HashWrapper>? GetStreamHashesInternal(Stream input, HashType[] hashTypes, bool leaveOpen)
{
// Create the output dictionary
var hashDict = new Dictionary<HashType, string?>();
@@ -213,83 +416,44 @@ namespace SabreTools.Hashing
hashers[hashType] = new HashWrapper(hashType);
}
// Initialize the hashing helpers
var loadBuffer = new ThreadLoadBuffer(input);
// Create the buffer for holding data
int buffersize = 3 * 1024 * 1024;
byte[] buffer0 = new byte[buffersize];
byte[] buffer1 = new byte[buffersize];
byte[] buffer = new byte[buffersize];
int lastRead;
/*
Please note that some of the following code is adapted from
RomVault. This is a modified version of how RomVault does
threaded hashing. As such, some of the terminology and code
is the same, though variable names and comments may have
been tweaked to better fit this code base.
*/
// Pre load the first buffer
long refsize = input.Length;
int next = refsize > buffersize ? buffersize : (int)refsize;
input.Read(buffer0, 0, next);
int current = next;
refsize -= next;
bool bufferSelect = true;
while (current > 0)
// Hash the input data in blocks
do
{
// Trigger the buffer load on the second buffer
next = refsize > buffersize ? buffersize : (int)refsize;
if (next > 0)
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next);
byte[] buffer = bufferSelect ? buffer0 : buffer1;
// Load the buffer and hold the number of bytes read
lastRead = input.Read(buffer, 0, buffersize);
if (lastRead == 0)
break;
#if NET20 || NET35
// Run hashers sequentially on each chunk
foreach (var h in hashers)
{
h.Value.Process(buffer, 0, current);
h.Value.Process(buffer, 0, lastRead);
}
#else
// Run hashers in parallel on each chunk
Parallel.ForEach(hashers, h => h.Value.Process(buffer, 0, current));
Parallel.ForEach(hashers, h => h.Value.Process(buffer, 0, lastRead));
#endif
// Wait for the load buffer worker, if needed
if (next > 0)
loadBuffer.Wait();
// Setup for the next hashing step
current = next;
refsize -= next;
bufferSelect = !bufferSelect;
}
while (lastRead > 0);
// Finalize all hashing helpers
loadBuffer.Finish();
#if NET20 || NET35
// Finalize all hashing helpers sequentially
foreach (var h in hashers)
{
h.Value.Terminate();
}
#else
// Finalize all hashing helpers in parallel
Parallel.ForEach(hashers, h => h.Value.Terminate());
#endif
// Get the results
foreach (var hasher in hashers)
{
hashDict[hasher.Key] = hasher.Value.CurrentHashString;
}
// Dispose of the hashers
loadBuffer.Dispose();
foreach (var hasher in hashers.Values)
{
hasher.Dispose();
}
return hashDict;
return hashers;
}
catch (IOException)
{
@@ -297,7 +461,8 @@ namespace SabreTools.Hashing
}
finally
{
input.Dispose();
if (!leaveOpen)
input.Dispose();
}
}

View File

@@ -5,23 +5,353 @@ namespace SabreTools.Hashing
/// </summary>
public enum HashType
{
/// <summary>
/// Mark Adler's 32-bit checksum
/// </summary>
Adler32,
#if NET7_0_OR_GREATER
/// <summary>
/// BLAKE3 512-bit digest
/// </summary>
BLAKE3,
#endif
/// <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, // Disabled until incorrect hashes can be fixed
/// <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, // Disabled until incorrect hashes can be fixed
/// <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, // Disabled until incorrect hashes can be fixed
/// <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,
/// <summary>
/// CRC 24-bit checksum (CRC-24/BLE)
/// </summary>
//CRC24_BLE, // Disabled until incorrect hashes can be fixed
/// <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,
/// <summary>
/// CRC 32-bit checksum
/// </summary>
/// <remarks>Identical to <see cref="CRC32_ISOHDLC"/>
CRC32,
#if NET462_OR_GREATER || NETCOREAPP
/// <summary>
/// CRC 32-bit checksum (CRC-32/AIXM)
/// </summary>
CRC32_AIXM,
/// <summary>
/// CRC 32-bit checksum (CRC-32/AUTOSAR)
/// </summary>
CRC32_AUTOSAR,
/// <summary>
/// CRC 32-bit checksum (CRC-32/BASE91-D)
/// </summary>
CRC32_BASE91D,
/// <summary>
/// CRC 32-bit checksum (BZIP2)
/// </summary>
CRC32_BZIP2,
/// <summary>
/// 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,
/// <summary>
/// CRC 40-bit checksum (CRC-40/GSM)
/// </summary>
CRC40_GSM,
/// <summary>
/// CRC 64-bit checksum
/// </summary>
/// <remarks>Identical to <see cref="CRC64_ECMA182"/>
CRC64,
#endif
/// <summary>
/// CRC 64-bit checksum (CRC-64/ECMA-182, Microsoft implementation)
/// </summary>
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,
/// <summary>
/// John G. Fletcher's 16-bit checksum
/// </summary>
Fletcher16,
/// <summary>
/// John G. Fletcher's 32-bit checksum
/// </summary>
Fletcher32,
/// <summary>
/// MD5 hash
/// </summary>
MD5,
#if NETFRAMEWORK
/// <summary>
/// RIPEMD160 hash
/// </summary>
RIPEMD160,
#endif
/// <summary>
/// SHA-1 hash
/// </summary>
@@ -42,6 +372,35 @@ namespace SabreTools.Hashing
/// </summary>
SHA512,
#if NET8_0_OR_GREATER
/// <summary>
/// SHA3-256 hash
/// </summary>
SHA3_256,
/// <summary>
/// SHA3-384 hash
/// </summary>
SHA3_384,
/// <summary>
/// SHA3-512 hash
/// </summary>
SHA3_512,
/// <summary>
/// SHAKE128 SHA-3 family hash
/// </summary>
/// <remarks>Outputs a 256-bit (32-byte) hash</remarks>
SHAKE128,
/// <summary>
/// SHAKE256 SHA-3 family hash
/// </summary>
/// <remarks>Outputs a 512-bit (64-byte) hash</remarks>
SHAKE256,
#endif
/// <summary>
/// spamsum fuzzy hash
/// </summary>

View File

@@ -2,12 +2,13 @@ using System;
#if NET462_OR_GREATER || NETCOREAPP
using System.IO.Hashing;
#endif
#if NET462_OR_GREATER || NETCOREAPP
using System.Linq;
#endif
using System.Security.Cryptography;
using Aaru.Checksums;
using Aaru.CommonTypes.Interfaces;
#if NET7_0_OR_GREATER
using Blake3;
#endif
using SabreTools.Hashing.Crc;
namespace SabreTools.Hashing
{
@@ -21,11 +22,7 @@ namespace SabreTools.Hashing
/// <summary>
/// Hash type associated with the current state
/// </summary>
#if NETFRAMEWORK || NETCOREAPP3_1
public HashType HashType { get; private set; }
#else
public HashType HashType { get; init; }
#endif
public readonly HashType HashType;
/// <summary>
/// Current hash in bytes
@@ -34,15 +31,31 @@ namespace SabreTools.Hashing
{
get
{
return _hasher switch
switch (_hasher)
{
HashAlgorithm ha => ha.Hash,
IChecksum ic => ic.Final(),
case CrcRunner cr:
var crArr = cr.Finalize();
Array.Reverse(crArr);
return crArr;
case HashAlgorithm ha:
return ha.Hash;
case IChecksum ic:
return ic.Final();
#if NET462_OR_GREATER || NETCOREAPP
NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash().Reverse().ToArray(),
case NonCryptographicHashAlgorithm ncha:
var nchaArr = ncha.GetCurrentHash();
Array.Reverse(nchaArr);
return nchaArr;
#endif
_ => null,
};
#if NET8_0_OR_GREATER
case Shake128 s128:
return s128.GetCurrentHash(32);
case Shake256 s256:
return s256.GetCurrentHash(64);
#endif
default:
return null;
}
}
}
@@ -81,7 +94,7 @@ namespace SabreTools.Hashing
/// <param name="hashType">Hash type to instantiate</param>
public HashWrapper(HashType hashType)
{
this.HashType = hashType;
HashType = hashType;
GetHasher();
}
@@ -92,17 +105,99 @@ namespace SabreTools.Hashing
{
_hasher = HashType switch
{
#if NET462_OR_GREATER || NETCOREAPP
HashType.CRC32 => new Crc32(),
HashType.CRC64 => new Crc64(),
#else
HashType.CRC32 => new OptimizedCRC.OptimizedCRC(),
HashType.Adler32 => new Adler32Context(),
#if NET7_0_OR_GREATER
HashType.BLAKE3 => new Blake3HashAlgorithm(),
#endif
HashType.CRC16 => new CrcRunner(StandardDefinitions.CRC16_ARC),
HashType.CRC16_ARC => new CrcRunner(StandardDefinitions.CRC16_ARC),
HashType.CRC16_CDMA2000 => new CrcRunner(StandardDefinitions.CRC16_CDMA2000),
HashType.CRC16_CMS => new CrcRunner(StandardDefinitions.CRC16_CMS),
HashType.CRC16_DDS110 => new CrcRunner(StandardDefinitions.CRC16_DDS110),
HashType.CRC16_DECTR => new CrcRunner(StandardDefinitions.CRC16_DECTR),
HashType.CRC16_DECTX => new CrcRunner(StandardDefinitions.CRC16_DECTX),
HashType.CRC16_DNP => new CrcRunner(StandardDefinitions.CRC16_DNP),
HashType.CRC16_EN13757 => new CrcRunner(StandardDefinitions.CRC16_EN13757),
HashType.CRC16_GENIBUS => new CrcRunner(StandardDefinitions.CRC16_GENIBUS),
HashType.CRC16_GSM => new CrcRunner(StandardDefinitions.CRC16_GSM),
HashType.CRC16_IBM3740 => new CrcRunner(StandardDefinitions.CRC16_IBM3740),
HashType.CRC16_IBMSDLC => new CrcRunner(StandardDefinitions.CRC16_IBMSDLC),
//HashType.CRC16_ISOIEC144433A => new CrcRunner(StandardDefinitions.CRC16_ISOIEC144433A),
HashType.CRC16_KERMIT => new CrcRunner(StandardDefinitions.CRC16_KERMIT),
HashType.CRC16_LJ1200 => new CrcRunner(StandardDefinitions.CRC16_LJ1200),
HashType.CRC16_M17 => new CrcRunner(StandardDefinitions.CRC16_M17),
HashType.CRC16_MAXIMDOW => new CrcRunner(StandardDefinitions.CRC16_MAXIMDOW),
HashType.CRC16_MCRF4XX => new CrcRunner(StandardDefinitions.CRC16_MCRF4XX),
HashType.CRC16_MODBUS => new CrcRunner(StandardDefinitions.CRC16_MODBUS),
HashType.CRC16_NRSC5 => new CrcRunner(StandardDefinitions.CRC16_NRSC5),
HashType.CRC16_OPENSAFETYA => new CrcRunner(StandardDefinitions.CRC16_OPENSAFETYA),
HashType.CRC16_OPENSAFETYB => new CrcRunner(StandardDefinitions.CRC16_OPENSAFETYB),
HashType.CRC16_PROFIBUS => new CrcRunner(StandardDefinitions.CRC16_PROFIBUS),
//HashType.CRC16_RIELLO => new CrcRunner(StandardDefinitions.CRC16_RIELLO),
HashType.CRC16_SPIFUJITSU => new CrcRunner(StandardDefinitions.CRC16_SPIFUJITSU),
HashType.CRC16_T10DIF => new CrcRunner(StandardDefinitions.CRC16_T10DIF),
HashType.CRC16_TELEDISK => new CrcRunner(StandardDefinitions.CRC16_TELEDISK),
//HashType.CRC16_TMS37157 => new CrcRunner(StandardDefinitions.CRC16_TMS37157),
HashType.CRC16_UMTS => new CrcRunner(StandardDefinitions.CRC16_UMTS),
HashType.CRC16_USB => new CrcRunner(StandardDefinitions.CRC16_USB),
HashType.CRC16_XMODEM => new CrcRunner(StandardDefinitions.CRC16_XMODEM),
//HashType.CRC24_BLE => new CrcRunner(StandardDefinitions.CRC24_BLE),
HashType.CRC24_FLEXRAYA => new CrcRunner(StandardDefinitions.CRC24_FLEXRAYA),
HashType.CRC24_FLEXRAYB => new CrcRunner(StandardDefinitions.CRC24_FLEXRAYB),
HashType.CRC24_INTERLAKEN => new CrcRunner(StandardDefinitions.CRC24_INTERLAKEN),
HashType.CRC24_LTEA => new CrcRunner(StandardDefinitions.CRC24_LTEA),
HashType.CRC24_LTEB => new CrcRunner(StandardDefinitions.CRC24_LTEB),
HashType.CRC24_OPENPGP => new CrcRunner(StandardDefinitions.CRC24_OPENPGP),
HashType.CRC24_OS9 => new CrcRunner(StandardDefinitions.CRC24_OS9),
HashType.CRC32 => new CrcRunner(StandardDefinitions.CRC32_ISOHDLC),
HashType.CRC32_AIXM => new CrcRunner(StandardDefinitions.CRC32_AIXM),
HashType.CRC32_AUTOSAR => new CrcRunner(StandardDefinitions.CRC32_AUTOSAR),
HashType.CRC32_BASE91D => new CrcRunner(StandardDefinitions.CRC32_BASE91D),
HashType.CRC32_BZIP2 => new CrcRunner(StandardDefinitions.CRC32_BZIP2),
HashType.CRC32_CDROMEDC => new CrcRunner(StandardDefinitions.CRC32_CDROMEDC),
HashType.CRC32_CKSUM => new CrcRunner(StandardDefinitions.CRC32_CKSUM),
HashType.CRC32_ISCSI => new CrcRunner(StandardDefinitions.CRC32_ISCSI),
HashType.CRC32_ISOHDLC => new CrcRunner(StandardDefinitions.CRC32_ISOHDLC),
HashType.CRC32_JAMCRC => new CrcRunner(StandardDefinitions.CRC32_JAMCRC),
HashType.CRC32_MEF => new CrcRunner(StandardDefinitions.CRC32_MEF),
HashType.CRC32_MPEG2 => new CrcRunner(StandardDefinitions.CRC32_MPEG2),
HashType.CRC32_XFER => new CrcRunner(StandardDefinitions.CRC32_XFER),
HashType.CRC40_GSM => new CrcRunner(StandardDefinitions.CRC40_GSM),
HashType.CRC64 => new CrcRunner(StandardDefinitions.CRC64_ECMA182),
HashType.CRC64_ECMA182 => new CrcRunner(StandardDefinitions.CRC64_ECMA182),
HashType.CRC64_GOISO => new CrcRunner(StandardDefinitions.CRC64_GOISO),
HashType.CRC64_MS => new CrcRunner(StandardDefinitions.CRC64_MS),
HashType.CRC64_NVME => new CrcRunner(StandardDefinitions.CRC64_NVME),
HashType.CRC64_REDIS => new CrcRunner(StandardDefinitions.CRC64_REDIS),
HashType.CRC64_WE => new CrcRunner(StandardDefinitions.CRC64_WE),
HashType.CRC64_XZ => new CrcRunner(StandardDefinitions.CRC64_XZ),
HashType.Fletcher16 => new Fletcher16Context(),
HashType.Fletcher32 => new Fletcher32Context(),
HashType.MD5 => MD5.Create(),
#if NETFRAMEWORK
HashType.RIPEMD160 => RIPEMD160.Create(),
#endif
HashType.SHA1 => SHA1.Create(),
HashType.SHA256 => SHA256.Create(),
HashType.SHA384 => SHA384.Create(),
HashType.SHA512 => SHA512.Create(),
#if NET8_0_OR_GREATER
HashType.SHA3_256 => SHA3_256.IsSupported ? SHA3_256.Create() : null,
HashType.SHA3_384 => SHA3_384.IsSupported ? SHA3_384.Create() : null,
HashType.SHA3_512 => SHA3_512.IsSupported ? SHA3_512.Create() : null,
HashType.SHAKE128 => Shake128.IsSupported ? new Shake128() : null,
HashType.SHAKE256 => Shake256.IsSupported ? new Shake256() : null,
#endif
HashType.SpamSum => new SpamSumContext(),
#if NET462_OR_GREATER || NETCOREAPP
HashType.XxHash32 => new XxHash32(),
@@ -132,13 +227,18 @@ namespace SabreTools.Hashing
{
switch (_hasher)
{
case CrcRunner cr:
cr.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;
#if NET462_OR_GREATER || NETCOREAPP
@@ -146,9 +246,17 @@ namespace SabreTools.Hashing
var nchaBufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
ncha.Append(nchaBufferSpan);
break;
#else
case OptimizedCRC.OptimizedCRC oc:
oc.Update(buffer, offset, size);
#endif
#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
}
@@ -157,7 +265,7 @@ namespace SabreTools.Hashing
/// <summary>
/// Finalize the internal hash algorigthm
/// </summary>
/// <remarks>NonCryptographicHashAlgorithm implementations do not need finalization</remarks>
/// <remarks>NonCryptographicHashAlgorithm, SHAKE128, and SHAKE256 implementations do not need finalization</remarks>
public void Terminate()
{
byte[] emptyBuffer = [];
@@ -166,12 +274,6 @@ namespace SabreTools.Hashing
case HashAlgorithm ha:
ha.TransformFinalBlock(emptyBuffer, 0, 0);
break;
#if NET20_OR_GREATER || NETCOREAPP3_1 || NET5_0
case OptimizedCRC.OptimizedCRC oc:
oc.Update([], 0, 0);
break;
#endif
}
}
@@ -202,21 +304,6 @@ namespace SabreTools.Hashing
}
}
/// <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,153 +0,0 @@
/*
Copyright (c) 2012-2015 Eugene Larchenko (spct@mail.ru)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
namespace OptimizedCRC
{
internal class OptimizedCRC : IDisposable
{
private const uint kCrcPoly = 0xEDB88320;
private const uint kInitial = 0xFFFFFFFF;
private const int CRC_NUM_TABLES = 8;
private static readonly uint[] Table;
static OptimizedCRC()
{
unchecked
{
Table = new uint[256 * CRC_NUM_TABLES];
int i;
for (i = 0; i < 256; i++)
{
uint r = (uint)i;
for (int j = 0; j < 8; j++)
{
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
}
Table[i] = r;
}
for (; i < 256 * CRC_NUM_TABLES; i++)
{
uint r = Table[i - 256];
Table[i] = Table[r & 0xFF] ^ (r >> 8);
}
}
}
public uint UnsignedValue;
public OptimizedCRC()
{
Init();
}
/// <summary>
/// Reset CRC
/// </summary>
public void Init()
{
UnsignedValue = kInitial;
}
public int Value
{
get { return (int)~UnsignedValue; }
}
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 = UnsignedValue;
for (; (offset & 7) != 0 && count != 0; count--)
{
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
}
if (count >= 8)
{
/*
* Idea from 7-zip project sources (http://7-zip.org/sdk.html)
*/
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++]];
}
UnsignedValue = 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);
}
static public int Compute(ArraySegment<byte> block)
{
return Compute(block.Array!, block.Offset, block.Count);
}
public void Dispose()
{
UnsignedValue = 0;
}
}
}

View File

@@ -1,43 +1,56 @@
<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.1.2</Version>
<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.2.3</Version>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- 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`)) 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>
<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>
<ItemGroup>
<PackageReference Include="Aaru.Checksums.Native" Version="6.0.0-alpha9" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,524 @@
namespace SabreTools.Hashing.Tiger
{
/// <summary>
/// Tiger S boxes
/// </summary>
public static class SBoxes
{
public static readonly ulong[] Table =
[
0x02AAB17CF7E90C5E /* 0 */, 0xAC424B03E243A8EC /* 1 */,
0x72CD5BE30DD5FCD3 /* 2 */, 0x6D019B93F6F97F3A /* 3 */,
0xCD9978FFD21F9193 /* 4 */, 0x7573A1C9708029E2 /* 5 */,
0xB164326B922A83C3 /* 6 */, 0x46883EEE04915870 /* 7 */,
0xEAACE3057103ECE6 /* 8 */, 0xC54169B808A3535C /* 9 */,
0x4CE754918DDEC47C /* 10 */, 0x0AA2F4DFDC0DF40C /* 11 */,
0x10B76F18A74DBEFA /* 12 */, 0xC6CCB6235AD1AB6A /* 13 */,
0x13726121572FE2FF /* 14 */, 0x1A488C6F199D921E /* 15 */,
0x4BC9F9F4DA0007CA /* 16 */, 0x26F5E6F6E85241C7 /* 17 */,
0x859079DBEA5947B6 /* 18 */, 0x4F1885C5C99E8C92 /* 19 */,
0xD78E761EA96F864B /* 20 */, 0x8E36428C52B5C17D /* 21 */,
0x69CF6827373063C1 /* 22 */, 0xB607C93D9BB4C56E /* 23 */,
0x7D820E760E76B5EA /* 24 */, 0x645C9CC6F07FDC42 /* 25 */,
0xBF38A078243342E0 /* 26 */, 0x5F6B343C9D2E7D04 /* 27 */,
0xF2C28AEB600B0EC6 /* 28 */, 0x6C0ED85F7254BCAC /* 29 */,
0x71592281A4DB4FE5 /* 30 */, 0x1967FA69CE0FED9F /* 31 */,
0xFD5293F8B96545DB /* 32 */, 0xC879E9D7F2A7600B /* 33 */,
0x860248920193194E /* 34 */, 0xA4F9533B2D9CC0B3 /* 35 */,
0x9053836C15957613 /* 36 */, 0xDB6DCF8AFC357BF1 /* 37 */,
0x18BEEA7A7A370F57 /* 38 */, 0x037117CA50B99066 /* 39 */,
0x6AB30A9774424A35 /* 40 */, 0xF4E92F02E325249B /* 41 */,
0x7739DB07061CCAE1 /* 42 */, 0xD8F3B49CECA42A05 /* 43 */,
0xBD56BE3F51382F73 /* 44 */, 0x45FAED5843B0BB28 /* 45 */,
0x1C813D5C11BF1F83 /* 46 */, 0x8AF0E4B6D75FA169 /* 47 */,
0x33EE18A487AD9999 /* 48 */, 0x3C26E8EAB1C94410 /* 49 */,
0xB510102BC0A822F9 /* 50 */, 0x141EEF310CE6123B /* 51 */,
0xFC65B90059DDB154 /* 52 */, 0xE0158640C5E0E607 /* 53 */,
0x884E079826C3A3CF /* 54 */, 0x930D0D9523C535FD /* 55 */,
0x35638D754E9A2B00 /* 56 */, 0x4085FCCF40469DD5 /* 57 */,
0xC4B17AD28BE23A4C /* 58 */, 0xCAB2F0FC6A3E6A2E /* 59 */,
0x2860971A6B943FCD /* 60 */, 0x3DDE6EE212E30446 /* 61 */,
0x6222F32AE01765AE /* 62 */, 0x5D550BB5478308FE /* 63 */,
0xA9EFA98DA0EDA22A /* 64 */, 0xC351A71686C40DA7 /* 65 */,
0x1105586D9C867C84 /* 66 */, 0xDCFFEE85FDA22853 /* 67 */,
0xCCFBD0262C5EEF76 /* 68 */, 0xBAF294CB8990D201 /* 69 */,
0xE69464F52AFAD975 /* 70 */, 0x94B013AFDF133E14 /* 71 */,
0x06A7D1A32823C958 /* 72 */, 0x6F95FE5130F61119 /* 73 */,
0xD92AB34E462C06C0 /* 74 */, 0xED7BDE33887C71D2 /* 75 */,
0x79746D6E6518393E /* 76 */, 0x5BA419385D713329 /* 77 */,
0x7C1BA6B948A97564 /* 78 */, 0x31987C197BFDAC67 /* 79 */,
0xDE6C23C44B053D02 /* 80 */, 0x581C49FED002D64D /* 81 */,
0xDD474D6338261571 /* 82 */, 0xAA4546C3E473D062 /* 83 */,
0x928FCE349455F860 /* 84 */, 0x48161BBACAAB94D9 /* 85 */,
0x63912430770E6F68 /* 86 */, 0x6EC8A5E602C6641C /* 87 */,
0x87282515337DDD2B /* 88 */, 0x2CDA6B42034B701B /* 89 */,
0xB03D37C181CB096D /* 90 */, 0xE108438266C71C6F /* 91 */,
0x2B3180C7EB51B255 /* 92 */, 0xDF92B82F96C08BBC /* 93 */,
0x5C68C8C0A632F3BA /* 94 */, 0x5504CC861C3D0556 /* 95 */,
0xABBFA4E55FB26B8F /* 96 */, 0x41848B0AB3BACEB4 /* 97 */,
0xB334A273AA445D32 /* 98 */, 0xBCA696F0A85AD881 /* 99 */,
0x24F6EC65B528D56C /* 100 */, 0x0CE1512E90F4524A /* 101 */,
0x4E9DD79D5506D35A /* 102 */, 0x258905FAC6CE9779 /* 103 */,
0x2019295B3E109B33 /* 104 */, 0xF8A9478B73A054CC /* 105 */,
0x2924F2F934417EB0 /* 106 */, 0x3993357D536D1BC4 /* 107 */,
0x38A81AC21DB6FF8B /* 108 */, 0x47C4FBF17D6016BF /* 109 */,
0x1E0FAADD7667E3F5 /* 110 */, 0x7ABCFF62938BEB96 /* 111 */,
0xA78DAD948FC179C9 /* 112 */, 0x8F1F98B72911E50D /* 113 */,
0x61E48EAE27121A91 /* 114 */, 0x4D62F7AD31859808 /* 115 */,
0xECEBA345EF5CEAEB /* 116 */, 0xF5CEB25EBC9684CE /* 117 */,
0xF633E20CB7F76221 /* 118 */, 0xA32CDF06AB8293E4 /* 119 */,
0x985A202CA5EE2CA4 /* 120 */, 0xCF0B8447CC8A8FB1 /* 121 */,
0x9F765244979859A3 /* 122 */, 0xA8D516B1A1240017 /* 123 */,
0x0BD7BA3EBB5DC726 /* 124 */, 0xE54BCA55B86ADB39 /* 125 */,
0x1D7A3AFD6C478063 /* 126 */, 0x519EC608E7669EDD /* 127 */,
0x0E5715A2D149AA23 /* 128 */, 0x177D4571848FF194 /* 129 */,
0xEEB55F3241014C22 /* 130 */, 0x0F5E5CA13A6E2EC2 /* 131 */,
0x8029927B75F5C361 /* 132 */, 0xAD139FABC3D6E436 /* 133 */,
0x0D5DF1A94CCF402F /* 134 */, 0x3E8BD948BEA5DFC8 /* 135 */,
0xA5A0D357BD3FF77E /* 136 */, 0xA2D12E251F74F645 /* 137 */,
0x66FD9E525E81A082 /* 138 */, 0x2E0C90CE7F687A49 /* 139 */,
0xC2E8BCBEBA973BC5 /* 140 */, 0x000001BCE509745F /* 141 */,
0x423777BBE6DAB3D6 /* 142 */, 0xD1661C7EAEF06EB5 /* 143 */,
0xA1781F354DAACFD8 /* 144 */, 0x2D11284A2B16AFFC /* 145 */,
0xF1FC4F67FA891D1F /* 146 */, 0x73ECC25DCB920ADA /* 147 */,
0xAE610C22C2A12651 /* 148 */, 0x96E0A810D356B78A /* 149 */,
0x5A9A381F2FE7870F /* 150 */, 0xD5AD62EDE94E5530 /* 151 */,
0xD225E5E8368D1427 /* 152 */, 0x65977B70C7AF4631 /* 153 */,
0x99F889B2DE39D74F /* 154 */, 0x233F30BF54E1D143 /* 155 */,
0x9A9675D3D9A63C97 /* 156 */, 0x5470554FF334F9A8 /* 157 */,
0x166ACB744A4F5688 /* 158 */, 0x70C74CAAB2E4AEAD /* 159 */,
0xF0D091646F294D12 /* 160 */, 0x57B82A89684031D1 /* 161 */,
0xEFD95A5A61BE0B6B /* 162 */, 0x2FBD12E969F2F29A /* 163 */,
0x9BD37013FEFF9FE8 /* 164 */, 0x3F9B0404D6085A06 /* 165 */,
0x4940C1F3166CFE15 /* 166 */, 0x09542C4DCDF3DEFB /* 167 */,
0xB4C5218385CD5CE3 /* 168 */, 0xC935B7DC4462A641 /* 169 */,
0x3417F8A68ED3B63F /* 170 */, 0xB80959295B215B40 /* 171 */,
0xF99CDAEF3B8C8572 /* 172 */, 0x018C0614F8FCB95D /* 173 */,
0x1B14ACCD1A3ACDF3 /* 174 */, 0x84D471F200BB732D /* 175 */,
0xC1A3110E95E8DA16 /* 176 */, 0x430A7220BF1A82B8 /* 177 */,
0xB77E090D39DF210E /* 178 */, 0x5EF4BD9F3CD05E9D /* 179 */,
0x9D4FF6DA7E57A444 /* 180 */, 0xDA1D60E183D4A5F8 /* 181 */,
0xB287C38417998E47 /* 182 */, 0xFE3EDC121BB31886 /* 183 */,
0xC7FE3CCC980CCBEF /* 184 */, 0xE46FB590189BFD03 /* 185 */,
0x3732FD469A4C57DC /* 186 */, 0x7EF700A07CF1AD65 /* 187 */,
0x59C64468A31D8859 /* 188 */, 0x762FB0B4D45B61F6 /* 189 */,
0x155BAED099047718 /* 190 */, 0x68755E4C3D50BAA6 /* 191 */,
0xE9214E7F22D8B4DF /* 192 */, 0x2ADDBF532EAC95F4 /* 193 */,
0x32AE3909B4BD0109 /* 194 */, 0x834DF537B08E3450 /* 195 */,
0xFA209DA84220728D /* 196 */, 0x9E691D9B9EFE23F7 /* 197 */,
0x0446D288C4AE8D7F /* 198 */, 0x7B4CC524E169785B /* 199 */,
0x21D87F0135CA1385 /* 200 */, 0xCEBB400F137B8AA5 /* 201 */,
0x272E2B66580796BE /* 202 */, 0x3612264125C2B0DE /* 203 */,
0x057702BDAD1EFBB2 /* 204 */, 0xD4BABB8EACF84BE9 /* 205 */,
0x91583139641BC67B /* 206 */, 0x8BDC2DE08036E024 /* 207 */,
0x603C8156F49F68ED /* 208 */, 0xF7D236F7DBEF5111 /* 209 */,
0x9727C4598AD21E80 /* 210 */, 0xA08A0896670A5FD7 /* 211 */,
0xCB4A8F4309EBA9CB /* 212 */, 0x81AF564B0F7036A1 /* 213 */,
0xC0B99AA778199ABD /* 214 */, 0x959F1EC83FC8E952 /* 215 */,
0x8C505077794A81B9 /* 216 */, 0x3ACAAF8F056338F0 /* 217 */,
0x07B43F50627A6778 /* 218 */, 0x4A44AB49F5ECCC77 /* 219 */,
0x3BC3D6E4B679EE98 /* 220 */, 0x9CC0D4D1CF14108C /* 221 */,
0x4406C00B206BC8A0 /* 222 */, 0x82A18854C8D72D89 /* 223 */,
0x67E366B35C3C432C /* 224 */, 0xB923DD61102B37F2 /* 225 */,
0x56AB2779D884271D /* 226 */, 0xBE83E1B0FF1525AF /* 227 */,
0xFB7C65D4217E49A9 /* 228 */, 0x6BDBE0E76D48E7D4 /* 229 */,
0x08DF828745D9179E /* 230 */, 0x22EA6A9ADD53BD34 /* 231 */,
0xE36E141C5622200A /* 232 */, 0x7F805D1B8CB750EE /* 233 */,
0xAFE5C7A59F58E837 /* 234 */, 0xE27F996A4FB1C23C /* 235 */,
0xD3867DFB0775F0D0 /* 236 */, 0xD0E673DE6E88891A /* 237 */,
0x123AEB9EAFB86C25 /* 238 */, 0x30F1D5D5C145B895 /* 239 */,
0xBB434A2DEE7269E7 /* 240 */, 0x78CB67ECF931FA38 /* 241 */,
0xF33B0372323BBF9C /* 242 */, 0x52D66336FB279C74 /* 243 */,
0x505F33AC0AFB4EAA /* 244 */, 0xE8A5CD99A2CCE187 /* 245 */,
0x534974801E2D30BB /* 246 */, 0x8D2D5711D5876D90 /* 247 */,
0x1F1A412891BC038E /* 248 */, 0xD6E2E71D82E56648 /* 249 */,
0x74036C3A497732B7 /* 250 */, 0x89B67ED96361F5AB /* 251 */,
0xFFED95D8F1EA02A2 /* 252 */, 0xE72B3BD61464D43D /* 253 */,
0xA6300F170BDC4820 /* 254 */, 0xEBC18760ED78A77A /* 255 */,
0xE6A6BE5A05A12138 /* 256 */, 0xB5A122A5B4F87C98 /* 257 */,
0x563C6089140B6990 /* 258 */, 0x4C46CB2E391F5DD5 /* 259 */,
0xD932ADDBC9B79434 /* 260 */, 0x08EA70E42015AFF5 /* 261 */,
0xD765A6673E478CF1 /* 262 */, 0xC4FB757EAB278D99 /* 263 */,
0xDF11C6862D6E0692 /* 264 */, 0xDDEB84F10D7F3B16 /* 265 */,
0x6F2EF604A665EA04 /* 266 */, 0x4A8E0F0FF0E0DFB3 /* 267 */,
0xA5EDEEF83DBCBA51 /* 268 */, 0xFC4F0A2A0EA4371E /* 269 */,
0xE83E1DA85CB38429 /* 270 */, 0xDC8FF882BA1B1CE2 /* 271 */,
0xCD45505E8353E80D /* 272 */, 0x18D19A00D4DB0717 /* 273 */,
0x34A0CFEDA5F38101 /* 274 */, 0x0BE77E518887CAF2 /* 275 */,
0x1E341438B3C45136 /* 276 */, 0xE05797F49089CCF9 /* 277 */,
0xFFD23F9DF2591D14 /* 278 */, 0x543DDA228595C5CD /* 279 */,
0x661F81FD99052A33 /* 280 */, 0x8736E641DB0F7B76 /* 281 */,
0x15227725418E5307 /* 282 */, 0xE25F7F46162EB2FA /* 283 */,
0x48A8B2126C13D9FE /* 284 */, 0xAFDC541792E76EEA /* 285 */,
0x03D912BFC6D1898F /* 286 */, 0x31B1AAFA1B83F51B /* 287 */,
0xF1AC2796E42AB7D9 /* 288 */, 0x40A3A7D7FCD2EBAC /* 289 */,
0x1056136D0AFBBCC5 /* 290 */, 0x7889E1DD9A6D0C85 /* 291 */,
0xD33525782A7974AA /* 292 */, 0xA7E25D09078AC09B /* 293 */,
0xBD4138B3EAC6EDD0 /* 294 */, 0x920ABFBE71EB9E70 /* 295 */,
0xA2A5D0F54FC2625C /* 296 */, 0xC054E36B0B1290A3 /* 297 */,
0xF6DD59FF62FE932B /* 298 */, 0x3537354511A8AC7D /* 299 */,
0xCA845E9172FADCD4 /* 300 */, 0x84F82B60329D20DC /* 301 */,
0x79C62CE1CD672F18 /* 302 */, 0x8B09A2ADD124642C /* 303 */,
0xD0C1E96A19D9E726 /* 304 */, 0x5A786A9B4BA9500C /* 305 */,
0x0E020336634C43F3 /* 306 */, 0xC17B474AEB66D822 /* 307 */,
0x6A731AE3EC9BAAC2 /* 308 */, 0x8226667AE0840258 /* 309 */,
0x67D4567691CAECA5 /* 310 */, 0x1D94155C4875ADB5 /* 311 */,
0x6D00FD985B813FDF /* 312 */, 0x51286EFCB774CD06 /* 313 */,
0x5E8834471FA744AF /* 314 */, 0xF72CA0AEE761AE2E /* 315 */,
0xBE40E4CDAEE8E09A /* 316 */, 0xE9970BBB5118F665 /* 317 */,
0x726E4BEB33DF1964 /* 318 */, 0x703B000729199762 /* 319 */,
0x4631D816F5EF30A7 /* 320 */, 0xB880B5B51504A6BE /* 321 */,
0x641793C37ED84B6C /* 322 */, 0x7B21ED77F6E97D96 /* 323 */,
0x776306312EF96B73 /* 324 */, 0xAE528948E86FF3F4 /* 325 */,
0x53DBD7F286A3F8F8 /* 326 */, 0x16CADCE74CFC1063 /* 327 */,
0x005C19BDFA52C6DD /* 328 */, 0x68868F5D64D46AD3 /* 329 */,
0x3A9D512CCF1E186A /* 330 */, 0x367E62C2385660AE /* 331 */,
0xE359E7EA77DCB1D7 /* 332 */, 0x526C0773749ABE6E /* 333 */,
0x735AE5F9D09F734B /* 334 */, 0x493FC7CC8A558BA8 /* 335 */,
0xB0B9C1533041AB45 /* 336 */, 0x321958BA470A59BD /* 337 */,
0x852DB00B5F46C393 /* 338 */, 0x91209B2BD336B0E5 /* 339 */,
0x6E604F7D659EF19F /* 340 */, 0xB99A8AE2782CCB24 /* 341 */,
0xCCF52AB6C814C4C7 /* 342 */, 0x4727D9AFBE11727B /* 343 */,
0x7E950D0C0121B34D /* 344 */, 0x756F435670AD471F /* 345 */,
0xF5ADD442615A6849 /* 346 */, 0x4E87E09980B9957A /* 347 */,
0x2ACFA1DF50AEE355 /* 348 */, 0xD898263AFD2FD556 /* 349 */,
0xC8F4924DD80C8FD6 /* 350 */, 0xCF99CA3D754A173A /* 351 */,
0xFE477BACAF91BF3C /* 352 */, 0xED5371F6D690C12D /* 353 */,
0x831A5C285E687094 /* 354 */, 0xC5D3C90A3708A0A4 /* 355 */,
0x0F7F903717D06580 /* 356 */, 0x19F9BB13B8FDF27F /* 357 */,
0xB1BD6F1B4D502843 /* 358 */, 0x1C761BA38FFF4012 /* 359 */,
0x0D1530C4E2E21F3B /* 360 */, 0x8943CE69A7372C8A /* 361 */,
0xE5184E11FEB5CE66 /* 362 */, 0x618BDB80BD736621 /* 363 */,
0x7D29BAD68B574D0B /* 364 */, 0x81BB613E25E6FE5B /* 365 */,
0x071C9C10BC07913F /* 366 */, 0xC7BEEB7909AC2D97 /* 367 */,
0xC3E58D353BC5D757 /* 368 */, 0xEB017892F38F61E8 /* 369 */,
0xD4EFFB9C9B1CC21A /* 370 */, 0x99727D26F494F7AB /* 371 */,
0xA3E063A2956B3E03 /* 372 */, 0x9D4A8B9A4AA09C30 /* 373 */,
0x3F6AB7D500090FB4 /* 374 */, 0x9CC0F2A057268AC0 /* 375 */,
0x3DEE9D2DEDBF42D1 /* 376 */, 0x330F49C87960A972 /* 377 */,
0xC6B2720287421B41 /* 378 */, 0x0AC59EC07C00369C /* 379 */,
0xEF4EAC49CB353425 /* 380 */, 0xF450244EEF0129D8 /* 381 */,
0x8ACC46E5CAF4DEB6 /* 382 */, 0x2FFEAB63989263F7 /* 383 */,
0x8F7CB9FE5D7A4578 /* 384 */, 0x5BD8F7644E634635 /* 385 */,
0x427A7315BF2DC900 /* 386 */, 0x17D0C4AA2125261C /* 387 */,
0x3992486C93518E50 /* 388 */, 0xB4CBFEE0A2D7D4C3 /* 389 */,
0x7C75D6202C5DDD8D /* 390 */, 0xDBC295D8E35B6C61 /* 391 */,
0x60B369D302032B19 /* 392 */, 0xCE42685FDCE44132 /* 393 */,
0x06F3DDB9DDF65610 /* 394 */, 0x8EA4D21DB5E148F0 /* 395 */,
0x20B0FCE62FCD496F /* 396 */, 0x2C1B912358B0EE31 /* 397 */,
0xB28317B818F5A308 /* 398 */, 0xA89C1E189CA6D2CF /* 399 */,
0x0C6B18576AAADBC8 /* 400 */, 0xB65DEAA91299FAE3 /* 401 */,
0xFB2B794B7F1027E7 /* 402 */, 0x04E4317F443B5BEB /* 403 */,
0x4B852D325939D0A6 /* 404 */, 0xD5AE6BEEFB207FFC /* 405 */,
0x309682B281C7D374 /* 406 */, 0xBAE309A194C3B475 /* 407 */,
0x8CC3F97B13B49F05 /* 408 */, 0x98A9422FF8293967 /* 409 */,
0x244B16B01076FF7C /* 410 */, 0xF8BF571C663D67EE /* 411 */,
0x1F0D6758EEE30DA1 /* 412 */, 0xC9B611D97ADEB9B7 /* 413 */,
0xB7AFD5887B6C57A2 /* 414 */, 0x6290AE846B984FE1 /* 415 */,
0x94DF4CDEACC1A5FD /* 416 */, 0x058A5BD1C5483AFF /* 417 */,
0x63166CC142BA3C37 /* 418 */, 0x8DB8526EB2F76F40 /* 419 */,
0xE10880036F0D6D4E /* 420 */, 0x9E0523C9971D311D /* 421 */,
0x45EC2824CC7CD691 /* 422 */, 0x575B8359E62382C9 /* 423 */,
0xFA9E400DC4889995 /* 424 */, 0xD1823ECB45721568 /* 425 */,
0xDAFD983B8206082F /* 426 */, 0xAA7D29082386A8CB /* 427 */,
0x269FCD4403B87588 /* 428 */, 0x1B91F5F728BDD1E0 /* 429 */,
0xE4669F39040201F6 /* 430 */, 0x7A1D7C218CF04ADE /* 431 */,
0x65623C29D79CE5CE /* 432 */, 0x2368449096C00BB1 /* 433 */,
0xAB9BF1879DA503BA /* 434 */, 0xBC23ECB1A458058E /* 435 */,
0x9A58DF01BB401ECC /* 436 */, 0xA070E868A85F143D /* 437 */,
0x4FF188307DF2239E /* 438 */, 0x14D565B41A641183 /* 439 */,
0xEE13337452701602 /* 440 */, 0x950E3DCF3F285E09 /* 441 */,
0x59930254B9C80953 /* 442 */, 0x3BF299408930DA6D /* 443 */,
0xA955943F53691387 /* 444 */, 0xA15EDECAA9CB8784 /* 445 */,
0x29142127352BE9A0 /* 446 */, 0x76F0371FFF4E7AFB /* 447 */,
0x0239F450274F2228 /* 448 */, 0xBB073AF01D5E868B /* 449 */,
0xBFC80571C10E96C1 /* 450 */, 0xD267088568222E23 /* 451 */,
0x9671A3D48E80B5B0 /* 452 */, 0x55B5D38AE193BB81 /* 453 */,
0x693AE2D0A18B04B8 /* 454 */, 0x5C48B4ECADD5335F /* 455 */,
0xFD743B194916A1CA /* 456 */, 0x2577018134BE98C4 /* 457 */,
0xE77987E83C54A4AD /* 458 */, 0x28E11014DA33E1B9 /* 459 */,
0x270CC59E226AA213 /* 460 */, 0x71495F756D1A5F60 /* 461 */,
0x9BE853FB60AFEF77 /* 462 */, 0xADC786A7F7443DBF /* 463 */,
0x0904456173B29A82 /* 464 */, 0x58BC7A66C232BD5E /* 465 */,
0xF306558C673AC8B2 /* 466 */, 0x41F639C6B6C9772A /* 467 */,
0x216DEFE99FDA35DA /* 468 */, 0x11640CC71C7BE615 /* 469 */,
0x93C43694565C5527 /* 470 */, 0xEA038E6246777839 /* 471 */,
0xF9ABF3CE5A3E2469 /* 472 */, 0x741E768D0FD312D2 /* 473 */,
0x0144B883CED652C6 /* 474 */, 0xC20B5A5BA33F8552 /* 475 */,
0x1AE69633C3435A9D /* 476 */, 0x97A28CA4088CFDEC /* 477 */,
0x8824A43C1E96F420 /* 478 */, 0x37612FA66EEEA746 /* 479 */,
0x6B4CB165F9CF0E5A /* 480 */, 0x43AA1C06A0ABFB4A /* 481 */,
0x7F4DC26FF162796B /* 482 */, 0x6CBACC8E54ED9B0F /* 483 */,
0xA6B7FFEFD2BB253E /* 484 */, 0x2E25BC95B0A29D4F /* 485 */,
0x86D6A58BDEF1388C /* 486 */, 0xDED74AC576B6F054 /* 487 */,
0x8030BDBC2B45805D /* 488 */, 0x3C81AF70E94D9289 /* 489 */,
0x3EFF6DDA9E3100DB /* 490 */, 0xB38DC39FDFCC8847 /* 491 */,
0x123885528D17B87E /* 492 */, 0xF2DA0ED240B1B642 /* 493 */,
0x44CEFADCD54BF9A9 /* 494 */, 0x1312200E433C7EE6 /* 495 */,
0x9FFCC84F3A78C748 /* 496 */, 0xF0CD1F72248576BB /* 497 */,
0xEC6974053638CFE4 /* 498 */, 0x2BA7B67C0CEC4E4C /* 499 */,
0xAC2F4DF3E5CE32ED /* 500 */, 0xCB33D14326EA4C11 /* 501 */,
0xA4E9044CC77E58BC /* 502 */, 0x5F513293D934FCEF /* 503 */,
0x5DC9645506E55444 /* 504 */, 0x50DE418F317DE40A /* 505 */,
0x388CB31A69DDE259 /* 506 */, 0x2DB4A83455820A86 /* 507 */,
0x9010A91E84711AE9 /* 508 */, 0x4DF7F0B7B1498371 /* 509 */,
0xD62A2EABC0977179 /* 510 */, 0x22FAC097AA8D5C0E /* 511 */,
0xF49FCC2FF1DAF39B /* 512 */, 0x487FD5C66FF29281 /* 513 */,
0xE8A30667FCDCA83F /* 514 */, 0x2C9B4BE3D2FCCE63 /* 515 */,
0xDA3FF74B93FBBBC2 /* 516 */, 0x2FA165D2FE70BA66 /* 517 */,
0xA103E279970E93D4 /* 518 */, 0xBECDEC77B0E45E71 /* 519 */,
0xCFB41E723985E497 /* 520 */, 0xB70AAA025EF75017 /* 521 */,
0xD42309F03840B8E0 /* 522 */, 0x8EFC1AD035898579 /* 523 */,
0x96C6920BE2B2ABC5 /* 524 */, 0x66AF4163375A9172 /* 525 */,
0x2174ABDCCA7127FB /* 526 */, 0xB33CCEA64A72FF41 /* 527 */,
0xF04A4933083066A5 /* 528 */, 0x8D970ACDD7289AF5 /* 529 */,
0x8F96E8E031C8C25E /* 530 */, 0xF3FEC02276875D47 /* 531 */,
0xEC7BF310056190DD /* 532 */, 0xF5ADB0AEBB0F1491 /* 533 */,
0x9B50F8850FD58892 /* 534 */, 0x4975488358B74DE8 /* 535 */,
0xA3354FF691531C61 /* 536 */, 0x0702BBE481D2C6EE /* 537 */,
0x89FB24057DEDED98 /* 538 */, 0xAC3075138596E902 /* 539 */,
0x1D2D3580172772ED /* 540 */, 0xEB738FC28E6BC30D /* 541 */,
0x5854EF8F63044326 /* 542 */, 0x9E5C52325ADD3BBE /* 543 */,
0x90AA53CF325C4623 /* 544 */, 0xC1D24D51349DD067 /* 545 */,
0x2051CFEEA69EA624 /* 546 */, 0x13220F0A862E7E4F /* 547 */,
0xCE39399404E04864 /* 548 */, 0xD9C42CA47086FCB7 /* 549 */,
0x685AD2238A03E7CC /* 550 */, 0x066484B2AB2FF1DB /* 551 */,
0xFE9D5D70EFBF79EC /* 552 */, 0x5B13B9DD9C481854 /* 553 */,
0x15F0D475ED1509AD /* 554 */, 0x0BEBCD060EC79851 /* 555 */,
0xD58C6791183AB7F8 /* 556 */, 0xD1187C5052F3EEE4 /* 557 */,
0xC95D1192E54E82FF /* 558 */, 0x86EEA14CB9AC6CA2 /* 559 */,
0x3485BEB153677D5D /* 560 */, 0xDD191D781F8C492A /* 561 */,
0xF60866BAA784EBF9 /* 562 */, 0x518F643BA2D08C74 /* 563 */,
0x8852E956E1087C22 /* 564 */, 0xA768CB8DC410AE8D /* 565 */,
0x38047726BFEC8E1A /* 566 */, 0xA67738B4CD3B45AA /* 567 */,
0xAD16691CEC0DDE19 /* 568 */, 0xC6D4319380462E07 /* 569 */,
0xC5A5876D0BA61938 /* 570 */, 0x16B9FA1FA58FD840 /* 571 */,
0x188AB1173CA74F18 /* 572 */, 0xABDA2F98C99C021F /* 573 */,
0x3E0580AB134AE816 /* 574 */, 0x5F3B05B773645ABB /* 575 */,
0x2501A2BE5575F2F6 /* 576 */, 0x1B2F74004E7E8BA9 /* 577 */,
0x1CD7580371E8D953 /* 578 */, 0x7F6ED89562764E30 /* 579 */,
0xB15926FF596F003D /* 580 */, 0x9F65293DA8C5D6B9 /* 581 */,
0x6ECEF04DD690F84C /* 582 */, 0x4782275FFF33AF88 /* 583 */,
0xE41433083F820801 /* 584 */, 0xFD0DFE409A1AF9B5 /* 585 */,
0x4325A3342CDB396B /* 586 */, 0x8AE77E62B301B252 /* 587 */,
0xC36F9E9F6655615A /* 588 */, 0x85455A2D92D32C09 /* 589 */,
0xF2C7DEA949477485 /* 590 */, 0x63CFB4C133A39EBA /* 591 */,
0x83B040CC6EBC5462 /* 592 */, 0x3B9454C8FDB326B0 /* 593 */,
0x56F56A9E87FFD78C /* 594 */, 0x2DC2940D99F42BC6 /* 595 */,
0x98F7DF096B096E2D /* 596 */, 0x19A6E01E3AD852BF /* 597 */,
0x42A99CCBDBD4B40B /* 598 */, 0xA59998AF45E9C559 /* 599 */,
0x366295E807D93186 /* 600 */, 0x6B48181BFAA1F773 /* 601 */,
0x1FEC57E2157A0A1D /* 602 */, 0x4667446AF6201AD5 /* 603 */,
0xE615EBCACFB0F075 /* 604 */, 0xB8F31F4F68290778 /* 605 */,
0x22713ED6CE22D11E /* 606 */, 0x3057C1A72EC3C93B /* 607 */,
0xCB46ACC37C3F1F2F /* 608 */, 0xDBB893FD02AAF50E /* 609 */,
0x331FD92E600B9FCF /* 610 */, 0xA498F96148EA3AD6 /* 611 */,
0xA8D8426E8B6A83EA /* 612 */, 0xA089B274B7735CDC /* 613 */,
0x87F6B3731E524A11 /* 614 */, 0x118808E5CBC96749 /* 615 */,
0x9906E4C7B19BD394 /* 616 */, 0xAFED7F7E9B24A20C /* 617 */,
0x6509EADEEB3644A7 /* 618 */, 0x6C1EF1D3E8EF0EDE /* 619 */,
0xB9C97D43E9798FB4 /* 620 */, 0xA2F2D784740C28A3 /* 621 */,
0x7B8496476197566F /* 622 */, 0x7A5BE3E6B65F069D /* 623 */,
0xF96330ED78BE6F10 /* 624 */, 0xEEE60DE77A076A15 /* 625 */,
0x2B4BEE4AA08B9BD0 /* 626 */, 0x6A56A63EC7B8894E /* 627 */,
0x02121359BA34FEF4 /* 628 */, 0x4CBF99F8283703FC /* 629 */,
0x398071350CAF30C8 /* 630 */, 0xD0A77A89F017687A /* 631 */,
0xF1C1A9EB9E423569 /* 632 */, 0x8C7976282DEE8199 /* 633 */,
0x5D1737A5DD1F7ABD /* 634 */, 0x4F53433C09A9FA80 /* 635 */,
0xFA8B0C53DF7CA1D9 /* 636 */, 0x3FD9DCBC886CCB77 /* 637 */,
0xC040917CA91B4720 /* 638 */, 0x7DD00142F9D1DCDF /* 639 */,
0x8476FC1D4F387B58 /* 640 */, 0x23F8E7C5F3316503 /* 641 */,
0x032A2244E7E37339 /* 642 */, 0x5C87A5D750F5A74B /* 643 */,
0x082B4CC43698992E /* 644 */, 0xDF917BECB858F63C /* 645 */,
0x3270B8FC5BF86DDA /* 646 */, 0x10AE72BB29B5DD76 /* 647 */,
0x576AC94E7700362B /* 648 */, 0x1AD112DAC61EFB8F /* 649 */,
0x691BC30EC5FAA427 /* 650 */, 0xFF246311CC327143 /* 651 */,
0x3142368E30E53206 /* 652 */, 0x71380E31E02CA396 /* 653 */,
0x958D5C960AAD76F1 /* 654 */, 0xF8D6F430C16DA536 /* 655 */,
0xC8FFD13F1BE7E1D2 /* 656 */, 0x7578AE66004DDBE1 /* 657 */,
0x05833F01067BE646 /* 658 */, 0xBB34B5AD3BFE586D /* 659 */,
0x095F34C9A12B97F0 /* 660 */, 0x247AB64525D60CA8 /* 661 */,
0xDCDBC6F3017477D1 /* 662 */, 0x4A2E14D4DECAD24D /* 663 */,
0xBDB5E6D9BE0A1EEB /* 664 */, 0x2A7E70F7794301AB /* 665 */,
0xDEF42D8A270540FD /* 666 */, 0x01078EC0A34C22C1 /* 667 */,
0xE5DE511AF4C16387 /* 668 */, 0x7EBB3A52BD9A330A /* 669 */,
0x77697857AA7D6435 /* 670 */, 0x004E831603AE4C32 /* 671 */,
0xE7A21020AD78E312 /* 672 */, 0x9D41A70C6AB420F2 /* 673 */,
0x28E06C18EA1141E6 /* 674 */, 0xD2B28CBD984F6B28 /* 675 */,
0x26B75F6C446E9D83 /* 676 */, 0xBA47568C4D418D7F /* 677 */,
0xD80BADBFE6183D8E /* 678 */, 0x0E206D7F5F166044 /* 679 */,
0xE258A43911CBCA3E /* 680 */, 0x723A1746B21DC0BC /* 681 */,
0xC7CAA854F5D7CDD3 /* 682 */, 0x7CAC32883D261D9C /* 683 */,
0x7690C26423BA942C /* 684 */, 0x17E55524478042B8 /* 685 */,
0xE0BE477656A2389F /* 686 */, 0x4D289B5E67AB2DA0 /* 687 */,
0x44862B9C8FBBFD31 /* 688 */, 0xB47CC8049D141365 /* 689 */,
0x822C1B362B91C793 /* 690 */, 0x4EB14655FB13DFD8 /* 691 */,
0x1ECBBA0714E2A97B /* 692 */, 0x6143459D5CDE5F14 /* 693 */,
0x53A8FBF1D5F0AC89 /* 694 */, 0x97EA04D81C5E5B00 /* 695 */,
0x622181A8D4FDB3F3 /* 696 */, 0xE9BCD341572A1208 /* 697 */,
0x1411258643CCE58A /* 698 */, 0x9144C5FEA4C6E0A4 /* 699 */,
0x0D33D06565CF620F /* 700 */, 0x54A48D489F219CA1 /* 701 */,
0xC43E5EAC6D63C821 /* 702 */, 0xA9728B3A72770DAF /* 703 */,
0xD7934E7B20DF87EF /* 704 */, 0xE35503B61A3E86E5 /* 705 */,
0xCAE321FBC819D504 /* 706 */, 0x129A50B3AC60BFA6 /* 707 */,
0xCD5E68EA7E9FB6C3 /* 708 */, 0xB01C90199483B1C7 /* 709 */,
0x3DE93CD5C295376C /* 710 */, 0xAED52EDF2AB9AD13 /* 711 */,
0x2E60F512C0A07884 /* 712 */, 0xBC3D86A3E36210C9 /* 713 */,
0x35269D9B163951CE /* 714 */, 0x0C7D6E2AD0CDB5FA /* 715 */,
0x59E86297D87F5733 /* 716 */, 0x298EF221898DB0E7 /* 717 */,
0x55000029D1A5AA7E /* 718 */, 0x8BC08AE1B5061B45 /* 719 */,
0xC2C31C2B6C92703A /* 720 */, 0x94CC596BAF25EF42 /* 721 */,
0x0A1D73DB22540456 /* 722 */, 0x04B6A0F9D9C4179A /* 723 */,
0xEFFDAFA2AE3D3C60 /* 724 */, 0xF7C8075BB49496C4 /* 725 */,
0x9CC5C7141D1CD4E3 /* 726 */, 0x78BD1638218E5534 /* 727 */,
0xB2F11568F850246A /* 728 */, 0xEDFABCFA9502BC29 /* 729 */,
0x796CE5F2DA23051B /* 730 */, 0xAAE128B0DC93537C /* 731 */,
0x3A493DA0EE4B29AE /* 732 */, 0xB5DF6B2C416895D7 /* 733 */,
0xFCABBD25122D7F37 /* 734 */, 0x70810B58105DC4B1 /* 735 */,
0xE10FDD37F7882A90 /* 736 */, 0x524DCAB5518A3F5C /* 737 */,
0x3C9E85878451255B /* 738 */, 0x4029828119BD34E2 /* 739 */,
0x74A05B6F5D3CECCB /* 740 */, 0xB610021542E13ECA /* 741 */,
0x0FF979D12F59E2AC /* 742 */, 0x6037DA27E4F9CC50 /* 743 */,
0x5E92975A0DF1847D /* 744 */, 0xD66DE190D3E623FE /* 745 */,
0x5032D6B87B568048 /* 746 */, 0x9A36B7CE8235216E /* 747 */,
0x80272A7A24F64B4A /* 748 */, 0x93EFED8B8C6916F7 /* 749 */,
0x37DDBFF44CCE1555 /* 750 */, 0x4B95DB5D4B99BD25 /* 751 */,
0x92D3FDA169812FC0 /* 752 */, 0xFB1A4A9A90660BB6 /* 753 */,
0x730C196946A4B9B2 /* 754 */, 0x81E289AA7F49DA68 /* 755 */,
0x64669A0F83B1A05F /* 756 */, 0x27B3FF7D9644F48B /* 757 */,
0xCC6B615C8DB675B3 /* 758 */, 0x674F20B9BCEBBE95 /* 759 */,
0x6F31238275655982 /* 760 */, 0x5AE488713E45CF05 /* 761 */,
0xBF619F9954C21157 /* 762 */, 0xEABAC46040A8EAE9 /* 763 */,
0x454C6FE9F2C0C1CD /* 764 */, 0x419CF6496412691C /* 765 */,
0xD3DC3BEF265B0F70 /* 766 */, 0x6D0E60F5C3578A9E /* 767 */,
0x5B0E608526323C55 /* 768 */, 0x1A46C1A9FA1B59F5 /* 769 */,
0xA9E245A17C4C8FFA /* 770 */, 0x65CA5159DB2955D7 /* 771 */,
0x05DB0A76CE35AFC2 /* 772 */, 0x81EAC77EA9113D45 /* 773 */,
0x528EF88AB6AC0A0D /* 774 */, 0xA09EA253597BE3FF /* 775 */,
0x430DDFB3AC48CD56 /* 776 */, 0xC4B3A67AF45CE46F /* 777 */,
0x4ECECFD8FBE2D05E /* 778 */, 0x3EF56F10B39935F0 /* 779 */,
0x0B22D6829CD619C6 /* 780 */, 0x17FD460A74DF2069 /* 781 */,
0x6CF8CC8E8510ED40 /* 782 */, 0xD6C824BF3A6ECAA7 /* 783 */,
0x61243D581A817049 /* 784 */, 0x048BACB6BBC163A2 /* 785 */,
0xD9A38AC27D44CC32 /* 786 */, 0x7FDDFF5BAAF410AB /* 787 */,
0xAD6D495AA804824B /* 788 */, 0xE1A6A74F2D8C9F94 /* 789 */,
0xD4F7851235DEE8E3 /* 790 */, 0xFD4B7F886540D893 /* 791 */,
0x247C20042AA4BFDA /* 792 */, 0x096EA1C517D1327C /* 793 */,
0xD56966B4361A6685 /* 794 */, 0x277DA5C31221057D /* 795 */,
0x94D59893A43ACFF7 /* 796 */, 0x64F0C51CCDC02281 /* 797 */,
0x3D33BCC4FF6189DB /* 798 */, 0xE005CB184CE66AF1 /* 799 */,
0xFF5CCD1D1DB99BEA /* 800 */, 0xB0B854A7FE42980F /* 801 */,
0x7BD46A6A718D4B9F /* 802 */, 0xD10FA8CC22A5FD8C /* 803 */,
0xD31484952BE4BD31 /* 804 */, 0xC7FA975FCB243847 /* 805 */,
0x4886ED1E5846C407 /* 806 */, 0x28CDDB791EB70B04 /* 807 */,
0xC2B00BE2F573417F /* 808 */, 0x5C9590452180F877 /* 809 */,
0x7A6BDDFFF370EB00 /* 810 */, 0xCE509E38D6D9D6A4 /* 811 */,
0xEBEB0F00647FA702 /* 812 */, 0x1DCC06CF76606F06 /* 813 */,
0xE4D9F28BA286FF0A /* 814 */, 0xD85A305DC918C262 /* 815 */,
0x475B1D8732225F54 /* 816 */, 0x2D4FB51668CCB5FE /* 817 */,
0xA679B9D9D72BBA20 /* 818 */, 0x53841C0D912D43A5 /* 819 */,
0x3B7EAA48BF12A4E8 /* 820 */, 0x781E0E47F22F1DDF /* 821 */,
0xEFF20CE60AB50973 /* 822 */, 0x20D261D19DFFB742 /* 823 */,
0x16A12B03062A2E39 /* 824 */, 0x1960EB2239650495 /* 825 */,
0x251C16FED50EB8B8 /* 826 */, 0x9AC0C330F826016E /* 827 */,
0xED152665953E7671 /* 828 */, 0x02D63194A6369570 /* 829 */,
0x5074F08394B1C987 /* 830 */, 0x70BA598C90B25CE1 /* 831 */,
0x794A15810B9742F6 /* 832 */, 0x0D5925E9FCAF8C6C /* 833 */,
0x3067716CD868744E /* 834 */, 0x910AB077E8D7731B /* 835 */,
0x6A61BBDB5AC42F61 /* 836 */, 0x93513EFBF0851567 /* 837 */,
0xF494724B9E83E9D5 /* 838 */, 0xE887E1985C09648D /* 839 */,
0x34B1D3C675370CFD /* 840 */, 0xDC35E433BC0D255D /* 841 */,
0xD0AAB84234131BE0 /* 842 */, 0x08042A50B48B7EAF /* 843 */,
0x9997C4EE44A3AB35 /* 844 */, 0x829A7B49201799D0 /* 845 */,
0x263B8307B7C54441 /* 846 */, 0x752F95F4FD6A6CA6 /* 847 */,
0x927217402C08C6E5 /* 848 */, 0x2A8AB754A795D9EE /* 849 */,
0xA442F7552F72943D /* 850 */, 0x2C31334E19781208 /* 851 */,
0x4FA98D7CEAEE6291 /* 852 */, 0x55C3862F665DB309 /* 853 */,
0xBD0610175D53B1F3 /* 854 */, 0x46FE6CB840413F27 /* 855 */,
0x3FE03792DF0CFA59 /* 856 */, 0xCFE700372EB85E8F /* 857 */,
0xA7BE29E7ADBCE118 /* 858 */, 0xE544EE5CDE8431DD /* 859 */,
0x8A781B1B41F1873E /* 860 */, 0xA5C94C78A0D2F0E7 /* 861 */,
0x39412E2877B60728 /* 862 */, 0xA1265EF3AFC9A62C /* 863 */,
0xBCC2770C6A2506C5 /* 864 */, 0x3AB66DD5DCE1CE12 /* 865 */,
0xE65499D04A675B37 /* 866 */, 0x7D8F523481BFD216 /* 867 */,
0x0F6F64FCEC15F389 /* 868 */, 0x74EFBE618B5B13C8 /* 869 */,
0xACDC82B714273E1D /* 870 */, 0xDD40BFE003199D17 /* 871 */,
0x37E99257E7E061F8 /* 872 */, 0xFA52626904775AAA /* 873 */,
0x8BBBF63A463D56F9 /* 874 */, 0xF0013F1543A26E64 /* 875 */,
0xA8307E9F879EC898 /* 876 */, 0xCC4C27A4150177CC /* 877 */,
0x1B432F2CCA1D3348 /* 878 */, 0xDE1D1F8F9F6FA013 /* 879 */,
0x606602A047A7DDD6 /* 880 */, 0xD237AB64CC1CB2C7 /* 881 */,
0x9B938E7225FCD1D3 /* 882 */, 0xEC4E03708E0FF476 /* 883 */,
0xFEB2FBDA3D03C12D /* 884 */, 0xAE0BCED2EE43889A /* 885 */,
0x22CB8923EBFB4F43 /* 886 */, 0x69360D013CF7396D /* 887 */,
0x855E3602D2D4E022 /* 888 */, 0x073805BAD01F784C /* 889 */,
0x33E17A133852F546 /* 890 */, 0xDF4874058AC7B638 /* 891 */,
0xBA92B29C678AA14A /* 892 */, 0x0CE89FC76CFAADCD /* 893 */,
0x5F9D4E0908339E34 /* 894 */, 0xF1AFE9291F5923B9 /* 895 */,
0x6E3480F60F4A265F /* 896 */, 0xEEBF3A2AB29B841C /* 897 */,
0xE21938A88F91B4AD /* 898 */, 0x57DFEFF845C6D3C3 /* 899 */,
0x2F006B0BF62CAAF2 /* 900 */, 0x62F479EF6F75EE78 /* 901 */,
0x11A55AD41C8916A9 /* 902 */, 0xF229D29084FED453 /* 903 */,
0x42F1C27B16B000E6 /* 904 */, 0x2B1F76749823C074 /* 905 */,
0x4B76ECA3C2745360 /* 906 */, 0x8C98F463B91691BD /* 907 */,
0x14BCC93CF1ADE66A /* 908 */, 0x8885213E6D458397 /* 909 */,
0x8E177DF0274D4711 /* 910 */, 0xB49B73B5503F2951 /* 911 */,
0x10168168C3F96B6B /* 912 */, 0x0E3D963B63CAB0AE /* 913 */,
0x8DFC4B5655A1DB14 /* 914 */, 0xF789F1356E14DE5C /* 915 */,
0x683E68AF4E51DAC1 /* 916 */, 0xC9A84F9D8D4B0FD9 /* 917 */,
0x3691E03F52A0F9D1 /* 918 */, 0x5ED86E46E1878E80 /* 919 */,
0x3C711A0E99D07150 /* 920 */, 0x5A0865B20C4E9310 /* 921 */,
0x56FBFC1FE4F0682E /* 922 */, 0xEA8D5DE3105EDF9B /* 923 */,
0x71ABFDB12379187A /* 924 */, 0x2EB99DE1BEE77B9C /* 925 */,
0x21ECC0EA33CF4523 /* 926 */, 0x59A4D7521805C7A1 /* 927 */,
0x3896F5EB56AE7C72 /* 928 */, 0xAA638F3DB18F75DC /* 929 */,
0x9F39358DABE9808E /* 930 */, 0xB7DEFA91C00B72AC /* 931 */,
0x6B5541FD62492D92 /* 932 */, 0x6DC6DEE8F92E4D5B /* 933 */,
0x353F57ABC4BEEA7E /* 934 */, 0x735769D6DA5690CE /* 935 */,
0x0A234AA642391484 /* 936 */, 0xF6F9508028F80D9D /* 937 */,
0xB8E319A27AB3F215 /* 938 */, 0x31AD9C1151341A4D /* 939 */,
0x773C22A57BEF5805 /* 940 */, 0x45C7561A07968633 /* 941 */,
0xF913DA9E249DBE36 /* 942 */, 0xDA652D9B78A64C68 /* 943 */,
0x4C27A97F3BC334EF /* 944 */, 0x76621220E66B17F4 /* 945 */,
0x967743899ACD7D0B /* 946 */, 0xF3EE5BCAE0ED6782 /* 947 */,
0x409F753600C879FC /* 948 */, 0x06D09A39B5926DB6 /* 949 */,
0x6F83AEB0317AC588 /* 950 */, 0x01E6CA4A86381F21 /* 951 */,
0x66FF3462D19F3025 /* 952 */, 0x72207C24DDFD3BFB /* 953 */,
0x4AF6B6D3E2ECE2EB /* 954 */, 0x9C994DBEC7EA08DE /* 955 */,
0x49ACE597B09A8BC4 /* 956 */, 0xB38C4766CF0797BA /* 957 */,
0x131B9373C57C2A75 /* 958 */, 0xB1822CCE61931E58 /* 959 */,
0x9D7555B909BA1C0C /* 960 */, 0x127FAFDD937D11D2 /* 961 */,
0x29DA3BADC66D92E4 /* 962 */, 0xA2C1D57154C2ECBC /* 963 */,
0x58C5134D82F6FE24 /* 964 */, 0x1C3AE3515B62274F /* 965 */,
0xE907C82E01CB8126 /* 966 */, 0xF8ED091913E37FCB /* 967 */,
0x3249D8F9C80046C9 /* 968 */, 0x80CF9BEDE388FB63 /* 969 */,
0x1881539A116CF19E /* 970 */, 0x5103F3F76BD52457 /* 971 */,
0x15B7E6F5AE47F7A8 /* 972 */, 0xDBD7C6DED47E9CCF /* 973 */,
0x44E55C410228BB1A /* 974 */, 0xB647D4255EDB4E99 /* 975 */,
0x5D11882BB8AAFC30 /* 976 */, 0xF5098BBB29D3212A /* 977 */,
0x8FB5EA14E90296B3 /* 978 */, 0x677B942157DD025A /* 979 */,
0xFB58E7C0A390ACB5 /* 980 */, 0x89D3674C83BD4A01 /* 981 */,
0x9E2DA4DF4BF3B93B /* 982 */, 0xFCC41E328CAB4829 /* 983 */,
0x03F38C96BA582C52 /* 984 */, 0xCAD1BDBD7FD85DB2 /* 985 */,
0xBBB442C16082AE83 /* 986 */, 0xB95FE86BA5DA9AB0 /* 987 */,
0xB22E04673771A93F /* 988 */, 0x845358C9493152D8 /* 989 */,
0xBE2A488697B4541E /* 990 */, 0x95A2DC2DD38E6966 /* 991 */,
0xC02C11AC923C852B /* 992 */, 0x2388B1990DF2A87B /* 993 */,
0x7C8008FA1B4F37BE /* 994 */, 0x1F70D0C84D54E503 /* 995 */,
0x5490ADEC7ECE57D4 /* 996 */, 0x002B3C27D9063A3A /* 997 */,
0x7EAEA3848030A2BF /* 998 */, 0xC602326DED2003C0 /* 999 */,
0x83A7287D69A94086 /* 1000 */, 0xC57A5FCB30F57A8A /* 1001 */,
0xB56844E479EBE779 /* 1002 */, 0xA373B40F05DCBCE9 /* 1003 */,
0xD71A786E88570EE2 /* 1004 */, 0x879CBACDBDE8F6A0 /* 1005 */,
0x976AD1BCC164A32F /* 1006 */, 0xAB21E25E9666D78B /* 1007 */,
0x901063AAE5E5C33C /* 1008 */, 0x9818B34448698D90 /* 1009 */,
0xE36487AE3E1E8ABB /* 1010 */, 0xAFBDF931893BDCB4 /* 1011 */,
0x6345A0DC5FBBD519 /* 1012 */, 0x8628FE269B9465CA /* 1013 */,
0x1E5D01603F9C51EC /* 1014 */, 0x4DE44006A15049B7 /* 1015 */,
0xBF6C70E5F776CBB1 /* 1016 */, 0x411218F2EF552BED /* 1017 */,
0xCB0C0708705A36A3 /* 1018 */, 0xE74D14754F986044 /* 1019 */,
0xCD56D9430EA8280E /* 1020 */, 0xC12591D7535F5065 /* 1021 */,
0xC83223F1720AEF96 /* 1022 */, 0xC3A0396F7363A51F /* 1023 */
];
}
}

View File

@@ -0,0 +1,185 @@
using System;
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 = new ulong[8];
Array.Copy(str, strOffset, x, 0, 8);
// 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];
}
}

36
publish-nix.sh Normal file
View File

@@ -0,0 +1,36 @@
#! /bin/bash
# This batch file assumes the following:
# - .NET 8.0 (or newer) SDK is installed and in PATH
#
# If any of these are not satisfied, the operation may fail
# in an unpredictable way and result in an incomplete output.
# Optional parameters
NO_BUILD=false
while getopts "uba" OPTION
do
case $OPTION in
b)
NO_BUILD=true
;;
*)
echo "Invalid option provided"
exit 1
;;
esac
done
# Set the current directory as a variable
BUILD_FOLDER=$PWD
# Only build if requested
if [ $NO_BUILD = false ]
then
# Restore Nuget packages for all builds
echo "Restoring Nuget packages"
dotnet restore
# Create Nuget Package
dotnet pack SabreTools.Hashing/SabreTools.Hashing.csproj --output $BUILD_FOLDER
fi

26
publish-win.ps1 Normal file
View File

@@ -0,0 +1,26 @@
# This batch file assumes the following:
# - .NET 8.0 (or newer) SDK is installed and in PATH
#
# If any of these are not satisfied, the operation may fail
# in an unpredictable way and result in an incomplete output.
# Optional parameters
param(
[Parameter(Mandatory = $false)]
[Alias("NoBuild")]
[switch]$NO_BUILD
)
# Set the current directory as a variable
$BUILD_FOLDER = $PSScriptRoot
# Only build if requested
if (!$NO_BUILD.IsPresent)
{
# Restore Nuget packages for all builds
Write-Host "Restoring Nuget packages"
dotnet restore
# Create Nuget Package
dotnet pack SabreTools.Hashing\SabreTools.Hashing.csproj --output $BUILD_FOLDER
}