Skip to content

fix(json_logic): sigma DoS hardening + canonical node encoding#52

Merged
scasplte2 merged 1 commit into
Constellation-Labs:devfrom
ottobot-ai:fix/sigma-dos-hardening
Jun 17, 2026
Merged

fix(json_logic): sigma DoS hardening + canonical node encoding#52
scasplte2 merged 1 commit into
Constellation-Labs:devfrom
ottobot-ai:fix/sigma-dos-hardening

Conversation

@ottobot-ai

Copy link
Copy Markdown
Contributor

Summary

Production-hardening remediation from the 2026-06-17 Fiat-Shamir audit of the Σ-protocol opcodes (prove_dlog_verify / prove_dhtuple_verify / sigma_verify).

The audit's Fiat-Shamir / CDS soundness verdict was clean — strong transcript binding, 31-byte injective challenge, canonical z, reconstructed commitments, identity-point rejection, explicit CDS split checks. No soundness change in this PR. These changes close the separately-reported production-hardening + documentation findings so the opcode can be called production DoS-hardened.

Findings addressed

ID Severity Fix
IMPL-1 High Bound the proposition raw node-count/depth (4096/64) BEFORE parsePropNode; depth-cap the gas estimator's proposition-shape walk by the same value (it runs before gas is consumed). boundProofShapeboundRawShape (bounds prop + proof).
IMPL-2/5 Med Reject any field outside the canonical schema in every prop/proof node — removes the proof-bound-inflation surface (leaf with a bogus children) and makes the raw encoding canonical.
IMPL-3 Med Cap the sigma message at 4096 bytes (SigmaMaxMessageBytes, shared by sigma_verify + prove_dhtuple_verify).
DOC-1 Med Vector metadata root challenge mod Rlow31(SHA256(…)).
DOC-2 Low RFC vector references → the sigma categories of zk_opcode_test_vectors.json.
DOC-3 Low RFC: proof tree carries per-leaf responses (commitments are reconstructed).
DOC-4 Low RFC status lists the TypeScript impl; verifyTree comment mod R → low31; threshold share-index test prose corrected (indices are implicit child positions).

Tests

  • 4 new shared conformance error-vectors (unknown-field on a prop leaf, unknown-field on a proof node, leaf-with-bogus-children, over-long message) — locked cross-language (Scala + Rust + TS).
  • 6 new SigmaVerifySuite cases pairing a clean baseline (parses → Right) with the malformed variant (→ Left).
  • Full suite 1210 green; scalafmtCheckAll clean.
  • The proposition depth cap is unit-tested per language (it can't be a shared vector — exceeding sigma depth 64 implies ~128 JSON levels, beyond serde_json's parse recursion limit; both languages still reject, just at different layers).

Sister PR: metakit-sdk (Rust + TypeScript mirror + shared vectors).

🤖 Generated with Claude Code

Production-hardening remediation from the 2026-06-17 Fiat-Shamir audit. The
FS/CDS soundness verdict was clean — no soundness change here; these close the
separately-reported DoS / encoding findings so the opcode can be called
production DoS-hardened.

IMPL-1 (proposition DoS): bound the proposition's raw node-count/depth with the
  absolute caps (4096 nodes / 64 depth) BEFORE the recursive parsePropNode, and
  depth-cap the gas estimator's proposition-shape walk by the same value, so a
  deeply nested / very wide proposition cannot drive unbounded stack/CPU work in
  the parser or in the pre-charge (which runs before gas is consumed). Generalize
  boundProofShape -> boundRawShape (bounds both proposition and proof).
IMPL-2/5 (canonical encoding): reject any field outside the canonical schema in
  every proposition/proof node. Removes the proof-bound-inflation surface (a leaf
  could carry an ignored children field) and makes the raw encoding canonical.
IMPL-3 (message DoS): cap the sigma message at 4096 bytes (shared by sigma_verify
  and prove_dhtuple_verify) so it can't force unbounded hex-decode + SHA-256 work
  outside the Sigma-tree pricing.

DOC-1: vector metadata root challenge mod R -> low31(SHA256(...)).
DOC-2: RFC vector references -> the sigma categories of zk_opcode_test_vectors.json.
DOC-3: RFC proof tree carries per-leaf responses (commitments are reconstructed).
DOC-4: RFC status lists the TypeScript impl; verifyTree comment mod R -> low31;
  threshold share-index test prose corrected (indices are implicit child positions).

Tests: 4 new shared conformance error-vectors (unknown-field x2, leaf-children,
over-long message) locked cross-language; 6 new SigmaVerifySuite hardening cases;
full suite 1210 green. The proposition depth cap is unit-tested per language (it
cannot be a shared vector — exceeding sigma depth 64 implies ~128 JSON levels,
beyond serde_json's parse recursion limit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scasplte2 scasplte2 merged commit 1e1d43b into Constellation-Labs:dev Jun 17, 2026
1 check passed
@scasplte2 scasplte2 deleted the fix/sigma-dos-hardening branch June 17, 2026 07:17
scasplte2 added a commit that referenced this pull request Jun 17, 2026
The shielded capstone pinned the OLD proof, which proved the UNSOUND circuit
(no intra-transfer nullifier uniqueness, cross-asset mint possible) and would have
stayed green while attesting the wrong circuit. Re-vendored from the regenerated
metakit-sdk fixture after the soundness fixes:
  - vkey 0x0080c764... -> 0x0006feea6b6b974ef1d5287464c7d8b5c38816267c064a33db664dc97147e0ff
  - publicValues now carry feeAsset (per-asset conservation)
ShieldedTransferVerifierSuite: 3/3 green (verifies in pure-JVM Sp1Groth16Verifier;
tamper + wrong-publicValues still rejected).

Companion to metakit-sdk PR #52.

Co-authored-by: OttoBot <jim.a.aman@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants