ZKPs Are Not Just for Crypto
Search for "zero-knowledge proofs" and you'll find 9 out of 10 results talking about rollups, zk-EVMs, and L2 scaling. That's fine — ZKPs are transformative for blockchain. But the core primitive — proving a fact without revealing the underlying data — is useful far beyond cryptocurrency.
A zero-knowledge proof lets a prover convince a verifier that a statement is true without transmitting any information beyond the truth of that statement. The mathematics don't care whether you're proving a transaction is valid on Ethereum or proving a user is over 21 without showing their driver's license.
A ZKP is a proof that a statement is true, where the proof reveals nothing except that the statement is true. No data leaks. No trust required. Mathematically guaranteed.
The reason ZKPs are so blockchain-dominated in popular discourse is historical — Zcash in 2016 brought ZK-SNARKs to mainstream attention, and the Ethereum ecosystem funded most of the subsequent tooling. But the underlying math (polynomial commitments, interactive oracle proofs, hash-based constraints) is completely general. The proof doesn't know or care what it's proving.
This post is for developers who want to use ZKPs for identity, credentials, and compliance — without deploying a single smart contract.
Real-World Use Cases (Without a Single Token)
Here are concrete, production-ready applications of zero-knowledge proofs that have nothing to do with blockchain:
In every case, the pattern is the same: a prover (the user or their agent) generates a proof from private data, and a verifier (the service) checks the proof without ever seeing the data. No blockchain needed. No gas fees. No wallet. Just an API call.
How H33's ZKP API Works
H33's ZKP system is STARK-based (Scalable Transparent ARgument of Knowledge), not SNARK-based. This is a deliberate architectural decision with three consequences:
- No trusted setup — SNARKs (Groth16, PLONK) require a one-time trusted setup ceremony where toxic waste must be destroyed. If the ceremony is compromised, all proofs are forgeable. STARKs eliminate this entirely. See ZK-SNARKs Explained.
- Post-quantum secure — STARKs rely on collision-resistant hash functions (SHA3-256), not elliptic curve pairings. They remain secure against quantum computers running Shor's algorithm. See STARK Proofs: Quantum-Resistant ZK.
- Transparent verification — Anyone can verify a STARK proof with only public parameters. No secret keys, no ceremony artifacts, no trust assumptions.
Here's what a ZKP verification looks like through the H33 API:
curl -X POST https://api.h33.ai/v1/zkp/verify \ -H "Authorization: Bearer $H33_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "proof": "base64_encoded_stark_proof", "public_inputs": { "statement": "age_gte", "threshold": 21, "issuer_commitment": "sha3_256_of_issuer_pk" } }' // Response { "verified": true, "statement": "age_gte", "threshold": 21, "proof_system": "STARK", "hash_function": "SHA3-256", "post_quantum": true, "latency_us": 0.062, "proof_size_bytes": 192, "data_revealed": "none" }
The verifier never sees the user's date of birth, ID number, or any personal data. The proof is a 192-byte STARK attestation that the statement "age >= 21" is true, given a commitment from a trusted issuer. Verification takes 0.062µs on a cached DashMap lookup.
STARK vs SNARK for Identity
The choice between STARKs and SNARKs matters more for identity applications than for blockchain rollups. Here's why:
| Property | SNARK (Groth16 / PLONK) | STARK (H33) | Why It Matters for Identity |
|---|---|---|---|
| Trusted Setup | Required | Not required | Identity proofs must be trustless from day one |
| Quantum Resistance | No (ECC-based) | Yes (hash-based) | Identity credentials persist for years/decades |
| Proof Size | ~128 B (Groth16) | ~192 B (cached) | Both small enough for API transport |
| Verification Speed | ~1.2 ms | 0.062 µs (cached) | Sub-microsecond enables real-time auth flows |
| Prover Complexity | Lower | Higher | H33 handles proving server-side |
| Transparency | Ceremony-dependent | Fully transparent | No trust assumptions in identity infrastructure |
For blockchain rollups, SNARKs win on proof size (cheaper on-chain verification). For identity, that advantage disappears — proofs are verified via API, not on-chain. STARKs win on every axis that matters for identity: no trusted setup, quantum resistance, and transparent verification.
Identity credentials issued today may need to be verifiable in 2035. If your ZKP system is based on elliptic curve pairings (SNARKs), a quantum computer can forge proofs for any previously issued credential. STARK proofs based on SHA3-256 remain secure regardless of quantum advances.
Performance
H33's ZKP verification leverages an in-process DashMap cache that stores pre-verified STARK proof hashes. For repeat verifications (the common case in production — the same credential checked by multiple verifiers), the lookup is a hash table read:
ZKP Verification Performance
At 0.062µs, cached ZKP verification is faster than a typical Redis GET (~50µs network round-trip) or PostgreSQL index scan (~200µs). You can verify a zero-knowledge proof faster than you can look up a row in a database. This means ZKP verification adds zero measurable latency to your authentication flow.
Proof size is 192 bytes — smaller than a typical JWT. Batch proving scales linearly: 100 proofs in 35ms, making bulk credential issuance practical for enterprise deployments.
| Metric | Value | Comparison |
|---|---|---|
| Cached verification | 0.062 µs | 800x faster than Redis GET |
| Proof size | 192 bytes | Smaller than a typical JWT (~800 B) |
| Batch (100 proofs) | 35 ms | 350 µs per proof amortized |
| Post-quantum | Yes (SHA3-256) | No ceremony, no ECC dependency |
Integration Guide
H33's ZKP API follows a three-step flow: create a proof request, generate the proof (server-side or client-side with our SDK), and verify the proof. Here's the complete age verification flow in four languages.
Step 1: Create a Proof Request
curl -X POST https://api.h33.ai/v1/zkp/request \ -H "Authorization: Bearer $H33_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "age_verification", "threshold": 21, "issuer": "state_dmv", "callback_url": "https://yourapp.com/api/zkp/callback" }' // Response { "request_id": "zk_req_8xNm...", "challenge": "base64_challenge_nonce", "expires_at": "2026-03-23T12:05:00Z" }
Step 2: Generate the Proof (Server-Side)
import { H33 } from '@h33/sdk'; const h33 = new H33({ apiKey: process.env.H33_API_KEY }); // Generate a proof that the user is over 21 // The SDK never sends the raw date of birth to H33 const proof = await h33.zkp.prove({ type: 'age_verification', threshold: 21, credential: userCredential, // signed by issuer, stays local challenge: requestChallenge // from Step 1 }); // Send proof to verifier const result = await h33.zkp.verify({ proof: proof.proof, public_inputs: proof.public_inputs }); console.log(result.verified); // true console.log(result.latency_us); // 0.062
from h33 import H33Client client = H33Client(api_key=os.environ["H33_API_KEY"]) # Generate proof — raw credential never leaves your server proof = client.zkp.prove( type="age_verification", threshold=21, credential=user_credential, challenge=request_challenge ) # Verify the proof result = client.zkp.verify( proof=proof.proof, public_inputs=proof.public_inputs ) assert result.verified == True print(f"Verified in {result.latency_us} µs") # 0.062 µs
use h33_sdk::{H33Client, zkp::ProveRequest}; let client = H33Client::new(std::env::var("H33_API_KEY")?); // Generate proof let proof = client.zkp().prove(ProveRequest { proof_type: "age_verification".into(), threshold: 21, credential: user_credential, challenge: request_challenge, }).await?; // Verify let result = client.zkp().verify(&proof).await?; assert!(result.verified); println!("Verified in {} µs", result.latency_us); // 0.062
# Step 1: Create proof request REQUEST=$(curl -s -X POST https://api.h33.ai/v1/zkp/request \ -H "Authorization: Bearer $H33_API_KEY" \ -H "Content-Type: application/json" \ -d '{"type":"age_verification","threshold":21}') CHALLENGE=$(echo $REQUEST | jq -r '.challenge') # Step 2: Generate proof (with pre-signed credential) PROOF=$(curl -s -X POST https://api.h33.ai/v1/zkp/prove \ -H "Authorization: Bearer $H33_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"age_verification\", \"threshold\": 21, \"credential\": \"$USER_CREDENTIAL\", \"challenge\": \"$CHALLENGE\" }") # Step 3: Verify proof curl -X POST https://api.h33.ai/v1/zkp/verify \ -H "Authorization: Bearer $H33_API_KEY" \ -H "Content-Type: application/json" \ -d "$(echo $PROOF | jq '{proof: .proof, public_inputs: .public_inputs}')" # {"verified": true, "latency_us": 0.062, "proof_size_bytes": 192}
Why Not Just Use JWTs?
JWTs are the standard bearer token for web authentication. They work. But they have a fundamental architectural flaw for privacy-sensitive claims: JWTs reveal their contents to every verifier.
When you embed "age": 25 or "kyc_status": "verified" in a JWT,
every service that validates that token sees those claims in plaintext. The verifier learns
not just that the user is over 21, but their exact age. Not just that they passed KYC, but
potentially which provider, when, and at what level.
| Property | JWT | ZKP |
|---|---|---|
| Data exposure | All claims visible to all verifiers | Zero data revealed beyond the statement |
| Selective disclosure | Not natively supported | Built-in — prove only what's needed |
| Verifier trust | Verifier sees all claims (must be trusted) | Verifier is untrusted by design |
| Token size | ~800 B (typical) | 192 B (proof only) |
| Quantum resistance | No (HMAC-SHA256 / RS256) | Yes (STARK / SHA3-256) |
| Forgery on compromise | Signing key leaked = all tokens forgeable | No signing key — proofs are self-verifying |
| Privacy guarantee | None (plaintext claims) | Mathematically proven zero-knowledge |
This doesn't mean you should replace all JWTs with ZKPs. JWTs are fine for session tokens and non-sensitive claims. But for identity attributes — age, income range, credit score bracket, health status, professional credentials — a ZKP is strictly better. The verifier gets exactly the information they need and nothing more.
Under GDPR, every piece of personal data you collect creates a compliance obligation. With JWTs, you're collecting and storing claims you don't need. With ZKPs, you collect zero personal data — you verify a mathematical proof. No data minimization required because there's no data to minimize. Your attack surface for data breaches drops to zero for ZKP-verified attributes.
Architecture: How It Fits Together
The ZKP flow integrates into standard API architectures without requiring blockchain nodes, wallet infrastructure, or smart contract deployments:
ISSUE
PROVE
VERIFY
POST /zkp/verify with the 192-byte proof.
H33 returns a boolean result in 0.062µs (cached). The verifier never sees
the credential, the user's data, or anything beyond the truth of the statement.