Skip to content

feat(dvm): verify_proof PoC with executing-block roothash bind (fixes #93) - #94

Open
liqdmetal wants to merge 1 commit into
DEROFDN:community-devfrom
liqdmetal:feature/verify-proof-poc
Open

liqdmetal wants to merge 1 commit into
DEROFDN:community-devfrom
liqdmetal:feature/verify-proof-poc

Conversation

@liqdmetal

@liqdmetal liqdmetal commented Aug 22, 2026

Copy link
Copy Markdown

Summary

PoC implementation of the P1-1 verify_proof intrinsic — ZK proof verification inside the DVM, as a native hook into the audited Go Proof.Verify (NOT VM-interpreted group arithmetic). Follows the design in issue #92.

The intrinsic

verify_proof(tx_hex String, scid_index Uint64, ctx_hex String) -> Uint64
  • tx_hex — a fully-serialized transaction (carries the statement's C/D/pointers/roothash + the proof)
  • ctx_hex — the expanded statement material DERO's serialization deliberately omits (ring/CLn/CRn are "expanded from graviton store"): per ring member [ring key (33B) | CLn (33B) | CRn (33B)] concatenated, 99·N bytes
  • The VM splices the context into the deserialized statement and runs the same Proof.Verify nodes run on every tx (transaction_verify.go:482)

Chain binding (shipped in this revision)

Executing-block roothash bind. When Chain_inputs is set (the real on-chain path), the handler rejects any statement whose Roothash != Chain_inputs.BLID. A fabricated-but-self-consistent proof carrying a roothash that is not the current block's BLID now returns 0.

  • Pinned by TestVerifyProofRoothashBind: same-BLID → 1, mismatched-BLID → 0.
  • Unit tests with Chain_inputs == nil skip the bind (so the low-level verification vectors still run standalone); a production contract gate MUST set the chain context.
  • This closes the chain-binding gap the original PoC documented. What remains open is gas metering: cost is a policy number (2,000,000), benchmarked ~85 ms/op (ring 16, 5900X), not a cycle-accurate meter.

Anti-sybil / proof-of-ownership pattern (wargame)

verify_proof also works as an ownership gate against one-GPU-many-wallets sybil: a contract can require proof of a recent self-spend anchored to the current BLID before allowing a Claim/submit. TestWargameVerifyProofAntiSybilOwnership locks it: valid recent self-spend → 1, stale/spoofed-chain proof → 0, tampered → 0, absent → 0. A production gate MUST set Chain_inputs.BLID for the freshness bind.

Why this serialization format

DERO's tx serialization strips the expanded statement (ring, CLn, CRn) to truncated pointers + C/D — the verifier needs the real points, which nodes normally reconstruct from the graviton balance tree. The context blob is the contract's way of supplying exactly what it expects. These are public values; nothing secret enters SCDATA.

Safety

  • Panic-safe: any internal failure (malformed input reaching a panicking decode path) returns 0 — a consensus primitive never panics out of the VM.
  • Malformed tx/context/index → 0.
  • Version-gated >= 10.0.0, gas 2,000,000.

Tests

TestVerifyProof: valid tx + correct context → 1; wrong context / context-size mismatch / tampered tx / malformed hex / bad index → 0; version-gated.

TestVerifyProofRoothashBind: executing-block bind enforced when Chain_inputs set.

TestWargameVerifyProofAntiSybil*: ownership-gate pattern vs sybil.

BenchmarkVerifyProof: ~85 ms/op ring-16 on a 5900X (3 iterations).

Honest scope

  • Verifies DERO's own proof system (aggregate Bulletproofs over the statement relation), not arbitrary zk-SNARK/STARK circuits.
  • No proof generation in-VM — proving happens off-chain (the prover holds the witness).
  • PoC: chain-binding present, but gas is a policy number, not a cycle meter.

Relationship


Branch: feature/verify-proof-poc in the fork liqdmetal/derohe-improvements-by-liqdmetal. Carries the build fixes. Flat on community-dev.

@liqdmetal

Copy link
Copy Markdown
Author

Folded local maturity: verify_proof now rejects a statement whose Roothash != executing BLID when Chain_inputs is set. TestVerifyProofRoothashBind + BenchmarkVerifyProof (~85ms/op ring-16). Still a PoC — gas is a policy number.

Rebuilt on DEROFDN community-dev (post-DEROFDN#129 func_table refactor).

verify_proof(tx_hex, scid_index, ctx_hex) -> 0/1: native hook into
Proof.Verify. Chain binding: when Chain_inputs set, rejects statements
whose Roothash != Chain_inputs.BLID. Anti-sybil ownership wargame locks
the recent-self-spend gate pattern. Gas 2,000,000 (policy number, PoC).

Tests: TestVerifyProof, TestVerifyProofRoothashBind,
TestWargameVerifyProofAntiSybil*, full dvm suite green.
@liqdmetal
liqdmetal force-pushed the feature/verify-proof-poc branch from 31d0f4c to 30b0f62 Compare August 31, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant