DocsIn Pigeon today
Zero knowledge in Pigeon today
Which parts of Pigeon use a zero-knowledge proof, which use something else, and what each one does.
The pieces
| Piece | What it is | A zero-knowledge proof? | In this alpha |
|---|---|---|---|
| Invite tokens: blinding | A verifiable oblivious pseudorandom function (VOPRF, RFC 9497, ristretto255 with SHA-512) | No. The privacy comes from blinding | On |
| Invite tokens: the server's proof | A DLEQ proof, from the same RFC: the server used the key it published | Yes, non-interactive (Fiat-Shamir) | On |
| Messages | End-to-end encryption with MLS (RFC 9420), through OpenMLS, then sealed again for the network (HPKE, RFC 9180, with X-Wing) | No. Encryption | On |
| Reports: message franking | Asymmetric message franking (Tyagi, Grubbs, Len, Miers and Ristenpart, 2019) over ristretto255: a signature of knowledge on each message | Yes, a signature of knowledge is a non-interactive zero-knowledge proof | Building toward Built and tested; reporting is switched off |
Invite tokens, step by step
An invite code carries a token minted blind, and the new account spends it for a second token, also blind (invite codes). Each mint goes like this:
- The app picks a random nonce, hashes it with a label and the key's period to a point on the curve, and multiplies that point by a random blind. Only the blinded point goes to the server.
- The server multiplies the blinded point by its secret key for that period and sends back the result with a DLEQ proof: the result and its public key were made with the same secret.
- The app checks the proof against the public key the server published for that period, removes the blind, and keeps the token: the nonce and the unblinded output.
- Spending a token, the app shows the nonce and output. The server checks them with its key and stores a hash of the nonce, so the token can't be spent twice.
The server never saw the nonce or the output at minting time, so what it stores (a roster, a mint counter and the hashes of spent nonces) can't join the person who invited you to the code, or the code to your new account. The DLEQ proof closes the remaining hole: without it, the server could answer one person with a key of its own and recognise their token when it is spent. Network addresses and timing are a separate gap, set out in our privacy policy.
These tokens are privately verifiable: only the server, which holds the key, can check one. That is enough for a gate the server runs itself.
Reports: proving who sent a message
A report will prove that a message really came from its sender, without telling us who reported it. Each message carries a frank: a commitment to its content, checked on arrival (message franking). The next layer adds a signature of knowledge over the message, which convinces the recipient and, once the message is reported, the moderator who judges it (the "judge", in the paper's words). To anyone else it proves nothing: the scheme lets anyone make one that looks the same from public keys alone. That layer is built and tested in Pigeon's core; reporting is switched off in this alpha.
What we are building toward
A public key log on the Midnight network, so anyone can check that the key behind a handle is the real one: Midnight and the key log.