Original

This article is a guide on how to generate an ECDSA private key and derives
its Ethereum address.

Use Openssl and keccak-256sum from a terminal.

SHA3 != keccak. Ethereum is using the keccak-256 algorithm and not the
standard sha3.

Ethereum use keccak-256, it should be noted that it does not follow the
FIPS-202 based standard(aka. SHA-3), which was finalized in August 2015

web3.utils.sha3 uses keccak-256 web3.sha3(string[, option]): keccak-256

Generate 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 in Bitcion.

This command will print the private key in BEM format(using the wonderful ASN.1
key structure) on stdout.

1
2
3
4
5
6
> openssl ecparam -name secp256k1 -genkey -noout
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIFDLYO9KuwsC4ej2UsdA4SYk7s3lb8aZuW+B8rjugrMmoAcGBSuBBAAK
oUQDQgAEsNjwhFoLKLXGBxfpMv3ILhzg2FeySRlFhtjfi3s8YFZzJtmckVR3N/YL
JLnUV7w3orZUyAz77k0ebug0ILd1lQ==
-----END EC PRIVATE KEY-----

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout
read EC key
Private-Key: (256 bit)
priv:
20:80:65:a2:47:ed:be:5d:f4:d8:6f:bd:c0:17:13:
03:f2:3a:76:96:1b:e9:f6:01:38:50:dd:2b:dc:75:
9b:bb
pub:
04:83:6b:35:a0:26:74:3e:82:3a:90:a0:ee:3b:91:
bf:61:5c:6a:75:7e:2b:60:b9:e1:dc:18:26:fd:0d:
d1:61:06:f7:bc:1e:81:79:f6:65:01:5f:43:c6:c8:
1f:39:06:2f:c2:08:6e:d8:49:62:5c:06:e0:46:97:
69:8b:21:85:5e
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.

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 ‘0x04’ prefix byte in order to hash it correctly.

This prefix represents the encoding of the public key:

  • 0x04 - both x and y of the elliptic curve point follows
  • 0x02, 0x03 - only x follows (y is either odd or even depending on the
    prefix)

Use any method you like to get it in the form of an hexadecimal string(without
line return nor semicolon)

1
2
3
4
# 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
836b35a026743e823a90a0ee3b91bf615c6a757e2b60b9e1dc1826fd0dd16106f7bc1e8179f665015f43c6c81f39062fc2086ed849625c06e04697698b21855e

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), 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.

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

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.