Mechanism of Operation
The goal of Semacaulk is to enable users to:
- Register their identity;
- Prove in zero-knowledge that they are a member of the set of registered users;
- Broadcast an arbitrary signal towards an external nullifier, without the possibility of double-signalling.
6.1. User identities
A user's identity consists of an identity nullifier \(\mathsf{id\_nul}\) and an identity trapdoor \(\mathsf{id\_trap}\). These are secret values and are elements of \(\mathbb{F}_r\) (see 1.1).
An identity commitment \(\mathsf{id\_comm}\) is the MiMC7 multi_hash
(see 4.3)
of \(\mathsf{id\_nul}\) and \(\mathsf{id\_trap}\):
\(\mathsf{id\_comm} = \mathsf{multi\_hash}([\mathsf{id\_nul}, \mathsf{id\_trap}])\)
6.2. External nullifiers
An external nullifier \(\mathsf{ext\_nul}\) is a \(\mathbb{F}_r\) field element which represents a topic. A signal can only be broadcast towards each external nullifier once and only once.
6.3. Nullifier hashes
A nullifier hash is the MiMC7 multi_hash
of
\(\mathsf{id\_nul}\) and \(\mathsf{ext\_nul}\):
\(\mathsf{nul\_hash} = \mathsf{multi\_hash}([\mathsf{id\_nul}, \mathsf{ext\_nul}])\)
6.4. Insertions
An insertion is the act of updating the on-chain accumulator with a user's
identity commitment. This is done by invoking the insertIdentity()
function
of the Semacaulk smart contract.
6.5. Broadcasting a signal
When a user broadcasts a signal, they generate a proof that they know the
secret identity nullifier and identity trapdoor behind their identity
commitment, and then submit said proof to the Semacaulk smart contract's
broadcastSignal()
function.
Tied to this proof is the hash of a signal and the user's desired external nullifier. The contract (not the user) hashes the user-provided signal using Keccak256 and right-shifts the result by 8 bits to derive \(\mathsf{sig\_hash}\), which is used as one of the public inputs to the verifier.
6.6. Preventing double-signalling
The Semacaulk smart contract maintains a mapping of nullifier hashes. Each
nullifier hash is unique to the user and an external nullifier. If the
broadcastSignal()
function finds that a nullifier hash has already been seen,
it rejects the transaction, thus preventing double-signalling.