Create bitcoin address using java in 6 steps

LearnWithParth
5 min readJun 10, 2021

Generate Bitcoin Addresses using Java in six steps

In this article, I will explain how to write a Java program to generate Pay to Public Key Hash (P2PKH) Bitcoin address (compressed and uncompressed public key). This is three article tutorials which will demonstrate how to generate different Bitcoin address using Java programming.

Bitcoin addresses are 26–35 characters long, consist of alphabetic and numeric characters and either begin with “1”, “3”, or “bc1”.

Currently, there are three Bitcoin address formats in use:

1. P2PKH (Pay to Public Key Hash) (address starts with the number “1”)

Example: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2

2. P2SH (Pay to Script Hash) (address starts with the number “3”)

Example: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy

3. Bech32 (address starts with “bc1”)

Example: bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq

The bitcoin address is a random string in the BASE58 encoding format used to send and receive bitcoins in the Bitcoin network. It is public-private asymmetry key cryptography based on ECDSA. The public part of the key is used to generate bitcoin address. The corresponding private key is used to sign the Bitcoin transaction as confirmation and proof at the time of the transaction.

Technically, the Bitcoin address is from ECDSA. Generated by the public part of the key, using SHA-256 and RIPEMD-160 Hash, as described below, to process the resulting hash, and finally, use Base58. The key is encoded by the check code.

Let’s see how to use JCE (java encryption extension), Bouncy Castle (RIPEMD-160), and finally Base58 encoding in the “bitcoinj” library to generate Bitcoin address.

Step 1: Initialize the security service provider.

We’ve added the BouncyCastleProvider as a security provider as we are going to use classes of it.

java.security.Security.addProvider(new BouncyCastleProvider());

Step 2: Generate ECDSA keypair

We have used crypto-3.3.1.jar developed by web3j. You can download it from: https://jar-download.com/artifacts/org.web3j/crypto/3.3.1/source-code

BigInteger privKey = Keys.createEcKeyPair().getPrivateKey();

OUTPUT: Private key: a76448f06981aeb02df458f657be1f2994729f8df0de672ecc0095421089f5bc

Generated private key is usually stored by the digital wallets.

BigInteger pubKey = Sign.publicKeyFromPrivate(privKey);

ECKeyPair keyPair = new ECKeyPair(privKey, pubKey);

OUTPUT: Public key: f51b58c89eebcdcdedfb6733bfe45fb884186e8277910ea7dea83fd44380a96de8671ddb36f0bf38d502d9ec7b1973ffe6d696431edc163d73f95cf9acd2180a

The public part of the key generated above will be encoded into a bitcoin address. The ECDSA public key is represented by a point on an elliptical curve. The X and Y coordinates of this point comprise the public key.

Once we’re done with the ECDSA key generation, all we need to do is to add the bytes 0x04 at the start of our public key. The result is a Bitcoin full public key.

But we can do better as we may compress the key as shown below. This key contains the same information, but it’s almost twice as short as the uncompressed key.

String bcPub = compressPubKey(pubKey);

OUTPUT: Compressed Public key: 02f51b58c89eebcdcdedfb6733bfe45fb884186e8277910ea7dea83fd44380a96d

Step 3: Generate hashes based on the public key

What we need to do here is to apply SHA-256 to the public key and then apply RIPEMD-160 to the result. The order is important.

Hashed public key = RIPEMD-160 (SHA-256 (public key))

MessageDigest sha = MessageDigest.getInstance(“SHA-256”);

byte[] s1 = sha.digest(hexStringToByteArray(bcPub));

MessageDigest rmd = MessageDigest.getInstance(“RipeMD160”);

byte[] r1 = rmd.digest(s1);

OUTPUT: SHA256: b21494d6b893fd73448a5fd7123938c3d5d4ff28d599bbf51eb89ad535e2fd1c

OUTPUT: RIPEMD160: 0582ab02f0abb93a049ba65e8738d4edec06075a

Step 4: Adding the address of type of the network to the output of hashing

Add version byte in front of RIPEMD-160 hash (0x00 for Main Network). The version byte is used to differentiate between MainNet and TestNet addresses as well as between P2PKH and P2SH addresses. It is 0x00 for mainnet and 0x6f for testnet.

byte[] r2 = new byte[r1.length + 1];

r2[0] = 0;

for (int i = 0; i < r1.length; i++) {

r2[i + 1] = r1[i];

}

OUTPUT: Added network byte: 000582ab02f0abb93a049ba65e8738d4edec06075a

Step 5: Generating checksum to verify the integrity of the key

Now we need to calculate the checksum of our key. The idea of checksum is to make sure that the data (in our case, the key) wasn’t corrupted during transmission. The wallet software should look at the checksum and mark the address as invalid if the checksum mismatches.

To calculate the checksum of the key, we need to apply SHA-256 twice and then take the first 4 bytes of the result.

Checksum = SHA-256( SHA-256(output from previous step))

byte[] s2 = sha.digest(r2);

OUTPUT: SHA256: db597d4fe6e6ad49c713be33f5e1907ce5839095e311f103b937acb2ac0cec01

byte[] s3 = sha.digest(s2);

OUTPUT: SHA256: 62a9971acb5e911c3472f924bfbe836173cef62d35c04b92118d69e6b3bf2602

The first 4 bytes of the result of the second hashing is used as the address checksum. It is appended to the RIPEMD160 hash above and generate 25-byte bitcoin address.

byte[] a1 = new byte[25];

for (int i = 0; i < r2.length; i++) {

a1[i] = r2[i];

}

for (int i = 0; i < 4; i++) {

a1[21 + i] = s3[i];

}

OUTPUT: Before Base58 encoding: 000582ab02f0abb93a049ba65e8738d4edec06075a62a9971a

Step 6: Applying Base58 encoding

We are using Base58.encode() Method of bitcoinj Library to get the final bitcoin address.

Base58.encode(a1)

OUTPUT: After Base58 encoding: 1W8uw3vTUD5CwaprwCWGPoMjk482xWm1K

We require the following utility functions for the execution of the above code:

The following function is used to convert the byte to hex representation for the sake of user’s understanding.

private static String bytesToHex(byte[] hashInBytes) {

StringBuilder sb = new StringBuilder();

for (int i = 0; i < hashInBytes.length; i++) {

sb.append(Integer.toString((hashInBytes[i] & 0xff) + 0x100, 16).substring(1));

}

return sb.toString();

}

As you may be knowing, the public key is some point (X, Y) on the elliptic curve. We know the curve, and for each X there are only two Ys that define the point which lies on that curve. So why keep Y? Instead, let’s keep X and the sign of Y. Later, we can derive Y from that if needed. The specifics are as follows: we take X from the ECDSA public key. Now, we add the 0x02 if the last byte of Y is even, and the byte 0x03 if the last byte is odd. The following method is used to generate a compressed public key based on the given public key in BigInteger.

public static String compressPubKey(BigInteger pubKey) {

String pubKeyYPrefix = pubKey.testBit(0) ? “03” : “02”;

String pubKeyHex = pubKey.toString(16);

String pubKeyX = pubKeyHex.substring(0, 64);

return pubKeyYPrefix + pubKeyX;

}

Hexadecimal representation in a string and its byte array representation is different in java (“0x78”! = “78”). The hashing algorithm which we have using in this program accept the byte array. Hence, to convert hexadecimal to byte array use following method:

public static byte[] hexStringToByteArray(String s) {

byte[] b = new byte[s.length() / 2];

for (int i = 0; i < b.length; i++) {

int index = i * 2;

int v = Integer.parseInt(s.substring(index, index + 2), 16);

b[i] = (byte) v;

}

return b;

}

Use the following tools to validate the result of intermediate steps:

1. To check the generated address is valid or not use: https://awebanalysis.com/en/bitcoin-address-validate/

2. Base58 encoding, decoding tool http://lenschulwitz.com/base58

3. Play with bitcoin address generator: https://brainwalletx.github.io/#generator

Some key facts about valid Bitcoin addresses:

· A Bitcoin address is between 25 and 34 characters long;

· The address always starts with a 1;

· An address can contain all alphanumeric characters, with the exceptions of 0, O, I, and l.

References:

1. https://medium.com/coinmonks/how-to-generate-a-bitcoin-address-step-by-step-9d7fcbf1ad0b

2. https://www.novixys.com/blog/generate-bitcoin-addresses-java/

3. https://developpaper.com/how-to-generate-bitcoin-wallet-address-in-java/

4. https://www.freecodecamp.org/news/how-to-create-a-bitcoin-wallet-address-from-a-private-key-eca3ddd9c05f/

5. https://blog.hubspot.com/marketing/bitcoin-address

--

--