Semaphore

Join the Telegram group to discuss.

Introduction

Semaphore is a zero-knowledge gadget which allows users to prove their membership of a set without revealing their original identity. At the same time, it allows users to signal their endorsement of an arbitrary string. It is designed to be a simple and generic privacy layer for Ethereum dApps. Use cases include private voting, whistleblowing, mixers, and anonymous authentication.

For more information, refer to the documentation.

Quick start

You should have Node 11.14.0 installed. Use nvm to install it.

Clone this repository, install dependencies, and build the source code:

git clone git@github.com:kobigurk/semaphore.git && \
cd semaphore && \
npm i && \
npm run bootstrap && \
npm run build

Next, either download the compiled zk-SNARK circuit, proving key, and verification key (note that these keys are for testing purposes, and not for production, as there is no certainty that the toxic waste was securely discarded).

To download the circuit, proving key, and verification key, run:

# Start from the base directory

cd circuits && \
./circuits/scripts/download_snarks.sh

To generate the above files locally instead, run:

# Start from the base directory

cd circuits && \
./circuits/scripts/build_snarks.sh

This process should take about 45 minutes.

Build the Solidity contracts (you need solc v 0.5.12 installed in your $PATH):

# Start from the base directory

cd contracts && \
npm run compileSol

Run tests while still in the contracts/ directory:

# The first command tests the Merkle tree contract and the second
# tests the Semaphore contract

npm run test-semaphore && \ 
npm run test-mt

How to use Semaphore in your dApp

The Semaphore contract is the base layer of Semaphore. Other contracts can build upon this to create applications that rely on anonymous signaling.

First, you should have the proving key, verification key, and circuit file, which are static, easily available to your users.

To have full flexibility over Semaphore's mechanisms, you should write a Client contract and set the owner of the Semaphore contract as the address of the Client contract. This allows the Client contract to call certain critical Semaphore functions.

See SemaphoreClient.sol for an example.

Semaphore functions

insertIdentity(uint256 _identityCommitment)

This inserts the user's identity commitment into the Semaphore contract's Merkle tree of identities.

The client should generate it using libsemaphore's genIdentityCommitment() function.

broadcastSignal(...)

TODO: fix this

The full function signature is:

broadcastSignal(
    bytes memory _signal,
    uint256[8] memory _proof,
    uint256 _root,
    uint256 _nullifiersHash,
    uint232 _externalNullifier
)
  • _signal: The signal to broadcast. Use ethers.utils.toUtf8Bytes(SIGNAL) to generate it, where SIGNAL is a string.

  • _proof: The zk-SNARK proof generated by libsemaphore's genBroadcastSignalParams() function.

  • _root: The root of the Merkle tree. This is part of the output of libsemaphore's genWitness() function.

  • _nullifiersHash: A uniquely derived hash of the external nullifier, user's identity nullifier, and the Merkle path index to their identity commitment. It ensures that a user cannot broadcast a signal with the same external nullifier more than once.

  • _externalNullifier: A 29-byte value which serves as a context of sorts for the signal. Refer to the high-level explanation of Semaphore for more details.

  1. (Optional) Has functions which call the Semaphore contract's:

    • addExternalNullifier()

    • deactivateExternalNullifier()

    • reactivateExternalNullifier()

These functions add, deactivate, and reactivate an external nullifier respectively. As each identity can only signal once to an external nullifier, and as a signal can only be successfully broadcasted to an active external nullifier, these functions enable use cases where it is necessary to have multiple external nullifiers or to activate and/or deactivate them.

  1. (Optional) There is also a function which controls broadcast permissioning: setPermissioning(bool _newPermission). If permissioning is set to true, then only the owner (usually the Client contract) may call broadcastSignal(). Otherwise, anyone may do so.

Audit results

The Ethereum Foundation and POA Network commissioned ABDK Consulting to audit the source code of Semaphore as well as circomlib, which contains components which the Semaphore zk-SNARK uses.

The results of the audit can be found in the audit/ directory. The team's responses to their results can be found in audit/README.md.

Description
No description provided
Readme MIT 139 MiB
Languages
TypeScript 71.1%
MDX 13.4%
Solidity 10.7%
SCSS 1.9%
CSS 1.8%
Other 1.1%