Skip to content

Commit

Permalink
Test initial approach
Browse files Browse the repository at this point in the history
  • Loading branch information
alexb5dh committed Feb 28, 2025
1 parent 0fe8beb commit c89db92
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Collections.Generic;
using FluentAssertions;
using Nethermind.Core.Extensions;
using Nethermind.Evm.Precompiles;
using Nethermind.Specs.Forks;
Expand Down
24 changes: 24 additions & 0 deletions src/Nethermind/Nethermind.Evm/Binaries/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"C"
"crypto/ecdsa"
"crypto/elliptic"
"math/big"
)

//export VerifyBytes
func VerifyBytes(bytes []byte) bool {
if len(bytes) != 160 {
return false
}

var hash = bytes[0:32]
var r, s = new(big.Int).SetBytes(bytes[32:64]), new(big.Int).SetBytes(bytes[64:96])
var x, y = new(big.Int).SetBytes(bytes[96:128]), new(big.Int).SetBytes(bytes[128:160])
var publicKey = &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}

return ecdsa.Verify(publicKey, hash, r, s)
}

func main() {}
Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,11 @@
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
<None Update="Binaries\secp256r1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Binaries\secp256r1.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
34 changes: 15 additions & 19 deletions src/Nethermind/Nethermind.Evm/Precompiles/Secp256r1Precompile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
// SPDX-License-Identifier: LGPL-3.0-only

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

namespace Nethermind.Evm.Precompiles;

public class Secp256r1Precompile : IPrecompile<Secp256r1Precompile>
public partial class Secp256r1Precompile : IPrecompile<Secp256r1Precompile>
{
private readonly struct GoSlice(nint data, long len)
{
public readonly nint Data = data;
public readonly long Len = len, Cap = len;
}

private static readonly byte[] ValidResult = new byte[] { 1 }.PadLeft(32);

public static readonly Secp256r1Precompile Instance = new();
Expand All @@ -19,24 +25,14 @@ public class Secp256r1Precompile : IPrecompile<Secp256r1Precompile>
public long BaseGasCost(IReleaseSpec releaseSpec) => 3450L;
public long DataGasCost(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 (byte[], bool) Run(ReadOnlyMemory<byte> inputData, IReleaseSpec releaseSpec)
[LibraryImport("Binaries/secp256r1", SetLastError = true)]
private static partial byte VerifyBytes(GoSlice hash);

public unsafe (byte[], bool) Run(ReadOnlyMemory<byte> input, 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);
using var pin = input.Pin();
GoSlice slice = new((nint)pin.Pointer, input.Length);
var isValid = VerifyBytes(slice) != 0;

Metrics.Secp256r1Precompile++;

Expand Down

0 comments on commit c89db92

Please sign in to comment.