Skip to content

apollo_starknet_os_program,starknet_os: verify the processed proof in the aggregator - #15162

Open
einat-starkware wants to merge 1 commit into
claude/privacy-proof-os-verify-gsxf2h-8-cairo-unpackfrom
claude/privacy-proof-os-verify-gsxf2h-9-aggregator-verify
Open

einat-starkware wants to merge 1 commit into
claude/privacy-proof-os-verify-gsxf2h-8-cairo-unpackfrom
claude/privacy-proof-os-verify-gsxf2h-9-aggregator-verify

Conversation

@einat-starkware

Copy link
Copy Markdown
Contributor

Part of milestone 3 of the single-proof verification stack, and its main PR: the aggregator verifies the processed proof of the aggregated blocks' proof-facts transaction in Cairo0, so the proof of the aggregator run covers the check.

Cairo (aggregator/verify_processed_proof.cairo, called from main.cairo after combine_blocks): when the combined header's n_proof_facts_transactions is 1, the aggregator:

  1. Runs the circuit verifier on the processed proof with the copied run_simple_bootloader (apollo_starknet_os_program: copy the simple bootloader's task execution #15160), as a single Blake-hashed task.
  2. Writes the bootloader's output to a scratch segment rather than the aggregator's output, whose layout the applicative bootloader and L1 rely on. The bootloader hints re-point the output builtin runner at the scratch segment for the task and restore it afterwards.
  3. Passes placeholder pointers for the builtins the aggregator doesn't have (ecdsa, bitwise, keccak, range_check96, add_mod, mul_mod). The verifier's program hash is pinned and its program uses only output and range_check, so they're never passed to it, and the bootloader validates that they didn't move.
  4. Asserts the bootloader output is [1 task, size 10, CIRCUIT_VERIFIER_PROGRAM_HASH, 8 digest words]. The task count is written by a hint, so it's checked before the output is read.
  5. Asserts the 8 words equal compute_verification_digest(unpack_output_digest(low, high)) (apollo_starknet_os_program,starknet_os: unpack the processed-proof output digest in Cairo #15161).

Rust:

  • run_aggregator_program wraps the aggregator hint processor in cairo-program-runner-lib's BootloaderHintProcessor as its extra_hint_processor. The aggregator's own hints and the Cairo0 core hints still go to the aggregator hint processor first. The bootloader's hints and the verifier's Cairo1 hints go to the bootloader hint processor.
  • run_program no longer requires CommonHintProcessor, which it never used.
  • AggregatorInput.circuit_verifier_task: Option<CircuitVerifierTaskInput>, holding the verifier executable path and the processed proof path.
  • The new EnterCircuitVerifierTaskScope aggregator hint builds the task (create_cairo1_program_task). It fails with MissingCircuitVerifierTask if the blocks contain a proof-facts transaction and the input has no task.
  • The hint-consistency tests skip hints of the copied starkware.cairo.bootloaders.simple_bootloader module, which cairo-program-runner-lib runs.

Tests (in aggregator/test.rs, using #15088's verifier and processed-proof fixtures):

  • test_aggregator_verifies_processed_proof: the golden leaf's processed digest in a block's header. The run succeeds, and the aggregator's output is unchanged apart from the header fields, so the verifier's output doesn't leak into it.
  • test_aggregator_rejects_processed_proof_of_other_proof_facts: the digest of other proof facts fails in assert_digests_equal. With the digest comparison removed, this test fails.
  • test_aggregator_requires_circuit_verifier_task_for_proof_facts.
  • The two tests that run the verifier take about 30 s each.

The aggregator program hashes change; the OS and virtual OS hashes don't.

Not in this PR: producing the processed proof and passing it into the aggregator input in production, publishing (or not) the digest in the aggregator's output, and the production verifier's program hash (TODO next to the pinned canonical_small value).

Stack: ← #15064 ← #15160 ← #15161 ← this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_015X6kWZhBXFeNyPwSuKTohy


Generated by Claude Code

… the aggregator

When the aggregated blocks contain a proof-facts transaction, the aggregator runs
the circuit verifier on its processed proof as a simple bootloader task, writing
the task's output to a scratch segment rather than to the aggregator's output. It
then checks the verifier's program hash against a pinned value and the verifier's
output against the verification digest of the processed proof output digest the
blocks emitted.

The aggregator hint processor is wrapped by the bootloader hint processor of
cairo-program-runner-lib, which runs the bootloader's hints and the verifier's
Cairo1 hints. The aggregator input gains the circuit verifier task (the verifier
executable and the processed proof).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015X6kWZhBXFeNyPwSuKTohy
@cursor

cursor Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

PR Summary

High Risk
Changes in-Cairo proof verification and pinned verifier program hash on a security-critical aggregation path; a bug could accept invalid single proofs or break aggregator runs when proof-facts blocks appear.

Overview
The aggregator now cryptographically checks the processed proof for aggregated blocks that include a proof-facts transaction, so that check is part of the aggregator proof rather than only off-chain.

After combine_blocks, verify_processed_proof runs when the combined header reports a proof-facts transaction: it executes the circuit verifier via the copied simple bootloader (single Blake-hashed task), writes verifier output to a scratch segment so the public aggregator output layout stays unchanged, pins the verifier program hash, and asserts the verifier digest matches compute_verification_digest of the header’s packed processed-proof digest.

On the Rust side, aggregator runs go through run_aggregator_program, which layers BootloaderHintProcessor over the aggregator hint processor for bootloader and Cairo1 verifier hints. AggregatorInput gains optional circuit_verifier_task (verifier executable + processed proof paths); EnterCircuitVerifierTaskScope builds that task and errors with MissingCircuitVerifierTask when blocks claim proof facts but no task is supplied. Aggregator program hashes in program_hash.json are updated; OS/virtual OS hashes are not.

Tests cover a successful golden processed proof, rejection when proof facts do not match, and failure when proof facts are present without a verifier task.

Reviewed by Cursor Bugbot for commit e2da678. Bugbot is set up for automated code reviews on this repo. Configure here.

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

@github-actions

Copy link
Copy Markdown

Artifacts upload workflows:

This branch has not been deployed

No deployments
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.

3 participants