Sitelet https://github.com/starkware-libs/cairo/pull/10213
Skip to content

(bug fix): validate entry-point builtins are in canonical order in class-to-casm - #10213

Merged
eytan-starkware merged 1 commit into
mainfrom
eytan_graphite/casm_class_builtin_order_check
Jul 20, 2026
Merged

eytan-starkware merged 1 commit into
mainfrom
eytan_graphite/casm_class_builtin_order_check

Conversation

@eytan-starkware

@eytan-starkware eytan-starkware commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The IMPLICIT_PRECEDENCE constant, which defines the canonical order that entry-point builtins must appear in as required by the Starknet OS, previously existed as two separate definitions: a &[&str] slice of Cairo paths in cairo-lang-starknet/src/plugin/consts.rs (used by the plugin to stamp #[implicit_precedence(...)] attributes), and an implicit inline set in casm_contract_class.rs (used to validate builtin types during compilation). These two definitions could silently drift out of sync.

This PR consolidates them into a single pub static IMPLICIT_PRECEDENCE: [(GenericTypeId, &str); 11] in casm_contract_class.rs, pairing each Sierra GenericTypeId with its Cairo path string. The plugin now imports and iterates over this shared constant (extracting the .1 path strings), and from_contract_class derives its builtin_types validation set from the same source (extracting the .0 type IDs).

Additionally, from_contract_class now enforces that an entry point's builtins are a subsequence of IMPLICIT_PRECEDENCE — i.e., they appear in the canonical OS-required order — returning InvalidEntryPointSignatureWrongBuiltinsOrder if they do not. Two new tests cover this: one verifying that a canonically-ordered entry point compiles successfully, and one verifying that a hand-written Sierra entry point with swapped builtins is rejected (this case cannot arise from the frontend, which always emits builtins in canonical order).


Type of change

Please check one:

  • Bug fix (fixes incorrect behavior)
  • New feature
  • Performance improvement
  • Documentation change with concrete technical impact
  • Style, wording, formatting, or typo-only change

Why is this change needed?

The builtin order required by the Starknet OS was encoded in two separate places with different representations. A change to one would not automatically update the other, risking silent divergence between what the plugin emits and what the compiler validates. Additionally, there was no runtime enforcement that entry-point builtins actually appear in the OS-required order during CASM compilation.


What was the behavior or documentation before?

The plugin used a &[&str] slice of Cairo path strings in consts.rs to generate #[implicit_precedence(...)] attributes. The compiler used a separately constructed UnorderedHashSet of GenericTypeIds to check that builtins were valid types, but did not verify their ordering.


What is the behavior or documentation after?

A single IMPLICIT_PRECEDENCE static in casm_contract_class.rs pairs each GenericTypeId with its Cairo path string. Both the plugin (for attribute generation) and the compiler (for type validation and order enforcement) derive their data from this one source. The compiler now also rejects entry points whose builtins are not a subsequence of the canonical order.


Related issue or discussion (if any)

N/A


Additional context

The non-canonical builtin order check can only be triggered by hand-crafted Sierra, since the Cairo frontend always emits builtins in canonical order. The new tests construct such Sierra directly using a hand-written entry_point_sierra helper and bypass the frontend entirely.

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

eytan-starkware commented Jul 19, 2026 •

Copy link
Copy Markdown
Contributor Author

@eytan-starkware
eytan-starkware marked this pull request as ready for review July 19, 2026 10:39
@cursor

cursor Bot commented Jul 19, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Tightens contract-class validation at compile time; legitimate hand-crafted Sierra with non-canonical builtin order will now fail, while normal frontend output should be unchanged.

Overview
Contract class → CASM now rejects entry points whose implicit builtins are not in the Starknet OS canonical order, not just unknown types.

A new public ENTRY_POINT_BUILTIN_ORDER lists the nine allowed mid-signature builtins (Pedersen through MulMod). Validation uses that list instead of an unordered set, still requires Gas and System as the last two slots, and adds a subsequence check so builtins must follow that order (e.g. swapping Bitwise and EcOp fails with InvalidEntryPointSignatureWrongBuiltinsOrder). Gas/System swapped into the middle still fail as InvalidBuiltinType.

Tests load example contracts via a shared helper and mutate the libfuncs-coverage external entry point to cover accepted canonical order, swapped builtins, and mid-list gas/system. The Starknet plugin documents that order is enforced in cairo-lang-starknet-classes via ENTRY_POINT_BUILTIN_ORDER.

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4a5298d. Configure here.

Comment thread crates/cairo-lang-starknet-classes/src/casm_contract_class.rs

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@orizi made 1 comment.
Reviewable status: 0 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).


crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 111 at r1 (raw file):

    (MulModType::ID, "core::circuit::MulMod"),
    (GasBuiltinType::ID, "core::gas::GasBuiltin"),
    (SystemType::ID, "System"),

rather have it duplicated - and use this as the source of truth - as this now has information that has nothing to do with sierra.

Code quote:

    (RangeCheckType::ID, "core::RangeCheck"),
    (BitwiseType::ID, "core::integer::Bitwise"),
    (EcOpType::ID, "core::ec::EcOp"),
    (PoseidonType::ID, "core::poseidon::Poseidon"),
    (SegmentArenaType::ID, "core::SegmentArena"),
    (RangeCheck96Type::ID, "core::circuit::RangeCheck96"),
    (AddModType::ID, "core::circuit::AddMod"),
    (MulModType::ID, "core::circuit::MulMod"),
    (GasBuiltinType::ID, "core::gas::GasBuiltin"),
    (SystemType::ID, "System"),

@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 4a5298d to 013c7ed Compare July 19, 2026 13:01

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@eytan-starkware made 1 comment.
Reviewable status: 0 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).


crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 111 at r1 (raw file):

Previously, orizi wrote…

rather have it duplicated - and use this as the source of truth - as this now has information that has nothing to do with sierra.

Done.

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@orizi reviewed 2 files, made 2 comments, and resolved 1 discussion.
Reviewable status: 2 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).


crates/cairo-lang-starknet/src/plugin/consts.rs line 68 at r2 (raw file):

/// Starknet OS required implicit precedence.
/// Checked in `cairo-lang-starknet-classes` during contract-class-to-CASM compilation (see

Validated

Code quote:

Checked

crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 550 at r2 (raw file):

            require(builtins.iter().all(|type_id| {
                canonical.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id))
            }))

Suggestion:

            let mut order_iter = ENTRY_POINT_BUILTIN_ORDER.iter();
            require(builtins.iter().all(|type_id| {
                order_iter.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id))
            }))

@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 013c7ed to 4612711 Compare July 19, 2026 15:02

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@eytan-starkware made 2 comments.
Reviewable status: 2 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).


crates/cairo-lang-starknet/src/plugin/consts.rs line 68 at r2 (raw file):

Previously, orizi wrote…

Validated

Done.


crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 550 at r2 (raw file):

            require(builtins.iter().all(|type_id| {
                canonical.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id))
            }))

Done.

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@orizi reviewed 2 files and all commit messages, made 1 comment, and resolved 2 discussions.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on eytan-starkware and TomerStarkware).


crates/cairo-lang-starknet-classes/src/casm_contract_class_test.rs line 45 at r3 (raw file):

/// Hand-written Sierra for a contract with a single entry point. `RangeCheck` is fixed as the
/// first builtin (it feeds `withdraw_gas`, so the entry-point cost is properly accounted); the

i really hate this test :\ i;m wondering if we should instead just read an existing program and edit it inplace.

@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 4612711 to 524a8cf Compare July 20, 2026 06:36

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@eytan-starkware made 1 comment.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on orizi and TomerStarkware).


crates/cairo-lang-starknet-classes/src/casm_contract_class_test.rs line 45 at r3 (raw file):

Previously, orizi wrote…

i really hate this test :\ i;m wondering if we should instead just read an existing program and edit it inplace.

Done.

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@orizi reviewed 1 file and all commit messages, and made 1 comment.
Reviewable status: 4 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).


a discussion (no related file):
add a pre-PR making signature checks happen before full sierra-to-casm bytecode compilation.

@eytan-starkware
eytan-starkware changed the base branch from main to graphite-base/10213 July 20, 2026 08:14
@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 524a8cf to 36be342 Compare July 20, 2026 08:14
@eytan-starkware
eytan-starkware changed the base branch from graphite-base/10213 to eytan_graphite/casm_entry_point_checks_before_compilation July 20, 2026 08:14

@eytan-starkware eytan-starkware left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@eytan-starkware made 1 comment.
Reviewable status: 4 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).


a discussion (no related file):

Previously, orizi wrote…

add a pre-PR making signature checks happen before full sierra-to-casm bytecode compilation.

Done.

@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 36be342 to 9172dbb Compare July 20, 2026 09:50
@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_entry_point_checks_before_compilation branch from d5c0814 to 46939ec Compare July 20, 2026 09:50

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

:lgtm:

@orizi reviewed 2 files and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on TomerStarkware).

@orizi orizi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@orizi resolved 1 discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on TomerStarkware).

@eytan-starkware
eytan-starkware changed the base branch from eytan_graphite/casm_entry_point_checks_before_compilation to main July 20, 2026 10:32
…ass-to-casm

A Starknet entry point's builtin order is only *assumed* to be the canonical
order the OS expects: it is produced upstream by the `cairo-lang-starknet` plugin
(which stamps `#[implicit_precedence(...)]`) plus the lowering-stage sort, and
nothing re-checks it when a `ContractClass` is compiled to a `CasmContractClass`.
A class whose entry points list builtins out of that order would compile here yet
misbehave in the OS.

Add `ENTRY_POINT_BUILTIN_ORDER` to `cairo-lang-starknet-classes`: the canonical
order excluding the trailing gas/system pair (which is checked separately).
`from_contract_class` now validates that each entry point's remaining builtins
are a subsequence of it, returning
`InvalidEntryPointSignatureWrongBuiltinsOrder` otherwise; gas or system threaded
mid-list is rejected as `InvalidBuiltinType` since they are no longer in the
valid mid-list set. The plugin's `IMPLICIT_PRECEDENCE` path list stays in the
plugin (Cairo type paths don't belong in the sierra/casm layer) with a comment
tying it to the check here.

Tested by loading the generated libfuncs-coverage example contract (whose entry
point lists all builtins) and swapping two builtins' positions in its entry
point signature — params, return
types, returns and their store_temps, consistently, so the program stays valid;
the frontend can never emit such an order. Canonical compiles; a swapped
mid-pair is rejected as wrong order; gas or system swapped into the mid-list is
rejected as an invalid builtin type.
@eytan-starkware
eytan-starkware force-pushed the eytan_graphite/casm_class_builtin_order_check branch from 9172dbb to c3f5303 Compare July 20, 2026 10:33
@graphite-app

graphite-app Bot commented Jul 20, 2026

Copy link
Copy Markdown

Merge activity

  • Jul 20, 10:33 AM UTC: Graphite rebased this pull request, because this pull request is set to merge when ready.

@eytan-starkware
eytan-starkware added this pull request to the merge queue Jul 20, 2026
Merged via the queue into main with commit 1fc7b7f Jul 20, 2026
55 checks passed
@eytan-starkware
eytan-starkware deleted the eytan_graphite/casm_class_builtin_order_check branch July 20, 2026 10:59
pull Bot pushed a commit to AKJUS/cairo that referenced this pull request Jul 21, 2026
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