From bb860728a861e099ad3b73ac5eda359c57a897a8 Mon Sep 17 00:00:00 2001 From: thanhpp Date: Thu, 21 Mar 2024 14:48:48 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20eth:=20RecoverSignerAddress?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: thanhpp --- go.mod | 1 + go.sum | 2 ++ pkg/eth/recover.go | 44 +++++++++++++++++++++++++++++++++++++++++ pkg/eth/recover_test.go | 18 +++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 pkg/eth/recover.go create mode 100644 pkg/eth/recover_test.go diff --git a/go.mod b/go.mod index 561ddba..6f540a2 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/sourcegraph/conc v0.3.0 github.com/stretchr/testify v1.8.4 + github.com/test-go/testify v1.1.4 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa ) diff --git a/go.sum b/go.sum index 2ca42f9..3d4c504 100644 --- a/go.sum +++ b/go.sum @@ -208,6 +208,8 @@ github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbe github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU= github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= diff --git a/pkg/eth/recover.go b/pkg/eth/recover.go new file mode 100644 index 0000000..7e61a4f --- /dev/null +++ b/pkg/eth/recover.go @@ -0,0 +1,44 @@ +package eth + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" +) + +const signatureLength = 65 + +func RecoverSignerAddress(hexEncodedHash string, hexEncodedSignature string) (common.Address, error) { + hash, err := hexutil.Decode(hexEncodedHash) + if err != nil { + return common.Address{}, fmt.Errorf("decode hash error: %w", err) + } + + signature, err := hexutil.Decode(hexEncodedSignature) + if err != nil { + return common.Address{}, fmt.Errorf("decode signature error: %w", err) + } + + // Signature in Ethereum consists of R, S, V; the V is at last byte, R and S are the rest. + // The standard Ethereum signature is 65 bytes (R: 32 bytes, S: 32 bytes, V: 1 byte). + // Ensure the signature is 65 bytes and split it into R, S, and V components. + if len(signature) != signatureLength { + return common.Address{}, fmt.Errorf("invalid signature length, expect: %d, got: %v", signatureLength, len(signature)) + } + + // Ethereum uses a 'recovery id' for V, but go-ethereum expects V to be 27 or 28. + signature[64] -= 27 + + // Recover the public key from the signature + pubKey, err := crypto.SigToPub(hash, signature) + if err != nil { + return common.Address{}, fmt.Errorf("signature to public key error: %w", err) + } + + // Derive the Ethereum address from the public key + address := crypto.PubkeyToAddress(*pubKey) + + return address, nil +} diff --git a/pkg/eth/recover_test.go b/pkg/eth/recover_test.go new file mode 100644 index 0000000..d311a14 --- /dev/null +++ b/pkg/eth/recover_test.go @@ -0,0 +1,18 @@ +package eth_test + +import ( + "testing" + + "github.com/KyberNetwork/tradinglib/pkg/eth" + "github.com/test-go/testify/require" +) + +func TestRecover(t *testing.T) { + hashHex := "0xef6777697377372751e5daa1772d3b2b03f6f50b85dd3d7a79b4f12381897ec8" + signatureHex := "0xf89e6165aa337b8ebf74effa1a2b0980cc54e3780af077337b12438f30c901ab69ad655518007bd15073c919780ac61d3a4d5918c8966ffdb07256776ca6223f1c" // nolint: lll + + addr, err := eth.RecoverSignerAddress(hashHex, signatureHex) + require.NoError(t, err) + + t.Log(addr.String()) +}