Skip to content

cairo_verifier: Output the program's digest words directly - #649

Merged
ilyalesokhin-starkware merged 1 commit into
mainfrom
ilya/output_digest_words
Jul 22, 2026
Merged

ilyalesokhin-starkware merged 1 commit into
mainfrom
ilya/output_digest_words

Conversation

@ilyalesokhin-starkware

Copy link
Copy Markdown
Contributor

The program's output is already a Blake2s digest stored across the output
memory cells. Instead of re-hashing those cells and exposing the hash as the
circuit output, guess the eight digest words, split them back into the output
cells (binding them to the public memory), and expose the words themselves.

The output cells' nine-bit limbs are still mixed into the channel as
blake2s(limbs) to match the Cairo prover (PublicData::mix_into).

Also generalize From<Blake2sHash> from HashValue<QM31> to a generic
HashValue<Value> so the guess path can reuse it.

Regenerates the multiverifier/recursion proof fixtures and updates the
cairo-verifier preprocessed-root and output-value regression constants.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

@cursor

cursor Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

PR Summary

High Risk
Changes how public outputs are bound to memory and the verifier channel—core to proof correctness—even though limb hashing for mixing is preserved.

Overview
The Cairo verifier no longer treats the circuit’s public output as Blake2s(output memory limbs). It guesses the eight digest u32s, registers them with set_outputs in CairoStatement::new, and rebuilds the two output memory cells by decomposing those words into little-endian bits and regrouping into 9-bit limbs (word_to_le_bits / output_limbs_from_hash) so the public logup still ties them to proven memory.

claims_to_mix still mixes blake2s(limbs) into the channel (Cairo prover compatibility) but no longer defines the circuit’s public outputs there. The old split-based limb reconstruction and related imports are removed.

Multiverifier privacy fixture constants PRIVACY_CAIRO_VERIFIER_OUTPUT_VALUES and PRIVACY_CAIRO_VERIFIER_PREPROCESSED_ROOT are updated for the new circuit shape.

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

@reviewable-StarkWare

Copy link
Copy Markdown
Collaborator

This change is Reviewable

ilyalesokhin-starkware commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor Author

@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from ilya/circuit_output to graphite-base/649 July 15, 2026 12:28
@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from graphite-base/649 to ilya/circuit_output July 15, 2026 13:27
@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from ilya/circuit_output to graphite-base/649 July 15, 2026 14:21
@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from graphite-base/649 to ilya/circuit_output July 21, 2026 11:23
@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from ilya/circuit_output to graphite-base/649 July 21, 2026 12:07
@ilyalesokhin-starkware
ilyalesokhin-starkware changed the base branch from graphite-base/649 to main July 22, 2026 06:17

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gali-StarkWare reviewed 6 files and all commit messages, and made 2 comments.
Reviewable status: 6 of 7 files reviewed, 2 unresolved discussions (waiting on ilyalesokhin-starkware and yuvalsw).


crates/cairo_verifier/src/statement.rs line 402 at r3 (raw file):

        let n_components = components.len();
        let output_hash = output_hash.guess(context);
        context.set_outputs(&output_hash.iter().map(|word| *word.get()).collect_vec());

Where did we do context.set_output(output_hash) before (for the hash of the limbs)?


crates/cairo_verifier/src/statement.rs line 505 at r3 (raw file):

        let n_output_bytes = 4 * output_limb_vars.len();
        let output_limb_words = to_padded_u32_words(context, output_limb_vars);
        let output_hash = blake2s_u32s(context, output_limb_words, n_output_bytes);

I think we have a const for it. Just a suggestion

Suggestion:

        // Mix the outputs as 9-bit limbs into the channel.
        let output_limb_vars = outputs.iter().flatten().map(|limb| *limb.get()).collect_vec();
        let output_limb_words = to_padded_u32_words(context, output_limb_vars);
        let n_output_bytes = BYTES_IN_WORD * output_limb_words.len();
        let output_hash = blake2s_u32s(context, output_limb_words, n_output_bytes);

@ilyalesokhin-starkware

Copy link
Copy Markdown
Contributor Author

crates/cairo_verifier/src/statement.rs line 402 at r3 (raw file):

Previously, Gali-StarkWare wrote…

Where did we do context.set_output(output_hash) before (for the hash of the limbs)?

in claims_to_mix.

@ilyalesokhin-starkware

Copy link
Copy Markdown
Contributor Author

crates/cairo_verifier/src/statement.rs line 505 at r3 (raw file):

Previously, Gali-StarkWare wrote…

I think we have a const for it. Just a suggestion

We use 4 in other places

let n_bytes = 4 * message.len();

N_U8S_PER_U32 is the closest that I could find

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gali-StarkWare made 1 comment.
Reviewable status: 6 of 7 files reviewed, 3 unresolved discussions (waiting on ilyalesokhin-starkware and yuvalsw).


crates/cairo_verifier/src/statement.rs line 347 at r3 (raw file):

/// Splits the digest `hash` into its [`N_OUTPUTS`] `u128` halves, each decomposed into
/// nine-bit limbs (little-endian).

You wrote N_OUTPUTS and then halves, it reads a bit weird

Code quote:

/// Splits the digest `hash` into its [`N_OUTPUTS`] `u128` halves, each decomposed into
/// nine-bit limbs (little-endian).

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gali-StarkWare reviewed 1 file.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on ilyalesokhin-starkware and yuvalsw).

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gali-StarkWare made 1 comment and resolved 2 discussions.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on ilyalesokhin-starkware and yuvalsw).


crates/cairo_verifier/src/statement.rs line 402 at r3 (raw file):

Previously, ilyalesokhin-starkware wrote…

in claims_to_mix.

Oh right

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@Gali-StarkWare made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on ilyalesokhin-starkware and yuvalsw).

The program's output is already a Blake2s digest stored across the output
memory cells. Instead of re-hashing those cells and exposing the hash as the
circuit output, guess the eight digest words, split them back into the output
cells (binding them to the public memory), and expose the words themselves.

The output cells' nine-bit limbs are still mixed into the channel as
blake2s(limbs) to match the Cairo prover (PublicData::mix_into).

Also generalize `From<Blake2sHash>` from `HashValue<QM31>` to a generic
`HashValue<Value>` so the guess path can reuse it.

Regenerates the multiverifier/recursion proof fixtures and updates the
cairo-verifier preprocessed-root and output-value regression constants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ilyalesokhin-starkware

Copy link
Copy Markdown
Contributor Author

crates/cairo_verifier/src/statement.rs line 347 at r3 (raw file):

Previously, Gali-StarkWare wrote…

You wrote N_OUTPUTS and then halves, it reads a bit weird

done

@Gali-StarkWare Gali-StarkWare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gali-StarkWare reviewed 1 file and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on yuvalsw).

@ilyalesokhin-starkware
ilyalesokhin-starkware merged commit 4fd1be9 into main Jul 22, 2026
13 checks passed
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