├── .gitignore ├── README.md ├── contracts ├── MerkleTreeLib.sol ├── Migrations.sol ├── ShrubsMiMC.sol ├── ShrubsMiMCIncremental.sol └── ShrubsMiMCShrubs.sol ├── migrations ├── 1_initial_migration.js ├── 2_deploy_mimc.js ├── 3_deploy_shrubs_mimc.js ├── 4_deploy_shrubs_mimc_incremental.js └── 5_deploy_shrubs_mimc_shrubs.js ├── package-lock.json ├── package.json ├── scripts └── run_ganache.sh ├── snark └── shrubs.circom ├── test └── contracts │ └── shrubs.js └── truffle-config.js /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shrubs benchmarks 2 | 3 | * Run ganache using `scripts/run_ganache.sh` 4 | * Deploy contracts using `truffle migrate --reset --network=local` 5 | * Run benchmark using `truffle test/contracts/shrubs.js --network=local` 6 | -------------------------------------------------------------------------------- /contracts/MerkleTreeLib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | library MiMC { 4 | function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) pure public returns (uint256 xL, uint256 xR); 5 | } 6 | 7 | contract ShrubsTree { 8 | uint8 levels; 9 | // 0 = mimcsponge, 1 = sha256 10 | uint8 hasher; 11 | // 0 = shrubs, 1 = only on filled, 2 = always 12 | uint8 mode; 13 | 14 | uint256 root; 15 | uint256[] filled_subtrees; 16 | uint256[] zeros; 17 | 18 | uint32 next_index; 19 | 20 | uint256[] internal tree_leaves; 21 | 22 | event LeafAdded(uint256 leaf, uint32 leaf_index, uint256 gas_used, uint256 new_val); 23 | event LeafVerified(uint256 leaf, uint32 leaf_index, uint8 level, bool result); 24 | 25 | constructor(uint8 tree_levels, uint8 hasher_type, uint8 mode_type, uint256 zero_value) public { 26 | levels = tree_levels; 27 | hasher = hasher_type; 28 | mode = mode_type; 29 | 30 | zeros.push(zero_value); 31 | 32 | filled_subtrees.push(zeros[0]); 33 | 34 | for (uint8 i = 1; i < tree_levels; i++) { 35 | zeros.push(HashLeftRight(zeros[i-1], zeros[i-1])); 36 | filled_subtrees.push(zeros[i]); 37 | } 38 | 39 | if (mode > 0) { 40 | root = HashLeftRight(zeros[levels - 1], zeros[levels - 1]); 41 | } 42 | 43 | next_index = 0; 44 | } 45 | 46 | function HashLeftRight(uint256 left, uint256 right) public returns (uint256 hash) { 47 | if (hasher == 0) { 48 | uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617; 49 | uint256 R = 0; 50 | uint256 C = 0; 51 | 52 | R = addmod(R, left, k); 53 | (R, C) = MiMC.MiMCSponge(R, C, 0); 54 | 55 | R = addmod(R, right, k); 56 | (R, C) = MiMC.MiMCSponge(R, C, 0); 57 | 58 | hash = R; 59 | } else { 60 | hash = uint256(sha256(abi.encodePacked(uint256(left), uint256(right)))); 61 | } 62 | } 63 | 64 | function insert(uint256 leaf) internal { 65 | uint256 start_gas = gasleft(); 66 | 67 | uint32 leaf_index = next_index; 68 | uint32 current_index = next_index; 69 | next_index += 1; 70 | 71 | uint256 current_level_hash = leaf; 72 | uint256 left; 73 | uint256 right; 74 | 75 | bool all_were_right = true; 76 | for (uint8 i = 0; i < levels; i++) { 77 | if (current_index % 2 == 0) { 78 | left = current_level_hash; 79 | right = zeros[i]; 80 | 81 | if (mode != 1 || (mode == 1 && all_were_right)) { 82 | filled_subtrees[i] = current_level_hash; 83 | } 84 | all_were_right = false; 85 | if (mode == 0) { 86 | break; 87 | } 88 | } else { 89 | left = filled_subtrees[i]; 90 | right = current_level_hash; 91 | } 92 | 93 | current_level_hash = HashLeftRight(left, right); 94 | 95 | current_index /= 2; 96 | } 97 | 98 | if (mode > 0) { 99 | root = current_level_hash; 100 | } 101 | 102 | tree_leaves.push(leaf); 103 | uint256 gas_used = start_gas - gasleft(); 104 | 105 | emit LeafAdded(leaf, leaf_index, gas_used, current_level_hash); 106 | } 107 | 108 | function verify(uint256 leaf, uint256[] memory path, uint32 leaf_index) internal { 109 | uint32 current_index = leaf_index; 110 | uint256 current_level_hash = leaf; 111 | uint256 left; 112 | uint256 right; 113 | for (uint8 i = 0; i < levels; i++) { 114 | if (mode == 0 && filled_subtrees[i] == current_level_hash) { 115 | emit LeafVerified(leaf, leaf_index, i, true); 116 | return; 117 | } 118 | if (current_index % 2 == 0) { 119 | left = current_level_hash; 120 | right = path[i]; 121 | } else { 122 | left = path[i]; 123 | right = current_level_hash; 124 | } 125 | 126 | current_level_hash = HashLeftRight(left, right); 127 | 128 | current_index /= 2; 129 | } 130 | 131 | emit LeafVerified(leaf, leaf_index, levels, root == current_level_hash); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/ShrubsMiMC.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./MerkleTreeLib.sol"; 4 | 5 | contract ShrubsMiMC is ShrubsTree { 6 | constructor(uint8 tree_levels, uint256 zero_value) ShrubsTree(tree_levels, 0, 2, 0) public { 7 | } 8 | 9 | function insertCommitment(uint256 commitment) public { 10 | insert(commitment); 11 | } 12 | 13 | function verifyCommitment(uint256 commitment, uint256[] memory path, uint32 leaf_index) public { 14 | verify(commitment, path, leaf_index); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/ShrubsMiMCIncremental.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./MerkleTreeLib.sol"; 4 | 5 | contract ShrubsMiMCIncremental is ShrubsTree { 6 | constructor(uint8 tree_levels, uint256 zero_value) ShrubsTree(tree_levels, 0, 1, 0) public { 7 | } 8 | 9 | function insertCommitment(uint256 commitment) public { 10 | insert(commitment); 11 | } 12 | 13 | function verifyCommitment(uint256 commitment, uint256[] memory path, uint32 leaf_index) public { 14 | verify(commitment, path, leaf_index); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/ShrubsMiMCShrubs.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./MerkleTreeLib.sol"; 4 | 5 | contract ShrubsMiMCShrubs is ShrubsTree { 6 | constructor(uint8 tree_levels, uint256 zero_value) ShrubsTree(tree_levels, 0, 0, 0) public { 7 | } 8 | 9 | function insertCommitment(uint256 commitment) public { 10 | insert(commitment); 11 | } 12 | 13 | function verifyCommitment(uint256 commitment, uint256[] memory path, uint32 leaf_index) public { 14 | verify(commitment, path, leaf_index); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = (deployer) => { 4 | return deployer.then( async () => { 5 | await deployer.deploy(Migrations); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /migrations/2_deploy_mimc.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const mimcGenContract = require('circomlib/src/mimcsponge_gencontract.js'); 4 | const Artifactor = require('truffle-artifactor'); 5 | 6 | const SEED = 'mimcsponge'; 7 | 8 | 9 | module.exports = function(deployer) { 10 | return deployer.then( async () => { 11 | const contractsDir = path.join(__dirname, '..', 'build/contracts'); 12 | let artifactor = new Artifactor(contractsDir); 13 | let mimcContractName = 'MiMC'; 14 | await artifactor.save({ 15 | contractName: mimcContractName, 16 | abi: mimcGenContract.abi, 17 | unlinked_binary: mimcGenContract.createCode(SEED, 220), 18 | }) 19 | .then(async () => { 20 | const MiMC = artifacts.require(mimcContractName); 21 | await deployer.deploy(MiMC); 22 | }); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /migrations/3_deploy_shrubs_mimc.js: -------------------------------------------------------------------------------- 1 | const MiMC = artifacts.require('MiMC'); 2 | const ShrubsMiMC = artifacts.require('ShrubsMiMC'); 3 | 4 | module.exports = function(deployer) { 5 | return deployer.then( async () => { 6 | await deployer.link(MiMC, ShrubsMiMC); 7 | await deployer.deploy(ShrubsMiMC, 20, 0); 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /migrations/4_deploy_shrubs_mimc_incremental.js: -------------------------------------------------------------------------------- 1 | const MiMC = artifacts.require('MiMC'); 2 | const ShrubsMiMCIncremental = artifacts.require('ShrubsMiMCIncremental'); 3 | 4 | module.exports = function(deployer) { 5 | return deployer.then( async () => { 6 | await deployer.link(MiMC, ShrubsMiMCIncremental); 7 | await deployer.deploy(ShrubsMiMCIncremental, 20, 0); 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /migrations/5_deploy_shrubs_mimc_shrubs.js: -------------------------------------------------------------------------------- 1 | const MiMC = artifacts.require('MiMC'); 2 | const ShrubsMiMCShrubs = artifacts.require('ShrubsMiMCShrubs'); 3 | 4 | module.exports = function(deployer) { 5 | return deployer.then( async () => { 6 | await deployer.link(MiMC, ShrubsMiMCShrubs); 7 | await deployer.deploy(ShrubsMiMCShrubs, 20, 0); 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zkp-shrubs", 3 | "version": "0.1.0", 4 | "description": "Shrubs", 5 | "main": "index.js", 6 | "author": "Kobi Gurkan", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/celo-org/shrubs.git" 11 | }, 12 | "dependencies": { 13 | "blakejs": "^1.1.0", 14 | "circom": "0.0.33", 15 | "circomlib": "0.0.18", 16 | "cors": "^2.8.5", 17 | "del": "^4.1.0", 18 | "ethers": "^4.0.33", 19 | "file-saver": "^2.0.1", 20 | "ganache-cli": "^6.4.1", 21 | "ganache-core": "^2.5.3", 22 | "html-webpack-plugin": "^3.2.0", 23 | "mocha": "^6.0.2", 24 | "node-fetch": "^2.3.0", 25 | "require-nocache": "^1.0.0", 26 | "semaphore-merkle-tree": "1.0.6", 27 | "snarkjs": "0.1.17", 28 | "truffle": "^5.0.10", 29 | "truffle-artifactor": "^4.0.10", 30 | "truffle-contract": "^4.0.11", 31 | "truffle-hdwallet-provider": "^1.0.0-web3one.5", 32 | "truffle-privatekey-provider": "^1.1.0", 33 | "web3": "^1.0.0-beta.51", 34 | "webpack": "^4.30.0", 35 | "websnark": "0.0.5", 36 | "winston": "^3.2.1" 37 | }, 38 | "devDependencies": { 39 | "npm-update-git-deps": "^1.2.4", 40 | "null-loader": "^0.1.1", 41 | "webpack-cli": "^3.3.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/run_ganache.sh: -------------------------------------------------------------------------------- 1 | ../node_modules/.bin/ganache-cli -p 7545 -l 8800000 -i 5777 --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,100000000000000000000000000' --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd22,10000000000000000000000000' -q 2 | 3 | -------------------------------------------------------------------------------- /snark/shrubs.circom: -------------------------------------------------------------------------------- 1 | include "../node_modules/circomlib/circuits/pedersen.circom"; 2 | include "../node_modules/circomlib/circuits/mimcsponge.circom"; 3 | include "../node_modules/circomlib/circuits/bitify.circom"; 4 | include "../node_modules/circomlib/circuits/eddsamimcsponge.circom"; 5 | include "./blake2s/blake2s.circom"; 6 | 7 | template HashLeftRight(n_rounds) { 8 | signal input left; 9 | signal input right; 10 | 11 | signal output hash; 12 | 13 | component hasher = MiMCSponge(2, n_rounds, 1); 14 | left ==> hasher.ins[0]; 15 | right ==> hasher.ins[1]; 16 | hasher.k <== 0; 17 | 18 | hash <== hasher.outs[0]; 19 | } 20 | 21 | template Selector() { 22 | signal input input_elem; 23 | signal input path_elem; 24 | signal input path_index; 25 | 26 | signal output left; 27 | signal output right; 28 | 29 | signal left_selector_1; 30 | signal left_selector_2; 31 | signal right_selector_1; 32 | signal right_selector_2; 33 | 34 | path_index * (1-path_index) === 0 35 | 36 | left_selector_1 <== (1 - path_index)*input_elem; 37 | left_selector_2 <== (path_index)*path_elem; 38 | right_selector_1 <== (path_index)*input_elem; 39 | right_selector_2 <== (1 - path_index)*path_elem; 40 | 41 | left <== left_selector_1 + left_selector_2; 42 | right <== right_selector_1 + right_selector_2; 43 | } 44 | 45 | template Semaphore(jubjub_field_size, n_levels, n_rounds) { 46 | // BEGIN signals 47 | 48 | signal input signal_hash; 49 | signal input external_nullifier; 50 | 51 | signal private input fake_zero; 52 | 53 | fake_zero === 0; 54 | 55 | // mimc vector commitment 56 | signal private input identity_pk[2]; 57 | signal private input identity_nullifier; 58 | signal private input identity_trapdoor; 59 | signal private input identity_path_elements[n_levels]; 60 | signal private input identity_path_index[n_levels]; 61 | 62 | // signature on (external nullifier, signal_hash) with identity_pk 63 | signal private input auth_sig_r[2]; 64 | signal private input auth_sig_s; 65 | 66 | // get a prime subgroup element derived from identity_pk 67 | component dbl1 = BabyDbl(); 68 | dbl1.x <== identity_pk[0]; 69 | dbl1.y <== identity_pk[1]; 70 | component dbl2 = BabyDbl(); 71 | dbl2.x <== dbl1.xout; 72 | dbl2.y <== dbl1.yout; 73 | component dbl3 = BabyDbl(); 74 | dbl3.x <== dbl2.xout; 75 | dbl3.y <== dbl2.yout; 76 | 77 | // mimc hash 78 | signal output root; 79 | signal output nullifiers_hash; 80 | 81 | // END signals 82 | 83 | 84 | component identity_nullifier_bits = Num2Bits(248); 85 | identity_nullifier_bits.in <== identity_nullifier; 86 | 87 | component identity_trapdoor_bits = Num2Bits(248); 88 | identity_trapdoor_bits.in <== identity_trapdoor; 89 | 90 | component identity_pk_0_bits = Num2Bits_strict(); 91 | identity_pk_0_bits.in <== dbl3.xout; 92 | 93 | component identity_commitment = Pedersen(3*256); 94 | // BEGIN identity commitment 95 | for (var i = 0; i < 256; i++) { 96 | if (i < 254) { 97 | identity_commitment.in[i] <== identity_pk_0_bits.out[i]; 98 | } else { 99 | identity_commitment.in[i] <== 0; 100 | } 101 | 102 | if (i < 248) { 103 | identity_commitment.in[i + 256] <== identity_nullifier_bits.out[i]; 104 | identity_commitment.in[i + 2*256] <== identity_trapdoor_bits.out[i]; 105 | } else { 106 | identity_commitment.in[i + 256] <== 0; 107 | identity_commitment.in[i + 2*256] <== 0; 108 | } 109 | } 110 | // END identity commitment 111 | 112 | // BEGIN tree 113 | component selectors[n_levels]; 114 | component hashers[n_levels]; 115 | 116 | for (var i = 0; i < n_levels; i++) { 117 | selectors[i] = Selector(); 118 | hashers[i] = HashLeftRight(n_rounds); 119 | 120 | identity_path_index[i] ==> selectors[i].path_index; 121 | identity_path_elements[i] ==> selectors[i].path_elem; 122 | 123 | selectors[i].left ==> hashers[i].left; 124 | selectors[i].right ==> hashers[i].right; 125 | } 126 | 127 | identity_commitment.out[0] ==> selectors[0].input_elem; 128 | 129 | for (var i = 1; i < n_levels; i++) { 130 | hashers[i-1].hash ==> selectors[i].input_elem; 131 | } 132 | 133 | root <== hashers[n_levels - 1].hash; 134 | // END tree 135 | 136 | // BEGIN nullifiers 137 | component external_nullifier_bits = Num2Bits(232); 138 | external_nullifier_bits.in <== external_nullifier; 139 | 140 | component nullifiers_hasher = Blake2s(512, 0); 141 | for (var i = 0; i < 248; i++) { 142 | nullifiers_hasher.in_bits[i] <== identity_nullifier_bits.out[i]; 143 | } 144 | 145 | for (var i = 0; i < 232; i++) { 146 | nullifiers_hasher.in_bits[248 + i] <== external_nullifier_bits.out[i]; 147 | } 148 | 149 | for (var i = 0; i < n_levels; i++) { 150 | nullifiers_hasher.in_bits[248 + 232 + i] <== identity_path_index[i]; 151 | } 152 | 153 | for (var i = (248 + 232 + n_levels); i < 512; i++) { 154 | nullifiers_hasher.in_bits[i] <== 0; 155 | } 156 | 157 | component nullifiers_hash_num = Bits2Num(253); 158 | for (var i = 0; i < 253; i++) { 159 | nullifiers_hash_num.in[i] <== nullifiers_hasher.out[i]; 160 | } 161 | 162 | nullifiers_hash <== nullifiers_hash_num.out; 163 | 164 | // END nullifiers 165 | 166 | // BEGIN verify sig 167 | component msg_hasher = MiMCSponge(2, n_rounds, 1); 168 | msg_hasher.ins[0] <== external_nullifier; 169 | msg_hasher.ins[1] <== signal_hash; 170 | msg_hasher.k <== 0; 171 | 172 | component sig_verifier = EdDSAMiMCSpongeVerifier(); 173 | (1 - fake_zero) ==> sig_verifier.enabled; 174 | identity_pk[0] ==> sig_verifier.Ax; 175 | identity_pk[1] ==> sig_verifier.Ay; 176 | auth_sig_r[0] ==> sig_verifier.R8x; 177 | auth_sig_r[1] ==> sig_verifier.R8y; 178 | auth_sig_s ==> sig_verifier.S; 179 | msg_hasher.outs[0] ==> sig_verifier.M; 180 | 181 | // END verify sig 182 | } 183 | -------------------------------------------------------------------------------- /test/contracts/shrubs.js: -------------------------------------------------------------------------------- 1 | const BN = require('bn.js'); 2 | const chai = require('chai'); 3 | 4 | const crypto = require('crypto'); 5 | const fs = require('fs'); 6 | const del = require('del'); 7 | const path = require('path'); 8 | 9 | const snarkjs = require('snarkjs'); 10 | const circomlib = require('circomlib'); 11 | 12 | const ethers = require('ethers'); 13 | 14 | const bigInt = snarkjs.bigInt; 15 | 16 | const mimcsponge = circomlib.mimcsponge; 17 | 18 | const assert = chai.assert; 19 | 20 | const ShrubsMiMC = artifacts.require('ShrubsMiMC'); 21 | const ShrubsMiMCIncremental = artifacts.require('ShrubsMiMCIncremental'); 22 | const ShrubsMiMCShrubs = artifacts.require('ShrubsMiMCShrubs'); 23 | 24 | const SemaphoreMerkleTree = require('semaphore-merkle-tree') 25 | const MemStorage = SemaphoreMerkleTree.storage.MemStorage 26 | const MerkleTree = SemaphoreMerkleTree.tree.MerkleTree 27 | const MimcSpongeHasher = SemaphoreMerkleTree.hashers.MimcSpongeHasher 28 | const Sha256Hasher = SemaphoreMerkleTree.hashers.Sha256Hasher 29 | 30 | async function testTree(hasher, shrubs) { 31 | const accounts = await web3.eth.getAccounts(); 32 | 33 | const default_value = '0'; 34 | const memStorage = new MemStorage(); 35 | const prefix = 'shrubs'; 36 | 37 | const memTree = new MerkleTree( 38 | prefix, 39 | memStorage, 40 | hasher, 41 | 20, 42 | default_value, 43 | ); 44 | 45 | const num_commitments = 16; 46 | for (let i = 0; i < num_commitments; i++) { 47 | const commitment = bigInt(`${i}`); 48 | const receipt = await shrubs.insertCommitment(commitment.toString()); 49 | assert.equal(receipt.logs[0].event, 'LeafAdded'); 50 | console.log(`gas used for commitment ${i}: `, receipt.logs[0].args.gas_used.toString()); 51 | const next_index = parseInt(receipt.logs[0].args.leaf_index.toString()); 52 | await memTree.update(next_index, commitment.toString()); 53 | } 54 | 55 | for (let i = 0; i < num_commitments; i++) { 56 | const commitment = bigInt(`${i}`); 57 | const mem_path = await memTree.path(i); 58 | const path_elements = mem_path.path_elements; 59 | const receipt = await shrubs.verifyCommitment(commitment.toString(), path_elements, i); 60 | assert.equal(receipt.logs[0].event, 'LeafVerified'); 61 | console.log(`level for commitment ${i}: `, receipt.logs[0].args.level.toString()); 62 | assert.equal(receipt.logs[0].args.result.toString(), 'true'); 63 | } 64 | } 65 | 66 | contract('ShrubsMiMC', function (accounts) { 67 | it('tests tree normal', async () => { 68 | const shrubs = await ShrubsMiMC.deployed(); 69 | const MimcSpongeHasher = SemaphoreMerkleTree.hashers.MimcSpongeHasher 70 | return testTree(new MimcSpongeHasher(), shrubs); 71 | }); 72 | }); 73 | 74 | contract('ShrubsMiMCIncremental', function (accounts) { 75 | it('tests tree incremental', async () => { 76 | const shrubs = await ShrubsMiMCIncremental.deployed(); 77 | const MimcSpongeHasher = SemaphoreMerkleTree.hashers.MimcSpongeHasher 78 | return testTree(new MimcSpongeHasher(), shrubs); 79 | }); 80 | }); 81 | 82 | contract('ShrubsMiMCShrubs', function (accounts) { 83 | it('tests tree shrubs', async () => { 84 | const shrubs = await ShrubsMiMCShrubs.deployed(); 85 | const MimcSpongeHasher = SemaphoreMerkleTree.hashers.MimcSpongeHasher 86 | return testTree(new MimcSpongeHasher(), shrubs); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura API 13 | * keys are available for free at: infura.io/register 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('truffle-hdwallet-provider'); 22 | // const infuraKey = "fj4jll3k....."; 23 | // 24 | // const fs = require('fs'); 25 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 26 | // 27 | var HDWalletProvider = require("truffle-hdwallet-provider"); 28 | var privateKey = "6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21"; 29 | 30 | module.exports = { 31 | /** 32 | * Networks define how you connect to your ethereum client and let you set the 33 | * defaults web3 uses to send transactions. If you don't specify one truffle 34 | * will spin up a development blockchain for you on port 9545 when you 35 | * run `develop` or `test`. You can ask a truffle command to use a specific 36 | * network from the command line, e.g 37 | * 38 | * $ truffle test --network 39 | */ 40 | 41 | networks: { 42 | // Useful for testing. The `development` name is special - truffle uses it by default 43 | // if it's defined here and no other network is specified at the command line. 44 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 45 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 46 | // options below to some value. 47 | // 48 | local: { 49 | host: "127.0.0.1", // Localhost (default: none) 50 | port: 7545, // Standard Ethereum port (default: none) 51 | network_id: "*", // Any network (default: none) 52 | gas: 8800000, 53 | }, 54 | goerli: { 55 | provider: () => new HDWalletProvider(privateKey, "https://goerli.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066"), 56 | network_id: 5, 57 | skipDryRun: true 58 | }, 59 | ropsten: { 60 | provider: () => new HDWalletProvider(privateKey, "https://ropsten.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066"), 61 | network_id: 3, 62 | skipDryRun: true 63 | }, 64 | rinkeby: { 65 | provider: () => { 66 | return new HDWalletProvider(privateKey, "https://rinkeby.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066"); 67 | }, 68 | gas: 7000000, 69 | network_id: 4, 70 | skipDryRun: true 71 | }, 72 | 73 | // Another network with more advanced options... 74 | // advanced: { 75 | // port: 8777, // Custom port 76 | // network_id: 1342, // Custom network 77 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 78 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 79 | // from:
, // Account to send txs from (default: accounts[0]) 80 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 81 | // }, 82 | 83 | // Useful for deploying to a public network. 84 | // NB: It's important to wrap the provider as a function. 85 | // ropsten: { 86 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/${infuraKey}`), 87 | // network_id: 3, // Ropsten's id 88 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 89 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 90 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 91 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 92 | // }, 93 | 94 | // Useful for private networks 95 | // private: { 96 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 97 | // network_id: 2111, // This network is yours, in the cloud. 98 | // production: true // Treats this network as if it was a public net. (default: false) 99 | // } 100 | }, 101 | 102 | // Set default mocha options here, use special reporters etc. 103 | mocha: { 104 | timeout: 1000000 105 | }, 106 | 107 | // Configure your compilers 108 | compilers: { 109 | solc: { 110 | version: "0.5.10", // Fetch exact version from solc-bin (default: truffle's version) 111 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 112 | // settings: { // See the solidity docs for advice about optimization and evmVersion 113 | // optimizer: { 114 | // enabled: false, 115 | // runs: 200 116 | // }, 117 | // evmVersion: "byzantium" 118 | // } 119 | } 120 | } 121 | } 122 | --------------------------------------------------------------------------------