1. Abstract
This spec introduces a new ZK circuit (“Ownership Proof”) to the World ID Protocol that allows a user to prove they own a specific registered leaf without revealing their leaf_index or any private key material to the verifier. The circuit takes a domain-separated commitment, H(domain_separator, leaf_index, commitment_blinder), and proves that the user controls a secret key registered in the WorldIDRegistry for that leaf, without exposing the commitment_blinder value (e.g. a credential blinding factor) as a public input. The initial use case is Issuer Authentication, where a user proves ownership of a credential sub to an Issuer for operations like re-issuance, renewal, or deletion.
2. Motivation
There are use cases that require users to prove ownership for their World ID and a specific commitment. At the time of writing there is a well-known use case for Issuer Authentication.
2.1 Issuer Authentication
Issuers may require users to authenticate with their World ID. Some examples of such use cases:
- Re-issuance. Allowing the user to get a new copy of their credential due to loss.
- Status information. Providing the user with information on their current enrollment state.
- Cancellation/deletion/unregistration. Allowing the user to unregister, delete or cancel their existing credential.
For the cases above, Issuers need to know the legitimate owner of a Credential is requesting the operation. Issuers do not know the user’s leaf_index by design, so a mechanism to authenticate based on the Credential’s subject (sub) is required.
3. Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
The terms Authenticator, Issuer and Credential are as defined in the World ID Protocol.
This specification introduces a new circuit to the Protocol: “Ownership Proof”. The Ownership Proof is a new circuit which allows users to prove ownership (as defined below) using a specific commitment.
A non-normative high-level description of what the circuit proves:
- It proves the user’s
leaf_indexhashed with acommitment_blinderand a specific domain separator produces anexpected_commitment. An example, is the Credential’s blindedsub.- It proves the user’s
leaf_indexis validly registered in theWorldIDRegistryand the user can produce a signature with a secret key ($sk$) registered as an authenticator for the particularleaf_index.- It proves the user authorized the operation through a signature with a registered authenticator secret key and that such operation is only valid for a specific
nonceandcontextprovided.
The Ownership Proof circuit MUST introduce the following inputs. The circuit MUST NOT introduce any additional public inputs which are not specified in this or a future spec.
| Input | Visibility | Type | Description |
|---|---|---|---|
expected_commitment | Public | Field element | The expected output of the hashed commitment (e.g. the sub of a credential) |
merkle_root | Public | Field element | The root hash of the Merkle tree used for inclusion (representing the WorldIDRegistry) |
depth | Public | Field element | The depth of the WorldIDRegistry’s Merkle tree used for inclusion |
nonce | Public | Field element | One-time use value to prevent replays. See Nonce section. |
context | Public | Field element | A verifier-supplied context for which the proof is valid. |
user_pk | Private | [PublicKey; NUM_KEYS] | The list of authenticator public keys registered in the WorldIDRegistry. |
pk_index | Private | Field element | The index in user_pk of the key used for signature. |
query_s | Private | Field element | The s component from the EdDSA signature on the message (see constraints). |
query_r | Private | [Field element; 2] | The r component from the EdDSA signature on the message (see constraints). |
leaf_index | Private | Field element | The index of the user’s World ID in the WorldIDRegistry. |
siblings | Private | [Field element; MAX_DEPTH] | The sequence of all siblings from the leaf_index to the merkle_root . |
commitment_blinder | Private | Field element | The blinding value that is hashed with the leaf_index to output the expected_commitment. The provenance of the value depends on the specific use case (see Use Cases). |
For the inputs above, a PublicKey is as defined in the WIP-100 spec (an EdDSA public key represented as its coordinate points $(x,y)$ with each coordinate being a Field element). For reference, user_pk, pk_index, leaf_index (named mt_index), siblings introduce the same constraints that the Nullifier Proof circuit.
3.1 Circuit constants
The Field ($F$), the Curve (BabyJubJub), and the Hashing ($H_t$) definitions MUST follow the requirements of WIP-100. For example, in this spec H_3 refers to the hash constructed from a Poseidon2 permutation of 3-elements.
| Constant | Value | Description |
|---|---|---|
NUM_KEYS | 7 | Length of the authenticator public key list. Fixed by the Nullifier Proof circuit and the WorldIDRegistry. |
MAX_DEPTH | 30 | For reference, defined in WIP-100. Maximum supported WorldIDRegistry Merkle tree depth; also the length of siblings. |
MERKLE_LEAF_DS | 105702839725298824521994315 (b"World ID PK") | Domain separator for the authenticator key list commitment. |
DS_EDDSA | 360302137480307891234917541314130533 (b"EdDSA Signature") | For reference, defined in WIP-100. Domain separator for the EdDSA challenge hash. |
DS_WIP_103 | 95972389630003 (b"WIP103") | Domain separator for the Ownership Proof signed message. MUST NOT be reused outside of the Ownership Proof signed-message construction. |
3.2 Circuit constraints
The Ownership Proof circuit MUST implement the following constraints (order is not relevant):
- Expected commitment. Compute the commitment as:
H_3(domain_separator, leaf_index, commitment_blinder). The computed commitment MUST equal theexpected_commitment. Thedomain_separatoris dependent on the Use Case and all possible domain separators MUST be hardcoded in the circuit. - Signature verification. Compute the message of the signature as:
message = H_4(DS_WIP_103, expected_commitment, nonce, context). The circuit MUST verify(query_r, query_s)as an EdDSA-Poseidon2 signature bypkover themessagein order to prove authorization by an authenticator over the particularnonceandcontext. The signature computation and verification MUST follow all the requirements from WIP-100. - Key selection. The circuit MUST select exactly one public key
pk = user_pk[pk_index]and MUST constrain:pk_index < NUM_KEYS, enforced as a comparison over the full field $F$ and not as a truncating cast to a smaller integer type. An out-of-rangepk_indexMUST cause proving to fail.- The selected
pkequals thepk_index-th element ofuser_pk, for the samepk_indexwitness.
- Key validity.
user_pkMUST be a fixed-length array ofNUM_KEYSentries inWorldIDRegistryslot order. Slots with no active authenticator, whether never used or removed, MUST be encoded as the neutral element $O = (0,1)$ of the BabyJubJub curve. The circuit MUST constrain the selected $\texttt{pk} = (A_x, A_y)$ as follows: 1) the point MUST be on the curve; 2) the point MUST be in the prime-order subgroup; and 3) the point MUST NOT be the neutral element $O$. Constraint (3) is particularly important because $O$ is used to signal an omitted element from the array, without it, the circuit would not have transitive proof ofskknowledge. - Leaf index commitment. The circuit MUST compute
offchainSignerCommitmentas designated in the Query Proof, with $H_{16}$ using the domain separatorMERKLE_LEAF_DSand each key inuser_pkencoded as $(x, y)$ points sequentially, with the last position (index15) equal to0. The digest is output state element1. All keys MUST be included in order, including empty slots with the neutral element $O$. - Merkle inclusion proof. The circuit MUST recompute
merkle_rootfromoffchainSignerCommitmentas the leaf value at positionleaf_indexfollowing the definitions of WIP-100. - Leaf-index binding. The
leaf_indexhashed into the commitment in constraint 1 and the position proven in constraint #6 MUST be the same witness. The circuit MUST NOT accept two independent values. This binding is essential, otherwise the circuit is only proving the prover knows theskof some leaf, not the one being proven in theexpected_commitment. - Verifier-supplied input validation. The
nonceandcontextMUST NOT equal0. These are usually intended as sentinel values and could surface an incorrect use of them.
3.3 Nonce
The nonce is a security mechanism to prevent replay attacks. Recipients of an Ownership Proof (also called “verifiers” in this spec) are responsible for its generation and verification.
- Provenance. Verifiers MUST generate and provide the nonce. Authenticators MUST NOT generate nonces.
- Single Use. Verifiers MUST enforce that a nonce may only be used one time. Verifiers MUST invalidate any nonce after first use.
- Entropy. Verifiers MUST generate the nonce from a uniformly random distribution using a CSPRNG over the whole field $F$.
- Expiration. Nonces MUST have a defined TTL and not be valid after expiration. Verifiers MAY define the mechanism to accomplish this.
- The
0element is NOT a valid nonce.
3.4 Context
The context is the mechanism by which a verifier binds a specific proof to a specific requested operation. The verifier MUST constrain the use of Ownership Proofs to specific operations and assign such operations with a unique context. For example, renewing a credential and deleting a credential are two different contexts. The verifier MUST provide the context when requesting a proof and MUST verify the provided context is valid for the explicit operation being executed.
It is RECOMMENDED that Verifiers use contexts shorter than 31 bytes or use a hash function to avoid collisions.
The 0 element is NOT a valid context.
4. Use Cases
- Authenticators MUST restrict Ownership Proofs subject only to the use cases outlined in this spec or a future spec which references this one.
- If future use cases are added, the
commitment_blinderIS REQUIRED to always be a high entropy value to prevent finding a user’sleaf_index. Unless otherwise noted, it should be randomly generated from a CSPRNG uniformly distributed over the entire $F$.
4.1 WIP-103-001: Issuer Authentication
- Use case: Authenticating to an Issuer where the Issuer has a
subas identifier. - Domain Separator:
b"H_CS(id, r)"namedDS_C_CS. commitment_blindervalue: The credential’s blinding factor as stored (or re-derived) by the Authenticator.- Use conditions: Can only be used to prove ownership with the specific Issuer for which the
subwas generated. The Authenticator MUST ensure this proof is only provided to the Issuer it corresponds. The Authenticator knows this from the blinding factor used as thecommitment_blinderinput. Furthermore, providing this proof MUST come from a user initiated action and SHALL NOT be requested by Issuers. Acceptable examples include: when a user requests a Credential re-issuance, when a user requests a Credential renewal, when a user requests a Credential deletion. - Verification: Issuers MUST ensure the
expected_commitmentpublic input of the circuit matches the expected identifier (i.e. Credential’ssub).
5. Rationale
A keen observer would notice the Ownership Proof circuit is very similar to the Query Proof circuit. Using this circuit is not an option because the verifying party would need to learn the commitment_blinder being verified to ensure the hash validity (it’s a public input). For example, an Issuer does not need to learn the credential blinding factor, which would defeat the purpose of the blinding factor because the leaf_index could be easily brute forced.
6. Reference Verification
An Issuer will be able to know a specific user is the legitimate owner of a sub by performing the following validations:
- Ensuring the received zero-knowledge proof verifies correctly with the correct verifying keys.
- The root hash (public input) matches a root hash for a valid Merkle tree of the
WorldIDRegistry, as well as the expected depth. - The
expected_commitmentpublic input matches the expectedsubbeing verified. This value MAY also be used for lookups when thesubis not known in advance. - The
noncepublic input is one the Issuer itself generated, has not expired, and has not been used before. The nonce MUST be invalidated at this point. See Nonce. - The
contextpublic input is the context the Issuer assigns to the operation it is about to execute. A proof carrying any other context MUST be rejected, even if every other check passes. See Context.
Validations 4 and 5 are what make the proof unreplayable and single-purpose. The circuit constrains the nonce and context to be bound in the authenticator’s signature, but it cannot know which values the verifier intended, so a verifier that accepts the values supplied alongside the proof without comparing them to its own gains no replay or cross-context protection.
It is strongly RECOMMENDED that implementations verify the Ownership Proof using a proof format and verification method supported by ProveKit.
7. Security
commitment_blinderis never revealed. Unlike the Query Proof circuit, thecommitment_blindervalue is a private input. For Issuer Authentication (WIP-103-001), this means the credential blinding factor is never exposed to the Issuer. If it were, the Issuer could brute-force theleaf_index(the domain of possible values is small) and break the unlinkability property of the blinding factor.- Domain separation prevents cross-context replay. Each use case defines its own domain separator, and the
domain_separatoris committed inside the hash. A proof generated for one use case cannot be replayed in another context. Authenticators MUST enforce that only domain separators defined in this spec or a referencing spec are used. - Authenticator-gated usage. Authenticators MUST restrict generation of Ownership Proofs to user-initiated actions for the defined use cases. Issuers SHALL NOT be able to request this proof; the Authenticator must initiate it. This prevents an Issuer from using the proof as an oracle to test whether a given
subbelongs to a particular user. - Nonce and context are bound into the signed message. The signature verified by the circuit is over
nonce,contextandexpected_commitment, not only over the bare commitment. This means every Ownership Proof requires a fresh signature from the authenticator signing key for that specific(nonce, context)tuple (in addition to theexpected_commitment), anchoring proof generation to an active signing event by the Authenticator. - For note, proofs for the same
expected_commitment(e.g. the samesub) are linkable because they use the same public input. This is intended as theexpected_commitmentis what its getting proven. This proof however prevents cross-verifier linking as thecommitment_blinderdiffers.
8. Backwards Compatibility
This World Improvement Proposal (WIP) introduces a new interface; no existing contracts or other previously existing functionality is affected.