Copy algorithms from current Aaru 6 dev tree.

This commit is contained in:
2021-09-28 00:46:47 +01:00
parent f963abe80a
commit c2244b767f
13 changed files with 1193 additions and 1711 deletions

View File

@@ -55,8 +55,8 @@
<ItemGroup>
<Compile Include="CRC16CCITTContext.cs"/>
<Compile Include="CRC16IBMContext.cs"/>
<Compile Include="CRC32CLMUL.cs"/>
<Compile Include="CRC64CLMUL.cs"/>
<Compile Include="CRC32\clmul.cs"/>
<Compile Include="CRC64\clmul.cs"/>
<Compile Include="SpamSumContext.cs"/>
<Compile Include="Adler32Context.cs"/>
<Compile Include="CRC16Context.cs"/>

View File

@@ -41,9 +41,9 @@ namespace Aaru6.Checksums
/// <summary>Implements the Adler-32 algorithm</summary>
public sealed class Adler32Context : IChecksum
{
const uint ADLER_MODULE = 65521;
const uint NMAX = 5552;
ushort _sum1, _sum2;
const ushort ADLER_MODULE = 65521;
const uint NMAX = 5552;
ushort _sum1, _sum2;
/// <summary>Initializes the Adler-32 sums</summary>
public Adler32Context()
@@ -56,10 +56,39 @@ namespace Aaru6.Checksums
/// <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)
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint sum1 = _sum1;
uint sum2 = _sum2;
uint finalSum = (uint)((_sum2 << 16) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
var adlerOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return adlerOutput.ToString();
}
static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len)
{
uint sum1 = preSum1;
uint sum2 = preSum2;
uint n;
int dataOff = 0;
@@ -76,8 +105,8 @@ namespace Aaru6.Checksums
if(sum2 >= ADLER_MODULE)
sum2 -= ADLER_MODULE;
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
@@ -94,9 +123,9 @@ namespace Aaru6.Checksums
if(sum1 >= ADLER_MODULE)
sum1 -= ADLER_MODULE;
sum2 %= ADLER_MODULE; /* only added so many ADLER_MODULE's */
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
sum2 %= ADLER_MODULE; /* only added so many ADLER_MODULE's */
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
@@ -203,35 +232,8 @@ namespace Aaru6.Checksums
sum2 %= ADLER_MODULE;
}
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
var adlerOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return adlerOutput.ToString();
preSum1 = (ushort)(sum1 & 0xFFFF);
preSum2 = (ushort)(sum2 & 0xFFFF);
}
/// <summary>Gets the hash of a file</summary>
@@ -253,10 +255,13 @@ namespace Aaru6.Checksums
ushort localSum1 = 1;
ushort localSum2 = 0;
for(int i = 0; i < fileStream.Length; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
localSum1 = (ushort)((localSum1 + fileStream.ReadByte()) % ADLER_MODULE);
localSum2 = (ushort)((localSum2 + localSum1) % ADLER_MODULE);
Step(ref localSum1, ref localSum2, buffer, (uint)read);
read = fileStream.Read(buffer, 0, 65536);
}
uint finalSum = (uint)((localSum2 << 16) | localSum1);
@@ -282,11 +287,7 @@ namespace Aaru6.Checksums
ushort localSum1 = 1;
ushort localSum2 = 0;
for(int i = 0; i < len; i++)
{
localSum1 = (ushort)((localSum1 + data[i]) % ADLER_MODULE);
localSum2 = (ushort)((localSum2 + localSum1) % ADLER_MODULE);
}
Step(ref localSum1, ref localSum2, data, len);
uint finalSum = (uint)((localSum2 << 16) | localSum1);

View File

@@ -30,22 +30,17 @@
// Copyright © 2011-2021 Natalia Portillo
// ****************************************************************************/
using System;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru6.Checksums
{
/// <inheritdoc />
/// <summary>Implements the CRC16 algorithm with CCITT polynomial and seed</summary>
public sealed class CRC16CCITTContext : IChecksum
public sealed class CRC16CCITTContext : Crc16Context
{
/// <summary>CCITT CRC16 polynomial</summary>
public const ushort CRC16_CCITT_POLY = 0x8408;
/// <summary>CCITT CRC16 seed</summary>
public const ushort CRC16_CCITT_SEED = 0x0000;
static readonly ushort[][] crc16_ccitt_table =
static readonly ushort[][] _ccittCrc16Table =
{
new ushort[]
{
@@ -232,61 +227,10 @@ namespace Aaru6.Checksums
0x8A95, 0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F
}
};
ushort _crc;
/// <summary>Initializes an instance of the CRC16 with IBM polynomial and seed.</summary>
/// <summary>Initializes an instance of the CRC16 with CCITT polynomial and seed.</summary>
/// <inheritdoc />
public CRC16CCITTContext() => _crc = 0;
/// <inheritdoc />
public void Update(byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ushort crc;
int current_pos = 0;
const int unroll = 4;
const int bytes_at_once = 8 * unroll;
crc = _crc;
while(len >= bytes_at_once)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
crc = (ushort)(crc16_ccitt_table[7][data[current_pos + 0] ^ (crc >> 8)] ^
crc16_ccitt_table[6][data[current_pos + 1] ^ (crc & 0xFF)] ^
crc16_ccitt_table[5][data[current_pos + 2]] ^
crc16_ccitt_table[4][data[current_pos + 3]] ^
crc16_ccitt_table[3][data[current_pos + 4]] ^
crc16_ccitt_table[2][data[current_pos + 5]] ^
crc16_ccitt_table[1][data[current_pos + 6]] ^
crc16_ccitt_table[0][data[current_pos + 7]]);
current_pos += 8;
}
len -= bytes_at_once;
}
while(len-- != 0)
crc = (ushort)((crc << 8) ^ crc16_ccitt_table[0][(crc >> 8) ^ data[current_pos++]]);
_crc = crc;
}
/// <inheritdoc />
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
public byte[] Final() => BigEndianBitConverter.GetBytes(_crc);
/// <inheritdoc />
public string End() => throw new NotImplementedException();
public CRC16CCITTContext() : base(CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true) {}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
@@ -300,21 +244,24 @@ namespace Aaru6.Checksums
/// <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();
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) => throw new NotImplementedException();
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
/// <summary>Calculates the IBM CRC16 of the specified buffer with the specified parameters</summary>
/// <summary>Calculates the CCITT CRC16 of the specified buffer with the specified parameters</summary>
/// <param name="buffer">Buffer</param>
public static ushort Calculate(byte[] buffer) => throw new NotImplementedException();
public static ushort Calculate(byte[] buffer) =>
Calculate(buffer, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
}
}

View File

@@ -30,25 +30,25 @@
// Copyright © 2011-2021 Natalia Portillo
// ****************************************************************************/
using System;
using System.IO;
using System.Linq;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru.Checksums
namespace Aaru6.Checksums
{
/// <inheritdoc />
/// <summary>Implements a CRC16 algorithm</summary>
public class Crc16Context : IChecksum
{
readonly ushort _finalSeed;
readonly bool _inverse;
readonly ushort[] _table;
ushort _hashInt;
readonly ushort _finalSeed;
readonly bool _inverse;
readonly ushort[][] _table;
ushort _hashInt;
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc16Context(ushort polynomial, ushort seed, ushort[] table, bool inverse)
public Crc16Context(ushort polynomial, ushort seed, ushort[][] table, bool inverse)
{
_hashInt = seed;
_finalSeed = seed;
@@ -63,13 +63,10 @@ namespace Aaru.Checksums
/// <param name="len">Length of buffer to hash.</param>
public void Update(byte[] data, uint len)
{
for(int i = 0; i < len; i++)
{
if(_inverse)
_hashInt = (ushort)((_hashInt << 8) ^ _table[data[i] ^ (_hashInt >> 8)]);
else
_hashInt = (ushort)((_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xFF)]);
}
if(_inverse)
StepInverse(ref _hashInt, _table, data, len);
else
Step(ref _hashInt, _table, data, len);
}
/// <inheritdoc />
@@ -79,7 +76,8 @@ namespace Aaru.Checksums
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final() => BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed));
public byte[] Final() => !_inverse ? BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed))
: BigEndianBitConverter.GetBytes((ushort)~(_hashInt ^ _finalSeed));
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
@@ -100,9 +98,88 @@ namespace Aaru.Checksums
return crc16Output.ToString();
}
static ushort[] GenerateTable(ushort polynomial, bool inverseTable)
static void Step(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
{
ushort[] table = new ushort[256];
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ushort crc;
int current_pos = 0;
const int unroll = 4;
const int bytes_at_once = 8 * unroll;
crc = previousCrc;
while(len >= bytes_at_once)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
// TODO: What trick is Microsoft doing here that's faster than arithmetic conversion
uint one = BitConverter.ToUInt32(data, current_pos) ^ crc;
current_pos += 4;
uint two = BitConverter.ToUInt32(data, current_pos);
current_pos += 4;
crc = (ushort)(table[0][(two >> 24) & 0xFF] ^ table[1][(two >> 16) & 0xFF] ^
table[2][(two >> 8) & 0xFF] ^ table[3][two & 0xFF] ^ table[4][(one >> 24) & 0xFF] ^
table[5][(one >> 16) & 0xFF] ^ table[6][(one >> 8) & 0xFF] ^ table[7][one & 0xFF]);
}
len -= bytes_at_once;
}
while(len-- != 0)
crc = (ushort)((crc >> 8) ^ table[0][(crc & 0xFF) ^ data[current_pos++]]);
previousCrc = crc;
}
static void StepInverse(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ushort crc;
int current_pos = 0;
const int unroll = 4;
const int bytes_at_once = 8 * unroll;
crc = previousCrc;
while(len >= bytes_at_once)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
crc = (ushort)(table[7][data[current_pos + 0] ^ (crc >> 8)] ^
table[6][data[current_pos + 1] ^ (crc & 0xFF)] ^ table[5][data[current_pos + 2]] ^
table[4][data[current_pos + 3]] ^ table[3][data[current_pos + 4]] ^
table[2][data[current_pos + 5]] ^ table[1][data[current_pos + 6]] ^
table[0][data[current_pos + 7]]);
current_pos += 8;
}
len -= bytes_at_once;
}
while(len-- != 0)
crc = (ushort)((crc << 8) ^ table[0][(crc >> 8) ^ data[current_pos++]]);
previousCrc = crc;
}
static ushort[][] GenerateTable(ushort polynomial, bool inverseTable)
{
ushort[][] table = new ushort[8][];
for(int i = 0; i < 8; i++)
table[i] = new ushort[256];
if(!inverseTable)
for(uint i = 0; i < 256; i++)
@@ -115,7 +192,7 @@ namespace Aaru.Checksums
else
entry >>= 1;
table[i] = (ushort)entry;
table[0][i] = (ushort)entry;
}
else
{
@@ -130,11 +207,20 @@ namespace Aaru.Checksums
else
entry <<= 1;
table[i] = (ushort)entry;
table[0][i] = (ushort)entry;
}
}
}
for(int slice = 1; slice < 8; slice++)
for(int i = 0; i < 256; i++)
{
if(inverseTable)
table[slice][i] = (ushort)((table[slice - 1][i] << 8) ^ table[0][table[slice - 1][i] >> 8]);
else
table[slice][i] = (ushort)((table[slice - 1][i] >> 8) ^ table[0][table[slice - 1][i] & 0xFF]);
}
return table;
}
@@ -145,22 +231,27 @@ namespace Aaru.Checksums
/// <param name="seed">CRC seed</param>
/// <param name="table">CRC lookup table</param>
/// <param name="inverse">Is CRC inverted?</param>
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[] table,
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
bool inverse)
{
var fileStream = new FileStream(filename, FileMode.Open);
ushort localHashInt = seed;
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
for(int i = 0; i < fileStream.Length; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
if(inverse)
localHashInt =
(ushort)(localTable[(localHashInt >> 8) ^ fileStream.ReadByte()] ^ (localHashInt << 8));
StepInverse(ref localHashInt, localTable, buffer, (uint)read);
else
localHashInt =
(ushort)((localHashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localHashInt & 0xff)]);
Step(ref localHashInt, localTable, buffer, (uint)read);
read = fileStream.Read(buffer, 0, 65536);
}
localHashInt ^= seed;
@@ -188,17 +279,16 @@ namespace Aaru.Checksums
/// <param name="table">CRC lookup table</param>
/// <param name="inverse">Is CRC inverted?</param>
public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed,
ushort[] table, bool inverse)
ushort[][] table, bool inverse)
{
ushort localHashInt = seed;
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
for(int i = 0; i < len; i++)
if(inverse)
localHashInt = (ushort)(localTable[(localHashInt >> 8) ^ data[i]] ^ (localHashInt << 8));
else
localHashInt = (ushort)((localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)]);
if(inverse)
StepInverse(ref localHashInt, localTable, data, len);
else
Step(ref localHashInt, localTable, data, len);
localHashInt ^= seed;
@@ -222,22 +312,23 @@ namespace Aaru.Checksums
/// <param name="table">Pre-generated lookup table</param>
/// <param name="inverse">Inverse CRC</param>
/// <returns>CRC16</returns>
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[] table, bool inverse)
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[][] table, bool inverse)
{
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
ushort localHashInt = seed;
ushort crc16 =
buffer.Aggregate<byte, ushort>(0,
(current, b) =>
inverse ? (ushort)(localTable[(current >> 8) ^ b] ^ (current << 8))
: (ushort)((current >> 8) ^ localTable[b ^ (current & 0xff)]));
crc16 ^= seed;
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
if(inverse)
crc16 = (ushort)~crc16;
StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length);
else
Step(ref localHashInt, localTable, buffer, (uint)buffer.Length);
return crc16;
localHashInt ^= seed;
if(inverse)
localHashInt = (ushort)~localHashInt;
return localHashInt;
}
}
}

View File

@@ -30,20 +30,16 @@
// Copyright © 2011-2021 Natalia Portillo
// ****************************************************************************/
using System;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
namespace Aaru6.Checksums
{
/// <inheritdoc />
/// <summary>Implements the CRC16 algorithm with IBM polynomial and seed</summary>
public sealed class CRC16IBMContext : IChecksum
public sealed class CRC16IBMContext : Crc16Context
{
const ushort CRC16_IBM_POLY = 0xA001;
const ushort CRC16_IBM_SEED = 0x0000;
static readonly ushort[][] crc16_table =
static readonly ushort[][] _ibmCrc16Table =
{
new ushort[]
{
@@ -230,60 +226,10 @@ namespace Aaru6.Checksums
0xA24E, 0xE20E, 0x2ECF, 0x3B8F, 0xF74E, 0x110F, 0xDDCE, 0xC88E, 0x044F
}
};
ushort _crc;
/// <summary>Initializes an instance of the CRC16 with IBM polynomial and seed.</summary>
/// <inheritdoc />
public CRC16IBMContext() => _crc = 0;
/// <inheritdoc />
public void Update(byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ushort crc;
int current_pos = 0;
const int unroll = 4;
const int bytes_at_once = 8 * unroll;
crc = _crc;
while(len >= bytes_at_once)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
uint one = BitConverter.ToUInt32(data, current_pos) ^ crc;
current_pos += 4;
uint two = BitConverter.ToUInt32(data, current_pos);
current_pos += 4;
crc = (ushort)(crc16_table[0][(two >> 24) & 0xFF] ^ crc16_table[1][(two >> 16) & 0xFF] ^
crc16_table[2][(two >> 8) & 0xFF] ^ crc16_table[3][two & 0xFF] ^
crc16_table[4][(one >> 24) & 0xFF] ^ crc16_table[5][(one >> 16) & 0xFF] ^
crc16_table[6][(one >> 8) & 0xFF] ^ crc16_table[7][one & 0xFF]);
}
len -= bytes_at_once;
}
while(len-- != 0)
crc = (ushort)((crc >> 8) ^ crc16_table[0][(crc & 0xFF) ^ data[current_pos++]]);
_crc = crc;
}
/// <inheritdoc />
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
public byte[] Final() => BigEndianBitConverter.GetBytes(_crc);
/// <inheritdoc />
public string End() => throw new NotImplementedException();
public CRC16IBMContext() : base(CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false) {}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
@@ -297,21 +243,19 @@ namespace Aaru6.Checksums
/// <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();
public static string File(string filename, out byte[] hash) =>
File(filename, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="len">Length of the data buffer to hash.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, uint len, out byte[] hash) => throw new NotImplementedException();
public static string Data(byte[] data, uint len, out byte[] hash) =>
Data(data, len, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
/// <summary>Gets the hash of the specified data buffer.</summary>
/// <param name="data">Data buffer.</param>
/// <param name="hash">Byte array of the hash value.</param>
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
/// <summary>Calculates the IBM CRC16 of the specified buffer with the specified parameters</summary>
/// <param name="buffer">Buffer</param>
public static ushort Calculate(byte[] buffer) => throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,541 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : clmul.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// Wajdi Feghali <wajdi.k.feghali@intel.com>
// Jim Guilford <james.guilford@intel.com>
// Vinodh Gopal <vinodh.gopal@intel.com>
// Erdinc Ozturk <erdinc.ozturk@intel.com>
// Jim Kukunas <james.t.kukunas@linux.intel.com>
// Marian Beermann
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
// instruction.
//
// A white paper describing this algorithm can be found at:
// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
//
// --[ License ] --------------------------------------------------------------
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2021 Natalia Portillo
// Copyright (c) 2016 Marian Beermann (add support for initial value, restructuring)
// Copyright (C) 2013 Intel Corporation. All rights reserved.
// ****************************************************************************/
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru6.Checksums.CRC32
{
internal static class Clmul
{
static readonly uint[] _crcK =
{
0xccaa009e, 0x00000000, /* rk1 */ 0x751997d0, 0x00000001, /* rk2 */ 0xccaa009e, 0x00000000, /* rk5 */
0x63cd6124, 0x00000001, /* rk6 */ 0xf7011640, 0x00000001, /* rk7 */ 0xdb710640, 0x00000001 /* rk8 */
};
static readonly Vector128<uint>[] _pshufbShfTable =
{
Vector128.Create(0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d), /* shl 15 (16 - 1)/shr1 */
Vector128.Create(0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e), /* shl 14 (16 - 3)/shr2 */
Vector128.Create(0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f), /* shl 13 (16 - 4)/shr3 */
Vector128.Create(0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100), /* shl 12 (16 - 4)/shr4 */
Vector128.Create(0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201), /* shl 11 (16 - 5)/shr5 */
Vector128.Create(0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302), /* shl 10 (16 - 6)/shr6 */
Vector128.Create(0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403), /* shl 9 (16 - 7)/shr7 */
Vector128.Create(0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504), /* shl 8 (16 - 8)/shr8 */
Vector128.Create(0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605), /* shl 7 (16 - 9)/shr9 */
Vector128.Create(0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706), /* shl 6 (16 -10)/shr10*/
Vector128.Create(0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807), /* shl 5 (16 -11)/shr11*/
Vector128.Create(0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908), /* shl 4 (16 -12)/shr12*/
Vector128.Create(0x008f8e8du, 0x04030201, 0x08070605, 0x0c0b0a09), /* shl 3 (16 -13)/shr13*/
Vector128.Create(0x01008f8eu, 0x05040302, 0x09080706, 0x0d0c0b0a), /* shl 2 (16 -14)/shr14*/
Vector128.Create(0x0201008fu, 0x06050403, 0x0a090807, 0x0e0d0c0b) /* shl 1 (16 -15)/shr15*/
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Fold1(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
ref Vector128<uint> xmmCRC3)
{
Vector128<uint> xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> xTmp3 = xmmCRC3;
xmmCRC3 = xmmCRC0;
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psRes = Sse.Xor(psCRC0, psCRC3);
xmmCRC0 = xmmCRC1;
xmmCRC1 = xmmCRC2;
xmmCRC2 = xTmp3;
xmmCRC3 = psRes.AsUInt32();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Fold2(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
ref Vector128<uint> xmmCRC3)
{
Vector128<uint> xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> xTmp3 = xmmCRC3;
Vector128<uint> xTmp2 = xmmCRC2;
xmmCRC3 = xmmCRC1;
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psCRC1 = xmmCRC1.AsSingle();
Vector128<float> psRes31 = Sse.Xor(psCRC3, psCRC1);
xmmCRC2 = xmmCRC0;
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
Vector128<float> psCRC2 = xmmCRC2.AsSingle();
Vector128<float> psRes20 = Sse.Xor(psCRC0, psCRC2);
xmmCRC0 = xTmp2;
xmmCRC1 = xTmp3;
xmmCRC2 = psRes20.AsUInt32();
xmmCRC3 = psRes31.AsUInt32();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Fold3(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
ref Vector128<uint> xmmCRC3)
{
Vector128<uint> xmmFold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001);
Vector128<uint> xTmp3 = xmmCRC3;
xmmCRC3 = xmmCRC2;
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC2 = xmmCRC2.AsSingle();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psRes32 = Sse.Xor(psCRC2, psCRC3);
xmmCRC2 = xmmCRC1;
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC1 = xmmCRC1.AsSingle();
psCRC2 = xmmCRC2.AsSingle();
Vector128<float> psRes21 = Sse.Xor(psCRC1, psCRC2);
xmmCRC1 = xmmCRC0;
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
psCRC1 = xmmCRC1.AsSingle();
Vector128<float> psRes10 = Sse.Xor(psCRC0, psCRC1);
xmmCRC0 = xTmp3;
xmmCRC1 = psRes10.AsUInt32();
xmmCRC2 = psRes21.AsUInt32();
xmmCRC3 = psRes32.AsUInt32();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Fold4(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
ref Vector128<uint> xmmCRC3)
{
Vector128<uint> xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> xTmp0 = xmmCRC0;
Vector128<uint> xTmp1 = xmmCRC1;
Vector128<uint> xTmp2 = xmmCRC2;
Vector128<uint> xTmp3 = xmmCRC3;
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp0 = Pclmulqdq.CarrylessMultiply(xTmp0.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
Vector128<float> psT0 = xTmp0.AsSingle();
Vector128<float> psRes0 = Sse.Xor(psCRC0, psT0);
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp1 = Pclmulqdq.CarrylessMultiply(xTmp1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC1 = xmmCRC1.AsSingle();
Vector128<float> psT1 = xTmp1.AsSingle();
Vector128<float> psRes1 = Sse.Xor(psCRC1, psT1);
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp2 = Pclmulqdq.CarrylessMultiply(xTmp2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC2 = xmmCRC2.AsSingle();
Vector128<float> psT2 = xTmp2.AsSingle();
Vector128<float> psRes2 = Sse.Xor(psCRC2, psT2);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
xTmp3 = Pclmulqdq.CarrylessMultiply(xTmp3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psT3 = xTmp3.AsSingle();
Vector128<float> psRes3 = Sse.Xor(psCRC3, psT3);
xmmCRC0 = psRes0.AsUInt32();
xmmCRC1 = psRes1.AsUInt32();
xmmCRC2 = psRes2.AsUInt32();
xmmCRC3 = psRes3.AsUInt32();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void PartialFold(long len, ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1,
ref Vector128<uint> xmmCRC2, ref Vector128<uint> xmmCRC3,
ref Vector128<uint> xmmCRCPart)
{
Vector128<uint> xmmFold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001);
Vector128<uint> xmmMask3 = Vector128.Create(0x80808080);
Vector128<uint> xmmShl = _pshufbShfTable[len - 1];
Vector128<uint> xmmShr = xmmShl;
xmmShr = Sse2.Xor(xmmShr, xmmMask3);
Vector128<uint> xmmA00 = Ssse3.Shuffle(xmmCRC0.AsByte(), xmmShl.AsByte()).AsUInt32();
xmmCRC0 = Ssse3.Shuffle(xmmCRC0.AsByte(), xmmShr.AsByte()).AsUInt32();
Vector128<uint> xmmTmp1 = Ssse3.Shuffle(xmmCRC1.AsByte(), xmmShl.AsByte()).AsUInt32();
xmmCRC0 = Sse2.Or(xmmCRC0, xmmTmp1);
xmmCRC1 = Ssse3.Shuffle(xmmCRC1.AsByte(), xmmShr.AsByte()).AsUInt32();
Vector128<uint> xmmTmp2 = Ssse3.Shuffle(xmmCRC2.AsByte(), xmmShl.AsByte()).AsUInt32();
xmmCRC1 = Sse2.Or(xmmCRC1, xmmTmp2);
xmmCRC2 = Ssse3.Shuffle(xmmCRC2.AsByte(), xmmShr.AsByte()).AsUInt32();
Vector128<uint> xmmTmp3 = Ssse3.Shuffle(xmmCRC3.AsByte(), xmmShl.AsByte()).AsUInt32();
xmmCRC2 = Sse2.Or(xmmCRC2, xmmTmp3);
xmmCRC3 = Ssse3.Shuffle(xmmCRC3.AsByte(), xmmShr.AsByte()).AsUInt32();
xmmCRCPart = Ssse3.Shuffle(xmmCRCPart.AsByte(), xmmShl.AsByte()).AsUInt32();
xmmCRC3 = Sse2.Or(xmmCRC3, xmmCRCPart);
Vector128<uint> xmmA01 = Pclmulqdq.CarrylessMultiply(xmmA00.AsUInt64(), xmmFold4.AsUInt64(), 0x10).
AsUInt32();
xmmA00 = Pclmulqdq.CarrylessMultiply(xmmA00.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
Vector128<float> psa00 = xmmA00.AsSingle();
Vector128<float> psa01 = xmmA01.AsSingle();
Vector128<float> psRes = Sse.Xor(psCRC3, psa00);
psRes = Sse.Xor(psRes, psa01);
xmmCRC3 = psRes.AsUInt32();
}
internal static uint Step(byte[] src, long len, uint initialCRC)
{
Vector128<uint> xmmT0, xmmT1, xmmT2;
Vector128<uint> xmmInitial = Sse2.ConvertScalarToVector128UInt32(initialCRC);
Vector128<uint> xmmCRC0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487);
Vector128<uint> xmmCRC1 = Vector128<uint>.Zero;
Vector128<uint> xmmCRC2 = Vector128<uint>.Zero;
Vector128<uint> xmmCRC3 = Vector128<uint>.Zero;
Vector128<uint> xmmCRCPart;
int bufPos = 0;
bool first = true;
/* fold 512 to 32 step variable declarations for ISO-C90 compat. */
Vector128<uint> xmmMask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000);
Vector128<uint> xmmMask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
uint crc;
if(len < 16)
{
switch(len)
{
case 0: return initialCRC;
case < 4:
/*
* no idea how to do this for <4 bytes, delegate to classic impl.
*/
crc = ~initialCRC;
switch(len)
{
case 3:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos++]];
goto case 2;
case 2:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos++]];
goto case 1;
case 1:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos]];
break;
}
return ~crc;
}
xmmCRCPart = Vector128.Create(BitConverter.ToUInt32(src, 0), BitConverter.ToUInt32(src, 4),
BitConverter.ToUInt32(src, 8), BitConverter.ToUInt32(src, 12));
xmmCRCPart = Sse2.Xor(xmmCRCPart, xmmInitial);
goto partial;
}
while((len -= 64) >= 0)
{
xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmmT2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
Vector128<uint> xmmT3 = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
}
Fold4(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
xmmCRC0 = Sse2.Xor(xmmCRC0, xmmT0);
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmT1);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT3);
}
/*
* len = num bytes left - 64
*/
if(len + 16 >= 0)
{
len += 16;
xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmmT2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
Fold3(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmT0);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT1);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT2);
if(len == 0)
goto done;
xmmCRCPart = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else if(len + 32 >= 0)
{
len += 32;
xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
Fold2(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT0);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT1);
if(len == 0)
goto done;
xmmCRCPart = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else if(len + 48 >= 0)
{
len += 48;
xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
Fold1(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT0);
if(len == 0)
goto done;
xmmCRCPart = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else
{
len += 64;
if(len == 0)
goto done;
xmmCRCPart = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
if(first)
xmmCRCPart = Sse2.Xor(xmmCRCPart, xmmInitial);
}
partial:
PartialFold(len, ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3, ref xmmCRCPart);
done:
/* fold 512 to 32 */
/*
* k1
*/
Vector128<uint> crcFold = Vector128.Create(_crcK[0], _crcK[1], _crcK[2], _crcK[3]);
Vector128<uint> xTmp0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x10).
AsUInt32();
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC1 = Sse2.Xor(xmmCRC1, xTmp0);
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmCRC0);
Vector128<uint> xTmp1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x10).
AsUInt32();
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC2 = Sse2.Xor(xmmCRC2, xTmp1);
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmCRC1);
Vector128<uint> xTmp2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x10).
AsUInt32();
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xTmp2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
/*
* k5
*/
crcFold = Vector128.Create(_crcK[4], _crcK[5], _crcK[6], _crcK[7]);
xmmCRC0 = xmmCRC3;
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
xmmCRC0 = Sse2.ShiftRightLogical128BitLane(xmmCRC0, 8);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
xmmCRC0 = xmmCRC3;
xmmCRC3 = Sse2.ShiftLeftLogical128BitLane(xmmCRC3, 4);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask2);
/*
* k7
*/
xmmCRC1 = xmmCRC3;
xmmCRC2 = xmmCRC3;
crcFold = Vector128.Create(_crcK[8], _crcK[9], _crcK[10], _crcK[11]);
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask);
xmmCRC2 = xmmCRC3;
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC1);
/*
* could just as well write xmm_crc3[2], doing a movaps and truncating, but
* no real advantage - it's a tiny bit slower per call, while no additional CPUs
* would be supported by only requiring SSSE3 and CLMUL instead of SSE4.1 + CLMUL
*/
crc = Sse41.Extract(xmmCRC3, 2);
return ~crc;
}
}
}

View File

@@ -1,562 +0,0 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : clmul.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
// Wajdi Feghali <wajdi.k.feghali@intel.com>
// Jim Guilford <james.guilford@intel.com>
// Vinodh Gopal <vinodh.gopal@intel.com>
// Erdinc Ozturk <erdinc.ozturk@intel.com>
// Jim Kukunas <james.t.kukunas@linux.intel.com>
// Marian Beermann
//
// Component : Checksums.
//
// --[ Description ] ----------------------------------------------------------
//
// Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
// instruction.
//
// A white paper describing this algorithm can be found at:
// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
//
// --[ License ] --------------------------------------------------------------
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2021 Natalia Portillo
// Copyright (c) 2016 Marian Beermann (add support for initial value, restructuring)
// Copyright (C) 2013 Intel Corporation. All rights reserved.
// ****************************************************************************/
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru6.Checksums
{
public static class CRC32CLMUL
{
static readonly uint[] crc_k =
{
0xccaa009e, 0x00000000, /* rk1 */ 0x751997d0, 0x00000001, /* rk2 */ 0xccaa009e, 0x00000000, /* rk5 */
0x63cd6124, 0x00000001, /* rk6 */ 0xf7011640, 0x00000001, /* rk7 */ 0xdb710640, 0x00000001 /* rk8 */
};
static readonly Vector128<uint>[] pshufb_shf_table =
{
Vector128.Create(0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d), /* shl 15 (16 - 1)/shr1 */
Vector128.Create(0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e), /* shl 14 (16 - 3)/shr2 */
Vector128.Create(0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f), /* shl 13 (16 - 4)/shr3 */
Vector128.Create(0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100), /* shl 12 (16 - 4)/shr4 */
Vector128.Create(0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201), /* shl 11 (16 - 5)/shr5 */
Vector128.Create(0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302), /* shl 10 (16 - 6)/shr6 */
Vector128.Create(0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403), /* shl 9 (16 - 7)/shr7 */
Vector128.Create(0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504), /* shl 8 (16 - 8)/shr8 */
Vector128.Create(0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605), /* shl 7 (16 - 9)/shr9 */
Vector128.Create(0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706), /* shl 6 (16 -10)/shr10*/
Vector128.Create(0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807), /* shl 5 (16 -11)/shr11*/
Vector128.Create(0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908), /* shl 4 (16 -12)/shr12*/
Vector128.Create(0x008f8e8du, 0x04030201, 0x08070605, 0x0c0b0a09), /* shl 3 (16 -13)/shr13*/
Vector128.Create(0x01008f8eu, 0x05040302, 0x09080706, 0x0d0c0b0a), /* shl 2 (16 -14)/shr14*/
Vector128.Create(0x0201008fu, 0x06050403, 0x0a090807, 0x0e0d0c0b) /* shl 1 (16 -15)/shr15*/
};
static void fold_1(ref Vector128<uint> xmm_crc0, ref Vector128<uint> xmm_crc1, ref Vector128<uint> xmm_crc2,
ref Vector128<uint> xmm_crc3)
{
Vector128<uint> xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> x_tmp3;
Vector128<float> ps_crc0, ps_crc3, ps_res;
x_tmp3 = xmm_crc3;
xmm_crc3 = xmm_crc0;
xmm_crc0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc0 = xmm_crc0.AsSingle();
ps_crc3 = xmm_crc3.AsSingle();
ps_res = Sse.Xor(ps_crc0, ps_crc3);
xmm_crc0 = xmm_crc1;
xmm_crc1 = xmm_crc2;
xmm_crc2 = x_tmp3;
xmm_crc3 = ps_res.AsUInt32();
}
static void fold_2(ref Vector128<uint> xmm_crc0, ref Vector128<uint> xmm_crc1, ref Vector128<uint> xmm_crc2,
ref Vector128<uint> xmm_crc3)
{
Vector128<uint> xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> x_tmp3, x_tmp2;
Vector128<float> ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res31, ps_res20;
x_tmp3 = xmm_crc3;
x_tmp2 = xmm_crc2;
xmm_crc3 = xmm_crc1;
xmm_crc1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc3 = xmm_crc3.AsSingle();
ps_crc1 = xmm_crc1.AsSingle();
ps_res31 = Sse.Xor(ps_crc3, ps_crc1);
xmm_crc2 = xmm_crc0;
xmm_crc0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc0 = xmm_crc0.AsSingle();
ps_crc2 = xmm_crc2.AsSingle();
ps_res20 = Sse.Xor(ps_crc0, ps_crc2);
xmm_crc0 = x_tmp2;
xmm_crc1 = x_tmp3;
xmm_crc2 = ps_res20.AsUInt32();
xmm_crc3 = ps_res31.AsUInt32();
}
static void fold_3(ref Vector128<uint> xmm_crc0, ref Vector128<uint> xmm_crc1, ref Vector128<uint> xmm_crc2,
ref Vector128<uint> xmm_crc3)
{
Vector128<uint> xmm_fold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001);
Vector128<uint> x_tmp3;
Vector128<float> ps_crc0, ps_crc1, ps_crc2, ps_crc3, ps_res32, ps_res21, ps_res10;
x_tmp3 = xmm_crc3;
xmm_crc3 = xmm_crc2;
xmm_crc2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc2 = xmm_crc2.AsSingle();
ps_crc3 = xmm_crc3.AsSingle();
ps_res32 = Sse.Xor(ps_crc2, ps_crc3);
xmm_crc2 = xmm_crc1;
xmm_crc1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc1 = xmm_crc1.AsSingle();
ps_crc2 = xmm_crc2.AsSingle();
ps_res21 = Sse.Xor(ps_crc1, ps_crc2);
xmm_crc1 = xmm_crc0;
xmm_crc0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
xmm_crc1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc0 = xmm_crc0.AsSingle();
ps_crc1 = xmm_crc1.AsSingle();
ps_res10 = Sse.Xor(ps_crc0, ps_crc1);
xmm_crc0 = x_tmp3;
xmm_crc1 = ps_res10.AsUInt32();
xmm_crc2 = ps_res21.AsUInt32();
xmm_crc3 = ps_res32.AsUInt32();
}
static void fold_4(ref Vector128<uint> xmm_crc0, ref Vector128<uint> xmm_crc1, ref Vector128<uint> xmm_crc2,
ref Vector128<uint> xmm_crc3)
{
Vector128<uint> xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
Vector128<uint> x_tmp0, x_tmp1, x_tmp2, x_tmp3;
Vector128<float> ps_crc0, ps_crc1, ps_crc2, ps_crc3;
Vector128<float> ps_t0, ps_t1, ps_t2, ps_t3;
Vector128<float> ps_res0, ps_res1, ps_res2, ps_res3;
x_tmp0 = xmm_crc0;
x_tmp1 = xmm_crc1;
x_tmp2 = xmm_crc2;
x_tmp3 = xmm_crc3;
xmm_crc0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
x_tmp0 = Pclmulqdq.CarrylessMultiply(x_tmp0.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc0 = xmm_crc0.AsSingle();
ps_t0 = x_tmp0.AsSingle();
ps_res0 = Sse.Xor(ps_crc0, ps_t0);
xmm_crc1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
x_tmp1 = Pclmulqdq.CarrylessMultiply(x_tmp1.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc1 = xmm_crc1.AsSingle();
ps_t1 = x_tmp1.AsSingle();
ps_res1 = Sse.Xor(ps_crc1, ps_t1);
xmm_crc2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
x_tmp2 = Pclmulqdq.CarrylessMultiply(x_tmp2.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc2 = xmm_crc2.AsSingle();
ps_t2 = x_tmp2.AsSingle();
ps_res2 = Sse.Xor(ps_crc2, ps_t2);
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
x_tmp3 = Pclmulqdq.CarrylessMultiply(x_tmp3.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
ps_crc3 = xmm_crc3.AsSingle();
ps_t3 = x_tmp3.AsSingle();
ps_res3 = Sse.Xor(ps_crc3, ps_t3);
xmm_crc0 = ps_res0.AsUInt32();
xmm_crc1 = ps_res1.AsUInt32();
xmm_crc2 = ps_res2.AsUInt32();
xmm_crc3 = ps_res3.AsUInt32();
}
static void partial_fold(long len, ref Vector128<uint> xmm_crc0, ref Vector128<uint> xmm_crc1,
ref Vector128<uint> xmm_crc2, ref Vector128<uint> xmm_crc3,
ref Vector128<uint> xmm_crc_part)
{
Vector128<uint> xmm_fold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001);
Vector128<uint> xmm_mask3 = Vector128.Create(0x80808080);
Vector128<uint> xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3;
Vector128<uint> xmm_a0_0, xmm_a0_1;
Vector128<float> ps_crc3, psa0_0, psa0_1, ps_res;
xmm_shl = pshufb_shf_table[len - 1];
xmm_shr = xmm_shl;
xmm_shr = Sse2.Xor(xmm_shr, xmm_mask3);
xmm_a0_0 = Ssse3.Shuffle(xmm_crc0.AsByte(), xmm_shl.AsByte()).AsUInt32();
xmm_crc0 = Ssse3.Shuffle(xmm_crc0.AsByte(), xmm_shr.AsByte()).AsUInt32();
xmm_tmp1 = Ssse3.Shuffle(xmm_crc1.AsByte(), xmm_shl.AsByte()).AsUInt32();
xmm_crc0 = Sse2.Or(xmm_crc0, xmm_tmp1);
xmm_crc1 = Ssse3.Shuffle(xmm_crc1.AsByte(), xmm_shr.AsByte()).AsUInt32();
xmm_tmp2 = Ssse3.Shuffle(xmm_crc2.AsByte(), xmm_shl.AsByte()).AsUInt32();
xmm_crc1 = Sse2.Or(xmm_crc1, xmm_tmp2);
xmm_crc2 = Ssse3.Shuffle(xmm_crc2.AsByte(), xmm_shr.AsByte()).AsUInt32();
xmm_tmp3 = Ssse3.Shuffle(xmm_crc3.AsByte(), xmm_shl.AsByte()).AsUInt32();
xmm_crc2 = Sse2.Or(xmm_crc2, xmm_tmp3);
xmm_crc3 = Ssse3.Shuffle(xmm_crc3.AsByte(), xmm_shr.AsByte()).AsUInt32();
xmm_crc_part = Ssse3.Shuffle(xmm_crc_part.AsByte(), xmm_shl.AsByte()).AsUInt32();
xmm_crc3 = Sse2.Or(xmm_crc3, xmm_crc_part);
xmm_a0_1 = Pclmulqdq.CarrylessMultiply(xmm_a0_0.AsUInt64(), xmm_fold4.AsUInt64(), 0x10).AsUInt32();
xmm_a0_0 = Pclmulqdq.CarrylessMultiply(xmm_a0_0.AsUInt64(), xmm_fold4.AsUInt64(), 0x01).AsUInt32();
ps_crc3 = xmm_crc3.AsSingle();
psa0_0 = xmm_a0_0.AsSingle();
psa0_1 = xmm_a0_1.AsSingle();
ps_res = Sse.Xor(ps_crc3, psa0_0);
ps_res = Sse.Xor(ps_res, psa0_1);
xmm_crc3 = ps_res.AsUInt32();
}
internal static uint crc32_clmul(byte[] src, long len, uint initial_crc)
{
Vector128<uint> xmm_t0, xmm_t1, xmm_t2, xmm_t3;
Vector128<uint> xmm_initial = Sse2.ConvertScalarToVector128UInt32(initial_crc);
Vector128<uint> xmm_crc0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487);
Vector128<uint> xmm_crc1 = Vector128<uint>.Zero;
Vector128<uint> xmm_crc2 = Vector128<uint>.Zero;
Vector128<uint> xmm_crc3 = Vector128<uint>.Zero;
Vector128<uint> xmm_crc_part;
int bufPos = 0;
bool first = true;
/* fold 512 to 32 step variable declarations for ISO-C90 compat. */
Vector128<uint> xmm_mask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000);
Vector128<uint> xmm_mask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
uint crc;
Vector128<uint> x_tmp0, x_tmp1, x_tmp2, crc_fold;
if(len < 16)
{
if(len == 0)
return initial_crc;
if(len < 4)
{
/*
* no idea how to do this for <4 bytes, delegate to classic impl.
*/
crc = ~initial_crc;
switch(len)
{
case 3:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos++]];
goto case 2;
case 2:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos++]];
goto case 1;
case 1:
crc = (crc >> 8) ^ Crc32Context._isoCrc32Table[0][(crc & 0xFF) ^ src[bufPos++]];
break;
}
return ~crc;
}
xmm_crc_part = Vector128.Create(BitConverter.ToUInt32(src, 0), BitConverter.ToUInt32(src, 4),
BitConverter.ToUInt32(src, 8), BitConverter.ToUInt32(src, 12));
if(first)
{
first = false;
xmm_crc_part = Sse2.Xor(xmm_crc_part, xmm_initial);
}
goto partial;
}
while((len -= 64) >= 0)
{
xmm_t0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t3 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmm_t0 = Sse2.Xor(xmm_t0, xmm_initial);
}
fold_4(ref xmm_crc0, ref xmm_crc1, ref xmm_crc2, ref xmm_crc3);
xmm_crc0 = Sse2.Xor(xmm_crc0, xmm_t0);
xmm_crc1 = Sse2.Xor(xmm_crc1, xmm_t1);
xmm_crc2 = Sse2.Xor(xmm_crc2, xmm_t2);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_t3);
}
/*
* len = num bytes left - 64
*/
if(len + 16 >= 0)
{
len += 16;
xmm_t0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmm_t0 = Sse2.Xor(xmm_t0, xmm_initial);
}
fold_3(ref xmm_crc0, ref xmm_crc1, ref xmm_crc2, ref xmm_crc3);
xmm_crc1 = Sse2.Xor(xmm_crc1, xmm_t0);
xmm_crc2 = Sse2.Xor(xmm_crc2, xmm_t1);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_t2);
if(len == 0)
goto done;
xmm_crc_part = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else if(len + 32 >= 0)
{
len += 32;
xmm_t0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
xmm_t1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmm_t0 = Sse2.Xor(xmm_t0, xmm_initial);
}
fold_2(ref xmm_crc0, ref xmm_crc1, ref xmm_crc2, ref xmm_crc3);
xmm_crc2 = Sse2.Xor(xmm_crc2, xmm_t0);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_t1);
if(len == 0)
goto done;
xmm_crc_part = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else if(len + 48 >= 0)
{
len += 48;
xmm_t0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
bufPos += 16;
if(first)
{
first = false;
xmm_t0 = Sse2.Xor(xmm_t0, xmm_initial);
}
fold_1(ref xmm_crc0, ref xmm_crc1, ref xmm_crc2, ref xmm_crc3);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_t0);
if(len == 0)
goto done;
xmm_crc_part = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
}
else
{
len += 64;
if(len == 0)
goto done;
xmm_crc_part = Vector128.Create(BitConverter.ToUInt32(src, bufPos),
BitConverter.ToUInt32(src, bufPos + 4),
BitConverter.ToUInt32(src, bufPos + 8),
BitConverter.ToUInt32(src, bufPos + 12));
if(first)
{
first = false;
xmm_crc_part = Sse2.Xor(xmm_crc_part, xmm_initial);
}
}
partial:
partial_fold(len, ref xmm_crc0, ref xmm_crc1, ref xmm_crc2, ref xmm_crc3, ref xmm_crc_part);
done:
/* fold 512 to 32 */
/*
* k1
*/
crc_fold = Vector128.Create(crc_k[0], crc_k[1], crc_k[2], crc_k[3]);
x_tmp0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), crc_fold.AsUInt64(), 0x10).AsUInt32();
xmm_crc0 = Pclmulqdq.CarrylessMultiply(xmm_crc0.AsUInt64(), crc_fold.AsUInt64(), 0x01).AsUInt32();
xmm_crc1 = Sse2.Xor(xmm_crc1, x_tmp0);
xmm_crc1 = Sse2.Xor(xmm_crc1, xmm_crc0);
x_tmp1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), crc_fold.AsUInt64(), 0x10).AsUInt32();
xmm_crc1 = Pclmulqdq.CarrylessMultiply(xmm_crc1.AsUInt64(), crc_fold.AsUInt64(), 0x01).AsUInt32();
xmm_crc2 = Sse2.Xor(xmm_crc2, x_tmp1);
xmm_crc2 = Sse2.Xor(xmm_crc2, xmm_crc1);
x_tmp2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), crc_fold.AsUInt64(), 0x10).AsUInt32();
xmm_crc2 = Pclmulqdq.CarrylessMultiply(xmm_crc2.AsUInt64(), crc_fold.AsUInt64(), 0x01).AsUInt32();
xmm_crc3 = Sse2.Xor(xmm_crc3, x_tmp2);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc2);
/*
* k5
*/
crc_fold = Vector128.Create(crc_k[4], crc_k[5], crc_k[6], crc_k[7]);
xmm_crc0 = xmm_crc3;
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), crc_fold.AsUInt64(), 0).AsUInt32();
xmm_crc0 = Sse2.ShiftRightLogical128BitLane(xmm_crc0, 8);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc0);
xmm_crc0 = xmm_crc3;
xmm_crc3 = Sse2.ShiftLeftLogical128BitLane(xmm_crc3, 4);
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), crc_fold.AsUInt64(), 0x10).AsUInt32();
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc0);
xmm_crc3 = Sse2.And(xmm_crc3, xmm_mask2);
/*
* k7
*/
xmm_crc1 = xmm_crc3;
xmm_crc2 = xmm_crc3;
crc_fold = Vector128.Create(crc_k[8], crc_k[9], crc_k[10], crc_k[11]);
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), crc_fold.AsUInt64(), 0).AsUInt32();
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc2);
xmm_crc3 = Sse2.And(xmm_crc3, xmm_mask);
xmm_crc2 = xmm_crc3;
xmm_crc3 = Pclmulqdq.CarrylessMultiply(xmm_crc3.AsUInt64(), crc_fold.AsUInt64(), 0x10).AsUInt32();
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc2);
xmm_crc3 = Sse2.Xor(xmm_crc3, xmm_crc1);
/*
* could just as well write xmm_crc3[2], doing a movaps and truncating, but
* no real advantage - it's a tiny bit slower per call, while no additional CPUs
* would be supported by only requiring SSSE3 and CLMUL instead of SSE4.1 + CLMUL
*/
crc = Sse41.Extract(xmm_crc3, 2);
return ~crc;
}
}
}

View File

@@ -36,6 +36,7 @@ using System.Runtime.Intrinsics.X86;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
using Aaru6.Checksums.CRC32;
namespace Aaru6.Checksums
{
@@ -332,6 +333,7 @@ namespace Aaru6.Checksums
readonly uint _finalSeed;
readonly uint[][] _table;
readonly bool _useIso;
uint _hashInt;
/// <summary>Initializes the CRC32 table and seed as CRC32-ISO</summary>
@@ -339,8 +341,8 @@ namespace Aaru6.Checksums
{
_hashInt = CRC32_ISO_SEED;
_finalSeed = CRC32_ISO_SEED;
_table = _isoCrc32Table;
_table = _isoCrc32Table;
_useIso = true;
}
/// <summary>Initializes the CRC32 table with a custom polynomial and seed</summary>
@@ -348,74 +350,16 @@ namespace Aaru6.Checksums
{
_hashInt = seed;
_finalSeed = seed;
/*
_table = new uint[256];
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
_table[i] = entry;
}*/
_useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
_table = GenerateTable(polynomial);
}
/// <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)
{
if(Pclmulqdq.IsSupported &&
Sse41.IsSupported &&
Ssse3.IsSupported &&
Sse2.IsSupported)
{
_hashInt = ~CRC32CLMUL.crc32_clmul(data, len, ~_hashInt);
return;
}
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
uint crc;
int current_pos = 0;
const int unroll = 4;
const int bytes_at_once = 8 * unroll;
crc = _hashInt;
while(len >= bytes_at_once)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
uint one = BitConverter.ToUInt32(data, current_pos) ^ crc;
current_pos += 4;
uint two = BitConverter.ToUInt32(data, current_pos);
current_pos += 4;
crc = _table[0][(two >> 24) & 0xFF] ^ _table[1][(two >> 16) & 0xFF] ^ _table[2][(two >> 8) & 0xFF] ^
_table[3][two & 0xFF] ^ _table[4][(one >> 24) & 0xFF] ^ _table[5][(one >> 16) & 0xFF] ^
_table[6][(one >> 8) & 0xFF] ^ _table[7][one & 0xFF];
}
len -= bytes_at_once;
}
while(len-- != 0)
crc = (crc >> 8) ^ _table[0][(crc & 0xFF) ^ data[current_pos++]];
_hashInt = crc;
}
public void Update(byte[] data, uint len) => Step(ref _hashInt, _table, data, len, _useIso);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
@@ -438,6 +382,79 @@ namespace Aaru6.Checksums
return crc32Output.ToString();
}
static uint[][] GenerateTable(uint polynomial)
{
uint[][] table = new uint[8][];
for(int i = 0; i < 8; i++)
table[i] = new uint[256];
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
table[0][i] = entry;
}
for(int slice = 1; slice < 8; slice++)
for(int i = 0; i < 256; i++)
table[slice][i] = (table[slice - 1][i] >> 8) ^ table[0][table[slice - 1][i] & 0xFF];
return table;
}
static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso)
{
if(useIso &&
Pclmulqdq.IsSupported &&
Sse41.IsSupported &&
Ssse3.IsSupported &&
Sse2.IsSupported)
{
previousCrc = ~Clmul.Step(data, len, ~previousCrc);
return;
}
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
int currentPos = 0;
const int unroll = 4;
const int bytesAtOnce = 8 * unroll;
uint crc = previousCrc;
while(len >= bytesAtOnce)
{
int unrolling;
for(unrolling = 0; unrolling < unroll; unrolling++)
{
uint one = BitConverter.ToUInt32(data, currentPos) ^ crc;
currentPos += 4;
uint two = BitConverter.ToUInt32(data, currentPos);
currentPos += 4;
crc = table[0][(two >> 24) & 0xFF] ^ table[1][(two >> 16) & 0xFF] ^ table[2][(two >> 8) & 0xFF] ^
table[3][two & 0xFF] ^ table[4][(one >> 24) & 0xFF] ^ table[5][(one >> 16) & 0xFF] ^
table[6][(one >> 8) & 0xFF] ^ table[7][one & 0xFF];
}
len -= bytesAtOnce;
}
while(len-- != 0)
crc = (crc >> 8) ^ table[0][(crc & 0xFF) ^ data[currentPos++]];
previousCrc = crc;
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
@@ -464,24 +481,19 @@ namespace Aaru6.Checksums
uint localHashInt = seed;
uint[] localTable = new uint[256];
uint[][] localTable = GenerateTable(polynomial);
for(int i = 0; i < 256; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
uint entry = (uint)i;
Step(ref localHashInt, localTable, buffer, (uint)read,
polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED);
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
localTable[i] = entry;
read = fileStream.Read(buffer, 0, 65536);
}
for(int i = 0; i < fileStream.Length; i++)
localHashInt = (localHashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localHashInt & 0xff)];
localHashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localHashInt);
@@ -512,23 +524,9 @@ namespace Aaru6.Checksums
{
uint localHashInt = seed;
uint[] localTable = new uint[256];
uint[][] localTable = GenerateTable(polynomial);
for(int i = 0; i < 256; i++)
{
uint entry = (uint)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
localTable[i] = entry;
}
for(int i = 0; i < len; i++)
localHashInt = (localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)];
Step(ref localHashInt, localTable, data, len, polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED);
localHashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localHashInt);

View File

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

View File

@@ -1,111 +0,0 @@
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Aaru6.Checksums
{
public class CRC64CLMUL
{
static readonly byte[] shuffleMasks =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
};
static void shiftRight128(Vector128<ulong> initial, uint n, out Vector128<ulong> outLeft,
out Vector128<ulong> outRight)
{
uint maskPos = 16 - n;
Vector128<byte> maskA = Vector128.Create(shuffleMasks[maskPos], shuffleMasks[maskPos + 1],
shuffleMasks[maskPos + 2], shuffleMasks[maskPos + 3],
shuffleMasks[maskPos + 4], shuffleMasks[maskPos + 5],
shuffleMasks[maskPos + 6], shuffleMasks[maskPos + 7],
shuffleMasks[maskPos + 8], shuffleMasks[maskPos + 9],
shuffleMasks[maskPos + 10], shuffleMasks[maskPos + 11],
shuffleMasks[maskPos + 12], shuffleMasks[maskPos + 13],
shuffleMasks[maskPos + 14], shuffleMasks[maskPos + 15]);
Vector128<byte> maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128<byte>.Zero, Vector128<byte>.Zero));
outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64();
outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64();
}
static Vector128<ulong> fold(Vector128<ulong> input, Vector128<ulong> foldConstants) =>
Sse2.Xor(Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x00),
Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x11));
internal static ulong crc64_clmul(ulong crc, byte[] data, uint length)
{
int bufPos = 16;
const ulong k1 = 0xe05dd497ca393ae4; // bitReflect(expMod65(128 + 64, poly, 1)) << 1;
const ulong k2 = 0xdabe95afc7875f40; // bitReflect(expMod65(128, poly, 1)) << 1;
const ulong mu = 0x9c3e466c172963d5; // (bitReflect(div129by65(poly)) << 1) | 1;
const ulong p = 0x92d8af2baf0e1e85; // (bitReflect(poly) << 1) | 1;
Vector128<ulong> foldConstants1 = Vector128.Create(k1, k2);
Vector128<ulong> foldConstants2 = Vector128.Create(mu, p);
uint leadOutSize = length % 16;
Vector128<ulong> initialCrc = Vector128.Create(~crc, 0);
Vector128<ulong> R;
length -= 16;
// Initial CRC can simply be added to data
shiftRight128(initialCrc, 0, out Vector128<ulong> crc0, out Vector128<ulong> crc1);
Vector128<ulong> accumulator =
Sse2.Xor(fold(Sse2.Xor(crc0, Vector128.Create(BitConverter.ToUInt64(data, 0), BitConverter.ToUInt64(data, 8))), foldConstants1),
crc1);
while(length >= 32)
{
accumulator =
fold(Sse2.Xor(Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8)), accumulator),
foldConstants1);
length -= 16;
bufPos += 16;
}
Vector128<ulong> P;
if(length == 16)
{
P = Sse2.Xor(accumulator,
Vector128.Create(BitConverter.ToUInt64(data, bufPos),
BitConverter.ToUInt64(data, bufPos + 8)));
}
else
{
Vector128<ulong> end0 = Sse2.Xor(accumulator,
Vector128.Create(BitConverter.ToUInt64(data, bufPos),
BitConverter.ToUInt64(data, bufPos + 8)));
bufPos += 16;
Vector128<ulong> end1 =
Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8));
shiftRight128(end0, leadOutSize, out Vector128<ulong> A, out Vector128<ulong> B);
shiftRight128(end1, leadOutSize, out Vector128<ulong> C, out Vector128<ulong> D);
P = Sse2.Xor(fold(A, foldConstants1), Sse2.Or(B, C));
}
R = Sse2.Xor(Pclmulqdq.CarrylessMultiply(P, foldConstants1, 0x10), Sse2.ShiftRightLogical128BitLane(P, 8));
// Final Barrett reduction
Vector128<ulong> T1 = Pclmulqdq.CarrylessMultiply(R, foldConstants2, 0x00);
Vector128<ulong> T2 =
Sse2.Xor(Sse2.Xor(Pclmulqdq.CarrylessMultiply(T1, foldConstants2, 0x10), Sse2.ShiftLeftLogical128BitLane(T1, 8)),
R);
return ~(((ulong)Sse41.Extract(T2.AsUInt32(), 3) << 32) | Sse41.Extract(T2.AsUInt32(), 2));
}
}
}

View File

@@ -32,9 +32,11 @@
using System;
using System.IO;
using System.Runtime.Intrinsics.X86;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
using Aaru6.Checksums.CRC64;
namespace Aaru6.Checksums
{
@@ -273,80 +275,32 @@ namespace Aaru6.Checksums
readonly ulong _finalSeed;
readonly ulong[][] _table;
readonly bool _useEcma;
ulong _hashInt;
/// <summary>Initializes the CRC64 table and seed as CRC64-ECMA</summary>
public Crc64Context()
{
_hashInt = CRC64_ECMA_SEED;
_table = _ecmaCrc64Table;
_hashInt = CRC64_ECMA_SEED;
_table = _ecmaCrc64Table;
_finalSeed = CRC64_ECMA_SEED;
_useEcma = true;
}
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
public Crc64Context(ulong polynomial, ulong seed)
{
_hashInt = seed;
/*
_table = new ulong[256];
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
_table[i] = entry;
}
*/
_hashInt = seed;
_table = GenerateTable(polynomial);
_finalSeed = seed;
_useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
}
/// <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)
{
_hashInt = ~CRC64CLMUL.crc64_clmul(~_hashInt, data, len);
return;
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ulong crc = _hashInt;
int dataOff = 0;
if(len > 4)
{
long limit;
limit = dataOff + (len & ~(uint)3);
len &= 3;
while(dataOff < limit)
{
uint tmp = (uint)(crc ^ BitConverter.ToUInt32(data, dataOff));
dataOff += 4;
crc = _table[3][tmp & 0xFF] ^ _table[2][(tmp >> 8) & 0xFF] ^ (crc >> 32) ^
_table[1][(tmp >> 16) & 0xFF] ^ _table[0][tmp >> 24];
}
}
while(len-- != 0)
crc = _table[0][data[dataOff++] ^ (crc & 0xFF)] ^ (crc >> 8);
_hashInt = crc;
}
public void Update(byte[] data, uint len) => Step(ref _hashInt, _table, data, len, _useEcma);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
@@ -369,6 +323,74 @@ namespace Aaru6.Checksums
return crc64Output.ToString();
}
static ulong[][] GenerateTable(ulong polynomial)
{
ulong[][] table = new ulong[8][];
for(int i = 0; i < 8; i++)
table[i] = new ulong[256];
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
table[0][i] = entry;
}
for(int slice = 1; slice < 4; slice++)
for(int i = 0; i < 256; i++)
table[slice][i] = (table[slice - 1][i] >> 8) ^ table[0][table[slice - 1][i] & 0xFF];
return table;
}
static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma)
{
if(useEcma &&
Pclmulqdq.IsSupported &&
Sse41.IsSupported &&
Ssse3.IsSupported &&
Sse2.IsSupported)
{
previousCrc = ~Clmul.Step(~previousCrc, data, len);
return;
}
// Unroll according to Intel slicing by uint8_t
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
// http://sourceforge.net/projects/slicing-by-8/
ulong crc = previousCrc;
int dataOff = 0;
if(len > 4)
{
long limit = dataOff + (len & ~(uint)3);
len &= 3;
while(dataOff < limit)
{
uint tmp = (uint)(crc ^ BitConverter.ToUInt32(data, dataOff));
dataOff += 4;
crc = table[3][tmp & 0xFF] ^ table[2][(tmp >> 8) & 0xFF] ^ (crc >> 32) ^
table[1][(tmp >> 16) & 0xFF] ^ table[0][tmp >> 24];
}
}
while(len-- != 0)
crc = table[0][data[dataOff++] ^ (crc & 0xFF)] ^ (crc >> 8);
previousCrc = crc;
}
/// <summary>Gets the hash of a file</summary>
/// <param name="filename">File path.</param>
public static byte[] File(string filename)
@@ -395,24 +417,19 @@ namespace Aaru6.Checksums
ulong localHashInt = seed;
ulong[] localTable = new ulong[256];
ulong[][] localTable = GenerateTable(polynomial);
for(int i = 0; i < 256; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
ulong entry = (ulong)i;
Step(ref localHashInt, localTable, buffer, (uint)read,
polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED);
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
localTable[i] = entry;
read = fileStream.Read(buffer, 0, 65536);
}
for(int i = 0; i < fileStream.Length; i++)
localHashInt = (localHashInt >> 8) ^ localTable[(ulong)fileStream.ReadByte() ^ (localHashInt & 0xffL)];
localHashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localHashInt);
@@ -443,23 +460,9 @@ namespace Aaru6.Checksums
{
ulong localHashInt = seed;
ulong[] localTable = new ulong[256];
ulong[][] localTable = GenerateTable(polynomial);
for(int i = 0; i < 256; i++)
{
ulong entry = (ulong)i;
for(int j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry >>= 1;
localTable[i] = entry;
}
for(int i = 0; i < len; i++)
localHashInt = (localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)];
Step(ref localHashInt, localTable, data, len, polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED);
localHashInt ^= seed;
hash = BigEndianBitConverter.GetBytes(localHashInt);

View File

@@ -57,10 +57,39 @@ namespace Aaru6.Checksums
/// <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)
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint sum1 = _sum1;
uint sum2 = _sum2;
uint finalSum = (uint)((_sum2 << 16) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
}
static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len)
{
uint sum1 = previousSum1;
uint sum2 = previousSum2;
uint n;
int dataOff = 0;
@@ -77,8 +106,8 @@ namespace Aaru6.Checksums
if(sum2 >= FLETCHER_MODULE)
sum2 -= FLETCHER_MODULE;
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
@@ -95,9 +124,9 @@ namespace Aaru6.Checksums
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
return;
}
@@ -204,35 +233,8 @@ namespace Aaru6.Checksums
sum2 %= FLETCHER_MODULE;
}
_sum1 = (ushort)(sum1 & 0xFFFF);
_sum2 = (ushort)(sum2 & 0xFFFF);
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
previousSum1 = (ushort)(sum1 & 0xFFFF);
previousSum2 = (ushort)(sum2 & 0xFFFF);
}
/// <summary>Gets the hash of a file</summary>
@@ -254,10 +256,14 @@ namespace Aaru6.Checksums
ushort localSum1 = 0xFFFF;
ushort localSum2 = 0xFFFF;
for(int i = 0; i < fileStream.Length; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
localSum1 = (ushort)((localSum1 + fileStream.ReadByte()) % FLETCHER_MODULE);
localSum2 = (ushort)((localSum2 + localSum1) % FLETCHER_MODULE);
Step(ref localSum1, ref localSum2, buffer, (uint)read);
read = fileStream.Read(buffer, 0, 65536);
}
uint finalSum = (uint)((localSum2 << 16) | localSum1);
@@ -283,11 +289,7 @@ namespace Aaru6.Checksums
ushort localSum1 = 0xFFFF;
ushort localSum2 = 0xFFFF;
for(int i = 0; i < len; i++)
{
localSum1 = (ushort)((localSum1 + data[i]) % FLETCHER_MODULE);
localSum2 = (ushort)((localSum2 + localSum1) % FLETCHER_MODULE);
}
Step(ref localSum1, ref localSum2, data, len);
uint finalSum = (uint)((localSum2 << 16) | localSum1);
@@ -326,10 +328,39 @@ namespace Aaru6.Checksums
/// <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)
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
uint sum1 = _sum1;
uint sum2 = _sum2;
ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
}
static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len)
{
uint sum1 = previousSum1;
uint sum2 = previousSum2;
uint n;
int dataOff = 0;
@@ -346,8 +377,8 @@ namespace Aaru6.Checksums
if(sum2 >= FLETCHER_MODULE)
sum2 -= FLETCHER_MODULE;
_sum1 = (byte)(sum1 & 0xFF);
_sum2 = (byte)(sum2 & 0xFF);
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
return;
}
@@ -364,9 +395,9 @@ namespace Aaru6.Checksums
if(sum1 >= FLETCHER_MODULE)
sum1 -= FLETCHER_MODULE;
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
_sum1 = (byte)(sum1 & 0xFF);
_sum2 = (byte)(sum2 & 0xFF);
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
return;
}
@@ -453,35 +484,8 @@ namespace Aaru6.Checksums
sum2 %= FLETCHER_MODULE;
}
_sum1 = (byte)(sum1 & 0xFF);
_sum2 = (byte)(sum2 & 0xFF);
}
/// <inheritdoc />
/// <summary>Updates the hash with data.</summary>
/// <param name="data">Data buffer.</param>
public void Update(byte[] data) => Update(data, (uint)data.Length);
/// <inheritdoc />
/// <summary>Returns a byte array of the hash value.</summary>
public byte[] Final()
{
ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
return BigEndianBitConverter.GetBytes(finalSum);
}
/// <inheritdoc />
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
public string End()
{
ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
return fletcherOutput.ToString();
previousSum1 = (byte)(sum1 & 0xFF);
previousSum2 = (byte)(sum2 & 0xFF);
}
/// <summary>Gets the hash of a file</summary>
@@ -503,10 +507,14 @@ namespace Aaru6.Checksums
byte localSum1 = 0xFF;
byte localSum2 = 0xFF;
for(int i = 0; i < fileStream.Length; i++)
byte[] buffer = new byte[65536];
int read = fileStream.Read(buffer, 0, 65536);
while(read > 0)
{
localSum1 = (byte)((localSum1 + fileStream.ReadByte()) % FLETCHER_MODULE);
localSum2 = (byte)((localSum2 + localSum1) % FLETCHER_MODULE);
Step(ref localSum1, ref localSum2, buffer, (uint)read);
read = fileStream.Read(buffer, 0, 65536);
}
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);
@@ -532,11 +540,7 @@ namespace Aaru6.Checksums
byte localSum1 = 0xFF;
byte localSum2 = 0xFF;
for(int i = 0; i < len; i++)
{
localSum1 = (byte)((localSum1 + data[i]) % FLETCHER_MODULE);
localSum2 = (byte)((localSum2 + localSum1) % FLETCHER_MODULE);
}
Step(ref localSum1, ref localSum2, data, len);
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);

View File

@@ -52,528 +52,12 @@ namespace Aaru6.Checksums
{
const uint ROLLING_WINDOW = 7;
const uint MIN_BLOCKSIZE = 3;
const uint HASH_INIT = 0x27;
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;
// Precomputed patrial FNV hash table
static readonly byte[][] sum_table =
{
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
},
new byte[]
{
// 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
}
};
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
readonly byte[] _b64 =
{
@@ -654,7 +138,7 @@ namespace Aaru6.Checksums
* we can cope with large blocksize values
*/
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void roll_hash(uint c)
void roll_hash(byte c)
{
_self.Roll.H2 -= _self.Roll.H1;
_self.Roll.H2 += ROLLING_WINDOW * c;
@@ -662,7 +146,7 @@ namespace Aaru6.Checksums
_self.Roll.H1 += c;
_self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW];
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = (byte)c;
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c;
_self.Roll.N++;
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
@@ -677,7 +161,7 @@ namespace Aaru6.Checksums
/* A simple non-rolling hash, based on the FNV hash. */
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint sum_hash(uint c, uint h) => sum_table[h][c & 0x3f];
static uint sum_hash(byte c, uint h) => (h * HASH_PRIME) ^ c;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
@@ -688,8 +172,8 @@ namespace Aaru6.Checksums
if(_self.Bhend >= NUM_BLOCKHASHES)
return;
/* if(_self.Bhend == 0) // assert
throw new Exception("Assertion failed");*/
if(_self.Bhend == 0) // assert
throw new Exception("Assertion failed");
uint obh = _self.Bhend - 1;
uint nbh = _self.Bhend;
@@ -704,8 +188,8 @@ namespace Aaru6.Checksums
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_try_reduce_blockhash()
{
/* if(_self.Bhstart >= _self.Bhend)
throw new Exception("Assertion failed");*/
if(_self.Bhstart >= _self.Bhend)
throw new Exception("Assertion failed");
if(_self.Bhend - _self.Bhstart < 2)
/* Need at least two working hashes. */
@@ -726,7 +210,7 @@ namespace Aaru6.Checksums
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void fuzzy_engine_step(uint c)
void fuzzy_engine_step(byte c)
{
uint i;
/* At each character we update the rolling hash and the normal hashes.
@@ -792,8 +276,8 @@ namespace Aaru6.Checksums
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");*/
if(!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < _self.TotalSize))
throw new Exception("Assertion failed");
int resultOff;
@@ -814,9 +298,9 @@ namespace Aaru6.Checksums
_self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
--bi;
/* if(bi > 0 &&
_self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
throw new Exception("Assertion failed");*/
if(bi > 0 &&
_self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
throw new Exception("Assertion failed");
sb.AppendFormat("{0}:", SSDEEP_BS(bi));
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
@@ -825,8 +309,8 @@ namespace Aaru6.Checksums
/* Maybe snprintf has set errno here? */
throw new OverflowException("The input exceeds data types.");
/* if(i >= remain)
throw new Exception("Assertion failed");*/
if(i >= remain)
throw new Exception("Assertion failed");
remain -= i;
@@ -836,8 +320,8 @@ namespace Aaru6.Checksums
i = (int)_self.Bh[bi].Dlen;
/* if(i > remain)
throw new Exception("Assertion failed");*/
if(i > remain)
throw new Exception("Assertion failed");
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
resultOff += i;
@@ -845,8 +329,8 @@ namespace Aaru6.Checksums
if(h != 0)
{
/* if(remain <= 0)
throw new Exception("Assertion failed");*/
if(remain <= 0)
throw new Exception("Assertion failed");
result[resultOff] = _b64[_self.Bh[bi].H % 64];
@@ -876,8 +360,8 @@ namespace Aaru6.Checksums
}
}
/* if(remain <= 0)
throw new Exception("Assertion failed");*/
if(remain <= 0)
throw new Exception("Assertion failed");
result[resultOff++] = 0x3A; // ':'
--remain;
@@ -887,8 +371,8 @@ namespace Aaru6.Checksums
++bi;
i = (int)_self.Bh[bi].Dlen;
/* if(i > remain)
throw new Exception("Assertion failed");*/
if(i > remain)
throw new Exception("Assertion failed");
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
resultOff += i;
@@ -896,8 +380,8 @@ namespace Aaru6.Checksums
if(h != 0)
{
/* if(remain <= 0)
throw new Exception("Assertion failed");*/
if(remain <= 0)
throw new Exception("Assertion failed");
h = _self.Bh[bi].Halfh;
result[resultOff] = _b64[h % 64];
@@ -917,8 +401,8 @@ namespace Aaru6.Checksums
if(i != 0)
{
/* if(remain <= 0)
throw new Exception("Assertion failed");*/
if(remain <= 0)
throw new Exception("Assertion failed");
result[resultOff] = (byte)i;
@@ -935,11 +419,11 @@ namespace Aaru6.Checksums
}
else if(h != 0)
{
/* if(_self.Bh[bi].Dlen != 0)
throw new Exception("Assertion failed");
if(_self.Bh[bi].Dlen != 0)
throw new Exception("Assertion failed");
if(remain <= 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