yakmesh 2.9.0 → 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 (225) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/Caddyfile +77 -0
  3. package/README.md +119 -29
  4. package/content/api.js +50 -41
  5. package/content/index.js +1 -2
  6. package/content/store.js +323 -177
  7. package/dashboard/index.html +19 -3
  8. package/database/replication.js +117 -37
  9. package/docs/CRYPTO-AGILITY.md +204 -0
  10. package/docs/MTLS-RESEARCH.md +367 -0
  11. package/docs/NAMCHE-SPEC.md +681 -0
  12. package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
  13. package/docs/PRECISION-DISCLOSURE.md +96 -0
  14. package/docs/README.md +76 -0
  15. package/docs/ROADMAP-2.4.0.md +447 -0
  16. package/docs/ROADMAP-2.5.0.md +244 -0
  17. package/docs/SECURITY-AUDIT-REPORT.md +306 -0
  18. package/docs/SST-INTEGRATION.md +712 -0
  19. package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
  20. package/docs/TERNARY-AUDIT-REPORT.md +247 -0
  21. package/docs/TME-FAQ.md +221 -0
  22. package/docs/WHITEPAPER.md +623 -0
  23. package/docs/adapters.html +1001 -0
  24. package/docs/advanced-systems.html +1045 -0
  25. package/docs/annex.html +1046 -0
  26. package/docs/api.html +970 -0
  27. package/docs/business/response-templates.md +160 -0
  28. package/docs/c2c.html +1225 -0
  29. package/docs/cli.html +1332 -0
  30. package/docs/configuration.html +1248 -0
  31. package/docs/darshan.html +1085 -0
  32. package/docs/dharma.html +966 -0
  33. package/docs/docs-bundle.html +1075 -0
  34. package/docs/docs.css +3120 -0
  35. package/docs/docs.js +556 -0
  36. package/docs/doko.html +969 -0
  37. package/docs/geo-proof.html +858 -0
  38. package/docs/getting-started.html +840 -0
  39. package/docs/gumba-tutorial.html +1144 -0
  40. package/docs/gumba.html +1098 -0
  41. package/docs/index.html +914 -0
  42. package/docs/jhilke.html +1312 -0
  43. package/docs/karma.html +1100 -0
  44. package/docs/katha.html +1037 -0
  45. package/docs/lama.html +978 -0
  46. package/docs/mandala.html +1067 -0
  47. package/docs/mani.html +964 -0
  48. package/docs/mantra.html +967 -0
  49. package/docs/mesh.html +1409 -0
  50. package/docs/nakpak.html +869 -0
  51. package/docs/namche.html +928 -0
  52. package/docs/nav-order.json +53 -0
  53. package/docs/prahari.html +1043 -0
  54. package/docs/prism-bash.min.js +1 -0
  55. package/docs/prism-javascript.min.js +1 -0
  56. package/docs/prism-json.min.js +1 -0
  57. package/docs/prism-tomorrow.min.css +1 -0
  58. package/docs/prism.min.js +1 -0
  59. package/docs/privacy.html +699 -0
  60. package/docs/quick-reference.html +1181 -0
  61. package/docs/sakshi.html +1402 -0
  62. package/docs/sandboxing.md +386 -0
  63. package/docs/seva.html +911 -0
  64. package/docs/sherpa.html +871 -0
  65. package/docs/studio.html +860 -0
  66. package/docs/stupa.html +995 -0
  67. package/docs/tailwind.min.css +2 -0
  68. package/docs/tattva.html +1332 -0
  69. package/docs/terms.html +686 -0
  70. package/docs/time-server-deployment.md +166 -0
  71. package/docs/time-sources.html +1392 -0
  72. package/docs/tivra.html +1127 -0
  73. package/docs/trademark-policy.html +686 -0
  74. package/docs/tribhuj.html +1183 -0
  75. package/docs/trust-security.html +1029 -0
  76. package/docs/tutorials/backup-recovery.html +654 -0
  77. package/docs/tutorials/dashboard.html +604 -0
  78. package/docs/tutorials/domain-setup.html +605 -0
  79. package/docs/tutorials/host-website.html +456 -0
  80. package/docs/tutorials/mesh-network.html +505 -0
  81. package/docs/tutorials/mobile-access.html +445 -0
  82. package/docs/tutorials/privacy.html +467 -0
  83. package/docs/tutorials/raspberry-pi.html +600 -0
  84. package/docs/tutorials/security-basics.html +539 -0
  85. package/docs/tutorials/share-files.html +431 -0
  86. package/docs/tutorials/troubleshooting.html +637 -0
  87. package/docs/tutorials/trust-karma.html +419 -0
  88. package/docs/tutorials/yak-protocol.html +456 -0
  89. package/docs/tutorials.html +1034 -0
  90. package/docs/vani.html +1270 -0
  91. package/docs/webserver.html +809 -0
  92. package/docs/yak-protocol.html +940 -0
  93. package/docs/yak-timeserver-design.md +475 -0
  94. package/docs/yakapp.html +1015 -0
  95. package/docs/ypc27.html +1069 -0
  96. package/docs/yurt.html +1344 -0
  97. package/embedded-docs/bundle.js +274 -114
  98. package/gossip/protocol.js +247 -27
  99. package/identity/key-resolver.js +262 -0
  100. package/identity/machine-seed.js +632 -0
  101. package/identity/node-key.js +669 -368
  102. package/identity/tribhuj-ratchet.js +506 -0
  103. package/knowledge-base.js +37 -8
  104. package/launcher/yakmesh.bat +62 -0
  105. package/launcher/yakmesh.sh +70 -0
  106. package/mesh/annex.js +462 -108
  107. package/mesh/beacon-broadcast.js +4 -1
  108. package/mesh/darshan.js +17 -5
  109. package/mesh/gumba.js +47 -13
  110. package/mesh/jhilke.js +651 -0
  111. package/mesh/katha.js +5 -2
  112. package/mesh/nakpak-routing.js +8 -5
  113. package/mesh/network.js +724 -34
  114. package/mesh/pulse-sync.js +4 -1
  115. package/mesh/seva.js +526 -0
  116. package/mesh/sherpa-discovery.js +89 -8
  117. package/mesh/sybil-defense.js +19 -5
  118. package/mesh/temporal-encoder.js +4 -3
  119. package/mesh/yurt.js +72 -17
  120. package/models/entropy-sentinel.onnx +0 -0
  121. package/models/karma-trust.onnx +0 -0
  122. package/models/manifest.json +43 -0
  123. package/models/sakshi-anomaly.onnx +0 -0
  124. package/oracle/code-proof-protocol.js +7 -6
  125. package/oracle/codebase-lock.js +257 -28
  126. package/oracle/index.js +74 -15
  127. package/oracle/ma902-snmp.js +678 -0
  128. package/oracle/module-sealer.js +5 -3
  129. package/oracle/packet-checksum.js +201 -0
  130. package/oracle/ternary-144t.js +714 -0
  131. package/oracle/ternary-ml.js +481 -0
  132. package/oracle/time-api.js +239 -0
  133. package/oracle/time-source.js +137 -47
  134. package/oracle/validation-oracle-hardened.js +1111 -1071
  135. package/oracle/validation-oracle.js +4 -2
  136. package/oracle/ypc27.js +211 -0
  137. package/package.json +20 -3
  138. package/protocol/yak-handler.js +35 -9
  139. package/protocol/yak-protocol.js +6 -5
  140. package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
  141. package/reference/cpp/yakmesh_ypc27.cpp +179 -0
  142. package/sbom.json +87 -0
  143. package/scripts/security-audit.mjs +264 -0
  144. package/scripts/update-docs-sidebar.cjs +164 -0
  145. package/security/crypto-config.js +4 -3
  146. package/security/dharma-moderation.js +4 -3
  147. package/security/doko-identity.js +193 -143
  148. package/security/domain-consensus.js +86 -85
  149. package/security/fs-hardening.js +620 -0
  150. package/security/hardware-attestation.js +5 -3
  151. package/security/hybrid-trust.js +227 -87
  152. package/security/karma-rate-limiter.js +692 -0
  153. package/security/khata-protocol.js +22 -21
  154. package/security/khata-trust-integration.js +277 -150
  155. package/security/memory-safety.js +635 -0
  156. package/security/mesh-auth.js +11 -10
  157. package/security/mesh-revocation.js +18 -5
  158. package/security/namche-gateway.js +298 -69
  159. package/security/sakshi.js +102 -3
  160. package/security/sangha.js +770 -0
  161. package/security/secure-config.js +473 -0
  162. package/security/silicon-parity.js +13 -10
  163. package/security/steadywatch.js +1142 -0
  164. package/security/strike-system.js +32 -3
  165. package/security/temporal-signing.js +488 -0
  166. package/security/trit-commitment.js +464 -0
  167. package/server/crypto/annex.js +247 -0
  168. package/server/darshan-api.js +343 -0
  169. package/server/index.js +3259 -362
  170. package/server/komm-api.js +668 -0
  171. package/utils/accel.js +2273 -0
  172. package/utils/ternary-id.js +79 -0
  173. package/utils/verify-worker.js +57 -0
  174. package/webserver/index.js +95 -5
  175. package/assets/yakmesh-logo.png +0 -0
  176. package/assets/yakmesh-logo.svg +0 -80
  177. package/assets/yakmesh-logo2.png +0 -0
  178. package/assets/yakmesh-logo2sm.png +0 -0
  179. package/assets/ymsm.png +0 -0
  180. package/scripts/update-docs-nav.cjs +0 -194
  181. package/update-docs-nav.cjs +0 -18
  182. package/update-nav.ps1 +0 -16
  183. package/website/assets/silhouettes/adapters.svg +0 -107
  184. package/website/assets/silhouettes/api-endpoints.svg +0 -115
  185. package/website/assets/silhouettes/atomic-clock.svg +0 -83
  186. package/website/assets/silhouettes/base-camp.svg +0 -81
  187. package/website/assets/silhouettes/bridge.svg +0 -69
  188. package/website/assets/silhouettes/docs-bundle.svg +0 -113
  189. package/website/assets/silhouettes/doko-basket.svg +0 -70
  190. package/website/assets/silhouettes/fortress.svg +0 -93
  191. package/website/assets/silhouettes/gateway.svg +0 -54
  192. package/website/assets/silhouettes/gears.svg +0 -93
  193. package/website/assets/silhouettes/globe-satellite.svg +0 -67
  194. package/website/assets/silhouettes/karma-wheel.svg +0 -137
  195. package/website/assets/silhouettes/lama-council.svg +0 -141
  196. package/website/assets/silhouettes/mandala-network.svg +0 -169
  197. package/website/assets/silhouettes/mani-stones.svg +0 -149
  198. package/website/assets/silhouettes/mantra-wheel.svg +0 -116
  199. package/website/assets/silhouettes/mesh-nodes.svg +0 -113
  200. package/website/assets/silhouettes/nakpak.svg +0 -56
  201. package/website/assets/silhouettes/peak-lightning.svg +0 -73
  202. package/website/assets/silhouettes/sherpa.svg +0 -69
  203. package/website/assets/silhouettes/stupa-tower.svg +0 -119
  204. package/website/assets/silhouettes/tattva-eye.svg +0 -78
  205. package/website/assets/silhouettes/terminal.svg +0 -74
  206. package/website/assets/silhouettes/webserver.svg +0 -145
  207. package/website/assets/silhouettes/yak.svg +0 -78
  208. package/website/assets/yakmesh-logo.png +0 -0
  209. package/website/assets/yakmesh-logo.webp +0 -0
  210. package/website/assets/yakmesh-logo128x140.webp +0 -0
  211. package/website/assets/yakmesh-logo2.png +0 -0
  212. package/website/assets/yakmesh-logo2.svg +0 -51
  213. package/website/assets/yakmesh-logo40x44.webp +0 -0
  214. package/website/assets/yakmesh.gif +0 -0
  215. package/website/assets/yakmesh.ico +0 -0
  216. package/website/assets/yakmesh.jpg +0 -0
  217. package/website/assets/yakmesh.pdf +0 -0
  218. package/website/assets/yakmesh.png +0 -0
  219. package/website/assets/yakmesh.svg +0 -70
  220. package/website/assets/yakmesh128.webp +0 -0
  221. package/website/assets/yakmesh32.png +0 -0
  222. package/website/assets/yakmesh32.svg +0 -65
  223. package/website/assets/yakmesh32o.ico +0 -2
  224. package/website/assets/yakmesh32o.svg +0 -65
  225. package/website/assets/yakmesh32o.svgz +0 -0
@@ -11,12 +11,18 @@
11
11
  * @version 1.0.0
12
12
  */
13
13
 
14
- import { sha3_256 } from '@noble/hashes/sha3.js';
14
+ import { sha3_256 as _nobleSha3 } from '@noble/hashes/sha3.js';
15
15
  import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
16
16
  import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
17
+ // ACCEL: Hardware-accelerated crypto
18
+ import { sha3_256, mlDsa65Sign, mlDsa65Verify } from '../utils/accel.js';
17
19
  import { EventEmitter } from 'events';
18
20
  import { createLogger } from '../utils/logger.js';
19
21
 
22
+ // ═══ TRIBHUJ — Balanced ternary for revocation status ═══
23
+ // POSITIVE: retained (not revoked), NEUTRAL: forming (insufficient network), NEGATIVE: revoked
24
+ import { POSITIVE, NEUTRAL, NEGATIVE } from '../oracle/tribhuj.js';
25
+
20
26
  const log = createLogger('security:mesh-revocation');
21
27
 
22
28
  /**
@@ -85,7 +91,7 @@ export class Attestation {
85
91
  */
86
92
  sign(privateKey) {
87
93
  const bytes = this.getSignableBytes();
88
- const sig = ml_dsa65.sign(bytes, privateKey);
94
+ const sig = mlDsa65Sign(bytes, privateKey);
89
95
  this.signature = bytesToHex(sig);
90
96
  return this;
91
97
  }
@@ -100,7 +106,7 @@ export class Attestation {
100
106
  const bytes = this.getSignableBytes();
101
107
  const sig = hexToBytes(this.signature);
102
108
  const pubKey = typeof publicKey === 'string' ? hexToBytes(publicKey) : publicKey;
103
- return ml_dsa65.verify(sig, bytes, pubKey);
109
+ return mlDsa65Verify(sig, bytes, pubKey);
104
110
  } catch (e) {
105
111
  return false;
106
112
  }
@@ -220,11 +226,16 @@ export class RevocationState {
220
226
 
221
227
  /**
222
228
  * Check if threshold is met
223
- * This is THE mathematical determination
229
+ * This is THE mathematical determination.
230
+ *
231
+ * Returns `revoked` boolean (backward compat) plus `status` trit:
232
+ * POSITIVE (+1): retained — below threshold, DOKO is valid
233
+ * NEUTRAL ( 0): forming — insufficient network to determine
234
+ * NEGATIVE (-1): revoked — threshold met, DOKO is revoked
224
235
  */
225
236
  isRevoked(activeNodeCount, config = DEFAULT_CONFIG) {
226
237
  if (activeNodeCount < config.minNodes) {
227
- return { revoked: false, reason: 'INSUFFICIENT_NETWORK' };
238
+ return { revoked: false, status: NEUTRAL, reason: 'INSUFFICIENT_NETWORK' };
228
239
  }
229
240
 
230
241
  const threshold = Math.ceil(activeNodeCount * config.threshold);
@@ -233,6 +244,7 @@ export class RevocationState {
233
244
  if (count >= threshold) {
234
245
  return {
235
246
  revoked: true,
247
+ status: NEGATIVE,
236
248
  reason: this.primaryReason,
237
249
  attestationCount: count,
238
250
  threshold,
@@ -243,6 +255,7 @@ export class RevocationState {
243
255
 
244
256
  return {
245
257
  revoked: false,
258
+ status: POSITIVE,
246
259
  reason: 'BELOW_THRESHOLD',
247
260
  attestationCount: count,
248
261
  threshold,
@@ -5,30 +5,38 @@
5
5
  * "Math as Authority - No human in the loop, no human weakness."
6
6
  *
7
7
  * ═══════════════════════════════════════════════════════════════════════════════
8
- * ⚠️ SECURITY: This module implements the 7-step verification flow.
8
+ * ⚠️ SECURITY: This module implements the 8-step verification flow.
9
9
  * All trust decisions are mathematical computations - no exceptions.
10
+ * Defense-in-depth: NIST (Gate 2) + 144T (Gate 8) must BOTH verify.
10
11
  * ═══════════════════════════════════════════════════════════════════════════════
11
12
  *
12
- * The 7 Gates of Verification:
13
- * 1. STRUCTURE_OK - Valid DOKO format
14
- * 2. SIGNATURE_OK - ML-DSA-65 signature verifies
15
- * 3. NODEID_OK - NodeID matches two-part derivation (network + instance)
16
- * 4. TEMPORAL_OK - Not expired, not from future
17
- * 5. NETWORK_OK - Correct network name
18
- * 6. NOT_REVOKED - Not in revocation log
19
- * 7. DOMAINS_OK - Quorum verified domain claims (if applicable)
13
+ * The 8 Gates of Verification:
14
+ * 1. STRUCTURE_OK - Valid DOKO format
15
+ * 2. SIGNATURE_OK - ML-DSA-65 signature verifies (NIST)
16
+ * 3. NODEID_OK - NodeID matches two-part derivation (network + instance)
17
+ * 4. TEMPORAL_OK - Not expired, not from future
18
+ * 5. NETWORK_OK - Correct network name
19
+ * 6. NOT_REVOKED - Not in revocation log
20
+ * 7. DOMAINS_OK - Quorum verified domain claims (if applicable)
21
+ * 8. TRIT_COMMITMENT_OK - 144T backbone verification (if present)
20
22
  *
21
23
  * @module security/namche-gateway
22
24
  * @version 1.0.0
23
25
  */
24
26
 
25
27
  import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
26
- import { sha3_256 } from '@noble/hashes/sha3.js';
28
+ import { sha3_256 as _nobleSha3 } from '@noble/hashes/sha3.js';
27
29
  import { bytesToHex, hexToBytes, utf8ToBytes } from '@noble/hashes/utils.js';
30
+ // ACCEL: Hardware-accelerated crypto
31
+ import { sha3_256, mlDsa65Verify } from '../utils/accel.js';
28
32
  import { EventEmitter } from 'events';
29
- import { generateNodeId, getCodebaseHash } from '../identity/node-key.js';
33
+ import { generateNodeId, getCodebaseHash, signMessage } from '../identity/node-key.js';
30
34
  import { deriveNetworkName } from '../oracle/network-identity.js';
31
35
  import { createLogger } from '../utils/logger.js';
36
+ // SAKSHI: Observational verification & revocation agreement
37
+ import { NodeWitness, checkMathematicalAgreement, checkRevocationAgreement } from './sakshi.js';
38
+ // 144T: Ternary backbone security (defense-in-depth with NIST)
39
+ import { TritCommitment } from './trit-commitment.js';
32
40
 
33
41
  const log = createLogger('security:namche');
34
42
 
@@ -71,6 +79,7 @@ export const VERIFY_RESULT = {
71
79
  REVOKED: 'REVOKED',
72
80
  DOMAIN_VERIFICATION_FAILED: 'DOMAIN_VERIFICATION_FAILED',
73
81
  INSUFFICIENT_QUORUM: 'INSUFFICIENT_QUORUM',
82
+ TRIT_COMMITMENT_INVALID: 'TRIT_COMMITMENT_INVALID',
74
83
  };
75
84
 
76
85
  /**
@@ -187,7 +196,8 @@ export class NamcheGateway extends EventEmitter {
187
196
  this.dokoCache = new LRUCache(this.config.dokoCacheSize);
188
197
  this.revocationLog = new RevocationLog();
189
198
  this.verifiedDomains = new Map(); // domain -> doko that verified it
190
-
199
+ this.revocationReports = new Map(); // dokoHash -> Array of { witness, evidence }
200
+
191
201
  this.stats = {
192
202
  verificationsAttempted: 0,
193
203
  verificationsSucceeded: 0,
@@ -312,11 +322,29 @@ export class NamcheGateway extends EventEmitter {
312
322
  checks.push('DOMAINS_OK');
313
323
  }
314
324
 
325
+ // ─────────────────────────────────────────────────────────────────────
326
+ // GATE 8: 144T COMMITMENT (if present — defense-in-depth)
327
+ // ─────────────────────────────────────────────────────────────────────
328
+ // The 144T commitment provides a second cryptographic layer independent
329
+ // of NIST. Both ML-DSA-65 (Gate 2) AND 144T must verify for full trust.
330
+ // This means an attacker must break BOTH NIST and lattice-hard SIS.
331
+ if (doko.tritCommitment) {
332
+ const tritResult = this.checkTritCommitment(doko);
333
+ if (!tritResult.valid) {
334
+ return this.fail(
335
+ VERIFY_RESULT.TRIT_COMMITMENT_INVALID,
336
+ tritResult.detail,
337
+ { tritChecks: tritResult.checks }
338
+ );
339
+ }
340
+ checks.push('TRIT_COMMITMENT_OK');
341
+ }
342
+
315
343
  // ═══════════════════════════════════════════════════════════════════════
316
- // ALL 7 GATES PASSED - MATHEMATICALLY VERIFIED
344
+ // ALL 8 GATES PASSED - MATHEMATICALLY VERIFIED (DUAL-LAYER)
317
345
  // ═══════════════════════════════════════════════════════════════════════
318
346
  this.stats.verificationsSucceeded++;
319
-
347
+
320
348
  // Cache the verified DOKO
321
349
  this.dokoCache.set(dokoHash, {
322
350
  doko,
@@ -362,7 +390,7 @@ export class NamcheGateway extends EventEmitter {
362
390
  */
363
391
  checkStructure(doko) {
364
392
  const required = ['version', 'type', 'nodeId', 'publicKey', 'issuedAt', 'expiresAt', 'signature'];
365
-
393
+
366
394
  for (const field of required) {
367
395
  if (!(field in doko)) {
368
396
  return { valid: false, detail: `Missing required field: ${field}` };
@@ -394,12 +422,12 @@ export class NamcheGateway extends EventEmitter {
394
422
  const publicKey = hexToBytes(doko.publicKey);
395
423
  const signature = hexToBytes(doko.signature);
396
424
 
397
- const valid = ml_dsa65.verify(signature, payloadBytes, publicKey);
398
-
425
+ const valid = mlDsa65Verify(signature, payloadBytes, publicKey);
426
+
399
427
  if (!valid) {
400
428
  return { valid: false, detail: 'ML-DSA-65 signature verification failed' };
401
429
  }
402
-
430
+
403
431
  return { valid: true };
404
432
  } catch (error) {
405
433
  return { valid: false, detail: `Signature check error: ${error.message}` };
@@ -419,35 +447,35 @@ export class NamcheGateway extends EventEmitter {
419
447
  try {
420
448
  // The nodeId must follow the format: node-[networkName]-[instanceId]
421
449
  if (!doko.nodeId.startsWith('node-')) {
422
- return {
423
- valid: false,
450
+ return {
451
+ valid: false,
424
452
  reason: VERIFY_RESULT.NODEID_MISMATCH,
425
- detail: 'NodeID must start with "node-"'
453
+ detail: 'NodeID must start with "node-"'
426
454
  };
427
455
  }
428
456
 
429
457
  // Extract the network name from the nodeId
430
458
  const parts = doko.nodeId.split('-');
431
459
  if (parts.length < 3) {
432
- return {
433
- valid: false,
460
+ return {
461
+ valid: false,
434
462
  reason: VERIFY_RESULT.NODEID_MISMATCH,
435
- detail: 'NodeID must have format node-[networkName]-[instanceId]'
463
+ detail: 'NodeID must have format node-[networkName]-[instanceId]'
436
464
  };
437
465
  }
438
466
 
439
467
  // Verify the network portion matches our expected network
440
468
  const ourNetworkName = this.getNetworkName();
441
-
469
+
442
470
  // The network name could be multiple words (e.g., "qubit-lattice-prism")
443
471
  // We need to check if the nodeId contains our network name after "node-"
444
472
  const nodeIdWithoutPrefix = doko.nodeId.substring(5); // Remove "node-"
445
-
473
+
446
474
  if (!nodeIdWithoutPrefix.startsWith(ourNetworkName + '-')) {
447
- return {
448
- valid: false,
475
+ return {
476
+ valid: false,
449
477
  reason: VERIFY_RESULT.WRONG_NETWORK_IN_NODEID,
450
- detail: `NodeID network mismatch. Expected: ${ourNetworkName}, Got: ${nodeIdWithoutPrefix.split('-').slice(0, -1).join('-')}`
478
+ detail: `NodeID network mismatch. Expected: ${ourNetworkName}, Got: ${nodeIdWithoutPrefix.split('-').slice(0, -1).join('-')}`
451
479
  };
452
480
  }
453
481
 
@@ -461,24 +489,24 @@ export class NamcheGateway extends EventEmitter {
461
489
  // Full verification: regenerate the expected nodeId from the publicKey
462
490
  const publicKeyBytes = hexToBytes(doko.publicKey);
463
491
  const expectedNodeId = generateNodeId(publicKeyBytes, codebaseHash);
464
-
492
+
465
493
  if (doko.nodeId !== expectedNodeId) {
466
- return {
467
- valid: false,
494
+ return {
495
+ valid: false,
468
496
  reason: VERIFY_RESULT.NODEID_MISMATCH,
469
- detail: `NodeID does not match public key derivation. Expected: ${expectedNodeId}, Got: ${doko.nodeId}`
497
+ detail: `NodeID does not match public key derivation. Expected: ${expectedNodeId}, Got: ${doko.nodeId}`
470
498
  };
471
499
  }
472
500
  }
473
501
  // If no codebase hash, we can only verify structure (cross-network scenario)
474
502
  // This is a known limitation documented in SECURITY.md
475
-
503
+
476
504
  return { valid: true };
477
505
  } catch (error) {
478
- return {
479
- valid: false,
506
+ return {
507
+ valid: false,
480
508
  reason: VERIFY_RESULT.NODEID_MISMATCH,
481
- detail: `NodeID check error: ${error.message}`
509
+ detail: `NodeID check error: ${error.message}`
482
510
  };
483
511
  }
484
512
  }
@@ -492,19 +520,19 @@ export class NamcheGateway extends EventEmitter {
492
520
 
493
521
  // Check not issued in the future (with clock skew allowance)
494
522
  if (doko.issuedAt > now + maxSkew) {
495
- return {
496
- valid: false,
523
+ return {
524
+ valid: false,
497
525
  reason: VERIFY_RESULT.ISSUED_IN_FUTURE,
498
- detail: `DOKO issued in future: ${new Date(doko.issuedAt).toISOString()}`
526
+ detail: `DOKO issued in future: ${new Date(doko.issuedAt).toISOString()}`
499
527
  };
500
528
  }
501
529
 
502
530
  // Check not expired
503
531
  if (doko.expiresAt < now) {
504
- return {
505
- valid: false,
532
+ return {
533
+ valid: false,
506
534
  reason: VERIFY_RESULT.EXPIRED,
507
- detail: `DOKO expired at: ${new Date(doko.expiresAt).toISOString()}`
535
+ detail: `DOKO expired at: ${new Date(doko.expiresAt).toISOString()}`
508
536
  };
509
537
  }
510
538
 
@@ -516,9 +544,9 @@ export class NamcheGateway extends EventEmitter {
516
544
  */
517
545
  checkNetwork(doko) {
518
546
  if (doko.networkName && doko.networkName !== this.networkName) {
519
- return {
520
- valid: false,
521
- detail: `Network mismatch. Expected: ${this.networkName}, Got: ${doko.networkName}`
547
+ return {
548
+ valid: false,
549
+ detail: `Network mismatch. Expected: ${this.networkName}, Got: ${doko.networkName}`
522
550
  };
523
551
  }
524
552
  return { valid: true };
@@ -530,9 +558,9 @@ export class NamcheGateway extends EventEmitter {
530
558
  checkRevocation(dokoHash) {
531
559
  if (this.revocationLog.contains(dokoHash)) {
532
560
  const revocation = this.revocationLog.get(dokoHash);
533
- return {
534
- valid: false,
535
- detail: `DOKO revoked at ${new Date(revocation.revokedAt).toISOString()}, reason: ${revocation.reason}`
561
+ return {
562
+ valid: false,
563
+ detail: `DOKO revoked at ${new Date(revocation.revokedAt).toISOString()}, reason: ${revocation.reason}`
536
564
  };
537
565
  }
538
566
  return { valid: true };
@@ -546,12 +574,12 @@ export class NamcheGateway extends EventEmitter {
546
574
 
547
575
  for (const domain of doko.domains) {
548
576
  const validProofs = await this.verifyDomainProofs(domain);
549
-
577
+
550
578
  if (validProofs < quorum) {
551
- return {
552
- valid: false,
579
+ return {
580
+ valid: false,
553
581
  domain: domain.name,
554
- detail: `Insufficient quorum for ${domain.name}: have ${validProofs}, need ${quorum}`
582
+ detail: `Insufficient quorum for ${domain.name}: have ${validProofs}, need ${quorum}`
555
583
  };
556
584
  }
557
585
  }
@@ -559,8 +587,61 @@ export class NamcheGateway extends EventEmitter {
559
587
  return { valid: true };
560
588
  }
561
589
 
590
+ /**
591
+ * GATE 8: Check 144T commitment (backbone verification)
592
+ *
593
+ * This gate provides DEFENSE-IN-DEPTH alongside NIST (Gate 2).
594
+ * The 144T commitment uses YPC-27 (lattice-hard SIS problem) and
595
+ * polynomial binding to ensure the payload is tied to the sender's
596
+ * 144T mesh address.
597
+ *
598
+ * Security properties:
599
+ * - YPC-27 operates in ring Z[x]/(x^27-1) mod 3
600
+ * - Forging requires solving the Shortest Vector Problem
601
+ * - Independent of NIST — if NIST is backdoored, 144T still holds
602
+ * - Both layers must be broken to compromise a message
603
+ *
604
+ * @param {Object} doko — DOKO with tritCommitment field
605
+ * @returns {Object} — { valid, detail?, checks? }
606
+ */
607
+ checkTritCommitment(doko) {
608
+ // Get the payload (everything except signature and tritCommitment)
609
+ const { signature, tritCommitment, ...payloadFields } = doko;
610
+
611
+ if (!TritCommitment.isValidStructure(tritCommitment)) {
612
+ return {
613
+ valid: false,
614
+ detail: 'Invalid tritCommitment structure',
615
+ checks: [],
616
+ };
617
+ }
618
+
619
+ // Verify the 144T commitment against the DOKO payload
620
+ const result = TritCommitment.verify(payloadFields, tritCommitment);
621
+
622
+ if (!result.valid) {
623
+ log.warn('144T commitment verification FAILED', {
624
+ reason: result.reason,
625
+ detail: result.detail,
626
+ checks: result.checks,
627
+ });
628
+ return {
629
+ valid: false,
630
+ detail: `144T: ${result.reason} — ${result.detail || 'verification failed'}`,
631
+ checks: result.checks,
632
+ };
633
+ }
634
+
635
+ log.debug('144T commitment verified (defense-in-depth active)', {
636
+ checks: result.checks,
637
+ });
638
+
639
+ return { valid: true, checks: result.checks };
640
+ }
641
+
562
642
  /**
563
643
  * Verify domain proofs from multiple verifiers
644
+ * Uses SAKSHI observational verification — mathematical agreement, not voting
564
645
  */
565
646
  async verifyDomainProofs(domainClaim) {
566
647
  let validProofs = 0;
@@ -569,6 +650,9 @@ export class NamcheGateway extends EventEmitter {
569
650
  return 0;
570
651
  }
571
652
 
653
+ // Collect SAKSHI observations from each proof verifier
654
+ const observations = [];
655
+
572
656
  for (const proof of domainClaim.proofs) {
573
657
  try {
574
658
  // Verify the verifier's signature on the beacon hash
@@ -582,13 +666,18 @@ export class NamcheGateway extends EventEmitter {
582
666
  const publicKey = hexToBytes(proof.verifierPublicKey);
583
667
  const signature = hexToBytes(proof.signature);
584
668
 
585
- const proofValid = ml_dsa65.verify(signature, payloadBytes, publicKey);
669
+ const proofValid = mlDsa65Verify(signature, payloadBytes, publicKey);
670
+
671
+ // SAKSHI: Record each verifier's observation
672
+ const witness = new NodeWitness({
673
+ nodeId: proof.verifierNodeId || bytesToHex(publicKey.slice(0, 16)),
674
+ });
675
+ observations.push({
676
+ witness,
677
+ value: proofValid ? proof.beaconHash : 'INVALID_SIGNATURE',
678
+ });
586
679
 
587
680
  if (proofValid) {
588
- // TODO: Integrate with SAKSHI observational verification
589
- // SAKSHI philosophy: Binary verification (signature valid or not),
590
- // NOT tier-weighted voting (SIRDAR counts more than PATHIK)
591
- // For now, we accept any valid signature
592
681
  validProofs++;
593
682
  }
594
683
  } catch (error) {
@@ -597,6 +686,26 @@ export class NamcheGateway extends EventEmitter {
597
686
  }
598
687
  }
599
688
 
689
+ // SAKSHI: Check mathematical agreement across all proof observations
690
+ if (observations.length > 0) {
691
+ const agreement = checkMathematicalAgreement(observations);
692
+ if (agreement.isAgreed) {
693
+ log.debug('SAKSHI: Domain proofs agree mathematically', {
694
+ domain: domainClaim.name,
695
+ proofCount: validProofs,
696
+ confidence: agreement.confidence,
697
+ });
698
+ } else if (agreement.isDisagreed) {
699
+ log.warn('SAKSHI: Domain proof disagreement — flagging for recomputation', {
700
+ domain: domainClaim.name,
701
+ reason: agreement.reason,
702
+ action: agreement.data?.action,
703
+ });
704
+ // Disagreement means proofs don't agree — return 0 to fail quorum
705
+ return 0;
706
+ }
707
+ }
708
+
600
709
  return validProofs;
601
710
  }
602
711
 
@@ -610,16 +719,26 @@ export class NamcheGateway extends EventEmitter {
610
719
  * @param {Object} originalDoko - The DOKO being revoked (for verification)
611
720
  */
612
721
  async processRevocation(revocation, originalDoko) {
613
- // Verify the revocation is signed by the DOKO owner
614
- if (revocation.revokedBy !== originalDoko.nodeId) {
615
- // Only owner can revoke (for now)
616
- // TODO: Integrate SAKSHI checkRevocationAgreement() for mesh revocation
617
- // SAKSHI uses mathematical agreement (do nodes agree on what happened?)
618
- // NOT tier-weighted voting (SIRDAR's revocation counts 2x)
619
- return { success: false, reason: 'Only DOKO owner can revoke' };
722
+ // Owner can always revoke directly (self-revocation)
723
+ if (revocation.revokedBy === originalDoko.nodeId) {
724
+ return this._processOwnerRevocation(revocation, originalDoko);
620
725
  }
621
726
 
622
- // Verify signature
727
+ // Non-owner: treat as a revocation REPORT for SAKSHI consensus
728
+ // SAKSHI uses mathematical agreement (do nodes agree on what happened?)
729
+ // NOT tier-weighted voting (SIRDAR's revocation counts 2x)
730
+ return this.processRevocationReport({
731
+ reportedBy: revocation.revokedBy,
732
+ reason: revocation.reason,
733
+ timestamp: revocation.revokedAt,
734
+ }, revocation.dokoHash);
735
+ }
736
+
737
+ /**
738
+ * Process self-revocation from the DOKO owner
739
+ * @private
740
+ */
741
+ async _processOwnerRevocation(revocation, originalDoko) {
623
742
  const revocationPayload = canonicalize({
624
743
  dokoHash: revocation.dokoHash,
625
744
  reason: revocation.reason,
@@ -632,7 +751,7 @@ export class NamcheGateway extends EventEmitter {
632
751
  const publicKey = hexToBytes(originalDoko.publicKey);
633
752
  const signature = hexToBytes(revocation.signature);
634
753
 
635
- const valid = ml_dsa65.verify(signature, payloadBytes, publicKey);
754
+ const valid = mlDsa65Verify(signature, payloadBytes, publicKey);
636
755
 
637
756
  if (!valid) {
638
757
  return { success: false, reason: 'Invalid revocation signature' };
@@ -653,6 +772,87 @@ export class NamcheGateway extends EventEmitter {
653
772
  }
654
773
  }
655
774
 
775
+ /**
776
+ * Process a revocation report from the mesh (SAKSHI consensus)
777
+ *
778
+ * Multiple nodes can report evidence of compromise/malice.
779
+ * Revocation happens when reports mathematically agree — not by weighted vote.
780
+ *
781
+ * @param {Object} report - The revocation report
782
+ * @param {string} report.reportedBy - NodeId of the reporting node
783
+ * @param {string} report.reason - Reason for revocation
784
+ * @param {number} [report.timestamp] - When the issue was observed
785
+ * @param {string} targetDokoHash - Hash of the DOKO to potentially revoke
786
+ * @returns {Object} Result: { success, method?, reason?, state? }
787
+ */
788
+ processRevocationReport(report, targetDokoHash) {
789
+ if (!this.revocationReports.has(targetDokoHash)) {
790
+ this.revocationReports.set(targetDokoHash, []);
791
+ }
792
+
793
+ const reports = this.revocationReports.get(targetDokoHash);
794
+ const witness = new NodeWitness({ nodeId: report.reportedBy });
795
+
796
+ reports.push({
797
+ witness,
798
+ evidence: {
799
+ reason: report.reason,
800
+ targetId: targetDokoHash,
801
+ timestamp: report.timestamp || Date.now(),
802
+ },
803
+ });
804
+
805
+ // SAKSHI: Check mathematical agreement across all revocation reports
806
+ const minReports = this.config.minRevocationReports || 3;
807
+ const result = checkRevocationAgreement(reports, { minReports });
808
+
809
+ if (result.isAgreed) {
810
+ // Mesh agrees on revocation — execute it
811
+ const revocationRecord = {
812
+ dokoHash: targetDokoHash,
813
+ reason: result.data.evidence?.reason || report.reason,
814
+ revokedAt: result.data.timestamp || Date.now(),
815
+ revokedBy: 'MESH_CONSENSUS',
816
+ reportCount: result.data.reportCount,
817
+ method: 'SAKSHI_AGREEMENT',
818
+ };
819
+
820
+ this.revocationLog.add(targetDokoHash, revocationRecord);
821
+ this.dokoCache.delete(targetDokoHash);
822
+ this.revocationReports.delete(targetDokoHash);
823
+ this.stats.revocationsProcessed++;
824
+
825
+ log.info('SAKSHI: Mesh revocation consensus reached', {
826
+ dokoHash: targetDokoHash,
827
+ reportCount: result.data.reportCount,
828
+ });
829
+
830
+ this.emit('revoked', {
831
+ dokoHash: targetDokoHash,
832
+ revocation: revocationRecord,
833
+ method: 'SAKSHI_AGREEMENT',
834
+ });
835
+
836
+ return { success: true, method: 'SAKSHI_AGREEMENT' };
837
+ }
838
+
839
+ if (result.isDisagreed) {
840
+ log.debug('SAKSHI: Revocation reports disagree', {
841
+ dokoHash: targetDokoHash,
842
+ reason: result.reason,
843
+ });
844
+ return { success: false, reason: 'Reports disagree on evidence', details: result.reason };
845
+ }
846
+
847
+ // PENDING — need more reports
848
+ log.debug('SAKSHI: Revocation report recorded, awaiting consensus', {
849
+ dokoHash: targetDokoHash,
850
+ currentReports: reports.length,
851
+ minRequired: minReports,
852
+ });
853
+ return { success: false, reason: 'Pending — need more reports', state: 'PENDING' };
854
+ }
855
+
656
856
  // ═══════════════════════════════════════════════════════════════════════════
657
857
  // CACHE & LOOKUP
658
858
  // ═══════════════════════════════════════════════════════════════════════════
@@ -695,13 +895,13 @@ export class NamcheGateway extends EventEmitter {
695
895
  */
696
896
  lookupByDomain(domain) {
697
897
  const normalizedDomain = domain.toLowerCase().replace(/^www\./, '');
698
-
898
+
699
899
  for (const [hash, cached] of this.dokoCache.cache.entries()) {
700
900
  // Check TTL first
701
901
  if (Date.now() - cached.verifiedAt >= this.config.dokoCacheTTL) {
702
902
  continue;
703
903
  }
704
-
904
+
705
905
  // Check if DOKO has domain claims
706
906
  const doko = cached.doko;
707
907
  if (doko.claims?.domains) {
@@ -726,6 +926,35 @@ export class NamcheGateway extends EventEmitter {
726
926
  revocationsCount: this.revocationLog.size,
727
927
  };
728
928
  }
929
+
930
+ /**
931
+ * Create a DOKO with 144T commitment (dual-layer security).
932
+ *
933
+ * This is the recommended way to create DOKOs for full defense-in-depth:
934
+ * - NIST layer: ML-DSA-65 signature
935
+ * - 144T layer: YPC-27 + polynomial binding commitment
936
+ *
937
+ * @param {Object} dokoFields — DOKO fields (type, nodeId, publicKey, etc.)
938
+ * @param {string} secretKey — Sender's ML-DSA-65 secret key (hex)
939
+ * @param {TritAddress} senderAddress — Sender's 144T mesh address
940
+ * @returns {Object} — Complete DOKO with signature and tritCommitment
941
+ */
942
+ static createDokoWithCommitment(dokoFields, secretKey, senderAddress) {
943
+ // Canonicalize for deterministic signing
944
+ const payload = canonicalize(dokoFields);
945
+
946
+ // Layer 1: NIST signature (ML-DSA-65)
947
+ const signature = signMessage(payload, secretKey);
948
+
949
+ // Layer 2: 144T commitment (YPC-27 + polynomial binding)
950
+ const tritCommitment = TritCommitment.create(dokoFields, senderAddress);
951
+
952
+ return {
953
+ ...dokoFields,
954
+ signature,
955
+ tritCommitment,
956
+ };
957
+ }
729
958
  }
730
959
 
731
960
  export default NamcheGateway;