Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
f2afee2
adds store interface
staheri14 Jan 8, 2022
fdce34f
adds implementation of store interface
staheri14 Jan 8, 2022
eee5ab6
exports all the fields, adds user id
staheri14 Jan 8, 2022
fbb3357
makes client an instance of user class
staheri14 Jan 8, 2022
08335af
adds operation type enum
staheri14 Jan 8, 2022
de5ef58
adds constructors
staheri14 Jan 8, 2022
b264fbb
implements util methods of totalNode and insertAll
staheri14 Jan 8, 2022
a5df036
defines equal and hashcode
staheri14 Jan 8, 2022
ba6f818
replaces string with operation type enum
staheri14 Jan 8, 2022
81926fb
renames the test class
staheri14 Jan 8, 2022
909d1a4
adds signature package and class
staheri14 Jan 9, 2022
c5163a5
implements the mocked signature unit
staheri14 Jan 9, 2022
12fd60c
updates users data type, introduces getverificationkey
staheri14 Jan 9, 2022
12d2f98
updates hash data type and its toString method
staheri14 Jan 9, 2022
8127770
an empty implementation of hash algorithm
staheri14 Jan 9, 2022
a30213c
exposes member fields, adds isLeaf utility function
staheri14 Jan 9, 2022
97490c5
implements mocked signature class
staheri14 Jan 9, 2022
362b13f
exposes user member fields, adds verification key field
staheri14 Jan 9, 2022
bec8831
initial implementation of push
staheri14 Jan 9, 2022
5b4df3f
revises test to match the new type of users
staheri14 Jan 9, 2022
23e15a4
Merge branch 'master' into integrita/server-side-push
staheri14 Jan 15, 2022
2c306fb
adds documentation and signature verification
staheri14 Jan 15, 2022
d9985d6
renames sign
staheri14 Jan 15, 2022
1b7c531
adds toLeaf
staheri14 Jan 15, 2022
6126882
removes redundant equals
staheri14 Jan 15, 2022
0ccec83
removes snake case names
staheri14 Jan 15, 2022
5c58ff9
fixes the name of HistoryTreeNodeTest
staheri14 Jan 15, 2022
8b219ed
invokes toLeaf
staheri14 Jan 15, 2022
7f6a01b
introduces cleanDigests
staheri14 Jan 15, 2022
f112c14
cleans tree digests
staheri14 Jan 15, 2022
230d44e
mock implementation of signature
staheri14 Jan 16, 2022
7567e86
adds signature unit test
staheri14 Jan 16, 2022
3c2009e
adds maxLevel method
staheri14 Jan 16, 2022
3ee862f
java doc
staheri14 Jan 16, 2022
492be4b
adds contains, updates cleanDigest to not update underlying hash map
staheri14 Jan 16, 2022
0250ffe
adds initHistoryTreeStore and testCleanTreeDigest
staheri14 Jan 16, 2022
6a6abee
fixes in-place hashmap update
staheri14 Jan 16, 2022
91fdbdf
finalizes CleanTreeDigest unit test
staheri14 Jan 16, 2022
63232e8
adds Server test class
staheri14 Jan 16, 2022
358a1a3
reorganization and javadoc
staheri14 Jan 16, 2022
9e1a4d1
adds test scenarios
staheri14 Jan 16, 2022
b0936c4
beatification and reorganising
staheri14 Jan 16, 2022
c8eb71d
check status is not nill
staheri14 Jan 16, 2022
495b7eb
adds insert method for user
staheri14 Jan 16, 2022
8f7a6bb
replaces map put function with custom function insert
staheri14 Jan 16, 2022
c5c344f
fixes formating problems
staheri14 Jan 16, 2022
69a132a
renames verification keys to vk
staheri14 Jan 16, 2022
042e771
unit test for the push
staheri14 Jan 16, 2022
59c52d4
unittest for unmatched node address
staheri14 Jan 16, 2022
be243e9
adds tests for toLabel
staheri14 Jan 22, 2022
de727ea
fixes a bug
staheri14 Jan 22, 2022
3d2aae8
add unit tests for input validation for push
staheri14 Jan 22, 2022
b2b24a5
unit test for not persisting the temporary nodes
staheri14 Jan 22, 2022
d185f84
revise a java doc
staheri14 Jan 22, 2022
c0c32bd
eraser of old tree digests
staheri14 Jan 22, 2022
653ed49
temp nodes that are tree digests should be stored
staheri14 Jan 22, 2022
835a20a
adds status getter
staheri14 Jan 22, 2022
7e6a3d6
checks the correct update of status
staheri14 Jan 22, 2022
b9d45a6
resolves linter issues
staheri14 Jan 22, 2022
6ddb0f8
WIP
staheri14 Jan 23, 2022
8b7097b
adds contains methods
staheri14 Jan 23, 2022
5d15c71
adds test for contains method
staheri14 Jan 23, 2022
acbf6be
changes get signature
staheri14 Jan 23, 2022
9de462e
adds totalUsers util
staheri14 Jan 23, 2022
3a0d0f3
checks if user exists before accessing it
staheri14 Jan 23, 2022
145d80c
adds unit test for user related methods
staheri14 Jan 23, 2022
44a4af4
updates get user input type
staheri14 Jan 23, 2022
448c618
adds test macro
staheri14 Jan 23, 2022
cf924e0
unit test for insertAllUsers
staheri14 Jan 23, 2022
f0eaa6e
adds pull algorithm
staheri14 Jan 30, 2022
e77e874
deletes incomplete tests
staheri14 Jan 30, 2022
0ed1ed0
deletes hash code
staheri14 Jan 30, 2022
de59939
comment for vk
staheri14 Jan 30, 2022
a7701d6
resolves linter issues
staheri14 Jan 30, 2022
006f5f6
Merge branch 'integrita/server-side-push' into integrita/cleanup-data…
staheri14 Jan 30, 2022
0682862
resolves linter errors
staheri14 Jan 30, 2022
0576329
java doc for pull method
staheri14 Jan 30, 2022
5e8ea94
adds pull test
staheri14 Jan 30, 2022
5c76a6f
Merge branch 'integrita/cleanup-database-interface' into integrita/se…
staheri14 Jan 30, 2022
96b5ff2
fixes linter errors
staheri14 Jan 30, 2022
7200ebb
adds todo
staheri14 Jan 30, 2022
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
3 changes: 2 additions & 1 deletion src/main/java/scenario/integrita/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import node.BaseNode;
import scenario.integrita.events.Push;
import scenario.integrita.historytree.HistoryTreeNode;
import scenario.integrita.user.User;


/**
* Integrita client implementation.
*/
public class Client implements BaseNode {
public class Client extends User implements BaseNode {
UUID id;
MiddleLayer network;
ArrayList<UUID> ids; // all ids inclding self
Expand Down
146 changes: 142 additions & 4 deletions src/main/java/scenario/integrita/Server.java
Original file line number Diff line number Diff line change
@@ -1,42 +1,180 @@
package scenario.integrita;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;

import groovy.lang.Tuple;
import metrics.MetricsCollector;
import network.MiddleLayer;
import network.packets.Event;
import node.BaseNode;
import scenario.integrita.database.HistoryTreeStore;
import scenario.integrita.events.PushResp;
import scenario.integrita.historytree.HistoryTreeNode;
import scenario.integrita.historytree.NodeAddress;
import scenario.integrita.signature.Signature;
import scenario.integrita.user.User;
import scenario.integrita.utils.StatusCode;

/**
* Integrita server implementation.
*/
public class Server implements BaseNode {
// Integrita related fields
int index; // server's index
int totalServers; // total number of servers
byte[] vk; // server's verification key
byte[] sk; // server's signature key
HistoryTreeStore db;
NodeAddress status; // the last node address seen by the server

// simulator related properties
UUID id;
MiddleLayer network;
ArrayList<UUID> ids; // all ids including self
HashMap<NodeAddress, HistoryTreeNode> db = new HashMap<>();
// all UUIDs including self
ArrayList<UUID> ids;

// Constructors -------------------------------------------------------------------------

/**
* Constructor.
*/
public Server() {
}

/**
* Constructor.
*/
public Server(UUID selfId, MiddleLayer network) {
this.id = selfId;
this.network = network;
}

/**
* Constructor.
*/
public Server(int index, int totalServers) {
this.index = index;
this.totalServers = totalServers;

this.db = new HistoryTreeStore();

// generate signature keys
byte[][] keys = Signature.keyGen();
this.sk = keys[0];
this.vk = keys[1];
}

// getters and setters ---------------------

public NodeAddress getStatus() {
// TODO add signature
return status;
}

// Integrita RPCs ---------------------------------------------------------------------

/**
* receives a HistoryTreeNode and updates its local db accordingly.
*/
public Tuple push(HistoryTreeNode historyTreeNode) {
// @TODO check the user membership via signature

// check whether the node is submitted to the right server
int serverIndex = NodeAddress.mapServerIndex(historyTreeNode.addr, totalServers);
if (serverIndex != this.index) {
return new Tuple(new Object[]{StatusCode.Reject, null});
}

// the difference between the label of supplied node and the status of the server
// should be equal to the total number of servers
if (this.status != null) {
int diff = NodeAddress.toLabel(historyTreeNode.addr) - NodeAddress.toLabel(this.status);
if (diff != totalServers) {
return new Tuple(new Object[]{StatusCode.Reject, null});
}
}

// verify user-side signature on the leaf
// needed for the authorization
if (NodeAddress.isLeaf(historyTreeNode.addr)) {
// @TODO check the hash value
// @TODO retrieve user vk and verify the signature
byte[] vk = db.getVerificationKey(historyTreeNode.userId);
String msg = historyTreeNode.toLeaf();
boolean res = Signature.verify(msg, historyTreeNode.signature, vk);
if (res == false) {
return new Tuple(new Object[]{StatusCode.Reject, null});
}
}

// verify user-side signature on the tree digest
if (NodeAddress.isTreeDigest(historyTreeNode.addr)) {
// verify signature
String msg = historyTreeNode.toLeaf();
if (!Signature.verify(msg, historyTreeNode.signature, this.db.getVerificationKey(historyTreeNode.userId))) {
new Tuple(new Object[]{StatusCode.Reject, null});
}
}

// update the database just for non-temporary nodes
if (!NodeAddress.isTemporary(historyTreeNode.addr) || NodeAddress.isTreeDigest(historyTreeNode.addr)) {
db.insert(historyTreeNode);
}

// remove tree digests of the old operations
// except the first operation
db.cleanDigests(historyTreeNode.addr);

// update the state variable
this.status = historyTreeNode.addr;

// server should sign tree digests
if (NodeAddress.isTreeDigest(historyTreeNode.addr)) {
String msg = historyTreeNode.toLeaf();
byte[] signature = Signature.sign(msg, vk);
return new Tuple(new Object[]{StatusCode.Accept, signature});
}

// if nothing goes wrong, then the push request is done successfully
return new Tuple(new Object[]{StatusCode.Accept, null});
}

/**
* implements the pull algorithm based on Integrita specification.
* by this method, a user can retrieve a specific node of history tree from the server.
* The method returns a tuple, where the first item is the retrieve history tree node.
* The second item is a server-side signature in case that the retrieved node is a tree digest.
* Otherwise, the second item is null.
*/
public Tuple pull(User user, NodeAddress nodeAddress) {
// check whether user is authorized
if (!this.db.contains(user)) {
return new Tuple(new Object[]{null, null});
}

if (!this.db.contains(nodeAddress)) {
return new Tuple(new Object[]{null, null});
}

HistoryTreeNode res = this.db.get(nodeAddress);
byte[] singauture = new byte[0];
if (NodeAddress.isTreeDigest(nodeAddress)) {
singauture = Signature.sign(res.hash, this.sk);
}
return new Tuple(new Object[]{res, singauture});


}

// BaseNode interface implementation ---------------------------------------------------

@Override
public void onCreate(ArrayList<UUID> allId) {
this.ids = allId;
this.network.ready();
}

// BaseNode interface implementation ------------
@Override
public void onStart() {

Expand Down
107 changes: 91 additions & 16 deletions src/main/java/scenario/integrita/database/HistoryTreeStore.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package scenario.integrita.database;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.*;

import scenario.integrita.historytree.HistoryTreeNode;
import scenario.integrita.historytree.NodeAddress;
Expand All @@ -12,9 +11,10 @@
*/
public class HistoryTreeStore implements Store {

public HashMap<Integer, User> users;
public HashMap<NodeAddress, HistoryTreeNode> historyTreeNodes;
private final HashMap<Integer, User> users;
private final HashMap<NodeAddress, HistoryTreeNode> historyTreeNodes;

// constructor ----------------------------------------------
public HistoryTreeStore() {
this.users = new HashMap<>();
this.historyTreeNodes = new HashMap<>();
Expand All @@ -25,40 +25,115 @@ public HistoryTreeStore(HashMap<Integer, User> users, HashMap<NodeAddress, Histo
this.historyTreeNodes = historyTreeNodes;
}


// getters and setters ---------------------------
public byte[] getVerificationKey(int userIndex) {
return users.get(userIndex).verificationKey;
return users.get(userIndex).vk;
}

// utility methods -----------------------------
public int totalNodes() {
return this.historyTreeNodes.size();
}

public int totalUsers() {
return this.users.size();
}

/**
* adds all the users supplied by `users` to the `HistoryTreeStore` object.
*/
public boolean insertAllUsers(ArrayList<User> users) {
for (User u : users) {
this.insert(u);
}
return true;
}

/**
* inserts all the history nodes contained in the `historyTreeNodes` into the `HistoryTreeStore` instance.
*/
public boolean insertAllNodes(ArrayList<HistoryTreeNode> historyTreeNodes) {
for (HistoryTreeNode node : historyTreeNodes) {
this.insert(node);
}
return true;
}

/**
* erases all the past nodes whose `position` precede the position of the supplied `addr` exclusively.
*/
public void cleanDigests(NodeAddress addr) {
Set<NodeAddress> keySet = historyTreeNodes.keySet();
Iterator<Map.Entry<NodeAddress, HistoryTreeNode>> it = historyTreeNodes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<NodeAddress, HistoryTreeNode> entry = it.next();
boolean isTreeDigest = NodeAddress.isTreeDigest(entry.getKey());
if (isTreeDigest && (entry.getKey().position < addr.position) && (entry.getKey().position != 1)) {
it.remove();
}
}
}

// ------------------- store API -----------------

@Override
public boolean insert(HistoryTreeNode historyTreeNode) {
if (this.contains(historyTreeNode)) {
return false;
}
historyTreeNodes.put(historyTreeNode.addr, historyTreeNode);
return true;
}

@Override
public boolean insertAll(ArrayList<HistoryTreeNode> historyTreeNodes) {
for (HistoryTreeNode node : historyTreeNodes) {
this.insert(node);
}
public boolean insert(User user) {
// TODO check duplicates
users.put(user.id, user);
return true;
}

@Override
public HistoryTreeNode get(NodeAddress nodeAddress) {
return historyTreeNodes.get(nodeAddress);
}

@Override
public User get(Integer id) {
return users.get(id);
}

@Override
public boolean delete(NodeAddress nodeAddress) {
historyTreeNodes.remove(nodeAddress);
return true;
}

@Override
public HistoryTreeNode get(NodeAddress nodeAddress) {
// if (!historyTreeNodes.containsKey(nodeAddress)) {
// return null;
// }
return historyTreeNodes.get(nodeAddress);
public boolean delete(User user) {
users.remove(user.id);
return true;
}

public Integer totalNodes() {
return this.historyTreeNodes.size();
@Override
public boolean contains(User user) {
boolean exists = this.users.containsKey(user.id);
return exists;
}

@Override
public boolean contains(HistoryTreeNode historyTreeNode) {
boolean exists = this.historyTreeNodes.containsKey(historyTreeNode.addr);
return exists;
}

/**
* checks if nodeAddress belongs to HistoryTreeStore object.
*/
@Override
public boolean contains(NodeAddress nodeAddress) {
boolean exists = historyTreeNodes.containsKey(nodeAddress);
return exists;
}

}
17 changes: 13 additions & 4 deletions src/main/java/scenario/integrita/database/Store.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package scenario.integrita.database;

import java.util.ArrayList;

import scenario.integrita.historytree.HistoryTreeNode;
import scenario.integrita.historytree.NodeAddress;
import scenario.integrita.user.User;

/**
* storage api.
Expand All @@ -12,10 +11,20 @@ public interface Store {

boolean insert(HistoryTreeNode historyTreeNode);

boolean insertAll(ArrayList<HistoryTreeNode> historyTreeNodes);
boolean insert(User user);

HistoryTreeNode get(NodeAddress nodeAddress);

User get(Integer id);

boolean delete(NodeAddress nodeAddress);

HistoryTreeNode get(NodeAddress nodeAddress);
boolean delete(User user);

boolean contains(User user);

boolean contains(HistoryTreeNode historyTreeNode);

boolean contains(NodeAddress nodeAddress);

}
8 changes: 8 additions & 0 deletions src/main/java/scenario/integrita/hash/Hash.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package scenario.integrita.hash;

/**
* Hash implementation used in Merkle tree.
*/
public class Hash {

}
Loading