Stwo Documentation

repository·dev·Indexed 19 days ago

https://github.com/starkware-libs/stwo

A high-performance, production-grade Circle STARK prover and verifier written in Rust. Stwo operates over the Mersenne prime field M31 and utilizes SIMD optimizations (AVX2, AVX-512, NEON, WebAssembly SIMD) for fast proving. It features a modular design and a minimal, no_std-compatible verifier suitable for on-chain deployment in environments like Ethereum (Solidity) and Starknet (Cairo). The ecosystem includes utilities for AIR execution, trace management via ComponentTrace, and integration with stwo-cairo and SHARP.

Tokens
24K
Snippets
89
Records
105
Agent score
64%

What's inside Stwo

  1. What is Stwo?

    dev

    Stwo is a production-grade Circle STARK prover and verifier implemented in Rust. It operates over the Mersenne prime field M31 (p = 2^31 − 1), which allows for highly efficient 32-bit modular arithmetic using SIMD (AVX2, AVX-512, NEON, WebAssembly SIMD) on modern CPUs.

    Key characteristics include:

    • Fast Proving: Uses a hand-tuned SIMD backend (backend::simd).
    • Cheap Verification: The verifier is no_std-compatible and small enough for on-chain environments like Ethereum (Solidity) and Starknet (Cairo).
    • Modular Design: Separates the core proof system, constraint framework, AIR utilities, and application logic.
  2. Understand the Stwo ecosystem and integrations

    dev

    Stwo is the core library for the prover. It is used as a foundation for several production-grade applications and services:

    • stwo-cairo: A production prover for the Cairo VM, serving as a reference for non-trivial provers built on Stwo.
    • SHARP: StarkWare's Shared Prover service that uses Stwo to generate proofs for Ethereum and other settlement layers.
    • Starknet: The largest production deployment that relies transitively on this codebase.

    If you have built a tool or integration on top of Stwo, you can contribute by opening a pull request to add it to the ecosystem documentation.

  3. Security considerations and vulnerability reporting

    dev

    Reporting Vulnerabilities

    If you discover a security issue, especially one affecting soundness (e.g., a forged proof being accepted or a valid proof being rejected), do not open a public GitHub issue. Instead, report it privately to security@starkware.co.

    Threat Model and Assumptions

    • Soundness: Circle STARKs are conjectured to be sound under standard cryptographic assumptions. Crucially, the consumer of this library is responsible for choosing proof parameters (blowup factor, FRI queries, grinding bits) to meet their target security level. Default parameters used in tests are not intended for production security.
    • Verifier Integrity: The no_std verifier provided in this repository is a reference. Users deploying on-chain verifiers are responsible for faithful re-implementation or transpilation.
    • Side Channels: Stwo is not constant-time. It is a public-coin proof system. While there are no secrets in the prover itself, the application using Stwo is responsible for protecting any optional witness data.
  4. Run Stwo benchmarks

    dev

    Benchmarks are located in crates/stwo/benches and crates/examples/benches. You can run all benchmarks or specific ones using the following commands.

    # Run all benchmarks
    cargo bench --features prover,parallel
    
    # Run a single benchmark (e.g., fft)
    cargo bench --features prover,parallel --bench fft
    
    # Quick Poseidon2 benchmark
    ./poseidon_benchmark.sh
  5. Run benchmarks for stwo

    dev

    To run specific benchmarks in the stwo crate, use cargo bench with the required features. You must specify the benchmark name as it is defined in the ../Cargo.toml file.

    Note: The benchmarks require the prover and parallel features to be enabled.

    cargo bench --features prover,parallel --bench [BENCH_NAME]
  6. Add Stwo as a dependency

    dev

    You can integrate Stwo into your Rust project depending on whether you need only the verifier or the full prover capabilities.

    • Verifier only: Use default-features = false to ensure no_std compatibility.
    • Prover: Enable the prover feature.
    • Parallel Prover: Enable both prover and parallel features for Rayon-based parallelism.
    [dependencies]
    # Verifier only (no_std-compatible)
    stwo = { version = "2.2", default-features = false }
    
    # Prover
    stwo = { version = "2.2", features = ["prover"] }
    
    # Prover + parallel proving
    stwo = { version = "2.2", features = ["prover", "parallel"] }
  7. Build and test Stwo

    dev

    Use the following commands to build and test different configurations of the library.

    Building:

    • Verifier-only: cargo build --release --no-default-features --package stwo
    • Full prover (single-threaded): cargo build --release --features prover
    • Full prover (parallel): cargo build --release --features "prover,parallel"

    Testing:

    • Standard suite: cargo test --features prover
    • Heavy/Slow tests: cargo test --release --features "prover,slow-tests"
    • Verifier-only tests: cargo test --no-default-features --package stwo
    # Verifier-only build (no_std-compatible)
    cargo build --release --no-default-features --package stwo
    
    # Full prover build, single-threaded
    cargo build --release --features prover
    
    # Full prover build, parallel
    cargo build --release --features "prover,parallel"
    
    # Standard test suite
    cargo test --features prover
    
    # Slow / heavy tests
    cargo test --release --features "prover,slow-tests"
    
    # Verifier-only tests (no prover dependencies)
    cargo test --no-default-features --package stwo
  8. Guidelines for contributing to Stwo

    dev

    Before submitting a non-trivial pull request, open an issue or discussion to align on direction. When contributing, follow these requirements:

    • Linting/Formatting: Run scripts/clippy.sh and scripts/rust_fmt.sh locally.
    • Testing: Add tests for new behavior. For soundness-critical changes, tests must cover both the accept and reject paths.
    • Verifier Constraints: The verifier must remain no_std. The ensure-verifier-no_std CI gate is used to prevent regressions.
    • Performance: Any changes to the SIMD backend should include a benchmark comparison.
    # Run linting and formatting locally before contributing
    ./scripts/clippy.sh
    ./scripts/rust_fmt.sh
  9. How ExprEvaluator manages intermediates and constraints

    dev

    The ExprEvaluator acts as a stateful collector during the symbolic evaluation of a constraint system. It maintains several internal collections:

    1. constraints: A list of ExtExpr representing the final constraints to be satisfied.
    2. intermediates: A mapping of names to BaseExpr values, used to store and reuse simpler expressions.
    3. ext_intermediates: A mapping of names to ExtExpr values, used for more complex or extended intermediate expressions.
    4. ordered_intermediates: A list that tracks the order in which intermediates were created, ensuring that when generating assignments or formatted strings, they follow a logical dependency order.

    When you call add_intermediate, the evaluator generates a unique name (e.g., intermediate0, intermediate1), stores the expression, and returns a parameter representing that name. This allows you to build complex, nested expressions while keeping the underlying symbolic representation manageable.

  10. Understand MerkleDecommitment data structures

    dev

    To perform verification, you must provide a MerkleDecommitment object which contains the necessary witness data that cannot be deduced from the queries alone.

    MerkleDecommitment<H>

    • hash_witness: Vec<H::Hash> - Hash values required by the verifier, provided in the order they are needed.
    • column_witness: Vec<BaseField> - Column values required by the verifier, provided in the order they are needed.

    MerkleDecommitmentAux<H>

    • all_node_values: Vec<HashMap<usize, H::Hash>> - Auxiliary data containing a map from node index to its hash value for each layer.
  11. Manage expression degree bounds with NamedExprs

    dev

    In the stwo-constraint-framework, calculating the degree of an expression often requires knowing the degrees of intermediate expressions or parameters. The NamedExprs struct acts as a registry that allows you to look up the degree of named expressions (both BaseExpr and ExtExpr) to correctly compute the total degree bound of complex expressions.

    Key Behaviors and Caveats

    • Degree Calculation Logic: The degree is computed with respect to columns treated as variables.
    • Constant 0: The constant 0 is treated as having degree 0 (rather than $-\infty$). Consequently, an expression like 0 * expr will return the degree of expr. It is recommended to use simplification to mitigate this.
    • Cancellation: The degree calculation does not account for algebraic cancellation. For example, (x^2 + 1) - (x^2 + x) will return a degree of 2 because the $x^2$ terms are not symbolically canceled during the bound computation.
    • Inverses: Computing the degree of an Inv (inverse) expression will panic! unless the expression being inverted is a constant or a parameter with degree 0.
    • Missing Names: If a name is not found in the registry and does not start with preprocessed., it is assumed to be an external variable (effectively a constant) with degree 0.
    // Example of registering intermediate expressions to compute complex degree bounds
    let intermediate = (felt!(12) + col!(1, 1, 0)) * var!("a") * col!(1, 0, 0);
    let qintermediate = secure_col!(intermediate.clone(), felt!(12), var!("b"), felt!(0));
    
    let named_exprs = NamedExprs::new(
        [("intermediate".to_string(), intermediate.clone())].into(),
        [("qintermediate".to_string(), qintermediate.clone())].into(),
    );
    
    // Now you can look up the degree of these named expressions
    let deg = named_exprs.degree_bound("intermediate".to_string());