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
@@ -13,9 +13,12 @@
13
13
  */
14
14
 
15
15
  import { EventEmitter } from 'events';
16
- import { sha3_256 } from '@noble/hashes/sha3.js';
17
- import { bytesToHex, randomBytes, hexToBytes, utf8ToBytes } from '@noble/hashes/utils.js';
16
+ import { sha3_256 as _nobleSha3 } from '@noble/hashes/sha3.js';
17
+ import { bytesToHex, hexToBytes, utf8ToBytes } from '@noble/hashes/utils.js';
18
+ import { ternaryId } from '../utils/ternary-id.js';
18
19
  import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
20
+ // ACCEL: Hardware-accelerated crypto
21
+ import { sha3_256, mlDsa65Verify } from '../utils/accel.js';
19
22
  import { createLogger } from '../utils/logger.js';
20
23
  import { MESH_REVOCATION_MESSAGES } from './mesh-revocation.js';
21
24
  import { SILICON_PARITY_MESSAGES } from './silicon-parity.js';
@@ -31,20 +34,20 @@ export const KHATA_TRUST_MESSAGE = {
31
34
  ATTESTATION_ANNOUNCE: 'khata:trust:attestation:announce',
32
35
  ATTESTATION_REQUEST: 'khata:trust:attestation:request',
33
36
  REVOCATION_CERTIFICATE: 'khata:trust:revocation:cert',
34
-
37
+
35
38
  // Silicon Parity messages
36
39
  SILICON_CHALLENGE: 'khata:trust:silicon:challenge',
37
40
  SILICON_RESPONSE: 'khata:trust:silicon:response',
38
41
  SILICON_IDENTITY: 'khata:trust:silicon:identity',
39
-
42
+
40
43
  // Sybil Graph messages
41
44
  GRAPH_UPDATE: 'khata:trust:graph:update',
42
45
  CLUSTER_ALERT: 'khata:trust:cluster:alert',
43
-
46
+
44
47
  // Trust Tier messages
45
48
  TIER_ANNOUNCE: 'khata:trust:tier:announce',
46
49
  TIER_REQUEST: 'khata:trust:tier:request',
47
-
50
+
48
51
  // v2.5.0 Geographic Proof messages
49
52
  GEO_PROOF_ANNOUNCE: 'khata:trust:geo:announce',
50
53
  GEO_PROOF_REQUEST: 'khata:trust:geo:request',
@@ -64,10 +67,10 @@ const DEFAULT_CONFIG = {
64
67
  };
65
68
 
66
69
  /**
67
- * Generate unique message ID
70
+ * Generate unique message ID (balanced ternary — '666' impossible by design)
68
71
  */
69
72
  function generateMessageId() {
70
- return bytesToHex(randomBytes(16));
73
+ return ternaryId(16);
71
74
  }
72
75
 
73
76
  /**
@@ -79,9 +82,9 @@ function generateMessageId() {
79
82
  export class KhataTrustIntegration extends EventEmitter {
80
83
  constructor(options = {}) {
81
84
  super();
82
-
85
+
83
86
  this.config = { ...DEFAULT_CONFIG, ...options };
84
-
87
+
85
88
  // Core components (injected)
86
89
  this.meshRevocation = options.meshRevocation || null;
87
90
  this.siliconParity = options.siliconParity || null;
@@ -89,17 +92,17 @@ export class KhataTrustIntegration extends EventEmitter {
89
92
  this.trustRegistry = options.trustRegistry || null;
90
93
  this.nodeIdentity = options.nodeIdentity || null;
91
94
  this.geoProofService = options.geoProofService || null; // v2.5.0
92
-
95
+
93
96
  // Network layer (set by setNetworkLayer)
94
97
  this.sendToPeer = null;
95
98
  this.broadcastToPeers = null;
96
-
99
+
97
100
  // Message deduplication
98
101
  this.seenMessages = new Map();
99
-
102
+
100
103
  // Pending silicon challenges
101
104
  this.pendingChallenges = new Map();
102
-
105
+
103
106
  // Statistics
104
107
  this.stats = {
105
108
  attestationsGossiped: 0,
@@ -112,11 +115,11 @@ export class KhataTrustIntegration extends EventEmitter {
112
115
  geoProofsReceived: 0,
113
116
  landmarksAnnounced: 0,
114
117
  };
115
-
118
+
116
119
  // Cleanup interval
117
120
  this.cleanupInterval = setInterval(() => this.cleanup(), 60000);
118
121
  }
119
-
122
+
120
123
  /**
121
124
  * Set network layer functions
122
125
  */
@@ -124,7 +127,7 @@ export class KhataTrustIntegration extends EventEmitter {
124
127
  this.sendToPeer = sendToPeer;
125
128
  this.broadcastToPeers = broadcastToPeers;
126
129
  }
127
-
130
+
128
131
  /**
129
132
  * Set core components
130
133
  */
@@ -136,11 +139,103 @@ export class KhataTrustIntegration extends EventEmitter {
136
139
  if (nodeIdentity) this.nodeIdentity = nodeIdentity;
137
140
  if (geoProofService) this.geoProofService = geoProofService;
138
141
  }
139
-
142
+
143
+ /**
144
+ * Verify ML-DSA-65 signature on an incoming trust message.
145
+ *
146
+ * Messages that include a `signature` field must prove authorship via
147
+ * the signer's public key. The dokoId/nodeId in the message identifies
148
+ * who signed. Their publicKey is resolved from the mesh peer registry.
149
+ *
150
+ * @param {Object} message - The incoming trust message
151
+ * @param {string} fromPeerId - The peer who forwarded this message
152
+ * @returns {{ valid: boolean, reason?: string }}
153
+ */
154
+ _verifyMessageSignature(message, fromPeerId) {
155
+ // Messages without signatures are rejected if they should have one
156
+ if (!message.signature) {
157
+ return { valid: false, reason: 'Missing signature' };
158
+ }
159
+
160
+ // Identify the signer's public key. Trust messages carry dokoId or nodeId.
161
+ const signerId = message.dokoId || message.landmark?.nodeId || fromPeerId;
162
+ if (!signerId) {
163
+ return { valid: false, reason: 'Cannot identify message signer' };
164
+ }
165
+
166
+ // Resolve public key from mesh peer registry (same pattern as requirePeerAuth)
167
+ let publicKey = null;
168
+ if (this._resolvePublicKey) {
169
+ publicKey = this._resolvePublicKey(signerId);
170
+ }
171
+ // Fallback: if this is the message dispatcher for another node's forwarded message,
172
+ // the fromPeerId may differ from the original signer. Try the signer directly.
173
+ if (!publicKey && signerId !== fromPeerId && this._resolvePublicKey) {
174
+ publicKey = this._resolvePublicKey(fromPeerId);
175
+ }
176
+
177
+ if (!publicKey) {
178
+ return { valid: false, reason: `No public key for signer ${signerId.slice(0, 20)}` };
179
+ }
180
+
181
+ // Reconstruct the signed payload based on message type
182
+ try {
183
+ let payload;
184
+
185
+ // Each announcement type signs a specific subset of fields
186
+ switch (message.type) {
187
+ case KHATA_TRUST_MESSAGE.TIER_ANNOUNCE:
188
+ payload = JSON.stringify({
189
+ dokoId: message.dokoId,
190
+ tier: message.tier,
191
+ weight: message.weight,
192
+ timestamp: message.timestamp,
193
+ });
194
+ break;
195
+ case KHATA_TRUST_MESSAGE.GEO_PROOF_ANNOUNCE:
196
+ payload = JSON.stringify({
197
+ proof: message.proof,
198
+ dokoId: message.dokoId,
199
+ timestamp: message.timestamp,
200
+ });
201
+ break;
202
+ case KHATA_TRUST_MESSAGE.LANDMARK_ANNOUNCE:
203
+ payload = JSON.stringify({
204
+ landmark: message.landmark,
205
+ timestamp: message.timestamp,
206
+ });
207
+ break;
208
+ default:
209
+ // For other signed messages, sign the full payload minus signature/messageId/hops
210
+ const { signature: _s, messageId: _m, hops: _h, ...rest } = message;
211
+ payload = JSON.stringify(rest);
212
+ }
213
+
214
+ const sigBytes = hexToBytes(message.signature);
215
+ const pubKeyBytes = hexToBytes(publicKey);
216
+ const msgBytes = utf8ToBytes(payload);
217
+ const valid = mlDsa65Verify(sigBytes, msgBytes, pubKeyBytes);
218
+
219
+ return { valid };
220
+ } catch (e) {
221
+ return { valid: false, reason: `Verification error: ${e.message}` };
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Set public key resolver function.
227
+ * Called during construction or setNetworkLayer to allow signature verification
228
+ * against the mesh peer registry.
229
+ * @param {Function} resolver - (nodeId) => publicKeyHex | null
230
+ */
231
+ setPublicKeyResolver(resolver) {
232
+ this._resolvePublicKey = resolver;
233
+ }
234
+
140
235
  // ═══════════════════════════════════════════════════════════════════════════
141
236
  // MESH REVOCATION GOSSIP
142
237
  // ═══════════════════════════════════════════════════════════════════════════
143
-
238
+
144
239
  /**
145
240
  * Gossip an attestation to the network
146
241
  */
@@ -149,7 +244,7 @@ export class KhataTrustIntegration extends EventEmitter {
149
244
  log.warn('khata-trust', 'Cannot gossip: network layer not set');
150
245
  return;
151
246
  }
152
-
247
+
153
248
  const message = {
154
249
  type: KHATA_TRUST_MESSAGE.ATTESTATION_ANNOUNCE,
155
250
  messageId: generateMessageId(),
@@ -158,19 +253,19 @@ export class KhataTrustIntegration extends EventEmitter {
158
253
  ttl: this.config.attestationTTL,
159
254
  hops: 0,
160
255
  };
161
-
256
+
162
257
  // Mark as seen
163
258
  const hash = this.computeMessageHash(message);
164
259
  this.seenMessages.set(hash, Date.now());
165
-
260
+
166
261
  this.stats.attestationsGossiped++;
167
262
  log.debug('khata-trust', `Gossiping attestation for ${attestation.targetDokoId}`);
168
-
263
+
169
264
  await this.broadcastToPeers(message);
170
-
265
+
171
266
  return message.messageId;
172
267
  }
173
-
268
+
174
269
  /**
175
270
  * Handle incoming attestation announcement
176
271
  */
@@ -181,32 +276,32 @@ export class KhataTrustIntegration extends EventEmitter {
181
276
  return;
182
277
  }
183
278
  this.seenMessages.set(hash, Date.now());
184
-
279
+
185
280
  // Check hop limit
186
281
  if (message.hops >= this.config.maxHops) {
187
282
  return;
188
283
  }
189
-
284
+
190
285
  // Check TTL
191
286
  const age = Date.now() - message.timestamp;
192
287
  if (age > message.ttl) {
193
288
  return;
194
289
  }
195
-
290
+
196
291
  this.stats.attestationsReceived++;
197
-
292
+
198
293
  // Add to local mesh revocation system
199
294
  if (this.meshRevocation) {
200
295
  try {
201
296
  const result = await this.meshRevocation.addAttestation(message.attestation);
202
-
297
+
203
298
  if (result.added) {
204
299
  this.emit('attestation-received', {
205
300
  attestation: message.attestation,
206
301
  fromPeerId,
207
302
  revocationTriggered: result.revoked,
208
303
  });
209
-
304
+
210
305
  // Update sybil graph with attestation
211
306
  if (this.sybilGraph) {
212
307
  this.sybilGraph.addAttestation(
@@ -215,7 +310,7 @@ export class KhataTrustIntegration extends EventEmitter {
215
310
  message.timestamp
216
311
  );
217
312
  }
218
-
313
+
219
314
  // Propagate to other peers
220
315
  if (this.broadcastToPeers) {
221
316
  await this.broadcastToPeers({
@@ -229,31 +324,31 @@ export class KhataTrustIntegration extends EventEmitter {
229
324
  }
230
325
  }
231
326
  }
232
-
327
+
233
328
  /**
234
329
  * Broadcast revocation certificate
235
330
  */
236
331
  async broadcastRevocationCertificate(certificate) {
237
332
  if (!this.broadcastToPeers) return;
238
-
333
+
239
334
  const message = {
240
335
  type: KHATA_TRUST_MESSAGE.REVOCATION_CERTIFICATE,
241
336
  messageId: generateMessageId(),
242
337
  certificate,
243
338
  timestamp: Date.now(),
244
339
  };
245
-
340
+
246
341
  log.info('khata-trust', `Broadcasting revocation certificate for ${certificate.targetDokoId}`);
247
-
342
+
248
343
  await this.broadcastToPeers(message);
249
344
  }
250
-
345
+
251
346
  /**
252
347
  * Handle incoming revocation certificate
253
348
  */
254
349
  async handleRevocationCertificate(message, fromPeerId) {
255
350
  const { certificate } = message;
256
-
351
+
257
352
  // Verify certificate
258
353
  if (this.meshRevocation) {
259
354
  const valid = await this.meshRevocation.constructor.verifyCertificate(
@@ -267,28 +362,28 @@ export class KhataTrustIntegration extends EventEmitter {
267
362
  return null;
268
363
  }
269
364
  );
270
-
365
+
271
366
  if (valid) {
272
367
  this.emit('revocation-certificate', {
273
368
  certificate,
274
369
  fromPeerId,
275
370
  targetDokoId: certificate.targetDokoId,
276
371
  });
277
-
372
+
278
373
  // Mark node as revoked in local state
279
- log.info('khata-trust',
374
+ log.info('khata-trust',
280
375
  `Verified revocation certificate for ${certificate.targetDokoId}`);
281
376
  } else {
282
- log.warn('khata-trust',
377
+ log.warn('khata-trust',
283
378
  `Invalid revocation certificate for ${certificate.targetDokoId}`);
284
379
  }
285
380
  }
286
381
  }
287
-
382
+
288
383
  // ═══════════════════════════════════════════════════════════════════════════
289
384
  // SILICON PARITY CHALLENGES
290
385
  // ═══════════════════════════════════════════════════════════════════════════
291
-
386
+
292
387
  /**
293
388
  * Challenge a peer to prove their silicon identity
294
389
  */
@@ -296,55 +391,55 @@ export class KhataTrustIntegration extends EventEmitter {
296
391
  if (!this.sendToPeer) {
297
392
  throw new Error('Network layer not set');
298
393
  }
299
-
394
+
300
395
  const challengeId = generateMessageId();
301
396
  const challenge = {
302
397
  type: KHATA_TRUST_MESSAGE.SILICON_CHALLENGE,
303
398
  challengeId,
304
399
  challengerId: this.nodeIdentity?.identity?.nodeId,
305
- nonce: bytesToHex(randomBytes(32)),
400
+ nonce: ternaryId(32),
306
401
  timestamp: Date.now(),
307
402
  };
308
-
403
+
309
404
  // Create promise for response
310
405
  return new Promise((resolve, reject) => {
311
406
  const timeout = setTimeout(() => {
312
407
  this.pendingChallenges.delete(challengeId);
313
408
  reject(new Error('Silicon challenge timeout'));
314
409
  }, this.config.siliconChallengeTimeout);
315
-
316
- this.pendingChallenges.set(challengeId, {
317
- resolve,
318
- reject,
410
+
411
+ this.pendingChallenges.set(challengeId, {
412
+ resolve,
413
+ reject,
319
414
  timeout,
320
415
  peerId,
321
416
  });
322
-
417
+
323
418
  this.stats.siliconChallengesSent++;
324
419
  this.sendToPeer(peerId, challenge);
325
420
  });
326
421
  }
327
-
422
+
328
423
  /**
329
424
  * Handle incoming silicon challenge
330
425
  */
331
426
  async handleSiliconChallenge(message, fromPeerId) {
332
427
  this.stats.siliconChallengesReceived++;
333
-
428
+
334
429
  if (!this.siliconParity) {
335
430
  log.warn('khata-trust', 'Received silicon challenge but SiliconParity not configured');
336
431
  return;
337
432
  }
338
-
433
+
339
434
  // Collect or retrieve our silicon identity
340
435
  const myDokoId = this.nodeIdentity?.identity?.nodeId;
341
436
  let identity = this.siliconParity.getIdentity(myDokoId);
342
-
437
+
343
438
  if (!identity) {
344
439
  // Collect identity on demand
345
440
  identity = await this.siliconParity.collectIdentity(myDokoId);
346
441
  }
347
-
442
+
348
443
  // Create response
349
444
  const response = {
350
445
  type: KHATA_TRUST_MESSAGE.SILICON_RESPONSE,
@@ -352,10 +447,10 @@ export class KhataTrustIntegration extends EventEmitter {
352
447
  responderId: myDokoId,
353
448
  identity: identity.toJSON(),
354
449
  challengeNonce: message.nonce,
355
- responseNonce: bytesToHex(randomBytes(16)),
450
+ responseNonce: ternaryId(16),
356
451
  timestamp: Date.now(),
357
452
  };
358
-
453
+
359
454
  // Sign response
360
455
  if (this.nodeIdentity) {
361
456
  const payload = JSON.stringify({
@@ -366,12 +461,12 @@ export class KhataTrustIntegration extends EventEmitter {
366
461
  });
367
462
  response.signature = this.nodeIdentity.sign(payload);
368
463
  }
369
-
464
+
370
465
  if (this.sendToPeer) {
371
466
  await this.sendToPeer(fromPeerId, response);
372
467
  }
373
468
  }
374
-
469
+
375
470
  /**
376
471
  * Handle silicon challenge response
377
472
  */
@@ -380,10 +475,10 @@ export class KhataTrustIntegration extends EventEmitter {
380
475
  if (!pending) {
381
476
  return; // Unknown or expired challenge
382
477
  }
383
-
478
+
384
479
  clearTimeout(pending.timeout);
385
480
  this.pendingChallenges.delete(message.challengeId);
386
-
481
+
387
482
  // Verify response
388
483
  const result = {
389
484
  valid: true,
@@ -391,7 +486,7 @@ export class KhataTrustIntegration extends EventEmitter {
391
486
  responderId: message.responderId,
392
487
  issues: [],
393
488
  };
394
-
489
+
395
490
  // Check signature if we have the public key
396
491
  if (message.signature && this.nodeIdentity) {
397
492
  const payload = JSON.stringify({
@@ -400,7 +495,7 @@ export class KhataTrustIntegration extends EventEmitter {
400
495
  responseNonce: message.responseNonce,
401
496
  fingerprint: message.identity.aesFingerprint,
402
497
  });
403
-
498
+
404
499
  // Verify signature with responder's public key from trust registry
405
500
  if (this.trustRegistry && message.responderId) {
406
501
  try {
@@ -409,9 +504,9 @@ export class KhataTrustIntegration extends EventEmitter {
409
504
  const payloadBytes = utf8ToBytes(payload);
410
505
  const publicKey = hexToBytes(profile.publicKey);
411
506
  const signature = hexToBytes(message.signature);
412
-
507
+
413
508
  // ml_dsa65.verify(signature, message, publicKey)
414
- const sigValid = ml_dsa65.verify(signature, payloadBytes, publicKey);
509
+ const sigValid = mlDsa65Verify(signature, payloadBytes, publicKey);
415
510
  if (!sigValid) {
416
511
  result.valid = false;
417
512
  result.issues.push('Invalid signature on silicon response');
@@ -426,33 +521,33 @@ export class KhataTrustIntegration extends EventEmitter {
426
521
  }
427
522
  }
428
523
  }
429
-
524
+
430
525
  // Check for VM indicators
431
526
  if (!message.identity.isRealSilicon) {
432
527
  result.issues.push('VM or emulation detected');
433
528
  }
434
-
529
+
435
530
  // Check core count for weight calculation
436
531
  if (message.identity.coreCount > 64) {
437
532
  result.issues.push(`High core count: ${message.identity.coreCount}`);
438
533
  }
439
-
534
+
440
535
  pending.resolve(result);
441
536
  }
442
-
537
+
443
538
  /**
444
539
  * Announce silicon identity to network
445
540
  */
446
541
  async announceSiliconIdentity() {
447
542
  if (!this.broadcastToPeers || !this.siliconParity) return;
448
-
543
+
449
544
  const myDokoId = this.nodeIdentity?.identity?.nodeId;
450
545
  let identity = this.siliconParity.getIdentity(myDokoId);
451
-
546
+
452
547
  if (!identity) {
453
548
  identity = await this.siliconParity.collectIdentity(myDokoId);
454
549
  }
455
-
550
+
456
551
  const message = {
457
552
  type: KHATA_TRUST_MESSAGE.SILICON_IDENTITY,
458
553
  messageId: generateMessageId(),
@@ -460,23 +555,23 @@ export class KhataTrustIntegration extends EventEmitter {
460
555
  identity: identity.toJSON(),
461
556
  timestamp: Date.now(),
462
557
  };
463
-
558
+
464
559
  await this.broadcastToPeers(message);
465
560
  }
466
-
561
+
467
562
  // ═══════════════════════════════════════════════════════════════════════════
468
563
  // SYBIL GRAPH UPDATES
469
564
  // ═══════════════════════════════════════════════════════════════════════════
470
-
565
+
471
566
  /**
472
567
  * Share graph update with network
473
568
  */
474
569
  async shareGraphUpdate() {
475
570
  if (!this.broadcastToPeers || !this.sybilGraph) return;
476
-
571
+
477
572
  const stats = this.sybilGraph.getGraphStats();
478
573
  const myDokoId = this.nodeIdentity?.identity?.nodeId;
479
-
574
+
480
575
  const message = {
481
576
  type: KHATA_TRUST_MESSAGE.GRAPH_UPDATE,
482
577
  messageId: generateMessageId(),
@@ -484,31 +579,31 @@ export class KhataTrustIntegration extends EventEmitter {
484
579
  graphStats: stats,
485
580
  timestamp: Date.now(),
486
581
  };
487
-
582
+
488
583
  await this.broadcastToPeers(message);
489
584
  }
490
-
585
+
491
586
  /**
492
587
  * Handle incoming graph update
493
588
  */
494
589
  async handleGraphUpdate(message, fromPeerId) {
495
590
  this.stats.graphUpdatesReceived++;
496
-
591
+
497
592
  this.emit('graph-update', {
498
593
  senderId: message.senderId,
499
594
  stats: message.graphStats,
500
595
  fromPeerId,
501
596
  });
502
-
597
+
503
598
  // Could merge graph data here if implementing distributed analysis
504
599
  }
505
-
600
+
506
601
  /**
507
602
  * Broadcast cluster alert
508
603
  */
509
604
  async broadcastClusterAlert(cluster) {
510
605
  if (!this.broadcastToPeers) return;
511
-
606
+
512
607
  const message = {
513
608
  type: KHATA_TRUST_MESSAGE.CLUSTER_ALERT,
514
609
  messageId: generateMessageId(),
@@ -522,53 +617,53 @@ export class KhataTrustIntegration extends EventEmitter {
522
617
  detectedBy: this.nodeIdentity?.identity?.nodeId,
523
618
  timestamp: Date.now(),
524
619
  };
525
-
526
- log.warn('khata-trust',
620
+
621
+ log.warn('khata-trust',
527
622
  `Broadcasting cluster alert: ${cluster.size} nodes, score=${cluster.suspicionScore}`);
528
-
623
+
529
624
  await this.broadcastToPeers(message);
530
625
  }
531
-
626
+
532
627
  /**
533
628
  * Handle incoming cluster alert
534
629
  */
535
630
  async handleClusterAlert(message, fromPeerId) {
536
631
  this.stats.clusterAlertsReceived++;
537
-
632
+
538
633
  this.emit('cluster-alert', {
539
634
  cluster: message.cluster,
540
635
  detectedBy: message.detectedBy,
541
636
  fromPeerId,
542
637
  });
543
-
638
+
544
639
  // Cross-reference with our own analysis
545
640
  if (this.sybilGraph) {
546
641
  const ourAnalysis = this.sybilGraph.analyze();
547
- const matchingCluster = ourAnalysis.clusters.find(c =>
642
+ const matchingCluster = ourAnalysis.clusters.find(c =>
548
643
  c.nodes.some(n => message.cluster.nodes.includes(n))
549
644
  );
550
-
645
+
551
646
  if (matchingCluster) {
552
- log.info('khata-trust',
647
+ log.info('khata-trust',
553
648
  `Cluster alert confirmed by local analysis: ${matchingCluster.size} nodes`);
554
649
  }
555
650
  }
556
651
  }
557
-
652
+
558
653
  // ═══════════════════════════════════════════════════════════════════════════
559
654
  // TRUST TIER ANNOUNCEMENTS
560
655
  // ═══════════════════════════════════════════════════════════════════════════
561
-
656
+
562
657
  /**
563
658
  * Announce our trust tier
564
659
  */
565
660
  async announceTier() {
566
661
  if (!this.broadcastToPeers || !this.trustRegistry) return;
567
-
662
+
568
663
  const myDokoId = this.nodeIdentity?.identity?.nodeId;
569
664
  const tier = await this.trustRegistry.getTier(myDokoId);
570
665
  const weight = await this.trustRegistry.getWeight(myDokoId);
571
-
666
+
572
667
  const message = {
573
668
  type: KHATA_TRUST_MESSAGE.TIER_ANNOUNCE,
574
669
  messageId: generateMessageId(),
@@ -577,7 +672,7 @@ export class KhataTrustIntegration extends EventEmitter {
577
672
  weight,
578
673
  timestamp: Date.now(),
579
674
  };
580
-
675
+
581
676
  // Sign announcement
582
677
  if (this.nodeIdentity) {
583
678
  const payload = JSON.stringify({
@@ -588,26 +683,26 @@ export class KhataTrustIntegration extends EventEmitter {
588
683
  });
589
684
  message.signature = this.nodeIdentity.sign(payload);
590
685
  }
591
-
686
+
592
687
  await this.broadcastToPeers(message);
593
688
  }
594
-
689
+
595
690
  // ═══════════════════════════════════════════════════════════════════════════
596
691
  // GEOGRAPHIC PROOF (v2.5.0)
597
692
  // ═══════════════════════════════════════════════════════════════════════════
598
-
693
+
599
694
  /**
600
695
  * Announce our geographic proof to the network
601
696
  */
602
697
  async announceGeoProof() {
603
698
  if (!this.broadcastToPeers || !this.geoProofService) return;
604
-
699
+
605
700
  const proof = this.geoProofService.getProof();
606
701
  if (!proof) {
607
702
  log.debug('khata-trust', 'No geo-proof available to announce');
608
703
  return;
609
704
  }
610
-
705
+
611
706
  const message = {
612
707
  type: KHATA_TRUST_MESSAGE.GEO_PROOF_ANNOUNCE,
613
708
  messageId: generateMessageId(),
@@ -616,7 +711,7 @@ export class KhataTrustIntegration extends EventEmitter {
616
711
  timestamp: Date.now(),
617
712
  hops: 0,
618
713
  };
619
-
714
+
620
715
  // Sign announcement
621
716
  if (this.nodeIdentity) {
622
717
  const payload = JSON.stringify({
@@ -626,14 +721,14 @@ export class KhataTrustIntegration extends EventEmitter {
626
721
  });
627
722
  message.signature = this.nodeIdentity.sign(payload);
628
723
  }
629
-
724
+
630
725
  this.stats.geoProofsGossiped++;
631
726
  log.debug('khata-trust', `Announcing geo-proof with ${proof.exclusionZones.length} zones`);
632
-
727
+
633
728
  await this.broadcastToPeers(message);
634
729
  return message.messageId;
635
730
  }
636
-
731
+
637
732
  /**
638
733
  * Request geographic proof from a specific peer
639
734
  */
@@ -641,18 +736,18 @@ export class KhataTrustIntegration extends EventEmitter {
641
736
  if (!this.sendToPeer) {
642
737
  throw new Error('Network layer not set');
643
738
  }
644
-
739
+
645
740
  const message = {
646
741
  type: KHATA_TRUST_MESSAGE.GEO_PROOF_REQUEST,
647
742
  messageId: generateMessageId(),
648
743
  requesterId: this.nodeIdentity?.identity?.nodeId,
649
744
  timestamp: Date.now(),
650
745
  };
651
-
746
+
652
747
  await this.sendToPeer(peerId, message);
653
748
  return message.messageId;
654
749
  }
655
-
750
+
656
751
  /**
657
752
  * Handle incoming geo-proof announcement
658
753
  */
@@ -663,20 +758,20 @@ export class KhataTrustIntegration extends EventEmitter {
663
758
  return;
664
759
  }
665
760
  this.seenMessages.set(hash, Date.now());
666
-
761
+
667
762
  // Check hop limit
668
763
  if (message.hops >= this.config.maxHops) {
669
764
  return;
670
765
  }
671
-
766
+
672
767
  this.stats.geoProofsReceived++;
673
-
768
+
674
769
  this.emit('geo-proof-received', {
675
770
  proof: message.proof,
676
771
  dokoId: message.dokoId,
677
772
  fromPeerId,
678
773
  });
679
-
774
+
680
775
  // Store in local registry if trust registry supports it
681
776
  if (this.trustRegistry && this.trustRegistry.setGeoProof) {
682
777
  try {
@@ -685,7 +780,18 @@ export class KhataTrustIntegration extends EventEmitter {
685
780
  log.warn('khata-trust', `Failed to store geo-proof: ${err.message}`);
686
781
  }
687
782
  }
688
-
783
+
784
+ // Cache deserialized proof in GeoProofService for /geo/verify lookups
785
+ if (this.geoProofService && message.proof) {
786
+ try {
787
+ const { GeographicProof } = await import('./geo-proof.js');
788
+ const peerProof = GeographicProof.deserialize(message.proof);
789
+ this.geoProofService.proofs.set(peerProof.nodeId || message.dokoId, peerProof);
790
+ } catch (err) {
791
+ log.warn('khata-trust', `Failed to cache peer geo-proof: ${err.message}`);
792
+ }
793
+ }
794
+
689
795
  // Propagate to other peers
690
796
  if (this.broadcastToPeers) {
691
797
  await this.broadcastToPeers({
@@ -694,19 +800,19 @@ export class KhataTrustIntegration extends EventEmitter {
694
800
  }, fromPeerId);
695
801
  }
696
802
  }
697
-
803
+
698
804
  /**
699
805
  * Handle incoming geo-proof request
700
806
  */
701
807
  async handleGeoProofRequest(message, fromPeerId) {
702
808
  if (!this.sendToPeer || !this.geoProofService) return;
703
-
809
+
704
810
  const proof = this.geoProofService.getProof();
705
811
  if (!proof) {
706
812
  log.debug('khata-trust', 'No geo-proof available to respond with');
707
813
  return;
708
814
  }
709
-
815
+
710
816
  const response = {
711
817
  type: KHATA_TRUST_MESSAGE.GEO_PROOF_RESPONSE,
712
818
  requestId: message.messageId,
@@ -714,10 +820,10 @@ export class KhataTrustIntegration extends EventEmitter {
714
820
  dokoId: this.nodeIdentity?.identity?.nodeId,
715
821
  timestamp: Date.now(),
716
822
  };
717
-
823
+
718
824
  await this.sendToPeer(fromPeerId, response);
719
825
  }
720
-
826
+
721
827
  /**
722
828
  * Handle incoming geo-proof response
723
829
  */
@@ -729,13 +835,13 @@ export class KhataTrustIntegration extends EventEmitter {
729
835
  fromPeerId,
730
836
  });
731
837
  }
732
-
838
+
733
839
  /**
734
840
  * Announce this node as a landmark
735
841
  */
736
842
  async announceLandmark(landmarkInfo) {
737
843
  if (!this.broadcastToPeers) return;
738
-
844
+
739
845
  const message = {
740
846
  type: KHATA_TRUST_MESSAGE.LANDMARK_ANNOUNCE,
741
847
  messageId: generateMessageId(),
@@ -751,7 +857,7 @@ export class KhataTrustIntegration extends EventEmitter {
751
857
  },
752
858
  timestamp: Date.now(),
753
859
  };
754
-
860
+
755
861
  // Sign announcement
756
862
  if (this.nodeIdentity) {
757
863
  const payload = JSON.stringify({
@@ -760,14 +866,14 @@ export class KhataTrustIntegration extends EventEmitter {
760
866
  });
761
867
  message.signature = this.nodeIdentity.sign(payload);
762
868
  }
763
-
869
+
764
870
  this.stats.landmarksAnnounced++;
765
871
  log.info('khata-trust', `Announcing as landmark: ${landmarkInfo.name} (${landmarkInfo.region})`);
766
-
872
+
767
873
  await this.broadcastToPeers(message);
768
874
  return message.messageId;
769
875
  }
770
-
876
+
771
877
  /**
772
878
  * Handle incoming landmark announcement
773
879
  */
@@ -778,29 +884,29 @@ export class KhataTrustIntegration extends EventEmitter {
778
884
  return;
779
885
  }
780
886
  this.seenMessages.set(hash, Date.now());
781
-
887
+
782
888
  this.emit('landmark-announce', {
783
889
  landmark: message.landmark,
784
890
  fromPeerId,
785
891
  });
786
-
892
+
787
893
  // Register landmark if geo-proof service is available
788
894
  if (this.geoProofService) {
789
895
  try {
790
896
  this.geoProofService.registerLandmark(message.landmark);
791
- log.info('khata-trust',
897
+ log.info('khata-trust',
792
898
  `Registered landmark from gossip: ${message.landmark.name} (${message.landmark.region})`);
793
899
  } catch (err) {
794
900
  log.warn('khata-trust', `Failed to register landmark: ${err.message}`);
795
901
  }
796
902
  }
797
-
903
+
798
904
  // Propagate to other peers
799
905
  if (this.broadcastToPeers) {
800
906
  await this.broadcastToPeers(message, fromPeerId);
801
907
  }
802
908
  }
803
-
909
+
804
910
  /**
805
911
  * Request landmark verification from peer
806
912
  */
@@ -808,7 +914,7 @@ export class KhataTrustIntegration extends EventEmitter {
808
914
  if (!this.sendToPeer) {
809
915
  throw new Error('Network layer not set');
810
916
  }
811
-
917
+
812
918
  const message = {
813
919
  type: KHATA_TRUST_MESSAGE.LANDMARK_VERIFY,
814
920
  messageId: generateMessageId(),
@@ -816,19 +922,40 @@ export class KhataTrustIntegration extends EventEmitter {
816
922
  requesterId: this.nodeIdentity?.identity?.nodeId,
817
923
  timestamp: Date.now(),
818
924
  };
819
-
925
+
820
926
  await this.sendToPeer(peerId, message);
821
927
  return message.messageId;
822
928
  }
823
-
929
+
824
930
  // ═══════════════════════════════════════════════════════════════════════════
825
931
  // MESSAGE ROUTING
826
932
  // ═══════════════════════════════════════════════════════════════════════════
827
-
933
+
828
934
  /**
829
935
  * Handle incoming trust message
830
936
  */
831
937
  async handleMessage(message, fromPeerId) {
938
+ // Messages that carry a signature MUST pass verification.
939
+ // Requests and challenges without signatures are allowed through.
940
+ const SIGNED_TYPES = new Set([
941
+ KHATA_TRUST_MESSAGE.TIER_ANNOUNCE,
942
+ KHATA_TRUST_MESSAGE.GEO_PROOF_ANNOUNCE,
943
+ KHATA_TRUST_MESSAGE.LANDMARK_ANNOUNCE,
944
+ KHATA_TRUST_MESSAGE.SILICON_IDENTITY,
945
+ KHATA_TRUST_MESSAGE.GRAPH_UPDATE,
946
+ KHATA_TRUST_MESSAGE.ATTESTATION_ANNOUNCE,
947
+ KHATA_TRUST_MESSAGE.REVOCATION_CERTIFICATE,
948
+ ]);
949
+
950
+ if (SIGNED_TYPES.has(message.type)) {
951
+ const sigResult = this._verifyMessageSignature(message, fromPeerId);
952
+ if (!sigResult.valid) {
953
+ log.warn('khata-trust',
954
+ `Rejected unsigned/forged trust message: ${message.type} from ${fromPeerId?.slice(0, 20)} — ${sigResult.reason}`);
955
+ return false;
956
+ }
957
+ }
958
+
832
959
  switch (message.type) {
833
960
  // Mesh Revocation
834
961
  case KHATA_TRUST_MESSAGE.ATTESTATION_ANNOUNCE:
@@ -837,7 +964,7 @@ export class KhataTrustIntegration extends EventEmitter {
837
964
  case KHATA_TRUST_MESSAGE.REVOCATION_CERTIFICATE:
838
965
  await this.handleRevocationCertificate(message, fromPeerId);
839
966
  break;
840
-
967
+
841
968
  // Silicon Parity
842
969
  case KHATA_TRUST_MESSAGE.SILICON_CHALLENGE:
843
970
  await this.handleSiliconChallenge(message, fromPeerId);
@@ -848,7 +975,7 @@ export class KhataTrustIntegration extends EventEmitter {
848
975
  case KHATA_TRUST_MESSAGE.SILICON_IDENTITY:
849
976
  this.emit('silicon-identity', { identity: message.identity, dokoId: message.dokoId, fromPeerId });
850
977
  break;
851
-
978
+
852
979
  // Sybil Graph
853
980
  case KHATA_TRUST_MESSAGE.GRAPH_UPDATE:
854
981
  await this.handleGraphUpdate(message, fromPeerId);
@@ -856,12 +983,12 @@ export class KhataTrustIntegration extends EventEmitter {
856
983
  case KHATA_TRUST_MESSAGE.CLUSTER_ALERT:
857
984
  await this.handleClusterAlert(message, fromPeerId);
858
985
  break;
859
-
986
+
860
987
  // Trust Tier
861
988
  case KHATA_TRUST_MESSAGE.TIER_ANNOUNCE:
862
989
  this.emit('tier-announce', { dokoId: message.dokoId, tier: message.tier, weight: message.weight, fromPeerId });
863
990
  break;
864
-
991
+
865
992
  // Geographic Proof (v2.5.0)
866
993
  case KHATA_TRUST_MESSAGE.GEO_PROOF_ANNOUNCE:
867
994
  await this.handleGeoProofAnnounce(message, fromPeerId);
@@ -878,26 +1005,26 @@ export class KhataTrustIntegration extends EventEmitter {
878
1005
  case KHATA_TRUST_MESSAGE.LANDMARK_VERIFY:
879
1006
  this.emit('landmark-verify-request', { landmarkId: message.landmarkId, requesterId: message.requesterId, fromPeerId });
880
1007
  break;
881
-
1008
+
882
1009
  default:
883
1010
  // Unknown message type - might be handled by base KHATA protocol
884
1011
  return false;
885
1012
  }
886
-
1013
+
887
1014
  return true;
888
1015
  }
889
-
1016
+
890
1017
  /**
891
1018
  * Check if message type is a trust message
892
1019
  */
893
1020
  isTrustMessage(messageType) {
894
1021
  return Object.values(KHATA_TRUST_MESSAGE).includes(messageType);
895
1022
  }
896
-
1023
+
897
1024
  // ═══════════════════════════════════════════════════════════════════════════
898
1025
  // UTILITIES
899
1026
  // ═══════════════════════════════════════════════════════════════════════════
900
-
1027
+
901
1028
  /**
902
1029
  * Compute message hash for deduplication
903
1030
  */
@@ -908,21 +1035,21 @@ export class KhataTrustIntegration extends EventEmitter {
908
1035
  });
909
1036
  return bytesToHex(sha3_256(new TextEncoder().encode(content)));
910
1037
  }
911
-
1038
+
912
1039
  /**
913
1040
  * Cleanup old data
914
1041
  */
915
1042
  cleanup() {
916
1043
  const now = Date.now();
917
1044
  const maxAge = this.config.attestationTTL;
918
-
1045
+
919
1046
  for (const [hash, timestamp] of this.seenMessages.entries()) {
920
1047
  if (now - timestamp > maxAge) {
921
1048
  this.seenMessages.delete(hash);
922
1049
  }
923
1050
  }
924
1051
  }
925
-
1052
+
926
1053
  /**
927
1054
  * Get statistics
928
1055
  */
@@ -933,13 +1060,13 @@ export class KhataTrustIntegration extends EventEmitter {
933
1060
  pendingChallenges: this.pendingChallenges.size,
934
1061
  };
935
1062
  }
936
-
1063
+
937
1064
  /**
938
1065
  * Shutdown
939
1066
  */
940
1067
  destroy() {
941
1068
  clearInterval(this.cleanupInterval);
942
-
1069
+
943
1070
  // Cleanup pending challenges
944
1071
  for (const [id, pending] of this.pendingChallenges.entries()) {
945
1072
  clearTimeout(pending.timeout);