WASM API Reference

Complete API documentation for MetaMUI Crypto Primitives in WebAssembly.

Installation

npm install @metamui/crypto-wasm
# or
yarn add @metamui/crypto-wasm
# or
pnpm add @metamui/crypto-wasm

Quick Start

import init, { Ed25519, ChaCha20Poly1305, Blake3 } from '@metamui/crypto-wasm';

// Initialize WASM module
await init();

// Generate keypair
const keypair = Ed25519.generateKeypair();

// Sign message
const message = new TextEncoder().encode("Hello");
const signature = Ed25519.sign(message, keypair.privateKey);

// Verify signature
const isValid = Ed25519.verify(signature, message, keypair.publicKey);

API Documentation

For detailed API documentation, see:

Initialization

Browser

import init from '@metamui/crypto-wasm';

// Auto-detect WASM URL
await init();

// Or specify custom URL
await init('/path/to/metamui_crypto_wasm_bg.wasm');

Node.js

import { readFile } from 'fs/promises';
import init from '@metamui/crypto-wasm';

const wasmBuffer = await readFile('./node_modules/@metamui/crypto-wasm/metamui_crypto_wasm_bg.wasm');
await init(wasmBuffer);

Web Workers

// worker.js
import init, * as crypto from '@metamui/crypto-wasm';

self.addEventListener('message', async (event) => {
    if (!self.cryptoInitialized) {
        await init();
        self.cryptoInitialized = true;
    }
    
    const { type, data } = event.data;
    
    switch (type) {
        case 'hash':
            const hash = crypto.Blake3.hash(data);
            self.postMessage({ type: 'hash', result: hash });
            break;
        // ... other operations
    }
});

Available Functions

Hash Functions

import { SHA256, SHA512, Blake2b, Blake3, SHAKE256 } from '@metamui/crypto-wasm';

// Simple hashing
const hash = SHA256.hash(data);
const blake3Hash = Blake3.hash(data);

// Streaming hash
const hasher = Blake3.createHasher();
hasher.update(chunk1);
hasher.update(chunk2);
const finalHash = hasher.finalize();

// SHAKE256 (XOF)
const output = SHAKE256.hash(data, outputLength);

Digital Signatures

import { Ed25519, Sr25519, Dilithium, Falcon512 } from '@metamui/crypto-wasm';

// Ed25519
const keypair = Ed25519.generateKeypair();
const signature = Ed25519.sign(message, keypair.privateKey);
const isValid = Ed25519.verify(signature, message, keypair.publicKey);

// Post-quantum signatures
const pqKeypair = Dilithium.generateKeypair();
const pqSignature = Dilithium.sign(message, pqKeypair.privateKey);

Encryption

import { ChaCha20Poly1305, AES256, ARIA256 } from '@metamui/crypto-wasm';

// ChaCha20-Poly1305
const key = ChaCha20Poly1305.generateKey();
const encrypted = ChaCha20Poly1305.encrypt(plaintext, key);
const decrypted = ChaCha20Poly1305.decrypt(
    encrypted.ciphertext,
    encrypted.nonce,
    key
);

// AES-256-GCM
const aesKey = AES256.generateKey();
const aesEncrypted = AES256.encrypt(plaintext, aesKey);

Key Exchange

import { X25519, MLKem768 } from '@metamui/crypto-wasm';

// X25519 ECDH
const alice = X25519.generateKeypair();
const bob = X25519.generateKeypair();
const sharedSecret = X25519.computeSharedSecret(
    alice.privateKey,
    bob.publicKey
);

// Post-quantum KEM
const kemKeypair = MLKem768.generateKeypair();
const encapsulated = MLKem768.encapsulate(kemKeypair.publicKey);
const sharedSecret2 = MLKem768.decapsulate(
    encapsulated.ciphertext,
    kemKeypair.privateKey
);

Key Derivation

import { Argon2, PBKDF2, HKDF } from '@metamui/crypto-wasm';

// Password hashing
const salt = Argon2.generateSalt();
const hash = Argon2.hash(
    password,
    salt,
    256 * 1024, // memory in KB
    4,          // iterations
    2           // parallelism
);

// Key derivation
const derivedKey = HKDF.derive(
    inputKey,
    salt,
    info,
    32 // output length
);

Memory Management

WASM memory is automatically managed, but you can optimize usage:

// Memory is automatically freed after use
const hash = Blake3.hash(largeData);

// For streaming operations, memory is reused
const hasher = Blake3.createHasher();
for (const chunk of chunks) {
    hasher.update(chunk); // Reuses internal buffer
}
const finalHash = hasher.finalize();
hasher.free(); // Explicitly free if needed

Performance Optimization

Batch Operations

// Process multiple items efficiently
const hashes = Blake3.batchHash(dataArray);
const signatures = Ed25519.batchSign(messages, privateKey);
const results = Ed25519.batchVerify(signatures, messages, publicKeys);

Streaming Large Files

async function hashLargeFile(file) {
    const hasher = Blake3.createHasher();
    const reader = file.stream().getReader();
    
    try {
        while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            hasher.update(value);
        }
        return hasher.finalize();
    } finally {
        hasher.free();
    }
}

Web Workers Pool

class CryptoWorkerPool {
    constructor(poolSize = 4) {
        this.workers = Array(poolSize).fill(null).map(() => {
            const worker = new Worker('/crypto-worker.js');
            return { worker, busy: false };
        });
    }
    
    async execute(operation, data) {
        const available = this.workers.find(w => !w.busy);
        if (!available) {
            // Wait for next available worker
            await new Promise(resolve => setTimeout(resolve, 10));
            return this.execute(operation, data);
        }
        
        available.busy = true;
        
        return new Promise((resolve, reject) => {
            available.worker.onmessage = (e) => {
                available.busy = false;
                resolve(e.data.result);
            };
            
            available.worker.onerror = (e) => {
                available.busy = false;
                reject(e);
            };
            
            available.worker.postMessage({ operation, data });
        });
    }
}

Browser Compatibility

Feature Detection

// Check WebAssembly support
if (typeof WebAssembly === 'undefined') {
    console.error('WebAssembly not supported');
    // Fall back to pure JS implementation
}

// Check for required features
const features = {
    bigInt: typeof BigInt !== 'undefined',
    sharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',
    atomics: typeof Atomics !== 'undefined'
};

Polyfills

// TextEncoder/TextDecoder polyfill for older browsers
if (typeof TextEncoder === 'undefined') {
    await import('fast-text-encoding');
}

Security Considerations

Content Security Policy

<!-- Allow WASM execution -->
<meta http-equiv="Content-Security-Policy" 
      content="script-src 'self' 'wasm-unsafe-eval'">

Secure Random

// Uses crypto.getRandomValues() internally
const randomBytes = crypto.secureRandom(32);

// For Node.js, uses crypto.randomBytes

Examples

Browser Encryption

class BrowserCrypto {
    constructor() {
        this.initialized = false;
    }
    
    async init() {
        if (!this.initialized) {
            await init();
            this.initialized = true;
        }
    }
    
    async encryptData(data, password) {
        await this.init();
        
        // Derive key from password
        const salt = Argon2.generateSalt();
        const key = Argon2.deriveKey(password, salt, 32);
        
        // Encrypt data
        const encrypted = ChaCha20Poly1305.encrypt(data, key);
        
        // Return encrypted package
        return {
            salt: Array.from(salt),
            nonce: Array.from(encrypted.nonce),
            ciphertext: Array.from(encrypted.ciphertext)
        };
    }
    
    async decryptData(encryptedPackage, password) {
        await this.init();
        
        // Reconstruct arrays
        const salt = new Uint8Array(encryptedPackage.salt);
        const nonce = new Uint8Array(encryptedPackage.nonce);
        const ciphertext = new Uint8Array(encryptedPackage.ciphertext);
        
        // Derive same key
        const key = Argon2.deriveKey(password, salt, 32);
        
        // Decrypt
        return ChaCha20Poly1305.decrypt(ciphertext, nonce, key);
    }
}

IndexedDB Integration

class SecureIndexedDB {
    constructor(dbName) {
        this.dbName = dbName;
        this.key = null;
    }
    
    async init(password) {
        await init(); // Initialize WASM
        
        // Derive database encryption key
        const salt = localStorage.getItem('db_salt') || (() => {
            const newSalt = Argon2.generateSalt();
            localStorage.setItem('db_salt', btoa(String.fromCharCode(...newSalt)));
            return newSalt;
        })();
        
        this.key = Argon2.deriveKey(password, salt, 32);
    }
    
    async store(key, value) {
        const data = JSON.stringify(value);
        const encrypted = AES256.encrypt(
            new TextEncoder().encode(data),
            this.key
        );
        
        // Store in IndexedDB
        const db = await this.openDB();
        const tx = db.transaction(['data'], 'readwrite');
        await tx.objectStore('data').put({
            key,
            ciphertext: encrypted.ciphertext,
            nonce: encrypted.nonce
        });
    }
    
    async retrieve(key) {
        const db = await this.openDB();
        const tx = db.transaction(['data'], 'readonly');
        const record = await tx.objectStore('data').get(key);
        
        if (!record) return null;
        
        const decrypted = AES256.decrypt(
            record.ciphertext,
            record.nonce,
            this.key
        );
        
        return JSON.parse(new TextDecoder().decode(decrypted));
    }
}

Troubleshooting

Common Issues

WASM not loading

// Check MIME type
// Server must serve .wasm files with: application/wasm

// Webpack config
module.exports = {
    experiments: {
        asyncWebAssembly: true
    }
};

Memory errors

// Increase memory if needed
const memory = new WebAssembly.Memory({
    initial: 256, // 16MB
    maximum: 4096 // 256MB
});

Performance issues

// Use streaming instantiation
const response = await fetch('/path/to/module.wasm');
const { instance } = await WebAssembly.instantiateStreaming(response);

See Also