feat: allow binding uniqueness proofs to an existing session#855
feat: allow binding uniqueness proofs to an existing session#855kilianglas wants to merge 4 commits into
Conversation
|
we should update the session proofs flow doc (https://github.com/worldcoin/world-id-protocol/tree/main/docs/world-id-4-specs#session-proofs) from this |
paolodamico
left a comment
There was a problem hiding this comment.
- updating docs
- conceptual: I wonder if it should be generally allowed to request a session_id without the uniqueness proof. it could be a footgun for RPs because then RPs would have to immediately request a session proof to verify it's valid.
- let's document details on privacy implications, for example, you could always request another uniqueness proof with the same
session_id. at the very least, when doing this, the authenticator's UI MUST NOT display any "anonymous" / "one-time" / etc language.
I'd wait until I've implemented the final version of this (single uniqueness proof flow). |
I'd say yes. Session proofs might be useful without a uniqueness proof, but might be wrong here. |
I don't fully get the privacy implications here. What's the point of requesting a different uniqunesess proof with the same session id? |
0xOsiris
left a comment
There was a problem hiding this comment.
This is functionally identical to passing the sessionId as the signal to the uniqueness proof correct?
No, it is not. This also verifier, that the |
| Ok(generate_ownership_proof_with_prover(input, prover)?) | ||
| } | ||
|
|
||
| fn validate_cached_session_r_seed( |
There was a problem hiding this comment.
nit: but maybe just validate_session_r_seed
cached implies there might be caching happening in this method
There was a problem hiding this comment.
this function also looks suspiciously close to functionality elsewhere, I recommend moving this to SessionId, it seems potentially problematic to have it here, if we're implementing validation here it means we could miss it elsewhere.
paolodamico
left a comment
There was a problem hiding this comment.
high. if I think about the problem fresh, the conceptual solution in my mind is that RPs use a uniqueness proof to gate access to creating a session, so uniqueness proof -> session, while the other way around may be more confusing (though correct). this also maintains the clear separation that a uniqueness proof is anonymous one-time use and avoids authenticators having to manage this variant. for consideration @kilianglas
| ProofType::Uniqueness => match proof_request.session_id { | ||
| // Bind the proof to the existing session. Requires the cached `r`. | ||
| Some(session_id) => { | ||
| let seed = session_id_r_seed.ok_or(AuthenticatorError::SessionSeedRequired)?; |
There was a problem hiding this comment.
this can be tackled in a separate PR, but I don't think we should fail here. if the RP provides a valid session_id we should recompute, especially because the RP has no control over what the user caches
| Ok(generate_ownership_proof_with_prover(input, prover)?) | ||
| } | ||
|
|
||
| fn validate_cached_session_r_seed( |
There was a problem hiding this comment.
this function also looks suspiciously close to functionality elsewhere, I recommend moving this to SessionId, it seems potentially problematic to have it here, if we're implementing validation here it means we could miss it elsewhere.
| .unwrap_err(); | ||
| assert!(matches!(err, AuthenticatorError::SessionSeedRequired)); | ||
|
|
||
| // a seed that does not open the session's commitment is rejected |
There was a problem hiding this comment.
| // a seed that does not open the session's commitment is rejected | |
| // a seed that does not match the session's commitment is rejected |
Summary
Allows a Uniqueness Proof request to carry an existing
session_id, cryptographically binding the proof to that session: the proof carriesSessionId.commitmentas itsid_commitmentpublic signal, proving in-circuit that the session and the nullifier belong to the same World ID. Requires no circuit changes, theid_commitmentcheck inoprf_nullifier.circomis proof-type-independent and was previously always disabled (0) for uniqueness proofs.New flow for a bound session id
ProofType::CreateSessionrequest.session_idand responds with corresponding session proofs.ProofType::Uniquenessrequest that now also carriesSome(session_id)session_idas a public input.Follow-up PRs may streamline this flow s.t. the initial request is not required, but the
session_idcan be generated as part of the uniqueness proof instead.Changes:
world-id-primitives:validate_proof_type()now allowssession_idonProofType::Uniqueness; newProofRequest::binds_session();validate_response()requires bound responses to echo thesession_id(and still rejects asession_idon plain uniqueness responses).world-id-authenticator:generate_proof()resolves(session_id, r)for binding requests from the caller-cachedsession_id_r_seed, validating it opens the session's commitment. A missing seed fails with the newSessionSeedRequirederror.Note: Re-deriving
rrequires a session-type request, since the uniqueness request's RP signature cannot authorize the seed query. This friction may be removed in a follow-up PR.0is valid but unbound) and the intentional-linkability caveat.On-chain, bound proofs can already be verified via
verifyProofAndSignalsby passing the session's commitment as thesessionIdsignal; the convenienceverify()entry point pins the signal to0and rejects bound proofs. A dedicated entry point for bound proofs may land in a follow-up PR.