Bitcoin Public and Private Keys Explained

Posted by on Mar 12, 2014 in Technical, Thoughts | No Comments

At its core, a Bitcoin address starts with just a number, albiet an extermely large number. So lets take a number. 31.   As a lot of Bitcoin math uses base 16 or hex numbers, we choose 31 so we can also show the conversion process.

31 in hexadecimal becomes 1F:  1 x 16^1 + 15 x 16^0

We convert this number into a base 58 and put it in “wallet import format” or WIF.
5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreE85b5kg.  You can check this is correct at brainwallet.org

Now, heres the trick. The Bitcoin protocol uses Elliptic Curve cryptography (y^2 = x^3 + ax + b), and the named curve secp256k1.

We set D = the private key 31.  Then apply the multiply function to D, such that it yields a point on the curve x,y which are 32bit numbers.

The ESDCA public key (not to be confused with your bitcoin address) starts with the number 04 and then is concatinated with x and y values in base 10.

x = 48009403158434809478298710137233764200988036438868259456275038304221065242292
y = 101379581344212856035375194820281365028426536613141130008386086305632315345538

We then double SHA256 and RipeMD160 hash 04 & x & y and convert to base 58 to give us our Bitcoin address  1KWj99Jwd9LGGC2Y1c9c4cmvWvYTQrLFVc which you can again verify at brainwallet.org.   The initial primary key, in this case 31, will always create the same Bitcoin address, and only that Bitcoin address.

Aside:

The code to generate is very simple, see the c# example below,

[code language=”csharp”]
private static void CreateAddress()
{
Org.BouncyCastle.Math.BigInteger d = new Org.BouncyCastle.Math.BigInteger(“31″);
String wifofBrainWallet = CreateWif(“000000000000000000000000000000000000000000000000000000000000001f”);

Debug.Assert(wifofBrainWallet == “5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreE85b5kg”);

Org.BouncyCastle.Asn1.X9.X9ECParameters ecp = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName(CURVE_NAME);
ECDomainParameters ecDomainParams = new ECDomainParameters(ecp.Curve, ecp.G, ecp.N, ecp.H);
ECPoint publicKey = ecp.G.Multiply(d);

Console.WriteLine(publicKey.X.ToBigInteger().ToString());
Console.WriteLine(publicKey.Y.ToBigInteger().ToString());

Byte[] keyArray = publicKey.GetEncoded();
Debug.Assert(keyArray.Length == 65);

String final = CreateAddress(keyArray);

Debug.Assert(final == “1KWj99Jwd9LGGC2Y1c9c4cmvWvYTQrLFVc”);
}
[/code]