The Constants That Define a Proof System: Uncovering PoSt Circuit Sizes in Filecoin's Groth16 Pipeline
Introduction
In the midst of an exhaustive investigation into Filecoin's SUPRASEAL_C2 Groth16 proof generation pipeline, a single message stands out as a moment of empirical grounding. Message <msg id=81> is deceptively simple: it contains the output of a sed command that extracts a handful of constant definitions from filecoin-proofs-18.1.0/src/constants.rs. Yet within those few lines lies the answer to a question that had been building across dozens of prior messages: just how large are the circuits for WinningPoSt and WindowPoSt? The numbers—66 challenges for WinningPoSt, 10 for WindowPoSt, and 1 sector for WinningPoSt—are the bedrock upon which all subsequent memory budgeting, throughput projections, and architectural decisions for the proposed cuzk proving daemon would rest.
Context: The Investigation Leading to This Message
To understand why message <msg id=81> was written, one must appreciate the trajectory of the session that produced it. The root session was a deep-dive investigation into the SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin's Proof-of-Replication (PoRep). The investigation had already produced four documents, including a background reference identifying nine structural bottlenecks and three optimization proposals. The overarching goal was to shift from optimizing individual proof generation toward architecting a continuous, memory-efficient proving pipeline optimized for heterogeneous cloud rental markets.
Within segment 3 of this root session, the assistant had been tasked with designing a pipelined SNARK proving daemon called cuzk. This required understanding every proof type the system would need to handle: not just PoRep (which had been the focus of earlier optimization proposals), but also SnapDeals (empty sector updates), WinningPoSt, and WindowPoSt. Each proof type has different circuit sizes, different SRS (Structured Reference String) parameter requirements, and different resource profiles. Without knowing these circuit sizes, any architecture for a multi-type proving daemon would be built on guesswork.
The immediate predecessor messages (starting around <msg id=70>) show the assistant systematically hunting for these numbers. It searched through storage-proofs-post, storage-proofs-update, filecoin-proofs-api, and filecoin-proofs source code, tracing the feature flag propagation from filecoin-proofs-api down through filecoin-proofs, storage-proofs-core, storage-proofs-post, storage-proofs-update, and ultimately bellperson. It examined how the cuda-supraseal feature flag controls which prover implementation is used. It looked at the sector_count() and challenge_count() methods in registry.rs. And in message <msg id=80>, it ran a grep that revealed the existence of WINNING_POST_CHALLENGE_COUNT, WINNING_POST_SECTOR_COUNT, and WINDOW_POST_CHALLENGE_COUNT constants—but only their line numbers, not their values.
Message <msg id=81> is the direct follow-up: a sed command to print the actual constant definitions from lines 29–120 of constants.rs. This is the moment the numbers are finally revealed.
The Message Itself
The message quotes the following output:
pub const WINNING_POST_CHALLENGE_COUNT: usize = 66;
pub const WINNING_POST_SECTOR_COUNT: usize = 1;
pub const WINDOW_POST_CHALLENGE_COUNT: usize = 10;
pub const MAX_LEGACY_REGISTERED_SEAL_PROOF_ID: u64 = MAX_LEGACY_POREP_REGISTERED_PROOF_ID;
/// Constant NI-PoRep aggregation bounds specified in FIP-0090, but
/// superseded by FIP-0092
pub const FIP92_MIN_NI_POREP_AGGREGATION_PROOFS: usize = 1;
pub const FIP92_MAX_NI_POREP_AGGREGATION_PROOFS: usize = 65;
/// Sector sizes for which parameters ...
The output is truncated—the sed command requested lines 29–120, but the output shown ends at line ~37, suggesting the command was either interrupted or the output was clipped for readability. The comment about "Sector sizes for which parameters" hints at further constants that would map sector sizes to parameter file identifiers, but those remain unseen in this message.
Why These Numbers Matter
The challenge counts are not arbitrary. They directly determine the size of the circuit that must be synthesized and proved. In Groth16 proof generation, the circuit size (number of constraints) is proportional to the number of challenges multiplied by the number of sectors, times the number of Merkle proof layers required per challenge. For WinningPoSt, with 66 challenges and 1 sector, the circuit is relatively modest. For WindowPoSt, with only 10 challenges but a variable sector count (determined dynamically via WINDOW_POST_SECTOR_COUNT stored in a RwLock<HashMap<u64, usize>>), the circuit size depends on how many sectors are being proven in a single batch.
These constants also have implications for memory usage. Each challenge in a PoSt proof requires generating Merkle inclusion proofs, which in turn require hashing operations and field element operations in the constraint system. The assistant had already established in earlier work that the SUPRASEAL_C2 pipeline's peak memory footprint of ~200 GiB was driven primarily by the need to hold all partition proofs simultaneously during synthesis. Understanding the challenge counts for PoSt proofs was essential to determining whether similar memory blowups would occur for these proof types, and whether the proposed Sequential Partition Synthesis optimization (streaming partitions sequentially to reduce peak memory) would be applicable.
Input Knowledge Required
To interpret this message, a reader needs substantial context about Filecoin's proof architecture. First, one must understand the distinction between WinningPoSt (a lightweight proof submitted by a miner who wins the right to mine a block, requiring proof of storage for a single sector with 66 challenges) and WindowPoSt (a periodic proof submitted daily for all sectors a miner has committed, with 10 challenges per sector). Second, one must know that these proofs use the Groth16 zk-SNARK protocol, where circuit size directly translates to computation time and memory pressure. Third, familiarity with the Rust crate structure—filecoin-proofs as the top-level proof library, storage-proofs-post for PoSt circuit definitions, and bellperson for the underlying Groth16 implementation—is necessary to understand where these constants fit in the codebase.
Additionally, the reader benefits from knowing the prior investigation's findings about the cuda-supraseal feature flag and how it switches between the native CPU/GPU prover and the C++/CUDA SUPRASEAL prover. The assistant had discovered in earlier messages (around <msg id=65>–<msg id=69>) that cuda-supraseal is a distinct feature from cuda—it enables a completely different prover path that bypasses bellperson's native GPU kernels entirely. The PoSt circuit constants are relevant to both paths, but their implications for memory and scheduling differ depending on which prover is used.
Output Knowledge Created
This message produces several concrete pieces of knowledge:
- WinningPoSt uses exactly 66 challenges and 1 sector. This is a fixed, compile-time constant. It means every WinningPoSt proof involves proving knowledge of 66 Merkle inclusion paths into a single sector's data. The circuit size is therefore deterministic and independent of sector size (except through the Merkle tree depth, which varies with sector size).
- WindowPoSt uses exactly 10 challenges per sector. The sector count, however, is dynamic—determined at runtime and stored in a global
RwLock<HashMap<u64, usize>>. This means WindowPoSt circuit size varies: proving 1 sector requires 10 challenges, proving 100 sectors requires 1,000 challenges, and so on. The dynamic sector count has profound implications for memory management in a proving daemon, as the circuit can grow unpredictably. - NI-PoRep aggregation bounds are defined by FIP-0092. The constants
FIP92_MIN_NI_POREP_AGGREGATION_PROOFS = 1andFIP92_MAX_NI_POREP_AGGREGATION_PROOFS = 65specify the range of proofs that can be aggregated in a single Non-Interactive Proof-of-Replication batch. This is relevant for understanding batching opportunities in the proposedcuzkdaemon. - The legacy seal proof ID ceiling (
MAX_LEGACY_REGISTERED_SEAL_PROOF_ID) is defined, though its value is not shown in the truncated output.
Assumptions and Potential Pitfalls
The assistant makes several implicit assumptions in this message. The primary assumption is that these constants are accurate and up-to-date for the version of the code being analyzed (v18.1.0). Given that the investigation is targeting a production system (Curio/Filecoin), this is a reasonable assumption—the constants are unlikely to change between minor versions without a formal FIP (Filecoin Improvement Proposal). However, the assistant does not verify that these constants match the actual on-chain proof verification parameters, nor does it cross-reference them against the Lotus implementation or the Filecoin specification. A subtle mismatch between the Rust code constants and the actual protocol parameters could lead to incorrect circuit size estimates.
Another assumption is that the challenge count is the primary driver of circuit size. While it is certainly a major factor, the circuit also includes constraints for Merkle tree hashing (which depends on sector size and tree arity), public input validation, and the proof-of-possession checks. The assistant does not yet have the full constraint counts—those would come in subsequent messages as it searches for num_constraints and circuit synthesis code.
A potential mistake is the truncation of the output. The sed command requests lines 29–120, but the output ends abruptly after line ~37. This could mean the assistant missed important constants defined later in the file, such as WINDOW_POST_SECTOR_COUNT (which is defined at line 102 as a RwLock<HashMap<u64, usize>>), or the sector-size-to-parameter mappings. The assistant does not follow up to get the full file contents, instead moving on to investigate SnapDeals circuit properties in message <msg id=82>. This is a minor oversight—the full picture of PoSt circuit sizing requires knowing both the challenge count and the sector count, and the sector count for WindowPoSt is notably absent from the extracted output.
The Thinking Process Visible in the Message
The message reveals a methodical, evidence-driven approach. The assistant does not speculate about circuit sizes or rely on documentation; it goes directly to the source code to extract the exact values. The choice of sed with line numbers (29–120) shows precise knowledge of where the constants are defined, gained from the preceding grep in message <msg id=80>. The assistant is building a mental model of the proof system piece by piece, starting with the high-level feature flags, then the prover selection logic, then the API layer, and finally the raw constants that define circuit complexity.
The truncation of the output is itself revealing. It suggests the assistant is reading the output in a terminal or pager that clips long outputs, or that the command produced more text than expected and the assistant chose to show only the most relevant portion. The decision to stop at the "Sector sizes for which parameters" comment indicates that the assistant considers the challenge count constants to be the critical finding and is ready to move on to the next piece of the puzzle—SnapDeals circuit sizes.
Broader Significance
In the context of the overall investigation, message <msg id=81> is a linchpin. The cuzk proving daemon architecture being designed in segment 3 requires accurate resource budgeting for each proof type. Without knowing that WinningPoSt uses 66 challenges and WindowPoSt uses 10, the scheduler cannot estimate GPU time per proof, the SRS memory manager cannot predict parameter residency requirements, and the batching logic cannot determine optimal aggregation sizes. The constants extracted here directly inform the throughput projections in the cuzk-project.md document: a WinningPoSt proof is approximately 6.6× more computationally intensive per-sector than a WindowPoSt proof (66 vs. 10 challenges), but WindowPoSt can involve many sectors, making it potentially the dominant workload.
Furthermore, these constants validate a key design decision in the proposed Sequential Partition Synthesis optimization. Since PoSt proofs have relatively few challenges compared to PoRep (which can have hundreds of partitions), the memory pressure from PoSt circuits is likely to be lower. This means the proving daemon can prioritize PoSt jobs for quick turnaround while batching PoRep jobs for throughput—a scheduling policy that emerges directly from understanding these numbers.
Conclusion
Message <msg id=81> is a small but critical step in a much larger journey. It exemplifies the investigative methodology that characterizes the entire session: trace the code, find the constants, verify the numbers, and build upward from empirical fact. The constants extracted here—66 challenges for WinningPoSt, 10 for WindowPoSt, 1 sector for WinningPoSt—are not merely trivia; they are the fundamental parameters that define the computational landscape for Filecoin's proof-of-spacetime proofs. Every optimization proposal, every memory budget, every scheduling decision in the cuzk architecture ultimately traces back to numbers like these. In the architecture of a proving system, constants are not just constants—they are the atoms from which the entire system is built.