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")