diff --git a/NBitcoin.Bench/README.md b/NBitcoin.Bench/README.md index ed3aaf6f4..bb15af43d 100644 --- a/NBitcoin.Bench/README.md +++ b/NBitcoin.Bench/README.md @@ -2,11 +2,12 @@ This project use BenchmarkDotnet to measure performance of parts of NBitcoin implementation. -You can generate flamegraph to view with Perfview on Windows with the following command: +You can generate flamegraph to view with [PerfView](https://github.com/microsoft/perfview) on Windows with the following command: + ```powershell dotnet run -c Release -- --runtimes net8.0 --filter *GolombRiceFilters* --profiler ETW ``` -Where `GolombRiceFilters` is the name of the benchmark class you are insterested in. +Where `GolombRiceFilters` is the name of the benchmark class you are interested in. For generating flamegraph on linux, see [this comment](https://github.com/MetacoSA/NBitcoin/pull/656#issuecomment-462927805). diff --git a/NBitcoin.Bench/UtilsBench.cs b/NBitcoin.Bench/UtilsBench.cs new file mode 100644 index 000000000..359c6b333 --- /dev/null +++ b/NBitcoin.Bench/UtilsBench.cs @@ -0,0 +1,35 @@ +using BenchmarkDotNet.Attributes; +using NBitcoin.DataEncoders; +using System.Collections.Generic; + +namespace NBitcoin.Bench; + +[MemoryDiagnoser] +public class UtilsBench +{ + private static readonly byte[] taprootPubKeyA = Encoders.Hex.DecodeData("54c9e50dde41d5fc0b3dc0ff1ed4f6603a493d0a50dcc1badc3a5d959da7e750"); + private static readonly byte[] taprootPubKeyB = Encoders.Hex.DecodeData("7ca556cf2fc5ba848c5ede3c8f0605dc78c005244915ad42b4b15076eb4b2c43"); + + public static IEnumerable ArrayEqualArgs + { + get + { + yield return new byte[][] { [], [] }; // No bytes. + yield return new byte[][] { [], [0x01] }; // Empty array against non-empty array. + yield return new byte[][] { [0x01], [0x02] }; // 1-byte arrays which are not equal. + yield return new byte[][] { [0x01, 0x02], [0x01, 0x03] }; // 2-byte arrays which are not equal. + yield return new byte[][] { [0x01, 0x02, 0x03], [0x02, 0x03, 0x04] }; // 3-byte arrays which are not equal. + yield return new byte[][] { [0x01, 0x02, 0x03, 0x04, 0x05], [0x01, 0x02, 0x03, 0x04, 0x05] }; // 5-byte arrays which are equal. + yield return new byte[][] { [0x01, 0x02, 0x03, 0x04, 0x06, 0x05], [0x01, 0x02, 0x03, 0x04, 0x05, 0x06] }; // 6-byte arrays which are not equal. + yield return new byte[][] { [.. taprootPubKeyA], [.. taprootPubKeyA] }; // Create a copy to avoid reference equality + yield return new byte[][] { [.. taprootPubKeyA], [.. taprootPubKeyB] }; + } + } + + [Benchmark] + [ArgumentsSource(nameof(ArrayEqualArgs))] + public bool ArrayEqual(byte[] a, byte[] b) + { + return Utils.ArrayEqual(a, b); + } +} diff --git a/NBitcoin.Tests/util_tests.cs b/NBitcoin.Tests/util_tests.cs index c383f1e1c..d498f8a97 100644 --- a/NBitcoin.Tests/util_tests.cs +++ b/NBitcoin.Tests/util_tests.cs @@ -938,7 +938,7 @@ public void CanEncryptAndDecryptMessages() Assert.True(Utils.ArrayEqual(text1, plainText)); Assert.Equal(text2, Encoders.ASCII.EncodeData(plainText)); - // Encrypt twice, should not give twice same cypher + // Encrypt twice, should not give twice same cipher var cipherText3 = key.PubKey.Encrypt(plainText); Assert.True(!Utils.ArrayEqual(cipherText1, cipherText3)); } diff --git a/NBitcoin/Utils.cs b/NBitcoin/Utils.cs index 4862b0c66..c3f6fb33a 100644 --- a/NBitcoin/Utils.cs +++ b/NBitcoin/Utils.cs @@ -471,24 +471,26 @@ internal static void SafeSet(ManualResetEvent ar) } catch { } } - public static bool ArrayEqual(byte[] a, byte[] b) + public static bool ArrayEqual(byte[]? a, byte[]? b) { if (a == null && b == null) return true; - if (a == null) + if (a == null || b == null) return false; - if (b == null) + + if (a.Length != b.Length) return false; - return ArrayEqual(a, 0, b, 0, Math.Max(a.Length, b.Length)); + + return ArrayEqual(a, 0, b, 0, a.Length); } - public static bool ArrayEqual(byte[] a, int startA, byte[] b, int startB, int length) + + public static bool ArrayEqual(byte[]? a, int startA, byte[]? b, int startB, int length) { if (a == null && b == null) return true; - if (a == null) - return false; - if (b == null) + if (a == null || b == null) return false; + var alen = a.Length - startA; var blen = b.Length - startB;