2

I have used the following code to generate an ecdsa key-pair(privKey and pubKey), encode them and then decode them back: https://stackoverflow.com/a/41315404/1901320.

Next I create a hash for a message (txnData.Payload() is of type []byte) using crypto.Keccak256() and sign it using crypto.Sign() from Ethereum's crypto package (github.com/ethereum/go-ethereum/crypto). This creates a 65 bit ECDSA signature in R || S || V format.

    hashData := crypto.Keccak256(txnData.Payload)
    sig, _ := crypto.Sign(hashData, privKey)

    pkey, _ := crypto.Ecrecover(hashData, sig) // This and pubKey do not match

When I try to get back the public key from the hashData and the ECDSA signature using crypto.Ecrecover() and compare it with the public key pubKey corresponding to the privKey used to create the signature, I find that the public keys do not match. This doesn't seem like something that should happen. Any idea as to where I am going wrong with this?

1 Answers1

4

Here's a complete working example of how to generate and verify signatures using go-ethereum.

package main

import (
    "bytes"
    "crypto/ecdsa"
    "fmt"
    "log"

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

func main() {
    privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
    if err != nil {
        log.Fatal(err)
    }

    publicKey := privateKey.PublicKey

    publicKeyBytes := crypto.FromECDSAPub(&publicKey)

    data := []byte("hello")
    hash := crypto.Keccak256Hash(data)
    fmt.Println(hash.Hex()) // 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8

    signature, err := crypto.Sign(hash.Bytes(), privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(hexutil.Encode(signature)) // 0x789a80053e4927d0a898db8e065e948f5cf086e32f9ccaa54c1908e22ac430c62621578113ddbb62d509bf6049b8fb544ab06d36f916685a2eb8e57ffadde02301

    sigPublicKey, err := crypto.Ecrecover(hash.Bytes(), signature)
    if err != nil {
        log.Fatal(err)
    }

    matches := bytes.Equal(sigPublicKey, publicKeyBytes)
    fmt.Println(matches) // true

    sigPublicKeyECDSA, err := crypto.SigToPub(hash.Bytes(), signature)
    if err != nil {
        log.Fatal(err)
    }

    sigPublicKeyBytes := crypto.FromECDSAPub(sigPublicKeyECDSA)
    matches = bytes.Equal(sigPublicKeyBytes, publicKeyBytes)
    fmt.Println(matches) // true

    signatureNoRecoverID := signature[:len(signature)-1] // remove recovery id
    verified := crypto.VerifySignature(publicKeyBytes, hash.Bytes(), signatureNoRecoverID)
    fmt.Println(verified) // true
}

Check out the Ethereum Development with Go guide book for more examples on using go-ethereum.

user10595796
  • 134
  • 9
Miguel Mota
  • 20,135
  • 5
  • 45
  • 64