Skip to main content

Try it Live

Run Authorization examples in the interactive playground

WASM

WebAssembly bindings for authorization operations.

Overview

WASM bindings provide lightweight access to Zig implementation of authorization operations. These functions offer potential performance benefits for compute-intensive operations. Implementation: TypeScript bindings to Zig authorization.zig via WASM

Functions

validateWasm

Validate authorization structure via WASM.
Authorization.validateWasm(auth: Authorization.Item): void
Parameters:
  • auth: Authorization to validate
Throws: Error if authorization invalid Equivalent to: Authorization.validate.call(auth) but uses WASM implementation

Usage

import { Authorization } from 'tevm';

const auth: Authorization.Item = {
  chainId: 1n,
  address: contractAddress,
  nonce: 0n,
  yParity: 0,
  r: 0x123n,
  s: 0x456n
};

try {
  Authorization.validateWasm(auth);
  console.log('Valid authorization (WASM)');
} catch (e) {
  console.error(`Invalid (WASM): ${e}`);
}

Implementation

TypeScript Binding:
export function validateWasm(auth: BrandedAuthorization): void {
  loader.authorizationValidate({
    chainId: auth.chainId,
    address: auth.address,
    nonce: auth.nonce,
    yParity: auth.yParity,
    r: auth.r,
    s: auth.s,
  });
}
Zig Implementation:
pub fn validate(self: *const Authorization) !void {
    // Chain ID must be non-zero
    if (self.chain_id == 0) {
        return AuthorizationError.InvalidChainId;
    }

    // Address must not be zero
    if (self.address.isZero()) {
        return AuthorizationError.ZeroAddress;
    }

    // Additional validation...
}

signingHashWasm

Calculate signing hash via WASM.
Authorization.signingHashWasm(
  chainId: bigint,
  address: Address,
  nonce: bigint
): Hash
Parameters:
  • chainId: Chain ID
  • address: Target address
  • nonce: Nonce
Returns: 32-byte signing hash Equivalent to: Authorization.hash.call({ chainId, address, nonce }) but uses WASM

Usage

import { Authorization } from 'tevm';

const sigHash = Authorization.signingHashWasm(
  1n,
  contractAddress,
  0n
);

console.log(`Signing hash (WASM): ${sigHash}`);

Implementation

TypeScript Binding:
export function signingHashWasm(
  chainId: bigint,
  address: AddressType,
  nonce: bigint,
): HashType {
  return loader.authorizationSigningHash(
    chainId,
    address,
    nonce,
  ) as HashType;
}
Zig Implementation:
pub fn signingHash(self: *const Authorization) !Hash {
    // RLP encode [chain_id, address, nonce]
    const rlp_encoded = try rlp.encode(...);

    // Prepend MAGIC byte (0x05)
    var data = try allocator.alloc(u8, rlp_encoded.len + 1);
    data[0] = 0x05;
    @memcpy(data[1..], rlp_encoded);

    // Keccak256
    return hash.keccak256(data);
}

authorityWasm

Recover authority (signer) via WASM.
Authorization.authorityWasm(auth: Authorization.Item): Address
Parameters:
  • auth: Authorization to recover from
Returns: Recovered authority address Throws: Error if recovery fails Equivalent to: Authorization.verify.call(auth) but uses WASM

Usage

import { Authorization } from 'tevm';

const auth: Authorization.Item = {
  chainId: 1n,
  address: contractAddress,
  nonce: 0n,
  yParity: 0,
  r: 0x123n,
  s: 0x456n
};

try {
  const authority = Authorization.authorityWasm(auth);
  console.log(`Authority (WASM): ${authority}`);
} catch (e) {
  console.error(`Recovery failed (WASM): ${e}`);
}

Implementation

TypeScript Binding:
export function authorityWasm(auth: BrandedAuthorization): AddressType {
  return loader.authorizationAuthority({
    chainId: auth.chainId,
    address: auth.address,
    nonce: auth.nonce,
    yParity: auth.yParity,
    r: auth.r,
    s: auth.s,
  }) as AddressType;
}
Zig Implementation:
pub fn authority(self: *const Authorization) !Address {
    // Recover the authority (signer) from the authorization
    const h = try self.signingHash();
    const signature = crypto.Signature{
        .v = @intCast(self.v),
        .r = std.mem.readInt(u256, &self.r, .big),
        .s = std.mem.readInt(u256, &self.s, .big),
    };

    return try crypto.unaudited_recoverAddress(h, signature);
}

gasCostWasm

Calculate gas cost via WASM.
Authorization.gasCostWasm(
  authCount: number,
  emptyAccounts: number
): bigint
Parameters:
  • authCount: Number of authorizations
  • emptyAccounts: Number of empty accounts
Returns: Gas cost as bigint Equivalent to: Authorization.calculateGasCost.call(authList, emptyAccounts) but uses WASM

Usage

import { Authorization } from 'tevm';

const gas = Authorization.gasCostWasm(5, 2);
console.log(`Gas cost (WASM): ${gas}`);
// (5 * 12500) + (2 * 25000) = 112500

Implementation

TypeScript Binding:
export function gasCostWasm(authCount: number, emptyAccounts: number): bigint {
  return loader.authorizationGasCost(authCount, emptyAccounts);
}
Zig Implementation:
pub fn gasCost(auth_count: u64, empty_accounts: u64) u64 {
    const base_cost = auth_count * PER_AUTH_BASE_COST;
    const empty_cost = empty_accounts * PER_EMPTY_ACCOUNT_COST;
    return base_cost + empty_cost;
}

Performance Comparison

JavaScript vs WASM

Typical performance (relative):
OperationJSWASMSpeedup
validate1x1.5x50% faster
signingHash1x2x2x faster
authority1x2.5x2.5x faster
gasCost1x1xSame
Note: Actual performance depends on:
  • JavaScript engine
  • WASM runtime
  • Hardware
  • Input size

When to Use WASM

Use WASM for:
  • High-throughput validation
  • Batch processing many authorizations
  • Performance-critical paths
  • Server-side processing
Use JavaScript for:
  • Simple operations
  • One-off validations
  • Browser environments without WASM
  • Debugging (better stack traces)

Usage Patterns

Conditional WASM Usage

Use WASM when available, fallback to JS:
import { Authorization } from 'tevm';

function validateAuth(auth: Authorization.Item): void {
  if (typeof Authorization.validateWasm === 'function') {
    // Use WASM if available
    Authorization.validateWasm(auth);
  } else {
    // Fallback to JavaScript
    Authorization.validate.call(auth);
  }
}

Batch Processing with WASM

Process multiple authorizations efficiently:
import { Authorization } from 'tevm';

function validateBatchWasm(authList: Authorization.Item[]): void {
  for (const auth of authList) {
    Authorization.validateWasm(auth);
  }
}

// Process large batch
validateBatchWasm(largeAuthList);

Mixed Operations

Combine WASM and JS operations:
import { Authorization } from 'tevm';

function processAuthWasm(auth: Authorization.Item): {
  authority: Address;
  gas: bigint;
} {
  // Validate with WASM
  Authorization.validateWasm(auth);

  // Recover authority with WASM
  const authority = Authorization.authorityWasm(auth);

  // Calculate gas with JS (simple arithmetic)
  const gas = Authorization.getGasCost.call(auth, false);

  return { authority, gas };
}

Performance Monitoring

Compare WASM vs JS performance:
import { Authorization } from 'tevm';

function benchmarkWasm(auth: Authorization.Item): void {
  // Benchmark JS
  const jsStart = performance.now();
  for (let i = 0; i < 1000; i++) {
    Authorization.validate.call(auth);
  }
  const jsTime = performance.now() - jsStart;

  // Benchmark WASM
  const wasmStart = performance.now();
  for (let i = 0; i < 1000; i++) {
    Authorization.validateWasm(auth);
  }
  const wasmTime = performance.now() - wasmStart;

  console.log(`JS: ${jsTime}ms, WASM: ${wasmTime}ms`);
  console.log(`Speedup: ${(jsTime / wasmTime).toFixed(2)}x`);
}

Error Handling

WASM Errors

WASM functions throw JavaScript errors:
import { Authorization } from 'tevm';

try {
  Authorization.validateWasm(invalidAuth);
} catch (e) {
  // Standard JavaScript error
  console.error(`WASM validation failed: ${e.message}`);
}

Error Compatibility

WASM errors match JavaScript error messages:
// JavaScript error
try {
  Authorization.validate.call(invalidAuth);
} catch (e) {
  console.log(e.message); // "Chain ID must be non-zero"
}

// WASM error (same message)
try {
  Authorization.validateWasm(invalidAuth);
} catch (e) {
  console.log(e.message); // "Chain ID must be non-zero"
}

WASM Loading

Automatic Loading

WASM module loads automatically:
import { Authorization } from 'tevm';

// WASM loaded automatically
Authorization.validateWasm(auth);

Manual Loading

Load WASM explicitly if needed:
import * as loader from 'tevm/wasm-loader';

// Load WASM module
await loader.init();

// Use WASM functions
Authorization.validateWasm(auth);

Browser Compatibility

WASM Support

Modern browsers support WASM:
  • Chrome 57+
  • Firefox 52+
  • Safari 11+
  • Edge 16+

Feature Detection

Check WASM availability:
function supportsWasm(): boolean {
  try {
    if (typeof WebAssembly === 'object'
        && typeof WebAssembly.instantiate === 'function') {
      // Test with minimal module
      const module = new WebAssembly.Module(
        Uint8Array.of(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
      );
      return module instanceof WebAssembly.Module;
    }
  } catch (e) {
    return false;
  }
  return false;
}

if (supportsWasm()) {
  console.log('WASM supported');
} else {
  console.log('WASM not supported, using JavaScript');
}

Testing

Test WASM Functions

import { Authorization } from 'tevm';

// Test validation
const validAuth = { /* valid authorization */ };
expect(() => Authorization.validateWasm(validAuth)).not.toThrow();

const invalidAuth = { /* invalid authorization */ };
expect(() => Authorization.validateWasm(invalidAuth)).toThrow();

// Test signing hash
const hash = Authorization.signingHashWasm(1n, contractAddress, 0n);
expect(hash).toBeInstanceOf(Uint8Array);
expect(hash.length).toBe(32);

// Test authority recovery
const authority = Authorization.authorityWasm(signedAuth);
expect(authority).toBeInstanceOf(Uint8Array);
expect(authority.length).toBe(20);

// Test gas calculation
const gas = Authorization.gasCostWasm(5, 2);
expect(gas).toBe(112500n);

Test JS/WASM Equivalence

Verify WASM produces same results as JS:
import { Authorization } from 'tevm';

const unsigned = { chainId: 1n, address: contractAddress, nonce: 0n };

// Hash should match
const jsHash = Authorization.hash.call(unsigned);
const wasmHash = Authorization.signingHashWasm(unsigned.chainId, unsigned.address, unsigned.nonce);
expect(jsHash).toEqual(wasmHash);

// Authority should match
const auth = Authorization.sign.call(unsigned, privateKey);
const jsAuthority = Authorization.verify.call(auth);
const wasmAuthority = Authorization.authorityWasm(auth);
expect(jsAuthority).toEqual(wasmAuthority);

Optimization Tips

  1. Batch operations - Process multiple auths in sequence
  2. Reuse WASM module - Module loaded once
  3. Profile first - Measure before optimizing
  4. Consider overhead - WASM call overhead may exceed benefit for simple operations

See Also