Skip to content

Zero-Knowledge Proof Verifier for Anonymous Meter Reading Submissions Using Groth16 over BLS12-381 #64

Description

@elizabetheonoja-art

Problem Statement / Feature Objective

Privacy regulations in certain jurisdictions require that meter reading submissions do not reveal the individual meter's identity or precise consumption to the central server. A zero-knowledge proof module must allow field operators to submit an encrypted meter reading along with a zk-SNARK proof that the reading is within an acceptable range (e.g., between 0 and 10,000 kWh) and was generated by a registered meter, without revealing the actual value or meter ID. The verifier runs client-side during audit, using a proving key cached from the Soroban contract's verification key registry.

Technical Invariants & Bounds

  • Proof system: Groth16 over BLS12-381 curve, compiled via circom + snarkjs to WASM. Proving key size: ~150 MB (must be cached in IndexedDB, not re-downloaded per proof).
  • Circuit constraints: ~50,000 R1CS constraints (range check + membership check + hash). Proving time target: under 30 seconds on a field tablet.
  • Input private signals: meterId (248 bits), consumption (64 bits), salt (248 bits). Public signals: merkleRoot (256 bits), encryptedCiphertext (512 bits), timestamp (32 bits).
  • Encryption: reading is encrypted using the server's public key (x25519) before submission. The proof ensures ciphertext corresponds to the plaintext without revealing it.
  • Verification key: stored on-chain in the Soroban contract under DataEntry key zk_verification_key; fetched and cached locally for 24 hours.
  • Freshness: each proof must include a recent block hash (last 10 ledgers) as a public signal to prevent replay attacks.

Codebase Navigation Guide

  • src/services/zkProver.ts - Orchestrator: loads proving key, constructs witness, invokes snarkjs Groth16 prover.
  • src/workers/zkProver.worker.ts - Web Worker running the WASM prover off the main thread; receives circuit inputs, returns proof + publicSignals.
  • public/wasm/zk/circuit_final.zkey - Proving key (symlink or placeholder; actual file hosted on CDN due to size).
  • src/services/zkVerifier.ts - Client-side verifier using snarkjs; loads verification key from Soroban contract and verifies proof.
  • src/hooks/useZKSubmission.ts - React hook: prepareInputs, generateProof, submitEncrypted, verify.
  • src/components/panels/ZKSubmissionPanel.tsx - UI panel for encrypted meter reading submission with proof generation progress bar.
  • src/services/keyCache.ts - IndexedDB store for caching the proving key (~150 MB) with LRU eviction and integrity check.

Implementation Blueprint

  1. Design the circom circuit: RangeCheck(consumption, 0, 10000), MembershipCheck(meterId, merkleRoot), HashEquality(consumption, ciphertext). Compile to WASM with circom and snarkjs.
  2. Host the proving key (circuit_final.zkey) on a CDN (e.g., S3 with CloudFront). In src/services/keyCache.ts, download it on demand to IndexedDB with a SHA-256 integrity check. Implement resumable download using Range requests.
  3. In src/services/zkProver.ts, prepareInputs(): gather meterId, consumption, salt, merkleRoot, ciphertext, blockHash. Serialize as JSON for the worker.
  4. The worker zkProver.worker.ts loads the WASM circuit and proving key using snarkjs, creates a witness, runs groth16Prove, returns { proof, publicSignals } as Transferable objects.
  5. Back on the main thread, package { encryptedReading, proof, publicSignals } into a Soroban transaction payload and submit via src/services/soroban.ts.
  6. implement src/services/zkVerifier.ts: fetch verification key from Soroban (data entry zk_verification_key), cache for 24h, call snarkjs groth16Verify.
  7. useZKSubmission exposes: submit(reading) returns { progress: 0-100, status: 'downloading-key' | 'proving' | 'submitting' | 'confirmed' | 'rejected', proofHash }. ZKSubmissionPanel renders a stepper UI showing each phase.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions