What the network knows about you.
Two mechanisms, and an honest account of what neither of them does. Anonymous access hides which holder is asking. Sealed prompts stop the orchestrator reading the text it routes. Everything below is backed by code in this repository; anything that is not built says so.
Reading the gate…
What leaked before
The network already stripped identity before a job reached a worker, and kept no prompt text. Then the $ZKMOSQ access gate arrived, and every request started carrying a wallet signature. The orchestrator could tie a wallet to every prompt it served. The token gate created exactly the linkage the privacy claim was about, and closing it is what this work is.
Anonymous access
You register once. A signature binds a Semaphore commitment to your wallet, the orchestrator reads your on-chain $ZKMOSQ balance and files the commitment under a tier. That step is public on purpose: it is the only place a balance can be checked.
After that, each request carries a membership proof instead of a wallet. The proof says “some member of this tier”, is bound to that exact request, and burns a single-use nullifier. One nullifier per slot per identity is what enforces the tier’s daily cap, cryptographically, without anyone keeping a per-wallet counter. Your browser builds the whole member set locally and proves against it, because asking the server for one member’s Merkle path would tell it which member is about to send a request.
The circuits are Semaphore v4, existing audited work. We write none of our own. Proving runs in your browser and costs about half a second:
| Build a 1,000-member group (depth 10) | 225 ms |
| Generate a proof | 527 ms |
| Verify a proof | 0 to 14 ms |
| Proof size | about 884 bytes |
Measured on a 6-core laptop under Node 20. Verifying is the orchestrator’s cost, and it is a rounding error next to running a model.
Sealed prompts
This one is not ZK, and we will not describe it as ZK. It is ordinary public-key encryption, and it closes the other half of the leak: without it the orchestrator can read prompt text in memory while routing it.
Every worker publishes an X25519 public key for its session. Your browser reserves a worker, derives a shared key against that key (ECDH, then HKDF-SHA256 salted with the job id) and encrypts the payload with AES-256-GCM. The worker decrypts, runs the model, and encrypts each token frame on the way back. The orchestrator relays opaque frames and becomes a blind relay. Token counts still travel in clear, so billing and settlement are untouched.
The orchestrator gets metadata without content. The worker gets content without identity. Registration gets identity, and stops there. No party holds both halves, which is the whole design.
Registration
Once per wallet. Public on purpose, and this is where it stops.- That this wallet joined this tier
- Its on-chain $ZKMOSQ balance
- Anything you ask later
- Which request is yours
Nothing crosses this line. A request carries a proof that some member of the tier sent it, and a single-use nullifier that spends one of the day's slots. Neither can be traced back to the wallet above.
Your browser
Holds everything. Nothing below it does.- The prompt
- Which wallet you are
- Your identity secret
The orchestrator
Routes and bills. Relays ciphertext it cannot read.- That some member of a tier asked
- Which model, and the token counts
- When the request happened
- Your IP address
- Which wallet asked
- The prompt text
- The answer text
The GPU worker
Runs the model. Gets the text, never the person.- The prompt text
- The answer it generates
- Which model and parameters
- Which wallet asked
- Your account or billing
- Your IP address
- Your tier
What this does not do
Privacy claims are worth what their limits are worth. These are the limits, and they are not footnotes.
It does not prove the model ran
Nothing here proves a worker ran the model you asked for, or ran it correctly. That is the state of the field, not a shortcut: the high-water mark for zkML is a full proof of GPT-2, and proving LLaMA-2-7B costs roughly 2,646 seconds per token. One sentence would take weeks. Verifiable execution is a later phase and would use TEE attestation or sampled re-execution, not ZK.
It does not hide that you asked
A sealed, anonymous request still tells the orchestrator that a request happened, which model it used, how many tokens went in and out, and when. Billing and routing run on exactly that.
It does not hide your IP
You connect over the network, so the orchestrator sees your address. We don’t log IPs and they are stripped before a job reaches a worker, but “we don’t log it” is a policy, not a proof. If the operator is in your threat model, use a VPN or Tor. That is your call, not something the protocol makes for you.
It is only as good as the set size
A proof hides you inside the registered holders of your tier and nothing more. In a set of three, the set identifies you. The panel above reports the live size of every tier so you can judge it before relying on it.
Registration itself is public
Registering binds a wallet to a commitment through an on-chain balance check, and that record is not hidden. Anyone can see a wallet joined a tier. What nobody can see is which member sent any particular request.
The request path, the endpoint shapes and the worker-side rules are in the privacy docs, and the console shows per request which of these protections actually applied.
