Skip to content

Session seed not cached after CreateSession proof requests #407

@kilianglas

Description

@kilianglas

Summary

walletkit-core/src/authenticator/mod.rs:513-523 drops the newly minted session_id_r_seed returned by a ProofType::CreateSession proof request. The storage-side caching block keys off the request's session_id, which is always None for CreateSession, so the seed is never persisted — even though the response carries a valid newly-minted session_id that would be the correct cache key.

(Lookup is fine — for a CreateSession request there's nothing to look up, by definition. The bug is purely on the storage side, after the core authenticator has minted the new session.)

Code

// walletkit-core/src/authenticator/mod.rs:513-523
if let Some(seed) = result.session_id_r_seed {
    if let Some(session_id) = proof_request.0.session_id {  // ← request's session_id
        self.store
            .store_session_seed(session_id.oprf_seed, seed, now)?;
    }
}

For CreateSession:

  • proof_request.0.session_id is None (the RP doesn't have a session yet) → the inner if let is skipped.
  • result.session_id_r_seed is Some(new_seed) and result.proof_response.session_id is Some(new_session_id), both available — but only proof_request.0.session_id is consulted, so the cache write is skipped.

For Session requests, proof_request.0.session_id is Some, so the current path works.

Impact

Correctness is preserved because the core authenticator's Session branch (world-id-protocol/crates/authenticator/src/prove.rs:319-326) handles a missing cached seed by re-deriving via OPRF from session_id.oprf_seed. The functional cost is one extra OPRF round-trip on the first Session request after a CreateSession, after which caching fills correctly on that Session path.

So: a performance regression on CreateSession → Session transitions, not a broken flow.

Proposed fix

Cache under result.proof_response.session_id.oprf_seed instead of proof_request.0.session_id.oprf_seed. The response's session_id is correct in both flows:

  • CreateSession: response carries the newly minted session_id.
  • Session: response echoes the request's session_id (same oprf_seed).

Sketch:

if let (Some(seed), Some(session_id)) = (
    result.session_id_r_seed,
    result.proof_response.session_id,
) {
    if let Err(err) = self.store.store_session_seed(session_id.oprf_seed, seed, now) {
        tracing::error\!("error caching session_id_r_seed: {}", err);
    }
}

Notes

  • Pre-existing — not introduced by chore: bump world-id-protocol to v0.11.0 #406 (chore: bump world-id-protocol to v0.11.0).
  • Currently masked by walletkit-core/tests/proof_generation_integration.rs, which primes the store via store.store_session_seed(...) directly before the Session proof, bypassing the caching block.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions