Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/provablehq/snarkvm/llms.txt

Use this file to discover all available pages before exploring further.

Overview

SnarkVM provides WebAssembly (WASM) bindings through the snarkvm-wasm crate, enabling zero-knowledge proof operations directly in web browsers, edge workers, and other WASM-compatible environments.

Features and Limitations

Supported Features

The WASM build includes:
  • Account management (address generation, key management)
  • Cryptographic operations (hashing, signatures)
  • Block and transaction parsing
  • Field and group arithmetic
  • Program compilation and execution
  • Query operations for blockchain data

Limitations

WASM builds have several important limitations:
  • No CUDA acceleration support
  • Limited proof generation (smaller constraint systems only)
  • Single-threaded execution (no Rayon parallelism)
  • Browser memory constraints (typically 2-4GB max)
  • No native filesystem access

Installation

Adding Dependency

Add snarkvm-wasm to your Cargo.toml:
Cargo.toml
[dependencies]
snarkvm-wasm = { version = "4.4.0", features = ["full"] }
wasm-bindgen = "0.2"

Feature Flags

The snarkvm-wasm crate supports granular feature flags:
Cargo.toml
[dependencies.snarkvm-wasm]
version = "4.4.0"
features = [
    "circuit",      # Circuit operations
    "curves",       # Curve arithmetic
    "fields",       # Field operations
    "ledger",       # Block and transaction handling
    "synthesizer",  # Program synthesis
    "utilities",    # Helper utilities
]
Feature Details:
  • full (default): Enables all features
  • circuit: Circuit-level operations and constraints
  • curves: Elliptic curve operations (BLS12-377)
  • fields: Finite field arithmetic
  • ledger: Blockchain query and data structures (BlockStore, QueryTrait)
  • synthesizer: Program compilation and execution
  • utilities: General-purpose utilities

Building for WASM

Prerequisites

Install WASM toolchain:
# Install wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

# Add WASM target
rustup target add wasm32-unknown-unknown

# Install wasm-bindgen-cli (optional, for direct building)
cargo install wasm-bindgen-cli

Build Commands

# Development build (with debug info)
wasm-pack build --target web --dev wasm/

# Production build (optimized)
wasm-pack build --target web --release wasm/

# For Node.js
wasm-pack build --target nodejs --release wasm/

# For bundlers (webpack, rollup, etc.)
wasm-pack build --target bundler --release wasm/

Using cargo

# Build WASM binary
cargo build --target wasm32-unknown-unknown --release \
    -p snarkvm-wasm --features full

# Generate bindings
wasm-bindgen target/wasm32-unknown-unknown/release/snarkvm_wasm.wasm \
    --out-dir ./pkg --target web

Optimization

Optimize WASM binary size:
# Install wasm-opt (part of binaryen)
# macOS
brew install binaryen

# Ubuntu/Debian
sudo apt-get install binaryen

# Optimize WASM
wasm-opt -Oz -o output_optimized.wasm input.wasm

# With wasm-pack
wasm-pack build --target web --release -- \
    --features full \
    --config 'profile.release.opt-level="z"'

Usage Examples

Browser Integration

JavaScript/TypeScript

import init, * as snarkvm from './pkg/snarkvm_wasm.js';

// Initialize WASM module
await init();

// Use SnarkVM functions
const account = snarkvm.create_account();
console.log('Address:', account.address());
console.log('Private key:', account.private_key());

// Parse block data
const blockData = '...';
const block = snarkvm.parse_block(blockData);
console.log('Block height:', block.height());
console.log('Block hash:', block.hash());

HTML Example

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>SnarkVM WASM Example</title>
</head>
<body>
    <h1>SnarkVM in Browser</h1>
    <button id="createAccount">Create Account</button>
    <div id="output"></div>

    <script type="module">
        import init, * as snarkvm from './pkg/snarkvm_wasm.js';

        await init();

        document.getElementById('createAccount').addEventListener('click', () => {
            try {
                const account = snarkvm.create_account();
                document.getElementById('output').innerHTML = `
                    <p><strong>Address:</strong> ${account.address()}</p>
                    <p><strong>View Key:</strong> ${account.view_key()}</p>
                `;
            } catch (error) {
                console.error('Error:', error);
                document.getElementById('output').innerText = `Error: ${error.message}`;
            }
        });
    </script>
</body>
</html>

Node.js Integration

const snarkvm = require('./pkg/snarkvm_wasm.js');

// Node.js async initialization
async function main() {
    // Initialize WASM
    await snarkvm.default();

    // Query blockchain data
    const client = snarkvm.create_client('https://api.explorer.aleo.org/v1');

    try {
        const latestHeight = await client.latest_height();
        console.log('Latest block height:', latestHeight);

        const latestBlock = await client.latest_block();
        console.log('Latest block hash:', latestBlock.hash());
    } catch (error) {
        console.error('Query failed:', error);
    }
}

main().catch(console.error);

React Integration

import React, { useState, useEffect } from 'react';
import init, * as snarkvm from 'snarkvm-wasm';

interface Account {
    address: string;
    privateKey: string;
    viewKey: string;
}

const AleoWallet: React.FC = () => {
    const [initialized, setInitialized] = useState(false);
    const [account, setAccount] = useState<Account | null>(null);
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        // Initialize WASM module
        init().then(() => {
            console.log('SnarkVM WASM initialized');
            setInitialized(true);
        }).catch(error => {
            console.error('Failed to initialize:', error);
        });
    }, []);

    const createAccount = () => {
        if (!initialized) return;

        setLoading(true);
        try {
            const newAccount = snarkvm.create_account();
            setAccount({
                address: newAccount.address(),
                privateKey: newAccount.private_key(),
                viewKey: newAccount.view_key(),
            });
        } catch (error) {
            console.error('Failed to create account:', error);
        } finally {
            setLoading(false);
        }
    };

    if (!initialized) {
        return <div>Loading SnarkVM...</div>;
    }

    return (
        <div>
            <h2>Aleo Wallet</h2>
            <button onClick={createAccount} disabled={loading}>
                {loading ? 'Creating...' : 'Create New Account'}
            </button>

            {account && (
                <div>
                    <p><strong>Address:</strong> {account.address}</p>
                    <p><strong>View Key:</strong> {account.viewKey}</p>
                </div>
            )}
        </div>
    );
};

export default AleoWallet;

Configuration

Cargo.toml Configuration

The snarkvm-wasm crate configuration:
[package]
name = "snarkvm-wasm"
version = "4.4.0"
edition = "2024"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
snarkvm-console = { workspace = true, features = ["wasm"] }
getrandom = { version = "0.2", features = ["js"] }

[dev-dependencies]
wasm-bindgen-test = "0.3.37"
Key Configuration Points:
  • crate-type = ["cdylib", "rlib"]: Enables WASM compilation
  • features = ["wasm"]: Activates WASM-specific code paths
  • getrandom with js feature: Provides browser-compatible RNG

Random Number Generation

SnarkVM uses getrandom with the js feature for cryptographically secure randomness in browsers:
use getrandom::getrandom;

// Works in browser via Web Crypto API
let mut random_bytes = [0u8; 32];
getrandom(&mut random_bytes)?;
The js feature is required for getrandom to work in browsers. Without it, random number generation will panic.

Testing WASM

Browser Tests

Using wasm-bindgen-test:
use wasm_bindgen_test::*;

wasm_bindgen_test_configure!(run_in_browser);

#[wasm_bindgen_test]
fn test_account_creation() {
    let account = create_account();
    assert!(account.address().len() > 0);
}

#[wasm_bindgen_test]
fn test_field_arithmetic() {
    let a = Field::from(5u64);
    let b = Field::from(3u64);
    let c = a + b;
    assert_eq!(c, Field::from(8u64));
}

Running Tests

# Install wasm-bindgen-test-runner
cargo install wasm-bindgen-cli

# Run tests in Node.js
wasm-pack test --node wasm/

# Run tests in browser (requires Chrome/Firefox)
wasm-pack test --headless --chrome wasm/
wasm-pack test --headless --firefox wasm/

# Run tests in all environments
wasm-pack test --node --headless --chrome --firefox wasm/

Performance Optimization

Build Optimization

Cargo.toml
[profile.release]
opt-level = "z"      # Optimize for size
lto = true           # Link-time optimization
codegen-units = 1    # Better optimization, slower compile
panic = "abort"      # Smaller binary size

Code Splitting

Split large WASM modules:
// Lazy load heavy operations
const loadProver = () => import('./pkg/snarkvm_prover.js');
const loadVerifier = () => import('./pkg/snarkvm_verifier.js');

// Only load when needed
button.addEventListener('click', async () => {
    const prover = await loadProver();
    const proof = await prover.generate_proof(input);
});

Worker Threads

Offload computation to web workers:
// main.js
const worker = new Worker('snarkvm-worker.js');

worker.postMessage({
    type: 'generate_proof',
    input: proofInput,
});

worker.onmessage = (event) => {
    if (event.data.type === 'proof_complete') {
        console.log('Proof:', event.data.proof);
    }
};

// snarkvm-worker.js
importScripts('./pkg/snarkvm_wasm.js');

self.onmessage = async (event) => {
    if (event.data.type === 'generate_proof') {
        try {
            await wasm_bindgen('./pkg/snarkvm_wasm_bg.wasm');
            const proof = generate_proof(event.data.input);
            self.postMessage({
                type: 'proof_complete',
                proof: proof,
            });
        } catch (error) {
            self.postMessage({
                type: 'error',
                error: error.message,
            });
        }
    }
};

Common Patterns

Error Handling

try {
    const result = snarkvm.risky_operation();
    console.log('Success:', result);
} catch (error) {
    if (error instanceof WebAssembly.RuntimeError) {
        console.error('WASM runtime error:', error.message);
    } else {
        console.error('Application error:', error);
    }
}

Memory Management

// Explicitly free resources
const account = snarkvm.create_account();
try {
    // Use account
    console.log(account.address());
} finally {
    // Free WASM memory
    account.free();
}

// Or use automatic cleanup
{
    const account = snarkvm.create_account();
    console.log(account.address());
    // account.free() called automatically at scope end (if configured)
}

Async Operations

// For long-running operations
async function generateProofAsync(input) {
    // Show loading indicator
    showLoading();

    try {
        // Run in microtask to avoid blocking
        await new Promise(resolve => setTimeout(resolve, 0));
        const proof = snarkvm.generate_proof(input);
        return proof;
    } finally {
        hideLoading();
    }
}

Deployment

CDN Deployment

<!-- Load from CDN -->
<script type="module">
    import init from 'https://cdn.example.com/snarkvm-wasm/pkg/snarkvm_wasm.js';
    await init();
    // Use SnarkVM
</script>

Webpack Configuration

// webpack.config.js
module.exports = {
    experiments: {
        asyncWebAssembly: true,
    },
    module: {
        rules: [
            {
                test: /\.wasm$/,
                type: 'webassembly/async',
            },
        ],
    },
};

Vite Configuration

// vite.config.js
import { defineConfig } from 'vite';
import wasm from 'vite-plugin-wasm';

export default defineConfig({
    plugins: [wasm()],
    optimizeDeps: {
        exclude: ['snarkvm-wasm'],
    },
});

Troubleshooting

WASM Binary Too Large

SnarkVM WASM can be 5-10MB uncompressed. Enable gzip compression on your server.
# nginx configuration
gzip on;
gzip_types application/wasm;
gzip_comp_level 6;

Memory Errors

// Increase WASM memory limit
const memory = new WebAssembly.Memory({
    initial: 256,  // 16MB
    maximum: 1024, // 64MB
});

Import Errors

// Ensure correct initialization order
import init from './pkg/snarkvm_wasm.js';

// Must await init before using any functions
await init();

// Now safe to use
const account = snarkvm.create_account();

Best Practices

Development

  • Use development builds for debugging (include source maps)
  • Test in multiple browsers (Chrome, Firefox, Safari)
  • Monitor memory usage in DevTools
  • Use Web Workers for heavy computation

Production

  • Always use optimized release builds (wasm-pack build --release)
  • Enable gzip/brotli compression for WASM files
  • Implement proper error handling and recovery
  • Cache WASM modules using Service Workers
  • Consider code splitting for large applications

Security

  • Validate all inputs from untrusted sources
  • Use HTTPS for all WASM deployments
  • Implement Content Security Policy (CSP)
  • Keep dependencies updated

Browser Compatibility

Minimum Browser Versions:
  • Chrome: 57+
  • Firefox: 52+
  • Safari: 11+
  • Edge: 16+
Required Features:
  • WebAssembly MVP
  • WebAssembly BigInt integration (for u64 support)
  • Web Crypto API (for secure randomness)

Build docs developers (and LLMs) love