Skip to content

Commit

Permalink
EIP/RIP-7212 (#7135)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexb5dh authored Jun 13, 2024
1 parent 7935979 commit 57a24e9
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 22 deletions.
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 @@ -91,6 +91,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);

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);
}
}
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

0 comments on commit 57a24e9

Please sign in to comment.