Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored the merkle tree contracts and cleaned up the mimc contract #29

Merged
merged 5 commits into from
Jun 12, 2019
Merged
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
4 changes: 2 additions & 2 deletions pyClient/testMiMCHash.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
mimc_interface, tree_interface = zethContracts.compile_util_contracts()

# deploy MimC contract
mimc_instance = zethContracts.deploy_mimc_contract(mimc_interface)
mimc_instance, mimc_address = zethContracts.deploy_mimc_contract(mimc_interface)

# deploy MerkleTreeMiMCHash contract
tree_instance = zethContracts.deploy_tree_contract(tree_interface, 3)
tree_instance = zethContracts.deploy_tree_contract(tree_interface, 3, mimc_address)


# Harry code test vector: https://github.com/HarryR/ethsnarks/blob/master/src/test/test_mimc_hash.cpp
Expand Down
12 changes: 6 additions & 6 deletions pyClient/zethContracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ def compile_util_contracts():
path_to_pairing = os.path.join(contracts_dir, "Pairing.sol")
path_to_bytes = os.path.join(contracts_dir, "Bytes.sol")
path_to_mimc7 = os.path.join(contracts_dir, "MiMC7.sol")
path_to_tree = os.path.join(contracts_dir, "MerkleTreeMiMCHash.sol")
path_to_tree = os.path.join(contracts_dir, "MerkleTreeMiMC7.sol")
compiled_sol = compile_files([path_to_pairing, path_to_bytes, path_to_mimc7, path_to_tree])
mimc_interface = compiled_sol[path_to_mimc7 + ':' + "MiMC7"]
tree_interface = compiled_sol[path_to_tree + ':' + "MerkleTreeMiMCHash"]
tree_interface = compiled_sol[path_to_tree + ':' + "MerkleTreeMiMC7"]
return mimc_interface, tree_interface

# Deploy the verifier used with PGHR13
Expand Down Expand Up @@ -154,12 +154,12 @@ def deploy_mimc_contract(interface):
address=address,
abi=interface['abi']
)
return instance
return instance, address

# Deploy tree contract
def deploy_tree_contract(interface, depth):
def deploy_tree_contract(interface, depth, hasher_address):
contract = w3.eth.contract(abi=interface['abi'], bytecode=interface['bin'])
tx_hash = contract.constructor(depth).transact({'from':w3.eth.accounts[1]})
tx_hash = contract.constructor(hasher_address, depth).transact({'from':w3.eth.accounts[1]})
# Get tx receipt to get Mixer contract address
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash, 10000)
address = tx_receipt['contractAddress']
Expand Down Expand Up @@ -273,7 +273,7 @@ def parse_mix_call(mixer_instance, tx_receipt):

# Call the hash method of MiMC contract
def mimcHash(instance, m, iv):
return instance.functions.MiMCHash(m, iv).call()
return instance.functions.hash(m, iv).call()

# Return MimC merklee tree
def getTree(instance):
Expand Down
69 changes: 69 additions & 0 deletions zeth-contracts/contracts/BaseMerkleTree.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
pragma solidity ^0.5.0;

// Adapted from: https://github.com/zcash-hackworks/babyzoe

contract BaseMerkleTree {
// Index of the current node: Index to insert the next incoming commitment
uint currentNodeIndex;

// Array containing the 2^(depth) leaves of the merkle tree
// We can switch the leaves to be of type bytes and not bytes32
// to support digest of various size (eg: if we use different hash functions)
// That way we'd have a merkle tree for any type of hash function (that can be implemented
// as a precompiled contract for instance)
//
// Leaves is a 2D array
bytes32[] leaves; // Declared as a dynamic array, the bound is put in the constructor

// Depth of the merkle tree (should be set with the same depth set in the cpp prover)
uint depth;

// Number of leaves
uint nbLeaves;

// Debug only
event LogDebug(bytes32 message);

// Constructor
constructor(uint treeDepth) public {
depth = treeDepth;
nbLeaves = 2**depth;

// Initialize the merkle tree with zeroes in values
bytes32 zeroes;
for (uint i = 0; i < nbLeaves; i++) {
leaves.push(zeroes);
}
}

// Appends a commitment to the tree, and returns its address
function insert(bytes32 commitment) public returns (uint) {
// If this require fails => the merkle tree is full, we can't append leaves anymore
require(
currentNodeIndex < nbLeaves,
"Merkle tree full: Cannot append anymore"
);

leaves[currentNodeIndex] = commitment;
currentNodeIndex++;

// This address can be emitted to indicate the address of the commiment
// This is useful for the proof generation
return currentNodeIndex - 1;
}

// Function that is fundamental in order to enable a client to fetch the leaves and
// recompute the merkle tree to generate a proof (needs the merkle authentication path and the merkle tree root to be computed)
//
// Recomputing the merkle should not be necessary as it could be read directly from the smart contract state
// but we'll use this function for now
function getLeaves() public view returns (bytes32[] memory) { // returns the bytes32[] array of leaves
bytes32[] memory tmpLeaves = new bytes32[](nbLeaves);
for(uint i = 0; i < nbLeaves; i++) {
tmpLeaves[i] = leaves[i];
}

// Returns the array of leaves of the merkle tree
return tmpLeaves;
}
}
53 changes: 53 additions & 0 deletions zeth-contracts/contracts/MerkleTreeMiMC7.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
pragma solidity ^0.5.0;

import "./BaseMerkleTree.sol";
import "./MiMC7.sol";

contract MerkleTreeMiMC7 is BaseMerkleTree {
// Custom hash smart contract
MiMC7 public mimc7_hasher;

// Constructor
constructor(address hasher_address, uint treeDepth) BaseMerkleTree(treeDepth) public {
mimc7_hasher = MiMC7(hasher_address);
}

// This function is constrainted to be internal by the fact that we return a bytes[]
// If we want to make it public and use a stable version of the solidity compiler, we need
// to switch to bytes32[] (and thus only hash functions with digest of length < 256bits)
// would be supported in the merkle tree.
//
// Note: This function diverges a little bit from the standard implementations
// because we usually affect the node index 1 to the root and follow the convention
// to append 0 if we go left or 1 if we go right in the merkle tree
// However, here we start at the index 0 for the merkle tree
function getTree() public view returns (bytes32[] memory) {
uint nbNodes = 2**(depth + 1) - 1;
bytes32[] memory tmpTree = new bytes32[](nbNodes);
bytes32[] memory leftRightInput = new bytes32[](2);

// Dump the leaves in the right indexes in the tree
for (uint i = 0; i < nbLeaves; i++) {
tmpTree[(nbLeaves - 1) + i] = leaves[i];
}

// Compute the internal nodes of the merkle tree
for (uint i = nbLeaves - 2; i > 0; i--) {
leftRightInput[0] = tmpTree[i*2+1];
leftRightInput[1] = tmpTree[2*(i+1)];
tmpTree[i] = mimc7_hasher.hash(leftRightInput, 0);
}

// Compute the merkle root
leftRightInput[0] = tmpTree[1];
leftRightInput[1] = tmpTree[2];
tmpTree[0] = mimc7_hasher.hash(leftRightInput, 0);

return tmpTree;
}

// Returns the root of the merkle tree
function getRoot() public view returns(bytes32) {
return getTree()[0];
}
}
132 changes: 0 additions & 132 deletions zeth-contracts/contracts/MerkleTreeMiMCHash.sol

This file was deleted.

44 changes: 44 additions & 0 deletions zeth-contracts/contracts/MerkleTreeSha256.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
solidity ^0.5.0;

import "./BaseMerkleTree.sol";

contract MerkleTreeSha256 is BaseMerkleTree {
// Constructor
constructor(uint treeDepth) BaseMerkleTree(treeDepth) {
// Nothing
}

// This function is constrainted to be internal by the fact that we return a bytes[]
// If we want to make it public and use a stable version of the solidity compiler, we need
// to switch to bytes32[] (and thus only hash functions with digest of length < 256bits)
// would be supported in the merkle tree.
//
// Note: This function diverges a little bit from the standard implementations
// because we usually affect the node index 1 to the root and follow the convention
// to append 0 if we go left or 1 if we go right in the merkle tree
// However, here we start at the index 0 for the merkle tree
function getTree() public view returns (bytes32[] memory) {
uint nbNodes = 2**(depth + 1) - 1;
bytes32[] memory tmpTree = new bytes32[](nbNodes);

// Dump the leaves in the right indexes in the tree
for (uint i = 0; i < nbLeaves; i++) {
tmpTree[(nbLeaves - 1) + i] = leaves[i];
}

// Compute the internal nodes of the merkle tree
for (uint i = nbLeaves - 2; i > 0; i--) {
tmpTree[i] = sha256(abi.encodePacked(tmpTree[i*2+1], tmpTree[2*(i+1)]));
}

// Compute the merkle root
tmpTree[0] = sha256(abi.encodePacked(tmpTree[1], tmpTree[2]));

return tmpTree;
}

// Returns the root of the merkle tree
function getRoot() public view returns(bytes32) {
return getTree()[0];
}
}
Loading