diff --git a/crypto/ecrecover_nocgo.go b/crypto/ecrecover_nocgo.go
new file mode 100644
index 0000000000..6d62de529e
--- /dev/null
+++ b/crypto/ecrecover_nocgo.go
@@ -0,0 +1,29 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+//go:build (nacl || wasm || wasip1 || !cgo || gofuzz) && !sp1
+
+package crypto
+
+// Ecrecover returns the uncompressed public key that created the given signature.
+func Ecrecover(hash, sig []byte) ([]byte, error) {
+ pub, err := sigToPub(hash, sig)
+ if err != nil {
+ return nil, err
+ }
+ bytes := pub.SerializeUncompressed()
+ return bytes, err
+}
diff --git a/crypto/ecrecover_nocgo_sp1.go b/crypto/ecrecover_nocgo_sp1.go
new file mode 100644
index 0000000000..8220f60d49
--- /dev/null
+++ b/crypto/ecrecover_nocgo_sp1.go
@@ -0,0 +1,39 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+//go:build wasm && sp1
+
+package crypto
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+// Ecrecover implementation using SP1 precompile
+
+//go:wasmimport sp1 ecrecover
+func innerEcrecover(hash, sig, output unsafe.Pointer) uint32
+
+// Ecrecover returns the uncompressed public key that created the given signature.
+func Ecrecover(hash, sig []byte) ([]byte, error) {
+ pub := make([]byte, 65)
+ ret := innerEcrecover(unsafe.Pointer(&hash[0]), unsafe.Pointer(&sig[0]), unsafe.Pointer(&pub[0]))
+ if ret != 0 {
+ return nil, fmt.Errorf("recovery failed with code: %d", ret)
+ }
+ return pub, nil
+}
diff --git a/crypto/keccak.go b/crypto/keccak.go
index 0ad79a63c1..b1030b8b81 100644
--- a/crypto/keccak.go
+++ b/crypto/keccak.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-//go:build !ziren
+//go:build !ziren && !sp1
package crypto
diff --git a/crypto/keccak_sp1.go b/crypto/keccak_sp1.go
new file mode 100644
index 0000000000..99d3853243
--- /dev/null
+++ b/crypto/keccak_sp1.go
@@ -0,0 +1,108 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+//
+//go:build sp1
+
+package crypto
+
+import (
+ "unsafe"
+
+ "github.com/ethereum/go-ethereum/common"
+)
+
+// Keccak implementation using SP1 precompile
+
+//go:wasmimport sp1 keccak256
+func doKeccak256(data unsafe.Pointer, dataLength uint32, output unsafe.Pointer)
+
+const (
+ rateK512 = (1600 - 512) / 8
+ rateK1024 = (1600 - 1024) / 8
+)
+
+type precompileKeccak256State struct {
+ d []byte
+}
+
+func (d *precompileKeccak256State) BlockSize() int { return rateK512 }
+
+func (d *precompileKeccak256State) Size() int { return 32 }
+
+func (d *precompileKeccak256State) Reset() {
+ d.d = nil
+}
+
+func (d *precompileKeccak256State) Read(out []byte) (n int, err error) {
+ output := make([]byte, 32)
+ input := unsafe.Pointer(uintptr(0))
+ if (len(d.d) > 0) {
+ input = unsafe.Pointer(&d.d[0])
+ }
+ doKeccak256(input, uint32(len(d.d)), unsafe.Pointer(&output[0]))
+ n = copy(out, output)
+ return
+}
+
+func (d *precompileKeccak256State) Sum(in []byte) []byte {
+ hash := make([]byte, 32)
+ d.Read(hash)
+ return append(in, hash...)
+}
+
+// NOTE: different from a native go implementation, here our precompile-based
+// hasher simply gathers the preimage data to a slice in the `Write` function.
+// The actual hashing work is done inside `Read` function, where all the gathered
+// input data are passed to the precompile function all together.
+// This might not be an optimal solution when the preimage data can be quite
+// big. But it provides a good tradeoff, since we don't need to keep Rust data
+// structure inside a go struct across FFI boundaries. If this implementation
+// really turns out to be a problem, we could revisit this design again.
+func (d *precompileKeccak256State) Write(p []byte) (n int, err error) {
+ n = len(p)
+ d.d = append(d.d, p...)
+ return
+}
+
+func (d *precompileKeccak256State) clone() *precompileKeccak256State {
+ ret := *d
+ return &ret
+}
+
+func NewKeccakState() KeccakState {
+ return &precompileKeccak256State{ d: nil }
+}
+
+func Keccak256(data ...[]byte) []byte {
+ b := make([]byte, 32)
+ d := NewKeccakState()
+ d.Reset()
+ for _, b := range data {
+ d.Write(b)
+ }
+ d.Read(b)
+ return b
+}
+
+func Keccak256Hash(data ...[]byte) (h common.Hash) {
+ d := NewKeccakState()
+ d.Reset()
+ for _, b := range data {
+ d.Write(b)
+ }
+ d.Read(h[:])
+ return h
+}
diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go
index 1686b1148b..7997a23ff1 100644
--- a/crypto/signature_nocgo.go
+++ b/crypto/signature_nocgo.go
@@ -29,16 +29,6 @@ import (
decred_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
)
-// Ecrecover returns the uncompressed public key that created the given signature.
-func Ecrecover(hash, sig []byte) ([]byte, error) {
- pub, err := sigToPub(hash, sig)
- if err != nil {
- return nil, err
- }
- bytes := pub.SerializeUncompressed()
- return bytes, err
-}
-
func sigToPub(hash, sig []byte) (*secp256k1.PublicKey, error) {
if len(sig) != SignatureLength {
return nil, errors.New("invalid signature")