75626 sc medium rc28 op succinct endofsource relabels an early output root as a later aggregateverifier sequence
#75626 [SC-Medium] rc28 OP-Succinct EndOfSource relabels an early output root as a later AggregateVerifier sequence
Submitted on Apr 30th 2026 at 05:59:35 UTC by @cgdusek for Audit Comp | Base Azul
Report ID: #75626
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/base/contracts/tree/v8.1.0/src/multiproof
Impacts:
Forging or bypassing TEE or ZK proof verification in AggregateVerifier to finalize an invalid state root on L1
Description
Vulnerability Report
Selected fields:
program:
Base Azulcategory:
Smart Contractselected asset:
base/contracts v8.1.0 src/multiproofsupporting asset:
base/base v0.8.0-rc.28for the ZK proof-service/range-program root causesupporting asset:
base/contract-deploymentsfor Base Sepolia deployment constantsimpact:
Critical: Forging or bypassing TEE or ZK proof verification in AggregateVerifier to finalize an invalid state root on L1title:
rc28 OP-Succinct EndOfSource relabels an early output root as a later AggregateVerifier sequence
Executive summary of issue
base/base v0.8.0-rc.28 can stop OP-Succinct derivation early on EndOfSource, keep the requested claimed_l2_block_number in ZK public values, and validate only that the returned output root equals claimed_l2_output_root. In the target geometry, an insufficient L1 head that only derives to root(N+200) can still produce exactly 20 intermediate roots at rc.28's default 10-block cadence, which matches the type-621 AggregateVerifier root count for a 600-block game at the deployed 30-block interval. The resulting ZK journal can bind endingL2SequenceNumber=N+600 to the earlier root(N+200), letting a defender-won game update the anchor for sequence N+600 with an output root that was not derived at that sequence.
Classification and Scope Justification
Exact program criteria match
asset name(s) exactly as listed on scope page:
Implementation Contracts,Offchain Components, andBase Azul, checked on the live Audit Comp | Base Azul scope page on2026-04-28specific scoped asset(s) supporting this severity claim: selected
base/contracts v8.1.0 src/multiprooffor theAggregateVerifieracceptance/finalization surface; supportingbase/base v0.8.0-rc.28for the in-scope Base changes around OP-Succinct; supportingbase/contract-deploymentsfor active Base Sepolia parametersexact current Immunefi scope picker URL(s) supporting this severity claim: scope page, multiproof contracts, Base code, deployment repo
online form asset picker selection:
base/contracts v8.1.0 src/multiproofexact current Immunefi scope picker URL for selected form asset:
base/contracts v8.1.0 src/multiproofselected severity from scope page:
Criticalselected impact title from scope page:
Forging or bypassing TEE or ZK proof verification in AggregateVerifier to finalize an invalid state root on L1exact scope wording: the live scope requires a runnable PoC, says Base Sepolia post-April 20 Azul activation is the competition environment, and identifies proof-system integration, TEE/ZK dispute game submission logic, verifier contract bugs, and ZK recursion soundness as primary concerns.
scope page last checked:
2026-04-28why this matches the demonstrated consequence: the source path and runnable artifact show the
AggregateVerifierjournal accepting a root forN+200while the game and anchor sequence areN+600; that is an invalid state-root finalization shape for the selected AggregateVerifier impact.
Why higher or adjacent criteria do not fit
closest higher severity criterion considered:
Draining or stealing funds from the L1 bridge portal through invalid withdrawal proofs constructed against a forged finalized statewhy the report does not satisfy it: the current PoC stops at invalid root acceptance/finalized-anchor eligibility. It does not construct a withdrawal proof against the forged finalized root, quantify bridge funds, or demonstrate bridge draining.
closest adjacent same/lower criteria considered:
Circumventing the dispute/challenge mechanism to prevent correction of an invalid proposal before finalization;High: Forcing a dispute game into an incorrect resolved state;High: Temporary freezing of funds for at least 24 hourswhy the selected criterion fits better: the demonstrated path is not merely liveness loss or wrong timing; it is a ZK-backed
AggregateVerifiergame whoserootClaimis an output root from an earlier derived state while the contract records the later sequence number.
Out-of-scope exclusion check
relevant out-of-scope exclusions reviewed: public testnet/mainnet testing ban, core Op-Succinct/circuit out-of-scope boundary, out-of-scope
base/basefolders (actions,devnet,baseup,etc), privileged-address assumptions, leaked credentials, Base-operated infrastructure compromise, and the rule boundary for reports that rely on invalid TEE/ZK proofs.excluded assumptions not used by this exploit: the PoC does not require key compromise, TEE signer behavior, governance, sequencer ordering, public network writes, Base infrastructure compromise, or a manual-service-restart assumption.
public proof definition: the PoC uses all publicly available source, release-pinned contracts, and active Base Sepolia parameters available to reviewers. It generates verifier-accepted SP1 Groth16 proof bytes for the
AggregateVerifierjournal shape and does not rely on a malformed proof, hidden public-network transaction, private key, or privileged action. The public SepoliaZK_AGGREGATE_HASHis included as a negative compatibility check because Base's production aggregate prover artifact is not publicly available; the report does not represent the generated bytes as accepted by that deployment-specific vkey.
Finding details
Public documentation invariant
Public evidence checked on 2026-04-28:
The live Audit Comp | Base Azul scope page lists
Runnable PoC Required, treats Base Sepolia post-April 20 Azul activation as the competition environment, and states that the core Op-Succinct program is out of scope while Base changes around it are in scope.The same scope page says Azul replaces optimistic fault proofs with a dual-proof TEE + ZK system for faster finality and calls out proof-system integration and TEE/ZK dispute-game submission logic as primary concerns.
The live information page states fixes may be applied mid-contest and that duplicate reports remain valid only while the bug is unfixed and not publicly disclosed.
AggregateVerifier.initializeWithInitData()requires the game sequence to be exactlystarting + BLOCK_INTERVAL, hashes the supplied root claim, sequence, L1 origin, and intermediate roots into_verifyZkProof(), and then records the proof in the game.AnchorStateRegistry.isGameClaimValid()requires a proper, respected, finalized, defender-won game, andOptimismPortal2.checkWithdrawal()depends on that validity check before withdrawal finalization.
The resulting invariant is inference-backed from public docs and source: a ZK proof that backs an AggregateVerifier game for (endingRoot, endingL2SequenceNumber) must bind the output root to the same L2 block number actually derived by the range proof. The bug breaks that invariant because rc.28 can derive only to N+200, keep claimed_l2_block_number=N+600 in the public values, and feed that relabeled endpoint to the contract journal.
Root cause
advance_to_target() handles PipelineError::EndOfSource by setting the working target to the current safe-head block number and continuing. Its post-Isthmus fail-closed guard calls cfg.is_isthmus_active(driver.cursor.read().l2_safe_head().block_info.number), but is_isthmus_active() expects a timestamp, not a block number. In a post-Isthmus Base Sepolia setting, current block numbers remain far below the Isthmus timestamp value, so the guard can stay false and the function can halt derivation at the current safe head.
After the early halt, WitnessExecutor::run() checks only output_root == boot.claimed_l2_output_root. It does not also require safe_head.block_info.number == boot.claimed_l2_block_number. BootInfoStruct::new() then writes l2BlockNumber: boot_info.claimed_l2_block_number, and the aggregation program commits endingL2SequenceNumber from the last boot info's l2BlockNumber. The contract accepts that sequence/root pair through _verifyZkProof() if the journal and proof match.
Strongest demonstrated exploit path
PoC-backed proof chain
The PoC package at the PoC gist performs four checks:
a deterministic rc.28 model proving the early-stop and 20-root geometry;
a public rc.28 aggregation-vkey probe from release-pinned
base/base v0.8.0-rc.28source;a read-only Sepolia parameter check when
castis available; anda real SP1 Groth16 proof for an equivalent
AggregateVerifier._verifyZkProofjournal, then a Foundry test against release-pinnedbase/contracts v8.1.0at commit01dad230390cd69bcf130b5fc7a7a580b31650a7.
High-signal expected markers include:
POC_RESULT: ISTHMUS_GUARD_BYPASSED_BY_BLOCK_NUMBER_AS_TIMESTAMP=truePOC_RESULT: ROOT_VECTOR_LENGTH_MATCH=truePOC_RESULT: ROOT_N_PLUS_200_DIFFERS_FROM_N_PLUS_600=truePOC_RESULT: PUBLIC_RC28_AGGREGATION_VKEY_PROBE_ATTEMPTED=truePOC_RESULT: PUBLIC_RC28_AGGREGATION_SOURCE_PRESENT=truePOC_RESULT: PUBLIC_RC28_AGGREGATION_VKEY_PROBE_STATUS=completedPOC_RESULT: SEPOLIA_READ_ONLY_PARAMETER_CHECK_ATTEMPTED=truePOC_RESULT: LIVE_SEPOLIA_PARAMS_MATCH_EXPECTED=truePOC_RESULT: REAL_ZK_PROOF_SYSTEM=SP1 Groth16POC_RESULT: BASE_ZK_VERIFIER_ACCEPTS_RELABEL_PROOF=truePOC_RESULT: RELABEL_PROOF_REJECTS_CANONICAL_N_PLUS_600_ROOT=truePOC_RESULT: RELABEL_PROOF_REJECTS_N_PLUS_200_SEQUENCE=truePOC_RESULT: RELABEL_PROOF_BINDS_ONLY_RELABELED_JOURNAL=truePOC_RESULT: AGGREGATE_VERIFIER_GAME_CREATED_WITH_ZK_PROOF=truePOC_RESULT: AGGREGATE_VERIFIER_ROOTCLAIM_EQ_ROOT_N_PLUS_200=truePOC_RESULT: AGGREGATE_VERIFIER_L2_SEQUENCE_NUMBER=25000600POC_RESULT: GAME_RESOLVED_DEFENDER_WINS=truePOC_RESULT: ANCHOR_ROOT_RELABELED_TO_EARLY_ROOT=truePOC_RESULT: ANCHOR_L2_SEQUENCE_NUMBER=25000600POC_RESULT: END_OF_SOURCE_ROOT_RELABEL_PROVEN=true
The PoC also prints the public-vkey compatibility markers:
POC_RESULT: PROGRAM_VKEY_DIFFERS_FROM_PUBLIC_SEPOLIA=truePOC_RESULT: ZK_VERIFIER_PUBLIC_SEPOLIA_VKEY_ACCEPTED=false
These two markers are intentional and must not be removed from the report. They prevent overclaiming that the generated proof bytes are accepted by Base Sepolia's deployed aggregate vkey.
PoC setup conditions
The PoC performs no public-network writes. It does not deploy to public Sepolia, submit transactions, use a private key, use a funded account, or rely on privileged addresses. The runner clones public source, probes the public aggregation-vkey path, optionally performs read-only Sepolia cast call checks, compiles the SP1 Groth16 verifier artifact, deploys the Base protocol contracts inside the reviewer-run Foundry process, deploys the release-pinned ZkVerifier, and configures AggregateVerifier with active public Sepolia values.
Meaning of valid ZK proof in this report
Within this publicly reproducible PoC, valid ZK proof means verifier-valid under the same proof system, proof encoding, vkey type, journal shape, and verifier interface used by the scoped Base contracts:
The proof bytes are generated during the runner by SP1 Groth16 for a concrete aggregate-journal program and concrete public inputs.
The public journal is the
AggregateVerifierZK journal shape:proposer,l1OriginHash, starting and ending roots, starting and ending L2 sequence numbers, intermediate roots,CONFIG_HASH, andZK_RANGE_HASH.The contract-side configuration uses active public Base Sepolia values where they are publicly usable in a reviewer-run proof: game type
621,BLOCK_INTERVAL=600,INTERMEDIATE_BLOCK_INTERVAL=30,PROOF_THRESHOLD=1, activeZK_VERIFIER, activeZK_RANGE_HASH, activeCONFIG_HASH, and the publicZK_AGGREGATE_HASHas a deployment-specific compatibility check.The vkey is a
bytes32SP1 program verification key passed to the release-pinnedZkVerifier.verify(proofBytes, imageId, journal)path, matching the Solidity type and verifier-call semantics used for Base Sepolia'sZK_AGGREGATE_HASH.The release-pinned
ZkVerifieraccepts the proof when paired with the journal it proves, and the release-pinnedAggregateVerifier/AnchorStateRegistrypath accepts the resulting relabeled root and later sequence number.
This is not an invalid-proof PoC. The ZK_VERIFIER_PUBLIC_SEPOLIA_VKEY_ACCEPTED=false marker shows that the generated proof bytes are not represented as accepted by Base Sepolia's deployment-specific aggregate vkey. That vkey identifies Base's production aggregate SP1 program, while the production aggregate prover artifact and inputs needed to produce proof bytes for that exact vkey are not publicly available to reviewers. The report proves the claim using the public source and parameters available for independent reproduction.
Exploit preconditions
None of these preconditions invalidates the report under the Base Azul rules checked on 2026-04-28:
Active game type and scope: the report targets game type
621, which is the public Sepolia multiproof game type in the Sepolia multiproof activation environment and maps to the in-scopeImplementation Contracts,Offchain Components, andBase Azulassets on the live Audit Comp | Base Azul scope page, checked2026-04-28.Verifier-configuration geometry:
BLOCK_INTERVAL=600,INTERMEDIATE_BLOCK_INTERVAL=30, andPROOF_THRESHOLD=1are public multiproof activation values in the same Sepolia environment file, andAggregateVerifierstores those constructor values as immutable verifier parameters in the release-pinned contract source. This is a public deployment/configuration precondition, not a privileged assumption.Public-network write boundary: the PoC does not test or exploit public Sepolia or mainnet; that matches the Immunefi Web3 PoC guideline, checked
2026-04-28, which requires runnable code without exploiting live public contracts.Root-cause path: rc.28
advance_to_target()handlesEndOfSourceby changing the working target to the current safe head and continuing unless the post-Isthmus guard trips; the guard callsis_isthmus_active()with the L2 block number at the rc.28EndOfSourcebranch, whileis_isthmus_active()expects a timestamp in the release-pinned rollup config. This is public source behavior inside Base changes around OP-Succinct, which the scope page says are in scope.Attacker-controllable proof inputs: the public witness path takes
claimed_l2_block_numberandclaimed_l2_output_rootfrom proof input construction, as shown byfetcher.rsassigning the claimed end block and root, thenWitnessExecutor::run()checks only output-root equality in the release-pinned witness executor. The claimed L2 number is preserved into public values byBootInfoStruct::new()and then committed asendingL2SequenceNumberby the aggregation program. This precondition does not require leaked keys, privileged addresses, Base-operated infrastructure, or a TEE signer.Finalization status: the PoC follows the contract's normal finalization path for a respected, finalized, defender-won game.
AnchorStateRegistry.isGameClaimValid()checks those conditions in release-pinned source. The bug is in the ZK acceptance path before that validity check: a game can satisfy the contract's finalization predicates while carryingroot(N+200)as the anchor root for sequenceN+600. Generic game-finalization monitoring would not necessarily detect this; detection requires an off-chain consistency check that independently recomputes the output root for the claimed L2 sequence and verifies that the game root claim and ZK public values bind to that same endpoint. External challenge, blacklist, retirement, or pause mechanisms can block the anchor update only if that root/sequence inconsistency is detected before finalization.
Deployment and in-scope surface
Read-only Base Sepolia checks from the successful reviewer artifact at Ethereum Sepolia block 10746823 found:
DisputeGameFactory=0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1gameImpls(621)=0xF3f0fA3124b7b0feB048A00404Fe4D5D49E60796initBonds(621)=50000000000000000BLOCK_INTERVAL=600INTERMEDIATE_BLOCK_INTERVAL=30PROOF_THRESHOLD=1ZK_VERIFIER=0xF9780104117C0FaD3A9b1386FbF40a9F5857988AZK_RANGE_HASH=0x23081d5f7a4d3ce04d41c2f03b386bad4f42a99d5b4c8ef44f4c362c2c595464ZK_AGGREGATE_HASH=0x0020f5df94945d8d40bc2b11128cbf2535565f5cde58960029017ee2ccef46d7respectedGameType=621paused=false
The release-pinned source for rc.28 is base/base commit e3467a2048881213b56739a54a876efb9c6ea103; the release-pinned contract source is base/contracts commit 01dad230390cd69bcf130b5fc7a7a580b31650a7.
Public-known / duplicate boundary
I did not identify a public disclosure for this exact EndOfSource relabel path. It is distinct from the earlier interval-mismatch temporary-freeze submission because that finding is a liveness failure: honest rc.28 ZK proofs do not match the contract's 30-block journal. This finding uses the same deployed interval geometry differently: only 200 derived blocks at the 10-block cadence produce the 20 roots expected by a 600-block type-621 game, so the journal can match while the sequence/root binding is wrong. It is also distinct from the public known issue where the proposer does not independently recompute output roots: that issue concerns proposer-side trust in a rollup RPC output-root response, while this report concerns the ZK witness and aggregation path accepting a root/sequence pair that diverges after EndOfSource. It is also distinct from TEE-only early-stop variants because the ZK range public values preserve the claimed L2 block number through BootInfoStruct::new() and aggregation.
Related public prior art reviewed on 2026-04-28: Optimism's April 1, 2026 Kona fallback-proof disclosure says an audit found three Kona-proof derivation issues, that Kona was a fallback rather than the active respected game type on OP Stack chains, and that fixes became public in PR #19775. The commit-pinned 2026 Kona Spearbit audit is materially related because it includes a trace-extension issue involving claimed_l2_block_number, an EndOfSource/zero-root validation issue, and a block-number-as-timestamp is_interop_active() issue. It is not the same root cause or exploit path as this report: those items concern Kona fallback proof behavior and PR #19775, while this report targets Base rc.28 OP-Succinct ZK public-value relabeling through advance_to_target() -> WitnessExecutor::run() -> BootInfoStruct::new() -> aggregation -> type-621 AggregateVerifier._verifyZkProof() with the deployed 20-root N+200 to N+600 geometry.
Repository, file, and line of code where finding is found
Steps to replicate
The PoC does not broadcast transactions or deploy contracts to public Sepolia or mainnet.
PoC gist: PoC gist
recommended PoC name:
zk-endofsource-root-relabel-poc
Expected high-signal output markers:
POC_RESULT: ROOT_VECTOR_LENGTH_MATCH=truePOC_RESULT: BASE_ZK_VERIFIER_ACCEPTS_RELABEL_PROOF=truePOC_RESULT: AGGREGATE_VERIFIER_ROOTCLAIM_EQ_ROOT_N_PLUS_200=truePOC_RESULT: AGGREGATE_VERIFIER_L2_SEQUENCE_NUMBER=25000600POC_RESULT: ANCHOR_ROOT_RELABELED_TO_EARLY_ROOT=truePOC_RESULT: ANCHOR_L2_SEQUENCE_NUMBER=25000600POC_RESULT: REVIEWER_COMMAND_SUCCEEDED=true
Impact of finding
Short term
The public-source proof path shows that rc.28 can instantiate a ZK-backed type-621 game whose root claim is the real output root at N+200 while the game and anchor sequence are N+600. Once finalized and defender-won, that game becomes a valid root-claim source for bridge withdrawal checks and anchor progression even though the root does not correspond to the claimed L2 sequence.
Long term
The long-term risk is invalid state-root finalization in the Base Azul proof system. This report does not claim direct bridge theft, permanent freezing, public network shutdown, unauthorized verifier upgrade, or a public-network transaction. The PoC proves the claim using all publicly available source and parameters, including an explicit deployment-vkey compatibility check.
Comparable public incidents
Not used. This report is source and PoC driven.
Mitigation suggestions
In
advance_to_target(), evaluate the Isthmus guard using the L2 safe-head timestamp, not the L2 block number.Fail closed on
EndOfSourcefor post-Isthmus range proofs instead of relabeling the target to the current safe head.In
WitnessExecutor::run(), requiresafe_head.block_info.number == boot.claimed_l2_block_numberbefore returning public values.In
BootInfoStruct::new(), bindl2BlockNumberto the actually derived safe-head block number or an explicitly verified value.Add regression tests for early
EndOfSourcewhere the claimed output root equals the current safe head but the claimed L2 block number is later.Add a deployment-level test for the 200-derived-block / 20-root / 600-claimed-block geometry.
Optional suggested patch
Treat EndOfSource as a proof-generation failure once the chain is post-Isthmus, and add a range-public-value invariant that the final root and final L2 sequence number must both come from the same derived safe head. A minimal defense is:
References
Runnable PoC package
PoC gist: PoC gist
recommended PoC name:
zk-endofsource-root-relabel-poc
Live deployment / release confirmation
Audit Comp | Base Azul scope, checked
2026-04-28Audit Comp | Base Azul information, checked
2026-04-28
Relevant code paths
Scope / rules
Immunefi Web3 PoC guidelines, checked
2026-04-28
Public protocol documentation
Base Azul upgrade overview, checked
2026-04-28Base v1 operator migration guide, checked
2026-04-28
Additional context / provenance
Base
baserepository, checked2026-04-28Base
contractsrepository, checked2026-04-28
Submission notes
selected scope criterion:
Critical: Forging or bypassing TEE or ZK proof verification in AggregateVerifier to finalize an invalid state root on L1specific scoped assets carrying the claim:
base/contracts v8.1.0 src/multiproof; supportingbase/base v0.8.0-rc.28andbase/contract-deploymentsonline form asset picker selection:
base/contracts v8.1.0 src/multiproofseverity anchor: invalid state-root finalization via ZK-backed
AggregateVerifierjournal relabelbreadth-only variants: same missing equality gate can affect other
EndOfSourcedistances, but the PoC anchors theN+200toN+600geometry because it matches the deployed 20-root contract vectorexplicitly not claiming: direct bridge theft, production-vkey proof acceptance, mainnet deployment, public testnet exploitation, key compromise, TEE compromise, governance compromise, permanent freezing, or a chain halt
Link to Proof of Concept
https://gist.github.com/cgdusek/d642046b16dfc5eb7c67b68e1437b449
Proof of Concept
PoC Specification
Recommended PoC name:
zk-endofsource-root-relabel-poc
Full PoC package:
One-sentence summary:
The PoC models the rc.28 EndOfSource early-stop relabel condition, generates a real SP1 Groth16 proof for the AggregateVerifier._verifyZkProof journal shape, and shows release-pinned Base contracts accepting root(N+200) as a defender-won type-621 game whose l2SequenceNumber is N+600.
Minimal file list:
README.mdOUTPUT.txtrun_poc.shzk_endofsource_root_relabel_model.pyZkEndOfSourceRootRelabelPoC.t.sol
Run:
Layout note:
Run from the downloaded PoC package directory after cloning or downloading all files into a single package path. The runner creates a temporary build area, clones public rc.28 base/base source for the aggregation-vkey probe, performs a read-only Sepolia parameter check when cast is available, clones base/contracts v8.1.0 at commit 01dad230390cd69bcf130b5fc7a7a580b31650a7, generates an SP1 fixture, copies the Foundry test into the cloned Base contracts tree, and writes the result transcript to OUTPUT.txt.
Inline proof-critical PoC code:
Why this proves the claim:
The fixture asserts the relabel geometry:
actualDerivedEndL2 == startingL2 + 200, whileclaimedEndL2 == startingL2 + 600._createRelabeledGame()submits a ZK proof toDisputeGameFactory.createWithInitData()withrootClaim=root(N+200)andextraDatasequenceN+600.The test requires the created
AggregateVerifiergame to recordrootClaim == root(N+200)andl2SequenceNumber == N+600.The negative controls prove the same proof is rejected for the canonical
root(N+600)journal and for the earlyN+200sequence journal, so the proof binds only the relabeled(root(N+200), N+600)journal.The game resolves
DEFENDER_WINS;AnchorStateRegistry.isGameClaimValid()accepts it;closeGame()updates the anchor to the early root at the later sequence.
Expected high-signal output markers:
POC_RESULT: PUBLIC_NETWORK_BROADCAST=falsePOC_RESULT: BASE_BASE_SCOPE_TAG=v0.8.0-rc.28POC_RESULT: BASE_BASE_SCOPE_COMMIT=e3467a2048881213b56739a54a876efb9c6ea103POC_RESULT: PUBLIC_RC28_AGGREGATION_VKEY_PROBE_ATTEMPTED=truePOC_RESULT: PUBLIC_RC28_AGGREGATION_SOURCE_PRESENT=truePOC_RESULT: PUBLIC_RC28_AGGREGATION_VKEY_PROBE_STATUS=completedPOC_RESULT: SEPOLIA_READ_ONLY_PARAMETER_CHECK_ATTEMPTED=truePOC_RESULT: LIVE_SEPOLIA_PARAMS_MATCH_EXPECTED=truePOC_RESULT: BASE_CONTRACTS_COMMIT_MATCH=truePOC_RESULT: REAL_ZK_PROOF_SYSTEM=SP1 Groth16POC_RESULT: ISTHMUS_GUARD_BYPASSED_BY_BLOCK_NUMBER_AS_TIMESTAMP=truePOC_RESULT: ROOT_VECTOR_LENGTH_MATCH=truePOC_RESULT: ROOT_CLAIM_IS_ROOT_N_PLUS_200=truePOC_RESULT: AGGREGATE_VERIFIER_SEQUENCE_IS_N_PLUS_600=truePOC_RESULT: ROOT_N_PLUS_200_DIFFERS_FROM_N_PLUS_600=truePOC_RESULT: BASE_ZK_VERIFIER_ACCEPTS_RELABEL_PROOF=truePOC_RESULT: RELABEL_PROOF_REJECTS_CANONICAL_N_PLUS_600_ROOT=truePOC_RESULT: RELABEL_PROOF_REJECTS_N_PLUS_200_SEQUENCE=truePOC_RESULT: RELABEL_PROOF_BINDS_ONLY_RELABELED_JOURNAL=truePOC_RESULT: AGGREGATE_VERIFIER_GAME_CREATED_WITH_ZK_PROOF=truePOC_RESULT: AGGREGATE_VERIFIER_ROOTCLAIM_EQ_ROOT_N_PLUS_200=truePOC_RESULT: AGGREGATE_VERIFIER_L2_SEQUENCE_NUMBER=25000600POC_RESULT: GAME_RESOLVED_DEFENDER_WINS=truePOC_RESULT: ANCHOR_ROOT_RELABELED_TO_EARLY_ROOT=truePOC_RESULT: ANCHOR_L2_SEQUENCE_NUMBER=25000600POC_RESULT: CRITICAL_INVALID_ROOT_FINALIZATION_PROVEN_WITH_PUBLIC_SOURCE=truePOC_RESULT: END_OF_SOURCE_ROOT_RELABEL_PROVEN=truePOC_RESULT: REVIEWER_COMMAND_SUCCEEDED=truePOC_RESULT: COMPLETE=1
Public reproducibility note:
The runnable artifact uses the public Base Sepolia parameters available to reviewers: game type 621, BLOCK_INTERVAL=600, INTERMEDIATE_BLOCK_INTERVAL=30, PROOF_THRESHOLD=1, ZK_RANGE_HASH=0x23081d5f7a4d3ce04d41c2f03b386bad4f42a99d5b4c8ef44f4c362c2c595464, CONFIG_HASH=0x12e9c45f19f9817c6d4385fad29e7a70c355502cf0883e76a9a7e478a85d1360, and the public Sepolia ZK_AGGREGATE_HASH=0x0020f5df94945d8d40bc2b11128cbf2535565f5cde58960029017ee2ccef46d7 as a deployment-specific compatibility check. The runner also records the public rc.28 aggregation source hash and vkey-probe result, plus a read-only check of the active Sepolia verifier parameters.
The proof itself is generated for an equivalent aggregate-journal SP1 program because Base's production aggregate prover artifact and exact proving inputs are not publicly available to reviewers. The artifact therefore prints PROGRAM_VKEY_DIFFERS_FROM_PUBLIC_SEPOLIA=true and ZK_VERIFIER_PUBLIC_SEPOLIA_VKEY_ACCEPTED=false. Those markers are an explicit validity definition: the proof is a real SP1 Groth16 proof accepted by the release-pinned Base verifier path for the journal it proves, while the report does not represent those generated bytes as accepted by Base Sepolia's deployment-specific aggregate vkey.
Notes:
The PoC does not deploy to, transact with, or mutate public Sepolia or mainnet.
No wallet, private key, funded account, public transaction, or privileged address is required.
SEPOLIA_RPC_URLis optional and is used only for read-only parameter checks.OUTPUT.txtin the gist contains the latest successful reviewer-run result transcript before submission.
Was this helpful?