Rust and WASM did-method-plc tools and structures
1# Quick Start: plc-audit WASM Implementation
2
3## What Was Created
4
5A JavaScript implementation of the `plc-audit` binary that uses WebAssembly for all cryptographic operations. This provides the same functionality as the Rust binary but runs in JavaScript/Node.js environments.
6
7### Files Created
8
91. **`wasm/plc-audit.js`** - JavaScript CLI tool (10KB)
102. **`wasm/README.md`** - Comprehensive documentation
113. **`wasm/build.sh`** - Build script for WASM module
124. **`wasm/pkg/`** - Generated WASM module directory (created by build)
13 - `atproto_plc_bg.wasm` - WebAssembly binary (374KB)
14 - `atproto_plc.js` - JavaScript bindings (39KB)
15 - `atproto_plc.d.ts` - TypeScript definitions
16
17### WASM Bindings Enhanced
18
19Enhanced `src/wasm.rs` with new exports:
20- `WasmVerifyingKey` - For creating verifying keys from did:key strings
21- `WasmOperation.prev()` - Get previous operation CID
22- `WasmOperation.signature()` - Get operation signature
23- `WasmOperation.rotationKeys()` - Get rotation keys
24- `WasmOperation.verify()` - Verify signatures
25- `WasmOperation.verifyWithKeyIndex()` - Verify and return which key signed
26
27## How to Build
28
29### Prerequisites
30
31```bash
32# Install wasm-pack (one-time setup)
33cargo install wasm-pack
34
35# Ensure wasm32 target is available
36rustup target add wasm32-unknown-unknown
37```
38
39### Build the WASM Module
40
41```bash
42cd wasm
43./build.sh
44```
45
46This will:
471. Check prerequisites
482. Compile Rust to WebAssembly
493. Generate JavaScript bindings
504. Optimize the WASM binary
515. Output to `wasm/pkg/`
52
53## How to Use
54
55### Basic Usage
56
57```bash
58cd wasm
59
60# Validate a DID (standard output)
61node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur
62
63# Output:
64# 🔍 Fetching audit log for: did:plc:z72i7hdynmk6r22z27h6tvur
65# Source: https://plc.directory
66#
67# 📊 Audit Log Summary:
68# Total operations: 4
69# Genesis operation: bafyreigp6shzy6dlcxuowwoxz7u5nemdrkad2my5zwzpwilcnhih7bw6zm
70# Latest operation: bafyreifn4pkect7nymne3sxkdg7tn7534msyxcjkshmzqtijmn3enyxm3q
71#
72# 🔐 Validating operation chain...
73# ✅ Validation successful!
74#
75# 📄 Final DID State:
76# Rotation keys: 2
77# [0] did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg
78# [1] did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK
79```
80
81### Verbose Mode
82
83Show detailed cryptographic validation steps:
84
85```bash
86node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur --verbose
87```
88
89Output includes:
90- All operations with CIDs and timestamps
91- Step 1: Chain linkage validation (prev reference checking)
92- Step 2: Cryptographic signature validation
93 - Genesis rotation key extraction
94 - Per-operation signature verification
95 - Which specific rotation key verified each signature
96 - Rotation key changes tracked
97
98### Quiet Mode
99
100For scripts and automation:
101
102```bash
103node plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur --quiet
104
105# Output: ✅ VALID
106# Exit code: 0 (success) or 1 (failure)
107```
108
109### Custom PLC Directory
110
111```bash
112node plc-audit.js did:plc:example --plc-url https://custom.plc.directory
113```
114
115## Integration Examples
116
117### Use in Node.js Application
118
119```javascript
120import { WasmDid, WasmOperation, WasmVerifyingKey } from './pkg/atproto_plc.js';
121
122// Parse and validate a DID
123const did = new WasmDid('did:plc:ewvi7nxzyoun6zhxrhs64oiz');
124console.log('Valid DID:', did.did);
125
126// Fetch and validate audit log
127const response = await fetch(`https://plc.directory/${did.did}/log/audit`);
128const auditLog = await response.json();
129
130// Parse operations
131const operations = auditLog.map(entry => ({
132 operation: WasmOperation.fromJson(JSON.stringify(entry.operation)),
133 cid: entry.cid,
134}));
135
136// Validate chain linkage
137for (let i = 1; i < operations.length; i++) {
138 const prev = operations[i].operation.prev();
139 if (prev !== operations[i - 1].cid) {
140 throw new Error('Chain linkage broken at operation ' + i);
141 }
142}
143
144// Validate signatures
145const rotationKeys = operations[0].operation.rotationKeys();
146const verifyingKeys = rotationKeys.map(k => WasmVerifyingKey.fromDidKey(k));
147
148for (let i = 1; i < operations.length; i++) {
149 const keyIndex = operations[i].operation.verifyWithKeyIndex(verifyingKeys);
150 console.log(`Operation ${i} verified with key ${keyIndex}`);
151}
152```
153
154### Use as Executable Script
155
156Add shebang to make it executable:
157
158```bash
159chmod +x plc-audit.js
160./plc-audit.js did:plc:z72i7hdynmk6r22z27h6tvur
161```
162
163## Performance Comparison
164
165| Metric | Rust Binary | WASM/JavaScript |
166|--------|-------------|-----------------|
167| **Validation Time** | ~100-200ms | ~200-500ms |
168| **Binary Size** | 1.5MB (native) | 374KB (WASM) + 39KB (JS) |
169| **Startup Time** | ~10ms | ~50-100ms (WASM init) |
170| **Memory Usage** | ~5MB | ~10MB |
171| **Platform** | Compiled per-platform | Universal |
172
173## Architecture
174
175The implementation divides responsibilities between JavaScript and WASM:
176
177### JavaScript Layer (`plc-audit.js`)
178- Command-line argument parsing (using Node.js `util.parseArgs`)
179- HTTP requests to plc.directory (using `fetch`)
180- Console output formatting with emojis
181- Control flow and orchestration
182- Error handling and reporting
183
184### WASM Layer (Rust compiled to WebAssembly)
185- DID parsing and validation
186- Operation parsing from JSON
187- Cryptographic signature verification
188 - P-256 (secp256r1) ECDSA
189 - secp256k1 ECDSA
190- Rotation key management
191- All security-critical operations
192
193## Troubleshooting
194
195### Build Issues
196
197**Error: `wasm-pack is not installed`**
198```bash
199cargo install wasm-pack
200```
201
202**Error: `wasm32-unknown-unknown target not found`**
203```bash
204rustup target add wasm32-unknown-unknown
205```
206
207**Error: `wasm-opt` bulk memory operations**
208- Already fixed in `Cargo.toml` with `wasm-opt = ["-O", "--enable-bulk-memory"]`
209
210### Runtime Issues
211
212**Error: `Module not found`**
213```bash
214# Ensure WASM module is built
215ls wasm/pkg/atproto_plc_bg.wasm
216
217# If missing, rebuild
218cd wasm && ./build.sh
219```
220
221**Error: `WasmDid.parse is not a function`**
222- Use `new WasmDid(didString)` constructor syntax instead
223
224**Error: `Cannot find module`**
225- Ensure you're running from the `wasm/` directory
226- Or use full paths: `node /path/to/wasm/plc-audit.js ...`
227
228### Node.js Version
229
230Requires Node.js v18 or later for:
231- Native `fetch` support
232- `util.parseArgs` support
233- ES modules support
234
235Check version:
236```bash
237node --version # Should be v18.0.0 or higher
238```
239
240## Next Steps
241
242- See [`wasm/README.md`](./README.md) for comprehensive documentation
243- See [`src/bin/README.md`](../src/bin/README.md) for Rust binary documentation
244- Check [examples](../examples/) for more usage patterns
245- Read the [did:plc specification](https://web.plc.directory/spec/v0.1/did-plc)
246
247## Key Differences from Rust Binary
248
249### Identical
250- ✅ Validation logic and cryptography
251- ✅ Command-line interface and arguments
252- ✅ Output format and messages
253- ✅ Error handling and exit codes
254
255### Different
256- 🔄 2-3x slower performance (acceptable for most use cases)
257- 🔄 Requires Node.js runtime (vs standalone binary)
258- 🔄 Smaller total size (413KB vs 1.5MB)
259- 🔄 Universal (no per-platform compilation)
260
261## License
262
263Dual-licensed under MIT or Apache-2.0, same as the parent library.