The Feature Flag That Determines Which Proving Backend Runs Your Filecoin Proofs

Introduction

In the course of a deep-dive investigation into the SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin PoRep, a seemingly mundane command was issued — a grep across a Cargo.toml file to check feature flag definitions. Yet this single command, message 69 in the conversation, represents a pivotal moment of architectural discovery. It confirmed that the Supraseal C++ proving backend, despite being the primary focus of the investigation, is not used for all proof types in the Filecoin ecosystem. This article examines that message in detail: why it was written, what assumptions it tested, what knowledge it required, and what insights it produced.

The Message Itself

The message is a bash command executed by the assistant, followed by its output:

[assistant] [bash] grep -n "feature\|supraseal\|cuda\|opencl" /home/theuser/.cargo/registry/src/index.crates.io-6f17d22bba15001f/storage-proofs-update-18.1.0/Cargo.toml 2>&1 | head -20
36:features = [
40:default-features = false
44:default-features = false
63:features = [
79:features = ["derive"]
83:default-features = false
87:default-features = false
98:[features]
99:cuda = [
100:    "storage-proofs-core/cuda",
101:    "storage-proofs-porep/cuda",
102:    "filecoin-hashers/cuda",
103:    "neptune/cuda",
104:    "bellperson/cuda",
107:    "opencl",
116:opencl = [
117:    "storage-proofs-core/opencl",
118:    "storage-proofs-porep/opencl",
119:    "filecoin-hashers/opencl",
120...

At first glance, this is just a developer checking which Cargo features are defined in a Rust crate. But in the context of the broader investigation, this output carried enormous weight.

The Reasoning and Motivation: Why This Message Was Written

To understand why this grep was necessary, we must trace the investigation that led to it. The assistant had been systematically mapping the call chain from Curio's Go task layer, through Rust FFI, into bellperson's Groth16 prover, and ultimately down to C++/CUDA kernels. The central question was: which proving backend does each Filecoin proof type actually use?

Earlier in the conversation ([msg 50], [msg 51]), the assistant had discovered the critical dispatch mechanism in bellperson's groth16/prover/mod.rs:

#[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 switch: when cuda-supraseal is enabled, bellperson compiles in the Supraseal C++ prover; otherwise, it uses the native Rust prover (which itself can use GPU acceleration via cuda or opencl features).

The natural next question was: which crates in the dependency tree enable bellperson/cuda-supraseal? The assistant traced the feature propagation upward through the stack:

Assumptions Tested and Corrected

This message tested several implicit assumptions that had been building throughout the investigation:

Assumption 1: Supraseal is the default GPU proving backend for all Filecoin proof types. This was a natural assumption given that the investigation's central focus was the SUPRASEAL_C2 pipeline and its ~200 GiB memory footprint. The grep results disproved this: Supraseal is only reachable through storage-proofs-porep, not through storage-proofs-post or storage-proofs-update.

Assumption 2: The feature flag propagates uniformly. One might assume that enabling cuda-supraseal at the top level would cause all downstream crates to use Supraseal. But the feature definitions in filecoin-proofs show a selective propagation: PoRep gets cuda-supraseal, while PoSt and Update get only cuda. This is a deliberate design choice, likely because Supraseal was specifically optimized for the PoRep circuit structure.

Assumption 3: SnapDeals (Update proofs) would benefit most from the Supraseal investigation. Since the investigation was motivated by memory optimization for large proofs, and SnapDeals involve updating sector data, one might think SnapDeals would be the primary consumer of Supraseal optimizations. The grep result showed the opposite: SnapDeals use the native prover, and any memory optimizations for Supraseal would primarily benefit PoRep, not SnapDeals.

Input Knowledge Required

To understand this message, several layers of context are necessary:

  1. Rust/Cargo feature system: The reader must understand that Cargo features are compile-time flags that conditionally include code. The #[cfg(feature = "...")] attribute gates compilation of entire modules.
  2. The Filecoin proof stack architecture: The dependency chain is: filecoin-proofs-apifilecoin-proofsstorage-proofs-{core,porep,post,update}bellpersonsupraseal-c2 (C++ library). Each layer can define its own features and propagate them selectively.
  3. The bellperson dispatch mechanism: The critical insight from [msg 51] that mod native vs mod supraseal is selected at compile time based on the cuda-supraseal feature.
  4. The proof type distinction: Filecoin has three main proof types — PoRep (Proof-of-Replication, for sealing), PoSt (Proof-of-Spacetime, for window/sector proving), and Update/SnapDeals (for updating committed sector data). Each has different circuit sizes and performance characteristics.
  5. Previous grep results: The assistant had already checked storage-proofs-post ([msg 68]) and found no cuda-supraseal feature. Message 69 was the parallel check for storage-proofs-update to complete the picture.

Output Knowledge Created

This message produced several concrete pieces of knowledge:

  1. SnapDeals/Update proofs never use Supraseal. The absence of a cuda-supraseal feature in storage-proofs-update means that even when the top-level crate is compiled with Supraseal support, Update proofs will use the native Rust prover with GPU acceleration via bellperson/cuda.
  2. The native prover is the universal fallback. For any proof type that doesn't explicitly enable cuda-supraseal, the native prover is used. This means the native prover's GPU capabilities (via LockedMultiexpKernel and LockedFftKernel) are the common denominator across all proof types.
  3. PoRep is the only Supraseal consumer. This focuses the optimization effort: if you want to reduce the ~200 GiB peak memory of Supraseal, you're optimizing for PoRep. PoSt and SnapDeals would need separate optimization efforts targeting the native prover.
  4. A mapping of proof type to proving backend: PoRep → Supraseal (when cuda-supraseal is enabled), PoSt → Native GPU, SnapDeals → Native GPU. This mapping is essential for understanding where to invest optimization resources.

The Thinking Process Visible in This Message

The assistant's reasoning is visible in the sequence of commands leading up to and following message 69. The investigation followed a systematic pattern:

  1. Discover the dispatch point: Find where bellperson chooses between native and Supraseal ([msg 51]).
  2. Trace the feature upward: Check how filecoin-proofs defines and propagates cuda-supraseal ([msg 67]).
  3. Check each sub-crate: Verify whether storage-proofs-post ([msg 68]) and storage-proofs-update (message 69) define their own cuda-supraseal feature.
  4. Synthesize the conclusion: The pattern is clear — only PoRep gets Supraseal. The assistant didn't stop at the feature definitions. After message 69, it immediately proceeded to examine the actual constraint count definitions in storage-proofs-post ([msg 70]), moving from "which backend is used" to "how big are the circuits for each proof type." This shows a methodical approach: first establish the architectural boundaries, then drill into the quantitative details.

Mistakes and Incorrect Assumptions

The most significant incorrect assumption that this message helped correct was the belief that Supraseal was the primary GPU proving path for all proof types. The investigation had been framed around "the SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin PoRep," but the memory and performance characteristics being studied were specific to PoRep. The grep results in message 69 and its predecessor [msg 68] revealed that PoSt and SnapDeals operate on a completely different proving backend, with different memory profiles, different GPU kernel implementations, and different optimization opportunities.

Another subtle mistake was the assumption that the feature name cuda-supraseal would be consistently defined across all sub-crates. The Rust/Cargo ecosystem allows each crate to define its own feature set independently. The fact that storage-proofs-update doesn't define cuda-supraseal doesn't prevent it from being compiled with Supraseal — it simply means the crate's own code doesn't conditionally use Supraseal. But since bellperson is where the dispatch happens, and bellperson's cuda-supraseal feature is enabled by filecoin-proofs's cuda-supraseal feature, the dispatch could still happen at the bellperson level. The key insight is that storage-proofs-update doesn't propagate cuda-supraseal to bellperson — it only propagates cuda. So bellperson receives cuda from the Update path, not cuda-supraseal.

Broader Implications

This finding has significant implications for the optimization proposals being developed in the broader investigation. The "Persistent Prover Daemon" and "Sequential Partition Synthesis" proposals were designed around Supraseal's memory characteristics. If PoSt and SnapDeals don't use Supraseal, those proposals would need to be adapted for the native prover's architecture, or the optimization scope would need to be explicitly limited to PoRep.

Furthermore, the finding explains why the investigation's memory accounting showed ~200 GiB for PoRep but didn't find equivalent peaks for PoSt. The native prover, while still GPU-accelerated, has a different memory management model — it uses LockedMultiexpKernel and LockedFftKernel with priority-based GPU access, rather than Supraseal's approach of loading the entire SRS (Structured Reference String) into GPU memory upfront.

Conclusion

Message 69 is a textbook example of how a simple grep command, in the right context, can produce an architectural insight that reshapes an entire investigation. By confirming that storage-proofs-update lacks a cuda-supraseal feature, the assistant established that SnapDeals proofs never use the Supraseal C++ backend — they always fall through to the native Rust prover with GPU acceleration. This finding corrected a significant assumption, focused the optimization effort on PoRep, and provided a clear map of which proving backend serves which proof type. In a codebase spanning Go, Rust, C++, and CUDA, with a dependency chain six layers deep, such architectural clarity is invaluable.