Mapping the API Frontier: How a Visibility Audit Shaped the SUPRASEAL_C2 Optimization Pipeline

Introduction

In the world of cryptographic proof systems, memory is the silent bottleneck. The SUPRASEAL_C2 Groth16 proof generation pipeline for Filecoin's Proof-of-Replication (PoRep) consumes approximately 200 GiB of peak memory — a staggering footprint that constrains deployment options, increases cloud rental costs, and limits throughput. A deep-dive investigation into this pipeline had already mapped the full call chain from Curio's Go task layer through Rust FFI into C++/CUDA kernels, identified nine structural bottlenecks, and proposed three ambitious optimization proposals: Sequential Partition Synthesis, Persistent Prover Daemon, and Cross-Sector Batching. But before any of these proposals could be implemented, a fundamental question had to be answered: what parts of the existing Rust codebase are actually accessible to a new CUDA integration layer?

This article synthesizes the work of a critical sub-investigation within that larger effort — a systematic audit of Rust API visibility across four crates that would determine the architectural boundaries within which the optimization proposals must operate. The investigation, spanning multiple rounds of file discovery, source reading, and re-export chain tracing, produced a definitive visibility map that directly shaped the feasibility and design of each optimization proposal.

The Strategic Context: Why Visibility Matters

The broader investigation had established that Filecoin's proof pipeline operates through a layered architecture. At the top, Curio's Go task layer orchestrates proof generation jobs. These flow through Rust FFI into the bellperson crate (a Groth16 proving system), which in turn calls into supraseal-c2 — the C++/CUDA layer that performs the actual GPU-accelerated computation. The peak memory problem stems from two main sources: the pipeline runs 10 partition circuits in parallel, each consuming ~16 GiB, while the Structured Reference String (SRS) occupies another ~48 GiB in pinned GPU memory.

The three optimization proposals aimed to address this:

  1. Sequential Partition Synthesis — stream partitions one-at-a-time through the GPU instead of holding all 10 in memory simultaneously, reducing peak from ~200 GiB to ~64–103 GiB.
  2. Persistent Prover Daemon — keep the proving process alive across multiple proofs to eliminate the ~60-second per-proof SRS loading overhead.
  3. Cross-Sector Batching — use the freed memory headroom to batch multiple sectors' circuits into single GPU invocations, projecting 2–3× throughput per GPU. But each proposal required direct access to specific Rust APIs. Could a new CUDA integration layer — codenamed "cuzk" — call seal_commit_phase2_circuit_proofs directly? Could it construct StackedCircuit instances with custom parameters? Could it load the SRS from cache without going through the existing high-level API? These questions were not academic; they would determine whether the proposals could be implemented as external tools or would require forking and modifying upstream crates.

The Investigation: A Multi-Round Visibility Audit

The visibility audit unfolded across seven messages in a dedicated subagent session, each round building on the previous one with methodical precision.

Round 1: The Questionnaire (Message 0)

The investigation began with a precise, multi-part query from the user (the parent session agent) to the subagent. The user wanted exact visibility modifiers — pub, pub(crate), or private — for ten specific items across four source files spanning three crates:

  1. storage-proofs-core/src/compound_proof.rs: The CompoundProof trait, its methods circuit_proofs() and circuit(), the constant MAX_GROTH16_BATCH_SIZE, and SetupParams.
  2. storage-proofs-porep/src/stacked/circuit/proof.rs: The StackedCompound and StackedCircuit types, and whether they can be constructed from outside the crate.
  3. filecoin-proofs/src/api/seal.rs: The seal_commit_phase2_circuit_proofs function, its intermediate types, and get_stacked_params.
  4. filecoin-proofs/src/caches.rs: The get_stacked_params function and GROTH_PARAM_MEMORY_CACHE. The user's framing — "key types and functions that cuzk would need to call directly" — revealed the strategic intent. This was not a casual code review; it was a reconnaissance mission to determine the integration surface for a new system.

Round 2: File Discovery (Messages 1–2)

The assistant's first attempt to locate the files used the glob tool, but it apparently failed to produce results — likely because the tool was restricted to the workspace directory, while the crate sources lived under ~/.cargo/registry/src/. Recognizing this limitation, the assistant pivoted to bash with a clear explanation: "Let me use bash to find the files since they're in an external directory" ([msg 2]).

This decision point — abandoning a specialized tool for a general-purpose one — exemplifies the adaptive problem-solving that characterizes effective code archaeology. The bash approach used ls with wildcard paths and 2>/dev/null error suppression, producing clean, resolved absolute paths for all four files. The output confirmed that all files existed under the same crate registry hash (1949cf8c6b5b557f), validating the assumption that the crates were downloaded from a consistent registry snapshot.

Round 3: Reading the Primary Sources (Message 3)

With file paths confirmed, the assistant read all four source files in parallel ([msg 3]). This parallel strategy was a deliberate optimization: since none of the reads depended on each other, issuing them simultaneously minimized round trips within the synchronous round-based execution model.

However, the initial reads revealed an important gap. Reading the source files alone was insufficient to determine external visibility. In Rust, a type declared pub in a submodule is not automatically accessible from outside the crate — it must be re-exported through every intermediate module in the hierarchy. The assistant recognized this and pivoted to trace the re-export chain.

Round 4: Tracing the Module Hierarchy (Messages 4–6)

The assistant systematically read three module declaration files to trace the visibility path from definition site to crate boundary:

  1. circuit/mod.rs ([msg 5]): Revealed that StackedCircuit and StackedCompound are explicitly re-exported via pub use proof::{StackedCircuit, StackedCompound};, while other submodules (column, column_proof, hash, params) remain private.
  2. stacked/mod.rs ([msg 5]): Showed pub use circuit::*; — a wildcard re-export that propagates the circuit module's public items upward. Notably, the vanilla module is declared pub(crate), making it inaccessible from outside the crate.
  3. api/mod.rs ([msg 6]): Confirmed pub use seal::*;, which combined with lib.rs's pub use api::*; (verified in message 5) ensures seal_commit_phase2_circuit_proofs reaches the crate root as a fully public function. This multi-level traversal demonstrated a sophisticated understanding of Rust's visibility model. The assistant was not just reading visibility modifiers — it was tracing the path that each item must travel to reach external consumers.

Round 5: Synthesis and Findings (Message 7)

The culmination of the investigation was a comprehensive visibility map that answered every question with precision. The key findings were:

CompoundProof trait: Public. Its methods circuit_proofs() and circuit() are implicitly public (Rust trait methods cannot be private). This means any code that can name the trait can call these methods — a crucial enabler for the Sequential Partition Synthesis proposal, which needs to invoke circuit_proofs() with different partition configurations.

MAX_GROTH16_BATCH_SIZE: Private, with value 10. This constant controls how many proofs can be batched in a single Groth16 batch proof. Its privacy means external code cannot read or modify it. For the Cross-Sector Batching proposal, this is a hard constraint: larger batch sizes would require modifying the storage-proofs-core crate itself.

StackedCircuit and StackedCompound: Public and re-exported to the crate root. However, the assistant went beyond the user's explicit question and examined field-level visibility. All fields of StackedCircuit are private, meaning the struct cannot be constructed using literal syntax from outside the crate. Instead, three construction pathways exist: via CompoundProof::circuit(), via CompoundProof::blank_circuit(), or via the pub fn synthesize(...) associated function. This distinction between "the type is public" and "you can construct an instance" is critical for integration work.

seal_commit_phase2_circuit_proofs: Fully public, re-exported through api/mod.rs and lib.rs to the crate root. This function is the main entry point for Phase 2 proof generation, and its public visibility means cuzk can call it directly without forking the filecoin-proofs crate.

get_stacked_params: pub(crate). This is arguably the most consequential finding. The function that loads Groth16 parameters (including the ~48 GiB SRS) from cache is not accessible from outside the filecoin-proofs crate. This directly impacts the Persistent Prover Daemon proposal: if the daemon cannot call get_stacked_params, it cannot keep the SRS loaded across invocations without either forking the crate or implementing its own parameter loading logic.

GROTH_PARAM_MEMORY_CACHE: Module-private. The cache itself is not directly accessible, further constraining external optimization attempts.

Implications for the Optimization Proposals

The visibility audit did not merely produce a report — it directly shaped the feasibility and design of each optimization proposal.

Sequential Partition Synthesis

This proposal requires calling StackedCompound::circuit_proofs() with different partition configurations. The audit confirmed that circuit_proofs() is accessible as a trait method on the public CompoundProof trait, and StackedCompound is public. However, the private partitions field means the partition count must be set through the trait's type parameter or constructor, not by directly modifying the struct. This is feasible but constrains the implementation approach — the partition count must be known at compile time or set through a controlled construction pathway.

Persistent Prover Daemon

This proposal faces the most significant obstacle from the visibility audit. The pub(crate) visibility of get_stacked_params means an external process cannot load the SRS through the existing caching layer. The daemon would need to either:

  1. Be implemented as a library within the filecoin-proofs crate (giving it access to pub(crate) items)
  2. Load parameters through the existing public API (which may have overhead and may not expose the raw SRS)
  3. Implement its own parameter loading from disk, duplicating logic This finding effectively forces a design decision about where the daemon lives in the codebase. The visibility audit transformed an abstract optimization idea into a concrete architectural constraint.

Cross-Sector Batching

The discovery that MAX_GROTH16_BATCH_SIZE = 10 is a private constant directly constrains this proposal. If the proposal requires larger batches (e.g., to batch multiple sectors' circuits), the constant would need to be changed in the storage-proofs-core crate itself — an operation that requires forking or patching the dependency. Alternatively, batching could be done at a higher level (multiple calls to circuit_proofs()), but this would not achieve the same efficiency gains as a single larger batch proof.

Beyond Visibility: Micro-Optimization Analysis

The visibility audit was not the end of the investigation. A final round of analysis examined the computational hotpaths at the instruction level, providing the data needed to optimize within the constraints the audit had revealed.

CPU Synthesis Hotpaths

The CPU-side circuit synthesis was analyzed at the instruction level, revealing several hotpaths:

GPU NTT/MSM Characteristics

On the GPU side, the analysis examined the Number Theoretic Transform (NTT) and Multi-Scalar Multiplication (MSM) operations that dominate the Groth16 proving time:

Host-to-Device Transfer Patterns

The analysis characterized the H-to-D (host-to-device) transfer patterns, revealing that the circuit witness data (the a/b/c vectors from the R1CS) is transferred from CPU to GPU for each partition. These vectors are large (~1.6 GiB per partition for the PoRep circuit), contributing significantly to the ~200 GiB peak. The analysis considered recomputing a/b/c vectors on-the-fly on the GPU rather than materializing them in host memory — a technique that would trade compute for memory, potentially reducing peak memory by ~16 GiB (one partition's worth of witness data) at the cost of increased GPU compute time.

The Broader Shift: From Optimization to Architecture

The visibility audit and micro-optimization analysis together represent a shift in the investigation's focus — from optimizing individual proof generation operations toward architecting a continuous, memory-efficient proving pipeline optimized for heterogeneous cloud rental markets where RAM cost dominates.

The key insight is that the ~200 GiB peak memory is not a single problem but a cascade of architectural decisions: 10 parallel partitions, each with its own circuit synthesis and witness materialization, combined with a 48 GiB SRS that is loaded from disk for every proof. The optimization proposals address these decisions at the architectural level:

Conclusion

The visibility audit of the SUPRASEAL_C2 Groth16 proof generation pipeline was far more than a technical exercise in reading Rust source files. It was a strategic reconnaissance mission that mapped the API boundaries within which all optimization work must operate. By tracing the re-export chains from definition site to crate boundary, the investigation produced a definitive map of what is accessible, what is hidden, and what the boundaries mean for the three optimization proposals.

The findings were consequential: get_stacked_params is pub(crate), forcing a design decision about the Persistent Prover Daemon's architecture. MAX_GROTH16_BATCH_SIZE is private, constraining Cross-Sector Batching to upstream modifications. CompoundProof and seal_commit_phase2_circuit_proofs are fully public, enabling Sequential Partition Synthesis as an external tool. The micro-optimization analysis then provided the instruction-level data needed to optimize within these constraints.

In the end, the investigation transformed the optimization problem from "how do we reduce memory?" to "how do we architect a continuous proving pipeline within the existing API boundaries?" — a shift that reflects the maturity of the analysis and the practical constraints of working with real-world cryptographic codebases. The visibility audit was the foundation upon which all subsequent architectural decisions would be built.## References

[1] "Mapping the API Surface: A Visibility Audit in the Filecoin Proof Pipeline" — Article examining the initial questionnaire message (msg 0) and its strategic purpose in the visibility audit.

[2] "The Art of the Preliminary: How a Single Message Orchestrates Discovery in OpenCode Sessions" — Article analyzing the assistant's first response (msg 1) and the decision to use glob for file discovery.

[3] "Reading the Source: A Data-Gathering Pivot in the Filecoin Proof Pipeline Investigation" — Article covering the parallel file read operation (msg 3) and its role in the investigation.

[4] "Tracing the Visibility Chain: How One Message Mapped Rust's Module Re-Export Topology for Filecoin Proofs" — Article examining the mod.rs reads (msg 5) and the re-export chain tracing.

[5] "Navigating Rust's Visibility Maze: A Deep Dive into Filecoin Proof Pipeline API Boundaries" — Article synthesizing the complete visibility findings (msg 7) and their implications.

[6] "Tracing Visibility Through Rust's Module Hierarchy: A Subagent's Investigation into Filecoin Proof Types" — Article analyzing the module hierarchy verification step (msg 4).

[7] "Navigating the Crate Jungle: How a Simple ls Unlocked the Filecoin Proof Pipeline's API Surface" — Article covering the bash-based file discovery pivot (msg 2).

[8] "Tracing the Re-export Chain: A Subagent's Systematic Visibility Investigation" — Article examining the api/mod.rs read (msg 6) and its role in completing the re-export chain.