Reading the Build Scripts: A Critical Decision Point in GPU Backend Selection for the cuzk Proving Daemon

Introduction

In the course of implementing Phase 0 of the cuzk pipelined SNARK proving daemon for Filecoin, the assistant reached a critical juncture: selecting the correct CUDA backend for the RTX 5070 Ti (Blackwell architecture, compute capability 12.0) available on the test machine. Message <msg id=200> captures this decision point — a brief but consequential investigation into two build scripts that would determine whether the proving pipeline could execute at all.

The message is deceptively simple: the assistant reads two build.rs files, one from supraseal-c2-0.1.2 and one from bellperson-0.26.0. But this act sits at the intersection of hardware compatibility, build system architecture, and the practical realities of deploying zero-knowledge proof infrastructure on modern GPU hardware. Understanding why this message was written, what assumptions it carries, and what knowledge it produces reveals the careful reasoning that underpins production-grade SNARK proving systems.

Context: The State of the cuzk Project

To appreciate message <msg id=200>, we must understand where the project stood at that moment. The cuzk proving daemon had been designed and implemented across six crates in extern/cuzk/, with a complete gRPC API, priority scheduler, and real seal_commit_phase2 integration. The workspace compiled cleanly with --no-default-features (a CPU-only build that avoids CUDA entirely). The 45 GiB SRS parameters had been laboriously fetched and copied to /data/zk/params/. A 51 MB golden C1 test file sat ready at /data/32gbench/c1.json.

The next milestone was unambiguous: run a real proof end-to-end. This would be the first time the full pipeline — deserialization, SRS loading, constraint synthesis, GPU computation, and proof verification — would execute on actual hardware. The assistant had already confirmed the environment: an RTX 5070 Ti with 16 GB VRAM, CUDA 13.1, compute capability 12.0 (Blackwell).

But between the assistant and that milestone lay a build configuration decision. The cuzk-core crate exposed two feature flags: cuda (using bellperson's native CUDA prover) and cuda-supraseal (using the specialized supraseal-c2 GPU prover). The question was: which one supports Blackwell GPUs?

Why This Message Was Written: The Blackwell Compatibility Question

The assistant's reasoning, visible in the preceding messages, follows a clear chain:

  1. Message <msg id=194>: Plans to "Build with CUDA features for GPU proving" and "Run daemon with FIL_PROOFS_PARAMETER_CACHE=/data/zk/params and test real PoRep C2 proof."
  2. Message <msg id=195>: Confirms the test data and GPU availability.
  3. Message <msg id=196>: Notes the "RTX 5070 Ti available with 16 GB VRAM."
  4. Message <msg id=197>: Reads the workspace and crate Cargo.toml files to understand the feature flag structure.
  5. Message <msg id=198>: Discovers compute capability 12.0 (Blackwell) and asks: "Let me check if supraseal supports it, or if we need the regular bellperson CUDA backend."
  6. Message <msg id=199>: Locates the build.rs files for both supraseal-c2 and bellperson. Message <msg id=200> is the direct follow-through: reading those build scripts to determine architecture support. The motivation is practical. Blackwell (sm_120 / compute cap 12.0) is NVIDIA's newest architecture as of early 2026. GPU compute libraries and CUDA kernel collections often lag behind new architectures — a library compiled for sm_80 (Ampere) or sm_89 (Ada Lovelace) may not contain the machine code needed to run on Blackwell. If supraseal-c2's build system doesn't target Blackwell, the daemon would crash at runtime with a "no kernel image for device" error, or fail to compile at all.

What the Build Scripts Reveal

The assistant reads two files. The first is supraseal-c2-0.1.2/build.rs:

use std::env;

fn main() {
    let mut nvcc = sppark::build::ccmd();
    nvcc.define("FEATURE_BLS12_381", None);
    apply_blst_flags(&mut nvcc);
    nvcc.file("cuda/groth16_cuda.cu").compile("groth16_cuda");

    println!("cargo:rerun-if-changed=cuda");
    println!("cargo:rerun-if-env-changed=CXXFLAGS");
}

This is a thin wrapper around sppark::build::ccmd(), which is a helper from the sppark library (supraseal's CUDA support library). The architecture targeting is entirely abstracted into sppark::build::ccmd() — the build script itself doesn't specify -arch=sm_XX flags. This means the answer to "does supraseal support Blackwell?" depends on what sppark's build helper does internally.

The second file is bellperson-0.26.0/build.rs:

fn main() {
    cfg_if_nightly();
    gpu_kernel();
}

Bellperson's build script is even simpler — it conditionally enables nightly Rust features and calls gpu_kernel() to generate CUDA/OpenCL kernels at compile time. The architecture targeting here is handled inside gpu_kernel(), which likely probes the system for available GPUs or uses environment variables.

The Unanswered Question

Crucially, message <msg id=200> does not resolve the Blackwell compatibility question. The assistant reads the build scripts but does not yet determine the answer. The investigation is incomplete — the assistant would need to either:

Assumptions Embedded in the Investigation

Several assumptions underpin this message:

Assumption 1: Architecture support is determined at build time. The assistant assumes that reading the build script will reveal which GPU architectures are targeted. This is generally true for CUDA projects — architecture flags like -arch=sm_89 or -gencode=arch=compute_89,code=sm_89 appear in build scripts or CMakeLists. However, sppark::build::ccmd() abstracts this away, making the assumption less productive.

Assumption 2: The build.rs files are the right place to look. For a Rust crate that compiles CUDA code, build.rs is indeed where CUDA compilation is orchestrated. This assumption is correct.

Assumption 3: There might be a compatibility issue. The assistant implicitly assumes that Blackwell support might be missing. This is a reasonable assumption given that Blackwell GPUs were only announced in late 2024 and the supraseal-c2 crate is version 0.1.2 — likely developed before Blackwell hardware was widely available.

Assumption 4: The two backends (supraseal vs bellperson) have different architecture support. This is plausible — supraseal-c2 is a specialized, optimized prover that may target specific architectures, while bellperson's CUDA backend is more general.

Input Knowledge Required

To understand this message, a reader needs:

  1. Knowledge of the cuzk project architecture: That there are two CUDA backends (cuda and cuda-supraseal), and that the choice affects GPU compatibility.
  2. Understanding of CUDA compute capabilities: That Blackwell = sm_120 = compute cap 12.0, and that older code may not support it.
  3. Familiarity with Rust build scripts: That build.rs files run at compile time and can invoke external compilers like nvcc.
  4. Knowledge of the sppark library: That sppark::build::ccmd() is a helper that configures the NVCC command with architecture flags.
  5. Context from the preceding messages: That the assistant is trying to run the first real proof and needs to choose the right feature flag.

Output Knowledge Created

This message produces several pieces of knowledge:

  1. The exact content of supraseal-c2's build.rs: It uses sppark::build::ccmd() and compiles a single CUDA file (groth16_cuda.cu). The architecture targeting is delegated to sppark.
  2. The exact content of bellperson's build.rs: It conditionally enables nightly features and calls gpu_kernel(), which handles kernel generation at compile time.
  3. Confirmation that both build scripts are relatively thin: Neither directly specifies architecture flags, meaning the architecture support question must be answered by examining their dependencies (sppark for supraseal, and the gpu_kernel() implementation for bellperson).
  4. A narrowing of the investigation: The assistant now knows where to look next — into sppark's build helper and bellperson's kernel generation.

The Thinking Process

The assistant's reasoning, visible across messages <msg id=194> through <msg id=200>, demonstrates a systematic, layered approach to build configuration:

  1. Goal identification: "Run a real proof" → requires GPU build.
  2. Feature discovery: Read Cargo.toml to find available CUDA features.
  3. Hardware characterization: Check nvidia-smi for GPU model and compute capability.
  4. Compatibility assessment: Compare hardware (compute cap 12.0) against software (supraseal-c2 v0.1.2).
  5. Source investigation: Read build scripts to understand architecture targeting.
  6. (Next) Deeper investigation or trial build: Depending on what the build scripts reveal. This mirrors how a experienced systems engineer would approach an unfamiliar build: gather facts about the hardware, examine the build configuration, and only then attempt a build. The alternative — blindly building with --features cuda-supraseal and debugging a cryptic linker or runtime error — would be far less efficient.

Broader Significance

Message <msg id=200> illustrates a recurring pattern in systems engineering: the moment when abstract design meets concrete hardware. The cuzk project had been designed with clean abstractions — gRPC APIs, priority schedulers, configurable backends. But at the point of deployment, the assistant must confront the messy reality of GPU architecture compatibility, build system quirks, and version dependencies.

This message also highlights the value of investigative reading in software development. Rather than guessing or trial-and-error, the assistant reads the actual source code of dependencies to understand their behavior. This approach produces reliable knowledge that can be referenced later and avoids the pitfalls of assuming documentation is accurate or complete.

Conclusion

Message <msg id=200> is a small but pivotal moment in the cuzk implementation. It represents the transition from "the code compiles" to "the code will run on this specific hardware." By reading the build scripts of both supraseal-c2 and bellperson, the assistant gathers the information needed to make an informed decision about which CUDA backend to use. The investigation is not yet complete — the architecture support question remains open — but the search space has been narrowed, and the next steps are clear.

This message exemplifies the careful, methodical approach required when deploying zero-knowledge proof infrastructure on modern GPU hardware. Every abstraction must eventually be grounded in the specifics of the silicon, and every build configuration must be validated against the actual hardware it will run on. The cuzk proving daemon is one step closer to producing its first real proof.