Three Dots

Three Dots

Tap anywhere, then tap three dots that appear one after another. The page never knows where they are: the server draws them, times you on its own clock, and signs what it saw.

Challenge nonce · issued by the server
1 · Tap anywhere2 · Tap three dots3 · Prime
server: idle
Tap anywhere to begin.

Human gate

Waiting for a tap

Environment

client-side claims
Risk
—

Prime hunt

0
candidates tested
—
expected
—
per second
Pass the gate to unlock the hunt.

Proof bundle

Verifier

    What changed, and why

    The earlier gates had two structural holes against a client that reads the page and waits: it could read the dot's position from page state, and it reported its own timestamps. This version closes both without adding any friction. The "server" here is a Web Worker so the whole protocol runs in one file; in deployment it is the download endpoint.

    1. The page is blind. Each dot is SHA-256(secret ‖ challenge ‖ "dot k" ‖ opener ‖ tap₁ … tap_{k−1}), computed by the server from a secret the client never sees, placed relative to the previous landing. The server draws the dot itself on an OffscreenCanvas it controls. No page-side variable ever holds the real position; the client only learns a dot's position after it has been hit, to draw history.
    2. Decoys. What the page does hold, in the obvious place, is a decoy: a plausible but wrong position 70–110 px from the real dot. A client that reads page state presses the decoy. Nobody presses a dot that is not drawn. One decoy press is heavy risk (a human miss can land anywhere); two is a rejection.
    3. The server owns the clock. The server records when it revealed each dot and when each press arrived, on its own clock, and gates on those: first press ≥ 150 ms after reveal, hit within 12 s. The client's timestamps are still in the trace for the evidence metrics, but the floor is now a measurement, not a claim. The server signs a receipt, HMAC(secret, transcript ‖ its times), which only it can verify. That is correct: the verifier of a download gate is the server.
    4. Everything else carries over. Slack (12 s, 30 px plus half a finger on touch, five presses), straight-route rejection, press duration and contact geometry, errors as evidence, the risk score and the Sophie Germain work seeded by the full transcript.

    What beats it now

    A client that locates the dot by looking: a screenshot and a centroid, or a vision model, per dot. The "Vision bot" simulation is that client (it asks the server for the position, which is what a screenshot pipeline recovers), waiting a plausible interval with plausible dynamics. It passes the gate. The cost it carries is real seconds per dot on the server's clock, CPU-seconds of work per attempt, and a per-session feature vector the server can compare across sessions: a fleet of such bots is drawn from one generator and clusters, while people do not. For a book download that is the right economics: the scrape costs more than the book.

    Verifier

    1. Client-verifiable: scheme, challenge, traces decode, SHA-256(challenge ‖ opener ‖ taps ‖ contacts) equals the seed, candidate rederives, p and 2p+1 prime, and the gate recomputed against the dots the bundle claims.
    2. Server-only: the dots re-derived from the secret match the claimed ones, the receipt validates over the transcript and the server times, and the server-clock floor and ceiling hold. The server that issued the challenge is the only party that can run these; a bundle from another session is rejected here as "unknown challenge".