Peeling Back the Layers: The Supraseal Prover Path in Bellperson
Message Overview
The message under analysis is a single command invocation and its output, executed by the assistant at index 52 in a deep-dive investigation of the Filecoin SUPRASEAL_C2 proof generation pipeline. The message reads:
[assistant] Now let me see the supraseal prover path:
[bash] head -80 /home/theuser/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bellperson-0.26.0/src/groth16/prover/supraseal.rs 2>&1
//! Prover implementation implemented using SupraSeal (C++).
use std::{sync::Arc, time::Instant};
use bellpepper_core::{Circuit, ConstraintSystem, Index, SynthesisError, Variable};
use ff::{Field, PrimeField};
use log::info;
use pairing::MultiMillerLoop;
use rayon::iter::{IntoParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
use super::{ParameterSource, Proof, ProvingAssignment};
use crate::{gpu::GpuName, BELLMAN_VERSION};
#[allow(clippy::type_complexity)]
pub(super) fn create...
At first glance, this appears to be a routine code-reading operation. But in the context of the broader investigation — a comprehensive mapping of the ~200 GiB peak memory Groth16 proof generation pipeline for Filecoin's Proof-of-Replication (PoRep) — this message represents a critical inflection point. It is the moment the investigation transitions from discovering the existence of the supraseal dispatch mechanism to reading its actual implementation.
Context and Motivation: Why This Message Was Written
To understand why the assistant issued this command, we must reconstruct the investigative chain that led to it. The preceding messages (29–51) form a deliberate, methodical descent through layers of abstraction.
The investigation began with a high-level question about SnapDeals and PoSt (Proof-of-Spacetime) circuit sizes. The assistant first queried the Lotus build parameters (parameters.json) to enumerate all proof parameter files ([msg 29] through [msg 35]). This revealed a surprising fact: there were no separate .params files for WindowPoSt or WinningPoSt — only for SnapDeals (empty-sector-update) and PoRep (stacked-proof). The assistant then checked actual file sizes on disk ([msg 36]) and found that the large .params files for 32 GiB and 64 GiB sectors had not been downloaded, suggesting they are fetched on demand.
The investigation then pivoted to resource requirements. The assistant grepped for TypeDetails, ResourceTable, MaxMemory, Ram, Gpu, and GPU across the Curio task definitions ([msg 37]). This revealed the memory budgets Curio assigns to each proof type: 25 GiB for WindowPoSt (WdPostTask), 50 GiB for SnapDeals (ProveTask), and 1 GiB for WinningPoSt. These numbers are marked with comments like "todo correct value," indicating they are placeholders — a critical detail for anyone analyzing memory pressure.
But the most important thread began at [msg 39], when the assistant asked: "Now let me look at how bellperson decides between supraseal-c2 and standard GPU proving. This is critical." This question — about the dispatch mechanism — is the key that unlocks the entire pipeline architecture. The assistant then located the bellperson source code ([msg 40], [msg 41]), read the prover module structure ([msg 42]), and discovered the pivotal dispatch logic in <msg id=50> and <msg id=51>:
#[cfg(not(feature = "cuda-supraseal"))]
mod native;
#[cfg(feature = "cuda-supraseal")]
mod supraseal;
#[cfg(not(feature = "cuda-supraseal"))]
use self::native as prover;
#[cfg(feature = "cuda-supraseal")]
use self::supraseal as prover;
This is a compile-time feature gate. When the cuda-supraseal feature is enabled, bellperson completely replaces the native Rust prover with the supraseal C++ prover. The entire proof generation pipeline — synthesis, NTT, MSM, and final proof construction — is delegated to the supraseal-c2 library.
Message 52 is the direct consequence of this discovery. Having found the dispatch gate, the assistant's next logical step is to read the supraseal prover implementation itself. The command head -80 is not arbitrary; it is a targeted read of the first 80 lines, which typically contain the module's doc comment, imports, and function signatures — enough to understand the module's structure and interface without drowning in implementation details.
The Thinking Process Visible in the Message
The assistant's reasoning is visible in the framing comment: "Now let me see the supraseal prover path." This is not a random exploration. It is a deliberate, goal-directed action driven by a specific hypothesis: that the supraseal prover is the actual implementation used in production for GPU-accelerated Groth16 proving, and that understanding its code is essential to mapping the full call chain from Curio to CUDA kernels.
The choice of head -80 is itself a reasoning artifact. The assistant could have read the entire file, but it chose a focused read of the beginning. This implies an expectation that the first 80 lines will contain the module's public interface — the create_proof_batch_priority_inner function signature and its type constraints. This is a pattern-matching heuristic: in Rust code, the top of a module typically contains imports, documentation, and the first few function declarations.
The output confirms this expectation. The file opens with a doc comment: //! Prover implementation implemented using SupraSeal (C++). This single line is enormously consequential. It tells the investigator that:
- The prover is not a Rust implementation — it delegates to C++ code.
- The C++ library is called "SupraSeal" (the actual crate name is
supraseal-c2). - This is a thin Rust wrapper around a foreign-language implementation. The imports reinforce this picture. The module imports
bellpepper_coretypes (Circuit, ConstraintSystem, etc.),ffandpairingfor field arithmetic and pairings,rayonfor parallel iteration, and crucially,crate::{gpu::GpuName, BELLMAN_VERSION}. The presence ofGpuNamesuggests that the supraseal prover interacts with GPU device enumeration, andBELLMAN_VERSIONhints at compatibility tracking. The function signature stub at the bottom —#[allow(clippy::type_complexity)] pub(super) fn create...— confirms that the module exposes acreate_proof_batch_priority_innerfunction (as seen in [msg 50]), matching the interface expected by the dispatch layer.
Input Knowledge Required
To fully understand this message, a reader needs several layers of context:
Filecoin Proof Architecture: The reader must understand that Filecoin uses Groth16 proofs for PoRep (Proof-of-Replication) and PoSt (Proof-of-Spacetime), and that these proofs are generated by bellperson, a Rust library that wraps bellpepper (a constraint system) and ec-gpu (GPU acceleration).
The Dispatch Mechanism: The reader must have seen [msg 50] and [msg 51], which reveal the compile-time feature gate between native and supraseal provers. Without this context, the supraseal.rs file appears as just another module; with it, it becomes the production path for GPU proving.
The Curio Task System: The reader should know that Curio is a task scheduler for Filecoin storage mining, and that each proof type (WindowPoSt, WinningPoSt, SnapDeals) has a task definition with resource budgets. The 25 GiB and 50 GiB RAM allocations seen in [msg 38] provide the memory context that makes the supraseal investigation urgent.
Cargo Feature Flags: The cuda-supraseal feature flag is a Cargo feature that conditionally compiles the supraseal prover. Understanding that this is a compile-time, not runtime, decision is critical — it means the choice of prover is baked into the binary at build time.
Output Knowledge Created
This message produces several distinct pieces of knowledge:
- Confirmation of the supraseal dispatch path: The assistant has now read the actual file that implements the supraseal prover, confirming that it exists and is structurally what the dispatch layer expects.
- Module structure and dependencies: The imports reveal the module's dependencies: bellpepper_core for circuit types, ff/pairing for field arithmetic, rayon for parallelism, and the bellperson-internal GpuName type.
- The C++ delegation boundary: The doc comment explicitly states "implemented using SupraSeal (C++)", marking the Rust/C++ FFI boundary. This is the seam where the investigation will later need to cross into C++ code.
- The function interface: The
pub(super) fn create...stub (truncated byhead -80) confirms the function name and visibility, allowing the investigator to search for its full signature and implementation. - A foundation for deeper investigation: With this file identified, the assistant can now read the full implementation, trace the FFI calls into supraseal-c2, and ultimately map the entire call chain down to CUDA kernels.
Assumptions and Potential Pitfalls
The assistant makes several assumptions that are worth examining:
Assumption that head -80 is sufficient: The assistant assumes that the first 80 lines contain the critical interface information. This is a reasonable heuristic but carries risk. If the file has a long license header or extensive documentation, the actual function signatures might begin after line 80. The output shows that line 80 cuts off mid-function-signature (pub(super) fn create...), which is both confirming (the function is there) and frustrating (the full signature is truncated).
Assumption of file accessibility: The assistant assumes it can read the file directly from the Cargo registry path. Earlier in the conversation ([msg 45]), the assistant attempted to copy files and was blocked by an external directory rule. The use of head -80 with 2>&1 (redirecting stderr to stdout) suggests the assistant is prepared for the command to fail and wants to capture any error message.
Assumption about the feature flag's meaning: The assistant treats cuda-supraseal as a simple on/off switch for the supraseal prover. While this is correct at the compilation level, it glosses over the possibility of runtime fallbacks. If the supraseal library fails to initialize (e.g., no GPU available), does bellperson fall back to the native prover? The dispatch code in [msg 51] shows a compile-time, not runtime, decision — suggesting no fallback exists. This is an important architectural property that the assistant has not yet verified.
Assumption about the prover's memory footprint: The assistant is investigating the ~200 GiB peak memory issue. By reading the supraseal prover path, the assistant implicitly assumes that the supraseal implementation is the primary contributor to this memory usage. This is a reasonable hypothesis, but it could be wrong — the memory pressure might come from the native prover's synthesis phase, the SRS (Structured Reference String) loading, or the GPU kernel allocations themselves.
Mistakes and Incorrect Assumptions
The most notable potential mistake is the truncation of the function signature. By stopping at line 80, the assistant sees only pub(super) fn create... without the full type signature. The full signature — which includes the generic parameters <E: MultiMillerLoop, C: Circuit<E>, P: ParameterSource<E>> and the argument types — is essential for understanding how the prover is invoked. The assistant would need to read more lines to get this information.
Another subtle issue is the use of 2>&1 (redirecting stderr to stdout). The command is head -80 ... 2>&1, which means any error messages will be mixed into the output. The fact that the output shows clean Rust code suggests the command succeeded, but the error-redirection idiom hints at the assistant's uncertainty about file permissions or path existence.
A more significant concern is the absence of version checking. The assistant is reading bellperson-0.26.0, but the Curio project may depend on a different version. If the dispatch mechanism changed between versions, the analysis could be stale. The assistant did not verify which version of bellperson Curio actually uses (e.g., by checking the go.sum or Cargo.lock equivalent).
The Broader Significance
This message is a textbook example of investigative coding: a targeted read of a specific file at a specific moment, driven by a clear hypothesis. The assistant is not browsing randomly; it is following a chain of reasoning:
- "I need to understand the proof generation pipeline."
- "The pipeline is implemented in bellperson."
- "Bellperson has a compile-time dispatch between native and supraseal provers."
- "I need to read the supraseal prover to understand the production path." Each step narrows the focus, and message 52 is the payoff — the moment of actually reading the production code path. The truncated function signature is a cliffhanger: the assistant has confirmed the file's existence and structure, but the full implementation details remain to be read. In the context of the overall investigation (documented in the analyzer summary), this message contributes to the "Background Reference" document by mapping the call chain from Curio's Go task layer through Rust FFI into C++/CUDA kernels. The supraseal prover is the critical bridge between bellperson's Rust API and the C++/CUDA implementation that does the actual GPU computation.
Conclusion
Message 52 is a small but pivotal step in a much larger investigation. It represents the moment the assistant transitions from knowing about the supraseal dispatch mechanism to reading its implementation. The command is simple — head -80 on a single file — but its motivation is deeply embedded in the investigative context: the discovery of the compile-time feature gate, the resource budgets from Curio tasks, and the overarching goal of mapping the ~200 GiB memory footprint. The output confirms the file's structure, reveals the C++ delegation boundary, and sets the stage for the next step: reading the full implementation and tracing the FFI calls into supraseal-c2.