Anonymous Tip Lines with Cryptographic Identity Proofs
Whistleblowing platforms face a fundamental tension. Sources need anonymity — the network must not learn who they are or that they contacted a journalist. But the journalist needs authentication — they must know the source is a credible insider, not a random tipster or a state actor planting disinformation. Existing tools force a choice: SecureDrop anonymizes but cannot authenticate; authenticated tip lines authenticate but expose the source's identity to the server. Tessera resolves the tension with zero-knowledge proofs under blinded pseudonyms.
The problem: anonymity without authentication, or vice versa
SecureDrop and similar Tor-based dropboxes provide strong source anonymity but no way to verify that a second submission comes from the same insider as the first — let alone to verify the source holds a specific role or clearance. Conversely, an authenticated tip line (SSO login, signed email) verifies identity but records the source's identity in server logs, defeating the purpose for anyone whose employer can subpoena or compromise the platform.
The result is that the two properties journalists want — "I know this source" and "the network doesn't know this source" — are treated as mutually exclusive. They are not. Cryptography separates them cleanly.
| Approach | Authenticates source | Metadata-private | Scalable |
|---|---|---|---|
| SecureDrop / anonymous drop | No | Partially (Tor) | Yes |
| Authenticated tip line | Yes | No | Yes |
| Tessera | Yes | Yes | Yes |
How Tessera solves it
Tessera authenticates the source with a Schnorr / Fiat–Shamir zero-knowledge proof under a blinded pseudonym. The proof convinces the journalist's verifier that the sender holds a known long-term key, without revealing that key to the network — and without linking this delivery to any other delivery, even to the same source.
- ZK proof authenticates the source. The journalist pre-enrolls the source and holds a
shared_seed. Each submission carries a proof the journalist's verifier accepts or rejects — 0% forgery across tamper, swap-key, forge, and replay trials. - Blinded pseudonyms hide identity. The source presents
Y' = Y + tGper session; the network sees a fresh, unlinkable pseudonym, never the long-term public keyY. - Metadata-private transport. Submissions route to buckets over a relay overlay with (ε,δ)-DP cover traffic. An observer cannot tell that this source contacted this journalist.
Architecture
Enrolment is a one-time, out-of-band meeting (in person or over a trusted channel): the source generates a long-term keypair and shares a shared_seed with the journalist. After that, every submission is autonomous and metadata-private.
Source (insider) Journalist (tip line)
───────────────── ───────────────────
long-term key (x, Y) shared_seed (from enrolment)
expected_pubkey Y
│
per submission:
1. session_id = fresh UUID
2. Y' = BlindedSender(Y, shared_seed, session_id).pseudonym()
3. π = BlindedSender(...).prove(submission_payload)
4. ct = SecureEncryption.encrypt(π, payload, journalist_key)
5. broadcast → bucket (DP cover traffic)
│
6. pull from bucket
7. decrypt → (π, payload)
8. BlindedVerifier.verify(π, Y', payload)
→ accept: known source, verified
→ reject: forged or unknown
Code example: a simple whistleblowing flow
from tessera.sdk import Sender, Verifier
from tessera.crypto.blinding import BlindedSender, BlindedVerifier
from tessera.crypto import SecureEncryption
# --- one-time enrolment (in-person meeting) ---
shared_seed = os.urandom(32) # source hands a copy to the journalist
# --- source prepares a submission ---
source = Sender(secret_key=b"...insider long-term sk...")
blinded = BlindedSender(source.public_key, shared_seed, session_id="tip-2026-06-29")
y_prime = blinded.pseudonym()
proof = blinded.prove(b"Folder /evidence/fy26 contains the records")
# encrypt the (proof, payload) for the journalist's transport key
ct = SecureEncryption.encrypt(proof, b"Folder /evidence/fy26 ...", journalist_pubkey)
# broadcast over relay overlay — network sees only a bucket address
relay.broadcast(bucket=compute_bucket(journalist_fingerprint), ciphertext=ct)
# --- journalist verifies ---
bver = BlindedVerifier(
Verifier(expected_pubkey=source.public_key),
shared_seed, session_id="tip-2026-06-29",
)
ok = bver.verify(proof, y_prime, b"Folder /evidence/fy26 contains the records")
assert ok # known source, cryptographically authenticated, network-blind
Why this beats signed-email tip lines
A signed email authenticates the source but leaves the source's identity in every mail server log along the path — exactly the metadata a whistleblower needs to keep private. Tessera's blinded pseudonym means the same authentication guarantee holds without any server learning that this source contacted this journalist, or that this submission is related to a previous one. The journalist gets verifiable attribution; the source gets network anonymity.
Frequently asked questions
What happens if the source loses their long-term key?
The long-term key is the root of authentication. If lost, the journalist can no longer verify submissions from that source — re-enrolment is required. Tessera's keystore supports PBKDF2-encrypted backups and key rotation; sources should back up the encrypted keystore, not the raw key.
Can a journalist prove to a third party (e.g. a court) which source sent a submission?
No — that is the point. The ZK proof is zero-knowledge: it convinces the verifier and no one else. The journalist can attest that they verified a submission, but they cannot cryptographically transfer that proof to a third party without the source's cooperation. This is the property that protects sources under subpoena pressure.