# plc-audit WASM Implementation This is a JavaScript implementation of the `plc-audit` binary that uses WebAssembly for cryptographic operations. It fetches and validates DID audit logs from plc.directory. ## Prerequisites - **Rust** (stable toolchain) - **wasm-pack** - Install with: `cargo install wasm-pack` - **Node.js** (v18 or later) - For running the JavaScript tool ## Building ### 1. Build the WASM Module From the project root directory: ```bash # Build WASM module with wasm feature wasm-pack build --target nodejs --out-dir wasm/pkg --features wasm # Or use the provided build script ./wasm/build.sh ``` This will: - Compile the Rust library to WebAssembly - Generate JavaScript bindings - Create a `wasm/pkg/` directory with the WASM module and TypeScript definitions ### 2. Install Node.js Dependencies ```bash cd wasm npm install ``` ## Usage The JavaScript version supports the same command-line interface as the Rust binary: ### Basic Validation Validate a DID and show detailed output: ```bash node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur ``` ### Verbose Mode Show all operations and detailed cryptographic validation steps: ```bash node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur --verbose # or node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur -v ``` Output includes: - Operation index and CID - Creation timestamp - Operation type (Genesis/Update) - Previous operation reference - Step-by-step chain linkage validation - Detailed signature verification with rotation key tracking ### Quiet Mode Only show validation result (useful for scripts): ```bash node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur --quiet # or node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur -q ``` Output: `✅ VALID` or error message ### Custom PLC Directory Use a custom PLC directory server: ```bash node plc-audit.js did:plc:example --plc-url https://custom.plc.directory ``` ## What is Validated? The WASM version performs the same comprehensive validation as the Rust binary: 1. **DID Format Validation** - Checks prefix is `did:plc:` - Verifies identifier is exactly 24 characters - Ensures only valid base32 characters (a-z, 2-7) 2. **Chain Linkage Verification** - First operation must be genesis (prev = null) - Each subsequent operation's `prev` field must match previous operation's CID - No breaks in the chain 3. **Cryptographic Signature Verification** - Each operation's signature is verified using rotation keys - Genesis operation establishes initial rotation keys - Later operations can rotate keys - Identifies which specific rotation key verified each signature ## Example Output ### Standard Mode ``` 🔍 Fetching audit log for: did:plc:z72i7hdynmk6r22z27h6tvur Source: https://plc.directory 📊 Audit Log Summary: Total operations: 4 Genesis operation: bafyreigp6shzy6dlcxuowwoxz7u5nemdrkad2my5zwzpwilcnhih7bw6zm Latest operation: bafyreifn4pkect7nymne3sxkdg7tn7534msyxcjkshmzqtijmn3enyxm3q 🔐 Validating operation chain... ✅ Validation successful! 📄 Final DID State: Rotation keys: 2 [0] did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg [1] did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK ``` ### Verbose Mode Shows detailed step-by-step validation: ``` Step 1: Chain Linkage Validation ================================ [1] Checking prev reference... Expected: bafyreigp6shzy6dlcxuowwoxz7u5nemdrkad2my5zwzpwilcnhih7bw6zm Actual: bafyreigp6shzy6dlcxuowwoxz7u5nemdrkad2my5zwzpwilcnhih7bw6zm ✅ Match - chain link valid [2] Checking prev reference... Expected: bafyreihmuvr3frdvd6vmdhucih277prdcfcezf67lasg5oekxoimnunjoq Actual: bafyreihmuvr3frdvd6vmdhucih277prdcfcezf67lasg5oekxoimnunjoq ✅ Match - chain link valid ... ✅ Chain linkage validation complete Step 2: Cryptographic Signature Validation ========================================== [0] Genesis operation - extracting rotation keys Rotation keys: 2 [0] did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg [1] did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK ⚠️ Genesis signature cannot be verified (bootstrapping trust) [1] Validating signature... CID: bafyreihmuvr3frdvd6vmdhucih277prdcfcezf67lasg5oekxoimnunjoq Signature: 1mEWzRtFOgeRXH-YCSPTxb990JOXxa__n8Qw6BOKl7Ndm6OFFmwYKiiMqMCpAbxpnGjF5abfIsKc7u3a77Cbnw Available rotation keys: 2 [0] did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg [1] did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK Parsed verifying keys: 2/2 ✅ Signature verified with rotation key [1] did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK ... ✅ Cryptographic signature validation complete ``` ## Architecture The WASM implementation divides responsibilities: - **JavaScript** (`plc-audit.js`): - Command-line argument parsing - HTTP requests to plc.directory - Console output formatting - Control flow and orchestration - **WASM** (Rust compiled to WebAssembly): - DID parsing and validation - Operation parsing from JSON - Cryptographic signature verification (P-256 and secp256k1) - Rotation key management - All security-critical operations ## Performance The WASM version has comparable performance to the native Rust binary: - **WASM module size**: ~200KB (optimized) - **Validation time**: ~200-500ms for typical DIDs (4-10 operations) - **Startup overhead**: ~50-100ms for WASM initialization ## Troubleshooting ### Build Errors If you encounter build errors: ```bash # Ensure wasm32-unknown-unknown target is installed rustup target add wasm32-unknown-unknown # Clean and rebuild rm -rf wasm/pkg wasm-pack build --target nodejs --out-dir wasm/pkg --features wasm ``` ### Runtime Errors If you get "Module not found" errors: ```bash # Ensure the WASM module is built ls wasm/pkg/atproto_plc_bg.wasm # If missing, rebuild wasm-pack build --target nodejs --out-dir wasm/pkg --features wasm ``` ### Node.js Version Ensure you're using Node.js v18 or later: ```bash node --version # Should be v18.0.0 or higher ``` ## Comparison with Rust Binary | Feature | Rust Binary | WASM/JavaScript | |---------|-------------|-----------------| | Performance | Native speed | ~2-3x slower | | Binary Size | 1.5MB | ~200KB WASM | | Dependencies | None (static) | Node.js runtime | | Platform | Per-platform compilation | Universal (runs anywhere with Node.js) | | Use Case | Production servers, CLI | Cross-platform, web integration | ## Integration Examples ### Use in a Node.js Application ```javascript import { WasmDid, WasmOperation, WasmVerifyingKey } from './pkg/atproto_plc.js'; async function validateDid(didString) { // Parse DID const did = WasmDid.parse(didString); // Fetch audit log const response = await fetch(`https://plc.directory/${did.did}/log/audit`); const auditLog = await response.json(); // Parse operations const operations = auditLog.map(entry => ({ operation: WasmOperation.fromJson(JSON.stringify(entry.operation)), cid: entry.cid, })); // Validate chain for (let i = 1; i < operations.length; i++) { const prev = operations[i].operation.prev(); if (prev !== operations[i - 1].cid) { throw new Error('Chain linkage broken'); } } return true; } ``` ### Use in Browser (with bundler) ```javascript // Build with web target instead // wasm-pack build --target web --out-dir wasm/pkg --features wasm import init, { WasmDid } from './pkg/atproto_plc.js'; await init(); // Initialize WASM const did = WasmDid.parse('did:plc:ewvi7nxzyoun6zhxrhs64oiz'); console.log('Valid DID:', did.did); ``` ## License Dual-licensed under MIT or Apache-2.0, same as the parent library.