2

So I am trying to get public key in hex formatting. In some documentation I found the following will give public key from the private key, but it is not formatted correctly as I can see:

publicKey := privateKey.Public()

// output is &{0xc0000aa810 111467676592638012114394423922557735151709477236068497041031680458777853727687 91044589275583075592054080804256995961966216084890183147914377743969771213580}


publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
    log.Fatal("error casting public key to ECDSA")
}

// output looks the same here: &{0xc0000aa810 111467676592638012114394423922557735151709477236068497041031680458777853727687 91044589275583075592054080804256995961966216084890183147914377743969771213580}

publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA) 

// output: [4 246 112 120 28 51 214 136 11 9 156 225 31 55 248 83 107 177 101 138 103 54 81 101 66 67 247 150 1 88 0 147 199 201 73 105 81 71 44 213 141 125 198 50 50 47 21 2 25 193 203 214 105 129 64 151 83 64 247 101 247 190 42 83 12]

But what I am trying to get is the hex formatted of this. It does look like privateKey,Public() gives this, but added things with it. Is there a way to get just the hex representation of the public key so I can store and use later in the code?

1
  • Try to convert the publickKeyBytes to a hex string and omit the first byte (the 4). This should give you a hex string which is 128 characters long (64 bytes). Like this: hex := fmt.Sprintf("%x", publicKeyBytes[1:]) Jan 8, 2019 at 19:55

2 Answers 2

3

You can use the hexutil.Encode() utility from go-ethereum. Here's a full working example:

package main

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

    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/crypto"
    "golang.org/x/crypto/sha3"
)

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

    privateKeyBytes := crypto.FromECDSA(privateKey)
    fmt.Println(hexutil.Encode(privateKeyBytes)[2:]) // fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19

    publicKey := privateKey.Public()
    publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
    if !ok {
        log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
    }

    publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
    fmt.Println(hexutil.Encode(publicKeyBytes)[4:]) // 9a7df67f79246283fdc93af76d4f8cdd62c4886e8cd870944e817dd0b97934fdd7719d0810951e03418205868a5c1b40b192451367f28e0088dd75e15de40c05

    address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
    fmt.Println(address) // 0x96216849c49358B10257cb55b28eA603c874b05E

    hash := sha3.NewLegacyKeccak256()
    hash.Write(publicKeyBytes[1:])
    fmt.Println(hexutil.Encode(hash.Sum(nil)[12:])) // 0x96216849c49358b10257cb55b28ea603c874b05e
}
1
  • Hello Miguel! For private key the first 2 digits is 0x and I tested out for public key is 0x04 which need to remove first 4 digits. I wonder what is the extra 2 digits in the public key?
    – Chhaileng
    Jun 23, 2022 at 9:25
1

The output is 65 bytes long and starts with 0x04. This indicates to me that this is a DER encoding of the public key (which is what Bitcoin and all its fork uses). Ethereum does not DER encode its public keys, public keys in Ethereum are only 64 bytes long.

Try to convert the publicKeyBytes to a hex string and omit the first byte (the 4). This should give you a hex string which is 128 characters long (64 bytes). Like this:

 hex := fmt.Sprintf("%x", publicKeyBytes[1:]).

Ethereum may expect this public key hex string to start with "0x". In that case:

hex := fmt.Sprintf("0x%x", publicKeyBytes[1:]).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.