Skip to content

feat: add verifyWithSession verifier entry point for session-bound proofs - #862

Merged
kilianglas merged 23 commits into
mainfrom
kilianglas/uniqueness-session-binding-contracts
Aug 5, 2026
Merged

feat: add verifyWithSession verifier entry point for session-bound proofs#862
kilianglas merged 23 commits into
mainfrom
kilianglas/uniqueness-session-binding-contracts

Conversation

@kilianglas

@kilianglas kilianglas commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Adds a verifier entry point for Uniqueness Proofs bound to a session commitment. The client side (#855) emits proofs whose session_id public signal carries the commitment; verify() pins that signal to 0, so bound proofs need their own entry point. Verification logic is unchanged — verifyProofAndSignals already takes sessionId.

Extends the V3 verifier added in #882. No V2 file is touched.

Contracts

  • UnreleasedIWorldIDVerifierV3 declares verifyWithSession(...).
  • UnreleasedWorldIDVerifierV3 implements it: requires the uniqueness action prefix (MSB 0x00, InvalidAction) and sessionId != 0 (InvalidSessionId), then delegates to verifyProofAndSignals.
  • verify() and verifySession() are unchanged; bound proofs are rejected by verify() and unbound proofs by verifyWithSession, so binding is explicit in both directions.

Rust

  • RegistryTestContext deploys WorldIDVerifierV3 behind the proxy.
  • generate-solidity-fixtures gains a bound-proof section: binds the request to the session fixture's id (cached r), asserts the nullifier is unchanged, and verifies on-chain.
  • The e2e positively verifies a bound proof via verifyWithSession, alongside the existing verify()-rejects assertion.

Tests & fixtures

  • WorldIDVerifierV3Test goes from 4 to 11 tests: happy path, bound proof rejected by verify(), unbound rejected by verifyWithSession, wrong session id, action-prefix checks, zero session id.
  • Fixtures in WorldIDVerifierTest.t.sol (shared mocks and merkle root) and the V3 test are regenerated as one consistent set — they can only be replaced together. The session fixture now carries its own sessionNonce and a 0x02-prefixed session action.

@kilianglas
kilianglas requested a review from a team as a code owner July 13, 2026 11:52
Comment thread contracts/src/core/interfaces/IWorldIDVerifierV2.sol
Comment thread contracts/test/core/WorldIDVerifierTest.t.sol
kilianglas and others added 7 commits August 3, 2026 22:08
Zero is the circuit's "no session" sentinel, satisfiable by any World ID
regardless of mt_index, so a session record left at zero could be satisfied
by an arbitrary World ID with a patched authenticator. verifyWithSession
already rejected it; apply the same check to verifySession.

V2 only — older implementations are immutable.

Reported via HackerOne #3912490.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
V2 is released and immutable, so the new entry point and the session id
validation move to a new version instead of extending V2 in place.

- IWorldIDVerifierV3 declares verifyWithSession + InvalidSessionId
- WorldIDVerifierV3 implements verifyWithSession and overrides
  verifySession to reject sessionId == 0
- WorldIDVerifierV2.sol is restored byte-identical to main; InvalidAction
  stays declared inline there and V3 inherits it
- V2 tests return to their original set (regenerated fixture values only);
  the binding and zero-session cases move to WorldIDVerifierV3Test
- test-utils deploys V3 behind the proxy; e2e and the fixture tool retarget

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The regenerated fixture values were unnecessary: all six V2 tests are
negative (four revert on InvalidAction before any proof math, two expect
ProofInvalid), so they pass unchanged against the refreshed mocks.

Leaves the PR with no V2 footprint at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The verifySession zero-session check is a separate security fix and moves
to its own PR against main. V3 here adds only the new entry point.

Depends on that PR landing for the session-proof hardening.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follows the error moving onto the V2 interface on main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Base automatically changed from kilianglas/uniqueness-session-binding to main August 5, 2026 02:27
kilianglas and others added 2 commits August 5, 2026 15:26
…-session-binding-contracts

# Conflicts:
#	contracts/test/core/WorldIDVerifierV3Test.t.sol
#	crates/core/tests/generate_proof.rs
#	docs/world-id-4-specs/README.md
test_BoundSuccess verifies a real bound proof end-to-end, which necessarily
passes both guards, so the synthetic case adds nothing. Also trims a comment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kilianglas
kilianglas enabled auto-merge (squash) August 5, 2026 14:29

/**
* @title WorldIDVerifier
* @title WorldIDVerifierV2

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we still update V2 or is this V3 now? CC @Dzejkop

uint64 constant credentialIssuerIdWrong = 2;

uint64 constant rpIdCorrect = 0x1a6ccf8f70e5de68;
uint64 constant rpIdCorrect = 0x387df34f862cd4e;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given these tests were part of an audit, is it possible to introduce a new module for V3 tests?

@kilianglas
kilianglas merged commit e854d7b into main Aug 5, 2026
24 checks passed
@kilianglas
kilianglas deleted the kilianglas/uniqueness-session-binding-contracts branch August 5, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants