Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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);
Comment thread
alexb5dh marked this conversation as 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);
Comment thread
alexb5dh marked this conversation as 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