From 9f6b56242f0f4a1818b737f36b07712b6955b373 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 13 Oct 2021 23:52:41 +0100 Subject: [PATCH] Add native CRC32. --- Aaru6.Checksums/CRC32Context.cs | 111 +++++++++++++++++++++++--- AaruBenchmark/Checksums/Aaru6.cs | 2 + AaruBenchmark/Checksums/AaruNative.cs | 46 +++-------- 3 files changed, 111 insertions(+), 48 deletions(-) diff --git a/Aaru6.Checksums/CRC32Context.cs b/Aaru6.Checksums/CRC32Context.cs index c4d1661..b4e6a47 100644 --- a/Aaru6.Checksums/CRC32Context.cs +++ b/Aaru6.Checksums/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 Aaru6.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 Aaru6.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 Aaru6.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 Aaru6.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 Aaru6.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) @@ -522,6 +578,16 @@ namespace Aaru6.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; @@ -533,14 +599,20 @@ namespace Aaru6.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(); @@ -567,14 +639,31 @@ namespace Aaru6.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/AaruBenchmark/Checksums/Aaru6.cs b/AaruBenchmark/Checksums/Aaru6.cs index 24a3aaf..9885ed7 100644 --- a/AaruBenchmark/Checksums/Aaru6.cs +++ b/AaruBenchmark/Checksums/Aaru6.cs @@ -183,6 +183,8 @@ namespace AaruBenchmark.Checksums public static void Crc32() { + Native.ForceManaged = true; + byte[] data = new byte[1048576]; var fs = new FileStream(Path.Combine(Program.Folder, "random"), FileMode.Open, FileAccess.Read); diff --git a/AaruBenchmark/Checksums/AaruNative.cs b/AaruBenchmark/Checksums/AaruNative.cs index cbcddf2..7a0137b 100644 --- a/AaruBenchmark/Checksums/AaruNative.cs +++ b/AaruBenchmark/Checksums/AaruNative.cs @@ -100,18 +100,6 @@ namespace AaruBenchmark.Checksums [DllImport("libAaru.Checksums.Native", SetLastError = true)] static extern void fletcher32_free(IntPtr ctx); - [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); - [DllImport("libAaru.Checksums.Native", SetLastError = true)] static extern IntPtr crc64_init(); @@ -279,39 +267,23 @@ namespace AaruBenchmark.Checksums public static void Crc32() { - byte[] data = new byte[1048576]; - uint crc32 = 0; - byte[] hash; + Native.ForceManaged = false; + + byte[] data = new byte[1048576]; var fs = new FileStream(Path.Combine(Program.Folder, "random"), FileMode.Open, FileAccess.Read); fs.Read(data, 0, 1048576); fs.Close(); fs.Dispose(); + IChecksum ctx = new Crc32Context(); + ctx.Update(data); + byte[] result = ctx.Final(); - IntPtr ctx = crc32_init(); + if(result?.Length != _expectedRandomCrc32.Length) + throw new Exception("Invalid hash length"); - if(ctx == IntPtr.Zero) - throw new Exception("Could not initialize digest"); - - int ret = crc32_update(ctx, data, (uint)data.Length); - - if(ret != 0) - throw new Exception("Could not digest block"); - - ret = crc32_final(ctx, ref crc32); - - if(ret != 0) - throw new Exception("Could not finalize hash"); - - crc32_free(ctx); - - crc32 = ((crc32 << 8) & 0xFF00FF00) | ((crc32 >> 8) & 0xFF00FF); - crc32 = (crc32 << 16) | (crc32 >> 16); - - hash = BitConverter.GetBytes(crc32); - - if(hash.Where((t, i) => t != _expectedRandomCrc32[i]).Any()) + if(result.Where((t, i) => t != _expectedRandomCrc32[i]).Any()) throw new Exception("Invalid hash value"); }