The Silence of the Parameters: Discovering What's Missing in Filecoin's Proof Pipeline
The Message
# From message 33 in the conversation
python3 -c "
import json
with open('/home/theuser/.opt/go/pkg/mod/github.com/filecoin-project/lotus@v1.34.4-rc1/build/proof-params/parameters.json') as f:
params = json.load(f)
# Print ALL param files for any size
for name, info in sorted(params.items()):
if name.endswith('.params'):
ss = info.get('sector_size', 0)
kind = 'unknown'
if 'window' in name:
kind = 'WindowPoSt'
elif 'winning' in name:
kind = 'WinningPoSt'
elif 'empty-sector-update' in name:
kind = 'SnapDeals'
elif 'stacked' in name:
kind = 'PoRep'
if kind in ['WindowPoSt', 'WinningPoSt', 'SnapDeals', 'PoRep']:
print(f'{kind} ss={ss}: {name[:80]}...')
"
SnapDeals ss=536870912: v28-empty-sector-update-merkletree-poseidon_hasher-8-0-0-61fa69f38b9cc771ba27b67...
SnapDeals ss=8388608: v28-empty-sector-update-merkletree-poseidon_hasher-8-0-0-92180959e1918d26350b8e6...
SnapDeals ss=2048: v28-empty-sector-update-merkletree-poseidon_hasher-8-0-0-fb9e095bebdd77511c0269b...
SnapDeals ss=34359738368: v28-empty-sector-update-merkletree-poseidon_hasher-8-8-0-3b7f44a9362e39853694549...
SnapDeals ss=68719476736: v28-empty-sector-update-merkletree-poseidon_has...
Introduction
At first glance, message 33 appears to be a routine data-gathering step in a larger investigation: a Python script that parses a JSON file and prints categorized parameter file names. But this message is anything but routine. It is the moment when a critical assumption collapses, when the investigation pivots from "what are the circuit sizes?" to "why are there no circuits at all?" The message's true significance lies not in what it prints, but in what it fails to print — the complete absence of WindowPoSt and WinningPoSt Groth16 parameter files from the Filecoin proof parameters registry. This discovery reshapes the entire trajectory of the exploration and reveals a fundamental architectural boundary in the Filecoin proof system.
Context: The Investigation So Far
To understand why this message was written, we must trace the investigation that led to it. The broader session is a deep-dive into the SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin's Proof-of-Replication (PoRep) mechanism. The analyst has been mapping the full call chain from Curio's Go task layer, through Rust FFI, into C++ and CUDA kernels, accounting for the notorious ~200 GiB peak memory footprint. The work has already produced a comprehensive background reference document, identified nine structural bottlenecks, and proposed three optimization strategies.
The subagent task that spawned this particular line of inquiry was: "Explore SnapDeals/PoSt circuit sizes." The goal was to understand the computational scale of different proof types — WindowPoSt, WinningPoSt, SnapDeals — by examining their Groth16 circuit constraint counts and parameter file sizes. This information is essential for designing the pipelined SNARK proving daemon (cuzk) architecture that is the ultimate deliverable of the root session.
In the messages leading up to message 33, the analyst has been methodically working through the codebase. They examined how Curio's proof tasks are configured ([msg 15]), traced the GPU selector layer in ffiselect ([msg 16]), looked at SnapDeals proving in task_prove.go ([msg 19]), and located the parameters.json file in the Lotus Go module cache (<msg id=28-29>). The first queries against this JSON file (<msg id=30-31>) began filtering for WindowPoSt, WinningPoSt, and SnapDeals entries at the standard sector sizes of 32 GiB and 64 GiB. Message 32 then ran a more targeted query that printed only these proof types at these sizes — and the output was startling: only SnapDeals entries appeared. No WindowPoSt or WinningPoSt .params files existed for 32 GiB or 64 GiB sectors.
This was the first hint of something anomalous, but it was still possible that the filtering was too narrow. Perhaps the parameters existed at different sector sizes, or the naming convention was unexpected. Message 33 was written to settle this question definitively.
What the Message Actually Does
The Python script in message 33 performs an exhaustive, unfiltered scan of the parameters.json file. It iterates over every entry, selects only those ending with .params (the actual Groth16 proving parameter files, as opposed to verification keys or other metadata), classifies each by its naming pattern, and prints the proof type, sector size in bytes, and the first 80 characters of the filename. The classification logic is straightforward: filenames containing "window" are WindowPoSt, "winning" are WinningPoSt, "empty-sector-update" are SnapDeals, and "stacked" are PoRep. The script imposes no size filter — it prints every entry regardless of sector size.
The output is unambiguous. Every single .params file in the entire registry belongs to the SnapDeals (empty-sector-update) category. There are exactly five entries, with sector sizes of 512 MiB, 8 MiB, 2 KiB, 32 GiB, and 64 GiB. The naming pattern reveals additional structure: the hasher is always poseidon_hasher, the version is v28, and the numeric components (e.g., 8-0-0, 8-8-0, 8-8-2) likely encode circuit parameters such as the number of Merkle tree layers or the arity of the hasher.
The absence of WindowPoSt, WinningPoSt, and PoRep entries is absolute. There are zero parameter files for these proof types.
The Reasoning and Motivation
Why was this message written? The immediate trigger was the puzzling output of message 32, which filtered for 32 GiB and 64 GiB and found only SnapDeals. The analyst needed to rule out the possibility that WindowPoSt or WinningPoSt parameters existed at other sector sizes — perhaps the 512 MiB or 8 MiB entries that had appeared in the unfiltered grep of message 30. By removing the size filter entirely, message 33 eliminates this confound. If WindowPoSt or WinningPoSt parameters exist anywhere in the registry, they will appear.
But the deeper motivation is architectural understanding. The analyst is not merely collecting data; they are building a mental model of how Filecoin's proof system is structured. The Groth16 parameter files are the "circuit blueprints" — they encode the constraint system that the prover must evaluate. If a proof type has no parameter file, it cannot be using the same Groth16 proving pipeline. This has profound implications for the cuzk architecture being designed. If WindowPoSt and WinningPoSt don't use Groth16 parameters, they must use a different proving mechanism — perhaps the "vanilla proof" approach glimpsed in earlier code searches ([msg 12]), where proofs are generated per-partition without the full Groth16 ceremony. This would mean these proof types have fundamentally different resource requirements, memory footprints, and optimization opportunities.
Assumptions and Their Collapse
The investigation up to this point operated under several implicit assumptions:
- All proof types use Groth16 parameters. This is the natural assumption given that PoRep (the most memory-intensive proof) uses them, and the SUPRASEAL_C2 pipeline is built around Groth16 proving. The analyst had been searching for "constraint counts," "circuit sizes," and "groth_params" ([msg 14]) under the assumption that these concepts applied uniformly.
- The parameters.json file is the authoritative source. This assumption proved correct — the file is indeed the central registry. But the assumption that it would contain entries for all proof types was wrong.
- WindowPoSt and WinningPoSt have circuit sizes worth measuring. The subagent task was specifically to "Explore SnapDeals/PoSt circuit sizes," implying that these proof types had circuits whose sizes could be measured and compared. The discovery that they have no Groth16 parameters at all renders this framing partially moot — at least for the Groth16 pipeline. The collapse of these assumptions is not a failure; it is a discovery. The analyst now knows something they did not know before: the Filecoin proof system is not monolithic. Different proof types use different proving technologies. PoRep and SnapDeals use Groth16 with full parameter files; WindowPoSt and WinningPoSt use something else.
Mistakes and Incorrect Assumptions
While the message itself is correct, the framing reveals a subtle error in the investigation's premise. The classification logic in the script assumes that "stacked" in the filename indicates PoRep. But the output shows no "stacked" entries at all — not even for the PoRep parameters that are known to exist from earlier analysis. This is because the parameters.json file being examined is from the Lotus v1.34.4-rc1 build, which may not include PoRep parameters in this particular registry, or PoRep parameters may be fetched from a different source (the SRS — Structured Reference String — which is loaded separately). The earlier analysis of the SUPRASEAL_C2 pipeline had already established that PoRep uses SRS parameters, not the .params files in this JSON. The analyst's classification logic, while reasonable, was too narrow — it assumed a naming convention that didn't match reality.
A more subtle issue is the assumption that the absence of .params files means the absence of Groth16 proving. In theory, WindowPoSt and WinningPoSt could use Groth16 with parameters embedded in the binary, generated on-the-fly, or fetched from a different URL. But the architecture of bellperson and the Filecoin proof system makes this unlikely — the parameter files are large (hundreds of megabytes to gigabytes) and are always fetched and cached as files.
Input Knowledge Required
To fully understand this message, the reader needs:
- Knowledge of Filecoin proof types: WindowPoSt (proof of spacetime submitted periodically for each window), WinningPoSt (proof submitted when a miner wins a block), SnapDeals (sector update proofs), and PoRep (proof of replication for initial sealing). Each serves a different function and has different latency and throughput requirements.
- Understanding of Groth16: The proving system used by Filecoin, which requires a "proving key" (the parameter file) that encodes the circuit's constraint system. These files are large and must be loaded into GPU memory before proving can begin.
- Familiarity with the Lotus codebase structure: Specifically that
build/proof-params/parameters.jsonis the central manifest of all Groth16 parameter files, keyed by a content-hash-based filename scheme. - Knowledge of the Curio/ffiselect architecture: The GPU selector layer that dispatches proof computations to either local execution (ffidirect) or remote GPU workers, and how this interacts with the underlying Rust/C++ proving code.
- Context from the broader investigation: The ~200 GiB memory bottleneck in PoRep, the nine structural bottlenecks identified, and the three optimization proposals (Sequential Partition Synthesis, Persistent Prover Daemon, Cross-Sector Batching).
Output Knowledge Created
This message creates several pieces of actionable knowledge:
- Definitive proof that WindowPoSt and WinningPoSt do not use Groth16 parameter files. This is the primary output. It means these proof types bypass the entire SUPRASEAL_C2 pipeline and its associated memory overhead.
- A complete inventory of SnapDeals parameter files. The five files span sector sizes from 2 KiB (likely a test/minimal circuit) to 64 GiB (full production). The 512 MiB and 8 MiB entries are intriguing — they may correspond to different Merkle tree configurations or proof variants.
- Evidence of a two-tier proving architecture. One tier (PoRep, SnapDeals) uses full Groth16 with parameter files; the other tier (WindowPoSt, WinningPoSt) uses a different mechanism. This has immediate implications for the cuzk daemon design — it means the daemon can focus on PoRep and SnapDeals without needing to handle WindowPoSt/WinningPoSt through the same pipeline.
- A methodological template. The Python script itself is a reusable tool for inspecting the parameters registry. The analyst will likely extend it to extract file sizes, checksums, and download URLs.
The Thinking Process Revealed
The reasoning visible in this message is a model of systematic investigation. The analyst follows the scientific method: observe a phenomenon (message 32's puzzling output), form a hypothesis (perhaps the parameters exist at other sizes), design an experiment (remove the size filter), and interpret the results. The script is carefully constructed to be exhaustive — it iterates over all entries, applies a conservative classification, and prints everything. The truncation of filenames to 80 characters is a deliberate choice to keep the output readable while preserving enough information to identify each file.
The progression from message 30 to message 34 shows a tightening spiral of inquiry. Message 30 uses a simple grep for "window|winning|sector-update" and gets only sector-update hits. Message 31 tries a more structured Python query but still filters by sector size. Message 32 narrows to 32 GiB and 64 GiB and gets only SnapDeals. Message 33 removes all filters and confirms the pattern. Message 34 (the immediate successor) then takes the final step: listing ALL .params files without any classification, just to be absolutely sure nothing was missed. This layered approach — each iteration removing one more degree of freedom — is characteristic of rigorous debugging.
The analyst also demonstrates a healthy skepticism of their own tools. The classification logic in message 33 includes a fallthrough kind = 'unknown' for entries that don't match any known pattern, ensuring that unexpected entries won't be silently dropped. The final if kind in [...] guard means only known proof types are printed, but the unknown entries are still present in the data structure — they could be inspected separately if needed.
Implications for the cuzk Architecture
The discovery in message 33 has direct consequences for the pipelined SNARK proving daemon being designed in the root session. The cuzk architecture, as outlined in the cuzk-project.md document, was being designed to handle all proof types through a unified pipeline. The finding that WindowPoSt and WinningPoSt don't use Groth16 parameters means they either:
- Use a different proving system entirely (perhaps the "vanilla proof" mechanism glimpsed in
GenerateSinglePartitionWindowPoStWithVanilla), which would have different resource profiles and optimization opportunities. - Use Groth16 but generate parameters dynamically, which would have different memory characteristics.
- Are not actually proven at the GPU level at all, which would mean they don't benefit from the cuzk daemon's GPU management. Each possibility changes the design of the daemon. If WindowPoSt and WinningPoSt are CPU-only, the daemon can reserve all GPU resources for PoRep and SnapDeals. If they use a different GPU pipeline, the daemon needs a separate scheduler for them. The investigation must now pivot to understanding what proving mechanism these proof types actually use.
Conclusion
Message 33 is a turning point. It is the message where the investigation's framing shifts from "how big are the circuits?" to "where are the circuits?" The answer — "nowhere, for most proof types" — is a negative result that is more valuable than a positive one. It reveals the hidden architecture of the Filecoin proof system: a bifurcation between Groth16-heavy proofs (PoRep, SnapDeals) and something lighter (WindowPoSt, WinningPoSt). For the cuzk daemon design, this means the optimization problem is both simpler (fewer proof types need the heavy pipeline) and more complex (the daemon must handle heterogeneous proving mechanisms). The silence of the parameters file speaks volumes.