EDIT: Based on received feedback, I altered the design:
Find the new repo here:
https://github.com/Nerolation/EIP-ERC721-zk-SNARK-Extension
and the related disussion (before submitting a pull request):
https://ethresear.ch/t/erc721-extension-for-zk-snarks/13237
The following is deprecated:
This is an ERC721 extension to store ownership information in a merkle tree.
It enables the use of private merkle-proofs (zk-SNARKs) for ownership verification.
The idea was inspired by the Souldbound token article of Vitalik.
How it works
When minting and transfering tokens, there is a commitment c created for the recipient that consists of a users address and the respective tokenID. This c is then written to a leaf in the merkle tree.
For prooving ownership, a user must demonstrate the ability to reproduce any c in the merkle tree. For that, the user must have access to an address a, which, when being hashed together with a tokenId tid (c = h(a, tid)), is present in the merkle tree. Prooving access to an address can be done by signing a message.
Using zk-SNARKs, the owner can verify to be included in the merkle tree without pointing to the exact location in the tree. This allows for private ownership proofs.
When a user transfers, the respective entry in the merkle tree is nullified ( c ==> True ). Same happens when tokens are burned.
Pros:
- Private Ownership proofs
- Logic handled by underlying ERC721 (no Stealth addresses)
Cons:
- Comes with fixed and limited nr of owners/transfers (depending on size of merkle tree)
- Inceasing gas costs for all users
- Once owner, always owner (see note below)
I initially thought about implementing it for ERC-4973 (Account-bound Tokens) or ERC-5114 (Soulbound Badge), but came to the conclusion that it would only make sense for ERC-721, at the time.
NOTE: Since there is no nullifier
(some secret noise to the commitment) incorporated in the commitment hash, users who once had the token can always proof ownership. I consider this a bug, not a feature, but might also depend on the usecase. By using a nullifier
, leafs can be marked as “spent”, however, it eventually requires users to transfer nullifiers off-chain, for doing transfers. So, as you can see, still some thoughts required on this.
Check out the Tornado Cash docs for some background.
You’ll find some really good explanations there.
I really appreciate receiving feedback!