top of page

Blockchain Project


March, 2021

Goals

​

The objective of this project was to demonstrate a key nonfunctional characteristic of blockchain technology: its tamper evident design. I implemented the project using Java and socket programming.

​

I performed two main tasks in the project:

 

  1. Build a standalone blockchain program

  2. Distribute the system on a TCP client-server application, where the client communicates with a blockchain API

​

In many applications of blockchain, information generally contains details about transactions between different entities. However, in this particular program, I demonstrated another use case of blockchain, Self-Sovereign Identity (SSI). An essential prerequisite in building this use case was understanding how information on the blockchain should look. 

​

Development

​

The data on my blockchain program included name-value pairs, where the names were decentralized identifiers (DID's), and their associated values were RSA keys. In the RSA cryptosystem, the public key is the pair e and n, where e is the encryption exponent and n is the modulus. In my project, I chose the default value of e = 65537, and used only the value of the modulus as the RSA public key. Enhanced data structures like Merkle trees were excluded from this project.

​

To be able to store data on the blockchain, I then defined a block on the blockchain. 

 

Block

​

A block on the blockchain was defined to have the following attributes:

  1. An index, which is the position of the block on the chain. The first block, called the Genesis block, has an index of 0.

  2. A timestamp, which is the time of the block’s creation. 

  3. A datum, which is the string holding the block’s identity details—in this case, name-value pairs.

  4. A hash pointer, which is a string holding the MD5 hash of a block’s parent.

  5. A nonce, which is the integer value determined by a proof of work routine. It is generated by computing the number of trials taken in verifying that the block has a hash of the proper difficulty.

  6. A difficulty level, which is the integer that specifies the exact number of leftmost hex digits, or nibbles, needed by a proper hash.

​

In addition to understanding a block’s structure on the chain, it was important to define the attributes of the actual data stored in each block. The following steps outline how my program allowed users to generate and store this data. 

​

Structuring Blockchain Data

​

  1. Allow the user to choose their public key, stored and accessed as a BigInteger*. 
    *The RSA public key is the pair e and n, where e is the encryption exponent and n is the modulus. In my project, the public key is simply the value of the modulus, n. Furthermore, although large keys are appropriate in real life applications, I created RSA keys with 100 bit prime numbers for this project.

     

  2. Compute the hash of the chosen public key using the MD5 message-digest algorithm.
     

  3. Take the rightmost 20 bytes of the hash of the public key. This is the DID.
     

  4. Concatenate the public key and the DID to get the data to be stored in the block.

 

​
 

Here’s a diagram to simplify the logic:
 

hash.jpg

Task 1

​

A well-founded understanding of these structures allowed me to develop the program’s constructors and methods, which formed the cornerstone of my project. My program then ran the following functions:

​

  • Inspect the blockchain’s current status, revealing details about its size, the number of hashes per second computed by the machine, the difficulty of the most recent block, the nonce for the most recent block, and the hash of the full chain.
     

  • Add a new block by generating a DID based on a new RSA public key.
     

  • Verify the blockchain by performing proof of work.
     

  • View the full blockchain printed in standard JSON format.
     

  • Corrupt the chain by adding a corrupt block in place of an existing block.
     

  • Repair a corrupt chain by incrementing the nonce of affected blocks, burning electricity and CPU cycles, until a good hash is produced.
     

 

Task 2

​

For Task 2 of my project, I built a distributed system where a remote client interacts with a blockchain API. The program aimed to demonstrate a high-level TCP client and interaction model, which worked with the previous build of the blockchain program. 
 

In this iteration, instead of relying on DatagramPackets and byte arrays, the TCP protocol made use of OutputStreamWriters, BufferedReaders, BufferedWriters, InputStreamReaders and PrintWriters to successfully write and read information on the socket. 
 

Each time the user activated communication on the client side, they were assigned an ID and RSA-generated public and private keys. After being presented with the choice of functions described earlier, the user’s selection was read, parsed, constructed into a TCP-consistent packet and sent on the socket. These requests made by the client were signed with the user’s private key, which were then verified on the server side. A signature that failed to verify sent an appropriate error message back to the client. As described earlier, every message communicated over the sockets was encapsulated in the standard JSON format. 
 

At a higher level, the program illustrated the marshaling and unmarshaling of requests and replies, and demonstrated the most significant differences between TCP style sockets and UDP style sockets. To keep my communication and application codes distinct, I used proxy design and a clear separation of concerns for scalability.

bottom of page