Skip to main content

Advanced

Embedded Allocator

SP1 programs use a simple bump allocator by default, which just increments a pointer to allocate memory. Although this works for many cases, some programs can still run out of memory in the SP1 zkVM. To address this, you can enable the embedded allocator feature on the SP1 zkVM.

The embedded allocator uses the embedded-alloc crate and offers more flexible memory management, albeit with extra cycle overhead.

To enable it, add the following to your sp1-zkvm dependency in Cargo.toml:

sp1-zkvm = { version = "...", features = ["embedded"] }

Once enabled, the embedded allocator replaces the default bump allocator.

Blake3 Public Values Hashing

important

This feature is supported on SP1 versions >= 4.2.0.

In certain verification contexts (e.g. Bitcoin script), verifying public values hashed with Blake3 is more efficient than verifying public values hashed with SHA-256.

To enable blake3 public values hashing for your program, enable the blake3 feature on the sp1-zkvm dependency in Cargo.toml:

sp1-zkvm = { version = "...", features = ["blake3"] }

The committed hash of the public values for your proof will be hashed with Blake3 instead of SHA-256.

warning

The official SP1 Solidity verifier does not yet support Blake3 public values, as it currently hardcodes the use of SHA-256.

Requesting Multiple Proofs in Parallel

If you're building an application that generates many proofs, you may want to parallelize proof generation for performance gains. There are two recommended approaches:

1. Using Threads and .prove

You can spawn multiple threads (or async tasks) and invoke .prove() on the NetworkProver in each. Each call will wait until the corresponding proof is available.

This approach is simple and doesn't require tracking proof state manually.

2. Using request_async and get_proof_status

Alternatively, you can use request_async() to fire off proof requests without blocking. This returns a proof_id immediately, which you can use to track the status of each request via get_proof_status(proof_id).

Example:

// Request a proof asynchronously and get the proof ID
let proof_id = network_prover
.prove(&program_key, &stdin)
.mode(proving_mode)
.strategy(proving_strategy)
.request_async()
.await?;

// Later, poll for the status of the proof
let (status, proof) = network_prover
.get_proof_status(&proof_id)
.await?;

This method is more flexible and may be preferable if you're working with large proofs or want more control over request timing and batching.