Utilizing Cryptography Libraries to Derive Ethereum Addresses from Private Keys

Written by johnquiwacode | Published 2018/05/28
Tech Story Tags: blockchain | cryptography | ethereum | solidity | software-development

TLDRvia the TL;DR App

For the non-math inclined developer

Cryptography is central to everything in the world of blockchain and cryptocurrencies. It’s used to create hash pointers that make blockchains possible and to create key pairs for wallets!

In this tutorial, we will be using the ‘elliptic’ and ‘js-sha3’ javascript libraries in order to leverage principles of Elliptic Curve Cryptography (ECC) to derive a public key from a private key, and then convert the public key into it’s corresponding Ethereum address.

Many online resources cover Elliptic Curve Cryptography from a mathematical perspective, but don’t offer applicable code examples. As a programmer, I find that seeing equations broken down into digestible code snippets can cement the principles into my mind. Before we dive into the code, let’s build a general foundation regarding what Elliptic Curve Cryptography is, why it is considered safe within the Ethereum ecosystem, and how it is used to generate key pairs.

What is Elliptic Curve Cryptography?

Elliptic Curve Example

Elliptic Curve Cryptography is a form of asymmetric cryptography that leverages the discrete logarithm problem of elliptic curves (ECDSA) to create public and private key pairs. Essentially, it is easy to perform operations in one direction, but is very computationally expensive to go in the other direction.

Is it possible to find a private key from a public key?

Public Keys are generated as a result of using elliptic curve multiplication to multiply private key (k) by generator point (G) in order to get public key (K).

K = k * G

In normal integer arithmetic, if we knew both K and g, we could simply divide K by g in order to get k. In other words, dividing the public key by the generator point would easily give us the private key.

k = K / G

Elliptic Curve arithmetic does not have division and is therefore considered a one-way mathematical function. It is technically possible to find the private key by multiplying all of the possible factors that result in K, however, the larger the numbers involved, the longer it would take to compute. For more information, I recommend reading checking out this section from Andreas M. Antonopoulos and Gavin Wood’s book Mastering Ethereum.

Overview

As previously discussed, K = k * G is actually another point on the elliptic curve. Therefore, K = (x, y) where x and y are it’s coordinates**.**

To convert the resulting public key (K) into it’s corresponding Ethereum address, we must run it through the Keccak-256 cryptographic hash function. The last 20 bytes of the resulting hash compose our Ethereum address.

Let’s jump into the code!

First, let’s setup our project. (You can skip to the next part if you’re already comfortable setting up node projects.)

Open up our terminal and create a directory for our code.

mkdir deriveEthAddress

Then, go into that directory using:

cd deriveEthAddress

To be able to npm install the modules we’ll be using, run

npm init

and fill in the prompts if you wish to.

Next, let’s npm install the ‘elliptic’ and ‘js-sha3’ libraries. Elliptic is a javascript library with various elliptic curve cryptography functions and js-sha3 provides us with a hash function we will be using.

npm install elliptic --save && npm install js-sha3 --save

Lastly, we create our project file.

touch deriveEthAddress.js

Now that our project is set up, open up deriveEthAddress.js in a text editor.

In deriveEthAddress.js we’ll require the modules we installed. Below, we create a new instance of an elliptic curve with the secp256k1 (a specific elliptic curve that both Ethereum and Bitcoin use) preset. We also require the keccak256 hash function from js-sha3.

// Required Modulesconst EC = require('elliptic').ec;const ec = new EC('secp256k1');const keccak256 = require('js-sha3').keccak256;

We’ll then create variables for our private key and ethereum address. (This key pair is only for testing and shouldn’t be used to store actual funds. It was taken from the Ganache CLI - see the github repo for more information.)

// Private Key and Public Ethereum address (from Ganache)const givenPrivateKey = 'c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3';const givenEthAddress = '0x627306090abab3a6e1400e9345bc60c78a8bef57';

Next, we’ll utilize the equation K = k * G. We get our generator point (G) from the secp256k1 elliptic curve instance. generatorPoint is then multiplied by privateKey (k). This results in pubKeyCoordinates (K). As we discussed earlier, K = (x,y), so we extract coordinates x and y and convert them to hexadecimal strings to be concatenated.

// Get secp256k1 generator pointconst generatorPoint = ec.g;

// Public Key Coordinates calculated via Elliptic Curve Multiplication// PublicKeyCoordinates = privateKey * generatorPointconst pubKeyCoordinates = generatorPoint.mul(givenPrivateKey);

const x = pubKeyCoordinates.getX().toString('hex');const y = pubKeyCoordinates.getY().toString('hex');

// Public Key = X and Y concatenatedconst publicKey = x + y;

console.log(publicKey);//af80b90d25145da28c583359beb47b21796b2fe1a23c1511e443e7a64dfdb27d7434c380f0aa4c500e220aa1a9d068514b1ff4d5019e624e7ba1efe82b340a59

We must then run our public key through the keccak256 hash function.

// Use Keccak-256 hash function to get public key hashconst hashOfPublicKey = keccak256(new Buffer(publicKey, 'hex'));

console.log(hashOfPublicKey);// 3f704e8b0ee605967f55081f627306090abab3a6e1400e9345bc60c78a8bef57

If we look at our hash, the last 20 bytes (which would be the last 40 bits) compose our Ethereum address! Let’s convert this to a buffer so we can slice out the bytes we want to use and convert it to a hexadecimal string. We can then add the hexadecimal prefix 0x to this.

// Convert hash to bufferconst ethAddressBuffer = new Buffer(hashOfPublicKey, 'hex');

// Ethereum Address is '0x' concatenated with last 20 bytes// of the public key hashconst ethAddress = ethAddressBuffer.slice(-20).toString('hex');const ethAddressWithPrefix = `0x${ethAddress}`;

Lastly, let’s compare our derived address to the address we were told our private key corresponded to.

// Ethereum Address derived from private key// is equal to the given addressconsole.log(ethAddressWithPrefix === givenEthAddress);

// true

It’s a match! Here’s the full example -

Closing

We’ve only covered the basic principles of Elliptic Curve Cryptography. That being said, the mathematical concepts applied to the Ethereum network are pretty straightforward, and there are many libraries out there to help us!

Thanks for reading! If you found this useful, give a clap below and follow me for more Javascript and Blockchain related articles.


Published by HackerNoon on 2018/05/28