snip: 36
title: In protocol S-Two verification
author: Ohad Barta
description: Introduce capability of verifying S-Two proofs within Starknet
discussions-to: https://community.starknet.io/t/snip-36-in-protocol-proof-verification
status: Draft
type: Standards Track
category: Core
created: 2026-02-15
Simple Summary
This SNIP proposes adding support for S-Two proof verification within the Starknet protocol. The document outlines the motivation and specifies a concrete mechanism to facilitate applications that use client-side proving on top of Starknet.
Motivation
Enabling applications to execute logic off-chain and prove it to Starknet unlocks two major domains that are impractical with naĂŻve on-chain execution:
Infinite scaling with ZKthreads and sharding - Starknet, despite being cost-effective, still has finite resources (storage, execution power, etc.). Transactions from one app must compete with others. Even ignoring congestion, networking, database, and sequencing expenses are not always aligned with application preferences. Enabling multiple Shards for application-specific logic anchored to Starknet would empower applications with more control over their environment while seamlessly leveraging Starknet’s liquidity and ecosystem.
Privacy: Proof-verification allows transactions to modify hidden/encrypted parts of a state in a secure way, which is still unknown to Starknet’s users and fullnodes.
Currently, Starknet lacks native proof verification. While creating an S-Two Verifier as a smart contract and submitting an S-Two proof in transaction calldata is possible, this approach is insufficient. Including the full proof (often tens of thousands of felts) in calldata exceeds the present transaction limit (5K felts). This configurable cap limits block usage to prevent excess burden on the Starknet p2p network. Further, large proofs are expensive for the feeder gateway to relay.
Although proofs can be split across multiple transactions (as Starknet does on Ethereum), this remains prohibitively expensive and degrades the usability of L3 and privacy-focused use cases.
​
Rationale
What is proven?
While any claim can be theoretically proven to Starknet, this SNIP suggests focusing on proving one particular claim: An execution of a Starknet transaction.
Reasons for proving a Starknet transaction:
- Significantly simpler:
- For protocols: developers can write standard Starknet contracts and rely on SNOS functionality without implementing custom Cairo proof systems.
- For Starknet: The set of acceptable programs to prove is constrained (e.g., tied to known Starknet OS program hashes), simplifying verification logic and bounding proof size variability.
- Sufficient for the main motivations:
- ZKThreads can execute large transactions off-chain and prove them via a cheaper on-chain transaction.
- Privacy applications can implement business logic in Cairo, use Starknet accounts and wallets, and prove a virtual block to Starknet.
Mindset behind the design - this is Phase 1
The following is knowingly omitted from the scope of this SNIP. Depending on adoption and feedback of this feature, these follow-up features will get prioritized and implemented:
- Trustlessness - In Phase 1, proofs are verified solely by Starknet consensus. A future phase will integrate SHARP so proofs are ultimately verified on Ethereum, ensuring correctness beyond Starknet consensus.
- Better support for ZKThreads - Future versions may allow a single proof to attest to multiple transactions or entire blocks.
- Better support for privacy -Currently, privacy is de facto (data is computationally infeasible to extract). A future phase may support fully zero-knowledge proofs.
- Allowing the full builtin set - To facilitate more efficient provers and verifiers, the builtins add_mod, mul_lod and Keccak are currently excluded from the claims that are proven. They can be easily added given use-case that needs them
High-level design and the rationale behind it
The aim is to enable transactions to reference off-chain execution via proofs, minimizing costs and avoiding issues seen in purely contract-based approaches.
Initially, proof verification is performed by Starknet consensus. Users need only rely on the assertion that “Starknet consensus has verified it.”
​
Therefore, a new optional field, proof, is introduced for an invoke tx*.* This field will be sent with the transaction to the gateway and will be echoed within the Starknet mempool network - but it will not be available for consumption through the feeder gateway, and will not appear explicitly in the block, and thus its networking footprint will be reduced.
​
However, some elements should reach Starknet itself to correlate the execution with the proof. Thus, another field that will be added to the transactions is proof_facts. Think of it as a TLDR of the proof that Starknet needs to care about. The exact structure is discussed in the “implementation” section, but it roughly includes:
- Program hash - the actual program that proof proved
- Block hash - the real Starknet block that the “virtual Starknet block proven” continued.
- MessageHashes - a list of instructions to perform on Starknet as a result of these proofs.
The raw messages to perform appear in the transaction’s calldata, so the on-chain logic can access them freely and check their connection to message hashes that appear within the proof_facts.
​
On-chain, proof facts are retrieved by calling a new version (v3) of the get_execution_info syscall. Notice:
- The above fields are optional. If they don’t exist, the tx hash will not include them in the calculation. This means that transaction v3, as it is today, will not be changed.
- Same with get_execution_info: the answer for current contracts that call this syscall will not change. Contracts will need to specify that they call the new version to retrieve the proof.
Implementation
The program to prove:
The program proves the execution of a “virtual/offchain” transaction that occurs on top of a given Starknet block, resulting in a virtual Starknet block to be proven. The OS of the virtual Starknet block is slightly different from the regular Starknet OS and has somewhat reduced functionality. The reason: some OS calls in Starknet are currently trusted. For example, the timestamp. The return values from these calls could have been tampered with by the app if the vanilla Starknet OS had been invoked.
​
The OS program of the virtual block is thus very similar to, but different from, the regular OS. You can notice some files in the SNOS repo have “virtual” in their name. These files replace the equivalent files (w/o “Virtual” in the name) when having the virtual OS.
​
The claim to prove:
Applications that integrate with this feature should deploy to Starknet contracts that include the logic that should be proven to Starknet. The proper execution of these transactions is the claim to be proved.
​
Verification process:
A S-Two Verifier written in Rust is added to the gateway, and the sequencer has the responsibility of verifying the proof , checking the connection between the proof and the proof facts, and propagating the transaction to other sequences only if these checks have passed.
Details and code are available here.
​
How to invoke the prover:
The proving service is a JSON-RPC 2.0 server (implemented in the starknet_os_runner crate within the Starknet sequencer repo) that generates proofs for Starknet transactions.
​
dApp developers that want to create proofs as part of the flow can setup a provng server, and request it to perform transaction proving by calling the prove_transaction method (see implementation here). The method takes a block Id and an invoke transaction, executes the transaction against that block’s state, and returns a proof.
​
Here is an example request:
​
curl -X POST http://localhost:3000 \
-H “Content-Type: application/json” \
-d '{
“jsonrpc”: “2.0”,
“method”: “starknet_proveTransaction”,
“params”: [
{"block\_number": 800000},
{
"type": "INVOKE",
"version": "0x3",
"sender\_address": "0x...",
"calldata": \["0x..."\],
"signature": \["0x...", "0x..."\],
"nonce": "0x...",
"resource\_bounds": {
"l1\_gas": {"max\_amount": "0x...", "max\_price\_per\_unit": "0x..."},
"l2\_gas": {"max\_amount": "0x0", "max\_price\_per\_unit": "0x0"},
"l1\_data\_gas": {"max\_amount": "0x0", "max\_price\_per\_unit": "0x0"}
},
"tip": "0x0",
"paymaster\_data": \[\],
"account\_deployment\_data": \[\],
"nonce\_data\_availability\_mode": "L1",
"fee\_data\_availability\_mode": "L1"
}
],
“id”: 1
}’
​
The response contains:
​
- proof — The generated proof (base64-encoded).
- proof_facts — Proof facts for verification (array of felts).
- l2_to_l1_messages — Messages sent from L2 to L1 during execution.
New tx - v3 structure and how new fields are treated
The exact suggested transaction structure can be found here. Specifically, it contains the new fields “proof” (array of uint32) and “proof facts” (array of felt252).
​
The “proof fact” array is accessible only through a dedicated syscall, “get execution info,” and only within the context of the transaction that included it.
You can see the new syscall here.
A small example of the new syscall usage:
​
use starknet::SyscallResultTrait;
#[starknet::contract]
mod Example {
#[external(v0)]
#[raw_output]
fn get_proof_facts(self: @ContractState) -> Span<felt252> {
let info \= starknet::syscalls::get\_execution\_info\_v3\_syscall()
.unwrap\_syscall()
.unbox();
info.tx\_info.unbox().proof\_facts
}
}
​
Updates for RPC 0.10.1 that are offered as part of this feature
New RPC & Transaction Capabilities
- Added support for proof submission in Invoke V3 transactions (`proof` and `proof_facts`)
- Added `initial_reads` flag to transaction simulation
- Added `initial_reads` flag for block tracing
- Added `proof_facts` flag support to websocket subscriptions and state update requests
Compatibility & Clarifications
- Improved backwards compatibility for initial read responses
- Clarified semantics for cases where initial proofs are absent in traces
Sending the new tx type
All major SDKs (starknet.js/py/rs/go and more) are currently working on being compatible with RPC 0.10.1. Their support is a prerequisite for having this feature on the Starknet testnet.
Proofs are stored within each Apollo.
Proofs will be stored in a new component inside each Apollo, called “proof manager”. Proofs will be saved there, after being verified, for a finite (TBD exactly what, but at least a few weeks) period of time, to optimize verification (i.e., avoid verifying again in the consensus) and to allow syncing of the proofs by new nodes that enter the consensus.
​
It will have the following interface:
- `set_proof(proof_facts, proof)`,
- `get_proof(proof_facts)-> Proof`
- `contains_proof(proof_facts) -> bool`.
Details and code can be found here
​
Pricing
Pricing of these new transactions (on top of the regular L2gas counting for on-chain operations) will be based on three main components:
- Proof propagation between Apollos - price proof as calldata is priced today. Price will go linearly with the proof length (as the “proof facts” structure would claim), and take the relevant STRKs according to the L2Gas price.
- Storing the proof sent by users (at least until milestone 2, when these proofs are proven to be correct)
- Prove the verification of these proofs (after this follow-up will be implemented)
The first two components are linearly dependent on the proof size, and their exact prices might change as we see how small proofs can be. The price per byte of proof is 125 L2gas for proof propagation (reflecting 4,000 L2gas/felt - which is 20% cheaper than calldata as the proof shouldn’t be transmitted to fullnodes), and an additional 5 L2gas/byte for storage. This results in 130 L2gas/byte, or, with proofs of 500K bytes, 65M L2gas.
​
10M additional L2gas will be added to cover future verification costs, resulting in a final price of 75M L2gas.
​
Backwards Compatibility
This SNIP is fully backwards compatible. All it does is introduce new functionality via a new transaction structure.
Security Considerations
In the first phase, all proofs will be verified by the Starknet consensus but not by the SNOS. This means that applications built with this feature will have degraded security compared to native Starknet applications. This will be mitigated in a follow-up release of this feature.
Copyright
Copyright and related rights waived via MIT.