Skip to content

Commit

Permalink
Identity VAnchor (#182)
Browse files Browse the repository at this point in the history
Co-authored-by: drewstone <drewstone329@gmail.com>
Co-authored-by: nepoche <nepoche@yahoo.com>
  • Loading branch information
3 people authored Oct 3, 2022
1 parent d764865 commit faf732a
Show file tree
Hide file tree
Showing 60 changed files with 25,428 additions and 1,458 deletions.
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
root = true

[*.sol]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.ts]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.md]
indent_style = space
indent_size = 4
max_line_length = 80
trim_trailing_whitespace = false
95 changes: 95 additions & 0 deletions circuits/identity_vanchor/identity-vanchor.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
pragma circom 2.0.0;

include "../vanchor/transaction.circom";
include "./semaphore.circom";
include "./manyMerkleProof.circom";

template IdentityVAnchor(levels, nIns, nOuts, zeroLeaf, length) {
// Semaphore inputs
signal input privateKey;
signal input semaphoreTreePathIndices[levels];
signal input semaphoreTreeSiblings[levels];

// roots for interoperability, one-of-many merkle membership proof
signal input semaphoreRoots[length];
signal input chainID;

// VAnchor inputs
signal input publicAmount;
signal input extDataHash; // arbitrary

// data for transaction inputs
signal input inputNullifier[nIns];
signal input inAmount[nIns];
signal input inPrivateKey[nIns];
signal input inBlinding[nIns];
signal input inPathIndices[nIns];
signal input inPathElements[nIns][levels];

// data for transaction outputs
signal input outputCommitment[nOuts];
signal input outChainID[nOuts];
signal input outAmount[nOuts];
signal input outPubkey[nOuts];
signal input outSemaphoreTreePathIndices[nOuts][levels];
// TODO: can we reduce this to a single index per nOut?
signal input outSemaphoreTreeElements[nOuts][levels];
signal input outBlinding[nOuts];

// roots for interoperability, one-of-many merkle membership proof
signal input vanchorRoots[length];

component semaphore = Semaphore(levels, length);

semaphore.privateKey <== privateKey;
for (var i = 0; i < levels; i++) {
semaphore.treePathIndices[i] <== semaphoreTreePathIndices[i];
semaphore.treeSiblings[i] <== semaphoreTreeSiblings[i];
}
semaphore.chainID <== chainID;

for (var i = 0; i < length; i++) {
semaphore.roots[i] <== semaphoreRoots[i];
}

component vanchor = Transaction(levels, nIns, nOuts, zeroLeaf, length);

vanchor.publicAmount <== publicAmount;
vanchor.extDataHash <== extDataHash;
vanchor.chainID <== chainID;
for (var i = 0; i < nIns; i++) {
vanchor.inputNullifier[i] <== inputNullifier[i];
vanchor.inAmount[i] <== inAmount[i];
vanchor.inPrivateKey[i] <== inPrivateKey[i];
vanchor.inBlinding[i] <== inBlinding[i];
vanchor.inPathIndices[i] <== inPathIndices[i];
for (var j = 0; j < levels; j++) {
vanchor.inPathElements[i][j] <== inPathElements[i][j];
}
}
for (var i = 0; i < nOuts; i++) {
vanchor.outputCommitment[i] <== outputCommitment[i];
vanchor.outChainID[i] <== outChainID[i];
vanchor.outAmount[i] <== outAmount[i];
vanchor.outPubkey[i] <== outPubkey[i];
vanchor.outBlinding[i] <== outBlinding[i];
}
for (var i = 0; i < length; i++) {
vanchor.roots[i] <== vanchorRoots[i];
}

component publicSemaphore[nOuts];

for (var n = 0; n < nOuts; n++) {
publicSemaphore[n] = ManyMerkleProofPublic(levels, length);
publicSemaphore[n].leaf <== outPubkey[n];
publicSemaphore[n].enabled <== outAmount[n];
for (var i = 0; i < length; i++) {
publicSemaphore[n].roots[i] <== semaphoreRoots[i];
}
for (var i = 0; i < levels; i++) {
publicSemaphore[n].pathIndices[i] <== outSemaphoreTreePathIndices[n][i];
publicSemaphore[n].pathElements[i] <== outSemaphoreTreeElements[n][i];
}
}
}
75 changes: 75 additions & 0 deletions circuits/identity_vanchor/manyMerkleProof.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
pragma circom 2.0.0;

include "../../node_modules/circomlib/circuits/bitify.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/switcher.circom";
include "../set/membership.circom";
include "../set/membership_if_enabled.circom";

// Verifies that merkle proof is correct for given merkle root and a leaf
// pathIndices bits is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
template ManyMerkleProofIdentity(levels, length) {
signal input leaf;
signal input pathElements[levels];
signal input pathIndices[levels];
signal input roots[length];

component switcher[levels];
component hasher[levels];

/* component indexBits = Num2Bits(levels); */
/* indexBits.in <== pathIndices; */

for (var i = 0; i < levels; i++) {
switcher[i] = Switcher();
switcher[i].L <== i == 0 ? leaf : hasher[i - 1].out;
switcher[i].R <== pathElements[i];
switcher[i].sel <== pathIndices[i];

hasher[i] = Poseidon(2);
hasher[i].inputs[0] <== switcher[i].outL;
hasher[i].inputs[1] <== switcher[i].outR;
}

// verify that the resultant hash (computed merkle root)
// is in the set of roots
component set = SetMembership(length);
for (var i = 0; i < length; i++) {
set.set[i] <== roots[i];
}
set.element <== hasher[levels - 1].out;
}

template ManyMerkleProofPublic(levels, length) {
signal input leaf;
signal input enabled;
signal input pathElements[levels];
signal input pathIndices[levels];
signal input roots[length];

component switcher[levels];
component hasher[levels];

/* component indexBits = Num2Bits(levels); */
/* indexBits.in <== pathIndices; */

for (var i = 0; i < levels; i++) {
switcher[i] = Switcher();
switcher[i].L <== i == 0 ? leaf : hasher[i - 1].out;
switcher[i].R <== pathElements[i];
switcher[i].sel <== pathIndices[i];

hasher[i] = Poseidon(2);
hasher[i].inputs[0] <== switcher[i].outL;
hasher[i].inputs[1] <== switcher[i].outR;
}

// verify that the resultant hash (computed merkle root)
// is in the set of roots
component set = ForceSetMembershipIfEnabled(length);
for (var i = 0; i < length; i++) {
set.set[i] <== roots[i];
}
set.enabled <== enabled;
set.element <== hasher[levels - 1].out;
}
40 changes: 40 additions & 0 deletions circuits/identity_vanchor/semaphore.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
pragma circom 2.0.0;

include "../../node_modules/circomlib/circuits/poseidon.circom";
include "./manyMerkleProof.circom";

// nLevels must be < 32.
template Semaphore(nLevels, length) {
signal input privateKey;
signal input treePathIndices[nLevels];
signal input treeSiblings[nLevels];

// roots for interoperability, one-of-many merkle membership proof
signal input roots[length];
signal input chainID;

component poseidon = Poseidon(1);
poseidon.inputs[0] <== privateKey;

signal publicKey;
publicKey <== poseidon.out;

component inclusionProof = ManyMerkleProofIdentity(nLevels, length);
inclusionProof.leaf <== publicKey;
// transformed value into list of values due to semaphore usage
/* inclusionProof.pathIndices <== inPathIndices[tx]; */

// add the roots and diffs signals to the bridge circuit
for (var i = 0; i < length; i++) {
inclusionProof.roots[i] <== roots[i];
}

for (var i = 0; i < nLevels; i++) {
inclusionProof.pathElements[i] <== treeSiblings[i];
inclusionProof.pathIndices[i] <== treePathIndices[i];
}

// Dummy square to prevent tampering chainID.
signal chainIDSquared;
chainIDSquared <== chainID * chainID;
}
7 changes: 7 additions & 0 deletions circuits/test/identity_vanchor_16_2.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma circom 2.0.0;

include "../identity_vanchor/identity-vanchor.circom";

// zeroLeaf = Poseidon(zero, zero)
// default `zero` value is keccak256("tornado") % FIELD_SIZE = 21663839004416932945382355908790599225266501822907911457504978515578255421292
component main {public [semaphoreRoots, publicAmount, extDataHash, inputNullifier, outputCommitment, chainID, vanchorRoots]} = IdentityVAnchor(30, 16, 2, 11850551329423159860688778991827824730037759162201783566284850822760196767874, 2);
7 changes: 7 additions & 0 deletions circuits/test/identity_vanchor_16_8.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma circom 2.0.0;

include "../identity_vanchor/identity-vanchor.circom";

// zeroLeaf = Poseidon(zero, zero)
// default `zero` value is keccak256("tornado") % FIELD_SIZE = 21663839004416932945382355908790599225266501822907911457504978515578255421292
component main {public [semaphoreRoots, publicAmount, extDataHash, inputNullifier, outputCommitment, chainID, vanchorRoots]} = IdentityVAnchor(30, 16, 2, 11850551329423159860688778991827824730037759162201783566284850822760196767874, 8);
7 changes: 7 additions & 0 deletions circuits/test/identity_vanchor_2_2.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma circom 2.0.0;

include "../identity_vanchor/identity-vanchor.circom";

// zeroLeaf = Poseidon(zero, zero)
// default `zero` value is keccak256("tornado") % FIELD_SIZE = 21663839004416932945382355908790599225266501822907911457504978515578255421292
component main {public [semaphoreRoots, publicAmount, extDataHash, inputNullifier, outputCommitment, chainID, vanchorRoots]} = IdentityVAnchor(30, 2, 2, 11850551329423159860688778991827824730037759162201783566284850822760196767874, 2);
7 changes: 7 additions & 0 deletions circuits/test/identity_vanchor_2_8.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma circom 2.0.0;

include "../identity_vanchor/identity-vanchor.circom";

// zeroLeaf = Poseidon(zero, zero)
// default `zero` value is keccak256("tornado") % FIELD_SIZE = 21663839004416932945382355908790599225266501822907911457504978515578255421292
component main {public [semaphoreRoots, publicAmount, extDataHash, inputNullifier, outputCommitment, chainID, vanchorRoots]} = IdentityVAnchor(30, 2, 2, 11850551329423159860688778991827824730037759162201783566284850822760196767874, 8);
Loading

0 comments on commit faf732a

Please sign in to comment.