feat(proofs): on-chain Groth16 verification of commitment openings#46
Merged
Conversation
Phase 5 of the ZK-friendly stack migration — the first end-to-end ZK proof through the protocol: TS commits, the Rust prover-server proves, Move verifies on chain. Move (commitments.move): - New `open_with_proof(commitment: &SecretCommitment, claimed_first_value, proof_bytes, clock)` entry. Reconstructs the proof's public inputs from the commitment's own on-chain fields (commitment_x/y, encoding_id) + the caller's claimed value, then calls proofs::verify_pedersen_opens_to (aborts E_INVALID_PROOF on failure). Emits SecretPartialOpened — only stream[0] (the proven public value) is revealed; the rest of the opening + the blinding stay private. - `&SecretCommitment` immutable: a partial-open doesn't consume the commitment or flip its `opened` flag, so it's repeatable and orthogonal to the full open_secret reveal. The proof is cryptographically self- authorizing; because commitments are owned objects, Sui's object model gates submission to the owner. - Test: open_with_proof_rejects_garbage_proof (128 zero bytes -> abort). The accept path needs a real proof and is covered by the live e2e. SDK (proofs.ts): - proveCommitmentOpening: shapes the PedersenOpensToInputs body, POSTs to the prover-server's /prove/pedersen_opens_to, returns the arkworks- compressed proof bytes (Sui-compatible, no re-encoding). - buildOpenWithProofTx: the open_with_proof PTB. Passes only the object + claimed value + proof; the Move entry reconstructs point coords + encoding_id from the object. - DEFAULT_PROVER_URL = 127.0.0.1:3001 (matches prover-server's bind). dApp (Commit.tsx): - "open with proof (ZK)" button alongside "reveal (full open)", with progress phases (proving -> verifying on chain -> verified) and a proven-value receipt row. Structured console logging at each boundary. - VITE_PROVER_URL env override. Redeploy: the new open_with_proof entry means a fresh publish was needed. whisper_protocol republished to the dev devnet (package 0xad371607..., registry 0x65a41743...); Published.toml + networks.json + networks.ts updated. VK drift guard passed (server VK == proofs.move VK, byte-for-byte) so server-generated proofs verify on chain. Verified end-to-end on the live devnet via Playwright + a locally-booted prover-server: commit -> "open with proof" -> prover produces a 128-byte Groth16 proof over HTTP -> open_with_proof posts it -> Sui's native verifier accepts against the embedded VK -> SecretPartialOpened emitted. Zero console errors. The console trace shows: [commit] posted -> [commit] proof produced (128 bytes) -> [commit] proof verified on chain This closes the unshipped Move-side verification criterion that the original issues #31/#32 never delivered. Verification: sui move test 15/15, pnpm typecheck (4 projects), SDK + dApp build, networks.ts drift check — all green. Closes #39 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
Owner
Author
|
Review pass: APPROVE — no critical, important, or nits. The reviewer validated the security crux: Merging. [agent comment] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 5 of the ZK-friendly stack migration: the first end-to-end ZK proof through the whole protocol. TS commits → the Rust
prover-serverproves → Move verifies on chain. This closes the unshipped Move-side verification criterion that the original (closed) issues #31/#32 never delivered.Linked Issue
Closes #39
Design decisions (recorded on #39)
open_with_proof(commitment: &SecretCommitment, claimed_first_value, proof_bytes, clock)— immutable ref: a partial-open doesn't consume the commitment or flip itsopenedflag. Repeatable, orthogonal to the fullopen_secretreveal.claimed_first_value(stream[0]) is revealed; the rest of the opening + blinding stay private.Changes
Move (
contracts/sources/commitments.move):open_with_proofentry +SecretPartialOpenedevent +open_with_proof_rejects_garbage_prooftest.SDK (
packages/sdk/src/proofs.ts, new):proveCommitmentOpening(HTTP → prover-server, returns arkworks-compressed proof bytes — Sui-compatible, no re-encoding) +buildOpenWithProofTxPTB builder +DEFAULT_PROVER_URL(127.0.0.1:3001). Exported from index.dApp (
Commit.tsx): "open with proof (ZK)" button with progress phases (proving → verifying on chain → verified) + proven-value receipt row + structured logging.VITE_PROVER_URLoverride.Redeploy: the new entry required a fresh publish.
whisper_protocolrepublished to the dev devnet (package0xad371607…, registry0x65a41743…);Published.toml+networks.json+networks.tsupdated.Requirements checklist (from #39)
POST /prove/pedersen_opens_towith a valid proof — verified liveopen_with_proofcallsverify_groth16_proof(viaproofs::verify_pedersen_opens_to), accepts a valid proof, emits the partial-open event; rejects a proof for garbage (Move test)proveCommitmentOpening+ theopen_with_proofPTB builderproofs.movebyte-for-byte (re-verified this PR)Live e2e (Playwright + locally-booted prover-server)
Booted
crates/prover-server(release; loaded its deterministic-seed keys), pointed the dApp at the devnet + prover, drove the flow:Zero console errors. The 128-byte arkworks-compressed proof is accepted by Sui's BN254 verifier against the VK embedded in
proofs.move— exactly as the VK-match check predicted. UI showed "zk partial open · verified · stream[0] = …".Before the redeploy, the proof-open correctly failed with "No function open_with_proof" against the Phase-2 package — confirming the binding is real (the function genuinely has to be on chain).
Testing
sui move test— 15/15 (was 14; +open_with_proof_rejects_garbage_proof)pnpm typecheck(4 projects), SDK + dApp build,networks.tsdrift check — all greenNotes for the reviewer
Published.toml/networks.json/networks.ts): unavoidable — a new entry function requires republishing, and the e2e needs the dApp/SDK pointed at the package that actually hasopen_with_proof. Same fresh-publish pattern as chore(devnet): publish whisper_protocol to the dev devnet #44 (the old Phase-2 package is orphaned on the shared devnet, harmless).proofs::E_INVALID_PROOF(cross-module const ref works in test attributes). The accept path can't be a Move unit test (needs a real proof from the off-chain prover) — covered by the live e2e per the behavior-only Move-test discipline.[agent PR]