Compute Layer
Privacy-preserving WASM compute with Pedersen commitments, ownership proofs, and BFT result agreement.
Compute layer
Status: alpha. Private compute is functional in tests and on devnet, but output-note plumbing into the shielded pool is still pending. Treat the API as unstable.
The compute layer lets a requester submit a WASM program with private inputs, have a small validator cohort execute it under sandboxed limits, and retrieve a result that only the requester can decrypt. The privacy guarantees rest on Pedersen commitments for value-hiding, an ownership proof that binds the result to the requester, and BFT agreement on the output hash so a single malicious validator can't forge a result.
Architecture
| Module | File | Role |
|---|---|---|
| Job engine | src/compute/engine.rs | top-level lifecycle: submit → assign → collect |
| Executor | src/compute/executor.rs | Wasmtime sandbox + resource limits |
| Distribution | src/compute/distribution.rs | validator scoring, retry, BFT result agreement |
| Privacy plumbing | src/compute/privacy.rs | Pedersen commits, ownership proof, AES encryption |
WASM execution
Wasmtime runs each job in a fresh Store with hard limits:
pub struct ExecutionConfig {
pub memory_limit_bytes: usize, // default 64 MiB
pub fuel: u64, // instruction budget
pub wall_timeout: Duration, // job-level timeout
pub max_concurrent_jobs: usize, // per executor
}Wasmtime runtime configuration:
consume_fuel(true)— fuel-metered execution; hits a trap before exhausting CPUnan_canonicalization(true)— determinism across hosts (BFT result hashes must match)max_wasm_stack(…)— bounded stack to block runaway recursion- No host functions exposed by default — programs are pure compute, no I/O
Determinism matters because the BFT cohort agrees on the hash of the output bytes. Non-deterministic execution would prevent agreement.
Private inputs & outputs
Inputs and outputs cross the network encrypted; only their commitments are public.
Pedersen commitment
// commit(value, blinding) = value · G + blinding · H
let c = pedersen_commit(value_bytes, blinding);Pedersen is additively homomorphic — sums of commitments equal commitments of sums — which is why it's used here rather than Poseidon. Implementation: src/privacy/pedersen.rs.
Ownership proof
A small Schnorr-style proof that the requester knows the secret key matching the public key embedded in the input commitment. This binds the output to the requester so a malicious validator can't redirect the encrypted result to a different recipient. Lives in src/compute/privacy.rs.
Encryption
Inputs are AES-256-GCM encrypted under a key derived from the requester's pubkey + a per-job nonce. Validators see ciphertext + commitment, never plaintext. After execution, the result is encrypted under the same key — so only the requester can decrypt.
BFT result agreement
The cohort runs the same WASM with the same encrypted inputs, then exchanges signed result hashes. Coordinator collects votes the same way withdrawal consensus does — thresholds and reputation gating are configurable per network. Default for compute is the same 7/10 as withdrawal consensus.
1. Coordinator scores validators by current load + reputation
2. Picks K validators (default: 3 for replication, more for higher security tiers)
3. Each runs WASM, emits sign(result_hash)
4. Cohort agrees on the most-voted result_hash
5. Disagreement → retry on a fresh quorum; persistent disagreement → rejectThe agreement code path uses the same primitives as consensus::WithdrawalVerificationCoordinator — same vote aggregation, same reputation gate. See Consensus.
Job submission
# Submit (devnet)
paraloom compute submit \
--wasm ./my_program.wasm \
--input ./input.json \
--private \
--replication 3
# → job_id: 7f3c8...
# Status
paraloom compute status 7f3c8...
# state: executing (2/3 validators replied)
# elapsed: 1.4s
# Result (decrypted with the local key)
paraloom compute result 7f3c8... --decryptOr programmatically:
use paraloom::compute::{Job, ResourceLimits};
let job = Job::builder()
.wasm(wasm_bytes)
.private_input(&input, &requester_pubkey)? // Pedersen commit + AES encrypt
.with_ownership_proof(&requester_secret)? // bind output to requester
.limits(ResourceLimits {
memory_limit_bytes: 64 << 20,
fuel: 1_000_000_000,
wall_timeout: Duration::from_secs(30),
max_concurrent_jobs: 4,
})
.build()?;
let job_id = compute.submit(job).await?;
let result = compute.wait(job_id).await?;
let plaintext = result.decrypt(&requester_secret)?;Resource limits (defaults)
| Default | |
|---|---|
| Memory | 64 MiB |
| Fuel | 1 × 10⁹ instructions |
| Wall-clock timeout | 30 s |
| Distribution timeout | 300 s |
| Concurrent jobs | 4 / executor |
Limits are configurable per job; the coordinator rejects jobs above the network-wide cap.
Tests
| File | What it covers |
|---|---|
tests/compute_wasm_execution_test.rs | sandbox, fuel limits, OOM, timeout |
tests/private_compute_e2e.rs | end-to-end private job |
tests/compute_distribution_test.rs | validator scoring + retry |
Known limitations (alpha)
- Output-note plumbing into the shielded pool is not yet wired — results are returned to the requester but don't (yet) re-enter the privacy pool as new commitments.
- No host I/O is exposed yet (no network, no filesystem). Compute is pure-input → pure-output. This is deliberate while the trust model is being firmed up.
- Cost / fee accounting is only partial; treat all fee figures on devnet as illustrative.
What's solid: WASM execution, sandbox limits, Pedersen + ownership proof, BFT result agreement, AES delivery. The pending pieces are about integrating with the rest of the privacy layer, not about the compute primitive itself.
Compute alpha demo
# Spin up 3-validator localnet + run the included demo program
./scripts/localnet/start-all.sh
cargo run --release --bin compute-demoThe demo submits a small private aggregation, watches the cohort agree on the result hash, and decrypts the output locally. Source: src/bin/compute_demo.rs.
Roadmap
| Item | Tracked in |
|---|---|
| Output-note integration with shielded pool | open issue |
| Verifier circuit for compute correctness (zk-WASM) | research / future track |
| Host capability surface (controlled, opt-in) | post-mainnet |
The minimum bar before compute leaves alpha: output-notes wired through to the merkle root, plus a real audit of the Pedersen + ownership-proof path.