ParaloomPARALOOM

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

ModuleFileRole
Job enginesrc/compute/engine.rstop-level lifecycle: submit → assign → collect
Executorsrc/compute/executor.rsWasmtime sandbox + resource limits
Distributionsrc/compute/distribution.rsvalidator scoring, retry, BFT result agreement
Privacy plumbingsrc/compute/privacy.rsPedersen 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 CPU
  • nan_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 → reject

The 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... --decrypt

Or 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
Memory64 MiB
Fuel1 × 10⁹ instructions
Wall-clock timeout30 s
Distribution timeout300 s
Concurrent jobs4 / executor

Limits are configurable per job; the coordinator rejects jobs above the network-wide cap.

Tests

FileWhat it covers
tests/compute_wasm_execution_test.rssandbox, fuel limits, OOM, timeout
tests/private_compute_e2e.rsend-to-end private job
tests/compute_distribution_test.rsvalidator 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-demo

The 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

ItemTracked in
Output-note integration with shielded poolopen 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.

On this page