From 8c60a34f9235bd017567851976827c866ae9447b Mon Sep 17 00:00:00 2001 From: nan01ab Date: Fri, 1 Nov 2024 21:58:27 +0800 Subject: [PATCH 1/3] A better and simpler impl for ByteArrayEqualityComparer A better and simpler impl for ByteArrayEqualityComparer --- .../ByteArrayEqualityComparer.cs | 35 +++++++++++ src/Neo.Extensions/Neo.Extensions.csproj | 1 + src/Neo.IO/ByteArrayEqualityComparer.cs | 58 ------------------- src/Neo/IO/Caching/ECPointCache.cs | 1 + src/Neo/Persistence/MemorySnapshot.cs | 1 + src/Neo/Persistence/MemoryStore.cs | 1 + .../Cryptography/MPTTrie/Trie.Proof.cs | 2 +- .../MPTTrie/IO/ByteArrayEqualityComparer.cs | 58 ------------------- .../UT_ByteArrayEqualityComparer.cs | 2 +- 9 files changed, 41 insertions(+), 118 deletions(-) create mode 100644 src/Neo.Extensions/ByteArrayEqualityComparer.cs delete mode 100644 src/Neo.IO/ByteArrayEqualityComparer.cs delete mode 100644 src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs rename tests/{Neo.UnitTests/IO => Neo.Extensions.Tests}/UT_ByteArrayEqualityComparer.cs (98%) diff --git a/src/Neo.Extensions/ByteArrayEqualityComparer.cs b/src/Neo.Extensions/ByteArrayEqualityComparer.cs new file mode 100644 index 0000000000..7eecabffc5 --- /dev/null +++ b/src/Neo.Extensions/ByteArrayEqualityComparer.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ByteArrayEqualityComparer.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections.Generic; +using System.IO.Hashing; +using System.Linq; + +namespace Neo.Extensions +{ + public class ByteArrayEqualityComparer : IEqualityComparer + { + public static readonly ByteArrayEqualityComparer Default = new(); + + public bool Equals(byte[]? x, byte[]? y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null || x.Length != y.Length) return false; + + return x.SequenceEqual(y); + } + + public int GetHashCode(byte[] obj) + { + return (int)XxHash3.HashToUInt64(obj); + } + } +} diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index f424dd0809..38cbf346fb 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Neo.IO/ByteArrayEqualityComparer.cs b/src/Neo.IO/ByteArrayEqualityComparer.cs deleted file mode 100644 index 2b6f01491c..0000000000 --- a/src/Neo.IO/ByteArrayEqualityComparer.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// ByteArrayEqualityComparer.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System.Collections.Generic; - -namespace Neo.IO -{ - internal class ByteArrayEqualityComparer : IEqualityComparer - { - public static readonly ByteArrayEqualityComparer Default = new(); - - public unsafe bool Equals(byte[]? x, byte[]? y) - { - if (ReferenceEquals(x, y)) return true; - if (x is null || y is null) return false; - var len = x.Length; - if (len != y.Length) return false; - if (len == 0) return true; - fixed (byte* xp = x, yp = y) - { - long* xlp = (long*)xp, ylp = (long*)yp; - for (; len >= 8; len -= 8) - { - if (*xlp != *ylp) return false; - xlp++; - ylp++; - } - byte* xbp = (byte*)xlp, ybp = (byte*)ylp; - for (; len > 0; len--) - { - if (*xbp != *ybp) return false; - xbp++; - ybp++; - } - } - return true; - } - - public int GetHashCode(byte[] obj) - { - unchecked - { - var hash = 17; - foreach (var element in obj) - hash = hash * 31 + element; - return hash; - } - } - } -} diff --git a/src/Neo/IO/Caching/ECPointCache.cs b/src/Neo/IO/Caching/ECPointCache.cs index a32671d30f..e875b190af 100644 --- a/src/Neo/IO/Caching/ECPointCache.cs +++ b/src/Neo/IO/Caching/ECPointCache.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Cryptography.ECC; +using Neo.Extensions; namespace Neo.IO.Caching { diff --git a/src/Neo/Persistence/MemorySnapshot.cs b/src/Neo/Persistence/MemorySnapshot.cs index b3d06798d4..4817cc963e 100644 --- a/src/Neo/Persistence/MemorySnapshot.cs +++ b/src/Neo/Persistence/MemorySnapshot.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using System.Collections.Concurrent; using System.Collections.Generic; diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs index 378d5374f1..3107ebdddd 100644 --- a/src/Neo/Persistence/MemoryStore.cs +++ b/src/Neo/Persistence/MemoryStore.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using System.Collections.Concurrent; using System.Collections.Generic; diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs index d3c04053b9..895f666d08 100644 --- a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs @@ -9,7 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.IO; +using Neo.Extensions; using Neo.Persistence; using System; using System.Collections.Generic; diff --git a/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs b/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs deleted file mode 100644 index 590306d560..0000000000 --- a/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// ByteArrayEqualityComparer.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using System.Collections.Generic; - -namespace Neo.IO -{ - public class ByteArrayEqualityComparer : IEqualityComparer - { - public static readonly ByteArrayEqualityComparer Default = new ByteArrayEqualityComparer(); - - public unsafe bool Equals(byte[] x, byte[] y) - { - if (ReferenceEquals(x, y)) return true; - if (x is null || y is null) return false; - int len = x.Length; - if (len != y.Length) return false; - if (len == 0) return true; - fixed (byte* xp = x, yp = y) - { - long* xlp = (long*)xp, ylp = (long*)yp; - for (; len >= 8; len -= 8) - { - if (*xlp != *ylp) return false; - xlp++; - ylp++; - } - byte* xbp = (byte*)xlp, ybp = (byte*)ylp; - for (; len > 0; len--) - { - if (*xbp != *ybp) return false; - xbp++; - ybp++; - } - } - return true; - } - - public int GetHashCode(byte[] obj) - { - unchecked - { - int hash = 17; - foreach (byte element in obj) - hash = hash * 31 + element; - return hash; - } - } - } -} diff --git a/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs b/tests/Neo.Extensions.Tests/UT_ByteArrayEqualityComparer.cs similarity index 98% rename from tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs rename to tests/Neo.Extensions.Tests/UT_ByteArrayEqualityComparer.cs index ea5ae86be4..dce9720028 100644 --- a/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs +++ b/tests/Neo.Extensions.Tests/UT_ByteArrayEqualityComparer.cs @@ -14,7 +14,7 @@ using System; using System.Linq; -namespace Neo.UnitTests +namespace Neo.Extensions.Tests { [TestClass] public class UT_ByteArrayEqualityComparer From 37ceb1077e03c230c9468490e2be18622a3f04b4 Mon Sep 17 00:00:00 2001 From: nan01ab Date: Sun, 3 Nov 2024 19:31:23 +0800 Subject: [PATCH 2/3] use HashCode.Combine --- src/Neo.Extensions/ByteArrayEqualityComparer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Neo.Extensions/ByteArrayEqualityComparer.cs b/src/Neo.Extensions/ByteArrayEqualityComparer.cs index 7eecabffc5..674b778285 100644 --- a/src/Neo.Extensions/ByteArrayEqualityComparer.cs +++ b/src/Neo.Extensions/ByteArrayEqualityComparer.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; using System.Collections.Generic; using System.IO.Hashing; using System.Linq; @@ -29,7 +30,7 @@ public bool Equals(byte[]? x, byte[]? y) public int GetHashCode(byte[] obj) { - return (int)XxHash3.HashToUInt64(obj); + return HashCode.Combine(XxHash3.HashToUInt64(obj)); } } } From 1c0f37294fb1bb94eca8d955fd04cf2e02ffc649 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 7 Nov 2024 10:27:28 +0100 Subject: [PATCH 3/3] Move to Extensions --- .../ByteArrayEqualityComparer.cs | 3 +- src/Neo.Extensions/ByteExtensions.cs | 28 +++++++++++++++++++ src/Neo/Cryptography/Helper.cs | 26 ----------------- src/Neo/Neo.csproj | 1 - src/Neo/SmartContract/StorageKey.cs | 2 +- .../Neo.Extensions.Tests/UT_ByteExtensions.cs | 10 +++++++ .../Cryptography/UT_Cryptography_Helper.cs | 7 ----- tests/Neo.UnitTests/Ledger/UT_StorageKey.cs | 1 + 8 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/Neo.Extensions/ByteArrayEqualityComparer.cs b/src/Neo.Extensions/ByteArrayEqualityComparer.cs index 674b778285..9dbd2e5a37 100644 --- a/src/Neo.Extensions/ByteArrayEqualityComparer.cs +++ b/src/Neo.Extensions/ByteArrayEqualityComparer.cs @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; -using System.IO.Hashing; using System.Linq; namespace Neo.Extensions @@ -30,7 +29,7 @@ public bool Equals(byte[]? x, byte[]? y) public int GetHashCode(byte[] obj) { - return HashCode.Combine(XxHash3.HashToUInt64(obj)); + return obj.XxHash3_32(); } } } diff --git a/src/Neo.Extensions/ByteExtensions.cs b/src/Neo.Extensions/ByteExtensions.cs index 013a8ef1cc..1de90d567c 100644 --- a/src/Neo.Extensions/ByteExtensions.cs +++ b/src/Neo.Extensions/ByteExtensions.cs @@ -10,12 +10,40 @@ // modifications are permitted. using System; +using System.IO.Hashing; +using System.Runtime.CompilerServices; using System.Text; namespace Neo.Extensions { public static class ByteExtensions { + private const int DefaultXxHash3Seed = 40343; + + /// + /// Computes the 32-bit hash value for the specified byte array using the xxhash3 algorithm. + /// + /// The input to compute the hash code for. + /// The seed used by the xxhash3 algorithm. + /// The computed hash code. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int XxHash3_32(this ReadOnlySpan value, long seed = DefaultXxHash3Seed) + { + return HashCode.Combine(XxHash3.HashToUInt64(value, seed)); + } + + /// + /// Computes the 32-bit hash value for the specified byte array using the xxhash3 algorithm. + /// + /// The input to compute the hash code for. + /// The seed used by the xxhash3 algorithm. + /// The computed hash code. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int XxHash3_32(this byte[] value, long seed = DefaultXxHash3Seed) + { + return XxHash3_32(value.AsSpan(), seed); + } + /// /// Converts a byte array to hex . /// diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index 761073463b..f398612e61 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -18,7 +18,6 @@ using Org.BouncyCastle.Crypto.Parameters; using System; using System.Buffers.Binary; -using System.IO.Hashing; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,7 +31,6 @@ namespace Neo.Cryptography /// public static class Helper { - private const int DefaultXxHash3Seed = 40343; private static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); /// @@ -120,30 +118,6 @@ public static byte[] Sha256(this byte[] value) return sha256.ComputeHash(value); } - /// - /// Computes the 32-bit hash value for the specified byte array using the xxhash3 algorithm. - /// - /// The input to compute the hash code for. - /// The seed used by the xxhash3 algorithm. - /// The computed hash code. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int XxHash3_32(this ReadOnlySpan value, long seed = DefaultXxHash3Seed) - { - return HashCode.Combine(XxHash3.HashToUInt64(value, seed)); - } - - /// - /// Computes the 32-bit hash value for the specified byte array using the xxhash3 algorithm. - /// - /// The input to compute the hash code for. - /// The seed used by the xxhash3 algorithm. - /// The computed hash code. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int XxHash3_32(this byte[] value, long seed = DefaultXxHash3Seed) - { - return XxHash3_32(value.AsSpan(), seed); - } - /// /// Computes the hash value for the specified region of the specified byte array using the sha256 algorithm. /// diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 89c200e31b..7c6478c33e 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -16,7 +16,6 @@ - diff --git a/src/Neo/SmartContract/StorageKey.cs b/src/Neo/SmartContract/StorageKey.cs index 7a643a2737..23ad2e1d17 100644 --- a/src/Neo/SmartContract/StorageKey.cs +++ b/src/Neo/SmartContract/StorageKey.cs @@ -9,7 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.Cryptography; +using Neo.Extensions; using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; diff --git a/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs b/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs index 3c0c21b8f0..7f4a58bc0d 100644 --- a/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs +++ b/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs @@ -12,6 +12,9 @@ using FluentAssertions; using System; +using System.IO.Hashing; +using System.Linq; +using System.Text; namespace Neo.Extensions.Tests { @@ -34,6 +37,13 @@ public void TestToHexString() str1.ToHexString(true).Should().Be("6f656e"); } + [TestMethod] + public void TestXxHash3() + { + byte[] data = Encoding.ASCII.GetBytes(string.Concat(Enumerable.Repeat("Hello, World!^_^", 16 * 1024))); + data.XxHash3_32().Should().Be(HashCode.Combine(XxHash3.HashToUInt64(data, 40343))); + } + [TestMethod] public void TestReadOnlySpanToHexString() { diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index 194d65c35b..00aac10d42 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -57,13 +57,6 @@ public void TestMurmurReadOnlySpan() input.Murmur128(0).Should().Equal(input2.Murmur128(0)); } - [TestMethod] - public void TestXxHash3() - { - byte[] data = Encoding.ASCII.GetBytes(string.Concat(Enumerable.Repeat("Hello, World!^_^", 16 * 1024))); - data.XxHash3_32().Should().Be(HashCode.Combine(XxHash3.HashToUInt64(data, 40343))); - } - [TestMethod] public void TestSha256() { diff --git a/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs b/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs index a3bcefb37c..59242acd1b 100644 --- a/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs +++ b/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; +using Neo.Extensions; using Neo.SmartContract; using System;