Log in by proving you know the password

zk-hashing runs real password hashes (Argon2id, bcrypt and MiMC-7) inside a STARK proof. Your browser proves the password matches what the server stored. The server never receives the password, or a hash it could replay.

Try a password Check a STARK proof Read the code

Live browser → server demo

Type a password. Watch the server verify it.

Your password is hashed in this tab. The server gets a public key at registration and a fresh proof at login. Inspect every request below.

This live flow uses Argon2id + a Schnorr signature proving possession of the derived secret key. It lets you try any password without the full STARK prover’s memory cost. The Miden STARK example below verifies the full hash computation; this live proof does not certify which hash settings a client used.

01 / REGISTER

Choose a demo password

Only the public key, random salt and hash settings leave your tab.

02 / PROVE & VERIFY

Try to log in

The server sends a new challenge and checks your proof against its stored public key.

Choose a password to start. No account or email needed.

In your browser

The secret stays here

Your password and Argon2id output are used locally to derive a private signing key.

Server challenge
Waiting for a login
64-byte proof sent
Waiting for a login
On the actual Cloud Run server

What the server stores

No registration yet.

Last request fields: None yet

Inspect the actual network requests

These are the exact JSON bodies passed to fetch. You can also inspect /api/demo/ in your browser’s Network tab. The server accepts only the displayed fields.

No requests yet.

Demo accounts expire after 30 minutes or a server restart. This is a learning demo: a leaked public key can still be tested against password guesses. The password hash and signing key are never sent to this server.

How a login works

Two messages per login, and the only secret never leaves the browser.

  1. In the browser

    Register

    Pick a random salt, hash the password, and send a commitment to the result along with the salt and hash settings. The server stores those three things.

  2. On the server

    Send a challenge

    At login, send a fresh, single-use 128-bit challenge.

  3. In the browser

    Prove

    Run the full hash inside the Miden VM with the password as private input, and produce a STARK proof that the result matches the stored commitment. The proof is tied to this challenge.

  4. On the server

    Verify

    Check the proof against the stored commitment, the challenge it issued and the exact compiled program. Then mark the challenge used, so the same proof can't log in twice.

Where it stands

All three hashes run end to end inside the circuit. One can be proved today on ordinary hardware.

Algorithm What the circuit computes VM cycles Trace rows Proof
Argon2id v1.3 RFC 9106 in full: Blake2b, H′, 1 KiB blocks, BlaMka, hybrid addressing, passes, slices and lanes. Matches RustCrypto across 64 parameter cases. 19,593,971 225 Needs ~102 GiB
bcrypt 2b The full EksBlowfish key schedule, 2cost key and salt expansions, and 64 encryptions of the magic string. The 1,042 table words are checked against an in-circuit commitment. 367,224,034 229 Needs ~1.6 TiB
MiMC-7 Poseidon2 absorbs the password and salt, then all 220 MiMC rounds run. Cheap to prove, but not memory-hard, so it's a stand-in for testing the protocol rather than for storing passwords. 430,204 219 Proved in 39 s, 172 KB

What's blocking Argon2id and bcrypt

Prover memory. Password hashes are slow on purpose, and a general-purpose prover pays that cost again for every step it records.

Browser tab
4 GiB
Desktop PC
128 GiB
  • MiMC-7 1.6 GiBProved natively in 39 s
  • Argon2id, 8 KiB 102 GiBMeasured, then ran out of memory
  • bcrypt, cost 4 1.6 TiBEstimated from trace size
  • bcrypt, cost 10 ~102 TiBExtrapolated
  • Argon2id, 19 MiB ~408 TiBOWASP settings, extrapolated
Prover memory on a log scale; each step on the axis is 16× the last. Measured and estimated figures come from the project's test runs. Extrapolated figures scale the measured cycle counts by work factor at about 3.2 KB per trace row, so read them as rough orders of magnitude.

The prover writes out the whole execution trace and its low-degree extension before it commits to anything, and the row count rounds up to the next power of two. A browser tab can address at most 4 GiB, and even MiMC stalled at that limit in Chromium. For now, proofs come from a native prover and the browser verifies them. Turning the proof-security dial down doesn't help, because the trace itself is what's too big.

Check a login proof

You're the server. A client registered with the password hunter2, received the challenge below and sent back this MiMC-7 proof. Your browser checks it with the project's real verifier, compiled to WebAssembly. Nothing is sent anywhere.

Salt
000102030405060708090a0b0c0d0e0f
Challenge you issued
305419896, 2596069104, 267242409, 2271560481
Stored commitment
8370215289663149514, 8090811050392849221, 9444347110279816554, 1235188709954996380
Program hash
Loading…

Loading the verifier (9 MB)…

    What's next

    Current limits