Documentation Index Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Try it Live Run Signature examples in the interactive playground
WASM
WebAssembly bindings for signature operations.
Overview
Signature primitive is pure TypeScript without WASM bindings. Cryptographic operations (signing, verification, key recovery) are handled by the crypto module, which provides both native and WASM implementations.
Architecture
Signature Primitive (TypeScript)
The Signature primitive provides:
Type definitions (BrandedSignature)
Format conversions (compact, DER)
Validation (canonicality checking)
Component extraction (getR, getS, getV)
Implementation: Pure TypeScript
Location: src/primitives/Signature/
No WASM: Signature manipulation doesn’t require WASM
Crypto Module (Zig + WASM)
Cryptographic operations provided by crypto module:
Signing (secp256k1, P-256, Ed25519)
Verification
Public key recovery
Key generation
Implementation: Zig with WASM bindings
Location: src/crypto/
WASM Available: Yes (via crypto module)
Usage Pattern
import { Signature } from '@voltaire/primitives' ;
import { secp256k1 } from '@voltaire/crypto' ; // WASM available here
// Signature operations (pure TypeScript)
const sig = Signature . fromSecp256k1 ( r , s , 27 );
const canonical = Signature . normalize ( sig );
const der = Signature . toDER ( sig );
// Crypto operations (WASM available)
const { r , s , v } = await secp256k1 . sign ( message , privateKey );
const valid = await secp256k1 . verify ( message , r , s , publicKey );
const pubKey = await secp256k1 . recover ( message , r , s , v );
Why No WASM for Signature?
Signature Operations Are Fast
Signature primitive operations are simple byte manipulations:
// Component extraction (32-byte slice)
const r = sig . slice ( 0 , 32 ); // O(1) view, no copy
// Canonicality check (32-byte comparison)
const canonical = s <= threshold ; // O(n), ~32 iterations
// DER encoding (minimal encoding logic)
const der = encodeDER ( r , s ); // O(n), simple byte operations
Performance: These operations take microseconds in JavaScript.
WASM Overhead: WASM call overhead would be larger than operation cost.
WASM Shines for Crypto Operations
// Expensive: Elliptic curve arithmetic
const sig = secp256k1 . sign ( message , privateKey );
// WASM speedup: 5-10x faster
// Expensive: Point multiplication and verification
const valid = secp256k1 . verify ( message , sig , publicKey );
// WASM speedup: 5-10x faster
// Expensive: Public key recovery
const pubKey = secp256k1 . recover ( message , sig , v );
// WASM speedup: 10-20x faster
Signature Primitive (TypeScript)
Operation TypeScript WASM (hypothetical) Winner fromSecp256k1 0.001ms 0.005ms (call overhead) TypeScript normalize 0.005ms 0.010ms (call overhead) TypeScript toDER 0.010ms 0.015ms (call overhead) TypeScript isCanonical 0.001ms 0.005ms (call overhead) TypeScript
Crypto Operations (via crypto module)
Operation TypeScript WASM Winner sign 0.5ms 0.1ms WASM (5x) verify 1.0ms 0.15ms WASM (6.7x) recover 1.5ms 0.12ms WASM (12.5x)
Integration with Crypto Module
Signing (WASM)
import { Signature } from '@voltaire/primitives' ;
import { secp256k1 } from '@voltaire/crypto' ;
// Sign message (uses WASM)
const { r , s , v } = await secp256k1 . sign ( message , privateKey );
// Create signature (TypeScript)
const sig = Signature . fromSecp256k1 ( r , s , v );
// Normalize (TypeScript)
const canonical = Signature . normalize ( sig );
Verification (WASM)
import { Signature } from '@voltaire/primitives' ;
import { secp256k1 } from '@voltaire/crypto' ;
// Extract components (TypeScript)
const r = Signature . getR ( sig );
const s = Signature . getS ( sig );
// Verify (uses WASM)
const valid = await secp256k1 . verify ( message , r , s , publicKey );
Recovery (WASM)
import { Signature } from '@voltaire/primitives' ;
import { secp256k1 } from '@voltaire/crypto' ;
// Get recovery parameters (TypeScript)
const r = Signature . getR ( sig );
const s = Signature . getS ( sig );
const v = Signature . getV ( sig ) ! ;
// Recover public key (uses WASM)
const publicKey = await secp256k1 . recover ( message , r , s , v );
Complete Example
End-to-End Signature Flow
import { Signature , Hash } from '@voltaire/primitives' ;
import { secp256k1 } from '@voltaire/crypto' ;
async function signAndVerify (
message : Uint8Array ,
privateKey : Uint8Array
) : Promise < boolean > {
// Hash message (TypeScript - fast)
const messageHash = Hash . keccak256 ( message );
// Sign (WASM - expensive crypto)
const { r , s , v } = await secp256k1 . sign ( messageHash , privateKey );
// Create signature (TypeScript - simple construction)
let sig = Signature . fromSecp256k1 ( r , s , v );
// Normalize (TypeScript - simple arithmetic)
sig = Signature . normalize ( sig );
// Convert to DER (TypeScript - simple encoding)
const der = Signature . toDER ( sig );
// Parse back (TypeScript - simple decoding)
const parsed = Signature . fromDER ( der , 'secp256k1' , v );
// Extract components (TypeScript - simple slicing)
const rParsed = Signature . getR ( parsed );
const sParsed = Signature . getS ( parsed );
// Derive public key (WASM - expensive crypto)
const publicKey = await secp256k1 . getPublicKey ( privateKey );
// Verify (WASM - expensive crypto)
return await secp256k1 . verify ( messageHash , rParsed , sParsed , publicKey );
}
Crypto Module WASM API
secp256k1 WASM
// Available via @voltaire/crypto
import { secp256k1 } from '@voltaire/crypto' ;
// Sign (WASM)
const sig = await secp256k1 . sign (
message : Uint8Array ,
privateKey : Uint8Array
): Promise < { r: Uint8Array ; s : Uint8Array ; v : number } > ;
// Verify (WASM)
const valid = await secp256k1 . verify (
message : Uint8Array ,
r : Uint8Array ,
s : Uint8Array ,
publicKey : Uint8Array
): Promise < boolean > ;
// Recover (WASM)
const publicKey = await secp256k1 . recover (
message : Uint8Array ,
r : Uint8Array ,
s : Uint8Array ,
v : number
): Promise < Uint8Array > ;
P-256 WASM
import { p256 } from '@voltaire/crypto' ;
// Sign (WASM)
const sig = await p256 . sign (
message : Uint8Array ,
privateKey : Uint8Array
): Promise < { r: Uint8Array ; s : Uint8Array } > ;
// Verify (WASM)
const valid = await p256 . verify (
message : Uint8Array ,
r : Uint8Array ,
s : Uint8Array ,
publicKey : Uint8Array
): Promise < boolean > ;
Ed25519 WASM
import { ed25519 } from '@voltaire/crypto' ;
// Sign (WASM)
const signature = await ed25519 . sign (
message : Uint8Array ,
privateKey : Uint8Array
): Promise < Uint8Array > ; // 64 bytes
// Verify (WASM)
const valid = await ed25519 . verify (
message : Uint8Array ,
signature : Uint8Array ,
publicKey : Uint8Array
): Promise < boolean > ;
Build Configuration
Crypto Module WASM Build
# Build crypto WASM (includes all signature algorithms)
zig build crypto-wasm
# Output:
# wasm/crypto/secp256k1.wasm
# wasm/crypto/p256.wasm
# wasm/crypto/ed25519.wasm
Tree-Shaking
// Import only what you need
import { secp256k1 } from '@voltaire/crypto/secp256k1' ;
// Only loads secp256k1.wasm (~50KB)
// Import multiple algorithms
import { secp256k1 , ed25519 } from '@voltaire/crypto' ;
// Loads secp256k1.wasm + ed25519.wasm (~90KB)
Bundle Sizes
Signature Primitive (TypeScript)
Type definitions: ~2KB
Constructors: ~3KB
Conversions: ~2KB
Validation: ~2KB
Utilities: ~1KB
Total: ~10KB (minified + gzipped)
Crypto Module WASM
secp256k1.wasm: ~50KB
p256.wasm: ~35KB
ed25519.wasm: ~20KB
With tree-shaking: Only load what you use
When to Use WASM
Use TypeScript (Signature Primitive)
Format conversions (DER, compact)
Component extraction (getR, getS, getV)
Validation (isCanonical, normalize)
Type checking (is, equals)
Serialization
Reason: These operations are simple byte manipulations, faster in TypeScript.
Use WASM (Crypto Module)
Signing messages
Verifying signatures
Recovering public keys
Key generation
Key derivation
Reason: These operations involve expensive elliptic curve arithmetic.
Migration Guide
Before (hypothetical WASM signature primitive)
// Hypothetical WASM API
const sig = await Signature . fromSecp256k1Wasm ( r , s , v );
const canonical = await Signature . normalizeWasm ( sig );
const der = await Signature . toDERWasm ( sig );
After (actual TypeScript + crypto WASM)
// Signature primitive (TypeScript, no await needed)
const sig = Signature . fromSecp256k1 ( r , s , v );
const canonical = Signature . normalize ( sig );
const der = Signature . toDER ( sig );
// Crypto operations (WASM)
const { r , s , v } = await secp256k1 . sign ( message , privateKey );
const valid = await secp256k1 . verify ( message , r , s , publicKey );
Benefits:
No WASM call overhead for simple operations
Synchronous API for signature primitive
WASM where it matters (crypto operations)
Browser Support
TypeScript (Signature Primitive)
All modern browsers
Node.js 14+
Deno
Bun
No special requirements
WASM (Crypto Module)
Chrome 57+
Firefox 52+
Safari 11+
Edge 16+
Feature detection:
if ( typeof WebAssembly !== 'undefined' ) {
// Use WASM crypto
const { secp256k1 } = await import ( '@voltaire/crypto' );
} else {
// Fallback to pure JavaScript crypto
const { secp256k1 } = await import ( '@voltaire/crypto/js' );
}
See Also