mirror of
https://github.com/SabreTools/SabreTools.Hashing.git
synced 2026-02-09 05:35:34 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd612f939a | ||
|
|
8e3a0f77e9 | ||
|
|
40cfa78be4 | ||
|
|
4d92c7cd23 | ||
|
|
acf1e3ec71 | ||
|
|
10027f78e3 | ||
|
|
187932b091 | ||
|
|
89dbe0460f | ||
|
|
365ee9019f | ||
|
|
e117892f37 | ||
|
|
1e11e9abb8 | ||
|
|
1d2985023d | ||
|
|
cfddb3dab4 | ||
|
|
08512abc59 | ||
|
|
71a330cf68 | ||
|
|
ad8d119905 | ||
|
|
c82a6dc39b | ||
|
|
414759cbd2 | ||
|
|
142ca6f327 | ||
|
|
8dee2e2501 | ||
|
|
240098dd03 | ||
|
|
15a022eca5 | ||
|
|
0ede92a5d9 | ||
|
|
0c3815e17c | ||
|
|
8f5bff0375 | ||
|
|
dc3cb0be5d | ||
|
|
f7346b20e1 | ||
|
|
f971fcf5c8 | ||
|
|
4e0da77cb4 | ||
|
|
7776112ec6 | ||
|
|
c65184689d | ||
|
|
704e08b5ed | ||
|
|
99f770ce81 | ||
|
|
e5fea69815 | ||
|
|
80448302e8 | ||
|
|
434a10d3db | ||
|
|
4ea5f95b5e | ||
|
|
381dffccf9 | ||
|
|
d4885d389d | ||
|
|
f0adc62394 | ||
|
|
d7790ac4e1 | ||
|
|
70b145c633 | ||
|
|
4e9d7fc927 |
@@ -1,4 +1,4 @@
|
||||
name: Nuget Pack
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -16,31 +16,22 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build library
|
||||
run: dotnet build
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: 'SabreTools.Hashing/bin/Release/*.nupkg'
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: 'SabreTools.Hashing/bin/Release/*.nupkg'
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
7
.github/workflows/check_pr.yml
vendored
7
.github/workflows/check_pr.yml
vendored
@@ -11,10 +11,13 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
run: dotnet test
|
||||
|
||||
14
README.MD
14
README.MD
@@ -1,7 +1,17 @@
|
||||
# SabreTools.Hashing
|
||||
|
||||
[](https://github.com/SabreTools/SabreTools.Hashing/actions/workflows/build_and_test.yml)
|
||||
|
||||
This library comprises of methods and helpers to simplify the process of getting checksums and hashes from both files and streams.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).
|
||||
|
||||
## Releases
|
||||
|
||||
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.Hashing/releases)
|
||||
|
||||
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.Hashing/releases/rolling)
|
||||
|
||||
## Internal Implementations
|
||||
|
||||
All hash and checksum types here have been written to ensure compatibility across all .NET versions. Some may have been adapted to ensure this compatibility. These can be treated as reference implementations, not always optimized.
|
||||
@@ -14,6 +24,7 @@ All hash and checksum types here have been written to ensure compatibility acros
|
||||
| FNV | 32-, and 64-bit variants; 0, 1, and 1a algorithms |
|
||||
| Message Digest | MD2 and MD4 only |
|
||||
| RIPEMD | 128-, 160-, 256-, and 320-bit variants |
|
||||
| SpamSum | Based on the [SSDEEP source code](https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c) |
|
||||
| Tiger | 128-, 160-, and 192-bit variants; 3- and 4-pass; `0x01` and `0x80` (Tiger2) pad-initialized |
|
||||
| xxHash | xxHash-32 and xxHash-64 only |
|
||||
|
||||
@@ -23,11 +34,8 @@ External implementations of hash and checksum types may not be compatible with a
|
||||
|
||||
| Source | Hash / Checksum Types | Notes |
|
||||
| --- | --- | --- |
|
||||
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | SpamSum | Some code tweaks made to support older .NET versions |
|
||||
| [Blake3.NET](https://github.com/xoofx/Blake3.NET) | BLAKE3 | Used in `net7.0` and above |
|
||||
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | XXH3, XXH128 | Used in `net462` and above |
|
||||
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
|
||||
|
||||
**Note:** If all you care about is performance, I encourage you to forego this library and use the ones listed above directly instead.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace SabreTools.Hashing.Test
|
||||
public void GetSingleGzipStreamHashesTest()
|
||||
{
|
||||
var gzipStream = new GZipStream(File.OpenRead(_singleGzipFilePath), CompressionMode.Decompress);
|
||||
var hashDict = HashTool.GetStreamHashes(gzipStream);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(gzipStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
@@ -38,7 +39,8 @@ namespace SabreTools.Hashing.Test
|
||||
{
|
||||
var zipFile = ZipFile.OpenRead(_singleZipFilePath);
|
||||
var fileStream = zipFile.Entries[0].Open();
|
||||
var hashDict = HashTool.GetStreamHashes(fileStream);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
@@ -50,7 +52,8 @@ namespace SabreTools.Hashing.Test
|
||||
for (int i = 0; i < zipFile.Entries.Count; i++)
|
||||
{
|
||||
var fileStream = zipFile.Entries[i].Open();
|
||||
var hashDict = HashTool.GetStreamHashes(fileStream);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace SabreTools.Hashing.Test
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardHashesTest()
|
||||
public void GetStandardHashesFileTest()
|
||||
{
|
||||
bool gotHashes = HashTool.GetStandardHashes(_hashFilePath, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
@@ -43,6 +43,32 @@ namespace SabreTools.Hashing.Test
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardHashesArrayTest()
|
||||
{
|
||||
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
|
||||
bool gotHashes = HashTool.GetStandardHashes(fileBytes, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
Assert.True(gotHashes);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHash(HashType.CRC32, crc32);
|
||||
TestHelper.ValidateHash(HashType.MD5, md5);
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardHashesStreamTest()
|
||||
{
|
||||
var fileStream = File.OpenRead(_hashFilePath);
|
||||
bool gotHashes = HashTool.GetStandardHashes(fileStream, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
Assert.True(gotHashes);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHash(HashType.CRC32, crc32);
|
||||
TestHelper.ValidateHash(HashType.MD5, md5);
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFileHashesParallelTest()
|
||||
{
|
||||
@@ -74,6 +100,15 @@ namespace SabreTools.Hashing.Test
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetByteArrayHashesAndSizeTest()
|
||||
{
|
||||
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
|
||||
var hashDict = HashTool.GetByteArrayHashesAndSize(fileBytes, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStreamHashesTest()
|
||||
{
|
||||
@@ -81,5 +116,14 @@ namespace SabreTools.Hashing.Test
|
||||
var hashDict = HashTool.GetStreamHashes(fileStream);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStreamHashesAndSizeTest()
|
||||
{
|
||||
var fileStream = File.OpenRead(_hashFilePath);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;net48;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
@@ -20,14 +20,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.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">
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -1,579 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : SpamSumContext.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the SpamSum fuzzy hashing algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
// Based on ssdeep
|
||||
// Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
|
||||
// Copyright (C) 2006 ManTech International Corporation
|
||||
// Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
|
||||
//
|
||||
// Earlier versions of this code were named fuzzy.c and can be found at:
|
||||
// http://www.samba.org/ftp/unpacked/junkcode/spamsum/
|
||||
// http://ssdeep.sf.net/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the SpamSum fuzzy hashing algorithm.</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")]
|
||||
internal sealed class SpamSumContext : IChecksum
|
||||
{
|
||||
const uint ROLLING_WINDOW = 7;
|
||||
const uint MIN_BLOCKSIZE = 3;
|
||||
const uint HASH_PRIME = 0x01000193;
|
||||
const uint HASH_INIT = 0x28021967;
|
||||
const uint NUM_BLOCKHASHES = 31;
|
||||
const uint SPAMSUM_LENGTH = 64;
|
||||
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
|
||||
|
||||
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
#if NET20 || NET35 || NET40 || NET452
|
||||
readonly byte[] _b64 = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||||
#else
|
||||
readonly byte[] _b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"u8.ToArray();
|
||||
#endif
|
||||
FuzzyState _self;
|
||||
|
||||
/// <summary>Initializes the SpamSum structures</summary>
|
||||
public SpamSumContext()
|
||||
{
|
||||
_self = new FuzzyState
|
||||
{
|
||||
Bh = new BlockhashContext[NUM_BLOCKHASHES]
|
||||
};
|
||||
|
||||
for (var i = 0; i < NUM_BLOCKHASHES; i++)
|
||||
_self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
|
||||
|
||||
_self.Bhstart = 0;
|
||||
_self.Bhend = 1;
|
||||
_self.Bh[0].H = HASH_INIT;
|
||||
_self.Bh[0].Halfh = HASH_INIT;
|
||||
_self.Bh[0].Digest[0] = 0;
|
||||
_self.Bh[0].Halfdigest = 0;
|
||||
_self.Bh[0].Dlen = 0;
|
||||
_self.TotalSize = 0;
|
||||
roll_init();
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "SpamSum";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("DA692981-3291-47D8-B8B9-A87F0605F6E9");
|
||||
|
||||
/// <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)
|
||||
{
|
||||
_self.TotalSize += len;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
fuzzy_engine_step(data[i]);
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a base64 representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return CToString(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void roll_init() => _self.Roll = new RollState
|
||||
{
|
||||
Window = new byte[ROLLING_WINDOW]
|
||||
};
|
||||
|
||||
/*
|
||||
* a rolling hash, based on the Adler checksum. By using a rolling hash
|
||||
* we can perform auto resynchronisation after inserts/deletes
|
||||
|
||||
* internally, h1 is the sum of the bytes in the window and h2
|
||||
* is the sum of the bytes times the index
|
||||
|
||||
* h3 is a shift/xor based rolling hash, and is mostly needed to ensure that
|
||||
* we can cope with large blocksize values
|
||||
*/
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void roll_hash(byte c)
|
||||
{
|
||||
_self.Roll.H2 -= _self.Roll.H1;
|
||||
_self.Roll.H2 += ROLLING_WINDOW * c;
|
||||
|
||||
_self.Roll.H1 += c;
|
||||
_self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW];
|
||||
|
||||
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c;
|
||||
_self.Roll.N++;
|
||||
|
||||
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
|
||||
* in theory should have no effect. This AND has been removed
|
||||
* for performance (jk) */
|
||||
_self.Roll.H3 <<= 5;
|
||||
_self.Roll.H3 ^= c;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
uint roll_sum() => _self.Roll.H1 + _self.Roll.H2 + _self.Roll.H3;
|
||||
|
||||
/* A simple non-rolling hash, based on the FNV hash. */
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static uint sum_hash(byte c, uint h) => h * HASH_PRIME ^ c;
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_try_fork_blockhash()
|
||||
{
|
||||
switch (_self.Bhend)
|
||||
{
|
||||
case >= NUM_BLOCKHASHES:
|
||||
return;
|
||||
|
||||
// assert
|
||||
case 0:
|
||||
throw new Exception("Assertion failed");
|
||||
}
|
||||
|
||||
uint obh = _self.Bhend - 1;
|
||||
uint nbh = _self.Bhend;
|
||||
_self.Bh[nbh].H = _self.Bh[obh].H;
|
||||
_self.Bh[nbh].Halfh = _self.Bh[obh].Halfh;
|
||||
_self.Bh[nbh].Digest[0] = 0;
|
||||
_self.Bh[nbh].Halfdigest = 0;
|
||||
_self.Bh[nbh].Dlen = 0;
|
||||
++_self.Bhend;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_try_reduce_blockhash()
|
||||
{
|
||||
if (_self.Bhstart >= _self.Bhend)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
if (_self.Bhend - _self.Bhstart < 2)
|
||||
/* Need at least two working hashes. */
|
||||
return;
|
||||
|
||||
if ((ulong)SSDEEP_BS(_self.Bhstart) * SPAMSUM_LENGTH >= _self.TotalSize)
|
||||
/* Initial blocksize estimate would select this or a smaller
|
||||
* blocksize. */
|
||||
return;
|
||||
|
||||
if (_self.Bh[_self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
|
||||
/* Estimate adjustment would select this blocksize. */
|
||||
return;
|
||||
|
||||
/* At this point we are clearly no longer interested in the
|
||||
* start_blocksize. Get rid of it. */
|
||||
++_self.Bhstart;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_engine_step(byte c)
|
||||
{
|
||||
uint i;
|
||||
/* At each character we update the rolling hash and the normal hashes.
|
||||
* When the rolling hash hits a reset value then we emit a normal hash
|
||||
* as a element of the signature and reset the normal hash. */
|
||||
roll_hash(c);
|
||||
ulong h = roll_sum();
|
||||
|
||||
for (i = _self.Bhstart; i < _self.Bhend; ++i)
|
||||
{
|
||||
_self.Bh[i].H = sum_hash(c, _self.Bh[i].H);
|
||||
_self.Bh[i].Halfh = sum_hash(c, _self.Bh[i].Halfh);
|
||||
}
|
||||
|
||||
for (i = _self.Bhstart; i < _self.Bhend; ++i)
|
||||
{
|
||||
/* With growing blocksize almost no runs fail the next test. */
|
||||
if (h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1)
|
||||
/* Once this condition is false for one bs, it is
|
||||
* automatically false for all further bs. I.e. if
|
||||
* h === -1 (mod 2*bs) then h === -1 (mod bs). */
|
||||
break;
|
||||
|
||||
/* We have hit a reset point. We now emit hashes which are
|
||||
* based on all characters in the piece of the message between
|
||||
* the last reset point and this one */
|
||||
if (0 == _self.Bh[i].Dlen)
|
||||
fuzzy_try_fork_blockhash();
|
||||
|
||||
_self.Bh[i].Digest[_self.Bh[i].Dlen] = _b64[_self.Bh[i].H % 64];
|
||||
_self.Bh[i].Halfdigest = _b64[_self.Bh[i].Halfh % 64];
|
||||
|
||||
if (_self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
|
||||
{
|
||||
/* We can have a problem with the tail overflowing. The
|
||||
* easiest way to cope with this is to only reset the
|
||||
* normal hash if we have room for more characters in
|
||||
* our signature. This has the effect of combining the
|
||||
* last few pieces of the message into a single piece
|
||||
* */
|
||||
_self.Bh[i].Digest[++_self.Bh[i].Dlen] = 0;
|
||||
_self.Bh[i].H = HASH_INIT;
|
||||
|
||||
if (_self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2)
|
||||
continue;
|
||||
|
||||
_self.Bh[i].Halfh = HASH_INIT;
|
||||
_self.Bh[i].Halfdigest = 0;
|
||||
}
|
||||
else
|
||||
fuzzy_try_reduce_blockhash();
|
||||
}
|
||||
}
|
||||
|
||||
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void FuzzyDigest(out byte[] result)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
uint bi = _self.Bhstart;
|
||||
uint h = roll_sum();
|
||||
var remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
|
||||
result = new byte[FUZZY_MAX_RESULT];
|
||||
|
||||
/* Verify that our elimination was not overeager. */
|
||||
if (!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < _self.TotalSize))
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
/* Initial blocksize guess. */
|
||||
while ((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _self.TotalSize)
|
||||
{
|
||||
++bi;
|
||||
|
||||
if (bi >= NUM_BLOCKHASHES)
|
||||
throw new OverflowException("The input exceeds data types");
|
||||
}
|
||||
|
||||
/* Adapt blocksize guess to actual digest length. */
|
||||
while (bi >= _self.Bhend)
|
||||
--bi;
|
||||
|
||||
while (bi > _self.Bhstart && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
|
||||
--bi;
|
||||
|
||||
if (bi > 0 && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
sb.Append($"{SSDEEP_BS(bi)}:");
|
||||
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
|
||||
|
||||
if (i <= 0)
|
||||
/* Maybe snprintf has set errno here? */
|
||||
throw new OverflowException("The input exceeds data types");
|
||||
|
||||
if (i >= remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
remain -= i;
|
||||
|
||||
Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i);
|
||||
|
||||
int resultOff = i;
|
||||
|
||||
i = (int)_self.Bh[bi].Dlen;
|
||||
|
||||
if (i > remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = _b64[_self.Bh[bi].H % 64];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else if (_self.Bh[bi].Digest[i] != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = _self.Bh[bi].Digest[i];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff++] = 0x3A; // ':'
|
||||
--remain;
|
||||
|
||||
if (bi < _self.Bhend - 1)
|
||||
{
|
||||
++bi;
|
||||
i = (int)_self.Bh[bi].Dlen;
|
||||
|
||||
if (i > remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
h = _self.Bh[bi].Halfh;
|
||||
result[resultOff] = _b64[h % 64];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _self.Bh[bi].Halfdigest;
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = (byte)i;
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (h != 0)
|
||||
{
|
||||
if (_self.Bh[bi].Dlen != 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff++] = _b64[_self.Bh[bi].H % 64];
|
||||
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
|
||||
* digest has length 1. */
|
||||
--remain;
|
||||
}
|
||||
|
||||
result[resultOff] = 0;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename) =>
|
||||
throw new NotImplementedException("SpamSum does not have a binary representation.");
|
||||
|
||||
/// <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) =>
|
||||
throw new NotImplementedException("Not yet implemented.");
|
||||
|
||||
/// <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">null</param>
|
||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
||||
public static string Data(byte[] data, uint len, out byte[]? hash)
|
||||
{
|
||||
var fuzzyContext = new SpamSumContext();
|
||||
|
||||
fuzzyContext.Update(data, len);
|
||||
|
||||
hash = null;
|
||||
|
||||
return fuzzyContext.End();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">null</param>
|
||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
||||
public static string Data(byte[] data, out byte[]? hash) => Data(data, (uint)data.Length, out hash);
|
||||
|
||||
// Converts an ASCII null-terminated string to .NET string
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static string CToString(byte[] cString)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
// LINQ is six times slower
|
||||
foreach (byte c in cString)
|
||||
{
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return Encoding.ASCII.GetString(cString, 0, count);
|
||||
}
|
||||
|
||||
#region Nested type: BlockhashContext
|
||||
|
||||
/* A blockhash contains a signature state for a specific (implicit) blocksize.
|
||||
* The blocksize is given by SSDEEP_BS(index). The h and halfh members are the
|
||||
* FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2
|
||||
* long. The halfh hash is needed be able to truncate digest for the second
|
||||
* output hash to stay compatible with ssdeep output. */
|
||||
struct BlockhashContext
|
||||
{
|
||||
public uint H;
|
||||
public uint Halfh;
|
||||
public byte[] Digest;
|
||||
|
||||
// SPAMSUM_LENGTH
|
||||
public byte Halfdigest;
|
||||
public uint Dlen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: FuzzyState
|
||||
|
||||
struct FuzzyState
|
||||
{
|
||||
public uint Bhstart;
|
||||
public uint Bhend;
|
||||
public BlockhashContext[] Bh;
|
||||
|
||||
//NUM_BLOCKHASHES
|
||||
public ulong TotalSize;
|
||||
public RollState Roll;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: RollState
|
||||
|
||||
struct RollState
|
||||
{
|
||||
public byte[] Window;
|
||||
|
||||
// ROLLING_WINDOW
|
||||
public uint H1;
|
||||
public uint H2;
|
||||
public uint H3;
|
||||
public uint N;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : IChecksum.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Provides an interface for implementing checksums and hashes.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aaru.CommonTypes.Interfaces;
|
||||
|
||||
/// <summary>Defines the interface to implement a checksum or hashing algorithm</summary>
|
||||
internal interface IChecksum
|
||||
{
|
||||
/// <summary>Plugin author</summary>
|
||||
string Author { get; }
|
||||
|
||||
/// <summary>Plugin name.</summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>Plugin UUID.</summary>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
void Update(byte[] data, uint len);
|
||||
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
void Update(byte[] data);
|
||||
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
byte[] Final();
|
||||
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
string End();
|
||||
}
|
||||
@@ -6,21 +6,24 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <see href="https://github.com/madler/zlib/blob/v1.2.11/adler32.c"/>
|
||||
public class Adler32 : ChecksumBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public Adler32()
|
||||
{
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = 1;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Adler-32 into component sums
|
||||
uint sum2 = (_hash >> 16) & 0xffff;
|
||||
@@ -131,9 +134,11 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] Finalize()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
return BitConverter.GetBytes(_hash);
|
||||
byte[] hashArr = BitConverter.GetBytes(_hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,9 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <summary>
|
||||
/// Common base class for Fletcher checksums
|
||||
/// </summary>
|
||||
public abstract class ChecksumBase
|
||||
public abstract class ChecksumBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public abstract void TransformBlock(byte[] data, int offset, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the hash and return as a byte array
|
||||
/// </summary>
|
||||
public abstract byte[] Finalize();
|
||||
// No common, untyped functionality
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,18 +20,16 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// </summary>
|
||||
protected T _hash;
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public virtual void Reset()
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] Finalize()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
return _hash switch
|
||||
byte[] hashArr = _hash switch
|
||||
{
|
||||
short s => BitConverter.GetBytes(s),
|
||||
ushort s => BitConverter.GetBytes(s),
|
||||
@@ -55,6 +42,9 @@ namespace SabreTools.Hashing.Checksum
|
||||
|
||||
_ => [],
|
||||
};
|
||||
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
#region Adler-32 / Fletcher-32
|
||||
#region Adler-32
|
||||
|
||||
/// <summary>
|
||||
/// Largest prime smaller than 65536
|
||||
@@ -14,6 +14,10 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// </summary>
|
||||
public const ushort A32NMAX = 5552;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fletcher-32
|
||||
|
||||
/// <summary>
|
||||
/// Max value for a single half of a Fletcher-32 checksum
|
||||
/// </summary>
|
||||
@@ -25,15 +29,5 @@ namespace SabreTools.Hashing.Checksum
|
||||
public const uint F64BASE = 0xffffffff;
|
||||
|
||||
#endregion
|
||||
|
||||
#region FNV
|
||||
|
||||
public const uint FNV32Basis = 0x811c9dc5;
|
||||
public const ulong FNV64Basis = 0xcbf29ce484222325;
|
||||
|
||||
public const uint FNV32Prime = 0x01000193;
|
||||
public const ulong FNV64Prime = 0x00000100000001b3;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
public class Crc : ChecksumBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => Def.Width;
|
||||
|
||||
/// <summary>
|
||||
/// Definition used to create the runner
|
||||
/// </summary>
|
||||
@@ -27,17 +30,17 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Reset()
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = Def.Init;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _table.TransformBlock(ref _hash, data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] Finalize()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Create a copy of the hash
|
||||
ulong localHash = _hash;
|
||||
@@ -53,4 +56,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
return BitOperations.ClampValueToBytes(localHash, Def.Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,4 +62,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// </summary>
|
||||
public ulong XorOut { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,4 +330,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
hash = local;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,20 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
|
||||
public class Fletcher16 : ChecksumBase<ushort>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 16;
|
||||
|
||||
public Fletcher16()
|
||||
{
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split the existing hash
|
||||
uint c0 = (uint)(_hash & 0x00FF);
|
||||
uint c1 = (uint)(_hash << 16);
|
||||
uint c0 = (uint)(_hash & 0x00ff);
|
||||
uint c1 = (uint)((_hash >> 8) & 0x00ff);
|
||||
|
||||
// Found by solving for c1 overflow:
|
||||
// n > 0 and n * (n+1) / 2 * (2^8-1) < (2^32-1).
|
||||
@@ -34,7 +37,8 @@ namespace SabreTools.Hashing.Checksum
|
||||
c1 %= 255;
|
||||
}
|
||||
|
||||
_hash = (ushort)(c1 << 8 | c0);
|
||||
// Return recombined sums
|
||||
_hash = (ushort)((c1 << 8) | c0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
|
||||
public class Fletcher32 : ChecksumBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public Fletcher32()
|
||||
{
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Fletcher-32 into component sums
|
||||
uint c0 = _hash & 0xffff;
|
||||
@@ -122,4 +125,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
_hash = (c1 << 16) | c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ namespace SabreTools.Hashing.Checksum
|
||||
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
|
||||
public class Fletcher64 : ChecksumBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public Fletcher64()
|
||||
{
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Fletcher-64 into component sums
|
||||
ulong c0 = _hash & 0xffffffff;
|
||||
@@ -122,4 +125,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
_hash = (c1 << 32) | c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
public abstract class FnvBase<T> : ChecksumBase<T> where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Initial value to use
|
||||
/// </summary>
|
||||
protected T _basis;
|
||||
|
||||
/// <summary>
|
||||
/// Round prime to use
|
||||
/// </summary>
|
||||
protected T _prime;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Reset()
|
||||
{
|
||||
_hash = _basis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1687,4 +1687,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
@@ -694,4 +694,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://datatracker.ietf.org/doc/html/rfc1115"/>
|
||||
public class MD2 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for forming digest in
|
||||
/// </summary>
|
||||
@@ -41,7 +44,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = 16 - _byteCount;
|
||||
@@ -116,14 +119,14 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
byte padLength = (byte)(16 - _byteCount);
|
||||
|
||||
// Pad the block
|
||||
byte[] padding = new byte[padLength];
|
||||
#if NETFRAMEWORK
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
for (int i = 0; i < padLength; i++)
|
||||
{
|
||||
padding[i] = padLength;
|
||||
@@ -131,18 +134,14 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
#else
|
||||
Array.Fill(padding, padLength);
|
||||
#endif
|
||||
TransformBlock(padding, 0, padLength);
|
||||
TransformBlock(_checksum, 0, _checksum.Length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padLength);
|
||||
HashCore(_checksum, 0, _checksum.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
Array.Copy(_digest, hash, 16);
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -167,4 +166,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://datatracker.ietf.org/doc/html/rfc1320"/>
|
||||
public class MD4 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
@@ -26,7 +29,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -81,7 +84,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -104,12 +107,9 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -121,8 +121,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -213,4 +211,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
private static uint H(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
public abstract class MessageDigestBase
|
||||
public abstract class MessageDigestBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Total number of bytes processed
|
||||
@@ -19,29 +19,8 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
protected abstract void ResetImpl();
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public abstract void TransformBlock(byte[] data, int offset, int length);
|
||||
|
||||
/// <summary>
|
||||
/// End the hashing process
|
||||
/// </summary>
|
||||
/// TODO: Combine this when the padding byte can be set by implementing classes
|
||||
public abstract void Terminate();
|
||||
|
||||
/// <summary>
|
||||
/// Get the current value of the hash
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <see cref="Terminate"/> has not been run, this value
|
||||
/// will not be accurate for the processed bytes so far.
|
||||
/// </remarks>
|
||||
/// TODO: Combine this when there's an easier way of passing the state
|
||||
public abstract byte[] GetHash();
|
||||
/// <inheritdoc/>
|
||||
protected abstract override void HashCore(byte[] array, int ibStart, int cbSize);
|
||||
}
|
||||
|
||||
public abstract class MessageDigestBase<T> : MessageDigestBase where T : struct
|
||||
@@ -63,13 +42,11 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
else
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
// Reset the seed values
|
||||
ResetImpl();
|
||||
@@ -82,4 +59,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
Array.Clear(_block, 0, _block.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD128 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
@@ -27,7 +30,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -82,7 +85,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -105,12 +108,9 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -122,8 +122,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -446,4 +444,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD160 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 5 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
@@ -28,7 +31,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -83,7 +86,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -102,16 +105,13 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8 ) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0 ) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[20];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -123,8 +123,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -682,4 +680,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD256 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 256;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
@@ -31,7 +34,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -86,7 +89,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -109,12 +112,9 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[32];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -126,8 +126,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -466,4 +464,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD320 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 320;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 10 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
@@ -33,7 +36,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -88,7 +91,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -107,16 +110,13 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8 ) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0 ) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[40];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -128,8 +128,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -707,4 +705,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
/// </summary>
|
||||
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-128
|
||||
/// </summary>
|
||||
public class Tiger128_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger128_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-128
|
||||
/// </summary>
|
||||
public class Tiger128_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger128_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-160
|
||||
/// </summary>
|
||||
public class Tiger160_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger160_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-160
|
||||
/// </summary>
|
||||
public class Tiger160_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger160_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-192
|
||||
/// </summary>
|
||||
public class Tiger192_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger192_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-192
|
||||
/// </summary>
|
||||
public class Tiger192_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger192_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-128
|
||||
/// </summary>
|
||||
public class Tiger2_128_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger2_128_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-128
|
||||
/// </summary>
|
||||
public class Tiger2_128_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger2_128_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-160
|
||||
/// </summary>
|
||||
public class Tiger2_160_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger2_160_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-160
|
||||
/// </summary>
|
||||
public class Tiger2_160_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger2_160_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
@@ -14,12 +17,12 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.GetHash();
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-192
|
||||
/// </summary>
|
||||
public class Tiger2_192_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger2_192_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-192
|
||||
/// </summary>
|
||||
public class Tiger2_192_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger2_192_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.MessageDigest.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.MessageDigest
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger//>
|
||||
public abstract class TigerHashBase : MessageDigestBase<ulong>
|
||||
@@ -35,7 +35,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
@@ -90,7 +90,7 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Terminate()
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
@@ -113,12 +113,9 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
TransformBlock(padding, 0, padding.Length);
|
||||
}
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override byte[] GetHash()
|
||||
{
|
||||
// Get the hash
|
||||
var hash = new byte[24];
|
||||
int hashOffset = 0;
|
||||
|
||||
@@ -130,8 +127,6 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
hashOffset += 8;
|
||||
}
|
||||
|
||||
// Reset the state and return
|
||||
Reset();
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -239,4 +234,4 @@ namespace SabreTools.Hashing.MessageDigest
|
||||
_block[7] -= _block[6] ^ 0x0123456789ABCDEF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,4 +178,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET40_OR_GREATER || NETCOREAPP
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
@@ -12,10 +12,16 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
public static class HashTool
|
||||
{
|
||||
#region Standard Hashes
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(string filename, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
@@ -35,6 +41,62 @@ namespace SabreTools.Hashing
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="array">Input byte array</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(byte[] array, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
HashType[] standardHashTypes = [HashType.CRC32, HashType.MD5, HashType.SHA1];
|
||||
var fileHashes = GetByteArrayHashesAndSize(array, standardHashTypes, out size);
|
||||
if (fileHashes == null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[HashType.CRC32];
|
||||
md5 = fileHashes[HashType.MD5];
|
||||
sha1 = fileHashes[HashType.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(Stream stream, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
HashType[] standardHashTypes = [HashType.CRC32, HashType.MD5, HashType.SHA1];
|
||||
var fileHashes = GetStreamHashesAndSize(stream, standardHashTypes, out size);
|
||||
if (fileHashes == null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[HashType.CRC32];
|
||||
md5 = fileHashes[HashType.MD5];
|
||||
sha1 = fileHashes[HashType.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
@@ -60,10 +122,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetFileHash(string filename, HashType hashType)
|
||||
{
|
||||
var hashes = GetFileHashes(filename, [hashType]);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetFileHashAndSize(filename, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input file path
|
||||
@@ -72,10 +131,7 @@ namespace SabreTools.Hashing
|
||||
/// <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];
|
||||
}
|
||||
=> GetFileHashArrayAndSize(filename, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
@@ -103,6 +159,7 @@ namespace SabreTools.Hashing
|
||||
/// Get hashes and size from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetFileHashesAndSize(string filename, out long size)
|
||||
{
|
||||
@@ -117,6 +174,7 @@ namespace SabreTools.Hashing
|
||||
/// Get hashes and size from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, out long size)
|
||||
{
|
||||
@@ -132,6 +190,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash and size on success, null on error</returns>
|
||||
public static string? GetFileHashAndSize(string filename, HashType hashType, out long size)
|
||||
{
|
||||
@@ -144,6 +203,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash and size on success, null on error</returns>
|
||||
public static byte[]? GetFileHashArrayAndSize(string filename, HashType hashType, out long size)
|
||||
{
|
||||
@@ -156,6 +216,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetFileHashesAndSize(string filename, HashType[] hashTypes, out long size)
|
||||
{
|
||||
@@ -166,14 +227,11 @@ namespace SabreTools.Hashing
|
||||
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 GetStreamHashes(input, hashTypes);
|
||||
return GetStreamHashesAndSize(input, hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -181,6 +239,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, HashType[] hashTypes, out long size)
|
||||
{
|
||||
@@ -191,19 +250,16 @@ namespace SabreTools.Hashing
|
||||
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);
|
||||
return GetStreamHashArraysAndSize(input, hashTypes, out size);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Byte Array Hashes
|
||||
#region Byte Array Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -211,13 +267,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashes(byte[] input)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashes(new MemoryStream(input), hashTypes);
|
||||
}
|
||||
=> GetByteArrayHashesAndSize(input, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -225,13 +275,7 @@ namespace SabreTools.Hashing
|
||||
/// <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);
|
||||
}
|
||||
=> GetByteArrayHashArraysAndSize(input, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
@@ -240,10 +284,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <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];
|
||||
}
|
||||
=> GetByteArrayHashAndSize(input, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
@@ -252,10 +293,7 @@ namespace SabreTools.Hashing
|
||||
/// <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];
|
||||
}
|
||||
=> GetByteArrayHashArrayAndSize(input, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -264,7 +302,7 @@ namespace SabreTools.Hashing
|
||||
/// <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?>? GetByteArrayHashes(byte[] input, HashType[] hashTypes)
|
||||
=> GetStreamHashes(new MemoryStream(input), hashTypes);
|
||||
=> GetByteArrayHashesAndSize(input, hashTypes, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -273,71 +311,271 @@ namespace SabreTools.Hashing
|
||||
/// <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);
|
||||
=> GetByteArrayHashArraysAndSize(input, hashTypes, out _);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes
|
||||
#region Byte Array Hashes With Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashesAndSize(byte[] input, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashesAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArraysAndSize(byte[] input, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashArraysAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetByteArrayHashAndSize(byte[] input, HashType hashType, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashesAndSize(new MemoryStream(input), [hashType], out size);
|
||||
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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetByteArrayHashArrayAndSize(byte[] input, HashType hashType, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashArraysAndSize(new MemoryStream(input), [hashType], out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashesAndSize(byte[] input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashesAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
|
||||
/// <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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArraysAndSize(byte[] input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashArraysAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
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, leaveOpen);
|
||||
}
|
||||
=> GetStreamHashesAndSize(input, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</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);
|
||||
}
|
||||
=> GetStreamHashArraysAndSize(input, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// Get a hash from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHash(Stream input, HashType hashType, bool leaveOpen = false)
|
||||
{
|
||||
var hashes = GetStreamHashes(input, [hashType], leaveOpen);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetStreamHashAndSize(input, hashType, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// Get a hash from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</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];
|
||||
}
|
||||
=> GetStreamHashArrayAndSize(input, hashType, leaveOpen, out _);
|
||||
|
||||
/// <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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
=> GetStreamHashesAndSize(input, hashTypes, leaveOpen, out _);
|
||||
|
||||
/// <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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
=> GetStreamHashArraysAndSize(input, hashTypes, leaveOpen, out _);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes With Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, out long size)
|
||||
=> GetStreamHashesAndSize(input, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashesAndSize(input, hashTypes, leaveOpen, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, out long size)
|
||||
=> GetStreamHashArraysAndSize(input, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashArraysAndSize(input, hashTypes, leaveOpen, out size);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHashAndSize(Stream input, HashType hashType, out long size)
|
||||
=> GetStreamHashAndSize(input, hashType, leaveOpen: false, out size);
|
||||
|
||||
/// <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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHashAndSize(Stream input, HashType hashType, bool leaveOpen, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashesAndSize(input, [hashType], leaveOpen, out size);
|
||||
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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetStreamHashArrayAndSize(Stream input, HashType hashType, out long size)
|
||||
=> GetStreamHashArrayAndSize(input, hashType, leaveOpen: false, out size);
|
||||
|
||||
/// <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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetStreamHashArrayAndSize(Stream input, HashType hashType, bool leaveOpen, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashArraysAndSize(input, [hashType], leaveOpen, out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size 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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashesAndSize(input, hashTypes, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size 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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var hashDict = new Dictionary<HashType, string?>();
|
||||
@@ -352,13 +590,14 @@ namespace SabreTools.Hashing
|
||||
hashDict[hashType] = ZeroHash.GetString(hashType);
|
||||
}
|
||||
|
||||
size = 0;
|
||||
return hashDict;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Run the hashing
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen, out size);
|
||||
if (hashers == null)
|
||||
return null;
|
||||
|
||||
@@ -378,12 +617,24 @@ namespace SabreTools.Hashing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// Get hashes and size 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>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashArraysAndSize(input, hashTypes, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size 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>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var hashDict = new Dictionary<HashType, byte[]?>();
|
||||
@@ -398,13 +649,14 @@ namespace SabreTools.Hashing
|
||||
hashDict[hashType] = ZeroHash.GetBytes(hashType);
|
||||
}
|
||||
|
||||
size = 0;
|
||||
return hashDict;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Run the hashing
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen, out size);
|
||||
if (hashers == null)
|
||||
return null;
|
||||
|
||||
@@ -424,16 +676,18 @@ namespace SabreTools.Hashing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input stream
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="hashTypes"></param>
|
||||
/// <param name="leaveOpen"></param>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns></returns>
|
||||
private static Dictionary<HashType, HashWrapper>? GetStreamHashesInternal(Stream input, HashType[] hashTypes, bool leaveOpen)
|
||||
private static Dictionary<HashType, HashWrapper>? GetStreamHashesInternal(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
// Create the output dictionary and size counter
|
||||
var hashDict = new Dictionary<HashType, string?>();
|
||||
size = 0;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -456,6 +710,7 @@ namespace SabreTools.Hashing
|
||||
{
|
||||
// Load the buffer and hold the number of bytes read
|
||||
lastRead = input.Read(buffer, 0, buffersize);
|
||||
size += lastRead;
|
||||
if (lastRead == 0)
|
||||
break;
|
||||
|
||||
@@ -498,4 +753,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,4 +947,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using System;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using System.IO.Hashing;
|
||||
#endif
|
||||
using System.Security.Cryptography;
|
||||
using Aaru.Checksums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
#if NET7_0_OR_GREATER
|
||||
using Blake3;
|
||||
#endif
|
||||
using SabreTools.Hashing.Checksum;
|
||||
using SabreTools.Hashing.CryptographicHash;
|
||||
using SabreTools.Hashing.NonCryptographicHash;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing
|
||||
@@ -28,81 +22,33 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// Current hash in bytes
|
||||
/// </summary>
|
||||
public byte[]? CurrentHashBytes
|
||||
public byte[]? CurrentHashBytes => _hasher switch
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (_hasher)
|
||||
{
|
||||
case ChecksumBase cb:
|
||||
var cbArr = cb.Finalize();
|
||||
Array.Reverse(cbArr);
|
||||
return cbArr;
|
||||
|
||||
case HashAlgorithm ha:
|
||||
return ha.Hash;
|
||||
|
||||
case IChecksum ic:
|
||||
return ic.Final();
|
||||
|
||||
case MessageDigest.MessageDigestBase mdb:
|
||||
return mdb.GetHash();
|
||||
|
||||
HashAlgorithm ha => ha.Hash,
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
case XxHash3 xxh3:
|
||||
return xxh3.GetCurrentHash();
|
||||
case XxHash128 xxh128:
|
||||
return xxh128.GetCurrentHash();
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
var nchaArr = ncha.GetCurrentHash();
|
||||
Array.Reverse(nchaArr);
|
||||
return nchaArr;
|
||||
System.IO.Hashing.NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash(),
|
||||
#endif
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
case Shake128 s128:
|
||||
return s128.GetCurrentHash(32);
|
||||
case Shake256 s256:
|
||||
return s256.GetCurrentHash(64);
|
||||
Shake128 s128 => s128.GetCurrentHash(32),
|
||||
Shake256 s256 => s256.GetCurrentHash(64),
|
||||
#endif
|
||||
|
||||
case XxHash.XxHash32 xxh32:
|
||||
var xxh32Arr = xxh32.Finalize();
|
||||
Array.Reverse(xxh32Arr);
|
||||
return xxh32Arr;
|
||||
case XxHash.XxHash64 xxh64:
|
||||
var xxh64Arr = xxh64.Finalize();
|
||||
Array.Reverse(xxh64Arr);
|
||||
return xxh64Arr;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => null,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Current hash as a string
|
||||
/// </summary>
|
||||
public string? CurrentHashString
|
||||
public string? CurrentHashString => _hasher switch
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (_hasher)
|
||||
{
|
||||
case Crc cr:
|
||||
var crArr = cr.Finalize();
|
||||
ulong crHash = BytesToUInt64(crArr);
|
||||
int length = cr.Def.Width / 4 + (cr.Def.Width % 4 > 0 ? 1 : 0);
|
||||
return crHash.ToString($"x{length}");
|
||||
case IChecksum ic:
|
||||
return ic.End();
|
||||
// Needed due to variable bit widths
|
||||
Crc cr => GetCRCVariableLengthString(cr),
|
||||
|
||||
default:
|
||||
return ByteArrayToString(CurrentHashBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Needed due to Base64 text output
|
||||
SpamSum.SpamSum ss => GetSpamSumBase64String(ss),
|
||||
|
||||
// Everything else are direct conversions
|
||||
_ => ByteArrayToString(CurrentHashBytes),
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -111,7 +57,6 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// Internal hasher being used for processing
|
||||
/// </summary>
|
||||
/// <remarks>May be either a HashAlgorithm or NonCryptographicHashAlgorithm</remarks>
|
||||
private object? _hasher;
|
||||
|
||||
#endregion
|
||||
@@ -138,7 +83,7 @@ namespace SabreTools.Hashing
|
||||
HashType.Adler32 => new Adler32(),
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
HashType.BLAKE3 => new Blake3HashAlgorithm(),
|
||||
HashType.BLAKE3 => new Blake3.Blake3HashAlgorithm(),
|
||||
#endif
|
||||
|
||||
HashType.CRC1_ZERO => new Crc(StandardDefinitions.CRC1_ZERO),
|
||||
@@ -292,14 +237,14 @@ namespace SabreTools.Hashing
|
||||
HashType.FNV1a_32 => new FNV1a_32(),
|
||||
HashType.FNV1a_64 => new FNV1a_64(),
|
||||
|
||||
HashType.MD2 => new MessageDigest.MD2(),
|
||||
HashType.MD4 => new MessageDigest.MD4(),
|
||||
HashType.MD2 => new MD2(),
|
||||
HashType.MD4 => new MD4(),
|
||||
HashType.MD5 => MD5.Create(),
|
||||
|
||||
HashType.RIPEMD128 => new MessageDigest.RipeMD128(),
|
||||
HashType.RIPEMD160 => new MessageDigest.RipeMD160(),
|
||||
HashType.RIPEMD256 => new MessageDigest.RipeMD256(),
|
||||
HashType.RIPEMD320 => new MessageDigest.RipeMD320(),
|
||||
HashType.RIPEMD128 => new RipeMD128(),
|
||||
HashType.RIPEMD160 => new CryptographicHash.RipeMD160(),
|
||||
HashType.RIPEMD256 => new RipeMD256(),
|
||||
HashType.RIPEMD320 => new RipeMD320(),
|
||||
|
||||
HashType.SHA1 => SHA1.Create(),
|
||||
HashType.SHA256 => SHA256.Create(),
|
||||
@@ -313,26 +258,26 @@ namespace SabreTools.Hashing
|
||||
HashType.SHAKE256 => Shake256.IsSupported ? new Shake256() : null,
|
||||
#endif
|
||||
|
||||
HashType.SpamSum => new SpamSumContext(),
|
||||
HashType.SpamSum => new SpamSum.SpamSum(),
|
||||
|
||||
HashType.Tiger128_3 => new MessageDigest.Tiger128_3(),
|
||||
HashType.Tiger128_4 => new MessageDigest.Tiger128_4(),
|
||||
HashType.Tiger160_3 => new MessageDigest.Tiger160_3(),
|
||||
HashType.Tiger160_4 => new MessageDigest.Tiger160_4(),
|
||||
HashType.Tiger192_3 => new MessageDigest.Tiger192_3(),
|
||||
HashType.Tiger192_4 => new MessageDigest.Tiger192_4(),
|
||||
HashType.Tiger2_128_3 => new MessageDigest.Tiger2_128_3(),
|
||||
HashType.Tiger2_128_4 => new MessageDigest.Tiger2_128_4(),
|
||||
HashType.Tiger2_160_3 => new MessageDigest.Tiger2_160_3(),
|
||||
HashType.Tiger2_160_4 => new MessageDigest.Tiger2_160_4(),
|
||||
HashType.Tiger2_192_3 => new MessageDigest.Tiger2_192_3(),
|
||||
HashType.Tiger2_192_4 => new MessageDigest.Tiger2_192_4(),
|
||||
HashType.Tiger128_3 => new Tiger128_3(),
|
||||
HashType.Tiger128_4 => new Tiger128_4(),
|
||||
HashType.Tiger160_3 => new Tiger160_3(),
|
||||
HashType.Tiger160_4 => new Tiger160_4(),
|
||||
HashType.Tiger192_3 => new Tiger192_3(),
|
||||
HashType.Tiger192_4 => new Tiger192_4(),
|
||||
HashType.Tiger2_128_3 => new Tiger2_128_3(),
|
||||
HashType.Tiger2_128_4 => new Tiger2_128_4(),
|
||||
HashType.Tiger2_160_3 => new Tiger2_160_3(),
|
||||
HashType.Tiger2_160_4 => new Tiger2_160_4(),
|
||||
HashType.Tiger2_192_3 => new Tiger2_192_3(),
|
||||
HashType.Tiger2_192_4 => new Tiger2_192_4(),
|
||||
|
||||
HashType.XxHash32 => new XxHash.XxHash32(),
|
||||
HashType.XxHash64 => new XxHash.XxHash64(),
|
||||
HashType.XxHash32 => new XxHash32(),
|
||||
HashType.XxHash64 => new XxHash64(),
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
HashType.XxHash3 => new XxHash3(),
|
||||
HashType.XxHash128 => new XxHash128(),
|
||||
HashType.XxHash3 => new System.IO.Hashing.XxHash3(),
|
||||
HashType.XxHash128 => new System.IO.Hashing.XxHash128(),
|
||||
#endif
|
||||
_ => null,
|
||||
};
|
||||
@@ -356,26 +301,12 @@ namespace SabreTools.Hashing
|
||||
{
|
||||
switch (_hasher)
|
||||
{
|
||||
case ChecksumBase cb:
|
||||
cb.TransformBlock(buffer, offset, size);
|
||||
break;
|
||||
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformBlock(buffer, offset, size, null, 0);
|
||||
break;
|
||||
|
||||
case IChecksum ic:
|
||||
byte[] icBlock = new byte[size];
|
||||
Array.Copy(buffer, offset, icBlock, 0, size);
|
||||
ic.Update(icBlock);
|
||||
break;
|
||||
|
||||
case MessageDigest.MessageDigestBase mdb:
|
||||
mdb.TransformBlock(buffer, offset, size);
|
||||
break;
|
||||
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
case System.IO.Hashing.NonCryptographicHashAlgorithm ncha:
|
||||
var nchaBufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
|
||||
ncha.Append(nchaBufferSpan);
|
||||
break;
|
||||
@@ -391,13 +322,6 @@ namespace SabreTools.Hashing
|
||||
s256.AppendData(s256BufferSpan);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case XxHash.XxHash32 xxh32:
|
||||
xxh32.TransformBlock(buffer, offset, size);
|
||||
break;
|
||||
case XxHash.XxHash64 xxh64:
|
||||
xxh64.TransformBlock(buffer, offset, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,13 +337,40 @@ namespace SabreTools.Hashing
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case MessageDigest.MessageDigestBase mdb:
|
||||
mdb.Terminate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the variable-length string representing a CRC value
|
||||
/// </summary>
|
||||
/// <param name="cr">Crc to get the value from</param>
|
||||
/// <returns>String representing the CRC, null on error</returns>
|
||||
private string? GetCRCVariableLengthString(Crc cr)
|
||||
{
|
||||
// Ignore null values
|
||||
if (cr.Hash == null)
|
||||
return null;
|
||||
|
||||
// Get the total number of characters needed
|
||||
ulong hash = BytesToUInt64(cr.Hash);
|
||||
int length = cr.Def.Width / 4 + (cr.Def.Width % 4 > 0 ? 1 : 0);
|
||||
return hash.ToString($"x{length}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Base64 representation of a SpamSum value
|
||||
/// </summary>
|
||||
/// <param name="ss">SpamSum to get the value from</param>
|
||||
/// <returns>String representing the SpamSum, null on error</returns>
|
||||
private string? GetSpamSumBase64String(SpamSum.SpamSum ss)
|
||||
{
|
||||
// Ignore null values
|
||||
if (ss.Hash == null)
|
||||
return null;
|
||||
|
||||
return System.Text.Encoding.ASCII.GetString(ss.Hash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
SabreTools.Hashing/NonCryptographicHash/Constants.cs
Normal file
43
SabreTools.Hashing/NonCryptographicHash/Constants.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
#region FNV
|
||||
|
||||
public const uint FNV32Basis = 0x811c9dc5;
|
||||
public const ulong FNV64Basis = 0xcbf29ce484222325;
|
||||
|
||||
public const uint FNV32Prime = 0x01000193;
|
||||
public const ulong FNV64Prime = 0x00000100000001b3;
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxHash-32
|
||||
|
||||
public const uint XXH_PRIME32_1 = 0x9E3779B1;
|
||||
|
||||
public const uint XXH_PRIME32_2 = 0x85EBCA77;
|
||||
|
||||
public const uint XXH_PRIME32_3 = 0xC2B2AE3D;
|
||||
|
||||
public const uint XXH_PRIME32_4 = 0x27D4EB2F;
|
||||
|
||||
public const uint XXH_PRIME32_5 = 0x165667B1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxHash-64
|
||||
|
||||
public const ulong XXH_PRIME64_1 = 0x9E3779B185EBCA87;
|
||||
|
||||
public const ulong XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4F;
|
||||
|
||||
public const ulong XXH_PRIME64_3 = 0x165667B19E3779F9;
|
||||
|
||||
public const ulong XXH_PRIME64_4 = 0x85EBCA77C2B2AE63;
|
||||
|
||||
public const ulong XXH_PRIME64_5 = 0x27D4EB2F165667C5;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV0_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV0_32()
|
||||
{
|
||||
_basis = 0;
|
||||
_prime = FNV32Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV0_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV0_64()
|
||||
{
|
||||
_basis = 0;
|
||||
_prime = FNV64Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV1_32()
|
||||
{
|
||||
_basis = FNV32Basis;
|
||||
_prime = FNV32Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV1_64()
|
||||
{
|
||||
_basis = FNV64Basis;
|
||||
_prime = FNV64Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1a_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV1a_32()
|
||||
{
|
||||
_basis = FNV32Basis;
|
||||
_prime = FNV32Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1a_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV1a_64()
|
||||
{
|
||||
_basis = FNV64Basis;
|
||||
_prime = FNV64Prime;
|
||||
Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void TransformBlock(byte[] data, int offset, int length)
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
@@ -20,4 +23,4 @@ namespace SabreTools.Hashing.Checksum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
SabreTools.Hashing/NonCryptographicHash/FnvBase.cs
Normal file
60
SabreTools.Hashing/NonCryptographicHash/FnvBase.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Common base class for FNV non-cryptographic hashes
|
||||
/// </summary>
|
||||
public abstract class FnvBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
// No common, untyped functionality
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common base class for FNV non-cryptographic hashes
|
||||
/// </summary>
|
||||
public abstract class FnvBase<T> : FnvBase where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Initial value to use
|
||||
/// </summary>
|
||||
protected T _basis;
|
||||
|
||||
/// <summary>
|
||||
/// Round prime to use
|
||||
/// </summary>
|
||||
protected T _prime;
|
||||
|
||||
/// <summary>
|
||||
/// The current value of the hash
|
||||
/// </summary>
|
||||
protected T _hash;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = _basis;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hashArr = _hash switch
|
||||
{
|
||||
short s => BitConverter.GetBytes(s),
|
||||
ushort s => BitConverter.GetBytes(s),
|
||||
|
||||
int i => BitConverter.GetBytes(i),
|
||||
uint i => BitConverter.GetBytes(i),
|
||||
|
||||
long l => BitConverter.GetBytes(l),
|
||||
ulong l => BitConverter.GetBytes(l),
|
||||
|
||||
_ => [],
|
||||
};
|
||||
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
SabreTools.Hashing/NonCryptographicHash/XxHash32.cs
Normal file
46
SabreTools.Hashing/NonCryptographicHash/XxHash32.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class XxHash32 : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
/// <summary>
|
||||
/// The 32-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash-32 state
|
||||
/// </summary>
|
||||
private readonly XxHash32State _state;
|
||||
|
||||
public XxHash32(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XxHash32State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
uint hash = _state.Digest();
|
||||
byte[] hashArr = BitConverter.GetBytes(hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.XxHash.Constants;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure for XXH32 streaming API.
|
||||
/// Structure for xxHash-32 streaming API.
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
|
||||
internal class XXH32State
|
||||
internal class XxHash32State
|
||||
{
|
||||
/// <summary>
|
||||
/// Total length hashed, modulo 2^32
|
||||
@@ -147,7 +147,7 @@ namespace SabreTools.Hashing.XxHash
|
||||
private static uint Round(uint acc, uint input)
|
||||
{
|
||||
acc += input * XXH_PRIME32_2;
|
||||
acc = RotateLeft32(acc, 13);
|
||||
acc = RotateLeft32(acc, 13);
|
||||
acc *= XXH_PRIME32_1;
|
||||
return acc;
|
||||
}
|
||||
@@ -201,4 +201,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
return Avalanche(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
SabreTools.Hashing/NonCryptographicHash/XxHash64.cs
Normal file
46
SabreTools.Hashing/NonCryptographicHash/XxHash64.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class XxHash64 : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
/// <summary>
|
||||
/// The 64-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash-64 state
|
||||
/// </summary>
|
||||
private readonly XxHash64State _state;
|
||||
|
||||
public XxHash64(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XxHash64State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
ulong hash = _state.Digest();
|
||||
byte[] hashArr = BitConverter.GetBytes(hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.XxHash.Constants;
|
||||
using static SabreTools.Hashing.XxHash.Utility;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure for XXH64 streaming API.
|
||||
/// Structure for xxHash-64 streaming API.
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
|
||||
internal class XXH64State
|
||||
internal class XxHash64State
|
||||
{
|
||||
/// <summary>
|
||||
/// Total length hashed. This is always 64-bit.
|
||||
@@ -145,7 +144,7 @@ namespace SabreTools.Hashing.XxHash
|
||||
private static ulong Round(ulong acc, ulong input)
|
||||
{
|
||||
acc += unchecked(input * XXH_PRIME64_2);
|
||||
acc = RotateLeft64(acc, 31);
|
||||
acc = RotateLeft64(acc, 31);
|
||||
acc *= XXH_PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
@@ -198,7 +197,23 @@ namespace SabreTools.Hashing.XxHash
|
||||
--length;
|
||||
}
|
||||
|
||||
return XXH64Avalanche(hash);
|
||||
return Avalanche(hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mixes all bits to finalize the hash.
|
||||
///
|
||||
/// The final mix ensures that all input bits have a chance to impact any bit in
|
||||
/// the output digest, resulting in an unbiased distribution.
|
||||
/// </summary>
|
||||
private static ulong Avalanche(ulong hash)
|
||||
{
|
||||
hash ^= hash >> 33;
|
||||
hash *= XXH_PRIME64_2;
|
||||
hash ^= hash >> 29;
|
||||
hash *= XXH_PRIME64_3;
|
||||
hash ^= hash >> 32;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<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;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.4.0</Version>
|
||||
<Version>1.5.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Copyright>Copyright (c)2016-2024 Matt Nadareski</Copyright>
|
||||
<Copyright>Copyright (c)2016-2025 Matt Nadareski</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Hashing</RepositoryUrl>
|
||||
@@ -22,30 +24,14 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- 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`)) OR $(TargetFramework.StartsWith(`net9`))">
|
||||
<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;net9.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- 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`)) OR $(TargetFramework.StartsWith(`net9`))">
|
||||
<PackageReference Include="Blake3" Version="1.1.0" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blake3" Version="1.1.0" Condition="$(TargetFramework.StartsWith(`net7`))" />
|
||||
<PackageReference Include="Blake3" Version="2.0.0" Condition="$(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`))" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="9.0.7" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net45`))" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
45
SabreTools.Hashing/SpamSum/BlockhashContext.cs
Normal file
45
SabreTools.Hashing/SpamSum/BlockhashContext.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using static SabreTools.Hashing.SpamSum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <summary>
|
||||
/// A blockhash contains a signature state for a specific (implicit) blocksize.
|
||||
/// The blocksize is given by <see cref="SSDEEP_BS(uint)"/>
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
internal class BlockhashContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Current digest length
|
||||
/// </summary>
|
||||
public uint DIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current message digest
|
||||
/// </summary>
|
||||
public byte[] Digest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Digest value at <see cref="HalfH"/>
|
||||
/// </summary>
|
||||
public byte HalfDigest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partial FNV hash
|
||||
/// </summary>
|
||||
public byte H { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partial FNV hash reset after <see cref="Digest"/> is
|
||||
/// <see cref="SPAMSUM_LENGTH"/> / 2 long. This is needed
|
||||
/// to be able to truncate digest for the second output hash
|
||||
/// to stay compatible with ssdeep output.
|
||||
/// </summary>
|
||||
public byte HalfH { get; set; }
|
||||
|
||||
public BlockhashContext()
|
||||
{
|
||||
Digest = new byte[SPAMSUM_LENGTH];
|
||||
}
|
||||
}
|
||||
}
|
||||
446
SabreTools.Hashing/SpamSum/Constants.cs
Normal file
446
SabreTools.Hashing/SpamSum/Constants.cs
Normal file
@@ -0,0 +1,446 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <see href="github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
/// <see href="github.com/ssdeep-project/ssdeep/blob/master/fuzzy.h"/>
|
||||
internal static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// fuzzy_digest flag indicating to eliminate sequences of more than
|
||||
/// three identical characters
|
||||
/// </summary>
|
||||
public const uint FUZZY_FLAG_ELIMSEQ = 1;
|
||||
|
||||
/// <summary>
|
||||
/// fuzzy_digest flag indicating not to truncate the second part to
|
||||
/// SPAMSUM_LENGTH / 2 characters.
|
||||
/// </summary>
|
||||
public const uint FUZZY_FLAG_NOTRUNC = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Length of an individual fuzzy hash signature component.
|
||||
/// </summary>
|
||||
public const int SPAMSUM_LENGTH = 64;
|
||||
|
||||
/// <summary>
|
||||
/// The longest possible length for a fuzzy hash signature
|
||||
/// (without the filename)
|
||||
/// </summary>
|
||||
public const int FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
|
||||
|
||||
public const uint ROLLING_WINDOW = 7;
|
||||
|
||||
public const uint MIN_BLOCKSIZE = 3;
|
||||
|
||||
public const byte HASH_INIT = 0x27;
|
||||
|
||||
public const int NUM_BLOCKHASHES = 31;
|
||||
|
||||
public const uint FUZZY_STATE_NEED_LASTHASH = 1;
|
||||
|
||||
public const uint FUZZY_STATE_SIZE_FIXED = 2;
|
||||
|
||||
public static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
|
||||
|
||||
public static ulong SSDEEP_TOTAL_SIZE_MAX
|
||||
=> (ulong)SSDEEP_BS(NUM_BLOCKHASHES - 1) * SPAMSUM_LENGTH;
|
||||
|
||||
public static readonly byte[] B64 = Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||||
|
||||
#region Precomputed Tables
|
||||
|
||||
/// <summary>
|
||||
/// Precomputed patrial FNV hash table
|
||||
/// </summary>
|
||||
public static readonly byte[][] SUM_TABLE = // [64][64]
|
||||
[
|
||||
[ // 0x00
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
],
|
||||
[ // 0x01
|
||||
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
|
||||
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
|
||||
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
|
||||
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
|
||||
],
|
||||
[ // 0x02
|
||||
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
|
||||
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
|
||||
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
|
||||
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
|
||||
],
|
||||
[ // 0x03
|
||||
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
|
||||
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
|
||||
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
|
||||
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
|
||||
],
|
||||
[ // 0x04
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
|
||||
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
|
||||
],
|
||||
[ // 0x05
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
],
|
||||
[ // 0x06
|
||||
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
|
||||
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
|
||||
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
|
||||
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
|
||||
],
|
||||
[ // 0x07
|
||||
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
|
||||
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
|
||||
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
|
||||
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
|
||||
],
|
||||
[ // 0x08
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
],
|
||||
[ // 0x09
|
||||
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
|
||||
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
|
||||
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
|
||||
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
|
||||
],
|
||||
[ // 0x0a
|
||||
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
|
||||
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
|
||||
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
|
||||
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
|
||||
],
|
||||
[ // 0x0b
|
||||
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
|
||||
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
|
||||
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
|
||||
],
|
||||
[ // 0x0c
|
||||
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
|
||||
],
|
||||
[ // 0x0d
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
],
|
||||
[ // 0x0e
|
||||
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
|
||||
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
|
||||
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
|
||||
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
|
||||
],
|
||||
[ // 0x0f
|
||||
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
|
||||
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
|
||||
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
|
||||
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
|
||||
],
|
||||
[ // 0x10
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
],
|
||||
[ // 0x11
|
||||
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
|
||||
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
|
||||
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
|
||||
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
|
||||
],
|
||||
[ // 0x12
|
||||
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
|
||||
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
|
||||
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
|
||||
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
|
||||
],
|
||||
[ // 0x13
|
||||
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
|
||||
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
|
||||
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
|
||||
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
|
||||
],
|
||||
[ // 0x14
|
||||
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
|
||||
],
|
||||
[ // 0x15
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
],
|
||||
[ // 0x16
|
||||
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
|
||||
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
|
||||
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
|
||||
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
|
||||
],
|
||||
[ // 0x17
|
||||
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
|
||||
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
|
||||
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
|
||||
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
|
||||
],
|
||||
[ // 0x18
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
],
|
||||
[ // 0x19
|
||||
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
|
||||
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
|
||||
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
|
||||
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
|
||||
],
|
||||
[ // 0x1a
|
||||
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
|
||||
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
|
||||
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
|
||||
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
|
||||
],
|
||||
[ // 0x1b
|
||||
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
|
||||
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
|
||||
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
|
||||
],
|
||||
[ // 0x1c
|
||||
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
|
||||
],
|
||||
[ // 0x1d
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
],
|
||||
[ // 0x1e
|
||||
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
|
||||
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
|
||||
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
|
||||
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
|
||||
],
|
||||
[ // 0x1f
|
||||
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
|
||||
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
|
||||
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
|
||||
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
|
||||
],
|
||||
[ // 0x20
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
],
|
||||
[ // 0x21
|
||||
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
|
||||
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
|
||||
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
|
||||
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
|
||||
],
|
||||
[ // 0x22
|
||||
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
|
||||
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
|
||||
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
|
||||
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
|
||||
],
|
||||
[ // 0x23
|
||||
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
|
||||
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
|
||||
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
|
||||
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
|
||||
],
|
||||
[ // 0x24
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
|
||||
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
|
||||
],
|
||||
[ // 0x25
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
],
|
||||
[ // 0x26
|
||||
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
|
||||
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
|
||||
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
|
||||
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
|
||||
],
|
||||
[ // 0x27
|
||||
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
|
||||
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
|
||||
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
|
||||
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
|
||||
],
|
||||
[ // 0x28
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
],
|
||||
[ // 0x29
|
||||
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
|
||||
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
|
||||
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
|
||||
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
|
||||
],
|
||||
[ // 0x2a
|
||||
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
|
||||
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
|
||||
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
|
||||
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
|
||||
],
|
||||
[ // 0x2b
|
||||
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
|
||||
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
|
||||
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
|
||||
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||
],
|
||||
[ // 0x2c
|
||||
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
|
||||
],
|
||||
[ // 0x2d
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
],
|
||||
[ // 0x2e
|
||||
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
|
||||
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
|
||||
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
|
||||
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
|
||||
],
|
||||
[ // 0x2f
|
||||
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
|
||||
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
|
||||
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
|
||||
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
|
||||
],
|
||||
[ // 0x30
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
],
|
||||
[ // 0x31
|
||||
0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24, 0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c,
|
||||
0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34, 0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c,
|
||||
0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
|
||||
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14, 0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c,
|
||||
],
|
||||
[ // 0x32
|
||||
0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31, 0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39,
|
||||
0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21, 0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29,
|
||||
0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11, 0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19,
|
||||
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09,
|
||||
],
|
||||
[ // 0x33
|
||||
0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
|
||||
0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16,
|
||||
0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e, 0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26,
|
||||
0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36,
|
||||
],
|
||||
[ // 0x34
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03,
|
||||
0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b, 0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b, 0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23,
|
||||
],
|
||||
[ // 0x35
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
],
|
||||
[ // 0x36
|
||||
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
|
||||
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
|
||||
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
|
||||
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
|
||||
],
|
||||
[ // 0x37
|
||||
0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12, 0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a,
|
||||
0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02, 0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a,
|
||||
0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32, 0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a,
|
||||
0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22, 0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a,
|
||||
],
|
||||
[ // 0x38
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
],
|
||||
[ // 0x39
|
||||
0x3b, 0x3a, 0x39, 0x38, 0x3f, 0x3e, 0x3d, 0x3c, 0x33, 0x32, 0x31, 0x30, 0x37, 0x36, 0x35, 0x34,
|
||||
0x2b, 0x2a, 0x29, 0x28, 0x2f, 0x2e, 0x2d, 0x2c, 0x23, 0x22, 0x21, 0x20, 0x27, 0x26, 0x25, 0x24,
|
||||
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c, 0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
|
||||
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
|
||||
],
|
||||
[ // 0x3a
|
||||
0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x08, 0x09, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
|
||||
0x1e, 0x1f, 0x1c, 0x1d, 0x1a, 0x1b, 0x18, 0x19, 0x16, 0x17, 0x14, 0x15, 0x12, 0x13, 0x10, 0x11,
|
||||
0x2e, 0x2f, 0x2c, 0x2d, 0x2a, 0x2b, 0x28, 0x29, 0x26, 0x27, 0x24, 0x25, 0x22, 0x23, 0x20, 0x21,
|
||||
0x3e, 0x3f, 0x3c, 0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x37, 0x34, 0x35, 0x32, 0x33, 0x30, 0x31,
|
||||
],
|
||||
[ // 0x3b
|
||||
0x21, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27, 0x26, 0x29, 0x28, 0x2b, 0x2a, 0x2d, 0x2c, 0x2f, 0x2e,
|
||||
0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37, 0x36, 0x39, 0x38, 0x3b, 0x3a, 0x3d, 0x3c, 0x3f, 0x3e,
|
||||
0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||
0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1b, 0x1a, 0x1d, 0x1c, 0x1f, 0x1e,
|
||||
],
|
||||
[ // 0x3c
|
||||
0x34, 0x35, 0x36, 0x37, 0x30, 0x31, 0x32, 0x33, 0x3c, 0x3d, 0x3e, 0x3f, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x20, 0x21, 0x22, 0x23, 0x2c, 0x2d, 0x2e, 0x2f, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x1c, 0x1d, 0x1e, 0x1f, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b,
|
||||
],
|
||||
[ // 0x3d
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
],
|
||||
[ // 0x3e
|
||||
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
|
||||
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
|
||||
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
|
||||
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
|
||||
],
|
||||
[ // 0x3f
|
||||
0x2d, 0x2c, 0x2f, 0x2e, 0x29, 0x28, 0x2b, 0x2a, 0x25, 0x24, 0x27, 0x26, 0x21, 0x20, 0x23, 0x22,
|
||||
0x3d, 0x3c, 0x3f, 0x3e, 0x39, 0x38, 0x3b, 0x3a, 0x35, 0x34, 0x37, 0x36, 0x31, 0x30, 0x33, 0x32,
|
||||
0x0d, 0x0c, 0x0f, 0x0e, 0x09, 0x08, 0x0b, 0x0a, 0x05, 0x04, 0x07, 0x06, 0x01, 0x00, 0x03, 0x02,
|
||||
0x1d, 0x1c, 0x1f, 0x1e, 0x19, 0x18, 0x1b, 0x1a, 0x15, 0x14, 0x17, 0x16, 0x11, 0x10, 0x13, 0x12,
|
||||
],
|
||||
];
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
91
SabreTools.Hashing/SpamSum/FuzzyState.cs
Normal file
91
SabreTools.Hashing/SpamSum/FuzzyState.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.SpamSum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <see href="https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
internal class FuzzyState
|
||||
{
|
||||
public ulong TotalSize { get; set; }
|
||||
|
||||
public ulong FixedSize { get; set; }
|
||||
|
||||
public ulong ReduceBorder { get; set; }
|
||||
|
||||
public uint BHStart { get; set; }
|
||||
|
||||
public uint BHEnd { get; set; }
|
||||
|
||||
public uint BHEndLimit { get; set; }
|
||||
|
||||
public uint Flags { get; set; }
|
||||
|
||||
public uint RollMask { get; set; }
|
||||
|
||||
public BlockhashContext[] BH { get; set; }
|
||||
|
||||
public RollState Roll { get; set; }
|
||||
|
||||
public byte LastH { get; set; }
|
||||
|
||||
public FuzzyState()
|
||||
{
|
||||
BH = new BlockhashContext[NUM_BLOCKHASHES];
|
||||
for (int i = 0; i < NUM_BLOCKHASHES; i++)
|
||||
{
|
||||
BH[i] = new BlockhashContext();
|
||||
}
|
||||
|
||||
Roll = new RollState();
|
||||
}
|
||||
|
||||
public void TryForkBlockhash()
|
||||
{
|
||||
uint obh, nbh;
|
||||
if (BHEnd <= 0)
|
||||
throw new Exception("assert(BHEnd > 0)");
|
||||
|
||||
obh = BHEnd - 1;
|
||||
if (BHEnd <= BHEndLimit)
|
||||
{
|
||||
nbh = obh + 1;
|
||||
BH[nbh].H = BH[obh].H;
|
||||
BH[nbh].HalfH = BH[obh].HalfH;
|
||||
BH[nbh].Digest[0] = 0x00;
|
||||
BH[nbh].HalfDigest = 0x00;
|
||||
BH[nbh].DIndex = 0;
|
||||
++BHEnd;
|
||||
}
|
||||
else if (BHEnd == NUM_BLOCKHASHES
|
||||
&& ((Flags & FUZZY_STATE_NEED_LASTHASH) == 0))
|
||||
{
|
||||
Flags |= FUZZY_STATE_NEED_LASTHASH;
|
||||
LastH = BH[obh].H;
|
||||
}
|
||||
}
|
||||
|
||||
public void TryReduceBlockhash()
|
||||
{
|
||||
if (BHStart >= BHEnd)
|
||||
throw new Exception("assert(BHStart < BHEnd)");
|
||||
|
||||
// Need at least two working hashes.
|
||||
if (BHEnd - BHStart < 2)
|
||||
return;
|
||||
|
||||
// Initial blocksize estimate would select this or a smaller blocksize.
|
||||
if (ReduceBorder >= (((Flags & FUZZY_STATE_SIZE_FIXED) != 0) ? FixedSize : TotalSize))
|
||||
return;
|
||||
|
||||
// Estimate adjustment would select this blocksize.
|
||||
if (BH[BHStart + 1].DIndex < SPAMSUM_LENGTH / 2)
|
||||
return;
|
||||
|
||||
// At this point we are clearly no longer interested in the
|
||||
// start_blocksize. Get rid of it.
|
||||
++BHStart;
|
||||
ReduceBorder *= 2;
|
||||
RollMask = RollMask * 2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
SabreTools.Hashing/SpamSum/RollState.cs
Normal file
56
SabreTools.Hashing/SpamSum/RollState.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using static SabreTools.Hashing.SpamSum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <see href="https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
internal class RollState
|
||||
{
|
||||
public byte[] Window { get; set; }
|
||||
|
||||
public uint H1 { get; set; }
|
||||
|
||||
public uint H2 { get; set; }
|
||||
|
||||
public uint H3 { get; set; }
|
||||
|
||||
public uint N { get; set; }
|
||||
|
||||
public RollState()
|
||||
{
|
||||
Window = new byte[ROLLING_WINDOW];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A rolling hash, based on the Adler checksum. By using a rolling hash
|
||||
/// we can perform auto resynchronisation after inserts/deletes.
|
||||
///
|
||||
/// Internally, H1 is the sum of the bytes in the window and H2
|
||||
/// is the sum of the bytes times the index.
|
||||
///
|
||||
/// H3 is a shift/xor based rolling hash, and is mostly needed to ensure that
|
||||
/// we can cope with large blocksize values.
|
||||
/// </summary>
|
||||
public void RollHash(byte c)
|
||||
{
|
||||
H2 -= H1;
|
||||
H2 += ROLLING_WINDOW * c;
|
||||
|
||||
H1 += c;
|
||||
H1 -= Window[N % ROLLING_WINDOW];
|
||||
|
||||
Window[N % ROLLING_WINDOW] = c;
|
||||
N++;
|
||||
|
||||
// The original spamsum AND'ed this value with 0xFFFFFFFF which
|
||||
// in theory should have no effect. This AND has been removed
|
||||
// for performance (jk)
|
||||
H3 <<= 5;
|
||||
H3 ^= c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the current rolling sum
|
||||
/// </summary>
|
||||
public uint RollSum() => H1 + H2 + H3;
|
||||
}
|
||||
}
|
||||
356
SabreTools.Hashing/SpamSum/SpamSum.cs
Normal file
356
SabreTools.Hashing/SpamSum/SpamSum.cs
Normal file
@@ -0,0 +1,356 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using static SabreTools.Hashing.SpamSum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <see href="https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
public class SpamSum : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
private FuzzyState _state;
|
||||
|
||||
public SpamSum()
|
||||
{
|
||||
_state = new();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_state = new FuzzyState
|
||||
{
|
||||
BHStart = 0,
|
||||
BHEnd = 1,
|
||||
BHEndLimit = NUM_BLOCKHASHES - 1,
|
||||
TotalSize = 0,
|
||||
ReduceBorder = MIN_BLOCKSIZE * SPAMSUM_LENGTH,
|
||||
Flags = 0,
|
||||
RollMask = 0,
|
||||
};
|
||||
|
||||
_state.BH[0].H = HASH_INIT;
|
||||
_state.BH[0].HalfH = HASH_INIT;
|
||||
_state.BH[0].Digest[0] = 0x00;
|
||||
_state.BH[0].HalfDigest = 0x00;
|
||||
_state.BH[0].DIndex = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
||||
{
|
||||
_state.TotalSize += (ulong)cbSize;
|
||||
for (int i = ibStart; i < cbSize; i++)
|
||||
{
|
||||
ProcessByte(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
string? digest = Finalize(0);
|
||||
if (digest == null)
|
||||
return [];
|
||||
|
||||
return Encoding.ASCII.GetBytes(digest.TrimEnd('\0'));
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Originally named `fuzzy_engine_step`
|
||||
/// </remarks>
|
||||
private void ProcessByte(byte c)
|
||||
{
|
||||
// At each character we update the rolling hash and the normal hashes.
|
||||
// When the rolling hash hits a reset value then we emit a normal hash
|
||||
// as a element of the signature and reset the normal hash.
|
||||
_state.Roll.RollHash(c);
|
||||
uint horg = _state.Roll.RollSum() + 1;
|
||||
uint h = horg / MIN_BLOCKSIZE;
|
||||
|
||||
uint i;
|
||||
for (i = _state.BHStart; i < _state.BHEnd; ++i)
|
||||
{
|
||||
_state.BH[i].H = SumHash(c, _state.BH[i].H);
|
||||
_state.BH[i].HalfH = SumHash(c, _state.BH[i].HalfH);
|
||||
}
|
||||
|
||||
if ((_state.Flags & FUZZY_STATE_NEED_LASTHASH) != 0)
|
||||
_state.LastH = SumHash(c, _state.LastH);
|
||||
|
||||
// 0xffffffff !== -1 (mod 3)
|
||||
if (horg == 0)
|
||||
return;
|
||||
|
||||
// With growing blocksize almost no runs fail the next test.
|
||||
if ((h & _state.RollMask) != 0)
|
||||
return;
|
||||
|
||||
// Delay computation of modulo as possible.
|
||||
if ((horg % MIN_BLOCKSIZE) != 0)
|
||||
return;
|
||||
|
||||
h >>= (int)_state.BHStart;
|
||||
i = _state.BHStart;
|
||||
do
|
||||
{
|
||||
// We have hit a reset point. We now emit hashes which are
|
||||
// based on all characters in the piece of the message between
|
||||
// the last reset point and this one
|
||||
if (_state.BH[i].DIndex == 0)
|
||||
{
|
||||
// Can only happen 30 times.
|
||||
// First step for this blocksize. Clone next.
|
||||
_state.TryForkBlockhash();
|
||||
}
|
||||
|
||||
_state.BH[i].Digest[_state.BH[i].DIndex] = B64[_state.BH[i].H];
|
||||
_state.BH[i].HalfDigest = B64[_state.BH[i].HalfH];
|
||||
|
||||
if (_state.BH[i].DIndex < SPAMSUM_LENGTH - 1)
|
||||
{
|
||||
// We can have a problem with the tail overflowing. The
|
||||
// easiest way to cope with this is to only reset the
|
||||
// normal hash if we have room for more characters in
|
||||
// our signature. This has the effect of combining the
|
||||
// last few pieces of the message into a single piece
|
||||
_state.BH[i].Digest[++_state.BH[i].DIndex] = 0x00;
|
||||
_state.BH[i].H = HASH_INIT;
|
||||
if (_state.BH[i].DIndex < SPAMSUM_LENGTH / 2)
|
||||
{
|
||||
_state.BH[i].HalfH = HASH_INIT;
|
||||
_state.BH[i].HalfDigest = 0x00;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_state.TryReduceBlockhash();
|
||||
}
|
||||
|
||||
if ((h & 1) != 0)
|
||||
break;
|
||||
|
||||
h >>= 1;
|
||||
} while (++i < _state.BHEnd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple non-rolling hash, based on the FNV hash
|
||||
/// </summary>
|
||||
private static byte SumHash(byte c, byte h) => SUM_TABLE[h][c & 0x3f];
|
||||
|
||||
/// <remarks>
|
||||
/// Originally named `fuzzy_digest`
|
||||
/// </remarks>
|
||||
private string? Finalize(uint flags)
|
||||
{
|
||||
uint bi = _state.BHStart;
|
||||
uint h = _state.Roll.RollSum();
|
||||
int i;
|
||||
|
||||
// Exclude terminating '\0'.
|
||||
int remain = FUZZY_MAX_RESULT - 1;
|
||||
|
||||
// Verify that our elimination was not overeager.
|
||||
if (bi != 0 && (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH >= _state.TotalSize)
|
||||
return null;
|
||||
|
||||
// The input exceeds data types.
|
||||
if (_state.TotalSize > SSDEEP_TOTAL_SIZE_MAX)
|
||||
return null;
|
||||
|
||||
// Initial blocksize guess.
|
||||
while ((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _state.TotalSize)
|
||||
{
|
||||
++bi;
|
||||
}
|
||||
|
||||
// Adapt blocksize guess to actual digest length.
|
||||
if (bi >= _state.BHEnd)
|
||||
bi = _state.BHEnd - 1;
|
||||
|
||||
while (bi > _state.BHStart && _state.BH[bi].DIndex < SPAMSUM_LENGTH / 2)
|
||||
{
|
||||
--bi;
|
||||
}
|
||||
|
||||
if (bi > 0 && _state.BH[bi].DIndex < SPAMSUM_LENGTH / 2)
|
||||
return null;
|
||||
|
||||
byte[] result = new byte[FUZZY_MAX_RESULT];
|
||||
int resultPtr = 0;
|
||||
|
||||
string prefixStr = $"{(ulong)SSDEEP_BS(bi)}:";
|
||||
byte[] prefixArr = Encoding.ASCII.GetBytes(prefixStr);
|
||||
Array.Copy(prefixArr, result, prefixArr.Length);
|
||||
|
||||
i = prefixArr.Length;
|
||||
if (i >= remain)
|
||||
return null;
|
||||
|
||||
remain -= i;
|
||||
resultPtr += i;
|
||||
|
||||
i = (int)_state.BH[bi].DIndex;
|
||||
if (i > remain)
|
||||
return null;
|
||||
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) != 0)
|
||||
i = EliminateSequences(result, resultPtr, _state.BH[bi].Digest, 0, i);
|
||||
else
|
||||
Array.Copy(_state.BH[bi].Digest, 0, result, resultPtr, i);
|
||||
|
||||
resultPtr += i;
|
||||
remain -= i;
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
result[resultPtr] = B64[_state.BH[bi].H];
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) == 0
|
||||
|| i < 3
|
||||
|| result[resultPtr] != result[resultPtr - 1]
|
||||
|| result[resultPtr] != result[resultPtr - 2]
|
||||
|| result[resultPtr] != result[resultPtr - 3])
|
||||
{
|
||||
++resultPtr;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else if (_state.BH[bi].Digest[_state.BH[bi].DIndex] != '\0')
|
||||
{
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
result[resultPtr] = _state.BH[bi].Digest[_state.BH[bi].DIndex];
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) == 0
|
||||
|| i < 3
|
||||
|| result[resultPtr] != result[resultPtr - 1]
|
||||
|| result[resultPtr] != result[resultPtr - 2]
|
||||
|| result[resultPtr] != result[resultPtr - 3])
|
||||
{
|
||||
++resultPtr;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
result[resultPtr++] = (byte)':';
|
||||
--remain;
|
||||
|
||||
if (bi < _state.BHEnd - 1)
|
||||
{
|
||||
++bi;
|
||||
i = (int)_state.BH[bi].DIndex;
|
||||
if ((flags & FUZZY_FLAG_NOTRUNC) == 0 && i > SPAMSUM_LENGTH / 2 - 1)
|
||||
i = SPAMSUM_LENGTH / 2 - 1;
|
||||
|
||||
if (i > remain)
|
||||
return null;
|
||||
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) != 0)
|
||||
i = EliminateSequences(result, resultPtr, _state.BH[bi].Digest, 0, i);
|
||||
else
|
||||
Array.Copy(_state.BH[bi].Digest, 0, result, resultPtr, i);
|
||||
|
||||
resultPtr += i;
|
||||
remain -= i;
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
h = (flags & FUZZY_FLAG_NOTRUNC) != 0
|
||||
? _state.BH[bi].H
|
||||
: _state.BH[bi].HalfH;
|
||||
|
||||
result[resultPtr] = B64[h];
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) == 0
|
||||
|| i < 3
|
||||
|| result[resultPtr] != result[resultPtr - 1]
|
||||
|| result[resultPtr] != result[resultPtr - 2]
|
||||
|| result[resultPtr] != result[resultPtr - 3])
|
||||
{
|
||||
++resultPtr;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = (flags & FUZZY_FLAG_NOTRUNC) != 0
|
||||
? _state.BH[bi].Digest[_state.BH[bi].DIndex]
|
||||
: _state.BH[bi].HalfDigest;
|
||||
|
||||
if (i != 0x00)
|
||||
{
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
result[resultPtr] = (byte)i;
|
||||
if ((flags & FUZZY_FLAG_ELIMSEQ) == 0
|
||||
|| i < 3
|
||||
|| result[resultPtr] != result[resultPtr - 1]
|
||||
|| result[resultPtr] != result[resultPtr - 2]
|
||||
|| result[resultPtr] != result[resultPtr - 3])
|
||||
{
|
||||
++resultPtr;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (h != 0)
|
||||
{
|
||||
if (bi != 0 && bi != NUM_BLOCKHASHES - 1)
|
||||
return null;
|
||||
if (remain <= 0)
|
||||
return null;
|
||||
|
||||
if (bi == 0)
|
||||
result[resultPtr++] = B64[_state.BH[bi].H];
|
||||
else
|
||||
result[resultPtr++] = B64[_state.LastH];
|
||||
|
||||
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
|
||||
* digest has length 1. */
|
||||
--remain;
|
||||
}
|
||||
|
||||
result[resultPtr] = 0x00;
|
||||
return Encoding.ASCII.GetString(result);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Originally named `memcpy_eliminate_sequences`
|
||||
/// </remarks>
|
||||
private static int EliminateSequences(byte[] dst, int dstPtr, byte[] src, int srcPtr, int n)
|
||||
{
|
||||
int srcend = srcPtr + n;
|
||||
if (n < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(n));
|
||||
|
||||
if (srcPtr < srcend) dst[dstPtr++] = src[srcPtr++];
|
||||
if (srcPtr < srcend) dst[dstPtr++] = src[srcPtr++];
|
||||
if (srcPtr < srcend) dst[dstPtr++] = src[srcPtr++];
|
||||
while (srcPtr < srcend)
|
||||
{
|
||||
if (src[srcPtr] == dst[dstPtr - 1]
|
||||
&& src[srcPtr] == dst[dstPtr - 2]
|
||||
&& src[srcPtr] == dst[dstPtr - 3])
|
||||
{
|
||||
++srcPtr;
|
||||
--n;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dstPtr++] = src[srcPtr++];
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,34 +13,6 @@ namespace SabreTools.Hashing.XxHash
|
||||
|
||||
#endregion
|
||||
|
||||
#region XXH32
|
||||
|
||||
public const uint XXH_PRIME32_1 = 0x9E3779B1;
|
||||
|
||||
public const uint XXH_PRIME32_2 = 0x85EBCA77;
|
||||
|
||||
public const uint XXH_PRIME32_3 = 0xC2B2AE3D;
|
||||
|
||||
public const uint XXH_PRIME32_4 = 0x27D4EB2F;
|
||||
|
||||
public const uint XXH_PRIME32_5 = 0x165667B1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region XXH64
|
||||
|
||||
public const ulong XXH_PRIME64_1 = 0x9E3779B185EBCA87;
|
||||
|
||||
public const ulong XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4F;
|
||||
|
||||
public const ulong XXH_PRIME64_3 = 0x165667B19E3779F9;
|
||||
|
||||
public const ulong XXH_PRIME64_4 = 0x85EBCA77C2B2AE63;
|
||||
|
||||
public const ulong XXH_PRIME64_5 = 0x27D4EB2F165667C5;
|
||||
|
||||
#endregion
|
||||
|
||||
#region XXH3
|
||||
|
||||
/// <summary>
|
||||
@@ -95,4 +67,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,4 +71,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
/// </summary>
|
||||
XXH_SVE = 6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.XxHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
@@ -248,4 +249,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace SabreTools.Hashing.XxHash
|
||||
internal class XXH3_128Hash
|
||||
{
|
||||
public ulong Low { get; set; }
|
||||
|
||||
|
||||
public ulong High { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
// Handle unused private fields
|
||||
#pragma warning disable CS0169
|
||||
#pragma warning disable CS0414
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0169
|
||||
#pragma warning disable CS0414
|
||||
#pragma warning disable CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Structure for XXH3 streaming API.
|
||||
@@ -106,7 +106,7 @@ namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
// TODO: XXH3_128bits_reset_withSecret
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
@@ -128,4 +128,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
return ulong.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
// Handle unused private fields
|
||||
#pragma warning disable CS0169
|
||||
#pragma warning disable CS0414
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0169
|
||||
#pragma warning disable CS0414
|
||||
#pragma warning disable CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Structure for XXH3 streaming API.
|
||||
@@ -111,7 +111,7 @@ namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
// TODO: XXH3_64bits_reset_withSecret
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
@@ -133,4 +133,4 @@ namespace SabreTools.Hashing.XxHash
|
||||
return ulong.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
public class XxHash32
|
||||
{
|
||||
/// <summary>
|
||||
/// The 32-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash32 state
|
||||
/// </summary>
|
||||
private readonly XXH32State _state;
|
||||
|
||||
public XxHash32(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XXH32State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public void TransformBlock(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the hash and return as a byte array
|
||||
/// </summary>
|
||||
public byte[] Finalize()
|
||||
{
|
||||
uint hash = _state.Digest();
|
||||
return BitConverter.GetBytes(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.XxHash
|
||||
{
|
||||
public class XxHash64
|
||||
{
|
||||
/// <summary>
|
||||
/// The 64-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash64 state
|
||||
/// </summary>
|
||||
private readonly XXH64State _state;
|
||||
|
||||
public XxHash64(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XXH64State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public void TransformBlock(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <summary>
|
||||
/// Finalize the hash and return as a byte array
|
||||
/// </summary>
|
||||
public byte[] Finalize()
|
||||
{
|
||||
ulong hash = _state.Digest();
|
||||
return BitConverter.GetBytes(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -620,4 +620,4 @@ namespace SabreTools.Hashing
|
||||
return _strings[hashType];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
publish-nix.sh
Normal file → Executable file
0
publish-nix.sh
Normal file → Executable file
Reference in New Issue
Block a user