Worldcoin Semaphore logoWorldcoin Semaphore


Number of verifiers

2

Aggregation

No

Trusted setup

Yes

List of verifiers

NameVerification status
OpWorldID_Zero
Unsuccessful
(performed by L2BEAT)
OpWorldID_One
Unsuccessful
(performed by L2BEAT)

Description

Worldcoin uses two types of circuits: Semaphore to prove the inclusion of a WorldId in the anonymity set, and the Semaphore Merkle Tree Batcher (SMTB) to efficiently insert or delete users from the Semaphore Merkle trees.

Semaphore

Worldcoin uses two semaphore anonymity sets, one called ‘orb’ (OpWorldID_One), used for verified humans, and the other called ‘phone’ (OpWorldID_Zero) for verified unique devices. More information can be found here. The two contracts have the same source code and contain multiple verification keys for multiple semaphore verifiers of different sizes, going from size 16 to 32. Currently, only the ones with size 30 are used. An example of a semaphore verification transaction can be found here.

The circuit is written in circom and the keys are generated using the snarkjs library. The semaphore artifacts can be found here.

Verification process

The procedure is explained for the semaphore circuit of size 30. While, as mentioned, the verifier contains the verification keys for all semaphore sizes from 16 to 32, the verification is always called with size 30 as the param is hardcoded, which can be verified here for OPWorldID_One and here for OPWorldID_Zero. To verify that the value 30 is actually the one used it is sufficient to look at one transaction for each of them. A script that semi-automatically performs the verification process from this point on can be found here. If you perform the verification manually, make sure to install the needed tools with the correct versions, as the verification fails with the latest ones.

Semaphore verification process

From the .circom to the .r1cs file: the circom version used in the original verification key generation process is non deterministic, meaning that a different r1cs file is generated every time the circom file is compiled. A workaround is currently being investigated.

From the .r1cs to the onchain verification keys: download the corresponding r1cs file from the semaphore artifacts. This can be done manually or with the following command:

curl https://storage.googleapis.com/trustedsetup-a86f4.appspot.com/semaphore/semaphore30/semaphore30.r1cs -o semaphore30.r1cs

Then, download the corresponding PPOT:

curl https://storage.googleapis.com/trustedsetup-a86f4.appspot.com/ptau/pot14_final.ptau -o pot14_final.ptau

Finally, we need to download the claimed verification keys:

curl https://storage.googleapis.com/trustedsetup-a86f4.appspot.com/semaphore/semaphore30/semaphore30_final.zkey -o semaphore30_final.zkey

Now we can run snarkjs to verify that the claimed verification keys have been indeed generated from the r1cs and the PPOT:

snarkjs zkv semaphore30.r1cs pot14_final.ptau semaphore30_final.zkey

If the verification is successful, the output will be ZKey Ok!.

We can now extract the verification keys from the zkey file:

snarkjs zkev semaphore30_final.zkey verification_key30.json

Now it’s time to compare the onchain verification keys to the generated ones. Download the corresponding onchain verifier either manually or using the following command using Foundry:

cast etherscan-source 0x3D40F9b177aFb9BF7e41999FFaF5aBA6cb3847eF --etherscan-api-key "${ETHERSCAN_API_KEY}" --chain optimism > SemaphoreVerifier.sol

The _getVerificationKey function shows how the verification keys are fetched. In particular, the alpha1, beta2 and gamma2 values are hardcoded in the function (because size-independent) while the delta2 and IC values are fetched from the VK_POINTS array depending on the size.

List of required tools

Tool nameVersionTool docs
snarkjsv0.6.11More info
circomv2.0.3More info