Skip to content

Add optional CUDA-accelerated PLONK prover for BLS12-381 - #1792

Open
seunlanlege wants to merge 23 commits into
Consensys:masterfrom
polytope-labs:gpu-base
Open

Add optional CUDA-accelerated PLONK prover for BLS12-381#1792
seunlanlege wants to merge 23 commits into
Consensys:masterfrom
polytope-labs:gpu-base

Conversation

@seunlanlege

@seunlanlege seunlanlege commented Jul 6, 2026

Copy link
Copy Markdown

This PR adds an optional, GPU-accelerated PLONK prover for the BLS12-381 backend, gated entirely behind a cuda build tag. When gnark is built normally (without -tags cuda), behavior is unchanged: the CPU prover is the only code path compiled in, and there is no new runtime dependency. When built with -tags cuda, the PLONK prover for BLS12-381 runs a device-resident proving pipeline on an NVIDIA GPU via cgo, backed by open-icicle.

The design goal is a fully device-resident prover: the witness, wires, canonical trace, and opening polynomials stay on the GPU across the entire proof, so host↔device transfers are minimized rather than round-tripping per NTT/MSM.

Build model & CPU-path safety

  • prove_gpu.go (//go:build cuda) carries the real device-resident prover; prove_nogpu.go (//go:build !cuda) provides no-op placeholders so the package builds identically without the tag.
  • The default (no-tag) build pulls in no cgo, no CUDA, no new imports — the existing pure-Go CPU prover is untouched.
  • The cuda build is strict GPU-or-die: device errors panic rather than silently falling back to CPU, so a misconfigured GPU can never produce a proof via an unintended path.

What runs on-device (cuda build)

  • NTT/FFT, MSM, and the quotient numerator rho-loop
  • Batch openings — eval / fold / divide / commit on resident device handles
  • Linearized polynomial evaluations (S1/S2/S3, Ql/Qr/Qm/Qo fed from resident canonical buffers)
  • Grand-product computation
  • Selectors, wires, and canonical polynomials are kept resident to skip their download

Supporting optimizations: the circuit-fixed trace and canonical Qk are cached on the proving key and cloned per-proof (pooled/recycled); SRS point-conversion and NTT warmup are overlapped with the CPU witness solve.

New code layout

Path Purpose
backend/plonk/bls12-381/prove_gpu.go Device-resident prover (//go:build cuda)
backend/plonk/bls12-381/prove_nogpu.go No-op placeholders (//go:build !cuda)
backend/plonk/bls12-381/prove_resident_openings.go Resident batch-open primitives
backend/plonk/bls12-381/prove_resident_wire.go Keep wires resident through openings
backend/plonk/bls12-381/prove.go, setup.go Hooks + cache trace/Qk on the proving key
internal/gpu/bls12381/gpu.go cgo bindings to libgnark_cuda + icicle
internal/gpu/bls12381/{resident,plonk}.go Device buffers + PLONK glue
internal/gpu/bls12381/p2/ Device/frvector/kernels/MSM primitives layer

Dependencies (for maintainer discussion)

The cuda build links against libgnark_cuda, icicle_field_bls12_381, icicle_curve_bls12_381, icicle_device, and cudart; paths are supplied via CGO_CFLAGS/CGO_LDFLAGS at build time (documented in gpu.go). These are only required when building with the tag.

go.sum currently references a polytope-labs/gnark-crypto fork (v0.19.3-0.20260627...). This is the main item to resolve before merge — we'd like to land the required gnark-crypto changes upstream first so this PR can build against stock gnark-crypto with no fork/replace. Happy to open that companion PR; guidance on how you'd prefer to structure it is welcome.

Scope & limitations

  • PLONK + BLS12-381 only. Groth16 and other curves are out of scope for this PR.
  • GPU code is exercised by prove_reuse_test.go and internal/gpu/bls12381/p2/grandproduct_test.go; CI without a CUDA device continues to build and test the CPU path only.

Note

High Risk
Large new proving surface on the critical proof-generation path; CUDA builds panic on GPU failure and omit full GPU support for statistical ZK, so correctness and ops risk are high despite CPU-only builds being isolated by build tags.

Overview
Adds an optional PLONK prover for BLS12-381 behind the cuda build tag: a device-resident pipeline (prove_gpu.go, internal/gpu/bls12381, p2/) that keeps wires, quotient work, and much of KZG on-GPU, with prove_nogpu.go stubs so default builds stay pure-Go and unchanged.

Shared prover changes (prove.go, setup.go): hooks try GPU helpers first where compiled; Setup caches circuit-fixed trace, canonical Qk, and a sync.Pool of trace clones (clone / cloneInto); prewarmGPU overlaps SRS/NTT prep with witness solve; defer freeGPUContext and pool return after prove; parallel batchInvert for large domains; TestProvingKeyTraceReuse guards trace aliasing across repeated proves.

CUDA-only behavior: strict GPU-or-die (gpuFatal panics, no silent CPU fallback); resident quotient rho-loop, on-device divide/commit for H, grand-product Z, async LRO MSMs, and resident batch openings; statistical ZK disables the full resident GPU quotient/openings path.

Reviewed by Cursor Bugbot for commit 5be470e. Bugbot is set up for automated code reviews on this repo. Configure here.

seunlanlege and others added 23 commits June 27, 2026 05:45
GPU PLONK prover: device-resident rho-loop (icicle/CUDA)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant