Mizaru is a cryptographic protocol designed to provide privacy-preserving authentication in the Geph5 network, using blind signatures to protect user anonymity.
In Geph5, Mizaru allows clients to prove they are authenticated without revealing their identity or usage patterns to exit nodes. This means that even if Geph's servers are compromised, user identities cannot be linked.
The unifying design goal is for Geph to be as anonymous as an unauthenticated open proxy, despite having user accounts and payments.
Mizaru is inspired by anonymous-credential systems like Privacy Pass, but with these main differences:
- Instead of one-time anonymous credentials, Mizaru anonymous credentials reusable within 24 hours. This is because while Privacy Pass is used in a context where we need unlinkability between different requests, Mizaru is used in a context where we want unlinkability between different days in a user's activity.
- This may seem weaker, but VPN sessions last for a long time, and it's generally infeasible to provide unlinkability between different user actions within the same VPN session. Linkability within 24 hours is equivalent to everyone using 24-hour burner accounts, which is not meaningfully less anonymous compared to not having authentication.
- Integer-math cryptographic primitives (FDH-RSA) are used instead of elliptic curves.
There are three roles involved:
- The client is the Geph user
- The broker validates client authentication and interacts with the client to create an anonymous credential
- The exit is the VPN server that the user actually connects to
Neither the broker nor the exit are trusted for anonymity.
Here we talk about the primitive building blocks of Mizaru, generally exposed in this library.
- Let
$T \in {0,1}^{256}$ be a client token, a 32-byte random value generated by the client. -
$T$ is the client’s anonymous identity token for one epoch, and must remain private.
We use the "standard" blind-signature scheme based on RSA and full-domain-hashes:
- Suppose
$(N, e)$ is an RSA public key, where$e$ is the standard RSA public exponent. - The client chooses a blinding factor
$r$ coprime to$N$ . - Define the blinded token:
where
- The broker holds
$2^{16}$ RSA key pairs:
each 2048 bits, indexed by
- A Merkle tree based on blake3 is is constructed over all
$2^{16}$ public keys$\bigl(N_i, e_{i}\bigr)$ . Leaves are hashes of these public keys; internal nodes are hashes of their children. - The broker long-term public key is the Merkle root:
- Any party with
$\mathsf{Root}$ and a proper Merkle proof for index$i$ can verify that$\bigl(N_i, e_{i}\bigr)$ is indeed one of the server’s valid public keys.
-
Token generation
- The client generates a random 32-byte token:
-
Epoch and key retrieval
- Define the epoch:
$E = \left\lfloor \frac{\text{UnixTime}}{86400} \right\rfloor$ - A function
$f(E)$ derives a key index$i \in {0,\dots,2^{16}-1}$ . For example,$i = E \bmod 65536$ . - The client requests both the broker's RSA public key
$\bigl(N_i, e_{i}\bigr)$ and a corresponding Merkle proof from the broker. - Client validates the Merkle proof:
- Using the known root
$\mathsf{Root}$ , which is hardcoded, the client checks that$\bigl(N_i, e_{i}\bigr)$ indeed appears as the valid leaf at index$i$ . - This prevents an untrusted broker from substituting a rogue public key in order to allow exits to deanonymize users.
- Define the epoch:
-
Blinding process
-
Once the client verifies the key
$\bigl(N_i, e_{i}\bigr)$ , it selects a random$r$ (coprime to$N_i$ ) and computes:$T' = \bigl(H(T) \cdot r^{,e_{i}}\bigr) \bmod N_i.$ -
The client sends
${ E, i, T' }$ to the broker.
-
-
Broker signing
-
The broker checks the client’s regular credentials (e.g., username/password).
-
If valid, the broker applies its private exponent
$d_i$ :$\sigma' = (T')^{d_i} \bmod N_i.$ -
The broker returns
$\sigma'$ (plus the Merkle proof again if needed, though typically the client already has it from step 2).
-
-
Unblinding
-
The client computes
$r^{-1}$ modulo$N_i$ and calculates:$\sigma = \sigma' \cdot r^{-1} \bmod N_i.$ -
Thus,
$\sigma$ is a valid RSA-FDH signature on$H(T)$ .
-
-
Verification
- To prove authenticity (e.g., to an exit node), the client presents
${ T, \sigma, E, i, \text{MerkleProof}(i) }$ . - The verifier checks:
-
Merkle proof: that
$\bigl(N_i, e_{i}\bigr)$ is a valid leaf at index$i$ under$\mathsf{Root}$ . -
RSA signature:
$\sigma^{,e_{i}} \bmod N_i \stackrel{?}{=} H(T)$ . -
Epoch validity:
$E$ is current (e.g., the correct 24-hour window).
-
Merkle proof: that
- To prove authenticity (e.g., to an exit node), the client presents
-
Broker key confidentiality
- Protect private exponents
${ d_i }$ . A leak enables forging of blind signatures for the corresponding epoch(s).
- Protect private exponents
-
Merkle proofs
- If the client fails to verify the Merkle proof, it could blindly trust a malicious key.
- Ensuring the client holds the correct
$\mathsf{Root}$ is crucial (e.g., pinned or distributed securely).
-
Replay within the epoch
- By design, a valid token can be replayed. After 24 hours, it expires.
-
Forward privacy
- After an epoch ends, the user obtains a new token. Past tokens do not link to future tokens, as each day effectively resets the user’s identity handle.