Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP/RIP-7212 #7135

Merged
merged 10 commits into from
Jun 13, 2024
Merged
2 changes: 1 addition & 1 deletion src/Nethermind/Chains/op-sepolia.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"eip4844TransitionTimestamp": "0x65D62C10",
"eip5656TransitionTimestamp": "0x65D62C10",
"eip6780TransitionTimestamp": "0x65D62C10",
"eip7212TransitionTimestamp": "0x66575100",
"rip7212TransitionTimestamp": "0x66575100",
"terminalTotalDifficulty": "0"
},
"genesis": {
Expand Down
5 changes: 5 additions & 0 deletions src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
/// </summary>
bool IsEip6780Enabled { get; }

/// <summary>
/// Secp256r1 precompile
/// </summary>
bool IsRip7212Enabled { get; }

/// <summary>
/// Should transactions be validated against chainId.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2024 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"
);

[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<byte> output, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance);
success.Should().BeTrue();
output.ToArray().Should().BeEquivalentTo(isValid ? ValidAnswer : []);
}

[Test]
[TestCase(
""
)]
[TestCase(
"4cee90eb86eaa050036147a12d49004b6a"
)]
[TestCase(
"4cee90eb86eaa050036147a12d49004b6a958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf319"
)]
public void Produces_Empty_Output_On_Invalid_Input(string input)
{
var bytes = Bytes.FromHexString(input);
(ReadOnlyMemory<byte> output, bool success) = Secp256r1Precompile.Instance.Run(bytes, Prague.Instance);
success.Should().BeTrue();
output.Should().Be(ReadOnlyMemory<byte>.Empty);
}
}
}
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Evm/CodeInfoRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ private static FrozenDictionary<AddressAsKey, CodeInfo> InitializePrecompiledCon
[MapToG2Precompile.Address] = new(MapToG2Precompile.Instance),

[PointEvaluationPrecompile.Address] = new(PointEvaluationPrecompile.Instance),

[Secp256r1Precompile.Address] = new(Secp256r1Precompile.Instance),
}.ToFrozenDictionary();
}

Expand Down
3 changes: 3 additions & 0 deletions src/Nethermind/Nethermind.Evm/Metrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
51 changes: 30 additions & 21 deletions src/Nethermind/Nethermind.Evm/Precompiles/AddressExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,38 @@ public static class AddressExtensions
public static bool IsPrecompile(this Address address, IReleaseSpec releaseSpec)
{
Span<uint> data = MemoryMarshal.Cast<byte, uint>(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,
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.IsRip7212Enabled,
_ => false
},
_ => false
};
}
Expand Down
45 changes: 45 additions & 0 deletions src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Security.Cryptography;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;

namespace Nethermind.Evm.Precompiles;

public class Secp256r1Precompile : IPrecompile<Secp256r1Precompile>
{
private static readonly byte[] ValidResult = new byte[] { 1 }.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<byte> 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<byte>, bool) Run(in ReadOnlyMemory<byte> inputData, IReleaseSpec releaseSpec)
{
if (inputData.Length != 160)
return (null, true);
alexb5dh marked this conversation as resolved.
Show resolved Hide resolved

ReadOnlySpan<byte> bytes = inputData.Span;
ReadOnlySpan<byte> hash = bytes[..32], sig = bytes[32..96];
ReadOnlySpan<byte> x = bytes[96..128], y = bytes[128..160];

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 : null, true);
alexb5dh marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public OverridableReleaseSpec(IReleaseSpec spec)

public bool IsEip3541Enabled => _spec.IsEip3541Enabled;
public bool IsEip4844Enabled => _spec.IsEip4844Enabled;
public bool IsRip7212Enabled => _spec.IsRip7212Enabled;
public bool IsEip3607Enabled { get; set; }

public bool IsEip158IgnoredAccount(Address address)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public class ChainParameters
public Address Eip4788ContractAddress { get; set; }
public ulong? Eip2935TransitionTimestamp { get; set; }
public Address Eip2935ContractAddress { get; set; }
public ulong? Rip7212TransitionTimestamp { get; set; }

#region EIP-4844 parameters
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ bool GetForInnerPathExistence(KeyValuePair<string, JsonElement> o) =>
Eip2537TransitionTimestamp = chainSpecJson.Params.Eip2537TransitionTimestamp,
Eip5656TransitionTimestamp = chainSpecJson.Params.Eip5656TransitionTimestamp,
Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp,
Rip7212TransitionTimestamp = chainSpecJson.Params.Rip7212TransitionTimestamp,
Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp,
Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress,
Eip2935TransitionTimestamp = chainSpecJson.Params.Eip2935TransitionTimestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,5 @@ internal class ChainSpecParamsJson
public ulong? Eip4844MaxBlobGasPerBlock { get; set; }
public UInt256? Eip4844MinBlobGasPrice { get; set; }
public ulong? Eip4844TargetBlobGasPerBlock { get; set; }
public ulong? Rip7212TransitionTimestamp { get; set; }
}
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Specs/Forks/18_Prague.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ protected Prague()
Name = "Prague";
IsEip2537Enabled = true;
IsEip2935Enabled = true;
IsRip7212Enabled = true;
Eip2935ContractAddress = Eip2935Constants.BlockHashHistoryAddress;
}

Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Specs/ReleaseSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public ReleaseSpec Clone()
public bool IsEip3860Enabled { get; set; }
public bool IsEip4895Enabled { get; set; }
public bool IsEip4844Enabled { get; set; }
public bool IsRip7212Enabled { get; set; }
public bool IsEip5656Enabled { get; set; }
public bool IsEip6780Enabled { get; set; }
public bool IsEip4788Enabled { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public SystemTransactionReleaseSpec(IReleaseSpec spec)
_spec = spec;
}
public bool IsEip4844Enabled => _spec.IsEip4844Enabled;
public bool IsRip7212Enabled => _spec.IsRip7212Enabled;

public string Name => "System";

Expand Down