|

Implementing the bitcoin white paper in Java

We’re going to attempt writing the simplest bitcoin client as described by Satoshi’s (2009) white paper. The paper is divided into 12 sections.

  1. Introduction
  2. Transactions
  3. Timestamp Server
  4. Proof-Of-Work
  5. Network
  6. Incentive
  7. Reclaiming Disk Space
  8. Simplified Payment Verification
  9. Combining and Splitting Value
  10. Privacy
  11. Calculations
  12. Conclusion

1. Introduction

The paper proposes a system that allows people to send payments to one another without the need for a third-party (i.e a bank or Stripe). This is understandable given that the western world was going through financial collapse around the same time. The proposal of the paper is:

A solution to the double-spending problem using a peer-to-peer distributed timestamp server to generate computational proof of the chronological order of transactions.

1.1 Double-spending problem

In the case of digital money where its easy to duplicate. A person can theoretically spend the same digital coin with two vendors. For example if Person A with 10 digital coins can spend 10 coins with Vendor B and duplicate the coins to spend with Vendor C. The current solution to double spending in digital money is that a third party ie. a bank would keep a database of everyone’s balance and would therefore ensure the balance stays consistent. The would ensure no duplication of coins are made and double spending is prevented. Rather than relying on a third central party to validate the transactions Satoshi proposes a peer to peer solution.

2. Transactions

We starts by defining a digital coin is and what processes happen when payments are made. This coin and payment system will be susceptible to the double spending but nonetheless it will form the foundation to the solution. Satoshi defines the coin as a chain of digital signatures. Explains that in order for Person A to pay Person B, Person A has to Sign the hash of the previous transaction and the public key of Person B and append these to the end of the coin.

Diagram from bitcoin whitepaper showing the chain of digital signatures involved in making a payment

The diagram above has several concepts that we need to understand, namely

  • Private/Public keys
  • Signature/Signings
  • Verification
  • Hashing

2.1 Private/Public keys

We can consider private and public keys as identities. An identity that consists of private key, one that is kept secret and public key which is known to everyone. We can use java.security package to create the private/public key for an identity;

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
System.out.printf("Private key is %s \nPublic key is %s\n",
                bytesToHex(keyPair.getPrivate().getEncoded()), bytesToHex(keyPair.getPublic().getEncoded()));
Output (the keys have been truncated for display purposes
Private key is .......15812 
Public key is ........b4a5ce862c2d0

2.2 Signatures/Signings

This is a function that takes a private key, a message hash and returns a digital signature. In Java it can be represented like this:

Signature sigObj = Signature.getInstance("SHA256withDSA");
// initialise the signature object
sigObj.initSign(keyPair.getPrivate());
// adding data to the signature object
byte[] message = "Hello world".getBytes();
sigObj.update(message);
byte[] signature = sigObj.sign();
System.out.printf("Signature is %s\n", new String(signature, "UTF8"));

2.3 Verification

This is a function that takes in a public key, message, signature and returns a boolean of true which means that the entity with that public key did in fact sign the message.

// lets verify now
sigObj.initVerify(keyPair.getPublic());
sigObj.update(message);
boolean verified = sigObj.verify(signature);
if(verified) {
    System.out.println("Signature verified");
} else {
    System.out.println("Signature not verified");
}

2.4 Hashing

This is defined as a function that takes an input of an arbitrary size and returns a value of fixed size. In Java the hashing value is called the message digest and it looks like this:

MessageDigest messageDigestInstance = MessageDigest.getInstance("SHA-256");
messageDigestInstance.update("Hello world".getBytes());
byte[] digest = messageDigestInstance.digest();
System.out.printf("Hex formatted message digest: %s\n", bytesToHex(digest));

2.5 Putting it all together

Now that we know vaguely what various transactions concepts mean, we can now model the transaction diagram provided by the white paper. Lets do this by an example. Consider 3 people that wanted to create a system to send digital coins to each other, lets call these coins Satoshi Coins. The rules are simple:

  • A single satoshi coin is the smallest coin that they can trade, ie. we cannot exchange 1/2 a Satoshi coin to each other.
  • The first transaction of the system will be one that will allocate all participants with an equal sum of satoshi coins.
  • A node will manage and store transactions (centralised but thats ok for now)

Lets model the system as follows:

  • Each participant will be an identity, which mean they will have a private key (known only to them), a public (how everyone else recognises them), a name (a string, this isnt needed but its to easily identify the participants). The number of satoshi coins that they hold.
package org.crypto;


import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;

public class Identity {
    private final byte[] privateKey; //note no getter because it secret.
    private final byte[] publicKey;
    private final String name;
    private int balance;

    public Identity(String name, int balance) throws NoSuchAlgorithmException {
        this.name = name;
        this.balance = balance;
        KeyPairGenerator sda = KeyPairGenerator.getInstance("SDA");
        sda.initialize(2486);
        KeyPair keyPair = sda.generateKeyPair();
        this.privateKey = keyPair.getPrivate().getEncoded();
        this.publicKey = keyPair.getPublic().getEncoded();
    }

    public byte[] getPublicKey() {
        return publicKey;
    }

    public String getName() {
        return name;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int newBalance) {
        this.balance = newBalance;
    }
}
  • The first transaction will be the one that will determine the initial state allocate the satoshis to all parties. The first transaction on the bitcoin network was from Satoshi Nakamoto to Hall Finny a software developer and a cryptographic activist. Our system will do a similar thing but it will be from Jack who will have 75 coins to begin with, will send Amy and Bill 25 coins each on the first transaction. Therefore, after the first transaction, they will all have 25 coins each.
  • The model will be centralised right now to only prove the chain of ownership of the coins, meaning that, the transaction list will be held/stored by a single entity called the Node. The participants will form the transactions, send it to the Node to store. It is also the job of the participants to verify the the ownership of the coins.
package org.crypto;

import java.sql.Date;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

public class Node {
    private final List<Transaction> txs;

    public Node(Identity identity, int amount) {
        this.txs = new ArrayList<>();
        // create genesis tx
        txs.add(new Transaction(String.valueOf(0).getBytes(),
                String.valueOf(0).getBytes(),
                null,
                identity.getPublicKey(), amount,
                Date.from(Instant.now())));
    }

    public Transaction getLastTx() {
        return txs.get(txs.size() - 1);
    }

    public void saveNewTx(Transaction newTx) {
        txs.add(newTx);
    }
}
  • We will implement this using TDD and the blessings of passing JUnit tests, in order to form a structure that will ultimately resemble what Satoshi was talking about.
  • So what would these look like, more specifically what would our first test do. Well lets see, the transaction section of the paper only concerns it self with the concept of digital signatures and the chain of ownership of the coins. It explicitly states that it does not solve the double spending problem, therefore it cannot be relied on to determine the true balances of the participants.
import org.crypto.Identity;
import org.crypto.Node;
import org.crypto.Transaction;
import org.junit.Test;

import java.security.NoSuchAlgorithmException;

import static org.junit.Assert.assertTrue;

public class KeysTest {

    @Test
    public void testSendAndVerifyTxs()throws NoSuchAlgorithmException {
        // Lets create our participants
        Identity jacksIdentity = new Identity("Jack");
        Identity amysIdentity  = new Identity("Amy");
        Identity billIdentity  = new Identity("Bill");
        // Instantiate the node with initial balance
        Node node = new Node(jacksIdentity, 75);
        // Let's carry out the first transaction
        // Jack sends 25 to Amy and 25 to Amy
        Transaction transaction = jacksIdentity.createTransaction(node, amysIdentity, 50);
        node.saveNewTx(transaction);
        // let amy verify that jack was the owner of the coin that was sent to her.
        assertTrue(amysIdentity.verified(transaction.thisTxId(), jacksIdentity.getPublicKey().getEncoded()));
    }
}

Example: Person A, B and C. Each have their ledger (a database or a notebook etc) where they keep a record of their own balance and everyone else’s balance. Lets say they all start off with the same ledger history and everyone balance according to everyone is

  • A’s ledger 10
  • B = 20
  • C = 15

We will start by making a the simplest blockchain possible, enough to grasp the idea of a block-chain and proof of work (PoW) and node.

This is intended to be a multipart series of blogs to attempt building a blockchain protocol from the ground up, we’re going to build a proof of concept of a blockchain client rather than a fully fledged one.

  • Blockchain – as the name hints, its a data structure that might look like a list of blocks that are linked(chained) together.
  • Node – this is the software that will manage the blockchain by adding blocks and doing validation work.
  • Proof of Work – Its is a piece of evidence (proof) that some work has taken place.

Component structure and relationships

Lets start by first making the blockchain component.

We start by defining the idea of a block and how the blockchain is linked. If we were to consider a record (block) that has has an identifier (id/ unique hash), a access to the identifier of the previous record. Then we can create our block class as follows:

public record Block(Integer timestamp, byte[] previousBlockHash, byte[] thisBlockHash, byte[] allData, int nonce) {}

Lets first imaging that we need a database of records to store a simple message from users/people. We have a requirement to maintain the order of those records at all cost.

We’ll divide this tutorial to main components.

  • The block structure: to illustrate a simple blockchain
  • The node structure to illustrate the responsibilities and logic the node executes in order to achieve a simple Proof of Work mechanism
  • block validation by the node

The next steps

  • make then nodes distributed
  • achieve consensus
Function to get the valid hash

Similar Posts