Comments (6)
I'm not a ZKP expert, but as I know FIELD_SIZE is a large prime number for the finite field math, and I'm not sure that you can change it.
MerkleTreeWithHistory is from the source code of TornadoCache, and it is for storing the commitments which are 31 bytes. Why would you store addresses here?
Btw, an Ethereum address is 20 bytes, so it should be smaller than the FIELD_SIZE.
from zk-merkle-tree.
The idea is that we use ZKP circuit, to prove that a user is eligible to perform specific operations on a smart contract. For example if we had a Merkle Tree with N users (thus N addresses), someone can prove that his address exists in the Merkle Tree, either using software of onchain to fetch the pathElements and pathIndices. These variables would then be imported in this circuit which is an extension of the link I provided above:
include "./MerkleTreeChecker.circom";
include "./eth_addr.circom";
template VotingLeaderEligibilityChecker(n, k, levels) {
signal input privkey[k];
signal input pathElements[levels];
signal input pathIndices[levels];
signal output root;
// PrivKeyToAddr will compute the address given the private key
// Keys are encoded as (x, y) pairs with each coordinate being
// encoded with k registers of n bits each
component privToAddr = PrivKeyToAddr(n, k);
for (var i = 0; i < k; i++) {
privToAddr.privkey[i] <== privkey[i];
}
// Verifies that merkle proof is correct for given merkle root and a leaf
// pathIndices input is an array of 0/1 selectors telling whether given pathElement
// is on the left or right side of merkle path
component merkleTreeChecker = MerkleTreeChecker(levels);
merkleTreeChecker.leaf <== privToAddr.addr;
for (var i = 0; i < levels; i++) {
merkleTreeChecker.pathElements[i] <== pathElements[i];
merkleTreeChecker.pathIndices[i] <== pathIndices[i];
}
root <== merkleTreeChecker.root;
}
component main = VotingLeaderEligibilityChecker(64, 4, 3);
This circuit expects the user's private key, pathElements and pathIndices as private inputs and calculates the root.
The circuit is working very well using the output of the software function calculateMerkleRootAndPath
and calculates the same root. Now the problem is in this line: merkleTreeChecker.leaf <== privToAddr.addr;
, the privToAddr.addr returns the address in BIGINT type, much larger.
The addresses are indeed 20 bytes, but the circuit output is a BIGINT number, so we had to do the same with Solidity using the following convertion:
function addressToBigint(address _addr) public pure returns (uint256) {
// Convert the address to a uint160, then to a uint256
uint256 bigintValue = uint256(uint160(_addr));
return bigintValue;
}
in order to be consistent with the circuit's output. The _insert function expects bytes32 which we do the convention, but when the function reaches the hasLeftRight
function, which expects the uint256 type as input, there the problem appears.
As I can see and please correct me I am wrong or if you have any ideas, either a way must be found to convert the BIGINT circuit output to hex address type and pass the address as leaf in the MerkleTreeChecker and then convert the address to bytes32 (not the BIGINT) in Solidity, or probably we need to cut some bytes from the BIGINT from both circuit and Solidity, in order to be consistent.
Do you have any ideas?
from zk-merkle-tree.
Hmm. One of the possible solutions is if you split your address into parts (10-10 bytes), and calculates the mimc hash of it as TC calculates the commitment from the nullifier and the secret (https://github.com/TheBojda/zk-merkle-tree/blob/main/src/zktree.ts#L21). This hash should be small enough.
What I don't really understand is the context of this thing. Why do you need addresses in the tree? Why don't you use commitments and nullifiers to prove you have permission? Only the user knows the secret to generate the zkp for the nullifier, so a nullifier is something like a public key, and the secret is like a private key. I don't know your whole use case, but it could be implemented simply in the original way (using commitment, secret, and nullifier).
from zk-merkle-tree.
Yes, excellent question, the user still have to provide the proofs about the creation of the nullifier. The main idea behind this, is if we have voting groups (specific users that can vote) for one election. The voter could provide zkp Merkle Proofs for on-chain verification and if the root existed in the history then the user would be able to proceed with the commitment and nullifier procedure. This is to prove the eligibility of a voter to vote in a specific election.
from zk-merkle-tree.
If I understand well, you don't need ZKP for this because you don't have to hide the address of the voter in the registration phase. Simply build a Merkle tree off-chain, and store the Merkle root. When the user sends the commitment, she has to also send a Merkle proof (no ZKP needed) that proves she is in the group. So the registration is public, and only the voting itself (by using the nullified) is anonymous.
There are many implementations for verifying Merkle proofs, like OpenZeppelin's util: https://docs.openzeppelin.com/contracts/5.x/api/utils#MerkleProof
from zk-merkle-tree.
Well, in ZKP it is considered a very good practice instead of sending the actual Merkle Proof, to send ZKP proofs to a Verifier, stating that you possess a Merkle Proof that can resolve to a Merkle's Tree Root. This is considered safer option as you eventually hide the actual Merkle Proof from the public, and you pass it as input to a ZKP circuit. The output of this circuit is the root. If the root exists in history this means that the Prover is right and has actual and correct Merkle Proofs in his possession.
from zk-merkle-tree.
Related Issues (7)
- could you set a video to show how to run this projject for voting? i HOT 1
- Can this library be used for new project without any security issues HOT 1
- React JS incompatible HOT 1
- Deployed this zk-tree-vote project on testnet but encountered error HOT 9
- Feature Request: Foundry Support HOT 3
- If a hashFn returns an odd length string, the buffer removes the last digit HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from zk-merkle-tree.