Skip to content

Commit

Permalink
refactor: update latest circuits
Browse files Browse the repository at this point in the history
  • Loading branch information
0xjei committed Apr 18, 2024
1 parent 0c8a9f0 commit 84a5736
Show file tree
Hide file tree
Showing 9 changed files with 538 additions and 432 deletions.
546 changes: 294 additions & 252 deletions circuits/circom/tallyVotes.circom

Large diffs are not rendered by default.

135 changes: 61 additions & 74 deletions circuits/circom/trees/incrementalMerkleTree.circom
Original file line number Diff line number Diff line change
@@ -1,126 +1,113 @@
pragma circom 2.0.0;

// Refer to:
// https://github.com/peppersec/tornado-mixer/blob/master/circuits/merkleTree.circom
// https://github.com/semaphore-protocol/semaphore/blob/audited/circuits/circom/semaphore-base.circom
// circomlib import
include "./mux1.circom";

// local import
include "../hasherPoseidon.circom";
include "../utils/hashers.circom";

// recompute a merkle root from a leaf and a path
/**
* Recomputes a Merkle root from a given leaf and its path in a Merkle tree.
*/
template MerkleTreeInclusionProof(n_levels) {
// The leaf node from which the Merkle root is calculated.
signal input leaf;
// Indices indicating left or right child for each level of the tree.
signal input path_index[n_levels];
// Sibling node values required to compute the hash at each level.
signal input path_elements[n_levels][1];
signal output root;

component hashers[n_levels];
component mux[n_levels];
signal output root;

// Stores the hash at each level starting from the leaf to the root.
signal levelHashes[n_levels + 1];
// Initialize the first level with the given leaf.
levelHashes[0] <== leaf;

for (var i = 0; i < n_levels; i++) {
// Should be 0 or 1
// Validate path_index to be either 0 or 1, ensuring no other values.
path_index[i] * (1 - path_index[i]) === 0;

hashers[i] = HashLeftRight();
mux[i] = MultiMux1(2);

mux[i].c[0][0] <== levelHashes[i];
mux[i].c[0][1] <== path_elements[i][0];
// Configure the multiplexer based on the path index for the current level.
var c[2][2] = [
[levelHashes[i], path_elements[i][0]],
[path_elements[i][0], levelHashes[i]]
];

mux[i].c[1][0] <== path_elements[i][0];
mux[i].c[1][1] <== levelHashes[i];
var mux[2] = MultiMux1(2)(
c,
path_index[i]
);

mux[i].s <== path_index[i];
hashers[i].left <== mux[i].out[0];
hashers[i].right <== mux[i].out[1];
var hasher = PoseidonHasher(2)([mux[0], mux[1]]);

levelHashes[i + 1] <== hashers[i].hash;
// Store the resulting hash as the next level's hash.
levelHashes[i + 1] <== hasher;
}

// Set the final level hash as the root.
root <== levelHashes[n_levels];
}

// Ensures that a leaf exists within a merkletree with given `root`
/**
* Ensures that a leaf exists within a Merkle tree with a given root.
*/
template LeafExists(levels){

// levels is depth of tree
// The leaf whose existence within the tree is being verified.
signal input leaf;

// The elements along the path needed for the inclusion proof.
signal input path_elements[levels][1];
// The indices indicating the path taken through the tree for the leaf.
signal input path_index[levels];

// The root of the Merkle tree, against which the inclusion is verified.
signal input root;

component merkletree = MerkleTreeInclusionProof(levels);
merkletree.leaf <== leaf;
for (var i = 0; i < levels; i++) {
merkletree.path_index[i] <== path_index[i];
merkletree.path_elements[i][0] <== path_elements[i][0];
}
var merkletree = MerkleTreeInclusionProof(levels)(
leaf,
path_index,
path_elements
);

root === merkletree.root;
root === merkletree;
}

// Given a Merkle root and a list of leaves, check if the root is the
// correct result of inserting all the leaves into the tree (in the given
// order)
/**
* Verifies the correct construction of a Merkle tree from a set of leaves.
* Given a Merkle root and a list of leaves, check if the root is the
* correct result of inserting all the leaves into the tree (in the given order).
*/
template CheckRoot(levels) {
// Circom has some perticularities which limit the code patterns we can
// use.

// You can only assign a value to a signal once.

// A component's input signal must only be wired to another component's output
// signal.

// Variables are only used for loops, declaring sizes of things, and anything
// that is not related to inputs of a circuit.

// The total number of leaves
// The total number of leaves in the Merkle tree, calculated as 2 to the power of `levels`.
var totalLeaves = 2 ** levels;

// The number of HashLeftRight components which will be used to hash the
// leaves
// The number of first-level hashers needed, equal to half the total leaves, as each hasher combines two leaves.
var numLeafHashers = totalLeaves / 2;

// The number of HashLeftRight components which will be used to hash the
// output of the leaf hasher components
// The number of intermediate hashers, one less than the number of leaf hashers,
// as each level of hashing reduces the number of hash elements by about half.
var numIntermediateHashers = numLeafHashers - 1;

// Inputs to the snark
// Array of leaf values input to the circuit.
signal input leaves[totalLeaves];

// The output
// Output signal for the Merkle root that results from hashing all the input leaves.
signal output root;

// The total number of hashers
// Total number of hashers used in constructing the tree, one less than the total number of leaves,
// since each level of the tree combines two elements into one.
var numHashers = totalLeaves - 1;
component hashers[numHashers];

// Instantiate all hashers
var i;
for (i=0; i < numHashers; i++) {
hashers[i] = HashLeftRight();
}
var hashers[numHashers];

// Wire the leaf values into the leaf hashers
for (i=0; i < numLeafHashers; i++){
hashers[i].left <== leaves[i*2];
hashers[i].right <== leaves[i*2+1];
// Initialize hashers for the leaves, each taking two adjacent leaves as inputs.
for (var i = 0; i < numLeafHashers; i++){
hashers[i] = PoseidonHasher(2)([leaves[i*2], leaves[i*2+1]]);
}

// Wire the outputs of the leaf hashers to the intermediate hasher inputs
// Initialize hashers for intermediate levels, each taking the outputs of two hashers from the previous level.
var k = 0;
for (i=numLeafHashers; i<numLeafHashers + numIntermediateHashers; i++) {
hashers[i].left <== hashers[k*2].hash;
hashers[i].right <== hashers[k*2+1].hash;
for (var i = numLeafHashers; i < numLeafHashers + numIntermediateHashers; i++) {
hashers[i] = PoseidonHasher(2)([hashers[k*2], hashers[k*2+1]]);
k++;
}

// Wire the output of the final hash to this circuit's output
root <== hashers[numHashers-1].hash;
// Connect the output of the final hasher in the array to the root output signal.
root <== hashers[numHashers-1];
}
5 changes: 0 additions & 5 deletions circuits/circom/utils/messageValidator.circom
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ include "./verifySignature.circom";
// circomlib import
include "./mux1.circom";

/**
* Checks if a MACI message is valid or not.
* This template supports the Quadratic Voting (QV).
*/

/**
* Checks if a MACI message is valid or not.
* This template supports the Quadratic Voting (QV).
Expand Down
Loading

0 comments on commit 84a5736

Please sign in to comment.