Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Semaphore V4 #480

Merged
merged 236 commits into from
Feb 28, 2024
Merged

Semaphore V4 #480

merged 236 commits into from
Feb 28, 2024

Conversation

cedoor
Copy link
Member

@cedoor cedoor commented Dec 15, 2023

Description

This PR updates the Semaphore codebase based on the findings from the analysis and research period described in the research repository.

The only supported tree depth is 10 at the moment. Another PR (based on issue #482) will be created to support a tree depth range from 1 to 32.

This is not the final version of the PR. The tasks that will follow are listed below. However, an initial review is necessary before proceeding.

ZK circuits

  • The identity trapdoor and identity nullifier have been replaced with a single value, the private key, from which an EdDSA public key is derived. The Poseidon hash of the public key is the new identity commitment.
  • Some input and output names in the circuits have been changed.
    • External Nullifier → Scope
    • SignalHash → Message
    • NullifierHash → Nullifier
    • Siblings → Tree Siblings
    • Path Indices → Tree Indices
  • The new circuit uses Anonymous Components to make the code clearer and more concise (24 lines of code without comments, rather than 90).
  • The circuit used to calculate the Merkle tree root is now part of an external package (@zk-kit/circuits - BinaryMerkleRoot) and supports dynamic depths.
  • Circomkit has been used for tests and scripts
  • The new circuit will be published on NPM (@semaphore-protocol/circuit)

JS libraries

  • The core Semaphore libraries have been updated to support the new LeanIMT data structure and the new V4 circuits.
  • The identity library now supports the generation of public/private keys using EdDSA and Baby Jubjub, as well as signatures.
  • The group and proof libraries have been greatly simplified.
  • The proof library now automatically downloads wasm/zkey artifacts on browsers and also on NodeJS.
  • JS tests have been moved outside the src folder. A new tests folder has been created for them.
  • @semaphore-protocol/heyauthn tests have been updated to support the new core libraries
  • @semaphore-protocol/hardhat has been updated to support the new contracts

Solidity contracts

  • The contracts have been updated with the new LeanIMT.
  • SemaphoreGroups.sol has been adapted to the new data structure, which does not require zero nodes and has a static depth.
  • SemaphoreGroups.sol now also manages access to functions (group admins).
  • The verifier has been updated with the latest version of the template provided by SnarkJS.
  • The VerifiedProof event now includes all the parameters of the proof, allowing anyone to verify the proof off-chain (Add private proof values to the VerifiedProof event #328).

Related Issue

Closes #357

Does this introduce a breaking change?

  • Yes
  • No

Other information

Next tasks

Before merging this PR to the main branch it is necessary to work on other tasks, which will be merged to this branch first.

@cedoor cedoor requested review from 0xjei and vplasencia December 18, 2023 12:01
@cedoor cedoor marked this pull request as ready for review December 18, 2023 12:01
Copy link

openzeppelin-code bot commented Dec 22, 2023

Semaphore V4

Generated at commit: 0dbf5f64dadad9c5968950f384a4a8aeab098431

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
0
0
0
4
14
18
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

@vplasencia
Copy link
Member

vplasencia commented Jan 2, 2024

Issues regarding the Merkle Tree circuit:

  1. When the parent of an element is itself.
  2. When the depth of the circuit is the same as the MAX_DEPTH.
    • To solve this we could add something like this code before out <== root; at the end.
      var a = IsEqual()([depth, MAX_DEPTH]);
      
      roots[MAX_DEPTH] <== a * nodes[MAX_DEPTH];
      
      root += roots[MAX_DEPTH];
      And the roots signal should be signal roots[MAX_DEPTH + 1];

@cedoor
Copy link
Member Author

cedoor commented Jan 2, 2024

Issues regarding the Merkle Tree circuit:

  1. When the parent of an element is itself.

What happens exactly? Could you add a test for it, or share the code you used here?

  1. When the depth of the circuit is the same as the MAX_DEPTH.

Good catch! I feel like this should be done here: https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/circuits/circom/binary-merkle-root.circom. What do you think?

@vplasencia
Copy link
Member

vplasencia commented Jan 2, 2024

@cedoor Yes, sure, I will create an example of test for it. Some changes should be in the zk-kit package and others in the semaphore proof package. For 2, yes, all the changes are in zk-kit.

@vplasencia
Copy link
Member

  1. When the parent of an element is itself.

Actually, this issue is related to variable naming in the Merkle Tree circuit because the name depth works for the IMT but not for the LeanIMT.

A test case could be to use the leaves:

BigInt(1), BigInt(2), BigInt(3), BigInt(4), BigInt(5)

And generate the merkle proof of the position 4.

Replace this part (https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/circuits/tests/binary-merkle-root.test.ts#L12-L20) with this:

    const leaf = BigInt(5)

    for (let i = 1; i < 6; i += 1) {
        tree.insert(BigInt(i))
    }

    const { siblings, index } = tree.generateProof(4)

With that, the test will not pass.

To pass the test, we can add const siblingsLength = siblings.length here:

    const indices: number[] = []
    const siblingsLength = siblings.length

    for (let i = 0; i < MAX_DEPTH; i += 1) {
        indices.push((index >> i) & 1)

        if (siblings[i] === undefined) {
            siblings[i] = BigInt(0)
        }
    }

And update the input:

    const INPUT = {
        leaf,
        depth: siblingsLength,
        indices,
        siblings
    }

To solve this issue, I think that it is better to change the name of the variable depth here and use another to refer to the siblings' length.

@cedoor
Copy link
Member Author

cedoor commented Jan 3, 2024

@vplasencia

Actually, this issue is related to variable naming in the Merkle Tree circuit because the name depth works for the IMT but not for the LeanIMT

The LeanIMT works a bit differently compared to the old IMT. The Merkle proof could contain a different index and number of siblings due to the tree properties. I'm not sure if the variable name should be something different than depth, as in most cases it is the actual tree depth, and the circuit also supports the IMT in theory.

The @semaphore-protocol/proof package uses the sibling list length anyway, which is the actual depth in most cases:

const merkleProofLength = merkleProof.siblings.length

It could be different when the leaf is on the right side of the tree.

Proposal:

https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/circuits/circom/binary-merkle-root.circom could still use depth, as it's not necessary related to the LeanIMT.

Semaphore could use other names, like treeProofLength, treeProofIndices and treeProofSiblings.

@cedoor cedoor force-pushed the feat/semaphore-v4 branch from 406bbc4 to 0c596d8 Compare January 3, 2024 11:21
@vplasencia
Copy link
Member

@cedoor

Regarding this:
#480 (comment)

I like this proposal 👍.

Copy link
Contributor

@0xjei 0xjei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outstanding job 🥇 - Thank you @cedoor.

Left some comments and minor nits around.

.github/workflows/production.yml Outdated Show resolved Hide resolved
packages/circuits/LICENSE Outdated Show resolved Hide resolved
packages/circuits/semaphore.circom Show resolved Hide resolved
packages/contracts/contracts/interfaces/ISemaphore.sol Outdated Show resolved Hide resolved
packages/identity/README.md Outdated Show resolved Hide resolved
packages/proof/README.md Outdated Show resolved Hide resolved
@cedoor cedoor force-pushed the feat/semaphore-v4 branch 4 times, most recently from 28727f9 to 3c7ce0e Compare January 12, 2024 10:54
Copy link
Member

@vplasencia vplasencia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! ✨

cedoor and others added 28 commits February 28, 2024 12:24
More documentation on Identity lib code
Co-authored-by: Vivian Plasencia <v.pcalana@gmail.com>
Co-authored-by: Vivian Plasencia <v.pcalana@gmail.com>
More documentation on proof lib code
The commit adds more documentation to the group package functions and updates the TypeDoc link.

re #483
More documentation on group lib code
@cedoor cedoor merged commit 0d8c322 into main Feb 28, 2024
3 checks passed
@cedoor cedoor deleted the feat/semaphore-v4 branch March 1, 2024 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Integrate Semaphore v4 changes into the protocol
6 participants