Skip to content

feat(EIP-0045): Native STARK Proof Verifier (VerifyStark) - Draft#1116

Draft
a-shannon wants to merge 1 commit into
ergoplatform:masterfrom
a-shannon:eip-0045-stark-verifier
Draft

feat(EIP-0045): Native STARK Proof Verifier (VerifyStark) - Draft#1116
a-shannon wants to merge 1 commit into
ergoplatform:masterfrom
a-shannon:eip-0045-stark-verifier

Conversation

@a-shannon

@a-shannon a-shannon commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR implements the preactivation review surface for EIP-0045's
VerifyStark opcode (0xB9). It replaces the earlier research prototype with
a four-child ABI, an unavailable-by-default host capability, complete
whole-input preflight for v4+ trees, and a pure-JVM verifier for the
B1-B3-closed RISC Zero v3 profile candidate.

This is deliberately not an activation PR. It does not make any profile
selectable by default or activate one on Ergo mainnet or testnet; the final
cost schedule, transition snapshot, node admission controller, and activation
package remain separate gates.

ErgoScript ABI

verifyStark(
  proofChunks:         Coll[Coll[Byte]],
  applicationPayload: Coll[Byte],
  programId:           Coll[Byte],
  profileId:           Coll[Byte]
): Boolean

The AST and wire encoding have exactly four children in that order. There is
no vmType, costParams, query count, Merkle depth, or other script-declared
work parameter.

Consensus-facing design

  • The evaluator is fail-closed by default. A node must supply an authenticated,
    purpose-specific StarkVerificationCapability; legacy constructors preserve
    source and binary compatibility by installing Unavailable.
  • The capability snapshots the chain domain, protocol generation, validation
    purpose, lifecycle table, dispatch charge, profile charge, proof shape, and
    payload bound. Profile IDs are unique and unsigned-lexicographically sorted.
  • Evaluation resolves profileId and lifecycle first. An exact unknown ID is
    Absent and returns false after dispatch without evaluating the three
    heavy children. Unavailable is a host-capability failure and Quarantined
    is a typed input failure; neither can be converted into Boolean success by
    negation or soft-fork fallback. An active invocation pays the complete fixed
    profile charge before the program, payload, proof chunks, parser, or
    cryptography can run.
  • Ergo constructs ErgoStatementV1, binding the receipt to the chain domain,
    profile, guest program, executing contract, and exact application payload.
    A typed invalid proof returns false; cost, host-invariant, allocation, and
    fatal VM failures continue to propagate.
  • v0-v3 retain their historical one-pass deserialization semantics but reject
    any structurally present or introduced VerifyStark. A v4+ tree completes a
    deterministic recursive materialization/preflight over the entire input,
    including dead branches, before normal evaluation. The continuation is
    opaque and single-use.

Initial verifier profile

The checked-in review/test candidate targets the stock RISC Zero v3.0.5
succinct receipt family (risc0-zkp 3.0.4 / recursion 4.0.4): BabyBear,
degree-4 extension, Poseidon2 recursion, and the shipping outermost lift,
join, and resolve controls needed by single-segment, multi-segment, and
assumption-bearing receipts.

The profile package is content-addressed and byte exact:

  • 29,773-byte algorithm artifact;
  • 65,119-byte binary-data artifact;
  • 458-byte manifest;
  • profileId 23c4a123ffb33a1c8db89436fe0e7972bd8e4e289459ee5fd71be5440607d383.

The verifier enforces canonical transport, strict EOF, BabyBear field bounds,
typed terminal allowlisting, the pinned inner control root, exact claim
equality, and complete FRI/Merkle/constraint verification. Imported RISC Zero
logic and independent test-vector provenance are mapped in
docs/eip-0045-risc0-source-map.json; Apache-2.0 notices are included in JVM
binary, source, test, and documentation artifacts and in the npm distribution.

Compatibility note

Complete preflight requires every ValueSerializer to describe its structural
children. Registered consensus serializers implement that contract explicitly.
Legacy external subclasses retain source and binary compatibility through
concrete defaults, but those defaults fail closed during structural preflight:
an undeclared serializer is rejected and is never silently treated as a leaf.

Validation included

  • exact four-child serialization and type rejection;
  • v0-v3 structural feature gating and v4 recursive whole-input preflight;
  • dead-branch, nested context/register, wrong-type, suffix, ordering, and
    single-use continuation cases;
  • unavailable, absent, quarantined, active, cost-limit, and exception paths;
  • statement/claim/profile/package canonicalization;
  • BabyBear, Ext4, Poseidon2, ReadIOP, Merkle, FRI, circuit, and raw-seal KATs;
  • one independent real RISC Zero raw-seal interoperability KAT using a
    different guest image and journal; it is not part of B4 and is not B4-closure
    evidence;
  • JVM/Scala.js compilation and the supported Scala binary-version matrix.

Verification status for the replacement commit

Targeted local verification of f78deadd668f801e7fae3bc884283f79c6f484fa
passed: coreJVM 63/63, dataJVM 4/4, and Scala.js 22/22, for 89/89 tests.
These are targeted preactivation checks, not a claim that every repository
suite has run. GitHub CI passed on this replacement commit in all four
configured lanes: JVM Scala 2.11.12, 2.12.21, and 2.13.18, plus the
Scala.js/npm lane on Scala 2.13.18. Node/devnet integration has not run. The
appropriate status remains draft review, not merge or activation readiness.

Integration note

Open PR #1170 also touches VersionContext.scala and Interpreter.scala in a
behavior-preserving refactor of checkSoftForkCondition. It addresses a
different objective, but both branches meet at the MaxSupportedScriptVersion
and soft-fork fallback boundary. If #1170 lands first, this branch may need
conflict resolution followed by rerunning the v0-v3/v4+ version, preflight,
and fallback tests.

Explicitly out of scope

Activation still requires EIP B4-B8: the final identity-bound receipt and
negative corpus, measured consensus metering, authenticated network transition,
independent reproduction/review, node admission and mempool protections, and
testnet operational evidence. A shared 262,144-byte standalone relay/API/
mempool policy must also be shipped before activation while received and
historical block decoding remain outside that local policy. The closed B1-B3
package is a reviewable profile identity, not authorization to use it on-chain.

Review focus

  1. Four-child serialization and language-version compatibility.
  2. Whole-input preflight completeness and single-use continuation semantics.
  3. Capability/lifecycle/fixed-precharge ordering and exception taxonomy.
  4. Exact profile package, raw-seal grammar, claim binding, and JVM verifier.
  5. Absence of an accidental activation or script-controlled workload path.

Specification: ergoplatform/eips#103

@a-shannon

a-shannon commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

Superseded: this comment describes the former 159-test Poseidon1/Ext16 prototype. The current branch is the four-child RISC Zero v3 BabyBear/Ext4/Poseidon2 preactivation review surface; see the PR body for exact scope and current verification status.

arkadianet added a commit to arkadianet/sigmastate-interpreter that referenced this pull request Jul 18, 2026
…fier, hardened profile) for integration with stock-profile KATs/primitives
arkadianet added a commit to arkadianet/sigmastate-interpreter that referenced this pull request Jul 18, 2026
…2-BabyBear with oracle parity

Integration pass on top of the ergoplatform#1116 merge:

- BabyBearFieldOracleParitySpec (data module): ergoplatform#1116's BabyBearField run
  against the risc0-core oracle vectors - all 128 checks pass. Two
  independently-written implementations (org.ergo.stark.field and
  sigma.stark) now agree with RISC0's production field code on the same
  external vectors.

- sigma.stark.Poseidon2: faithful port of risc0-zkp 1.2.6 poseidon2_mix
  (initial external layer, 4 full / 21 partial / 4 full rounds, x^7
  s-box, 4x4-circulant external matrix, all-ones+diag internal matrix).
  Round constants and the internal diagonal are EXTRACTED
  PROGRAMMATICALLY from risc0-zkp's public arrays by the stark-kat
  generator into Poseidon2Constants.scala (numeric parameters, not
  code) - no manual transcription to get wrong. All 16 permutation
  vectors (risc0-zkp oracle) pass.

Stock-profile primitive status: BabyBear (base field), Ext4, Poseidon2
all oracle-parity green. Remaining for a stock-profile verifier:
Merkle-cap verification over Poseidon2, the succinct FRI/DEEP-ALI
checks and transcript, and bincode InnerReceipt parsing - ergoplatform#1116's
protocol framework (MerkleVerifier/FriVerifier/FiatShamirTranscript)
is the intended structural home once parameterized over these
primitives. All 142 pre-existing org.ergo.stark tests remain green
after the merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYSS7hBNFeddkwE3RadSfw
arkadianet added a commit to arkadianet/sigmastate-interpreter that referenced this pull request Jul 18, 2026
Completes the stock-profile primitive layer: unpaddedHash mirrors
risc0-zkp's overwrite-absorb sponge (rate 16, zero-padded final block,
empty input hashes one zero block, 8-element digest) and hashPair - the
RISC0 Merkle node compression - is its 16-element specialization, with
the equivalence pinned on a full-rate vector. Oracle vectors cover
lengths 0..48 (padding boundaries and multi-block absorption),
generated from risc0-zkp's own unpadded_hash.

Primitive layer now fully oracle-parity green: BabyBear field, Ext4
tower, Poseidon2 permutation, sponge/pair hashing. Next layer up:
Merkle-cap verification, succinct FRI/DEEP-ALI + transcript, and
bincode InnerReceipt parsing, structurally homed in ergoplatform#1116's protocol
framework.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYSS7hBNFeddkwE3RadSfw
@a-shannon
a-shannon force-pushed the eip-0045-stark-verifier branch from 730c6c1 to 9372697 Compare July 19, 2026 19:38
@a-shannon
a-shannon changed the base branch from develop to master July 19, 2026 19:38
@a-shannon
a-shannon force-pushed the eip-0045-stark-verifier branch from 9372697 to f78dead Compare July 20, 2026 16:35
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