Once a user visits an orb and does a successful signup, the orb's backend will insert the user's
Semaphore public key (identity commitment) to the
signup-sequencer
queue. The signup sequencer will
create a batch of size 10, 100 or 1000 (based on current parameters), create a zk proof of insertion
using semaphore-mtb
, calls registerIdentities()
and the contract verifies the proof and updates the merkle tree root. Each chain that World ID
supports (currently Base, Optimism and Polygon PoS) has a state bridge contract which fetches the
state from the WorldIDIdentityManager
contract and propagates it further to the other chains. The
state bridge contracts can be found here.
The below diagram shows the flow of a verification request. The user will generate a proof using
semaphore-rs
from within the World App or elsewhere,
and then send it to the World ID contract. Alternatively, app developers integrating WorldID can use
IDKit.js
to handle all the interactions with WorldID on
the client side. The
WorldIDRouter
will route the proof to the specified group (0 - Phone, 1 - Orb) and the
WorldIDIdentityManager
contract will verify the proof using the
SemaphoreVerifier
.
If the proof is valid, the call won't revert and therefore any subsequent logic from the app
integrating WorldID will go through. If the proof is invalid, it will revert with
InvalidProof
.
Note that the inclusion proof needs to be generated against a merkle tree root that already includes
the identity commitment of the user. In the backend, the merkle path for a given node is fetched
from the signup-sequencer
using /inclusionProof
and the proof is generated against the latest root inside of the World App. Proofs can also be
verified off-chain by the signup-sequencer
using /verifySemaphoreProof
or using semaphore-rs
if you manually provide all the right parameters.