Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/main/java/crypto/Sha3256Hasher.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Sha3256Hash computeHash(byte[] bytes) {
}

/**
* Commutative hashing of two given byte arrays.
* Hashing of two given byte arrays.
*
* @param b1 first byte array.
* @param b2 second byte array.
Expand All @@ -73,6 +73,13 @@ public Sha3256Hash computeHash(byte[] b1, byte[] b2) {
}
}

/**
* Hashing of two SHA3-256 hash objects.
*
* @param h1 first SHA3-256 hash object.
* @param h2 second SHA3-256 hash object.
* @return SHA3-256 hash object of the concatenation of the two SHA3-256 hash objects.
*/
public Sha3256Hash computeHash(Sha3256Hash h1, Sha3256Hash h2) {
return computeHash(h1.getBytes(), h2.getBytes());
}
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/model/lightchain/Direction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package model.lightchain;

import java.io.Serializable;

/**
* Represents the semantic of direction that is used for
* traversing data structures, e.g., Merkle trees.
* A Direction can be either LEFT or RIGHT.
*/
public class Direction implements Serializable {
/**
* The value of the direction; either "Left" or "Right".
*/
private final String value;

/**
* The public static instances of Left direction.
*/
public static final Direction LEFT = new Direction("Left");

/**
* The public static instances of Right direction.
*/
public static final Direction RIGHT = new Direction("Right");

/**
* Constructor.
*
* @param value The value of the direction; either "Left" or "Right".
*/
private Direction(String value) {
this.value = value;
}

/**
* Returns true if the direction is RIGHT.
*
* @return true if the direction is RIGHT.
*/
public boolean isRight() {
return this == RIGHT;
}

/**
* Returns true if the direction is LEFT.
*
* @return true if the direction is LEFT.
*/
public boolean isLeft() {
return this == LEFT;
}

@Override
public String toString() {
return value;
}
}
36 changes: 34 additions & 2 deletions src/main/java/model/lightchain/Identifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@ private static String pretty(byte[] identifier) {
return Multibase.encode(Multibase.Base.Base58BTC, identifier);
}

/**
* Converts a bit string to an identifier.
*
* @param bitString a bit string of length 256.
* @return an identifier.
*/
public static Identifier bitStringToIdentifier(String bitString) {
if (bitString.length() != 8 * Size) {
throw new IllegalArgumentException("Bit string must be 256 bits long");
}

byte[] bytes = new byte[Size];
for (int i = 0; i < Size; i++) {
String byteString = bitString.substring(i * 8, (i + 1) * 8);
bytes[i] = (byte) Integer.parseInt(byteString, 2);
}

return new Identifier(bytes);
}

/**
* Returns if objects equal.
*
Expand Down Expand Up @@ -91,6 +111,19 @@ public byte[] getBytes() {
return this.value.clone();
}

/**
* Returns the bit representation of the identifier.
*
* @return the bit representation of the identifier as a string.
*/
public String getBitString() {
StringBuilder bits = new StringBuilder();
for (byte b : this.value) {
bits.append(String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0'));
}
return bits.toString();
}

/**
* Returns string representation of identifier in Base58BTC.
*
Expand All @@ -104,8 +137,7 @@ public String toString() {
* Compares this identifier with the other identifier.
*
* @param other represents other identifier to compared to.
* @return 0 if two identifiers are equal, 1 if this identifier is greater than other,
* -1 if other identifier is greater than this.
* @return 0 if two identifiers are equal, 1 if this identifier is greater than other, -1 if other identifier is greater than this.
*/
public int comparedTo(Identifier other) {
int result = Arrays.compare(this.value, other.value);
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/modules/ads/AuthenticatedDataStructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,28 @@
* Models AuthenticatedDataStructure (ADS) and a key-value store of entities supported with membership proofs.
*/
public interface AuthenticatedDataStructure {
/**
* Adds an entity to the ADS.
*
* @param e the entity to add
*
* @return AuthenticatedEntity containing the entity and its membership proof
*/
AuthenticatedEntity put(Entity e);

/**
* Returns the AuthenticatedEntity corresponding to the given identifier.
*
* @param id the identifier of the entity to retrieve
*
* @return the AuthenticatedEntity corresponding to the given identifier
*/
AuthenticatedEntity get(Identifier id);

/**
* Returns the size of the ADS.
*
* @return the size of the ADS
*/
int size();
}
11 changes: 4 additions & 7 deletions src/main/java/modules/ads/MembershipProof.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package modules.ads;

import java.util.ArrayList;

import model.crypto.Sha3256Hash;
import modules.ads.merkletree.MerklePath;

/**
* Represents a Merkle Proof of membership against a certain root identifier.
Expand All @@ -16,11 +15,9 @@ public interface MembershipProof {
Sha3256Hash getRoot();

/**
* Returns the path of the proof of membership.
* Returns the merkle path of the proof of membership.
*
* @return path of the proof of membership.
* @return merkle path of the proof of membership.
*/
ArrayList<Sha3256Hash> getPath();

ArrayList<Boolean> getIsLeftNode();
MerklePath getMerklePath();
}
131 changes: 113 additions & 18 deletions src/main/java/modules/ads/merkletree/MerkleNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import model.Entity;
import model.crypto.Sha3256Hash;
import model.lightchain.Direction;

/**
* A node in the Merkle tree.
Expand All @@ -13,8 +14,8 @@ public class MerkleNode {
private MerkleNode left;
private MerkleNode right;
private MerkleNode parent;
private boolean isLeft;
private Sha3256Hash hash;
private Direction direction;
private Sha3256Hash rootHash;

/**
* Default constructor.
Expand All @@ -23,22 +24,52 @@ public MerkleNode() {
this.left = null;
this.right = null;
this.parent = null;
this.isLeft = false;
this.hash = null;
this.rootHash = new Sha3256Hash(new byte[32]);
}

/**
* Constructor with entity and isLeft.
*
* @param e input entity
* @param isLeft boolean that specifies if the node is left child or not
* @param e input entity
* @param direction whether the node is left child or right child of its parent.
*/
public MerkleNode(Entity e, boolean isLeft) {
public MerkleNode(Entity e, Direction direction) {
this.left = null;
this.right = null;
this.parent = null;
this.isLeft = isLeft;
this.hash = hasher.computeHash(e.id());
this.direction = direction;
this.rootHash = hasher.computeHash(e.id());
}

/**
* Constructor with parent and isLeft.
*
* @param parent the parent of the node
* @param direction boolean that specifies if the node is left child or not
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "parent is intentionally mutable externally")
public MerkleNode(MerkleNode parent, Direction direction) {
this.left = null;
this.right = null;
this.parent = parent;
this.direction = direction;
this.rootHash = new Sha3256Hash(new byte[32]);
}

/**
* Constructor with parent, isLeft and hash.
*
* @param parent the parent of the node
* @param direction whether the node is left child or right child of its parent.
* @param hash input hash of the entity corresponding to that node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "parent is intentionally mutable externally")
public MerkleNode(MerkleNode parent, Direction direction, Sha3256Hash hash) {
this.left = null;
this.right = null;
this.parent = parent;
this.direction = direction;
this.rootHash = hash;
}

/**
Expand All @@ -50,8 +81,8 @@ public MerkleNode(Sha3256Hash hash) {
this.left = null;
this.right = null;
this.parent = null;
this.isLeft = false;
this.hash = hash;
this.direction = null;
this.rootHash = hash;
}

/**
Expand All @@ -66,40 +97,75 @@ public MerkleNode(Sha3256Hash hash, MerkleNode left, MerkleNode right) {
this.left = left;
this.right = right;
this.parent = null;
this.isLeft = false;
this.hash = hash;
this.direction = null;
this.rootHash = hash;
}

/**
* Returns the left child of the node.
*
* @return the left child of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "internal representation is intentionally returned")
public MerkleNode getLeft() {
return left;
}

/**
* Returns the right child of the node.
*
* @return the right child of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "internal representation is intentionally returned")
public MerkleNode getRight() {
return right;
}

/**
* Returns the parent of the node.
*
* @return the parent of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "internal representation is intentionally returned")
public MerkleNode getParent() {
return parent;
}

/**
* Sets the parent of the node.
*
* @param parent the parent of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "parent is intentionally mutable externally")
public void setParent(MerkleNode parent) {
this.parent = parent;
}

public Sha3256Hash getHash() {
return hash;
/**
* Returns the hash corresponding to the node.
*
* @return the hash corresponding to the node
*/
public Sha3256Hash getRootHash() {
return rootHash;
}

/**
* Returns true if the node is a left child, false otherwise.
*
* @return true if the node is a left child, false otherwise
*/
public boolean isLeft() {
return isLeft;
return direction.isLeft();
}

public void setLeft(boolean isLeft) {
this.isLeft = isLeft;
/**
* Sets if the node is a left child.
*
* @param direction whether the node is left child or right child of its parent.
*/
public void setDirection(Direction direction) {
this.direction = direction;
}

/**
Expand All @@ -114,4 +180,33 @@ public MerkleNode getSibling() {
return parent.getLeft();
}
}

/**
* Sets the left child of the node.
*
* @param left the left child of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "left is intentionally mutable externally")
public void setLeftNode(MerkleNode left) {
this.left = left;
}

/**
* Sets the left child of the node.
*
* @param right the right child of the node
*/
@SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "right is intentionally mutable externally")
public void setRightNode(MerkleNode right) {
this.right = right;
}

/**
* Updates the hash of the node.
*/
public void updateHash() {
Sha3256Hash leftHash = left == null ? new Sha3256Hash(new byte[32]) : left.getRootHash();
Sha3256Hash rightHash = right == null ? new Sha3256Hash(new byte[32]) : right.getRootHash();
this.rootHash = hasher.computeHash(leftHash, rightHash);
}
}
Loading