Reference

Configuration

Every configuration value StateSync-GKR reads, with its default, accepted range and the error returned at each limit, plus the cryptographic parameters that are fixed in the source.

A prover's behavior is set by one StateSyncGkrConfig value. Its fields are plain values. Changing smt or layer_strategy changes the compiled circuit identity, its commitment and every proof made under it; batching only affects callers that drive batching::BatchProver. This page lists each value with its default and limits, then the parameters that are fixed in the source.

StateSyncGkrConfig#

Rust
use statesync_gkr::StateSyncGkrConfig;
use statesync_gkr::batching::BatchPolicy;
use statesync_gkr::compiler::{LayerStrategy, SmtParams};

fn main() {
    let config = StateSyncGkrConfig {
        smt: SmtParams {
            depth: 24,
            leaf_max_fields: 31,
        },
        layer_strategy: LayerStrategy::A,
        batching: BatchPolicy::default(),
    };
    // The explicit values above are the defaults.
    assert_eq!(config.smt, SmtParams::default());
    assert_eq!(config.layer_strategy, LayerStrategy::default());
    println!("{config:?}");
}
FieldTypeDefaultRead by
smtcompiler::SmtParamsdepth 24, leaf_max_fields 31Compiler, witness generation, verifier, circuit commitment, encoding
layer_strategycompiler::LayerStrategyACompiler, circuit commitment, encoding
batchingbatching::BatchPolicy32, 200 ms, 2Only callers that drive batching::BatchProver; the facade's methods do not read it

Build PreparedSync after you fix the configuration, because it encodes that configuration's circuit. Do not change prover.config while you reuse prepared state; build a new preparation instead.

Tree depth#

SmtParams::depth is the number of tree levels, which is also the number of siblings in every path.

PropertyValue
Typeu32
Default24, which gives 2^24 slots
Minimum1. Depth 0 makes compilation fail with CompileError::UnsupportedConfig and the reason "tree depth must be positive"
Key rangeasset_id must be below 2^depth while depth is below 64
Path lengthExactly depth siblings
Measured profilesDepths 24, 28 and 32
MaximumNone enforced. From depth 64 upward the key-range check is disabled; such depths are untested

A larger depth widens the circuit and increases witness, proving and verification work. In the measured profiles the layer count stayed at 118 and the encoded membership proof grew about 2.93% from depth 24 to depth 32; Circuits and layers explains why. Each depth compiles to a different circuit with a different commitment and prepared state, so trees of different depths are separate instances.

Leaf bound#

SmtParams::leaf_max_fields is the maximum length of a leaf encoding in field elements, tag included.

PropertyValue
Typeu32
Default31 (primitives::hash::DEFAULT_LEAF_MAX_FIELDS)
Minimum10: the tag plus the nine identity limbs of an occupied leaf. Smaller values make compilation fail with CompileError::UnsupportedConfig and the reason "leaf_max_fields must be >= 10 (tag + 9 keccak limbs)"
Encoding limit65,535. The circuit identity stores the bound as a u16; above this, circuit_identity and encode_sync_result fail with EncodeError::CountOverflow and verify_encoded_sync_op returns false
State fields per occupied leafAt most leaf_max_fields - 10, which is 21 at the default
Leaf pre-image widthleaf_max_fields + 1 rounded up to a multiple of 8: 32 lanes, absorbed in four sponge blocks, at the default

The bound is part of the circuit identity and the circuit commitment, so any change produces a different circuit identity and commitment. A change that alters the pre-image width also changes every leaf digest, and with it every root, so treat the bound like the depth: fixed for the life of a tree. The 118-layer schedule was measured at the default bound; a bound with a different pre-image width changes the leaf hash circuit, and that measurement no longer applies.

Layer strategy#

LayerStrategy selects how tree levels map to GKR layers.

VariantMeaningResult
AOne data-parallel instance per tree levelDefault; compiles
B { merge_k: u32 }Merge k adjacent tree levels into one layerCompileError::UnsupportedConfig
CSplit each level's hash rounds into thinner layersCompileError::UnsupportedConfig

The unsupported variants fail with the reason "v0.1 implements strategy A (one data-parallel instance per tree level) only". The inner-proof encoding accepts only the strategy identifier of A.

Batch policy#

batching::BatchPolicy holds the knobs of the in-process deadline scheduler.

FieldTypeDefaultMeaning
max_batch_sizeusize32Upper bound on one batch
deadlineDuration200 msBudget of one scheduling round
min_batch_sizeusize2Queue length below which the scheduler takes whatever is queued

DeadlineScheduler::decide_batch_size(queue_len, remaining) returns 0 for an empty queue and the whole queue when it is shorter than min_batch_size. Otherwise it takes up to max_batch_size jobs, and when remaining is below deadline it scales that size down in proportion, never below min_batch_size.

The defaults are provisional values for this scheduler. The measured serving settings (worker count, batch cap and maximum wait) belong to a separate benchmark caller and are covered in Performance tuning.

Fixed parameters#

These values are compiled in. There is no runtime API to select a different field, hash or transcript.

ParameterValueWhere
Base fieldKoalaBear, p = 2^31 - 2^24 + 1 = 2130706433primitives::BaseField
Challenge fieldDegree-four binomial extension of KoalaBearprimitives::ChallengeField, CHALLENGE_EXT_DEGREE
PermutationPoseidon2, width 16, x^3 S-box, 4 + 4 external and 20 internal rounds, Plonky3 0.4.3 constantsprimitives::poseidon2_arith
Digest width8 field elementsprimitives::hash::DIGEST_WIDTH
Leaf sponge rate8 lanes per permutationprimitives::hash::LEAF_SPONGE_RATE
TranscriptPoseidon2 duplex sponge, rate 8primitives::Transcript
Transcript domain tagstatesync-gkr/v0.1DOMAIN_TAG_V01
Commitment domain tagssgkr/circuit-commitment/v1wrap::commitment::CIRCUIT_COMMITMENT_DOMAIN_V1
Round degree bound4gkr::reduce::LAYER_ROUND_DEGREE
Inner-proof versionsEncoding 1, protocol 1, circuit 1, leaf encoding 1wrap::encoding
Plonky3 cratesExact =0.4.3 pinsWorkspace Cargo.toml

Changing the cryptographic profile#

The generic traits, HashGadget, WiringOracle, SumcheckOracle and the Field bounds of the sumcheck and circuit types, are extension points. The shipped proving and verification functions, however, use the fixed aliases above. Replacing the field, the hash, the transcript or the compiler is a new implementation and a new verification task:

  • proof bytes, circuit commitments and inner-proof compatibility change, and the transcript change requires a new protocol_version;
  • the existing proof evidence and formal results do not transfer automatically.

Custom frontends describes what a new frontend over the existing field and hash must supply.

Limits at a glance#

LimitEnforced byResult
depth is 0Compilation (prepare, prove_sync_op, verify_sync_op)CompileError::UnsupportedConfig; verify_sync_op returns false
leaf_max_fields below 10CompilationCompileError::UnsupportedConfig
Strategy other than ACompilationCompileError::UnsupportedConfig
Path length differs from depthMerklePath::compute_root, witness generation, verificationSmtError::PathLengthMismatch; verification returns false
Key at or above 2^depth, depth below 64MerklePath::compute_root, verificationSmtError::KeyOutOfRange; verification returns false. Witness generation does not check it
Leaf encoding empty or longer than leaf_max_fieldsLeaf hashingHashError::EmptyEncoding or EncodingTooLong, wrapped as SmtError::LeafEncoding
leaf_max_fields above 65,535circuit_identity, encode_sync_resultEncodeError::CountOverflow; verify_encoded_sync_op returns false
Encoded message longer than u32::MAX byteswrap::encoding::encode_inner_proofEncodeError::MessageTooLong

Errors describes every error type and how to handle it.