diff --git a/Aaru.Checksums.csproj b/Aaru.Checksums.csproj
index 62391a3..9a18a37 100644
--- a/Aaru.Checksums.csproj
+++ b/Aaru.Checksums.csproj
@@ -65,6 +65,7 @@
+
@@ -100,6 +101,7 @@
+
diff --git a/Adler32Context.cs b/Adler32Context.cs
index c92bfb2..974e080 100644
--- a/Adler32Context.cs
+++ b/Adler32Context.cs
@@ -36,7 +36,9 @@
// Copyright (C) Jean-loup Gailly
// ****************************************************************************/
+using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Text;
using Aaru.Checksums.Adler32;
@@ -52,6 +54,8 @@ namespace Aaru.Checksums
{
internal const ushort ADLER_MODULE = 65521;
internal const uint NMAX = 5552;
+ readonly IntPtr _nativeContext;
+ readonly bool _useNative;
ushort _sum1, _sum2;
/// Initializes the Adler-32 sums
@@ -59,13 +63,19 @@ namespace Aaru.Checksums
{
_sum1 = 1;
_sum2 = 0;
+
+ if(!Native.IsSupported)
+ return;
+
+ _nativeContext = adler32_init();
+ _useNative = _nativeContext != IntPtr.Zero;
}
///
/// Updates the hash with data.
/// Data buffer.
/// Length of buffer to hash.
- public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
+ public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
///
/// Updates the hash with data.
@@ -78,6 +88,12 @@ namespace Aaru.Checksums
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
+ if(!_useNative)
+ return BigEndianBitConverter.GetBytes(finalSum);
+
+ adler32_final(_nativeContext, ref finalSum);
+ adler32_free(_nativeContext);
+
return BigEndianBitConverter.GetBytes(finalSum);
}
@@ -85,8 +101,15 @@ namespace Aaru.Checksums
/// Returns a hexadecimal representation of the hash value.
public string End()
{
- uint finalSum = (uint)((_sum2 << 16) | _sum1);
- var adlerOutput = new StringBuilder();
+ uint finalSum = (uint)((_sum2 << 16) | _sum1);
+
+ if(_useNative)
+ {
+ adler32_final(_nativeContext, ref finalSum);
+ adler32_free(_nativeContext);
+ }
+
+ var adlerOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
@@ -94,8 +117,28 @@ namespace Aaru.Checksums
return adlerOutput.ToString();
}
- static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len)
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr adler32_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int adler32_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int adler32_final(IntPtr ctx, ref uint checksum);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void adler32_free(IntPtr ctx);
+
+ static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len, bool useNative,
+ IntPtr nativeContext)
{
+ if(useNative)
+ {
+ adler32_update(nativeContext, data, len);
+
+ return;
+ }
+
if(Ssse3.IsSupported)
{
Adler32.Ssse3.Step(ref preSum1, ref preSum2, data, len);
@@ -273,6 +316,17 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string File(string filename, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = adler32_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
var fileStream = new FileStream(filename, FileMode.Open);
ushort localSum1 = 1;
@@ -283,12 +337,18 @@ namespace Aaru.Checksums
while(read > 0)
{
- Step(ref localSum1, ref localSum2, buffer, (uint)read);
+ Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.Read(buffer, 0, 65536);
}
uint finalSum = (uint)((localSum2 << 16) | localSum1);
+ if(useNative)
+ {
+ adler32_final(nativeContext, ref finalSum);
+ adler32_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
@@ -307,13 +367,30 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string Data(byte[] data, uint len, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = adler32_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
ushort localSum1 = 1;
ushort localSum2 = 0;
- Step(ref localSum1, ref localSum2, data, len);
+ Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
uint finalSum = (uint)((localSum2 << 16) | localSum1);
+ if(useNative)
+ {
+ adler32_final(nativeContext, ref finalSum);
+ adler32_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
diff --git a/CRC16Context.cs b/CRC16Context.cs
index 688543a..971ea87 100644
--- a/CRC16Context.cs
+++ b/CRC16Context.cs
@@ -32,6 +32,7 @@
using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
@@ -44,7 +45,11 @@ namespace Aaru.Checksums
{
readonly ushort _finalSeed;
readonly bool _inverse;
+ readonly IntPtr _nativeContext;
readonly ushort[][] _table;
+ readonly bool _useCcitt;
+ readonly bool _useIbm;
+ readonly bool _useNative;
ushort _hashInt;
/// Initializes the CRC16 table with a custom polynomial and seed
@@ -54,7 +59,29 @@ namespace Aaru.Checksums
_finalSeed = seed;
_inverse = inverse;
- _table = table ?? GenerateTable(polynomial, inverse);
+ _useNative = Native.IsSupported;
+
+ _useCcitt = polynomial == CRC16CCITTContext.CRC16_CCITT_POLY &&
+ seed == CRC16CCITTContext.CRC16_CCITT_SEED && inverse;
+
+ _useIbm = polynomial == CRC16IBMContext.CRC16_IBM_POLY && seed == CRC16IBMContext.CRC16_IBM_SEED &&
+ !inverse;
+
+ if(_useCcitt && _useNative)
+ {
+ _nativeContext = crc16_ccitt_init();
+ _useNative = _nativeContext != IntPtr.Zero;
+ }
+ else if(_useIbm && _useNative)
+ {
+ _nativeContext = crc16_init();
+ _useNative = _nativeContext != IntPtr.Zero;
+ }
+ else
+ _useNative = false;
+
+ if(!_useNative)
+ _table = table ?? GenerateTable(polynomial, inverse);
}
///
@@ -63,10 +90,26 @@ namespace Aaru.Checksums
/// Length of buffer to hash.
public void Update(byte[] data, uint len)
{
- if(_inverse)
- StepInverse(ref _hashInt, _table, data, len);
- else
- Step(ref _hashInt, _table, data, len);
+ switch(_useNative)
+ {
+ case true when _useCcitt:
+ crc16_ccitt_update(_nativeContext, data, len);
+
+ break;
+ case true when _useIbm:
+ crc16_update(_nativeContext, data, len);
+
+ break;
+ default:
+ {
+ if(_inverse)
+ StepInverse(ref _hashInt, _table, data, len);
+ else
+ Step(ref _hashInt, _table, data, len);
+
+ break;
+ }
+ }
}
///
@@ -76,19 +119,65 @@ namespace Aaru.Checksums
///
/// Returns a byte array of the hash value.
- public byte[] Final() => !_inverse ? BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed))
- : BigEndianBitConverter.GetBytes((ushort)~(_hashInt ^ _finalSeed));
+ public byte[] Final()
+ {
+ ushort crc = 0;
+
+ switch(_useNative)
+ {
+ case true when _useCcitt:
+ crc16_ccitt_final(_nativeContext, ref crc);
+ crc16_ccitt_free(_nativeContext);
+
+ break;
+ case true when _useIbm:
+ crc16_final(_nativeContext, ref crc);
+ crc16_free(_nativeContext);
+
+ break;
+ default:
+ {
+ if(_inverse)
+ crc = (ushort)~(_hashInt ^ _finalSeed);
+ else
+ crc = (ushort)(_hashInt ^ _finalSeed);
+
+ break;
+ }
+ }
+
+ return BigEndianBitConverter.GetBytes(crc);
+ }
///
/// Returns a hexadecimal representation of the hash value.
public string End()
{
- var crc16Output = new StringBuilder();
+ var crc16Output = new StringBuilder();
+ ushort final = 0;
- ushort final = (ushort)(_hashInt ^ _finalSeed);
+ switch(_useNative)
+ {
+ case true when _useCcitt:
+ crc16_ccitt_final(_nativeContext, ref final);
+ crc16_ccitt_free(_nativeContext);
- if(_inverse)
- final = (ushort)~final;
+ break;
+ case true when _useIbm:
+ crc16_final(_nativeContext, ref final);
+ crc16_free(_nativeContext);
+
+ break;
+ default:
+ {
+ if(_inverse)
+ final = (ushort)~(_hashInt ^ _finalSeed);
+ else
+ final = (ushort)(_hashInt ^ _finalSeed);
+
+ break;
+ }
+ }
byte[] finalBytes = BigEndianBitConverter.GetBytes(final);
@@ -98,6 +187,30 @@ namespace Aaru.Checksums
return crc16Output.ToString();
}
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr crc16_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc16_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc16_final(IntPtr ctx, ref ushort crc);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void crc16_free(IntPtr ctx);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr crc16_ccitt_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc16_ccitt_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc16_ccitt_final(IntPtr ctx, ref ushort crc);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void crc16_ccitt_free(IntPtr ctx);
+
static void Step(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
{
// Unroll according to Intel slicing by uint8_t
@@ -234,10 +347,34 @@ namespace Aaru.Checksums
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
bool inverse)
{
+ bool useNative = Native.IsSupported;
+
+ bool useCcitt = polynomial == CRC16CCITTContext.CRC16_CCITT_POLY &&
+ seed == CRC16CCITTContext.CRC16_CCITT_SEED && inverse;
+
+ bool useIbm = polynomial == CRC16IBMContext.CRC16_IBM_POLY && seed == CRC16IBMContext.CRC16_IBM_SEED &&
+ !inverse;
+
+ IntPtr nativeContext = IntPtr.Zero;
+
var fileStream = new FileStream(filename, FileMode.Open);
ushort localHashInt = seed;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ nativeContext = crc16_ccitt_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ case true when useIbm:
+ nativeContext = crc16_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ }
+
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
byte[] buffer = new byte[65536];
@@ -245,18 +382,52 @@ namespace Aaru.Checksums
while(read > 0)
{
- if(inverse)
- StepInverse(ref localHashInt, localTable, buffer, (uint)read);
- else
- Step(ref localHashInt, localTable, buffer, (uint)read);
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_update(nativeContext, buffer, (uint)read);
+
+ break;
+ case true when useIbm:
+ crc16_update(nativeContext, buffer, (uint)read);
+
+ break;
+ default:
+ {
+ if(inverse)
+ StepInverse(ref localHashInt, localTable, buffer, (uint)read);
+ else
+ Step(ref localHashInt, localTable, buffer, (uint)read);
+
+ break;
+ }
+ }
read = fileStream.Read(buffer, 0, 65536);
}
localHashInt ^= seed;
- if(inverse)
- localHashInt = (ushort)~localHashInt;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_final(nativeContext, ref localHashInt);
+ crc16_ccitt_free(nativeContext);
+
+ break;
+ case true when useIbm:
+ crc16_final(nativeContext, ref localHashInt);
+ crc16_free(nativeContext);
+
+ break;
+ default:
+ {
+ if(inverse)
+ localHashInt = (ushort)~localHashInt;
+
+ break;
+ }
+ }
hash = BigEndianBitConverter.GetBytes(localHashInt);
@@ -281,19 +452,77 @@ namespace Aaru.Checksums
public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed,
ushort[][] table, bool inverse)
{
+ bool useNative = Native.IsSupported;
+
+ bool useCcitt = polynomial == CRC16CCITTContext.CRC16_CCITT_POLY &&
+ seed == CRC16CCITTContext.CRC16_CCITT_SEED && inverse;
+
+ bool useIbm = polynomial == CRC16IBMContext.CRC16_IBM_POLY && seed == CRC16IBMContext.CRC16_IBM_SEED &&
+ !inverse;
+
+ IntPtr nativeContext = IntPtr.Zero;
+
ushort localHashInt = seed;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ nativeContext = crc16_ccitt_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ case true when useIbm:
+ nativeContext = crc16_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ }
+
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
- if(inverse)
- StepInverse(ref localHashInt, localTable, data, len);
- else
- Step(ref localHashInt, localTable, data, len);
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_update(nativeContext, data, len);
+
+ break;
+ case true when useIbm:
+ crc16_update(nativeContext, data, len);
+
+ break;
+ default:
+ {
+ if(inverse)
+ StepInverse(ref localHashInt, localTable, data, len);
+ else
+ Step(ref localHashInt, localTable, data, len);
+
+ break;
+ }
+ }
localHashInt ^= seed;
- if(inverse)
- localHashInt = (ushort)~localHashInt;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_final(nativeContext, ref localHashInt);
+ crc16_ccitt_free(nativeContext);
+
+ break;
+ case true when useIbm:
+ crc16_final(nativeContext, ref localHashInt);
+ crc16_free(nativeContext);
+
+ break;
+ default:
+ {
+ if(inverse)
+ localHashInt = (ushort)~localHashInt;
+
+ break;
+ }
+ }
hash = BigEndianBitConverter.GetBytes(localHashInt);
@@ -314,19 +543,77 @@ namespace Aaru.Checksums
/// CRC16
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[][] table, bool inverse)
{
+ bool useNative = Native.IsSupported;
+
+ bool useCcitt = polynomial == CRC16CCITTContext.CRC16_CCITT_POLY &&
+ seed == CRC16CCITTContext.CRC16_CCITT_SEED && inverse;
+
+ bool useIbm = polynomial == CRC16IBMContext.CRC16_IBM_POLY && seed == CRC16IBMContext.CRC16_IBM_SEED &&
+ !inverse;
+
+ IntPtr nativeContext = IntPtr.Zero;
+
ushort localHashInt = seed;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ nativeContext = crc16_ccitt_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ case true when useIbm:
+ nativeContext = crc16_init();
+ useNative = nativeContext != IntPtr.Zero;
+
+ break;
+ }
+
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
- if(inverse)
- StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length);
- else
- Step(ref localHashInt, localTable, buffer, (uint)buffer.Length);
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_update(nativeContext, buffer, (uint)buffer.Length);
+
+ break;
+ case true when useIbm:
+ crc16_update(nativeContext, buffer, (uint)buffer.Length);
+
+ break;
+ default:
+ {
+ if(inverse)
+ StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length);
+ else
+ Step(ref localHashInt, localTable, buffer, (uint)buffer.Length);
+
+ break;
+ }
+ }
localHashInt ^= seed;
- if(inverse)
- localHashInt = (ushort)~localHashInt;
+ switch(useNative)
+ {
+ case true when useCcitt:
+ crc16_ccitt_final(nativeContext, ref localHashInt);
+ crc16_ccitt_free(nativeContext);
+
+ break;
+ case true when useIbm:
+ crc16_final(nativeContext, ref localHashInt);
+ crc16_free(nativeContext);
+
+ break;
+ default:
+ {
+ if(inverse)
+ localHashInt = (ushort)~localHashInt;
+
+ break;
+ }
+ }
return localHashInt;
}
diff --git a/CRC16IBMContext.cs b/CRC16IBMContext.cs
index f5e539f..259fd60 100644
--- a/CRC16IBMContext.cs
+++ b/CRC16IBMContext.cs
@@ -36,8 +36,8 @@ namespace Aaru.Checksums
/// Implements the CRC16 algorithm with IBM polynomial and seed
public sealed class CRC16IBMContext : Crc16Context
{
- const ushort CRC16_IBM_POLY = 0xA001;
- const ushort CRC16_IBM_SEED = 0x0000;
+ internal const ushort CRC16_IBM_POLY = 0xA001;
+ internal const ushort CRC16_IBM_SEED = 0x0000;
static readonly ushort[][] _ibmCrc16Table =
{
diff --git a/CRC32Context.cs b/CRC32Context.cs
index 132869b..0995ed2 100644
--- a/CRC32Context.cs
+++ b/CRC32Context.cs
@@ -32,6 +32,7 @@
using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using System.Text;
@@ -333,8 +334,10 @@ namespace Aaru.Checksums
};
readonly uint _finalSeed;
+ readonly IntPtr _nativeContext;
readonly uint[][] _table;
readonly bool _useIso;
+ readonly bool _useNative;
uint _hashInt;
/// Initializes the CRC32 table and seed as CRC32-ISO
@@ -344,6 +347,12 @@ namespace Aaru.Checksums
_finalSeed = CRC32_ISO_SEED;
_table = _isoCrc32Table;
_useIso = true;
+
+ if(!Native.IsSupported)
+ return;
+
+ _nativeContext = crc32_init();
+ _useNative = _nativeContext != IntPtr.Zero;
}
/// Initializes the CRC32 table with a custom polynomial and seed
@@ -353,14 +362,21 @@ namespace Aaru.Checksums
_finalSeed = seed;
_useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
- _table = GenerateTable(polynomial);
+ if(Native.IsSupported && _useIso)
+ {
+ _nativeContext = crc32_init();
+ _useNative = _nativeContext != IntPtr.Zero;
+ }
+ else
+ _table = GenerateTable(polynomial);
}
///
/// Updates the hash with data.
/// Data buffer.
/// Length of buffer to hash.
- public void Update(byte[] data, uint len) => Step(ref _hashInt, _table, data, len, _useIso);
+ public void Update(byte[] data, uint len) =>
+ Step(ref _hashInt, _table, data, len, _useIso, _useNative, _nativeContext);
///
/// Updates the hash with data.
@@ -369,20 +385,52 @@ namespace Aaru.Checksums
///
/// Returns a byte array of the hash value.
- public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed);
+ public byte[] Final()
+ {
+ uint crc = _hashInt ^ _finalSeed;
+
+ if(!_useNative ||
+ !_useIso)
+ return BigEndianBitConverter.GetBytes(crc);
+
+ crc32_final(_nativeContext, ref crc);
+ crc32_free(_nativeContext);
+
+ return BigEndianBitConverter.GetBytes(crc);
+ }
///
/// Returns a hexadecimal representation of the hash value.
public string End()
{
+ uint crc = _hashInt ^ _finalSeed;
+
var crc32Output = new StringBuilder();
- for(int i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed).Length; i++)
- crc32Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^ _finalSeed)[i].ToString("x2"));
+ if(_useNative && _useIso)
+ {
+ crc32_final(_nativeContext, ref crc);
+ crc32_free(_nativeContext);
+ }
+
+ for(int i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
+ crc32Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
return crc32Output.ToString();
}
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr crc32_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc32_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc32_final(IntPtr ctx, ref uint crc);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void crc32_free(IntPtr ctx);
+
static uint[][] GenerateTable(uint polynomial)
{
uint[][] table = new uint[8][];
@@ -410,8 +458,16 @@ namespace Aaru.Checksums
return table;
}
- static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso)
+ static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso, bool useNative,
+ IntPtr nativeContext)
{
+ if(useNative && useIso)
+ {
+ crc32_update(nativeContext, data, len);
+
+ return;
+ }
+
int currentPos = 0;
if(useIso)
@@ -426,7 +482,7 @@ namespace Aaru.Checksums
if(blocks > 0)
{
- previousCrc = ~Clmul.Step(data, blocks * 64, ~previousCrc);
+ previousCrc = ~CRC32.Clmul.Step(data, blocks * 64, ~previousCrc);
currentPos = (int)(blocks * 64);
len -= blocks * 64;
@@ -505,6 +561,16 @@ namespace Aaru.Checksums
/// CRC seed
public static string File(string filename, out byte[] hash, uint polynomial, uint seed)
{
+ bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative && useIso)
+ {
+ nativeContext = crc32_init();
+ useNative = nativeContext != IntPtr.Zero;
+ }
+
var fileStream = new FileStream(filename, FileMode.Open);
uint localHashInt = seed;
@@ -516,14 +582,20 @@ namespace Aaru.Checksums
while(read > 0)
{
- Step(ref localHashInt, localTable, buffer, (uint)read,
- polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED);
+ Step(ref localHashInt, localTable, buffer, (uint)read, useIso, useNative, nativeContext);
read = fileStream.Read(buffer, 0, 65536);
}
localHashInt ^= seed;
- hash = BigEndianBitConverter.GetBytes(localHashInt);
+
+ if(useNative && useIso)
+ {
+ crc32_final(nativeContext, ref localHashInt);
+ crc32_free(nativeContext);
+ }
+
+ hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc32Output = new StringBuilder();
@@ -550,14 +622,31 @@ namespace Aaru.Checksums
/// CRC seed
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
{
+ bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative && useIso)
+ {
+ nativeContext = crc32_init();
+ useNative = nativeContext != IntPtr.Zero;
+ }
+
uint localHashInt = seed;
uint[][] localTable = GenerateTable(polynomial);
- Step(ref localHashInt, localTable, data, len, polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED);
+ Step(ref localHashInt, localTable, data, len, useIso, useNative, nativeContext);
localHashInt ^= seed;
- hash = BigEndianBitConverter.GetBytes(localHashInt);
+
+ if(useNative && useIso)
+ {
+ crc32_final(nativeContext, ref localHashInt);
+ crc32_free(nativeContext);
+ }
+
+ hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc32Output = new StringBuilder();
diff --git a/CRC64Context.cs b/CRC64Context.cs
index f9c0855..834e99a 100644
--- a/CRC64Context.cs
+++ b/CRC64Context.cs
@@ -32,9 +32,9 @@
using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;
using System.Text;
-using Aaru.Checksums.CRC64;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
@@ -274,8 +274,10 @@ namespace Aaru.Checksums
};
readonly ulong _finalSeed;
+ readonly IntPtr _nativeContext;
readonly ulong[][] _table;
readonly bool _useEcma;
+ readonly bool _useNative;
ulong _hashInt;
/// Initializes the CRC64 table and seed as CRC64-ECMA
@@ -285,22 +287,36 @@ namespace Aaru.Checksums
_table = _ecmaCrc64Table;
_finalSeed = CRC64_ECMA_SEED;
_useEcma = true;
+
+ if(!Native.IsSupported)
+ return;
+
+ _nativeContext = crc64_init();
+ _useNative = _nativeContext != IntPtr.Zero;
}
/// Initializes the CRC16 table with a custom polynomial and seed
public Crc64Context(ulong polynomial, ulong seed)
{
_hashInt = seed;
- _table = GenerateTable(polynomial);
_finalSeed = seed;
_useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
+
+ if(Native.IsSupported && _useEcma)
+ {
+ _nativeContext = crc64_init();
+ _useNative = _nativeContext != IntPtr.Zero;
+ }
+ else
+ _table = GenerateTable(polynomial);
}
///
/// Updates the hash with data.
/// Data buffer.
/// Length of buffer to hash.
- public void Update(byte[] data, uint len) => Step(ref _hashInt, _table, data, len, _useEcma);
+ public void Update(byte[] data, uint len) =>
+ Step(ref _hashInt, _table, data, len, _useEcma, _useNative, _nativeContext);
///
/// Updates the hash with data.
@@ -309,20 +325,52 @@ namespace Aaru.Checksums
///
/// Returns a byte array of the hash value.
- public byte[] Final() => BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed);
+ public byte[] Final()
+ {
+ ulong crc = _hashInt ^ _finalSeed;
+
+ if(!_useNative ||
+ !_useEcma)
+ return BigEndianBitConverter.GetBytes(crc);
+
+ crc64_final(_nativeContext, ref crc);
+ crc64_free(_nativeContext);
+
+ return BigEndianBitConverter.GetBytes(crc);
+ }
///
/// Returns a hexadecimal representation of the hash value.
public string End()
{
+ ulong crc = _hashInt ^ _finalSeed;
+
var crc64Output = new StringBuilder();
- for(int i = 0; i < BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed).Length; i++)
- crc64Output.Append(BigEndianBitConverter.GetBytes(_hashInt ^= _finalSeed)[i].ToString("x2"));
+ if(_useNative && _useEcma)
+ {
+ crc64_final(_nativeContext, ref crc);
+ crc64_free(_nativeContext);
+ }
+
+ for(int i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
+ crc64Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
return crc64Output.ToString();
}
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr crc64_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc64_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int crc64_final(IntPtr ctx, ref ulong crc);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void crc64_free(IntPtr ctx);
+
static ulong[][] GenerateTable(ulong polynomial)
{
ulong[][] table = new ulong[8][];
@@ -350,8 +398,16 @@ namespace Aaru.Checksums
return table;
}
- static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma)
+ static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma, bool useNative,
+ IntPtr nativeContext)
{
+ if(useNative && useEcma)
+ {
+ crc64_update(nativeContext, data, len);
+
+ return;
+ }
+
int dataOff = 0;
if(useEcma &&
@@ -365,7 +421,7 @@ namespace Aaru.Checksums
if(blocks > 0)
{
- previousCrc = ~Clmul.Step(~previousCrc, data, blocks * 32);
+ previousCrc = ~CRC64.Clmul.Step(~previousCrc, data, blocks * 32);
dataOff = (int)(blocks * 32);
len -= blocks * 32;
@@ -424,6 +480,16 @@ namespace Aaru.Checksums
/// CRC seed
public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed)
{
+ bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative && useEcma)
+ {
+ nativeContext = crc64_init();
+ useNative = nativeContext != IntPtr.Zero;
+ }
+
var fileStream = new FileStream(filename, FileMode.Open);
ulong localHashInt = seed;
@@ -435,14 +501,20 @@ namespace Aaru.Checksums
while(read > 0)
{
- Step(ref localHashInt, localTable, buffer, (uint)read,
- polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED);
+ Step(ref localHashInt, localTable, buffer, (uint)read, useEcma, useNative, nativeContext);
read = fileStream.Read(buffer, 0, 65536);
}
localHashInt ^= seed;
- hash = BigEndianBitConverter.GetBytes(localHashInt);
+
+ if(useNative && useEcma)
+ {
+ crc64_final(nativeContext, ref localHashInt);
+ crc64_free(nativeContext);
+ }
+
+ hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc64Output = new StringBuilder();
@@ -469,14 +541,31 @@ namespace Aaru.Checksums
/// CRC seed
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
{
+ bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative && useEcma)
+ {
+ nativeContext = crc64_init();
+ useNative = nativeContext != IntPtr.Zero;
+ }
+
ulong localHashInt = seed;
ulong[][] localTable = GenerateTable(polynomial);
- Step(ref localHashInt, localTable, data, len, polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED);
+ Step(ref localHashInt, localTable, data, len, useEcma, useNative, nativeContext);
localHashInt ^= seed;
- hash = BigEndianBitConverter.GetBytes(localHashInt);
+
+ if(useNative && useEcma)
+ {
+ crc64_final(nativeContext, ref localHashInt);
+ crc64_free(nativeContext);
+ }
+
+ hash = BigEndianBitConverter.GetBytes(localHashInt);
var crc64Output = new StringBuilder();
diff --git a/FletcherContext.cs b/FletcherContext.cs
index c633423..bdabdca 100644
--- a/FletcherContext.cs
+++ b/FletcherContext.cs
@@ -32,7 +32,9 @@
// Disabled because the speed is abnormally slow
+using System;
using System.IO;
+using System.Runtime.InteropServices;
using System.Text;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
@@ -42,22 +44,30 @@ namespace Aaru.Checksums
/// Implements the Fletcher-32 algorithm
public sealed class Fletcher32Context : IChecksum
{
- const ushort FLETCHER_MODULE = 0xFFFF;
- const uint NMAX = 5552;
- ushort _sum1, _sum2;
+ const ushort FLETCHER_MODULE = 0xFFFF;
+ const uint NMAX = 5552;
+ readonly IntPtr _nativeContext;
+ readonly bool _useNative;
+ ushort _sum1, _sum2;
/// Initializes the Fletcher-32 sums
public Fletcher32Context()
{
_sum1 = 0xFFFF;
_sum2 = 0xFFFF;
+
+ if(!Native.IsSupported)
+ return;
+
+ _nativeContext = fletcher32_init();
+ _useNative = _nativeContext != IntPtr.Zero;
}
///
/// Updates the hash with data.
/// Data buffer.
/// Length of buffer to hash.
- public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
+ public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
///
/// Updates the hash with data.
@@ -70,6 +80,12 @@ namespace Aaru.Checksums
{
uint finalSum = (uint)((_sum2 << 16) | _sum1);
+ if(!_useNative)
+ return BigEndianBitConverter.GetBytes(finalSum);
+
+ fletcher32_final(_nativeContext, ref finalSum);
+ fletcher32_free(_nativeContext);
+
return BigEndianBitConverter.GetBytes(finalSum);
}
@@ -77,8 +93,15 @@ namespace Aaru.Checksums
/// Returns a hexadecimal representation of the hash value.
public string End()
{
- uint finalSum = (uint)((_sum2 << 16) | _sum1);
- var fletcherOutput = new StringBuilder();
+ uint finalSum = (uint)((_sum2 << 16) | _sum1);
+
+ if(_useNative)
+ {
+ fletcher32_final(_nativeContext, ref finalSum);
+ fletcher32_free(_nativeContext);
+ }
+
+ var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
@@ -86,8 +109,28 @@ namespace Aaru.Checksums
return fletcherOutput.ToString();
}
- static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len)
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr fletcher32_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int fletcher32_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int fletcher32_final(IntPtr ctx, ref uint crc);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void fletcher32_free(IntPtr ctx);
+
+ static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len, bool useNative,
+ IntPtr nativeContext)
{
+ if(useNative)
+ {
+ fletcher32_update(nativeContext, data, len);
+
+ return;
+ }
+
uint sum1 = previousSum1;
uint sum2 = previousSum2;
uint n;
@@ -251,6 +294,17 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string File(string filename, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = fletcher32_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
var fileStream = new FileStream(filename, FileMode.Open);
ushort localSum1 = 0xFFFF;
@@ -261,13 +315,19 @@ namespace Aaru.Checksums
while(read > 0)
{
- Step(ref localSum1, ref localSum2, buffer, (uint)read);
+ Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.Read(buffer, 0, 65536);
}
uint finalSum = (uint)((localSum2 << 16) | localSum1);
+ if(useNative)
+ {
+ fletcher32_final(nativeContext, ref finalSum);
+ fletcher32_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var fletcherOutput = new StringBuilder();
@@ -286,13 +346,30 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string Data(byte[] data, uint len, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = fletcher32_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
ushort localSum1 = 0xFFFF;
ushort localSum2 = 0xFFFF;
- Step(ref localSum1, ref localSum2, data, len);
+ Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
uint finalSum = (uint)((localSum2 << 16) | localSum1);
+ if(useNative)
+ {
+ fletcher32_final(nativeContext, ref finalSum);
+ fletcher32_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
@@ -315,20 +392,29 @@ namespace Aaru.Checksums
{
const byte FLETCHER_MODULE = 0xFF;
const byte NMAX = 22;
- byte _sum1, _sum2;
+
+ readonly IntPtr _nativeContext;
+ readonly bool _useNative;
+ byte _sum1, _sum2;
/// Initializes the Fletcher-16 sums
public Fletcher16Context()
{
_sum1 = 0xFF;
_sum2 = 0xFF;
+
+ if(!Native.IsSupported)
+ return;
+
+ _nativeContext = fletcher16_init();
+ _useNative = _nativeContext != IntPtr.Zero;
}
///
/// Updates the hash with data.
/// Data buffer.
/// Length of buffer to hash.
- public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len);
+ public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
///
/// Updates the hash with data.
@@ -341,6 +427,12 @@ namespace Aaru.Checksums
{
ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
+ if(!_useNative)
+ return BigEndianBitConverter.GetBytes(finalSum);
+
+ fletcher16_final(_nativeContext, ref finalSum);
+ fletcher16_free(_nativeContext);
+
return BigEndianBitConverter.GetBytes(finalSum);
}
@@ -348,8 +440,15 @@ namespace Aaru.Checksums
/// Returns a hexadecimal representation of the hash value.
public string End()
{
- ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
- var fletcherOutput = new StringBuilder();
+ ushort finalSum = (ushort)((_sum2 << 8) | _sum1);
+
+ if(_useNative)
+ {
+ fletcher16_final(_nativeContext, ref finalSum);
+ fletcher16_free(_nativeContext);
+ }
+
+ var fletcherOutput = new StringBuilder();
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
@@ -357,8 +456,28 @@ namespace Aaru.Checksums
return fletcherOutput.ToString();
}
- static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len)
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern IntPtr fletcher16_init();
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int fletcher16_update(IntPtr ctx, byte[] data, uint len);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern int fletcher16_final(IntPtr ctx, ref ushort checksum);
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern void fletcher16_free(IntPtr ctx);
+
+ static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len, bool useNative,
+ IntPtr nativeContext)
{
+ if(useNative)
+ {
+ fletcher16_update(nativeContext, data, len);
+
+ return;
+ }
+
uint sum1 = previousSum1;
uint sum2 = previousSum2;
uint n;
@@ -502,6 +621,17 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string File(string filename, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = fletcher16_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
var fileStream = new FileStream(filename, FileMode.Open);
byte localSum1 = 0xFF;
@@ -512,13 +642,19 @@ namespace Aaru.Checksums
while(read > 0)
{
- Step(ref localSum1, ref localSum2, buffer, (uint)read);
+ Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
read = fileStream.Read(buffer, 0, 65536);
}
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);
+ if(useNative)
+ {
+ fletcher16_final(nativeContext, ref finalSum);
+ fletcher16_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var fletcherOutput = new StringBuilder();
@@ -537,13 +673,30 @@ namespace Aaru.Checksums
/// Byte array of the hash value.
public static string Data(byte[] data, uint len, out byte[] hash)
{
+ bool useNative = Native.IsSupported;
+ IntPtr nativeContext = IntPtr.Zero;
+
+ if(useNative)
+ {
+ nativeContext = fletcher16_init();
+
+ if(nativeContext == IntPtr.Zero)
+ useNative = false;
+ }
+
byte localSum1 = 0xFF;
byte localSum2 = 0xFF;
- Step(ref localSum1, ref localSum2, data, len);
+ Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);
+ if(useNative)
+ {
+ fletcher16_final(nativeContext, ref finalSum);
+ fletcher16_free(nativeContext);
+ }
+
hash = BigEndianBitConverter.GetBytes(finalSum);
var adlerOutput = new StringBuilder();
diff --git a/Native.cs b/Native.cs
new file mode 100644
index 0000000..8a39e0f
--- /dev/null
+++ b/Native.cs
@@ -0,0 +1,83 @@
+// /***************************************************************************
+// Aaru Data Preservation Suite
+// ----------------------------------------------------------------------------
+//
+// Filename : Native.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Checksums.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Checks that Aaru.Checksums.Native library is available and usable.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2021 Natalia Portillo
+// ****************************************************************************/
+
+using System.Runtime.InteropServices;
+
+namespace Aaru.Checksums
+{
+ public static class Native
+ {
+ static bool _checked;
+ static bool _supported;
+
+ /// Set to return native as never supported
+ public static bool ForceManaged { get; set; }
+
+ ///
+ /// If set to true the native library was found and loaded correctly and its reported version is
+ /// compatible.
+ ///
+ public static bool IsSupported
+ {
+ get
+ {
+ if(ForceManaged)
+ return false;
+
+ if(_checked)
+ return _supported;
+
+ ulong version;
+ _checked = true;
+
+ try
+ {
+ version = get_acn_version();
+ }
+ catch
+ {
+ _supported = false;
+
+ return false;
+ }
+
+ // TODO: Check version compatibility
+ _supported = version >= 0x06000000;
+
+ return _supported;
+ }
+ }
+
+ [DllImport("libAaru.Checksums.Native", SetLastError = true)]
+ static extern ulong get_acn_version();
+ }
+}
\ No newline at end of file