yakmesh 2.8.2 → 3.0.0

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.
Files changed (232) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/Caddyfile +77 -0
  4. package/README.md +119 -29
  5. package/adapters/adapter-mlv-bible/README.md +124 -0
  6. package/adapters/adapter-mlv-bible/index.js +400 -0
  7. package/adapters/chat-mod-adapter.js +532 -0
  8. package/adapters/content-adapter.js +273 -0
  9. package/content/api.js +50 -41
  10. package/content/index.js +2 -2
  11. package/content/store.js +355 -173
  12. package/dashboard/index.html +19 -3
  13. package/database/replication.js +117 -37
  14. package/docs/CRYPTO-AGILITY.md +204 -0
  15. package/docs/MTLS-RESEARCH.md +367 -0
  16. package/docs/NAMCHE-SPEC.md +681 -0
  17. package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
  18. package/docs/PRECISION-DISCLOSURE.md +96 -0
  19. package/docs/README.md +76 -0
  20. package/docs/ROADMAP-2.4.0.md +447 -0
  21. package/docs/ROADMAP-2.5.0.md +244 -0
  22. package/docs/SECURITY-AUDIT-REPORT.md +306 -0
  23. package/docs/SST-INTEGRATION.md +712 -0
  24. package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
  25. package/docs/TERNARY-AUDIT-REPORT.md +247 -0
  26. package/docs/TME-FAQ.md +221 -0
  27. package/docs/WHITEPAPER.md +623 -0
  28. package/docs/adapters.html +1001 -0
  29. package/docs/advanced-systems.html +1045 -0
  30. package/docs/annex.html +1046 -0
  31. package/docs/api.html +970 -0
  32. package/docs/business/response-templates.md +160 -0
  33. package/docs/c2c.html +1225 -0
  34. package/docs/cli.html +1332 -0
  35. package/docs/configuration.html +1248 -0
  36. package/docs/darshan.html +1085 -0
  37. package/docs/dharma.html +966 -0
  38. package/docs/docs-bundle.html +1075 -0
  39. package/docs/docs.css +3120 -0
  40. package/docs/docs.js +556 -0
  41. package/docs/doko.html +969 -0
  42. package/docs/geo-proof.html +858 -0
  43. package/docs/getting-started.html +840 -0
  44. package/docs/gumba-tutorial.html +1144 -0
  45. package/docs/gumba.html +1098 -0
  46. package/docs/index.html +914 -0
  47. package/docs/jhilke.html +1312 -0
  48. package/docs/karma.html +1100 -0
  49. package/docs/katha.html +1037 -0
  50. package/docs/lama.html +978 -0
  51. package/docs/mandala.html +1067 -0
  52. package/docs/mani.html +964 -0
  53. package/docs/mantra.html +967 -0
  54. package/docs/mesh.html +1409 -0
  55. package/docs/nakpak.html +869 -0
  56. package/docs/namche.html +928 -0
  57. package/docs/nav-order.json +53 -0
  58. package/docs/prahari.html +1043 -0
  59. package/docs/prism-bash.min.js +1 -0
  60. package/docs/prism-javascript.min.js +1 -0
  61. package/docs/prism-json.min.js +1 -0
  62. package/docs/prism-tomorrow.min.css +1 -0
  63. package/docs/prism.min.js +1 -0
  64. package/docs/privacy.html +699 -0
  65. package/docs/quick-reference.html +1181 -0
  66. package/docs/sakshi.html +1402 -0
  67. package/docs/sandboxing.md +386 -0
  68. package/docs/seva.html +911 -0
  69. package/docs/sherpa.html +871 -0
  70. package/docs/studio.html +860 -0
  71. package/docs/stupa.html +995 -0
  72. package/docs/tailwind.min.css +2 -0
  73. package/docs/tattva.html +1332 -0
  74. package/docs/terms.html +686 -0
  75. package/docs/time-server-deployment.md +166 -0
  76. package/docs/time-sources.html +1392 -0
  77. package/docs/tivra.html +1127 -0
  78. package/docs/trademark-policy.html +686 -0
  79. package/docs/tribhuj.html +1183 -0
  80. package/docs/trust-security.html +1029 -0
  81. package/docs/tutorials/backup-recovery.html +654 -0
  82. package/docs/tutorials/dashboard.html +604 -0
  83. package/docs/tutorials/domain-setup.html +605 -0
  84. package/docs/tutorials/host-website.html +456 -0
  85. package/docs/tutorials/mesh-network.html +505 -0
  86. package/docs/tutorials/mobile-access.html +445 -0
  87. package/docs/tutorials/privacy.html +467 -0
  88. package/docs/tutorials/raspberry-pi.html +600 -0
  89. package/docs/tutorials/security-basics.html +539 -0
  90. package/docs/tutorials/share-files.html +431 -0
  91. package/docs/tutorials/troubleshooting.html +637 -0
  92. package/docs/tutorials/trust-karma.html +419 -0
  93. package/docs/tutorials/yak-protocol.html +456 -0
  94. package/docs/tutorials.html +1034 -0
  95. package/docs/vani.html +1270 -0
  96. package/docs/webserver.html +809 -0
  97. package/docs/yak-protocol.html +940 -0
  98. package/docs/yak-timeserver-design.md +475 -0
  99. package/docs/yakapp.html +1015 -0
  100. package/docs/ypc27.html +1069 -0
  101. package/docs/yurt.html +1344 -0
  102. package/embedded-docs/bundle.js +334 -74
  103. package/gossip/protocol.js +247 -27
  104. package/identity/key-resolver.js +262 -0
  105. package/identity/machine-seed.js +632 -0
  106. package/identity/node-key.js +669 -368
  107. package/identity/tribhuj-ratchet.js +506 -0
  108. package/knowledge-base.js +37 -8
  109. package/launcher/yakmesh.bat +62 -0
  110. package/launcher/yakmesh.sh +70 -0
  111. package/mesh/annex.js +462 -108
  112. package/mesh/beacon-broadcast.js +113 -1
  113. package/mesh/darshan.js +1718 -0
  114. package/mesh/gumba.js +1567 -0
  115. package/mesh/jhilke.js +651 -0
  116. package/mesh/katha.js +1012 -0
  117. package/mesh/nakpak-routing.js +8 -5
  118. package/mesh/network.js +724 -34
  119. package/mesh/pulse-sync.js +4 -1
  120. package/mesh/rate-limiter.js +127 -15
  121. package/mesh/seva.js +526 -0
  122. package/mesh/sherpa-discovery.js +89 -8
  123. package/mesh/sybil-defense.js +19 -5
  124. package/mesh/temporal-encoder.js +4 -3
  125. package/mesh/vani.js +1364 -0
  126. package/mesh/yurt.js +1340 -0
  127. package/models/entropy-sentinel.onnx +0 -0
  128. package/models/karma-trust.onnx +0 -0
  129. package/models/manifest.json +43 -0
  130. package/models/sakshi-anomaly.onnx +0 -0
  131. package/oracle/code-proof-protocol.js +7 -6
  132. package/oracle/codebase-lock.js +257 -28
  133. package/oracle/index.js +74 -15
  134. package/oracle/ma902-snmp.js +678 -0
  135. package/oracle/module-sealer.js +5 -3
  136. package/oracle/network-identity.js +16 -0
  137. package/oracle/packet-checksum.js +201 -0
  138. package/oracle/sst.js +579 -0
  139. package/oracle/ternary-144t.js +714 -0
  140. package/oracle/ternary-ml.js +481 -0
  141. package/oracle/time-api.js +239 -0
  142. package/oracle/time-source.js +137 -47
  143. package/oracle/validation-oracle-hardened.js +1111 -1071
  144. package/oracle/validation-oracle.js +4 -2
  145. package/oracle/ypc27.js +211 -0
  146. package/package.json +20 -3
  147. package/protocol/yak-handler.js +35 -9
  148. package/protocol/yak-protocol.js +28 -13
  149. package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
  150. package/reference/cpp/yakmesh_ypc27.cpp +179 -0
  151. package/sbom.json +87 -0
  152. package/scripts/security-audit.mjs +264 -0
  153. package/scripts/update-docs-nav.js +194 -0
  154. package/scripts/update-docs-sidebar.cjs +164 -0
  155. package/security/crypto-config.js +4 -3
  156. package/security/dharma-moderation.js +517 -0
  157. package/security/doko-identity.js +193 -143
  158. package/security/domain-consensus.js +86 -85
  159. package/security/fs-hardening.js +620 -0
  160. package/security/hardware-attestation.js +5 -3
  161. package/security/hybrid-trust.js +227 -87
  162. package/security/karma-rate-limiter.js +692 -0
  163. package/security/khata-protocol.js +22 -21
  164. package/security/khata-trust-integration.js +277 -150
  165. package/security/memory-safety.js +635 -0
  166. package/security/mesh-auth.js +11 -10
  167. package/security/mesh-revocation.js +373 -5
  168. package/security/namche-gateway.js +298 -69
  169. package/security/sakshi.js +460 -3
  170. package/security/sangha.js +770 -0
  171. package/security/secure-config.js +473 -0
  172. package/security/silicon-parity.js +13 -10
  173. package/security/steadywatch.js +1142 -0
  174. package/security/strike-system.js +32 -3
  175. package/security/temporal-signing.js +488 -0
  176. package/security/trit-commitment.js +464 -0
  177. package/server/crypto/annex.js +247 -0
  178. package/server/darshan-api.js +343 -0
  179. package/server/index.js +3259 -362
  180. package/server/komm-api.js +668 -0
  181. package/utils/accel.js +2273 -0
  182. package/utils/ternary-id.js +79 -0
  183. package/utils/verify-worker.js +57 -0
  184. package/webserver/index.js +95 -5
  185. package/assets/yakmesh-logo.png +0 -0
  186. package/assets/yakmesh-logo.svg +0 -80
  187. package/assets/yakmesh-logo2.png +0 -0
  188. package/assets/yakmesh-logo2sm.png +0 -0
  189. package/assets/ymsm.png +0 -0
  190. package/website/assets/silhouettes/adapters.svg +0 -107
  191. package/website/assets/silhouettes/api-endpoints.svg +0 -115
  192. package/website/assets/silhouettes/atomic-clock.svg +0 -83
  193. package/website/assets/silhouettes/base-camp.svg +0 -81
  194. package/website/assets/silhouettes/bridge.svg +0 -69
  195. package/website/assets/silhouettes/docs-bundle.svg +0 -113
  196. package/website/assets/silhouettes/doko-basket.svg +0 -70
  197. package/website/assets/silhouettes/fortress.svg +0 -93
  198. package/website/assets/silhouettes/gateway.svg +0 -54
  199. package/website/assets/silhouettes/gears.svg +0 -93
  200. package/website/assets/silhouettes/globe-satellite.svg +0 -67
  201. package/website/assets/silhouettes/karma-wheel.svg +0 -137
  202. package/website/assets/silhouettes/lama-council.svg +0 -141
  203. package/website/assets/silhouettes/mandala-network.svg +0 -169
  204. package/website/assets/silhouettes/mani-stones.svg +0 -149
  205. package/website/assets/silhouettes/mantra-wheel.svg +0 -116
  206. package/website/assets/silhouettes/mesh-nodes.svg +0 -113
  207. package/website/assets/silhouettes/nakpak.svg +0 -56
  208. package/website/assets/silhouettes/peak-lightning.svg +0 -73
  209. package/website/assets/silhouettes/sherpa.svg +0 -69
  210. package/website/assets/silhouettes/stupa-tower.svg +0 -119
  211. package/website/assets/silhouettes/tattva-eye.svg +0 -78
  212. package/website/assets/silhouettes/terminal.svg +0 -74
  213. package/website/assets/silhouettes/webserver.svg +0 -145
  214. package/website/assets/silhouettes/yak.svg +0 -78
  215. package/website/assets/yakmesh-logo.png +0 -0
  216. package/website/assets/yakmesh-logo.webp +0 -0
  217. package/website/assets/yakmesh-logo128x140.webp +0 -0
  218. package/website/assets/yakmesh-logo2.png +0 -0
  219. package/website/assets/yakmesh-logo2.svg +0 -51
  220. package/website/assets/yakmesh-logo40x44.webp +0 -0
  221. package/website/assets/yakmesh.gif +0 -0
  222. package/website/assets/yakmesh.ico +0 -0
  223. package/website/assets/yakmesh.jpg +0 -0
  224. package/website/assets/yakmesh.pdf +0 -0
  225. package/website/assets/yakmesh.png +0 -0
  226. package/website/assets/yakmesh.svg +0 -70
  227. package/website/assets/yakmesh128.webp +0 -0
  228. package/website/assets/yakmesh32.png +0 -0
  229. package/website/assets/yakmesh32.svg +0 -65
  230. package/website/assets/yakmesh32o.ico +0 -2
  231. package/website/assets/yakmesh32o.svg +0 -65
  232. package/website/assets/yakmesh32o.svgz +0 -0
@@ -59,7 +59,8 @@
59
59
  */
60
60
 
61
61
  import { sha3_256 } from '@noble/hashes/sha3.js';
62
- import { bytesToHex, utf8ToBytes, randomBytes } from '@noble/hashes/utils.js';
62
+ import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';
63
+ import { ternaryId } from '../utils/ternary-id.js';
63
64
  import { EventEmitter } from 'events';
64
65
 
65
66
  /**
@@ -69,43 +70,43 @@ const DEFAULT_CONFIG = {
69
70
  // Quorum settings
70
71
  quorumSize: 3, // Minimum verifiers needed for consensus
71
72
  verifiersToRequest: 5, // Request from more than quorum (some may fail)
72
-
73
+
73
74
  // Timeouts
74
75
  verificationTimeout: 30000, // 30 seconds per verification
75
76
  totalTimeout: 120000, // 2 minutes for entire process
76
-
77
+
77
78
  // Retry settings
78
79
  maxRetries: 2,
79
80
  retryDelay: 5000,
80
-
81
+
81
82
  // Beacon requirements
82
83
  beaconPath: '/.well-known/yakmesh/beacon',
83
84
  beaconMaxAge: 300000, // Beacon must be < 5 minutes old
84
-
85
+
85
86
  // Rate limiting
86
87
  maxConcurrentVerifications: 10,
87
88
  cooldownBetweenClaims: 3600000, // 1 hour between claims for same domain
88
-
89
+
89
90
  // ═══════════════════════════════════════════════════════════════════════════
90
91
  // SYBIL DEFENSE CONFIGURATION
91
92
  // ═══════════════════════════════════════════════════════════════════════════
92
-
93
+
93
94
  // Verifier age requirements
94
95
  minVerifierAge: 7 * 24 * 60 * 60 * 1000, // 7 days minimum mesh presence
95
96
  preferredVerifierAge: 30 * 24 * 60 * 60 * 1000, // 30 days for bonus weight
96
-
97
+
97
98
  // IP/ASN diversity requirements
98
99
  minDistinctSubnets: 3, // Minimum different /24 subnets
99
100
  minDistinctASNs: 2, // Minimum different ASNs (Autonomous Systems)
100
101
  subnetMaskBits: 24, // /24 subnet grouping (256 IPs per group)
101
-
102
+
102
103
  // Claimant exclusion radius
103
104
  claimantExclusionSubnet: 16, // Exclude verifiers in same /16 as claimant
104
-
105
+
105
106
  // Reputation thresholds
106
107
  minReputationScore: 0.2, // Minimum reputation to be eligible (0-1)
107
108
  reputationWeightFactor: 2.0, // Higher reputation = more likely selected
108
-
109
+
109
110
  // Time-based verification windows
110
111
  enableTimeWindows: false, // When true, verify at T, T+1hr, T+24hr
111
112
  timeWindowIntervals: [0, 3600000, 86400000], // 0, 1 hour, 24 hours
@@ -135,13 +136,13 @@ const DEFAULT_CONFIG = {
135
136
  class VerifierEligibilityChecker {
136
137
  constructor(config = {}) {
137
138
  this.config = { ...DEFAULT_CONFIG, ...config };
138
-
139
+
139
140
  // Node reputation store (nodeId -> reputation data)
140
141
  this.reputations = new Map();
141
-
142
+
142
143
  // Node first-seen timestamps (nodeId -> timestamp)
143
144
  this.nodeFirstSeen = new Map();
144
-
145
+
145
146
  // Node network info cache (nodeId -> { ip, asn, subnet })
146
147
  this.nodeNetworkInfo = new Map();
147
148
  }
@@ -153,7 +154,7 @@ class VerifierEligibilityChecker {
153
154
  if (!this.nodeFirstSeen.has(nodeId)) {
154
155
  this.nodeFirstSeen.set(nodeId, Date.now());
155
156
  }
156
-
157
+
157
158
  if (networkInfo.ip) {
158
159
  this.nodeNetworkInfo.set(nodeId, {
159
160
  ip: networkInfo.ip,
@@ -194,14 +195,14 @@ class VerifierEligibilityChecker {
194
195
  getReputationScore(nodeId) {
195
196
  const rep = this.reputations.get(nodeId);
196
197
  if (!rep) return 0.5; // Neutral for unknown nodes
197
-
198
+
198
199
  const total = rep.successCount + rep.failureCount;
199
200
  if (total === 0) return 0.5;
200
-
201
+
201
202
  // Success ratio weighted by volume (more history = more reliable score)
202
203
  const successRatio = rep.successCount / total;
203
204
  const volumeWeight = Math.min(1, total / 20); // Full weight at 20+ verifications
204
-
205
+
205
206
  // Blend toward neutral for low-volume nodes
206
207
  return 0.5 + (successRatio - 0.5) * volumeWeight;
207
208
  }
@@ -239,7 +240,7 @@ class VerifierEligibilityChecker {
239
240
  if (claimantInfo.ip) {
240
241
  const nodeInfo = this.nodeNetworkInfo.get(nodeId);
241
242
  const claimantWideSubnet = this.getSubnet(claimantInfo.ip, this.config.claimantExclusionSubnet);
242
-
243
+
243
244
  if (nodeInfo && nodeInfo.wideSubnet === claimantWideSubnet) {
244
245
  reasons.push(`Same IP range as claimant (/${this.config.claimantExclusionSubnet})`);
245
246
  }
@@ -299,21 +300,21 @@ class VerifierEligibilityChecker {
299
300
  remaining.sort((a, b) => {
300
301
  const aInfo = this.nodeNetworkInfo.get(a.nodeId) || {};
301
302
  const bInfo = this.nodeNetworkInfo.get(b.nodeId) || {};
302
-
303
+
303
304
  const aNewSubnet = !usedSubnets.has(aInfo.subnet) ? 1 : 0;
304
305
  const bNewSubnet = !usedSubnets.has(bInfo.subnet) ? 1 : 0;
305
306
  if (aNewSubnet !== bNewSubnet) return bNewSubnet - aNewSubnet;
306
-
307
+
307
308
  const aNewASN = !usedASNs.has(aInfo.asn) ? 1 : 0;
308
309
  const bNewASN = !usedASNs.has(bInfo.asn) ? 1 : 0;
309
310
  if (aNewASN !== bNewASN) return bNewASN - aNewASN;
310
-
311
+
311
312
  return b.weight - a.weight; // Higher weight preferred
312
313
  });
313
314
 
314
315
  const choice = remaining.shift();
315
316
  selected.push(choice);
316
-
317
+
317
318
  const info = this.nodeNetworkInfo.get(choice.nodeId) || {};
318
319
  if (info.subnet) usedSubnets.add(info.subnet);
319
320
  if (info.asn) usedASNs.add(info.asn);
@@ -351,17 +352,17 @@ class VerifierEligibilityChecker {
351
352
  calculateSelectionWeight(nodeId) {
352
353
  const age = this.getNodeAge(nodeId);
353
354
  const reputation = this.getReputationScore(nodeId);
354
-
355
+
355
356
  // Base weight from reputation
356
357
  let weight = reputation * this.config.reputationWeightFactor;
357
-
358
+
358
359
  // Bonus for older nodes
359
360
  if (age >= this.config.preferredVerifierAge) {
360
361
  weight *= 1.5;
361
362
  } else if (age >= this.config.minVerifierAge * 2) {
362
363
  weight *= 1.25;
363
364
  }
364
-
365
+
365
366
  return weight;
366
367
  }
367
368
 
@@ -370,24 +371,24 @@ class VerifierEligibilityChecker {
370
371
  */
371
372
  getSubnet(ip, maskBits) {
372
373
  if (!ip) return null;
373
-
374
+
374
375
  // Handle IPv4
375
376
  const parts = ip.split('.');
376
377
  if (parts.length === 4) {
377
378
  const fullBits = parts.map(p => parseInt(p, 10));
378
379
  const octetsToKeep = Math.floor(maskBits / 8);
379
380
  const result = fullBits.slice(0, octetsToKeep);
380
-
381
+
381
382
  // Handle partial octet
382
383
  const remainingBits = maskBits % 8;
383
384
  if (remainingBits > 0 && octetsToKeep < 4) {
384
385
  const mask = (0xFF << (8 - remainingBits)) & 0xFF;
385
386
  result.push(fullBits[octetsToKeep] & mask);
386
387
  }
387
-
388
+
388
389
  return result.join('.') + '/' + maskBits;
389
390
  }
390
-
391
+
391
392
  // For IPv6 or unknown, just return the IP (less effective but works)
392
393
  return ip;
393
394
  }
@@ -437,8 +438,8 @@ class VerifierEligibilityChecker {
437
438
  return {
438
439
  totalNodes: this.nodeFirstSeen.size,
439
440
  eligibleByAge: eligibleCount,
440
- averageAge: this.nodeFirstSeen.size > 0
441
- ? Math.floor(totalAge / this.nodeFirstSeen.size / (24 * 60 * 60 * 1000))
441
+ averageAge: this.nodeFirstSeen.size > 0
442
+ ? Math.floor(totalAge / this.nodeFirstSeen.size / (24 * 60 * 60 * 1000))
442
443
  : 0,
443
444
  nodesWithReputation: this.reputations.size,
444
445
  nodesWithNetworkInfo: this.nodeNetworkInfo.size,
@@ -451,7 +452,7 @@ class VerifierEligibilityChecker {
451
452
  */
452
453
  class DomainVerificationRequest {
453
454
  constructor(options) {
454
- this.id = bytesToHex(randomBytes(16));
455
+ this.id = ternaryId(16);
455
456
  this.domain = options.domain;
456
457
  this.claimantNodeId = options.claimantNodeId;
457
458
  this.claimantPublicKey = options.claimantPublicKey;
@@ -561,28 +562,28 @@ export class DomainConsensusVerifier extends EventEmitter {
561
562
  this.identity = nodeIdentity;
562
563
  this.gateway = namcheGateway;
563
564
  this.config = { ...DEFAULT_CONFIG, ...options };
564
-
565
+
565
566
  // ═══════════════════════════════════════════════════════════════════════
566
567
  // SYBIL DEFENSE: Eligibility checker for verifier selection
567
568
  // ═══════════════════════════════════════════════════════════════════════
568
569
  this.eligibility = new VerifierEligibilityChecker(this.config);
569
-
570
+
570
571
  // Active verification requests (by domain)
571
572
  this.activeRequests = new Map();
572
-
573
+
573
574
  // Cooldown tracking (domain -> last claim timestamp)
574
575
  this.cooldowns = new Map();
575
-
576
+
576
577
  // Fetch function (must be set by network layer)
577
578
  this.fetchBeacon = null;
578
-
579
+
579
580
  // Peer messaging (must be set by network layer)
580
581
  this.requestVerification = null; // (peerId, request) => Promise<proof>
581
582
  this.getVerifierPeers = null; // () => [{ nodeId, ip?, asn? }, ...]
582
-
583
+
583
584
  // Our own network info (for claimant exclusion when we claim)
584
585
  this.ownNetworkInfo = null;
585
-
586
+
586
587
  this.stats = {
587
588
  claimsInitiated: 0,
588
589
  claimsSucceeded: 0,
@@ -640,9 +641,9 @@ export class DomainConsensusVerifier extends EventEmitter {
640
641
  const lastClaim = this.cooldowns.get(domain);
641
642
  if (lastClaim && Date.now() - lastClaim < this.config.cooldownBetweenClaims) {
642
643
  const waitTime = this.config.cooldownBetweenClaims - (Date.now() - lastClaim);
643
- return {
644
- success: false,
645
- error: 'Cooldown active',
644
+ return {
645
+ success: false,
646
+ error: 'Cooldown active',
646
647
  retryAfter: waitTime,
647
648
  };
648
649
  }
@@ -672,7 +673,7 @@ export class DomainConsensusVerifier extends EventEmitter {
672
673
  request.status = 'verifying';
673
674
 
674
675
  // Request verification from each peer (in parallel)
675
- const verificationPromises = verifiers.map(peerId =>
676
+ const verificationPromises = verifiers.map(peerId =>
676
677
  this.requestVerificationFromPeer(peerId, request)
677
678
  .catch(err => {
678
679
  request.addError({ peerId, error: err.message });
@@ -683,7 +684,7 @@ export class DomainConsensusVerifier extends EventEmitter {
683
684
  // Wait for all with timeout
684
685
  const results = await Promise.race([
685
686
  Promise.all(verificationPromises),
686
- new Promise((_, reject) =>
687
+ new Promise((_, reject) =>
687
688
  setTimeout(() => reject(new Error('Verification timeout')), this.config.totalTimeout)
688
689
  ),
689
690
  ]);
@@ -700,9 +701,9 @@ export class DomainConsensusVerifier extends EventEmitter {
700
701
  request.status = 'completed';
701
702
  this.stats.claimsSucceeded++;
702
703
  this.cooldowns.set(domain, Date.now());
703
-
704
- this.emit('claim-succeeded', {
705
- domain,
704
+
705
+ this.emit('claim-succeeded', {
706
+ domain,
706
707
  requestId: request.id,
707
708
  proofs: request.proofs.map(p => p.serialize()),
708
709
  });
@@ -716,9 +717,9 @@ export class DomainConsensusVerifier extends EventEmitter {
716
717
  } else {
717
718
  request.status = 'failed';
718
719
  this.stats.claimsFailed++;
719
-
720
- this.emit('claim-failed', {
721
- domain,
720
+
721
+ this.emit('claim-failed', {
722
+ domain,
722
723
  requestId: request.id,
723
724
  proofsCollected: request.proofs.length,
724
725
  quorumNeeded: this.config.quorumSize,
@@ -737,9 +738,9 @@ export class DomainConsensusVerifier extends EventEmitter {
737
738
  } catch (error) {
738
739
  request.status = 'failed';
739
740
  this.stats.claimsFailed++;
740
-
741
+
741
742
  this.emit('claim-error', { domain, requestId: request.id, error: error.message });
742
-
743
+
743
744
  return { success: false, error: error.message };
744
745
  } finally {
745
746
  this.activeRequests.delete(domain);
@@ -761,7 +762,7 @@ export class DomainConsensusVerifier extends EventEmitter {
761
762
  }
762
763
 
763
764
  const allPeers = await this.getVerifierPeers();
764
-
765
+
765
766
  // Filter out ourselves
766
767
  const candidates = allPeers
767
768
  .filter(peer => {
@@ -820,15 +821,15 @@ export class DomainConsensusVerifier extends EventEmitter {
820
821
  };
821
822
 
822
823
  const startTime = Date.now();
823
-
824
+
824
825
  try {
825
826
  const result = await this.requestVerification(peerId, verificationRequest);
826
827
  const responseTime = Date.now() - startTime;
827
-
828
+
828
829
  // Update verifier reputation based on response
829
830
  const success = result && result.success && result.proof;
830
831
  this.eligibility.updateReputation(peerId, success, responseTime);
831
-
832
+
832
833
  return result;
833
834
  } catch (error) {
834
835
  // Track failed response in reputation
@@ -855,7 +856,7 @@ export class DomainConsensusVerifier extends EventEmitter {
855
856
  try {
856
857
  // Fetch the beacon from the claimed domain
857
858
  const beaconUrl = `https://${domain}${this.config.beaconPath}`;
858
-
859
+
859
860
  if (!this.fetchBeacon) {
860
861
  throw new Error('Network layer not configured');
861
862
  }
@@ -891,9 +892,9 @@ export class DomainConsensusVerifier extends EventEmitter {
891
892
  proof.signature = this.identity.sign(signableData);
892
893
 
893
894
  this.stats.verificationsSucceeded++;
894
-
895
- this.emit('verification-completed', {
896
- domain,
895
+
896
+ this.emit('verification-completed', {
897
+ domain,
897
898
  claimantNodeId,
898
899
  beaconHash,
899
900
  });
@@ -902,9 +903,9 @@ export class DomainConsensusVerifier extends EventEmitter {
902
903
 
903
904
  } catch (error) {
904
905
  this.stats.verificationsFailed++;
905
-
906
- this.emit('verification-failed', {
907
- domain,
906
+
907
+ this.emit('verification-failed', {
908
+ domain,
908
909
  claimantNodeId,
909
910
  error: error.message,
910
911
  });
@@ -924,9 +925,9 @@ export class DomainConsensusVerifier extends EventEmitter {
924
925
 
925
926
  // Check nodeId matches claimant
926
927
  if (beacon.nodeId !== expectedNodeId) {
927
- return {
928
- valid: false,
929
- error: `NodeID mismatch: expected ${expectedNodeId}, got ${beacon.nodeId}`
928
+ return {
929
+ valid: false,
930
+ error: `NodeID mismatch: expected ${expectedNodeId}, got ${beacon.nodeId}`
930
931
  };
931
932
  }
932
933
 
@@ -938,9 +939,9 @@ export class DomainConsensusVerifier extends EventEmitter {
938
939
  // Check beacon is fresh (not too old)
939
940
  const age = Date.now() - beacon.timestamp;
940
941
  if (age > this.config.beaconMaxAge) {
941
- return {
942
- valid: false,
943
- error: `Beacon too old (${Math.round(age/1000)}s, max ${this.config.beaconMaxAge/1000}s)`
942
+ return {
943
+ valid: false,
944
+ error: `Beacon too old (${Math.round(age / 1000)}s, max ${this.config.beaconMaxAge / 1000}s)`
944
945
  };
945
946
  }
946
947
 
@@ -982,8 +983,8 @@ export class DomainConsensusVerifier extends EventEmitter {
982
983
  verifyProof(proof) {
983
984
  try {
984
985
  // Deserialize if needed
985
- const p = proof instanceof DomainVerificationProof
986
- ? proof
986
+ const p = proof instanceof DomainVerificationProof
987
+ ? proof
987
988
  : DomainVerificationProof.deserialize(proof);
988
989
 
989
990
  // Verify signature
@@ -1024,7 +1025,7 @@ export class DomainConsensusVerifier extends EventEmitter {
1024
1025
  */
1025
1026
  verifyDomainClaim(proofs, domain, claimantNodeId, options = {}) {
1026
1027
  const checkDiversity = options.checkDiversity !== false;
1027
-
1028
+
1028
1029
  if (!Array.isArray(proofs) || proofs.length === 0) {
1029
1030
  return { valid: false, error: 'No proofs provided' };
1030
1031
  }
@@ -1063,10 +1064,10 @@ export class DomainConsensusVerifier extends EventEmitter {
1063
1064
  // SYBIL DEFENSE: Check verifier diversity
1064
1065
  // ═══════════════════════════════════════════════════════════════════════
1065
1066
  let diversityCheck = { sufficient: true };
1066
-
1067
+
1067
1068
  if (checkDiversity && hasQuorum) {
1068
1069
  diversityCheck = this.checkVerifierDiversity(validProofs);
1069
-
1070
+
1070
1071
  if (!diversityCheck.sufficient) {
1071
1072
  return {
1072
1073
  valid: false,
@@ -1103,7 +1104,7 @@ export class DomainConsensusVerifier extends EventEmitter {
1103
1104
 
1104
1105
  for (const proof of proofs) {
1105
1106
  const info = this.eligibility.nodeNetworkInfo.get(proof.verifierNodeId);
1106
-
1107
+
1107
1108
  if (info) {
1108
1109
  if (info.subnet) subnets.add(info.subnet);
1109
1110
  if (info.asn && info.asn !== 'unknown') asns.add(info.asn);
@@ -1114,13 +1115,13 @@ export class DomainConsensusVerifier extends EventEmitter {
1114
1115
 
1115
1116
  // If we have enough known verifiers, check diversity
1116
1117
  const knownCount = proofs.length - unknownNetwork.length;
1117
-
1118
+
1118
1119
  // Require at least minDistinctSubnets known verifiers with different subnets
1119
1120
  const sufficientSubnets = subnets.size >= this.config.minDistinctSubnets;
1120
-
1121
+
1121
1122
  // ASN diversity is a soft requirement (may not always have ASN info)
1122
- const sufficientASNs = asns.size >= this.config.minDistinctASNs ||
1123
- unknownNetwork.length > 0; // Lenient if some are unknown
1123
+ const sufficientASNs = asns.size >= this.config.minDistinctASNs ||
1124
+ unknownNetwork.length > 0; // Lenient if some are unknown
1124
1125
 
1125
1126
  return {
1126
1127
  sufficient: sufficientSubnets,
@@ -1152,16 +1153,16 @@ export class DomainConsensusVerifier extends EventEmitter {
1152
1153
  // Basic domain validation
1153
1154
  if (!domain || typeof domain !== 'string') return false;
1154
1155
  if (domain.length > 253) return false;
1155
-
1156
+
1156
1157
  // Must have at least one dot
1157
1158
  if (!domain.includes('.')) return false;
1158
-
1159
+
1159
1160
  // No protocol prefix
1160
1161
  if (domain.includes('://')) return false;
1161
-
1162
+
1162
1163
  // No path
1163
1164
  if (domain.includes('/')) return false;
1164
-
1165
+
1165
1166
  // Basic pattern check
1166
1167
  const domainPattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/;
1167
1168
  return domainPattern.test(domain);
@@ -1215,7 +1216,7 @@ export class DomainConsensusVerifier extends EventEmitter {
1215
1216
  */
1216
1217
  restoreState(data) {
1217
1218
  if (!data) return;
1218
-
1219
+
1219
1220
  // Only restore if version matches (or upgrade logic here)
1220
1221
  if (data.version >= 2) {
1221
1222
  if (data.eligibility) {