| Crates.io | zk-nalloc |
| lib.rs | zk-nalloc |
| version | 0.2.0 |
| created_at | 2026-01-01 17:25:46.762949+00 |
| updated_at | 2026-01-12 01:06:22.763748+00 |
| description | High-performance, deterministic memory allocator optimized for Zero-Knowledge Proof (ZKP) systems and cryptographic provers. |
| homepage | |
| repository | https://github.com/nzengi/nalloc |
| max_upload_size | |
| id | 2016501 |
| size | 141,130 |
A high-performance, deterministic, and security-hardened memory allocator specifically engineered for Zero-Knowledge Proof (ZKP) systems and cryptographic provers.
General-purpose allocators (malloc, jemalloc) are designed for long-lived, heterogeneous workloads. ZK provers, however, exhibit extreme memory patterns: massive short-lived vectors, sensitive witness data, and performance-critical FFT/NTT operations.
nalloc addresses these unique requirements:
| Feature | Description |
|---|---|
| Drop Safety | Prevents use-after-free via Arc reference counting |
| Panic-Free | Gracefully falls back to system allocator on errors |
| Fallback Allocator | Continues working when arena exhausted |
| Huge Pages | 2MB/1GB huge page support (Linux) |
| Guard Pages | Buffer overflow protection at arena boundaries |
| Memory Locking | Prevent witness data from being swapped |
[dependencies]
zk-nalloc = { version = "0.2.0", features = ["fallback"] }
| Feature | Description | Default |
|---|---|---|
fallback |
Fall back to system allocator when arena exhausted | ✅ |
huge-pages |
Linux 2MB/1GB huge page support | ❌ |
guard-pages |
Guard pages at arena boundaries | ❌ |
mlock |
Lock witness memory to prevent swapping | ❌ |
nalloc is a pure memory primitive designed to work with any ZK framework:
| Framework | Use Case |
|---|---|
| Halo2 | Plonkish circuits, recursive proofs |
| Plonky2 | Fast recursive STARKs |
| Risc0 | zkVM execution |
| SP1 | Succinct zkVM |
| Miden | STARK-based VM |
| Cairo | StarkNet proofs |
| Circom/SnarkJS | Groth16, PLONK circuits |
| Arkworks | General-purpose ZK toolkit |
nalloc partitions memory into three specialized pools to eliminate fragmentation and enforce security boundaries:
| Arena | Purpose | Optimization | Security |
|---|---|---|---|
| Witness | Secret inputs / Witnesses | Zero-on-recycled-alloc | Secure Wipe (Volatile) |
| Polynomial | FFT / NTT Vectors | 64-byte & Page Alignment | Isolated from scratch |
| Scratch | Temp computation space | High-speed bump allocation | O(1) Batch Reset |
Witness data is handled with extreme caution. The secure_wipe() method uses platform-specific primitives that the compiler cannot optimize away:
explicit_bzeromemset_sRtlSecureZeroMemorynalloc has zero external ZK dependencies. It provides pure memory primitives that any proving system can utilize. Lock-free AtomicPtr initialization prevents recursive allocation deadlocks during prover startup.
use zk_nalloc::NAlloc;
// Fallible initialization
match NAlloc::try_new() {
Ok(alloc) => { /* use alloc */ }
Err(e) => eprintln!("Allocation failed: {}", e),
}
// Or use the auto-fallback version
let alloc = NAlloc::new(); // Falls back to system allocator if needed
if alloc.is_fallback_mode() {
eprintln!("Running in fallback mode");
}
Easily track your circuit's memory footprint:
let stats = alloc.stats().expect("Stats available");
println!("Witness used: {} bytes", stats.witness_used);
println!("Polynomial used: {} bytes", stats.polynomial_used);
#[cfg(feature = "fallback")]
println!("Fallback bytes: {} bytes", stats.total_fallback_bytes());
Add to your Cargo.toml:
[dependencies]
zk-nalloc = "0.2.0"
In your main.rs or lib.rs:
use zk_nalloc::NAlloc;
#[global_allocator]
static ALLOC: NAlloc = NAlloc::new();
fn main() {
// All allocations are now routed to specialized arenas
let data = vec![0u8; 1024];
}
For maximum performance, access arenas directly:
use zk_nalloc::NAlloc;
fn prove() {
let nalloc = NAlloc::new();
// 1. Allocate witness data
let witness = nalloc.witness();
let secret = witness.alloc(1024, 64);
// 2. Compute proof with your preferred ZK framework...
// 3. Securely erase traces
unsafe { witness.secure_wipe(); }
}
use zk_nalloc::ArenaManager;
// Allocate with guard pages for buffer overflow detection
#[cfg(feature = "guard-pages")]
let manager = ArenaManager::with_guard_pages(
128 * 1024 * 1024, // witness
1024 * 1024 * 1024, // polynomial
256 * 1024 * 1024, // scratch
)?;
#[cfg(feature = "mlock")]
{
let manager = ArenaManager::new()?;
manager.lock_witness()?; // Prevent swapping of sensitive data
}
nalloc provides cross-platform abstractions for low-level memory management:
mach_vm_allocate / mach_vm_deallocatemmap / munmap (via rustix) with huge page supportVirtualAlloc / VirtualFree with guard pages| Task | System Alloc | nalloc | Speedup |
|---|---|---|---|
| 10k Small Allocs | ~150 μs | ~50 μs | 3x |
| Large FFT Vector | ~10 μs | ~8 μs | 1.2x |
| Batch Dealloc | O(N) | O(1) | ∞ |
Licensed under either of:
Designed with ❤️ for the ZK community. Contributions for Huge Page support or new platform backends are welcome.