@ruvector/edge-net 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1025 @@
1
+ /**
2
+ * @ruvector/edge-net WASM Core
3
+ *
4
+ * Pure WASM implementation for cross-platform edge support:
5
+ * - Browsers (Chrome, Firefox, Safari, Edge)
6
+ * - Node.js 16+
7
+ * - Deno
8
+ * - Cloudflare Workers
9
+ * - Vercel Edge
10
+ * - Bun
11
+ *
12
+ * Uses ruvector_edge_net WASM module for:
13
+ * - Ed25519 signing/verification
14
+ * - SHA256/SHA512 hashing
15
+ * - Merkle tree operations
16
+ * - Canonical JSON encoding
17
+ *
18
+ * @module @ruvector/edge-net/models/wasm-core
19
+ */
20
+
21
+ // ============================================================================
22
+ // PLATFORM DETECTION
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Detect current runtime environment
27
+ */
28
+ export function detectPlatform() {
29
+ // Cloudflare Workers
30
+ if (typeof caches !== 'undefined' && typeof HTMLRewriter !== 'undefined') {
31
+ return 'cloudflare-workers';
32
+ }
33
+
34
+ // Deno
35
+ if (typeof Deno !== 'undefined') {
36
+ return 'deno';
37
+ }
38
+
39
+ // Bun
40
+ if (typeof Bun !== 'undefined') {
41
+ return 'bun';
42
+ }
43
+
44
+ // Node.js
45
+ if (typeof process !== 'undefined' && process.versions?.node) {
46
+ return 'node';
47
+ }
48
+
49
+ // Browser with WebAssembly
50
+ if (typeof window !== 'undefined' && typeof WebAssembly !== 'undefined') {
51
+ return 'browser';
52
+ }
53
+
54
+ // Generic WebAssembly environment
55
+ if (typeof WebAssembly !== 'undefined') {
56
+ return 'wasm';
57
+ }
58
+
59
+ return 'unknown';
60
+ }
61
+
62
+ /**
63
+ * Platform capabilities
64
+ */
65
+ export function getPlatformCapabilities() {
66
+ const platform = detectPlatform();
67
+
68
+ return {
69
+ platform,
70
+ hasWebAssembly: typeof WebAssembly !== 'undefined',
71
+ hasSIMD: checkSIMDSupport(),
72
+ hasThreads: checkThreadsSupport(),
73
+ hasStreaming: typeof WebAssembly?.compileStreaming === 'function',
74
+ hasIndexedDB: typeof indexedDB !== 'undefined',
75
+ hasWebCrypto: typeof crypto?.subtle !== 'undefined',
76
+ hasP2P: typeof RTCPeerConnection !== 'undefined',
77
+ maxMemory: getMaxMemory(),
78
+ };
79
+ }
80
+
81
+ function checkSIMDSupport() {
82
+ try {
83
+ return WebAssembly.validate(new Uint8Array([
84
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
85
+ 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7b, 0x03,
86
+ 0x02, 0x01, 0x00, 0x0a, 0x0a, 0x01, 0x08, 0x00,
87
+ 0xfd, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b
88
+ ]));
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
94
+ function checkThreadsSupport() {
95
+ try {
96
+ return typeof SharedArrayBuffer !== 'undefined' &&
97
+ typeof Atomics !== 'undefined';
98
+ } catch {
99
+ return false;
100
+ }
101
+ }
102
+
103
+ function getMaxMemory() {
104
+ // Browser
105
+ if (typeof navigator !== 'undefined' && navigator.deviceMemory) {
106
+ return navigator.deviceMemory * 1024 * 1024 * 1024;
107
+ }
108
+
109
+ // Node.js
110
+ if (typeof process !== 'undefined') {
111
+ try {
112
+ const os = require('os');
113
+ return os.totalmem?.() || 4 * 1024 * 1024 * 1024;
114
+ } catch {
115
+ return 4 * 1024 * 1024 * 1024;
116
+ }
117
+ }
118
+
119
+ // Default 4GB
120
+ return 4 * 1024 * 1024 * 1024;
121
+ }
122
+
123
+ // ============================================================================
124
+ // WASM MODULE LOADING
125
+ // ============================================================================
126
+
127
+ let wasmModule = null;
128
+ let wasmInstance = null;
129
+ let wasmReady = false;
130
+
131
+ /**
132
+ * Initialize WASM module with platform-specific loading
133
+ */
134
+ export async function initWasm(options = {}) {
135
+ if (wasmReady && wasmInstance) {
136
+ return wasmInstance;
137
+ }
138
+
139
+ const platform = detectPlatform();
140
+ const capabilities = getPlatformCapabilities();
141
+
142
+ console.log(`[WASM Core] Initializing on ${platform}`);
143
+
144
+ try {
145
+ // Try to import the main WASM module
146
+ const wasmPath = options.wasmPath || findWasmPath();
147
+
148
+ if (capabilities.hasStreaming && platform !== 'cloudflare-workers') {
149
+ // Streaming compilation (faster)
150
+ const response = await fetch(wasmPath);
151
+ wasmModule = await WebAssembly.compileStreaming(response);
152
+ } else {
153
+ // Buffer-based compilation (Workers, fallback)
154
+ const wasmBytes = await loadWasmBytes(wasmPath);
155
+ wasmModule = await WebAssembly.compile(wasmBytes);
156
+ }
157
+
158
+ // Instantiate with imports
159
+ wasmInstance = await WebAssembly.instantiate(wasmModule, getWasmImports());
160
+ wasmReady = true;
161
+
162
+ console.log(`[WASM Core] Ready with ${capabilities.hasSIMD ? 'SIMD' : 'no SIMD'}`);
163
+
164
+ return wasmInstance;
165
+ } catch (error) {
166
+ console.warn(`[WASM Core] Native WASM failed, using JS fallback:`, error.message);
167
+
168
+ // Use JavaScript fallback
169
+ wasmInstance = createJSFallback();
170
+ wasmReady = true;
171
+
172
+ return wasmInstance;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Find WASM file path based on environment
178
+ */
179
+ function findWasmPath() {
180
+ const platform = detectPlatform();
181
+
182
+ switch (platform) {
183
+ case 'node':
184
+ case 'bun':
185
+ return new URL('../ruvector_edge_net_bg.wasm', import.meta.url).href;
186
+ case 'deno':
187
+ return new URL('../ruvector_edge_net_bg.wasm', import.meta.url).href;
188
+ case 'browser':
189
+ // Try multiple paths
190
+ return './ruvector_edge_net_bg.wasm';
191
+ case 'cloudflare-workers':
192
+ // Workers use bundled WASM
193
+ return '__WASM_MODULE__';
194
+ default:
195
+ return './ruvector_edge_net_bg.wasm';
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Load WASM bytes based on platform
201
+ */
202
+ async function loadWasmBytes(path) {
203
+ const platform = detectPlatform();
204
+
205
+ switch (platform) {
206
+ case 'node': {
207
+ // Node 18+ has native fetch, use it for URLs
208
+ if (path.startsWith('http://') || path.startsWith('https://')) {
209
+ const response = await fetch(path);
210
+ return response.arrayBuffer();
211
+ }
212
+ // For file:// URLs or local paths
213
+ const fs = await import('fs/promises');
214
+ const { fileURLToPath } = await import('url');
215
+ // Convert file:// URL to path if needed
216
+ const filePath = path.startsWith('file://')
217
+ ? fileURLToPath(path)
218
+ : path;
219
+ return fs.readFile(filePath);
220
+ }
221
+ case 'deno': {
222
+ return Deno.readFile(path);
223
+ }
224
+ case 'bun': {
225
+ return Bun.file(path).arrayBuffer();
226
+ }
227
+ default: {
228
+ const response = await fetch(path);
229
+ return response.arrayBuffer();
230
+ }
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Shared WASM memory - created once before instantiation
236
+ */
237
+ let sharedMemory = null;
238
+
239
+ function getSharedMemory() {
240
+ if (!sharedMemory) {
241
+ // Reasonable memory limits for edge platforms:
242
+ // initial: 256 pages (16MB), max: 1024 pages (64MB)
243
+ sharedMemory = new WebAssembly.Memory({ initial: 256, maximum: 1024 });
244
+ }
245
+ return sharedMemory;
246
+ }
247
+
248
+ /**
249
+ * WASM imports for the module
250
+ * CRITICAL: Does NOT reference wasmInstance - uses shared memory instead
251
+ */
252
+ function getWasmImports() {
253
+ const memory = getSharedMemory();
254
+
255
+ return {
256
+ env: {
257
+ // Memory - use shared instance created BEFORE wasm instantiation
258
+ memory,
259
+
260
+ // Console - uses shared memory buffer (safe, memory exists)
261
+ console_log: (ptr, len) => {
262
+ const bytes = new Uint8Array(memory.buffer, ptr, len);
263
+ console.log(new TextDecoder().decode(bytes));
264
+ },
265
+ console_error: (ptr, len) => {
266
+ const bytes = new Uint8Array(memory.buffer, ptr, len);
267
+ console.error(new TextDecoder().decode(bytes));
268
+ },
269
+
270
+ // Time
271
+ now_ms: () => Date.now(),
272
+
273
+ // Random - uses shared memory buffer (safe)
274
+ get_random_bytes: (ptr, len) => {
275
+ const bytes = new Uint8Array(memory.buffer, ptr, len);
276
+ crypto.getRandomValues(bytes);
277
+ },
278
+ },
279
+ wasi_snapshot_preview1: {
280
+ // Minimal WASI stubs for compatibility
281
+ fd_write: () => 0,
282
+ fd_read: () => 0,
283
+ fd_close: () => 0,
284
+ environ_get: () => 0,
285
+ environ_sizes_get: () => 0,
286
+ proc_exit: () => {},
287
+ },
288
+ };
289
+ }
290
+
291
+ // ============================================================================
292
+ // JAVASCRIPT FALLBACK
293
+ // ============================================================================
294
+
295
+ /**
296
+ * Pure JavaScript fallback when WASM is unavailable
297
+ */
298
+ function createJSFallback() {
299
+ return {
300
+ exports: {
301
+ // SHA256
302
+ sha256: async (data) => {
303
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
304
+ return new Uint8Array(hashBuffer);
305
+ },
306
+
307
+ // SHA512
308
+ sha512: async (data) => {
309
+ const hashBuffer = await crypto.subtle.digest('SHA-512', data);
310
+ return new Uint8Array(hashBuffer);
311
+ },
312
+
313
+ // Ed25519 (using SubtleCrypto if available)
314
+ // SECURITY: Fail closed - never return mock signatures
315
+ ed25519_sign: async (message, privateKey) => {
316
+ // SubtleCrypto Ed25519 support varies by platform
317
+ try {
318
+ const key = await crypto.subtle.importKey(
319
+ 'raw',
320
+ privateKey,
321
+ { name: 'Ed25519' },
322
+ false,
323
+ ['sign']
324
+ );
325
+ const signature = await crypto.subtle.sign('Ed25519', key, message);
326
+ return new Uint8Array(signature);
327
+ } catch (error) {
328
+ // FAIL CLOSED: Do not return mock signatures - throw error
329
+ throw new Error(`[SECURITY] Ed25519 signing unavailable: ${error.message}. Install tweetnacl for platforms without native Ed25519.`);
330
+ }
331
+ },
332
+
333
+ ed25519_verify: async (message, signature, publicKey) => {
334
+ try {
335
+ const key = await crypto.subtle.importKey(
336
+ 'raw',
337
+ publicKey,
338
+ { name: 'Ed25519' },
339
+ false,
340
+ ['verify']
341
+ );
342
+ return await crypto.subtle.verify('Ed25519', key, signature, message);
343
+ } catch (error) {
344
+ // FAIL CLOSED: If verification unavailable, reject
345
+ console.error('[SECURITY] Ed25519 verify unavailable:', error.message);
346
+ return false; // Reject signature when verification unavailable
347
+ }
348
+ },
349
+
350
+ // Merkle operations (pure JS)
351
+ merkle_root: (hashes) => {
352
+ return computeMerkleRootJS(hashes);
353
+ },
354
+
355
+ // Canonical JSON
356
+ canonical_json: (obj) => {
357
+ return canonicalizeJS(obj);
358
+ },
359
+ },
360
+ };
361
+ }
362
+
363
+ /**
364
+ * Pure JS Merkle root computation
365
+ */
366
+ function computeMerkleRootJS(hashes) {
367
+ if (hashes.length === 0) return new Uint8Array(32);
368
+ if (hashes.length === 1) return hashes[0];
369
+
370
+ let level = [...hashes];
371
+
372
+ while (level.length > 1) {
373
+ const nextLevel = [];
374
+ for (let i = 0; i < level.length; i += 2) {
375
+ const left = level[i];
376
+ const right = level[i + 1] || left;
377
+ // Concatenate and hash
378
+ const combined = new Uint8Array(left.length + right.length);
379
+ combined.set(left, 0);
380
+ combined.set(right, left.length);
381
+ // Use sync hash for fallback
382
+ nextLevel.push(hashSync(combined));
383
+ }
384
+ level = nextLevel;
385
+ }
386
+
387
+ return level[0];
388
+ }
389
+
390
+ /**
391
+ * Synchronous hash for fallback (uses simple hash if crypto.subtle unavailable)
392
+ */
393
+ function hashSync(data) {
394
+ // Simple FNV-1a hash for fallback (NOT cryptographically secure)
395
+ // In production, use a proper sync hash library
396
+ const FNV_PRIME = 0x01000193;
397
+ const FNV_OFFSET = 0x811c9dc5;
398
+
399
+ let hash = FNV_OFFSET;
400
+ for (let i = 0; i < data.length; i++) {
401
+ hash ^= data[i];
402
+ hash = Math.imul(hash, FNV_PRIME);
403
+ }
404
+
405
+ // Expand to 32 bytes (not secure, just for structure)
406
+ const result = new Uint8Array(32);
407
+ for (let i = 0; i < 32; i++) {
408
+ result[i] = (hash >> (i % 4) * 8) & 0xff;
409
+ hash = Math.imul(hash, FNV_PRIME);
410
+ }
411
+
412
+ return result;
413
+ }
414
+
415
+ /**
416
+ * Canonical JSON for JS fallback
417
+ */
418
+ function canonicalizeJS(obj) {
419
+ if (obj === null || obj === undefined) return 'null';
420
+ if (typeof obj === 'boolean') return obj ? 'true' : 'false';
421
+ if (typeof obj === 'number') {
422
+ if (!Number.isFinite(obj)) throw new Error('Cannot canonicalize Infinity/NaN');
423
+ return JSON.stringify(obj);
424
+ }
425
+ if (typeof obj === 'string') {
426
+ return JSON.stringify(obj).replace(/[\u007f-\uffff]/g, (c) =>
427
+ '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
428
+ );
429
+ }
430
+ if (Array.isArray(obj)) {
431
+ return '[' + obj.map(canonicalizeJS).join(',') + ']';
432
+ }
433
+ if (typeof obj === 'object') {
434
+ const keys = Object.keys(obj).sort();
435
+ const pairs = keys
436
+ .filter(k => obj[k] !== undefined)
437
+ .map(k => canonicalizeJS(k) + ':' + canonicalizeJS(obj[k]));
438
+ return '{' + pairs.join(',') + '}';
439
+ }
440
+ throw new Error(`Cannot canonicalize: ${typeof obj}`);
441
+ }
442
+
443
+ // ============================================================================
444
+ // WASM CRYPTO API
445
+ // ============================================================================
446
+
447
+ /**
448
+ * WASM-accelerated cryptographic operations
449
+ */
450
+ export class WasmCrypto {
451
+ constructor() {
452
+ this.ready = false;
453
+ this.instance = null;
454
+ }
455
+
456
+ async init() {
457
+ this.instance = await initWasm();
458
+ this.ready = true;
459
+ return this;
460
+ }
461
+
462
+ /**
463
+ * SHA256 hash
464
+ */
465
+ async sha256(data) {
466
+ if (!this.ready) await this.init();
467
+
468
+ const input = typeof data === 'string'
469
+ ? new TextEncoder().encode(data)
470
+ : new Uint8Array(data);
471
+
472
+ if (this.instance.exports.sha256) {
473
+ return this.instance.exports.sha256(input);
474
+ }
475
+
476
+ // Fallback to SubtleCrypto
477
+ const hash = await crypto.subtle.digest('SHA-256', input);
478
+ return new Uint8Array(hash);
479
+ }
480
+
481
+ /**
482
+ * SHA256 as hex string
483
+ */
484
+ async sha256Hex(data) {
485
+ const hash = await this.sha256(data);
486
+ return Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('');
487
+ }
488
+
489
+ /**
490
+ * Ed25519 sign
491
+ */
492
+ async sign(message, privateKey) {
493
+ if (!this.ready) await this.init();
494
+
495
+ const msgBytes = typeof message === 'string'
496
+ ? new TextEncoder().encode(message)
497
+ : new Uint8Array(message);
498
+
499
+ return this.instance.exports.ed25519_sign(msgBytes, privateKey);
500
+ }
501
+
502
+ /**
503
+ * Ed25519 verify
504
+ */
505
+ async verify(message, signature, publicKey) {
506
+ if (!this.ready) await this.init();
507
+
508
+ const msgBytes = typeof message === 'string'
509
+ ? new TextEncoder().encode(message)
510
+ : new Uint8Array(message);
511
+
512
+ return this.instance.exports.ed25519_verify(msgBytes, signature, publicKey);
513
+ }
514
+
515
+ /**
516
+ * Compute Merkle root from chunk hashes
517
+ */
518
+ async merkleRoot(chunkHashes) {
519
+ if (!this.ready) await this.init();
520
+
521
+ if (this.instance.exports.merkle_root) {
522
+ return this.instance.exports.merkle_root(chunkHashes);
523
+ }
524
+
525
+ // JS fallback
526
+ return computeMerkleRootJS(chunkHashes);
527
+ }
528
+
529
+ /**
530
+ * Canonical JSON encoding
531
+ */
532
+ canonicalize(obj) {
533
+ return canonicalizeJS(obj);
534
+ }
535
+
536
+ /**
537
+ * Hash canonical JSON
538
+ */
539
+ async hashCanonical(obj) {
540
+ const canonical = this.canonicalize(obj);
541
+ return this.sha256Hex(canonical);
542
+ }
543
+ }
544
+
545
+ // ============================================================================
546
+ // WASM MODEL INFERENCE
547
+ // ============================================================================
548
+
549
+ /**
550
+ * WASM-accelerated model inference
551
+ */
552
+ export class WasmInference {
553
+ constructor(options = {}) {
554
+ this.ready = false;
555
+ this.model = null;
556
+ this.crypto = new WasmCrypto();
557
+ this.useSIMD = options.useSIMD ?? true;
558
+ this.useThreads = options.useThreads ?? false;
559
+ }
560
+
561
+ async init() {
562
+ await this.crypto.init();
563
+ this.ready = true;
564
+
565
+ const caps = getPlatformCapabilities();
566
+ console.log(`[WASM Inference] Ready: SIMD=${caps.hasSIMD}, Threads=${caps.hasThreads}`);
567
+
568
+ return this;
569
+ }
570
+
571
+ /**
572
+ * Load ONNX model into WASM runtime
573
+ */
574
+ async loadModel(modelData, manifest) {
575
+ if (!this.ready) await this.init();
576
+
577
+ // Verify model integrity first
578
+ const hash = await this.crypto.sha256Hex(modelData);
579
+ // Support both manifest formats: artifacts.model.sha256 and artifacts[0].sha256
580
+ const expected = manifest.artifacts?.model?.sha256 ||
581
+ manifest.artifacts?.[0]?.sha256 ||
582
+ manifest.model?.sha256;
583
+
584
+ if (expected && hash !== expected) {
585
+ throw new Error(`Model hash mismatch: ${hash} !== ${expected}`);
586
+ }
587
+
588
+ // In production, this would initialize ONNX runtime in WASM
589
+ // For now, we store the model data
590
+ this.model = {
591
+ data: modelData,
592
+ manifest,
593
+ loadedAt: Date.now(),
594
+ };
595
+
596
+ return this;
597
+ }
598
+
599
+ /**
600
+ * Run inference (placeholder for ONNX WASM runtime)
601
+ */
602
+ async infer(input, options = {}) {
603
+ if (!this.model) {
604
+ throw new Error('No model loaded');
605
+ }
606
+
607
+ // In production, this would call ONNX WASM runtime
608
+ // For now, return placeholder
609
+ console.log('[WASM Inference] Would run inference on:', typeof input);
610
+
611
+ return {
612
+ output: null,
613
+ timeMs: 0,
614
+ platform: detectPlatform(),
615
+ };
616
+ }
617
+
618
+ /**
619
+ * Generate embeddings
620
+ */
621
+ async embed(texts) {
622
+ if (!this.model) {
623
+ throw new Error('No model loaded');
624
+ }
625
+
626
+ const inputTexts = Array.isArray(texts) ? texts : [texts];
627
+
628
+ // Placeholder - in production, run through ONNX
629
+ const embeddings = inputTexts.map(text => {
630
+ // Generate deterministic pseudo-embedding from text hash
631
+ const hash = this.crypto.canonicalize(text);
632
+ const embedding = new Float32Array(384);
633
+ for (let i = 0; i < 384; i++) {
634
+ embedding[i] = (hash.charCodeAt(i % hash.length) - 64) / 64;
635
+ }
636
+ return embedding;
637
+ });
638
+
639
+ return {
640
+ embeddings,
641
+ model: this.model.manifest?.model?.id || 'unknown',
642
+ platform: detectPlatform(),
643
+ };
644
+ }
645
+
646
+ /**
647
+ * Unload model and free memory
648
+ */
649
+ unload() {
650
+ this.model = null;
651
+ }
652
+ }
653
+
654
+ // ============================================================================
655
+ // GENESIS BIRTHING SYSTEM (WASM)
656
+ // ============================================================================
657
+
658
+ /**
659
+ * WASM-native network genesis/birthing system
660
+ *
661
+ * Creates new network instances with:
662
+ * - Cryptographic identity (Ed25519 keypair)
663
+ * - Lineage tracking (Merkle DAG)
664
+ * - Cross-platform compatibility
665
+ * - Cryptographic signing of genesis blocks
666
+ */
667
+ export class WasmGenesis {
668
+ constructor(options = {}) {
669
+ this.crypto = new WasmCrypto();
670
+ this.ready = false;
671
+
672
+ // Genesis configuration
673
+ this.config = {
674
+ networkName: options.networkName || 'edge-net',
675
+ version: options.version || '1.0.0',
676
+ parentId: options.parentId || null,
677
+ traits: options.traits || {},
678
+ };
679
+
680
+ // Network keypair (generated during birth)
681
+ this.keypair = null;
682
+ }
683
+
684
+ async init() {
685
+ await this.crypto.init();
686
+ this.ready = true;
687
+ return this;
688
+ }
689
+
690
+ /**
691
+ * Generate Ed25519 keypair for network identity
692
+ * SECURITY: Uses WebCrypto for key generation
693
+ */
694
+ async _generateKeypair() {
695
+ try {
696
+ const keyPair = await crypto.subtle.generateKey(
697
+ { name: 'Ed25519' },
698
+ true, // extractable for export
699
+ ['sign', 'verify']
700
+ );
701
+
702
+ // Export public key
703
+ const publicKeyRaw = await crypto.subtle.exportKey('raw', keyPair.publicKey);
704
+
705
+ return {
706
+ privateKey: keyPair.privateKey,
707
+ publicKey: keyPair.publicKey,
708
+ publicKeyBytes: new Uint8Array(publicKeyRaw),
709
+ publicKeyHex: Array.from(new Uint8Array(publicKeyRaw))
710
+ .map(b => b.toString(16).padStart(2, '0'))
711
+ .join(''),
712
+ };
713
+ } catch (error) {
714
+ throw new Error(`[SECURITY] Cannot generate Ed25519 keypair: ${error.message}. Native Ed25519 required for genesis.`);
715
+ }
716
+ }
717
+
718
+ /**
719
+ * Sign data with network private key
720
+ */
721
+ async _signWithKeypair(data, keypair) {
722
+ const dataBytes = typeof data === 'string'
723
+ ? new TextEncoder().encode(data)
724
+ : new Uint8Array(data);
725
+
726
+ try {
727
+ const signature = await crypto.subtle.sign(
728
+ { name: 'Ed25519' },
729
+ keypair.privateKey,
730
+ dataBytes
731
+ );
732
+
733
+ return {
734
+ signature: new Uint8Array(signature),
735
+ signatureHex: Array.from(new Uint8Array(signature))
736
+ .map(b => b.toString(16).padStart(2, '0'))
737
+ .join(''),
738
+ };
739
+ } catch (error) {
740
+ throw new Error(`[SECURITY] Signing failed: ${error.message}`);
741
+ }
742
+ }
743
+
744
+ /**
745
+ * Birth a new network instance with cryptographic signing
746
+ */
747
+ async birthNetwork(options = {}) {
748
+ if (!this.ready) await this.init();
749
+
750
+ const timestamp = Date.now();
751
+
752
+ // Generate network keypair
753
+ this.keypair = await this._generateKeypair();
754
+
755
+ // Generate network identity
756
+ const networkId = await this._generateNetworkId(timestamp);
757
+
758
+ // Create genesis block (unsigned payload)
759
+ const genesisBlock = {
760
+ networkId,
761
+ version: this.config.version,
762
+ birthTimestamp: timestamp,
763
+ parentId: this.config.parentId,
764
+ traits: {
765
+ ...this.config.traits,
766
+ ...options.traits,
767
+ },
768
+ capabilities: options.capabilities || ['embed', 'generate'],
769
+ platform: detectPlatform(),
770
+ platformCapabilities: getPlatformCapabilities(),
771
+ // Include public key for verification
772
+ publicKey: this.keypair.publicKeyHex,
773
+ keyAlgorithm: 'Ed25519',
774
+ };
775
+
776
+ // Compute canonical hash of genesis block
777
+ const genesisCanonical = this.crypto.canonicalize(genesisBlock);
778
+ const genesisHash = await this.crypto.sha256Hex(genesisCanonical);
779
+
780
+ // SECURITY: Sign the genesis hash with network keypair
781
+ const { signature, signatureHex } = await this._signWithKeypair(genesisHash, this.keypair);
782
+
783
+ // Create network manifest with signature
784
+ const manifest = {
785
+ schemaVersion: '2.0.0',
786
+ genesis: genesisBlock,
787
+ integrity: {
788
+ genesisHash,
789
+ signatureAlgorithm: 'Ed25519',
790
+ signature: signatureHex,
791
+ signedPayload: 'genesis',
792
+ merkleRoot: await this.crypto.merkleRoot([
793
+ await this.crypto.sha256(genesisCanonical),
794
+ ]),
795
+ },
796
+ lineage: this.config.parentId ? {
797
+ parentId: this.config.parentId,
798
+ generation: options.generation || 1,
799
+ inheritedTraits: options.inheritedTraits || [],
800
+ } : null,
801
+ };
802
+
803
+ return {
804
+ networkId,
805
+ manifest,
806
+ genesisHash,
807
+ signature: signatureHex,
808
+ publicKey: this.keypair.publicKeyHex,
809
+ platform: detectPlatform(),
810
+ };
811
+ }
812
+
813
+ /**
814
+ * Generate unique network ID using cryptographic randomness
815
+ * SECURITY: Uses crypto.getRandomValues instead of Math.random()
816
+ */
817
+ async _generateNetworkId(timestamp) {
818
+ // Generate 16 bytes of cryptographic randomness
819
+ const randomBytes = new Uint8Array(16);
820
+ crypto.getRandomValues(randomBytes);
821
+ const randomHex = Array.from(randomBytes)
822
+ .map(b => b.toString(16).padStart(2, '0'))
823
+ .join('');
824
+
825
+ const seed = `${this.config.networkName}:${timestamp}:${randomHex}`;
826
+ const hash = await this.crypto.sha256Hex(seed);
827
+ return `net_${hash.slice(0, 16)}`;
828
+ }
829
+
830
+ /**
831
+ * Verify a network's genesis signature
832
+ * SECURITY: Validates cryptographic signature of genesis block
833
+ */
834
+ async verifyGenesis(manifest) {
835
+ const genesis = manifest.genesis;
836
+ const integrity = manifest.integrity;
837
+
838
+ if (!genesis.publicKey || !integrity.signature) {
839
+ return { valid: false, error: 'Missing public key or signature' };
840
+ }
841
+
842
+ try {
843
+ // Reconstruct the canonical hash
844
+ const genesisCanonical = this.crypto.canonicalize(genesis);
845
+ const genesisHash = await this.crypto.sha256Hex(genesisCanonical);
846
+
847
+ // Verify hash matches
848
+ if (genesisHash !== integrity.genesisHash) {
849
+ return { valid: false, error: 'Genesis hash mismatch' };
850
+ }
851
+
852
+ // Convert hex strings back to bytes
853
+ const publicKeyBytes = new Uint8Array(
854
+ genesis.publicKey.match(/.{2}/g).map(b => parseInt(b, 16))
855
+ );
856
+ const signatureBytes = new Uint8Array(
857
+ integrity.signature.match(/.{2}/g).map(b => parseInt(b, 16))
858
+ );
859
+ const hashBytes = new TextEncoder().encode(genesisHash);
860
+
861
+ // Import public key and verify
862
+ const publicKey = await crypto.subtle.importKey(
863
+ 'raw',
864
+ publicKeyBytes,
865
+ { name: 'Ed25519' },
866
+ false,
867
+ ['verify']
868
+ );
869
+
870
+ const valid = await crypto.subtle.verify(
871
+ { name: 'Ed25519' },
872
+ publicKey,
873
+ signatureBytes,
874
+ hashBytes
875
+ );
876
+
877
+ return { valid, genesisHash };
878
+ } catch (error) {
879
+ return { valid: false, error: `Verification failed: ${error.message}` };
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Verify a network's lineage with cryptographic validation
885
+ */
886
+ async verifyLineage(manifest, parentManifest = null) {
887
+ // First verify genesis signature
888
+ const genesisResult = await this.verifyGenesis(manifest);
889
+ if (!genesisResult.valid) {
890
+ return { valid: false, error: `Genesis invalid: ${genesisResult.error}` };
891
+ }
892
+
893
+ if (!manifest.lineage) {
894
+ return { valid: true, isRoot: true, genesisVerified: true };
895
+ }
896
+
897
+ if (!parentManifest) {
898
+ return { valid: false, error: 'Parent manifest required for lineage verification' };
899
+ }
900
+
901
+ // Verify parent genesis signature
902
+ const parentGenesisResult = await this.verifyGenesis(parentManifest);
903
+ if (!parentGenesisResult.valid) {
904
+ return { valid: false, error: `Parent genesis invalid: ${parentGenesisResult.error}` };
905
+ }
906
+
907
+ // Verify parent ID matches
908
+ if (manifest.lineage.parentId !== parentManifest.genesis.networkId) {
909
+ return { valid: false, error: 'Parent ID mismatch' };
910
+ }
911
+
912
+ // Verify generation is sequential
913
+ const parentGen = parentManifest.lineage?.generation || 0;
914
+ if (manifest.lineage.generation !== parentGen + 1) {
915
+ return { valid: false, error: 'Generation sequence broken' };
916
+ }
917
+
918
+ return {
919
+ valid: true,
920
+ parentId: manifest.lineage.parentId,
921
+ generation: manifest.lineage.generation,
922
+ genesisVerified: true,
923
+ parentVerified: true,
924
+ };
925
+ }
926
+
927
+ /**
928
+ * Create a child network (reproduction)
929
+ */
930
+ async reproduce(parentManifest, options = {}) {
931
+ if (!this.ready) await this.init();
932
+
933
+ // Mutate traits from parent
934
+ const mutatedTraits = this._mutateTraits(
935
+ parentManifest.genesis.traits,
936
+ options.mutationRate || 0.1
937
+ );
938
+
939
+ // Birth child network
940
+ const child = await this.birthNetwork({
941
+ traits: mutatedTraits,
942
+ capabilities: options.capabilities || parentManifest.genesis.capabilities,
943
+ generation: (parentManifest.lineage?.generation || 0) + 1,
944
+ inheritedTraits: Object.keys(parentManifest.genesis.traits),
945
+ });
946
+
947
+ // Update config for lineage
948
+ child.manifest.lineage = {
949
+ parentId: parentManifest.genesis.networkId,
950
+ generation: (parentManifest.lineage?.generation || 0) + 1,
951
+ inheritedTraits: Object.keys(parentManifest.genesis.traits),
952
+ mutatedTraits: Object.keys(mutatedTraits).filter(
953
+ k => mutatedTraits[k] !== parentManifest.genesis.traits[k]
954
+ ),
955
+ };
956
+
957
+ return child;
958
+ }
959
+
960
+ /**
961
+ * Mutate traits for evolution using cryptographic randomness
962
+ * SECURITY: Uses crypto.getRandomValues for unpredictable mutations
963
+ */
964
+ _mutateTraits(parentTraits, mutationRate) {
965
+ const mutated = { ...parentTraits };
966
+
967
+ // Generate random bytes for mutation decisions
968
+ const randomBytes = new Uint8Array(Object.keys(mutated).length * 2);
969
+ crypto.getRandomValues(randomBytes);
970
+
971
+ let idx = 0;
972
+ for (const [key, value] of Object.entries(mutated)) {
973
+ // Use crypto random for mutation probability check
974
+ const shouldMutate = (randomBytes[idx++] / 255) < mutationRate;
975
+
976
+ if (typeof value === 'number' && shouldMutate) {
977
+ // Use crypto random for mutation amount (+/- 10%)
978
+ const mutationFactor = ((randomBytes[idx++] / 255) - 0.5) * 0.2;
979
+ mutated[key] = value * (1 + mutationFactor);
980
+ } else {
981
+ idx++; // Skip unused random byte
982
+ }
983
+ }
984
+
985
+ return mutated;
986
+ }
987
+ }
988
+
989
+ // ============================================================================
990
+ // SINGLETON INSTANCES
991
+ // ============================================================================
992
+
993
+ let cryptoInstance = null;
994
+ let genesisInstance = null;
995
+
996
+ export async function getCrypto() {
997
+ if (!cryptoInstance) {
998
+ cryptoInstance = new WasmCrypto();
999
+ await cryptoInstance.init();
1000
+ }
1001
+ return cryptoInstance;
1002
+ }
1003
+
1004
+ export async function getGenesis(options = {}) {
1005
+ if (!genesisInstance) {
1006
+ genesisInstance = new WasmGenesis(options);
1007
+ await genesisInstance.init();
1008
+ }
1009
+ return genesisInstance;
1010
+ }
1011
+
1012
+ // ============================================================================
1013
+ // EXPORTS
1014
+ // ============================================================================
1015
+
1016
+ export default {
1017
+ detectPlatform,
1018
+ getPlatformCapabilities,
1019
+ initWasm,
1020
+ WasmCrypto,
1021
+ WasmInference,
1022
+ WasmGenesis,
1023
+ getCrypto,
1024
+ getGenesis,
1025
+ };