From e5454964e7c1e18d3b56341fbe3b0ac127040ec1 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 4 Jun 2024 14:21:26 +0300 Subject: [PATCH 1/8] Initial secp256r1 precompile implementation --- .../Secp256r1PrecompilePrecompileTests.cs | 87 +++++++++++++++++++ src/Nethermind/Nethermind.Evm/Metrics.cs | 3 + .../Precompiles/AddressExtensions.cs | 1 + .../Precompiles/Secp256r1Precompile.cs | 46 ++++++++++ .../Nethermind.Evm/VirtualMachine.cs | 2 + 5 files changed, 139 insertions(+) create mode 100644 src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs create mode 100644 src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs diff --git a/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs new file mode 100644 index 00000000000..0e759da167e --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using FluentAssertions; +using Nethermind.Core.Extensions; +using Nethermind.Evm.Precompiles; +using Nethermind.Specs.Forks; +using NUnit.Framework; + +namespace Nethermind.Evm.Test +{ + [TestFixture] + public class Secp256r1PrecompilePrecompileTests : VirtualMachineTestsBase + { + private static readonly byte[] ValidAnswer = Bytes.FromHexString( + "0000000000000000000000000000000000000000000000000000000000000001" + ); + + private static readonly byte[] InvalidAnswer = Bytes.FromHexString( + "0000000000000000000000000000000000000000000000000000000000000000" + ); + + [Test] // https://github.com/paradigmxyz/alphanet/blob/main/crates/precompile/src/secp256r1.rs#L137 + [TestCase( + "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", + true + )] + [TestCase( + "3fec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", + true + )] + [TestCase( + "e775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", + true + )] + [TestCase( + "b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", + true + )] + [TestCase( + "858b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", + true + )] + [TestCase( + "3cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", + false + )] + [TestCase( + "afec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", + false + )] + [TestCase( + "f775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", + false + )] + [TestCase( + "c5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", + false + )] + [TestCase( + "958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", + false + )] + public void Produces_Correct_Outputs(string input, bool isValid) + { + var bytes = Bytes.FromHexString(input); + (ReadOnlyMemory output, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance); + success.Should().BeTrue(); + output.ToArray().Should().BeEquivalentTo(isValid ? ValidAnswer : InvalidAnswer); + } + + [Test] + [TestCase( + "4cee90eb86eaa050036147a12d49004b6a" + )] + [TestCase( + "4cee90eb86eaa050036147a12d49004b6a958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf319" + )] + public void Fails_On_Incorrect_Input(string input) + { + var bytes = Bytes.FromHexString(input); + (ReadOnlyMemory _, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance); + success.Should().BeFalse(); + } + } +} diff --git a/src/Nethermind/Nethermind.Evm/Metrics.cs b/src/Nethermind/Nethermind.Evm/Metrics.cs index 8c3286facc9..c1072cafe20 100644 --- a/src/Nethermind/Nethermind.Evm/Metrics.cs +++ b/src/Nethermind/Nethermind.Evm/Metrics.cs @@ -113,6 +113,9 @@ public static long SstoreOpcode [Description("Number of SHA256 precompile calls.")] public static long Sha256Precompile { get; set; } + [Description("Number of Secp256r1 precompile calls.")] + public static long Secp256r1Precompile { get; set; } + [Description("Number of Point Evaluation precompile calls.")] public static long PointEvaluationPrecompile { get; set; } diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs index 0f4fe5ebb6b..b604eaf42c4 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs @@ -36,6 +36,7 @@ public static bool IsPrecompile(this Address address, IReleaseSpec releaseSpec) 0x11 => releaseSpec.Bls381Enabled, 0x12 => releaseSpec.Bls381Enabled, 0x13 => releaseSpec.Bls381Enabled, + 0x100 => true, // TODO clarify if should be conditional _ => false }; } diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs new file mode 100644 index 00000000000..c44bc8c312b --- /dev/null +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Buffers; +using System.Security.Cryptography; +using Nethermind.Core; +using Nethermind.Core.Extensions; +using Nethermind.Core.Specs; + +namespace Nethermind.Evm.Precompiles; + +public class Secp256r1Precompile: IPrecompile +{ + private const int RequiredInputLength = 160; + private static readonly byte[] ValidResult = new byte[] { 1 }.PadLeft(32); + private static readonly byte[] InvalidResult = new byte[] { 0 }.PadLeft(32); + + public static readonly Secp256r1Precompile Instance = new (); + public static Address Address { get; } = Address.FromNumber(0x100); + + public long BaseGasCost(IReleaseSpec releaseSpec) => 3450L; + public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; + + public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) + { + if (inputData.Length != RequiredInputLength) + return (Array.Empty(), false); + + ReadOnlySpan bytes = inputData.Span; + ReadOnlySpan hash = bytes[..32], sig = bytes[32..96]; + ReadOnlySpan x = bytes[96..128], y = bytes[128..160]; + + // TODO optimize + using var ecdsa = ECDsa.Create(new ECParameters + { + Curve = ECCurve.NamedCurves.nistP256, + Q = new() { X = x.ToArray(), Y = y.ToArray() } + }); + var isValid = ecdsa.VerifyHash(hash, sig); + + Metrics.Secp256r1Precompile++; + + return (isValid ? ValidResult : InvalidResult, true); + } +} diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 7f681fdb560..9436da0fe4b 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -127,6 +127,8 @@ private static FrozenDictionary InitializePrecompiledCon [MapToG2Precompile.Address] = new(MapToG2Precompile.Instance), [PointEvaluationPrecompile.Address] = new(PointEvaluationPrecompile.Instance), + + [Secp256r1Precompile.Address] = new (Secp256r1Precompile.Instance) }.ToFrozenDictionary(); } From 8d653fc6e233296538d51466981bb7399976ce03 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 4 Jun 2024 14:28:39 +0300 Subject: [PATCH 2/8] Formatting fix --- .../Nethermind.Evm/Precompiles/Secp256r1Precompile.cs | 6 +++--- src/Nethermind/Nethermind.Evm/VirtualMachine.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs index c44bc8c312b..c462d72aea3 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only using System; @@ -10,13 +10,13 @@ namespace Nethermind.Evm.Precompiles; -public class Secp256r1Precompile: IPrecompile +public class Secp256r1Precompile : IPrecompile { private const int RequiredInputLength = 160; private static readonly byte[] ValidResult = new byte[] { 1 }.PadLeft(32); private static readonly byte[] InvalidResult = new byte[] { 0 }.PadLeft(32); - public static readonly Secp256r1Precompile Instance = new (); + public static readonly Secp256r1Precompile Instance = new(); public static Address Address { get; } = Address.FromNumber(0x100); public long BaseGasCost(IReleaseSpec releaseSpec) => 3450L; diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index 9436da0fe4b..51f4b48a40d 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -128,7 +128,7 @@ private static FrozenDictionary InitializePrecompiledCon [PointEvaluationPrecompile.Address] = new(PointEvaluationPrecompile.Instance), - [Secp256r1Precompile.Address] = new (Secp256r1Precompile.Instance) + [Secp256r1Precompile.Address] = new(Secp256r1Precompile.Instance) }.ToFrozenDictionary(); } From 2b100b7ef650f54a04e3821fd8be1f3b33868114 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Mon, 10 Jun 2024 14:53:52 +0300 Subject: [PATCH 3/8] Spec updates --- .../Nethermind.Core/Specs/IReleaseSpec.cs | 2 + .../Precompiles/AddressExtensions.cs | 52 +++++++++++-------- .../OverridableReleaseSpec.cs | 1 + .../ChainSpecStyle/ChainParameters.cs | 1 + .../ChainSpecBasedSpecProvider.cs | 1 + .../ChainSpecStyle/ChainSpecLoader.cs | 1 + .../Json/ChainSpecParamsJson.cs | 1 + .../Nethermind.Specs/Forks/18_Prague.cs | 1 + .../Nethermind.Specs/ReleaseSpec.cs | 1 + .../SystemTransactionReleaseSpec.cs | 1 + 10 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index c34e6933f53..a7564cccaec 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -279,6 +279,8 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec /// bool IsEip6780Enabled { get; } + bool IsEip7212Enabled { get; } + /// /// Should transactions be validated against chainId. /// diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs index b604eaf42c4..6a7b3e6140f 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs @@ -13,30 +13,38 @@ public static class AddressExtensions public static bool IsPrecompile(this Address address, IReleaseSpec releaseSpec) { Span data = MemoryMarshal.Cast(address.Bytes.AsSpan()); - return (data[4] & 0x00ffffff) == 0 + return (data[4] & 0x0000ffff) == 0 && data[3] == 0 && data[2] == 0 && data[1] == 0 && data[0] == 0 - && (data[4] >>> 24) switch + && ((data[4] >>> 16) & 0xff) switch { - 0x01 => true, - 0x02 => true, - 0x03 => true, - 0x04 => true, - 0x05 => releaseSpec.ModExpEnabled, - 0x06 => releaseSpec.Bn128Enabled, - 0x07 => releaseSpec.Bn128Enabled, - 0x08 => releaseSpec.Bn128Enabled, - 0x09 => releaseSpec.BlakeEnabled, - 0x0a => releaseSpec.IsEip4844Enabled, - 0x0b => releaseSpec.Bls381Enabled, - 0x0c => releaseSpec.Bls381Enabled, - 0x0d => releaseSpec.Bls381Enabled, - 0x0e => releaseSpec.Bls381Enabled, - 0x0f => releaseSpec.Bls381Enabled, - 0x10 => releaseSpec.Bls381Enabled, - 0x11 => releaseSpec.Bls381Enabled, - 0x12 => releaseSpec.Bls381Enabled, - 0x13 => releaseSpec.Bls381Enabled, - 0x100 => true, // TODO clarify if should be conditional + 0x00 => (data[4] >>> 24) switch + { + 0x01 => true, + 0x02 => true, + 0x03 => true, + 0x04 => true, + 0x05 => releaseSpec.ModExpEnabled, + 0x06 => releaseSpec.Bn128Enabled, + 0x07 => releaseSpec.Bn128Enabled, + 0x08 => releaseSpec.Bn128Enabled, + 0x09 => releaseSpec.BlakeEnabled, + 0x0a => releaseSpec.IsEip4844Enabled, + 0x0b => releaseSpec.Bls381Enabled, + 0x0c => releaseSpec.Bls381Enabled, + 0x0d => releaseSpec.Bls381Enabled, + 0x0e => releaseSpec.Bls381Enabled, + 0x0f => releaseSpec.Bls381Enabled, + 0x10 => releaseSpec.Bls381Enabled, + 0x11 => releaseSpec.Bls381Enabled, + 0x12 => releaseSpec.Bls381Enabled, + 0x13 => releaseSpec.Bls381Enabled, + _ => false + }, + 0x01 => (data[4] >>> 24) switch + { + 0x00 => releaseSpec.IsEip7212Enabled, + _ => false + }, _ => false }; } diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index f6d4bacf1a6..4358c9f50f7 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -111,6 +111,7 @@ public OverridableReleaseSpec(IReleaseSpec spec) public bool IsEip3541Enabled => _spec.IsEip3541Enabled; public bool IsEip4844Enabled => _spec.IsEip4844Enabled; + public bool IsEip7212Enabled => _spec.IsEip7212Enabled; public bool IsEip3607Enabled { get; set; } public bool IsEip158IgnoredAccount(Address address) diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 41fa983d646..21d7f603a44 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -119,6 +119,7 @@ public class ChainParameters public Address Eip4788ContractAddress { get; set; } public ulong? Eip2935TransitionTimestamp { get; set; } public Address Eip2935ContractAddress { get; set; } + public ulong? Eip7212TransitionTimestamp { get; set; } #region EIP-4844 parameters /// diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index 860e48b8814..f15978909aa 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -245,6 +245,7 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.WithdrawalTimestamp = chainSpec.Parameters.Eip4895TransitionTimestamp ?? ulong.MaxValue; releaseSpec.IsEip4844Enabled = (chainSpec.Parameters.Eip4844TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; + releaseSpec.IsEip7212Enabled = (chainSpec.Parameters.Eip7212TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.Eip4844TransitionTimestamp = chainSpec.Parameters.Eip4844TransitionTimestamp ?? ulong.MaxValue; releaseSpec.IsEip5656Enabled = (chainSpec.Parameters.Eip5656TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip6780Enabled = (chainSpec.Parameters.Eip6780TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index 769a9858633..e948a52a23c 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -141,6 +141,7 @@ bool GetForInnerPathExistence(KeyValuePair o) => Eip2537TransitionTimestamp = chainSpecJson.Params.Eip2537TransitionTimestamp, Eip5656TransitionTimestamp = chainSpecJson.Params.Eip5656TransitionTimestamp, Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp, + Eip7212TransitionTimestamp = chainSpecJson.Params.Eip7212TransitionTimestamp, Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp, Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress, Eip2935TransitionTimestamp = chainSpecJson.Params.Eip2935TransitionTimestamp, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index 283f755d9f0..527f520b611 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -147,4 +147,5 @@ internal class ChainSpecParamsJson public ulong? Eip4844MaxBlobGasPerBlock { get; set; } public UInt256? Eip4844MinBlobGasPrice { get; set; } public ulong? Eip4844TargetBlobGasPerBlock { get; set; } + public ulong? Eip7212TransitionTimestamp { get; set; } } diff --git a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs index 11036fa0946..04296fb1d58 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs @@ -16,6 +16,7 @@ protected Prague() Name = "Prague"; IsEip2537Enabled = true; IsEip2935Enabled = true; + IsEip7212Enabled = true; Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress; } diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index c3615a05a13..490351e507a 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -80,6 +80,7 @@ public ReleaseSpec Clone() public bool IsEip3860Enabled { get; set; } public bool IsEip4895Enabled { get; set; } public bool IsEip4844Enabled { get; set; } + public bool IsEip7212Enabled { get; set; } public bool IsEip5656Enabled { get; set; } public bool IsEip6780Enabled { get; set; } public bool IsEip4788Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index cc9f87ffa7a..34dd79db8bc 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -16,6 +16,7 @@ public SystemTransactionReleaseSpec(IReleaseSpec spec) _spec = spec; } public bool IsEip4844Enabled => _spec.IsEip4844Enabled; + public bool IsEip7212Enabled => _spec.IsEip7212Enabled; public string Name => "System"; From 3f099b697a5d22dac691dde1406ff36868fd416f Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 11 Jun 2024 18:50:23 +0300 Subject: [PATCH 4/8] Fix missing precompile --- src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs index 48b67ddd52d..57eb47d499d 100644 --- a/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs +++ b/src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs @@ -89,6 +89,8 @@ private static FrozenDictionary InitializePrecompiledCon [MapToG2Precompile.Address] = new(MapToG2Precompile.Instance), [PointEvaluationPrecompile.Address] = new(PointEvaluationPrecompile.Instance), + + [Secp256r1Precompile.Address] = new(Secp256r1Precompile.Instance), }.ToFrozenDictionary(); } From 1dc5ccc234d95df47fe2a49033c43e6c7aecb207 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 11 Jun 2024 22:32:42 +0300 Subject: [PATCH 5/8] Update precompile implementation --- .../Precompiles/Secp256r1Precompile.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs index c462d72aea3..ed00e14a789 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; -using System.Buffers; using System.Security.Cryptography; using Nethermind.Core; using Nethermind.Core.Extensions; @@ -12,9 +11,7 @@ namespace Nethermind.Evm.Precompiles; public class Secp256r1Precompile : IPrecompile { - private const int RequiredInputLength = 160; private static readonly byte[] ValidResult = new byte[] { 1 }.PadLeft(32); - private static readonly byte[] InvalidResult = new byte[] { 0 }.PadLeft(32); public static readonly Secp256r1Precompile Instance = new(); public static Address Address { get; } = Address.FromNumber(0x100); @@ -22,16 +19,18 @@ public class Secp256r1Precompile : IPrecompile public long BaseGasCost(IReleaseSpec releaseSpec) => 3450L; public long DataGasCost(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) => 0L; + // TODO can be optimized - Go implementation is 2-6 times faster depending on the platform. Options: + // - Try to replicate Go version in C# + // - Compile Go code into a library and call it via P/Invoke public (ReadOnlyMemory, bool) Run(in ReadOnlyMemory inputData, IReleaseSpec releaseSpec) { - if (inputData.Length != RequiredInputLength) - return (Array.Empty(), false); + if (inputData.Length != 160) + return (null, true); ReadOnlySpan bytes = inputData.Span; ReadOnlySpan hash = bytes[..32], sig = bytes[32..96]; ReadOnlySpan x = bytes[96..128], y = bytes[128..160]; - // TODO optimize using var ecdsa = ECDsa.Create(new ECParameters { Curve = ECCurve.NamedCurves.nistP256, @@ -41,6 +40,6 @@ public class Secp256r1Precompile : IPrecompile Metrics.Secp256r1Precompile++; - return (isValid ? ValidResult : InvalidResult, true); + return (isValid ? ValidResult : null, true); } } From 9830ab38d3720d2158e6b6d4c2e5b622f57f54f7 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 11 Jun 2024 22:32:54 +0300 Subject: [PATCH 6/8] Update and fix tests --- .../Secp256r1PrecompilePrecompileTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs index 0e759da167e..4ab96c72984 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs @@ -17,10 +17,6 @@ public class Secp256r1PrecompilePrecompileTests : VirtualMachineTestsBase "0000000000000000000000000000000000000000000000000000000000000001" ); - private static readonly byte[] InvalidAnswer = Bytes.FromHexString( - "0000000000000000000000000000000000000000000000000000000000000000" - ); - [Test] // https://github.com/paradigmxyz/alphanet/blob/main/crates/precompile/src/secp256r1.rs#L137 [TestCase( "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", @@ -67,21 +63,25 @@ public void Produces_Correct_Outputs(string input, bool isValid) var bytes = Bytes.FromHexString(input); (ReadOnlyMemory output, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance); success.Should().BeTrue(); - output.ToArray().Should().BeEquivalentTo(isValid ? ValidAnswer : InvalidAnswer); + output.ToArray().Should().BeEquivalentTo(isValid ? ValidAnswer : []); } [Test] + [TestCase( + "" + )] [TestCase( "4cee90eb86eaa050036147a12d49004b6a" )] [TestCase( "4cee90eb86eaa050036147a12d49004b6a958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf319" )] - public void Fails_On_Incorrect_Input(string input) + public void Produces_Empty_Output_On_Invalid_Input(string input) { var bytes = Bytes.FromHexString(input); - (ReadOnlyMemory _, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance); - success.Should().BeFalse(); + (ReadOnlyMemory output, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance); + success.Should().BeTrue(); + output.Should().Be(ReadOnlyMemory.Empty); } } } From 23b58928797f691bb44679b84d3b4c958aa6f405 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Tue, 11 Jun 2024 22:57:32 +0300 Subject: [PATCH 7/8] Rename EIP7212 -> RIP7212 --- src/Nethermind/Chains/op-sepolia.json | 2 +- src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs | 5 ++++- .../Nethermind.Evm/Precompiles/AddressExtensions.cs | 2 +- .../Nethermind.Specs.Test/OverridableReleaseSpec.cs | 2 +- .../Nethermind.Specs/ChainSpecStyle/ChainParameters.cs | 2 +- .../ChainSpecStyle/ChainSpecBasedSpecProvider.cs | 2 +- .../Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs | 2 +- .../ChainSpecStyle/Json/ChainSpecParamsJson.cs | 2 +- src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs | 2 +- src/Nethermind/Nethermind.Specs/ReleaseSpec.cs | 2 +- .../Nethermind.Specs/SystemTransactionReleaseSpec.cs | 2 +- 11 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Nethermind/Chains/op-sepolia.json b/src/Nethermind/Chains/op-sepolia.json index f90ba4e5a25..ab7158b1261 100644 --- a/src/Nethermind/Chains/op-sepolia.json +++ b/src/Nethermind/Chains/op-sepolia.json @@ -61,7 +61,7 @@ "eip4844TransitionTimestamp": "0x65D62C10", "eip5656TransitionTimestamp": "0x65D62C10", "eip6780TransitionTimestamp": "0x65D62C10", - "eip7212TransitionTimestamp": "0x66575100", + "rip7212TransitionTimestamp": "0x66575100", "terminalTotalDifficulty": "0" }, "genesis": { diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs index a7564cccaec..de7e33ea06d 100644 --- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs @@ -279,7 +279,10 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec /// bool IsEip6780Enabled { get; } - bool IsEip7212Enabled { get; } + /// + /// Secp256r1 precompile + /// + bool IsRip7212Enabled { get; } /// /// Should transactions be validated against chainId. diff --git a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs index 6a7b3e6140f..11ba1f00ae5 100644 --- a/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs +++ b/src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs @@ -42,7 +42,7 @@ public static bool IsPrecompile(this Address address, IReleaseSpec releaseSpec) }, 0x01 => (data[4] >>> 24) switch { - 0x00 => releaseSpec.IsEip7212Enabled, + 0x00 => releaseSpec.IsRip7212Enabled, _ => false }, _ => false diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs index 4358c9f50f7..5ed238c70b8 100644 --- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs @@ -111,7 +111,7 @@ public OverridableReleaseSpec(IReleaseSpec spec) public bool IsEip3541Enabled => _spec.IsEip3541Enabled; public bool IsEip4844Enabled => _spec.IsEip4844Enabled; - public bool IsEip7212Enabled => _spec.IsEip7212Enabled; + public bool IsRip7212Enabled => _spec.IsRip7212Enabled; public bool IsEip3607Enabled { get; set; } public bool IsEip158IgnoredAccount(Address address) diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs index 21d7f603a44..d3f5c970570 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs @@ -119,7 +119,7 @@ public class ChainParameters public Address Eip4788ContractAddress { get; set; } public ulong? Eip2935TransitionTimestamp { get; set; } public Address Eip2935ContractAddress { get; set; } - public ulong? Eip7212TransitionTimestamp { get; set; } + public ulong? Rip7212TransitionTimestamp { get; set; } #region EIP-4844 parameters /// diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs index f15978909aa..d0b3805a52f 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecBasedSpecProvider.cs @@ -245,7 +245,7 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt releaseSpec.WithdrawalTimestamp = chainSpec.Parameters.Eip4895TransitionTimestamp ?? ulong.MaxValue; releaseSpec.IsEip4844Enabled = (chainSpec.Parameters.Eip4844TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; - releaseSpec.IsEip7212Enabled = (chainSpec.Parameters.Eip7212TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; + releaseSpec.IsRip7212Enabled = (chainSpec.Parameters.Rip7212TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.Eip4844TransitionTimestamp = chainSpec.Parameters.Eip4844TransitionTimestamp ?? ulong.MaxValue; releaseSpec.IsEip5656Enabled = (chainSpec.Parameters.Eip5656TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; releaseSpec.IsEip6780Enabled = (chainSpec.Parameters.Eip6780TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp; diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs index e948a52a23c..068c4d19365 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs @@ -141,7 +141,7 @@ bool GetForInnerPathExistence(KeyValuePair o) => Eip2537TransitionTimestamp = chainSpecJson.Params.Eip2537TransitionTimestamp, Eip5656TransitionTimestamp = chainSpecJson.Params.Eip5656TransitionTimestamp, Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp, - Eip7212TransitionTimestamp = chainSpecJson.Params.Eip7212TransitionTimestamp, + Rip7212TransitionTimestamp = chainSpecJson.Params.Rip7212TransitionTimestamp, Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp, Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress, Eip2935TransitionTimestamp = chainSpecJson.Params.Eip2935TransitionTimestamp, diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs index 527f520b611..499022ca0c6 100644 --- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs +++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs @@ -147,5 +147,5 @@ internal class ChainSpecParamsJson public ulong? Eip4844MaxBlobGasPerBlock { get; set; } public UInt256? Eip4844MinBlobGasPrice { get; set; } public ulong? Eip4844TargetBlobGasPerBlock { get; set; } - public ulong? Eip7212TransitionTimestamp { get; set; } + public ulong? Rip7212TransitionTimestamp { get; set; } } diff --git a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs index 04296fb1d58..928e61cc372 100644 --- a/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs +++ b/src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs @@ -16,7 +16,7 @@ protected Prague() Name = "Prague"; IsEip2537Enabled = true; IsEip2935Enabled = true; - IsEip7212Enabled = true; + IsRip7212Enabled = true; Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress; } diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs index 490351e507a..67cdfdd7a14 100644 --- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs @@ -80,7 +80,7 @@ public ReleaseSpec Clone() public bool IsEip3860Enabled { get; set; } public bool IsEip4895Enabled { get; set; } public bool IsEip4844Enabled { get; set; } - public bool IsEip7212Enabled { get; set; } + public bool IsRip7212Enabled { get; set; } public bool IsEip5656Enabled { get; set; } public bool IsEip6780Enabled { get; set; } public bool IsEip4788Enabled { get; set; } diff --git a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs index 34dd79db8bc..9ab42d14e21 100644 --- a/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs +++ b/src/Nethermind/Nethermind.Specs/SystemTransactionReleaseSpec.cs @@ -16,7 +16,7 @@ public SystemTransactionReleaseSpec(IReleaseSpec spec) _spec = spec; } public bool IsEip4844Enabled => _spec.IsEip4844Enabled; - public bool IsEip7212Enabled => _spec.IsEip7212Enabled; + public bool IsRip7212Enabled => _spec.IsRip7212Enabled; public string Name => "System"; From 833c90390c0bfa66da5364e41331db944fdad5d3 Mon Sep 17 00:00:00 2001 From: Alex Bespalov Date: Wed, 12 Jun 2024 04:12:27 +0300 Subject: [PATCH 8/8] File header year fix --- .../Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs index 4ab96c72984..b123d2074b9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Secp256r1PrecompilePrecompileTests.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only using System;