ZeroVerify Technical Specification
Version: 1.0 | Date: 2/15/26
Team: Lisa Nguyen (CS), Anton Sakhanovyvh (CS), Souleymane Sono (CS), Fateha Ima (CS), Simon Griemert (CS)
(CS) = Computer Science Major
Product Overview (The “What”)
Problem Statement: Existing identity verification systems require users to disclose entire credential documents (student IDs, driver’s licenses) to prove a single attribute, creating unnecessary privacy exposure and centralized data liability for verifiers. ZeroVerify allows circuit-defined attributes (“I am an enrolled student,” “I am over 21”) to be cryptographically proven without revealing any underlying personal data.
Target User: The primary persona is an end user (student, individual) who holds a digitally-issued credential and needs to selectively prove specific attributes to third-party verifiers (merchants, services, platforms) without exposing their full identity. Secondary actors are institutional identity providers (universities, employers) whose OAuth/OIDC infrastructure ZeroVerify delegates to for attribute verification during issuance, and verifiers (merchants, services) who integrate ZeroVerify’s open-source SDK to cryptographically validate proofs.
Minimum Viable Product (MVP) Features:
Credential Issuance: ZeroVerify authenticates the user via the institution’s OAuth/OIDC IdP, generates a W3C Verifiable Credential containing the user’s attribute set, signs it with a BBS+ signature, and delivers the signed credential to the user’s client for local storage.
Proof Generation: The user’s client runs a ZeroVerify-provided zk-SNARK circuit against their locally-stored credential. The circuit derives a boolean claim (e.g. “over 21”, “is a student”) from the credential’s attribute set, producing a proof of that claim without revealing the underlying attributes. If the credential does not contain the data required by the circuit, proof generation fails. No credential data leaves the device.
Proof Verification: A verifier uses ZeroVerify’s open-source SDK to validate the zk-proof against the issuer’s published verification key and checks credential revocation status against a publicly-accessible W3C Bitstring Status List that ZeroVerify hosts on S3. The cryptographic validation runs entirely on the verifier’s side with no round-trip to ZeroVerify’s infrastructure.
System Architecture (The “How”)
System Diagram
Architectural Boundary
ZeroVerify is a library and issuance service, not a verification intermediary. The system provides: (1) an issuance API that issues BBS+ signed credentials, (2) a client-SDK that handles credential storage and proof generation, and (3) a verification library that verifiers embed. Verifiers interact directly with users. They only call ZeroVerify to get a W3C revocation bitstring.
The Tech Stack
Backend: AWS Lambda (Rust)
The credential issuance service is implemented as a serverless Lambda function behind the API Gateway. Lambda is appropriate here because issuance is a stateless, event-driven operation with low baseline traffic and unpredictable spikes during enrollment periods. A persistent server (EC2 or ECS) would be over-provisioned at idle and require operational management that adds no architectural value for this workload. Lambda’s per-invocation billing and automatic scaling match the issuance traffic pattern.
Rust was chosen over Java or other runtime options because Lambda cold start times are critical for issuance responsiveness (target < 800ms total execution). Rust Lambda functions have significantly faster cold starts ( 100-300ms) compared to Java ( 1-3s) and lower memory footprint. Since issuance operations involve cryptographic operations (BBS+ signing) where memory safety is critical, Rust’s compile-time guarantees eliminate entire classes of vulnerabilities without runtime overhead. The BBS+ signature library ecosystem in Rust is mature, and Rust’s zero-cost abstractions ensure the 6-7.5ms signature operation target is achievable without JVM garbage collection pauses.
Database: AWS DynamoDB
Credential metadata is stored in DynamoDB. The access pattern is entirely key-value.
Revocation Storage: AWS S3
The revocation bitstring (a Bitstring Status List per the W3C spec) is stored as a static object in S3 and replicated globally using S3 Cross Region Replication (CRR). The bitstring is small (1 bit per credential) so CDN is not justified.
Client SDK: TypeScript
The proof generation library that runs entirely in the browser. The library fetches needed keys from ZeroVerify.
Infrastructure/IaC: Terraform/OpenTofu
Infrastructure is defined as code for reproducible deployments and CI/CD.
External APIs & Integrations
University OAuth 2.0/OIDC IdP
Used during credential issuance to authenticate the user and fetch authoritative attribute claims (enrollment status) from the IdPs” endpoint.
AWS Secrets Manager
The BBS+ issuer private key is stored here, since AWS KMS does not support BBS+ as it is not a NIST-standardized algorithm.
Data Design
Core Entities
List the 3–4 most important data objects:
Users
Proofs
Credentials
Proof Entity Schema
{
"proof_type": "age_over_21",
"proof": "base64_zkSNARK_proof_bytes",
"public_inputs": {
"challenge": "n-0S6_WzA2Mj",
"credential_status_index": 94567
}
} Credential Entity Schema
{
"student_id": "G89u28394",
"email": "anton@oakland.edu",
"first_name": "Anton",
"last_name": "Sakhanovych",
"birthdate": "2000-05-15",
"custom_claims": {
"student_status": "enrolled",
"enrollment_date": "2021-09-01",
"university": "Oakland University",
"major": "Computer Science"
}
} Data Schema
Relationships:
One user can have multiple different credentials. Specifically, they can draw their credentials from different sources (e.g. University, Job, Government). However, they will only have one unique
idp_unique_id.One user can generate many different proofs
Each signed credential can be used to generate many proofs
Credential Metadata Table:
{
"subject_id": "did:key:z6MkF5rGMoatr...",
"credential_id": "https://api.zeroverify.com/credentials/a3f8b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"credential_type": "Student_Credential",
"issued_at": "2025-02-10T20:41:27Z",
"expiresAt": "2026-02-10T20:41:27Z",
"revocation_index": 94567,
"revoked": false
} Storage Strategy
The files will be stored in AWS S3 and metadata about issued credentials will be in AWS DynamoDB.
Technical Complexity & Depth
The “Hard” Part
Integrating with existing Authentication protocols
OAuth/OIDC protocol variability: institutions use different implementations with varying standards compliance, attribute formats.
Designing Efficient and expressive zk-SNARK circuit
Designing circuits that prove boolean claims (e.g “Over 21”, “is student”) without revealing any underlying attributes.
Revocation consistency and batch processing
The core challenge is preventing race conditions when multiple Lambda functions concurrently process revocation requests. For example: 1000 users generate revocation requests → SQS queue batches them (100 requests/batch) → lambda reads S3 bitstring, modifies bits for all 100 requests, write back to S3. However, concurrent lambda invocations reading and writing the same S3 file create race conditions where revocation updates can be lost or overwritten. The solution is implementing optimistic locking or atomic update mechanism to ensure all revocation bit flips are captured under high concurrency.
Performance Goals
Credential Issuance
OAuth/OIDC authentication < 500ms
Lambda execution for credential generation < 800ms
BBS+ signature Operation: 0.3 - 7.5ms per credential
DynamoDB write: 20ms
Credential delivery to user: 200ms
Client-Side Proof Generation Performance
zk-SNARK Circuit Execution
- Target: < 4 seconds for proof generation
Proof Verification
Target: < 300ms for complete verification
Cryptographic zk-proof validation < 150ms
BitString retrieval from S3 < 100ms
BBS+ Signature Operation
Credential signing: 6-7.5ms
Proof Generation: 1-2ms
Proof Verification: 19ms/zk proof
Revocation Processing
Revocation Update Latency: < 10 min from revocation request to global availability
Batch Processing:
Process 100 revocations requests/batch
Lambda execution time: < 3s/batch
S3 upload < 1 second
Race condition Handling:
Target: 99.9% consistency for concurrent revocation update
Use DynamoDB conditional writes or optimistic locking
Resilience & Security
Error Handling
If the OAuth IdP fails or times out, the system returns HTTP 503 and prompts the user to retry.
If the revocation list cannot be retrieved, the system denies verification rather than approving the proof.
The system implements a circuit breaker approach:
After repeated external API failures, requests temporarily fail fast instead of waiting for long timeouts.
The system retries after a cooldown period.
ZeroVerify follows a fail-safe policy: verification is never approved if validation cannot be fully completed.
Security
All communication between users, verifiers, and ZeroVerify uses HTTPS (TLS 1.2+).
Server-side data (DynamoDB and S3) is encrypted using AWS KMS.
ZeroVerify does not store raw PII after credential issuance.
Credentials are stored locally in the user’s browser and are not transmitted to ZeroVerify unless generating a proof.
Each proof is bound to a verifier-provided session nonce to prevent replay attacks.
Session identifiers expire after a fixed time window (e.g., 5 minutes).
The verification API validates:
Proof structure
Cryptographic validity
Issuer signature
Revocation status
IAM roles follow least privilege principles.
API keys and signing keys are stored in AWS Secrets Manager and are never hardcoded in source code.
The system never returns “valid” if verification fails or is incomplete.
Milestone Roadmap (The “When”)
Phase 1 (Weeks 1-3): Prototype Implementation
Infrastructure + Database Schema + Issuance Skeleton (API endpoints)
Set up basic infrastructure so the demo can run end-to-end (frontend + backend running).
Create the minimal database schema needed for the demo (credential storage + proof session/challenge tracking).
Set up Keycloak identity middleware (login/authentication) and connect it to our backend.
Stand up the issuance API skeleton (endpoints exist and respond):
POST /api/credentials/request (start issuance)
POST /api/idp/mock-login (mock IdP auth)
POST /api/credentials/issue (issue/store credential)
Trusted Setup (required before credential generation + proofs)
Run a trusted setup to generate the setup parameters/files needed for our circuits so credential-related proof generation and verification can work.
Deploy verification and proving key to the S3
Credential Issuance Flow
Backend generates the credential and returns it to the web app, and the credential is stored locally in the user’s browser
The user clicks “Request Credential” on our web app to start issuance.
Create a mock verifier.
Replay Protection (session nonce/challenge binding)
Generate a unique session challenge (session nonce) per verification attempt and bind it to the proof (handled as part of the circuit).
Demo check: attempt to reuse an old proof in a new session → should be rejected.
Proof Generation + User Consent (at least 1 proof type)
Proof request is shown in our web app and the user must approve/deny.
On approval, generate a proof for one proof type (ex: student status or over 21).
Verifier Verification Flow (Accepted/Rejected) (last step)
Verify proof using issuer public key + public inputs.
Return Accepted/Rejected and log basic non-PII debug info.
Phase 4 (Week 4-6): Hardening + UI + Testing
Goal: Done by April 13
Error handling + clear rejection reasons
Add clear rejection reasons: invalid, malformed, revoked, expired
Invalid: proof doesn’t verify
Malformed: missing/wrong format
Revoked: credential was disabled
Expired: session/challenge/credential expired (if applicable)
Revocation checking (if in scope for demo)
Add a revocation check during verification
Demo case (if implemented): revoked credential → rejected
UI polish for demo flow
Simplify the demo screens and prompts
clear “Approve/Deny” consent step
clear “Accepted/Rejected” result screen
Testing plan + test cases
Happy path: request → approve → proof generated → verify → accepted
Failure cases: replay attempt, malformed input, invalid proof (and revoked/expired if implemented)
Phase 5 (Week 7-Finals): Final Checklist + Demo Prep
Deployment/demo packaging + documentation cleanup
Decide demo format: hosted or local run
Create simple “how to run” steps so any teammate can launch the demo
Cleanup documentation so it matches what we actually built
Final deliverables prep
Finalize website/video (if required)
Lock demo script + slide updates (who presents what, demo steps)
Final product demo (Finals Week)
Final rehearsal + backup plan (in case something breaks)
Deliver final demo during finals week
Limitations and Tradeoffs
Credential Revocation
We implement W3C Bitstring Status Lists rather than PKI mechanisms (CRL/OCSP) because bitstrings preserve verification privacy. CRL requires merchants to download lists of revoked credential identifiers, creating linkability. OCSP requires real-time queries with credential identifiers, exposing verification patterns. Bitstrings encode revocation as bit positions in a compressed list; merchants fetch the bitstring, check the relevant bit locally, reveal nothing about which credential they’re verifying. Users self-revoke by generating ZK proofs of credential ownership. Time-based expiration handles normal lifecycle without revocation overhead.
Proof Generation Cost
Generating ZK Proofs takes 2-5 seconds on modern devices. This is more compute-intensive than submitting a SheerID form. However, it is faster than uploading the document and waiting for manual approval. The computational cost shifts from servers to user’s device.
Browser Security vs Apple’s hardware wallet
Browser-based credentials storage is less secure than Apple’s secure element. However, our architecture never transmits the credentials. Credentials always stay on the device, and only ZK proofs are sent. Even if someone compromises browser storage, they get only one user’s credentials, not a centralized database of millions. Apple’s approach is more secure, but their selective disclosure still sends identity data. We trade hardware-level security for zero data disclosure.
Trust
Merchants trust our mechanism through cryptographic verification, not reputation. The ZK proof is mathematically verifiable using our public key; if it verifies, the credential was genuinely issued by us and hasn’t been tampered with. We issue credentials only after OAuth confirmation from the authoritative source; the issuer is the source of truth, not us. Merchants can audit our public key and verification code for transparency. SheerID offers broader coverage through 200,000+ data sources but requires collecting excessive user data. We offer cryptographic certainty with zero data collection. Initial adoption requires pilots with privacy-conscious brands.