All posts

Cryptography / August 9, 2026 · Updated August 11, 2026

Authentication that never sees the password

How a ceremony-bound proof replaces the password in a ZKAuth login request, plus the risks that zero knowledge does not remove.

Mohith · 6 min read

A password stays inside a client window while a robot guides a proof signal across a guarded boundary to a verifier.

A password database is dangerous even when every record is salted and deliberately expensive to guess. ZKAuth tests a different protocol: the client derives a commitment during registration, then proves knowledge of the matching password during login. The password itself is absent from both requests.

The difference begins in the wire format. Here is the request body the engine receives when someone registers:

POST /api/v1/auth/registerjson
{  "email": "ada@example.com",  "salt": "0x8f3a...",  "commitment": "0x2c17...",  "deviceInfo": { "deviceName": "Chrome on Mac", "deviceType": "desktop" }}

No password field. Before the request leaves the device, the zkauth-client SDK stretches the password with Argon2id, then binds the result to the user’s salt, the project, and the email with a Poseidon hash. The output is a commitment: a number the server can store that is not directly reusable as a login. As with any stored password verifier, a database compromise can still enable offline guessing, so password strength and Argon2id cost remain important.

Client device

PasswordNever transmitted
CommitmentDerived locally
Fresh ceremonyOne request
Proof generated locallyBound statement

Verifier

Trusted contextExpected public values
Verify onceConsume challenge
The secret stays on the client. Only the ceremony-bound proof and its public signals cross the network boundary.

Login proves knowledge in a fresh ceremony

At login, the SDK re-derives the same material on the device and generates a Groth16 zero-knowledge proof that says I know a password whose commitment matches the one you stored for this email, in this project, without revealing the password or even its hash. The login request looks like this:

POST /api/v1/auth/loginjson
{  "email": "ada@example.com",  "proof": { "pi_a": ["..."], "pi_b": [["..."]], "pi_c": ["..."] },  "publicSignals": ["...12 canonical V2 field values..."],  "proofProtocol": "zkauth-groth16-v2",  "policyVersion": 1,  "circuitVersion": "auth-v2",  "provingKeyVersion": "auth-v2-dev-0000",  "ceremonyId": "123e4567-e89b-42d3-a456-426614174000",  "challenge": "...server-issued 32-byte base64url challenge...",  "deviceInfo": { "deviceName": "Chrome on Mac", "deviceType": "desktop" }}

The engine loads the short-lived ceremony from its database, derives every expected public signal from trusted context, verifies the Groth16 proof, and atomically consumes the challenge when it creates the session. The statement binds the commitment, tenant, email, purpose, versions, challenge, ceremony, and exact expiry. Reuse, expiry, or any context mismatch is rejected.

What the protocol changes

  • A stored commitment is not a bearer credential. It cannot be submitted directly as a login, although a database compromise still creates offline password-guessing risk.
  • The proof is tenant-bound. A valid proof for one project cannot be replayed against another; the tenant hash is a public input to the circuit itself.
  • Intercepting the server request is less useful. There is no password in transit to steal from the ZKAuth request; device malware and fake login pages are still separate risks.

What zero knowledge does not solve

Malware on the user’s device is out of scope: if the device is compromised, the password can be captured before any cryptography runs. Groth16 over BN128 is not post-quantum. The current V2 proving keys are development artifacts, so this password-proof path is experimental and disabled by default in production.

Experimental production status

Promotion requires independent circuit review, a multi-party phase-2 ceremony, and signed artifact provenance. Passkeys remain the recommended production primary factor.

The Proof V2 Lab documents the unpublished SDK checkout required to run the flow. Exact measurements and verification scope live in the evidence record; broader risks remain on the limitations page.

Mohith

Founder, ZKAuth

August 9, 2026

Next post

When replay protection is unavailable, login stops