Skip to content

Instantly share code, notes, and snippets.

@dcb9
Last active December 17, 2025 09:36
Show Gist options
  • Select an option

  • Save dcb9/385631846097e1f59e3cba3b1d42f3ed to your computer and use it in GitHub Desktop.

Select an option

Save dcb9/385631846097e1f59e3cba3b1d42f3ed to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
func main() {
fmt.Println(verifySig(
"0x0EaE3eF6CC7176553E6B45d94e9eFDE2Da7B82a5",
"0x34850b7e36e635783df0563c7202c3ac776df59db5015d2b6f0add33955bb5c43ce35efb5ce695a243bc4c5dc4298db40cd765f3ea5612d2d57da1e4933b2f201b",
[]byte("Example `personal_sign` message"),
))
}
func verifySig(from, sigHex string, msg []byte) bool {
sig := hexutil.MustDecode(sigHex)
msg = accounts.TextHash(msg)
if sig[crypto.RecoveryIDOffset] == 27 || sig[crypto.RecoveryIDOffset] == 28 {
sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
}
recovered, err := crypto.SigToPub(msg, sig)
if err != nil {
return false
}
recoveredAddr := crypto.PubkeyToAddress(*recovered)
return from == recoveredAddr.Hex()
}
@kabaluyot
Copy link
Copy Markdown

works like a charm

@delaneyj
Copy link
Copy Markdown

This is godsend!

@0xRampey
Copy link
Copy Markdown

0xRampey commented Aug 2, 2021

Saved me from more head-breaking. Thank you!

@phuwn
Copy link
Copy Markdown

phuwn commented Nov 4, 2021

Thank you. geth should use this as an example

@benhenryhunter
Copy link
Copy Markdown

4 years later this is saving lives.

@jackcpku
Copy link
Copy Markdown

Worked. Thanks man!

@rht
Copy link
Copy Markdown

rht commented Feb 22, 2022

Hello internet. Make sure to read the latest version of func (s *PrivateAccountAPI) EcRecover at https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go.
Notable changes are:

  • The 64 is replaced with crypto.RecoveryIDOffset
  • signHash is replaced with accounts.TextHash

Maybe @dcb9 should update this gist.

@9cat
Copy link
Copy Markdown

9cat commented Mar 17, 2022

it works, really thanks

@krasi-georgiev
Copy link
Copy Markdown

krasi-georgiev commented Mar 22, 2022

simplified version

package main

import (
	"fmt"

	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
)

func main() {
	fmt.Println(verifySig(
		"0x0EaE3eF6CC7176553E6B45d94e9eFDE2Da7B82a5",
		"0x34850b7e36e635783df0563c7202c3ac776df59db5015d2b6f0add33955bb5c43ce35efb5ce695a243bc4c5dc4298db40cd765f3ea5612d2d57da1e4933b2f201b",
		[]byte("Example `personal_sign` message"),
	))
}

func verifySig(from, sigHex string, msg []byte) bool {
	sig := hexutil.MustDecode(sigHex)

	msg = accounts.TextHash(msg)
	sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1

	recovered, err := crypto.SigToPub(msg, sig)
	if err != nil {
		return false
	}

	recoveredAddr := crypto.PubkeyToAddress(*recovered)

	return from == recoveredAddr.Hex()
}

@dcb9
Copy link
Copy Markdown
Author

dcb9 commented Mar 23, 2022

@krasi-georgiev Perfect I copied yours as the latest version
@rht Thanks you so much

@RyoJerryYu
Copy link
Copy Markdown

It works! Thanks!

@xx444812313
Copy link
Copy Markdown

Good! helped me a lot!

@chbill8
Copy link
Copy Markdown

chbill8 commented Aug 24, 2022

Do you have any examples on generating the signature?

@letroglodyte
Copy link
Copy Markdown

Helped a lot cheers !

@bertho-zero
Copy link
Copy Markdown

Works fine but I need to replace

	sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1

with

	if sig[crypto.RecoveryIDOffset] == 27 || sig[crypto.RecoveryIDOffset] == 28 {
		sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
	}

@darshantejani007
Copy link
Copy Markdown

Amazing! Worked on the first go!

@quiet-node
Copy link
Copy Markdown

quiet-node commented Nov 14, 2022

OMG You're the absolute life saver! Thanks a lot! Spent up all night long but couldn't find the right answer until seeing this post!

@psmithson
Copy link
Copy Markdown

In our case, the last line had a bug, in which it needs the address to be lower cased, otherwise the comparison fails. Fix this bug lowering the case of the right parameter, like this:

return from == strings.ToLower(recoveredAddress.Hex())

@memochou1993
Copy link
Copy Markdown

@NFEL
Copy link
Copy Markdown

NFEL commented May 12, 2023

@psmithson
in that case you should use something like

return strings.ToLower(from) == strings.ToLower(recoveredAddress.Hex())

@al-maisan
Copy link
Copy Markdown

@psmithson in that case you should use something like

return strings.ToLower(from) == strings.ToLower(recoveredAddress.Hex())

or even better

return strings.EqualFold(from, recoveredAddr.Hex())

@Spillage
Copy link
Copy Markdown

Spillage commented Nov 6, 2023

Very helpful!

@al-maisan
Copy link
Copy Markdown

@valterlobo
Copy link
Copy Markdown

valterlobo commented Apr 3, 2024

Sign in with Ethereum - frontend
https://docs.metamask.io/wallet/how-to/sign-data/siwe/

Signature checker in backend with go-ethereum with this code.

@dcb9
Copy link
Copy Markdown
Author

dcb9 commented Apr 4, 2024

@valterlobo Very useful, thanks for sharing

@umiiii
Copy link
Copy Markdown

umiiii commented Sep 7, 2025

Thanks for your solution!!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment