Vincent Kobel

Unfolding Protons - A blog about Ethereum, blockchains and code chivalry

github linkedin email rss
Create full Ethereum wallet, keypair and address
Feb 15, 2017
6 minutes read

Generating a usable Ethereum wallet and its corresponding keys


This article is a guide on how to generate an ECDSA private key and derive its Ethereum address. Using OpenSSL and keccak-256sum from a terminal.

You can find a working implementation of keccak-256sum here. Cool thing, it exists as a package in the Arch User Repository as well. If you’re feeling lazy, you can find statically linked pre-compiled versions for both i386 and x86-64 on my repo.

Warning SHA3 != keccak. Ethereum is using the keccak-256 algorithm and not the standard sha3. More info at Stackoverflow.

I have a repository with complete scripts in both bash and python if you’d like.

Generating the EC private key

First of all we use OpenSSL ecparam command to generate an elliptic curve private key. Ethereum standard is to use the secp256k1 curve. The same curve is used by Bitcoin.

This command will print the private key in PEM format (using the wonderful ASN.1 key structure) on stdout. If you want more OpenSSL info on elliptic curves, please feel free to dig further.

> openssl ecparam -name secp256k1 -genkey -noout

On its own this command is not very useful for us, but if you pipe it with the ec command it will display both private and public part in hexadecimal format, and this is what we want! Let’s do it:

> openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout
read EC key
Private-Key: (256 bit)
ASN1 OID: secp256k1

This command decodes the ASN.1 structure and derives the public key from the private one. Sometimes, OpenSSL is adding a null byte (0x00) in front of the private part, I don’t know why it does that but you have to trim any leading zero bytes in order to use it with Ethereum.

The private key must be 32 bytes and not begin with 0x00 and the public one must be uncompressed and 64 bytes long or 65 with the constant 0x04 prefix. More on that in the next section.

Derive the Ethereum address from the public key

The public key is what we need in order to derive its Ethereum address. Every EC public key begins with the 0x04 prefix before giving the location of the two point on the curve. You should remove this leading 0x04 byte in order to hash it correctly. I recommend the excellent Cloudflare article on elliptic curves if you want more details.

Use any method you like to get it in the form of an hexadecimal string (without line return nor semicolon). Here is an example of extraction using grep, tail, tr and sed. I’m sure there’s an easier way to do it but I’m not a bash guru. You can find the scripts (python as well) on my github repository.

The examples below assume you saved the output of the openssl commands in a file named ‘Key’

# Extract the public key and remove the EC prefix 0x04
> cat Key | grep pub -A 5 | tail -n +2 | 
            tr -d '\n[:space:]:' | sed 's/^04//' > pub

The pub file now contains the hexadecimal value of the public key without the 0x04 prefix.

An Ethereum address is made of 20 bytes (40 hex characters long), it is commonly represented by adding the 0x prefix. In order to derive it, one should take the keccak-256 hash of the hexadecimal form of a public key, then keep only the last 20 bytes (aka get rid of the first 12 bytes).

Simply pass the file containing the public key in hexadecimal format to the keccak-256sum command. Do not forget to use the ‘-x’ option in order to interpret it as hexadecimal and not a simple string.

In the below snippet, the ‘-l’ option is to output as lowercase. Then I use tr to delete the trailing ‘ -’ from the stdout of the keccak command. Finally, I take only the last 40 characters using the tail command. Yes, I specify 41 in order to get 40 characters, probably because of a line return.

# Generate the hash and take the address part
> cat pub | keccak-256sum -x -l | tr -d ' -' | tail -c 41

Which gives us the Ethereum address 0x0bed7abd61247635c1973eb38474a2516ed1d884

CAUTION! if your final address looks like *0xdcc703c0E500B653Ca82273B7BFAd8045D85a470* this means you have hashed an empty public key. Sending funds to this address will lock them forever! People made this mistake before as shown on etherscan.

Thanks to Linus Miller for highlighting this issue in the comments section below.

Importing the private key to geth

Let’s import the private key to geth and therefore validating the derivation of the address.

To begin with, we format the private key the same way we did for the public one above. The only exception is removing the leading 0x00 instead of the 0x04:

# Extract the private key and remove the leading zero byte
> cat Key | grep priv -A 3 | tail -n +2 | 
            tr -d '\n[:space:]:' | sed 's/^00//' > priv

To import it to geth, use the account import feature like this:

> geth account import priv
Your new account is locked with a password. Please give a password. Do not forget this password.
Repeat passphrase: 
Address: {0bed7abd61247635c1973eb38474a2516ed1d884}

YAY! the address returned by geth is the same we computed. Note that geth will ask you a passphrase to encrypt your private key.

You’re now ready to use the new account with geth. Of course, it would be easier to take advantage of the geth account new feature in order to quickly setup an Ethereum account. But manually doing it gives you the power of knowing your public and unencrypted private keys. In addition, this would be useful to generate a secure Ethereum account completely off chain.

Complete example

# Generate the private and public keys
> openssl ecparam -name secp256k1 -genkey -noout | 
  openssl ec -text -noout > Key

# Extract the public key and remove the EC prefix 0x04
> cat Key | grep pub -A 5 | tail -n +2 |
            tr -d '\n[:space:]:' | sed 's/^04//' > pub

# Extract the private key and remove the leading zero byte
> cat Key | grep priv -A 3 | tail -n +2 | 
            tr -d '\n[:space:]:' | sed 's/^00//' > priv

# Generate the hash and take the address part
> cat pub | keccak-256sum -x -l | tr -d ' -' | tail -c 41 > address

# (Optional) import the private key to geth
> geth account import priv

Back to posts

comments powered by Disqus