The Moment of Discovery: Uncovering PoSt Circuit Constants in Filecoin's Proof Pipeline

Message Overview

In message <msg id=80>, the assistant executes a single grep command that extracts the definitive constant values for WinningPoSt and WindowPoSt proof parameters from the Filecoin proof system's source code:

grep -rn "WINNING_POST_CHALLENGE_COUNT\|WINNING_POST_SECTOR_COUNT\|WINDOW_POST_CHALLENGE_COUNT\|WINDOW_POST_SECTOR_COUNT" /home/theuser/.cargo/registry/src/index.crates.io-6f17d22bba15001f/filecoin-proofs-18.1.0/src/constants.rs 2>&1 | head -20

The output reveals:

29:pub const WINNING_POST_CHALLENGE_COUNT: usize = 66;
30:pub const WINNING_POST_SECTOR_COUNT: usize = 1;
32:pub const WINDOW_POST_CHALLENGE_COUNT: usize = 10;
102:    pub static ref WINDOW_POST_SECTOR_COUNT: RwLock<HashMap<u64, usize>> = RwLock::new(

On its surface, this appears to be a trivial grep operation. But within the arc of the investigation, it represents a critical juncture: the moment when abstract architectural exploration crystallizes into concrete, actionable numbers that will drive the design of a new pipelined SNARK proving daemon.

The Context: Why This Message Exists

The message is part of a deep-dive investigation into the SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin's Proof-of-Replication (PoRep) system. The broader session had already produced extensive documentation of the ~200 GiB peak memory footprint and its root causes, along with nine structural bottlenecks and three composable optimization proposals. The investigation had then shifted into designing a pipelined SNARK proving daemon called cuzk — an architecture inspired by GPU inference engines like vLLM and Triton, where SRS parameters are treated like model weights, proof jobs like inference requests, and witness vectors like KV caches.

The user's query that triggered this line of investigation was specific and practical: "I need to understand the circuit sizes and proof parameters for non-PoRep proof types in Curio." The user explicitly asked about WindowPoSt, WinningPoSt, and SnapDeals (update proofs), wanting to know for each proof type: does it use supraseal? What's its circuit size? What's its memory footprint?

This question is not merely academic. The cuzk architecture being designed must schedule and manage GPU resources across multiple proof types simultaneously. Without knowing the circuit sizes — the number of constraints, the FFT domain sizes, the challenge counts — it is impossible to estimate memory footprints, predict GPU kernel durations, or design a scheduler that can intelligently batch and prioritize jobs. The entire cuzk project depends on these numbers.

The Investigation Trail Leading to This Message

The assistant's path to message &lt;msg id=80&gt; is a textbook example of systematic source code archaeology. Let me trace the key steps:

  1. Understanding the prover dispatch (messages 50-55): The assistant first established that bellperson has two prover implementations — native and supraseal — selected at compile time via the cuda-supraseal feature flag. This confirmed that PoSt proofs could use supraseal if the feature is enabled, but the feature propagation chain needed verification.
  2. Tracing feature propagation (messages 62-69): By examining Cargo.toml files across the dependency chain — filecoin-proofs-api, filecoin-proofs, storage-proofs-post, storage-proofs-update — the assistant discovered a critical asymmetry: the cuda-supraseal feature is not propagated to storage-proofs-post or storage-proofs-update. Only storage-proofs-porep gets the cuda-supraseal feature. This means WindowPoSt and WinningPoSt proofs cannot use the supraseal C++/CUDA prover, even when the feature is enabled for PoRep. They fall back to the native prover, which uses CPU-based multiexponentiation and FFT via ec-gpu-gen's CPU threadpool.
  3. Hunting for constraint counts (messages 70-79): The assistant then searched through storage-proofs-post and filecoin-proofs source code looking for circuit size indicators — challenge_count, sector_count, constraint, partition — progressively narrowing from the API layer through the registry to the constants file. By message 79, the assistant had traced through registry.rs to find that sector_count() and challenge_count are populated from constants, but the actual values remained elusive. The registry code showed references to constants::WINNING_POST_CHALLENGE_COUNT and constants::WINDOW_POST_CHALLENGE_COUNT, but the constants file hadn't been read yet.

The Discovery: What Message 80 Actually Reveals

The grep output in message 80 delivers four pieces of information, each with distinct significance:

WinningPoSt: 66 Challenges, 1 Sector

WINNING_POST_CHALLENGE_COUNT = 66 and WINNING_POST_SECTOR_COUNT = 1 define the Winning Proof-of-Spacetime parameters. WinningPoSt is the proof a storage miner must submit when they win the right to mine a block — it proves they still have the sector at the time of winning. The circuit must verify 66 Merkle inclusion proofs across a single sector. With 66 challenges and one sector, the circuit is relatively modest in size compared to PoRep, but it must be generated under tight time constraints (a Filecoin epoch is 30 seconds, and the proof must be included in a block within that window).

WindowPoSt: 10 Challenges, Dynamic Sector Count

WINDOW_POST_CHALLENGE_COUNT = 10 defines the number of Merkle challenges per sector for Window Proof-of-Spacetime. WindowPoSt is the periodic proof every miner must submit for each partition of their stored sectors over a 24-hour window. The critical detail here is that WINDOW_POST_SECTOR_COUNT is not a compile-time constant — it is declared as pub static ref WINDOW_POST_SECTOR_COUNT: RwLock&lt;HashMap&lt;u64, usize&gt;&gt;, a runtime, mutable, per-sector-size mapping protected by a read-write lock. This means the number of sectors checked in a WindowPoSt proof varies dynamically based on the partition configuration, and it can be updated at runtime without recompilation.

This distinction is architecturally significant: WinningPoSt has a fixed, predictable circuit size (66 challenges, 1 sector), while WindowPoSt's circuit size depends on the partition's sector count, which is configured at runtime. A scheduler designed for cuzk must handle both fixed-size and variable-size proof jobs.

Assumptions Made and Their Validity

The assistant makes several implicit assumptions in this message:

Assumption 1: These constants are the definitive values used in proof generation. This is well-supported — the constants are defined in filecoin-proofs/src/constants.rs, which is the canonical location for such parameters in the Filecoin proof system. The registry code in filecoin-proofs-api references these exact constants by name.

Assumption 2: The challenge count directly corresponds to circuit size. This is generally correct but requires nuance. The challenge count determines the number of Merkle inclusion proofs the circuit must verify, which directly affects the number of constraints. However, the total circuit size also depends on other factors: the Merkle tree depth (determined by sector size), the hashing algorithm (Poseidon vs. SHA-256), and the arity of the tree. The challenge count is a multiplier on the per-challenge circuit size, not the total circuit size itself.

Assumption 3: The WINDOW_POST_SECTOR_COUNT RwLock pattern is relevant for understanding circuit size variability. This is correct and important — it reveals that WindowPoSt circuit sizes are not fixed at compile time, which has implications for memory budgeting and scheduling.

Potential Mistakes and Nuances

The most notable nuance is the asymmetry between WINNING_POST_SECTOR_COUNT (a simple pub const usize = 1) and WINDOW_POST_SECTOR_COUNT (a RwLock&lt;HashMap&lt;u64, usize&gt;&gt;). The assistant does not comment on this difference in the message itself, but the subsequent message (82) immediately pivots to investigating SnapDeals circuit properties, suggesting the assistant recognized the need for further exploration.

Another subtle point: the grep pattern includes WINDOW_POST_SECTOR_COUNT which matches on line 102, but the output is truncated by head -20. The full constant definition — what the default sector count values are for each sector size — is not visible in this message. The assistant would need to read more of the constants file to get the complete picture.

Additionally, these constants define the number of challenges and number of sectors, but they do not directly give the constraint count or FFT domain size of the circuit. The assistant's next steps (message 82 onward) show an awareness of this gap, as the investigation pivots to looking at storage-proofs-update for SnapDeals circuit internals.

Input Knowledge Required

To fully understand this message, one needs:

  1. Filecoin proof type taxonomy: Knowledge that there are three main proof types — PoRep (Proof-of-Replication for sealing), WinningPoSt (for block-winning), and WindowPoSt (for ongoing storage verification) — plus SnapDeals (update proofs for empty sectors).
  2. The bellperson prover architecture: Understanding that bellperson has two prover backends — native (CPU-based multiexp/FFT via ec-gpu-gen) and supraseal (C++/CUDA GPU kernels) — selected by compile-time feature flags.
  3. Feature propagation chains: The cuda-supraseal feature must be explicitly propagated through each crate's Cargo.toml. The assistant had just discovered that storage-proofs-post and storage-proofs-update do not propagate this feature, meaning PoSt proofs always use the native CPU prover.
  4. The cuzk project context: This investigation feeds directly into designing a pipelined SNARK proving daemon that must handle heterogeneous proof types with different resource profiles.

Output Knowledge Created

This message produces several concrete outputs:

  1. WinningPoSt parameters: 66 challenges, 1 sector. This means a WinningPoSt proof verifies 66 Merkle inclusion proofs for a single sector. The circuit is relatively small and fixed-size.
  2. WindowPoSt challenge count: 10 challenges per sector. The sector count is dynamic, stored in a runtime RwLock&lt;HashMap&lt;u64, usize&gt;&gt; keyed by sector size.
  3. Confirmation of asymmetry: WinningPoSt has a fixed sector count (1), while WindowPoSt's sector count varies. This has implications for memory allocation and scheduling in cuzk.
  4. A concrete anchor for memory estimation: With 10 challenges per sector for WindowPoSt, and knowing the Merkle tree depth for a given sector size (e.g., 32 GiB), one can estimate the number of constraints and thus the FFT domain size and memory footprint.
  5. Evidence for the cuzk scheduler design: The scheduler must handle both fixed-size jobs (WinningPoSt) and variable-size jobs (WindowPoSt), which affects batching strategies and GPU memory partitioning.

The Thinking Process Visible in the Message

The message itself is terse — a single bash command with its output — but the thinking process is visible in the choice of command. The assistant did not search for "circuit size" or "constraint count" broadly; instead, it targeted the specific constant names that had been revealed in the registry code (message 78 showed constants::WINNING_POST_CHALLENGE_COUNT and constants::WINDOW_POST_CHALLENGE_COUNT). This demonstrates a methodical, top-down approach:

  1. Start at the API layer (filecoin-proofs-api/src/registry.rs) to find how proof configs are constructed.
  2. Identify the constant references used in construction.
  3. Drill into the constants file to extract the actual values. The grep pattern is carefully crafted to capture all four relevant constants in a single pass, using alternation (\|) to match any of the four names. The head -20 limiter suggests the assistant expects the results to be compact — a reasonable assumption for a constants file where these definitions should appear near the top. The fact that the assistant runs this as a bash command rather than reading the file directly with cat or sed is also telling: it indicates a preference for targeted extraction over full-file reading, a strategy that becomes necessary when navigating large, unfamiliar codebases. The assistant is building a mental map of the codebase by querying specific landmarks rather than reading linearly.

Broader Significance

This message sits at the intersection of two investigations: the backward-looking analysis of the existing proof pipeline's memory and performance characteristics, and the forward-looking design of the cuzk proving daemon. The constants discovered here are not just numbers — they are the parameters that define the resource requirements for two of the three major proof types in Filecoin. Without them, the cuzk scheduler would be designing blind.

The discovery that WindowPoSt's sector count is a runtime parameter (RwLock&lt;HashMap&lt;u64, usize&gt;&gt;) is particularly valuable. It means that cuzk cannot simply hardcode WindowPoSt circuit sizes; it must query the current configuration or accept it as part of the proof request. This has direct implications for the gRPC API design — the Prove RPC must include the sector count or the scheduler must have access to the current WindowPoSt configuration.

In the broader narrative of the coding session, message 80 is the moment when the investigation shifts from "how does the system work?" to "what are the concrete numbers we need to build something new?" It is the bridge between analysis and synthesis, between understanding the existing system and designing its replacement.