diff --git a/Aaru6.Checksums/Aaru6.Checksums.csproj b/Aaru6.Checksums/Aaru6.Checksums.csproj index 282591f..14422c3 100644 --- a/Aaru6.Checksums/Aaru6.Checksums.csproj +++ b/Aaru6.Checksums/Aaru6.Checksums.csproj @@ -55,8 +55,8 @@ - - + + diff --git a/Aaru6.Checksums/Adler32Context.cs b/Aaru6.Checksums/Adler32Context.cs index 4b91f13..cc7b4e8 100644 --- a/Aaru6.Checksums/Adler32Context.cs +++ b/Aaru6.Checksums/Adler32Context.cs @@ -41,9 +41,9 @@ namespace Aaru6.Checksums /// Implements the Adler-32 algorithm 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; /// Initializes the Adler-32 sums public Adler32Context() @@ -56,10 +56,39 @@ namespace Aaru6.Checksums /// Updates the hash with data. /// Data buffer. /// Length of buffer to hash. - public void Update(byte[] data, uint len) + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() { - uint sum1 = _sum1; - uint sum2 = _sum2; + uint finalSum = (uint)((_sum2 << 16) | _sum1); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + 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); - } - - /// - /// Updates the hash with data. - /// Data buffer. - public void Update(byte[] data) => Update(data, (uint)data.Length); - - /// - /// Returns a byte array of the hash value. - public byte[] Final() - { - uint finalSum = (uint)((_sum2 << 16) | _sum1); - - return BigEndianBitConverter.GetBytes(finalSum); - } - - /// - /// Returns a hexadecimal representation of the hash value. - 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); } /// Gets the hash of a file @@ -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); diff --git a/Aaru6.Checksums/CRC16CCITTContext.cs b/Aaru6.Checksums/CRC16CCITTContext.cs index 0c62b6b..c0e0a55 100644 --- a/Aaru6.Checksums/CRC16CCITTContext.cs +++ b/Aaru6.Checksums/CRC16CCITTContext.cs @@ -30,22 +30,17 @@ // Copyright © 2011-2021 Natalia Portillo // ****************************************************************************/ -using System; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; - namespace Aaru6.Checksums { /// /// Implements the CRC16 algorithm with CCITT polynomial and seed - public sealed class CRC16CCITTContext : IChecksum + public sealed class CRC16CCITTContext : Crc16Context { /// CCITT CRC16 polynomial public const ushort CRC16_CCITT_POLY = 0x8408; /// CCITT CRC16 seed 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; - /// Initializes an instance of the CRC16 with IBM polynomial and seed. + /// Initializes an instance of the CRC16 with CCITT polynomial and seed. /// - public CRC16CCITTContext() => _crc = 0; - - /// - 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; - } - - /// - public void Update(byte[] data) => Update(data, (uint)data.Length); - - /// - public byte[] Final() => BigEndianBitConverter.GetBytes(_crc); - - /// - public string End() => throw new NotImplementedException(); + public CRC16CCITTContext() : base(CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true) {} /// Gets the hash of a file /// File path. @@ -300,21 +244,24 @@ namespace Aaru6.Checksums /// Gets the hash of a file in hexadecimal and as a byte array. /// File path. /// Byte array of the hash value. - 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); /// Gets the hash of the specified data buffer. /// Data buffer. /// Length of the data buffer to hash. /// Byte array of the hash value. - 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); /// Gets the hash of the specified data buffer. /// Data buffer. /// Byte array of the hash value. public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); - /// Calculates the IBM CRC16 of the specified buffer with the specified parameters + /// Calculates the CCITT CRC16 of the specified buffer with the specified parameters /// Buffer - 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); } } \ No newline at end of file diff --git a/Aaru6.Checksums/CRC16Context.cs b/Aaru6.Checksums/CRC16Context.cs index e981da7..0539b4c 100644 --- a/Aaru6.Checksums/CRC16Context.cs +++ b/Aaru6.Checksums/CRC16Context.cs @@ -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 { /// /// Implements a CRC16 algorithm 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; /// Initializes the CRC16 table with a custom polynomial and seed - 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 /// Length of buffer to hash. 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); } /// @@ -79,7 +76,8 @@ namespace Aaru.Checksums /// /// Returns a byte array of the hash value. - public byte[] Final() => BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed)); + public byte[] Final() => !_inverse ? BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed)) + : BigEndianBitConverter.GetBytes((ushort)~(_hashInt ^ _finalSeed)); /// /// Returns a hexadecimal representation of the hash value. @@ -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 /// CRC seed /// CRC lookup table /// Is CRC inverted? - 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 /// CRC lookup table /// Is CRC inverted? 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 /// Pre-generated lookup table /// Inverse CRC /// CRC16 - 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(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; } } } \ No newline at end of file diff --git a/Aaru6.Checksums/CRC16IBMContext.cs b/Aaru6.Checksums/CRC16IBMContext.cs index 6e65933..3399587 100644 --- a/Aaru6.Checksums/CRC16IBMContext.cs +++ b/Aaru6.Checksums/CRC16IBMContext.cs @@ -30,20 +30,16 @@ // Copyright © 2011-2021 Natalia Portillo // ****************************************************************************/ -using System; -using Aaru.CommonTypes.Interfaces; -using Aaru.Helpers; - namespace Aaru6.Checksums { /// /// Implements the CRC16 algorithm with IBM polynomial and seed - 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; /// Initializes an instance of the CRC16 with IBM polynomial and seed. /// - public CRC16IBMContext() => _crc = 0; - - /// - 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; - } - - /// - public void Update(byte[] data) => Update(data, (uint)data.Length); - - /// - public byte[] Final() => BigEndianBitConverter.GetBytes(_crc); - - /// - public string End() => throw new NotImplementedException(); + public CRC16IBMContext() : base(CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false) {} /// Gets the hash of a file /// File path. @@ -297,21 +243,19 @@ namespace Aaru6.Checksums /// Gets the hash of a file in hexadecimal and as a byte array. /// File path. /// Byte array of the hash value. - 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); /// Gets the hash of the specified data buffer. /// Data buffer. /// Length of the data buffer to hash. /// Byte array of the hash value. - 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); /// Gets the hash of the specified data buffer. /// Data buffer. /// Byte array of the hash value. public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash); - - /// Calculates the IBM CRC16 of the specified buffer with the specified parameters - /// Buffer - public static ushort Calculate(byte[] buffer) => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/Aaru6.Checksums/CRC32/clmul.cs b/Aaru6.Checksums/CRC32/clmul.cs new file mode 100644 index 0000000..15298c9 --- /dev/null +++ b/Aaru6.Checksums/CRC32/clmul.cs @@ -0,0 +1,541 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : clmul.cs +// Author(s) : Natalia Portillo +// Wajdi Feghali +// Jim Guilford +// Vinodh Gopal +// Erdinc Ozturk +// Jim Kukunas +// 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[] _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 xmmCRC0, ref Vector128 xmmCRC1, ref Vector128 xmmCRC2, + ref Vector128 xmmCRC3) + { + Vector128 xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); + + Vector128 xTmp3 = xmmCRC3; + + xmmCRC3 = xmmCRC0; + xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC0 = xmmCRC0.AsSingle(); + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 psRes = Sse.Xor(psCRC0, psCRC3); + + xmmCRC0 = xmmCRC1; + xmmCRC1 = xmmCRC2; + xmmCRC2 = xTmp3; + xmmCRC3 = psRes.AsUInt32(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void Fold2(ref Vector128 xmmCRC0, ref Vector128 xmmCRC1, ref Vector128 xmmCRC2, + ref Vector128 xmmCRC3) + { + Vector128 xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); + + Vector128 xTmp3 = xmmCRC3; + Vector128 xTmp2 = xmmCRC2; + + xmmCRC3 = xmmCRC1; + xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 psCRC1 = xmmCRC1.AsSingle(); + Vector128 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 psCRC0 = xmmCRC0.AsSingle(); + Vector128 psCRC2 = xmmCRC2.AsSingle(); + Vector128 psRes20 = Sse.Xor(psCRC0, psCRC2); + + xmmCRC0 = xTmp2; + xmmCRC1 = xTmp3; + xmmCRC2 = psRes20.AsUInt32(); + xmmCRC3 = psRes31.AsUInt32(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void Fold3(ref Vector128 xmmCRC0, ref Vector128 xmmCRC1, ref Vector128 xmmCRC2, + ref Vector128 xmmCRC3) + { + Vector128 xmmFold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001); + + Vector128 xTmp3 = xmmCRC3; + + xmmCRC3 = xmmCRC2; + xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC2 = xmmCRC2.AsSingle(); + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 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 psCRC1 = xmmCRC1.AsSingle(); + psCRC2 = xmmCRC2.AsSingle(); + Vector128 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 psCRC0 = xmmCRC0.AsSingle(); + psCRC1 = xmmCRC1.AsSingle(); + Vector128 psRes10 = Sse.Xor(psCRC0, psCRC1); + + xmmCRC0 = xTmp3; + xmmCRC1 = psRes10.AsUInt32(); + xmmCRC2 = psRes21.AsUInt32(); + xmmCRC3 = psRes32.AsUInt32(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static void Fold4(ref Vector128 xmmCRC0, ref Vector128 xmmCRC1, ref Vector128 xmmCRC2, + ref Vector128 xmmCRC3) + { + Vector128 xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); + + Vector128 xTmp0 = xmmCRC0; + Vector128 xTmp1 = xmmCRC1; + Vector128 xTmp2 = xmmCRC2; + Vector128 xTmp3 = xmmCRC3; + + xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp0 = Pclmulqdq.CarrylessMultiply(xTmp0.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC0 = xmmCRC0.AsSingle(); + Vector128 psT0 = xTmp0.AsSingle(); + Vector128 psRes0 = Sse.Xor(psCRC0, psT0); + + xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp1 = Pclmulqdq.CarrylessMultiply(xTmp1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC1 = xmmCRC1.AsSingle(); + Vector128 psT1 = xTmp1.AsSingle(); + Vector128 psRes1 = Sse.Xor(psCRC1, psT1); + + xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp2 = Pclmulqdq.CarrylessMultiply(xTmp2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC2 = xmmCRC2.AsSingle(); + Vector128 psT2 = xTmp2.AsSingle(); + Vector128 psRes2 = Sse.Xor(psCRC2, psT2); + + xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + xTmp3 = Pclmulqdq.CarrylessMultiply(xTmp3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32(); + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 psT3 = xTmp3.AsSingle(); + Vector128 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 xmmCRC0, ref Vector128 xmmCRC1, + ref Vector128 xmmCRC2, ref Vector128 xmmCRC3, + ref Vector128 xmmCRCPart) + { + Vector128 xmmFold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001); + Vector128 xmmMask3 = Vector128.Create(0x80808080); + + Vector128 xmmShl = _pshufbShfTable[len - 1]; + Vector128 xmmShr = xmmShl; + xmmShr = Sse2.Xor(xmmShr, xmmMask3); + + Vector128 xmmA00 = Ssse3.Shuffle(xmmCRC0.AsByte(), xmmShl.AsByte()).AsUInt32(); + + xmmCRC0 = Ssse3.Shuffle(xmmCRC0.AsByte(), xmmShr.AsByte()).AsUInt32(); + Vector128 xmmTmp1 = Ssse3.Shuffle(xmmCRC1.AsByte(), xmmShl.AsByte()).AsUInt32(); + xmmCRC0 = Sse2.Or(xmmCRC0, xmmTmp1); + + xmmCRC1 = Ssse3.Shuffle(xmmCRC1.AsByte(), xmmShr.AsByte()).AsUInt32(); + Vector128 xmmTmp2 = Ssse3.Shuffle(xmmCRC2.AsByte(), xmmShl.AsByte()).AsUInt32(); + xmmCRC1 = Sse2.Or(xmmCRC1, xmmTmp2); + + xmmCRC2 = Ssse3.Shuffle(xmmCRC2.AsByte(), xmmShr.AsByte()).AsUInt32(); + Vector128 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 xmmA01 = Pclmulqdq.CarrylessMultiply(xmmA00.AsUInt64(), xmmFold4.AsUInt64(), 0x10). + AsUInt32(); + + xmmA00 = Pclmulqdq.CarrylessMultiply(xmmA00.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32(); + + Vector128 psCRC3 = xmmCRC3.AsSingle(); + Vector128 psa00 = xmmA00.AsSingle(); + Vector128 psa01 = xmmA01.AsSingle(); + + Vector128 psRes = Sse.Xor(psCRC3, psa00); + psRes = Sse.Xor(psRes, psa01); + + xmmCRC3 = psRes.AsUInt32(); + } + + internal static uint Step(byte[] src, long len, uint initialCRC) + { + Vector128 xmmT0, xmmT1, xmmT2; + Vector128 xmmInitial = Sse2.ConvertScalarToVector128UInt32(initialCRC); + Vector128 xmmCRC0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487); + Vector128 xmmCRC1 = Vector128.Zero; + Vector128 xmmCRC2 = Vector128.Zero; + Vector128 xmmCRC3 = Vector128.Zero; + Vector128 xmmCRCPart; + int bufPos = 0; + + bool first = true; + + /* fold 512 to 32 step variable declarations for ISO-C90 compat. */ + Vector128 xmmMask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000); + Vector128 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 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 crcFold = Vector128.Create(_crcK[0], _crcK[1], _crcK[2], _crcK[3]); + + Vector128 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 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 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; + } + } +} \ No newline at end of file diff --git a/Aaru6.Checksums/CRC32CLMUL.cs b/Aaru6.Checksums/CRC32CLMUL.cs deleted file mode 100644 index a6e6c9b..0000000 --- a/Aaru6.Checksums/CRC32CLMUL.cs +++ /dev/null @@ -1,562 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : clmul.cs -// Author(s) : Natalia Portillo -// Wajdi Feghali -// Jim Guilford -// Vinodh Gopal -// Erdinc Ozturk -// Jim Kukunas -// 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[] 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 xmm_crc0, ref Vector128 xmm_crc1, ref Vector128 xmm_crc2, - ref Vector128 xmm_crc3) - { - Vector128 xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); - - Vector128 x_tmp3; - Vector128 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 xmm_crc0, ref Vector128 xmm_crc1, ref Vector128 xmm_crc2, - ref Vector128 xmm_crc3) - { - Vector128 xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); - - Vector128 x_tmp3, x_tmp2; - Vector128 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 xmm_crc0, ref Vector128 xmm_crc1, ref Vector128 xmm_crc2, - ref Vector128 xmm_crc3) - { - Vector128 xmm_fold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001); - - Vector128 x_tmp3; - Vector128 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 xmm_crc0, ref Vector128 xmm_crc1, ref Vector128 xmm_crc2, - ref Vector128 xmm_crc3) - { - Vector128 xmm_fold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001); - - Vector128 x_tmp0, x_tmp1, x_tmp2, x_tmp3; - Vector128 ps_crc0, ps_crc1, ps_crc2, ps_crc3; - Vector128 ps_t0, ps_t1, ps_t2, ps_t3; - Vector128 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 xmm_crc0, ref Vector128 xmm_crc1, - ref Vector128 xmm_crc2, ref Vector128 xmm_crc3, - ref Vector128 xmm_crc_part) - { - Vector128 xmm_fold4 = Vector128.Create(0x54442bd4, 0x00000001, 0xc6e41596, 0x00000001); - Vector128 xmm_mask3 = Vector128.Create(0x80808080); - - Vector128 xmm_shl, xmm_shr, xmm_tmp1, xmm_tmp2, xmm_tmp3; - Vector128 xmm_a0_0, xmm_a0_1; - Vector128 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 xmm_t0, xmm_t1, xmm_t2, xmm_t3; - Vector128 xmm_initial = Sse2.ConvertScalarToVector128UInt32(initial_crc); - Vector128 xmm_crc0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487); - Vector128 xmm_crc1 = Vector128.Zero; - Vector128 xmm_crc2 = Vector128.Zero; - Vector128 xmm_crc3 = Vector128.Zero; - Vector128 xmm_crc_part; - int bufPos = 0; - - bool first = true; - - /* fold 512 to 32 step variable declarations for ISO-C90 compat. */ - Vector128 xmm_mask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000); - Vector128 xmm_mask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); - - uint crc; - Vector128 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; - } - } -} \ No newline at end of file diff --git a/Aaru6.Checksums/CRC32Context.cs b/Aaru6.Checksums/CRC32Context.cs index 13667ba..ce1d95c 100644 --- a/Aaru6.Checksums/CRC32Context.cs +++ b/Aaru6.Checksums/CRC32Context.cs @@ -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; /// Initializes the CRC32 table and seed as CRC32-ISO @@ -339,8 +341,8 @@ namespace Aaru6.Checksums { _hashInt = CRC32_ISO_SEED; _finalSeed = CRC32_ISO_SEED; - - _table = _isoCrc32Table; + _table = _isoCrc32Table; + _useIso = true; } /// Initializes the CRC32 table with a custom polynomial and seed @@ -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); } /// /// Updates the hash with data. /// Data buffer. /// Length of buffer to hash. - 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); /// /// Updates the hash with data. @@ -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; + } + /// Gets the hash of a file /// File path. 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); diff --git a/Aaru6.Checksums/CRC64/clmul.cs b/Aaru6.Checksums/CRC64/clmul.cs new file mode 100644 index 0000000..e7a3e82 --- /dev/null +++ b/Aaru6.Checksums/CRC64/clmul.cs @@ -0,0 +1,142 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : clmul.cs +// Author(s) : Natalia Portillo +// +// 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 . +// +// ---------------------------------------------------------------------------- +// 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 initial, uint n, out Vector128 outLeft, + out Vector128 outRight) + { + uint maskPos = 16 - n; + + Vector128 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 maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128.Zero, Vector128.Zero)); + + outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64(); + outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Vector128 Fold(Vector128 input, Vector128 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 foldConstants1 = Vector128.Create(k1, k2); + Vector128 foldConstants2 = Vector128.Create(mu, pol); + uint leadOutSize = length % 16; + Vector128 initialCrc = Vector128.Create(~crc, 0); + Vector128 p; + length -= 16; + + // Initial CRC can simply be added to data + ShiftRight128(initialCrc, 0, out Vector128 crc0, out Vector128 crc1); + + Vector128 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 end0 = Sse2.Xor(accumulator, + Vector128.Create(BitConverter.ToUInt64(data, bufPos), + BitConverter.ToUInt64(data, bufPos + 8))); + + bufPos += 16; + + Vector128 end1 = + Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8)); + + ShiftRight128(end0, leadOutSize, out Vector128 a, out Vector128 b); + ShiftRight128(end1, leadOutSize, out Vector128 c, out _); + + p = Sse2.Xor(Fold(a, foldConstants1), Sse2.Or(b, c)); + } + + Vector128 r = Sse2.Xor(Pclmulqdq.CarrylessMultiply(p, foldConstants1, 0x10), + Sse2.ShiftRightLogical128BitLane(p, 8)); + + // Final Barrett reduction + Vector128 t1 = Pclmulqdq.CarrylessMultiply(r, foldConstants2, 0x00); + + Vector128 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)); + } + } +} \ No newline at end of file diff --git a/Aaru6.Checksums/CRC64CLMUL.cs b/Aaru6.Checksums/CRC64CLMUL.cs deleted file mode 100644 index 665a363..0000000 --- a/Aaru6.Checksums/CRC64CLMUL.cs +++ /dev/null @@ -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 initial, uint n, out Vector128 outLeft, - out Vector128 outRight) - { - uint maskPos = 16 - n; - - Vector128 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 maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128.Zero, Vector128.Zero)); - - outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64(); - outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64(); - } - - static Vector128 fold(Vector128 input, Vector128 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 foldConstants1 = Vector128.Create(k1, k2); - Vector128 foldConstants2 = Vector128.Create(mu, p); - - uint leadOutSize = length % 16; - Vector128 initialCrc = Vector128.Create(~crc, 0); - - Vector128 R; - length -= 16; - - // Initial CRC can simply be added to data - shiftRight128(initialCrc, 0, out Vector128 crc0, out Vector128 crc1); - - Vector128 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 P; - - if(length == 16) - { - P = Sse2.Xor(accumulator, - Vector128.Create(BitConverter.ToUInt64(data, bufPos), - BitConverter.ToUInt64(data, bufPos + 8))); - } - else - { - Vector128 end0 = Sse2.Xor(accumulator, - Vector128.Create(BitConverter.ToUInt64(data, bufPos), - BitConverter.ToUInt64(data, bufPos + 8))); - - bufPos += 16; - - Vector128 end1 = - Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8)); - - shiftRight128(end0, leadOutSize, out Vector128 A, out Vector128 B); - shiftRight128(end1, leadOutSize, out Vector128 C, out Vector128 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 T1 = Pclmulqdq.CarrylessMultiply(R, foldConstants2, 0x00); - - Vector128 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)); - } - } -} \ No newline at end of file diff --git a/Aaru6.Checksums/CRC64Context.cs b/Aaru6.Checksums/CRC64Context.cs index 653cf3d..4806d64 100644 --- a/Aaru6.Checksums/CRC64Context.cs +++ b/Aaru6.Checksums/CRC64Context.cs @@ -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; /// Initializes the CRC64 table and seed as CRC64-ECMA public Crc64Context() { - _hashInt = CRC64_ECMA_SEED; - - _table = _ecmaCrc64Table; - + _hashInt = CRC64_ECMA_SEED; + _table = _ecmaCrc64Table; _finalSeed = CRC64_ECMA_SEED; + _useEcma = true; } /// Initializes the CRC16 table with a custom polynomial and seed 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; } /// /// Updates the hash with data. /// Data buffer. /// Length of buffer to hash. - 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); /// /// Updates the hash with data. @@ -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; + } + /// Gets the hash of a file /// File path. 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); diff --git a/Aaru6.Checksums/FletcherContext.cs b/Aaru6.Checksums/FletcherContext.cs index 0cf4214..1376214 100644 --- a/Aaru6.Checksums/FletcherContext.cs +++ b/Aaru6.Checksums/FletcherContext.cs @@ -57,10 +57,39 @@ namespace Aaru6.Checksums /// Updates the hash with data. /// Data buffer. /// Length of buffer to hash. - public void Update(byte[] data, uint len) + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() { - uint sum1 = _sum1; - uint sum2 = _sum2; + uint finalSum = (uint)((_sum2 << 16) | _sum1); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + 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); - } - - /// - /// Updates the hash with data. - /// Data buffer. - public void Update(byte[] data) => Update(data, (uint)data.Length); - - /// - /// Returns a byte array of the hash value. - public byte[] Final() - { - uint finalSum = (uint)((_sum2 << 16) | _sum1); - - return BigEndianBitConverter.GetBytes(finalSum); - } - - /// - /// Returns a hexadecimal representation of the hash value. - 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); } /// Gets the hash of a file @@ -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 /// Updates the hash with data. /// Data buffer. /// Length of buffer to hash. - public void Update(byte[] data, uint len) + public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len); + + /// + /// Updates the hash with data. + /// Data buffer. + public void Update(byte[] data) => Update(data, (uint)data.Length); + + /// + /// Returns a byte array of the hash value. + public byte[] Final() { - uint sum1 = _sum1; - uint sum2 = _sum2; + ushort finalSum = (ushort)((_sum2 << 8) | _sum1); + + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + 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); - } - - /// - /// Updates the hash with data. - /// Data buffer. - public void Update(byte[] data) => Update(data, (uint)data.Length); - - /// - /// Returns a byte array of the hash value. - public byte[] Final() - { - ushort finalSum = (ushort)((_sum2 << 8) | _sum1); - - return BigEndianBitConverter.GetBytes(finalSum); - } - - /// - /// Returns a hexadecimal representation of the hash value. - 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); } /// Gets the hash of a file @@ -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); diff --git a/Aaru6.Checksums/SpamSumContext.cs b/Aaru6.Checksums/SpamSumContext.cs index 3342615..bf022d5 100644 --- a/Aaru6.Checksums/SpamSumContext.cs +++ b/Aaru6.Checksums/SpamSumContext.cs @@ -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