Skip to content

fix(persistent-tee): use Poseidon L1->L2 message hash for Starknet settlement#77

Merged
kariy merged 1 commit into
mainfrom
fix/l1-to-l2-poseidon-msg-hash
May 29, 2026
Merged

fix(persistent-tee): use Poseidon L1->L2 message hash for Starknet settlement#77
kariy merged 1 commit into
mainfrom
fix/l1-to-l2-poseidon-msg-hash

Conversation

@kariy
Copy link
Copy Markdown
Member

@kariy kariy commented May 29, 2026

Problem

compute_l1_to_l2_msg_hash (persistent-tee settlement) hashes L1→L2 messages with the Ethereum keccak256 StarknetMessaging.sol formula. But saya-tee settles to a Starknet piltover core, whose canonical L1→L2 message hash is Poseidon (compute_message_hash_sn_to_appc). Katana commits to that Poseidon hash in the appchain attestation's messages_commitment — it stores the L1-handler message_hash produced by its Starknet messaging collector.

Because keccak ≠ poseidon, piltover's recomputed messages_commitment never matches Katana's for any settled block that consumes an L1→L2 message (e.g. a relayed L1-handler). piltover reverts with 'tee: invalid messages', and every subsequent block then fails 'invalid block number' — settlement stalls permanently.

This path isn't covered by the persistent-tee e2e test, which only settles plain transfer blocks (no messages), so it slipped through.

Fix

Use the Poseidon formula Katana uses, hashing over the L1-handler calldata [from_address, ...payload]:

Poseidon([from_address, to_address, nonce, selector, calldata.len(), ...calldata])
  where calldata = [from_address, ...payload]

(See katana crates/messaging/src/stream/collector/starknet.rs::compute_starknet_to_appchain_message_hash, whose result becomes the L1-handler message_hash fed into the attestation.) Drops the now-unused sha3 import.

Verification

Verified end-to-end against a local Katana rollup settling to a piltover core via saya-tee --mock-prove: blocks that consume an L1→L2 message (a mint_game L1-handler) now settle cleanly, alongside L2→L1 messages — both directions of a cross-chain demo work and saya-tee reports no settlement errors.

Scope: only compute_l1_to_l2_msg_hash. For Ethereum settlement the keccak formula would still be correct, but persistent-tee settles to a Starknet piltover core, so Poseidon is the right (and only) formula here.

…ttlement

`compute_l1_to_l2_msg_hash` hashed L1->L2 messages with the Ethereum
`keccak256` StarknetMessaging.sol formula. But saya-tee settles to a Starknet
piltover core, whose canonical L1->L2 hash is Poseidon
(`compute_message_hash_sn_to_appc`). Katana commits to that Poseidon hash in
the appchain attestation's `messages_commitment` (the L1-handler `message_hash`
from its Starknet messaging collector).

With keccak, piltover's recomputed `messages_commitment` never matches, so any
settled block that consumes an L1->L2 message reverts with
`'tee: invalid messages'`, and subsequent blocks fail `'invalid block number'`
— settlement stalls permanently. This path isn't covered by the persistent-tee
e2e test, which only settles plain transfer blocks (no messages).

Switch to the Poseidon formula Katana uses, hashing over the L1-handler calldata
`[from_address, ...payload]`:
  Poseidon([from, to, nonce, selector, calldata.len(), ...calldata])

Verified end-to-end against a Katana rollup settling to piltover: L1->L2
purchases (mint L1-handler) now settle, alongside L2->L1 messages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kariy kariy merged commit 56ee2b4 into main May 29, 2026
5 of 7 checks passed
kariy added a commit to dojoengine/katana that referenced this pull request May 31, 2026
The `test` workflow (and its `saya-tee-e2e` job) is path-filtered to
`crates/**`/`bin/**`, so PRs that only touch integration-test crates under
`tests/**` (e.g. the saya-tee e2e) never trigger it — every workflow shows as
skipped. Add `tests/**/*.rs`, `tests/**/Cargo.toml`, and `Cargo.lock` to both
the workflow `paths` filter and the `detect-changes` `broader-rust` filter so
those changes run the workspace jobs.

Bump the saya pin the `saya-tee-e2e` job builds from `17c0ee0` to `v0.4.1`,
which includes the L1->L2 Poseidon message-hash fix (dojoengine/saya#77) the
new messaging regression test depends on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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