Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Skills covered in this lab that were reviewed in class: SHA256 Hashing Multithre

ID: 3744449 • Letter: S

Question

Skills covered in this lab that were reviewed in class:

SHA256 Hashing

Multithreading

TIP

: Remember, don't be overwhelmed by all the details. Simply focus on one line at a time as the

instructions walk you through the creation of the app.

1. SUMMARY

The user first enters in the merkle root of four words the user will try to give to the merkle thread...

this merkle root can be manually figured out by the user from the "NOTE" desctiption on the top of

page 2.

Then a multithreaded portion of the app allows user submission of Strings on the main thread, and

each of those Strings is grabbed by a Merkle or Rogue background thread depending on the user’s

timing.

If the Merkle thread gets enough words (4), then it will create a merkle tree and produce a merkle

root string – and if it matches the initial merkle root entered by the user, the user wins ... if it doesn’t

match the user loses.

Meanwhile, every word the rogue thread gets is a “strike.” 3 strikes and the user loses.

The two background threads will sleep a random number of seconds which challenges the user to

time their entry just right so that the Merkle thread gets the word.

A third Monitor thread in the background will check on progress and end the app once lost or won.

So it's just a simple game to allow you to get some coding experience with multithreading and merkle

roots.

2. DETAILS

a.

You’re creating a console app.

b. Remember that if you prompt the user for input and background threads are printing stuff to screen,

it doesn’t affect your typing and hitting return... even if your typing is mixed up with all the printing

statements.

c.

Classes

i. MerkleManager_Test

1. Will have main method and will instantiate instance of MerkleManager and call manage

function... that's it.

ii. MerkleManager

1. Instance variables:

a.

Public & static & volatile String for User’s entered word.

b. Public & static String for user entered expected merkle root.

c.

Public & static String for merkle root set to null.

d. Public & static int for strikes set to 0.

2. Method: A public "manage" method and this will be called by the MerkleManager_Test class's

main method.

a.

No inputs or outputs.

b. Use Util class (that you’ll create later on below) to prompt user for the expected merkle

root after they’ve entered four words.

i. Put user entered text into the instance variable to hold for end of game comparison.

ii.

NOTE

: Use

https://www.xorbin.com/tools/sha256-hash-calculator to figure out merkle

root of the four words you expect to use just like we do in the code:

1. EXAMPLE:

H6: Merkle root

/

H4 H5

/ /

H0 H1 H2 H3

| | | |

“word1” “word2” “word3” “word4”

a.

if your words were “word1”, “word2”, “word3”, “word4”, then you would

enter “word1” into the above web page and get the hash (H0),

b. Then do the same with the others.

c.

Then combine each pair of hashes, so the hash of “word1” (H0) together with

the hash of “word2” (H1), and get the hash of that long string (H4). You’ll do

that twice, once for the first two (H0 & H1) and once for the second two (H2 &

H3). So you now have H4 & H5.

d. Finally, then combine those resulting two hashes (H4 & H5) into one string in

the web page entry to produce another hash – this is your merkle root hash.

e. Copy this merkle root from the web page and paste into your user entry when

prompted in the console.

c.

Start 3 separate threads: Instantiate and start new threads for...

i. MerkleThread, RogueThead, MonitorThread.

d. Begin UI Menu Loop:

i. Just use while(true) to make an eternal loop (because the monitor will eventually close

the app).

ii. Ask user for a word and put it into instance variable for user’s word.

3. Method: A public & static & synchronized method called grabWord.

a.

No inputs but returns a String.

b. Puts instance variable of user’s word into a temp String variable and then makes the

instance variable null.

c.

Then returns the temp variable.

iii. MerkleThread

1. This class must implement Runnable.

2. Instance variables:

a.

Public & static & volatile ArrayList<String> that holds all the grabbed words.

i. Example:

1. public static volatile ArrayList<String>

lstWords

;

b. Private int called

iMerkleTreeInputs

for how many words to wait for before creating a

merkle tree.

i. Set it equal to 4.

3. Method: A public “run” method that is triggered when “start” is called from MerkleManager.

a.

No inputs or outputs.

b. Instantiate a Util class object (Util class is defined lower down).

c.

Instantiate the ArrayList instance variable.

i. Example:

1. lstWords = new ArrayList();

ii. Create a neverending while loop like this:

1. while(true){...

2. In loop, do all the following:

a.

Call sleepRandomTime on util variable.

b. Cal grabWord on MerkleManager.

i. Example of how to call static method:

String sNewWord = MerkleManager.grabWord();

c.

Then if sNewWord is not null:

i. Print out that Merkle grabbed a word.

ii. Add word to lstWords like this: lstWords.add(sNewWord);

iii. Check if lstWords.size() is equal to iMerkleTreeInputs.

iv. And if true, then set MerkleManager.sMerkleRoot to the merkle root

generated by the getMerkleRoot method on util class.

iv. RogueThread

1. This class must implement Runnable.

2. Method: A public “run” method.

a.

No inputs or outputs.

b. Instantiate a Util object.

c.

Create a neverending loop again just like you’ve done before.

i. Inside loop, do all the following:

1. Call sleepRandomTime on util variable.

2. Call grabWord similar to how described in MerkleThread.

3. If sNewWord is not null:

a.

Increase iStrikes static variable on MerkleManager by 1.

b. Print out to screen that rogue grabbed a word and mention “STRIKE!”

v. MonitorThread

1. Method: “run” method just as in the other Thread classes.

a.

Create endless loop as you’ve done above.

i. If MerkleManager.sMerkleRoot is not null then...

1. If the above merkle root equals the initial user-entered merkle root (which you

can access the same way as above since they’re both static on MerkleManager):

a.

Then print out “You win: “ followed by the merkle root (which is the above

static variable on MerkleManager) and exit the app.

2. Else if they’re not equal, then tell the user and that the user lost – and exit the

app.

a.

To exit:

System.exit(0);

ii. Else if MerkleManager.iStrikes equals 3 then print out “3 strikes: you lost!” or

something like that and exit the app as shown in line of code above.

iii. After the if-else statement, then call sleep on util object and sleep for 1 second.

1. (if you don’t do this, the endless loop never allows updates on that thread to see

MerkleManager’s changing values.)

vi. MerkleNode

1. Three instance variables:

a.

sHash is a String.

b. oLeft is a MerkleNode.

c.

oRight is a MerkleNode.

vii. Util

1. This will have helper functions that all the classes can use.

2. Method: Public method called getMerkleRoot.

a.

Inputs:

i. ArrayList<String> type for the list of words from MerkleThread.

b. Description:

i. Not much description here since we did this in class.

ii. Creates 7 MerkleNode objects and slowly builds tree to get merkle root.

3. Method: Private method called populateMerkleNode.

a.

Inputs:

i. Three MerkleNode types: first is to be populated, second is to be the left node of the

first node, and third is to be the right node of the first node.

ii. Desctiption:

iii. Not much description because was reviewed in class.

1. Basically sets hash, left, and right node values.

4. Method: generateHash

a.

NOTE

: This method is given to you on Canvas in this week’s module and in class.

5. Method: public method called promptUser.

a.

Input: String of question to ask user.

b. Output: String answer from user.

c.

Description: Use JOptionPane class to get user input so that the user doesn’t have to type

while all the other text is being printed out.

i. Code provided here for getting user input in case you haven’t used JOptionPane

before:

//at top of file to allow use of JOptionPane:

import javax.swing.JOptionPane;

//inside class

public String promptUser(String sQuestion){

JOptionPane oQuestion = new JOptionPane();

String sAnswer = oQuestion.showInputDialog(sQuestion);

return sAnswer;

}

HashCodeFunction:

Imports required for hash function:

import java.nio.charset.StandardCharsets;

import java.security.MessageDigest;

...

Function to go inside of a Util class:

public synchronized String generateHash(String sOriginal){

try {

MessageDigest digest = MessageDigest.getInstance("SHA-256");

byte[] btEncodedhash = digest.digest(

sOriginal.getBytes(StandardCharsets.UTF_8));

StringBuilder sb = new StringBuilder();

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

sb.append(Integer.toString((btEncodedhash[i] & 0xff) + 0x100,

16).substring(1));

}

return sb.toString();

}

catch(Exception ex){

System.out.println("Error generating hash: " + ex.getMessage());

return null;

}

}

sleepRandomTime_method:

// Here is the import for the random number generator to go at top of your

class...

import java.security.SecureRandom;

// and here is the method...

public void sleepRandomTime(String sThreadName){

// Gets random number between 0 and 5 and then adds 3, meaning

between 3 and 8 now.

int iSleepTime = new SecureRandom().nextInt(5) + 3;

System.out.println(sThreadName + " sleeping for " + iSleepTime + "

seconds.");

sleep(iSleepTime);

}

Please use Intellj and mark each Java file to me. Thank you.

Explanation / Answer

MerkleManager_Test.java

public class MerkleManager_Test {

    public static void main(String[] args){

        MerkleManager oMerkleManager = new MerkleManager();
        oMerkleManager.manageFunction();
    }
}


MerkleManager.java

public class MerkleManager {

    // Variable initial and declarations
    public static volatile String sUserEnteredValue; //volatile: prevents different threads from keeping cache of this
    public static String sEnteredExpectedRoot;
    public static String sMerkleRoot = null;
    public static int iStrike = 0;

    public void manageFunction() {
        // Create an instance of the Util class
        Utils utils = new Utils();

        // Created 3 instances of the three kinds of threads
        Thread oMerkleThread = new Thread(new MerkleThread());
        Thread oRogueThread = new Thread(new RogueThread());
        Thread oMonitorThread = new Thread(new MonitorThread());


        sEnteredExpectedRoot = utils.promptUser("Enter the expected merkle root: ");

        // start my three threads
        oMerkleThread.start();
        oRogueThread.start();
        oMonitorThread.start();

        while(true){
            sUserEnteredValue = utils.promptUser("Enter value: ");
        }

    }

    public String grabWord(){
        String temp = sUserEnteredValue;
        sUserEnteredValue = null;
        return temp;
    }

}

MerkleThread.java

import java.util.ArrayList;

public class MerkleThread implements Runnable{

    public static volatile ArrayList<String> grabbedWords;
    private int iMerkleTreeInputs = 4; //how many words to wait for before tree gets created

    @Override
    public void run() {
        Utils utils = new Utils();
        MerkleManager merkleManager = new MerkleManager();
        grabbedWords = new ArrayList<>();
        while(true){

            utils.sleepRandomTime("Merkle Thread"); // let user know sleep status of thread
            String sNewWord = merkleManager.grabWord();

            // validate user input
            if(sNewWord != null){
                utils.print("[Merkle] grabbed word");
                grabbedWords.add(sNewWord); // add grabbed word to list
                if(grabbedWords.size() == iMerkleTreeInputs){
                    // set the sMerkleRoot to the generated merkle root value by getMerkleNode
                    MerkleManager.sMerkleRoot = utils.getMerkleNode(grabbedWords);
                }
            }
        }
    }
}


RogueThread.java


public class RogueThread implements Runnable {

    @Override
    public void run() {

        Utils utils = new Utils();
        MerkleManager merkleManager = new MerkleManager();

        while(true){

            utils.sleepRandomTime("Rogue Thread"); // let user know sleep status of thread
            String sNewWord = merkleManager.grabWord();

            // validate user input
            if(sNewWord != null){
                utils.print("[Rogue] grabbed word: STRIKE!");
                MerkleManager.iStrike++ ; // strike incrementer to end game
            }

        }
    }
}


Utils.java

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Scanner;

public class Utils {

    public String getMerkleNode(ArrayList<String> listName){

        // Create Merkle Node Projects
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();
        MerkleNode MerkleNode();

        // Create leaves of tree with hashes of inputs
        oNode0.sHash = generateHash(listName.get(0));
        oNode1.sHash = generateHash(listName.get(1));
        oNode2.sHash = generateHash(listName.get(2));
        oNode3.sHash = generateHash(listName.get(3));

        // Begin creating upper levels of tree
        populateMerkleNode(oNode4,oNode0,oNode1);
        populateMerkleNode(oNode5,oNode2,oNode3);
        populateMerkleNode(oNode6,oNode4,oNode5);

        return oNode6.sHash; //this is the merkel root

    }

    private void populateMerkleNode(MerkleNode oNode, MerkleNode oLeftNode, MerkleNode oRightNode){

        oNode.oLeft = oLeftNode;// set our left side of node
        oNode.oRight = oRightNode;// set our right side of node
        oNode.sHash = generateHash(oLeftNode.sHash + oRightNode.sHash); //create the next node
    }

    /* Algorithm to generate has using SHA-256*/
    public synchronized String generateHash(String sOriginal){

        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] btEncodedhash = digest.digest(
                    sOriginal.getBytes(StandardCharsets.UTF_8));

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < btEncodedhash.length; i++) {
                //0xff is telling it's going to be a hex number
                sb.append(Integer.toString((btEncodedhash[i] & 0xff) + 0x100, 16).substring(1));
            }
            return sb.toString();
        }
        catch(Exception ex){

            System.out.println("Error generating hash: " + ex.getMessage());
            return null;
        }
    }

    /*This will pass in the string which will be the questions you want to display to user*/
    public String promptUser(String question){
        Scanner scan = new Scanner(System.in);
        System.out.println(question);
        return scan.nextLine().trim(); //returns the user answer
    }

    /*Simple print statement to make my coding simpler*/
    public void print(String displayText){
        System.out.println(displayText);
    }

    /*This function will allow for my threads to sleep at random times*/
    public void sleepRandomTime(String sThreadName){

        // Gets random number between 0 and 5 and then adds 3, meaning between 3 and 8 now.
        int iSleepTime = new SecureRandom().nextInt(5) + 3;

        System.out.println(sThreadName + " sleeping for " + iSleepTime + " seconds.");
        sleep(iSleepTime);
    }

    /*This function will print out the array lists*/
    public void printList(ArrayList<String> list){
        for(String str : list){
            print(str +" ");
        }
        System.out.println();
    }

    /*Function will put my threads to sleep*/
    public void sleep(int iSeconds){
        try {
            Thread.sleep(iSeconds * 1000);
        }
        catch (Exception ex) {
            //it failed... oops
        }
    }
}

MerkleNode.java

public class MerkleNode {

    String sHash; // Has value for node
    MerkleNode oLeft;// Left node of tree
    MerkleNode oRight;// Right node of tree

}

MonitorThread.java

public class MonitorThread implements Runnable {

    Utils utils = new Utils();
    @Override
    public void run() {


        while(true){
            if(MerkleManager.sMerkleRoot != null){
                //if there is a merkle root
                if(MerkleManager.sMerkleRoot.equals(MerkleManager.sEnteredExpectedRoot)){
                    utils.print("You Win: " +MerkleManager.sMerkleRoot);
                    System.exit(0);
                }
                else {
                    utils.print("The roots don't match: You lose! ");

                    /*---------------------DEBUG TESTS------------------- */
                    utils.printList(MerkleThread.grabbedWords); // DEBUG: test print to see what's in my ArrayList
                    utils.print("Actual Root: " +MerkleManager.sMerkleRoot ); // DEBUG: test print to see what the actual merkle root value is
                    utils.print("Your guessed root: " +MerkleManager.sEnteredExpectedRoot); //DEBUG: test print for users guess of merkle root

                    System.exit(0); // exit program
                }
            }
            else if(MerkleManager.iStrike == 3){
                utils.print("3 Strikes: you lost!");
                System.exit(0); // exit program
            }

            utils.sleep(1); //sleep the utils object to allow for updates
        }
    }
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote