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
@@ -0,0 +1,464 @@
1
+ /**
2
+ * TRIT COMMITMENT — 144T Cryptographic Backbone
3
+ *
4
+ * Provides a ternary cryptographic layer that runs ALONGSIDE NIST algorithms.
5
+ * This is defense-in-depth: both NIST (ML-DSA-65) AND 144T must verify for
6
+ * a message to be trusted.
7
+ *
8
+ * ═══════════════════════════════════════════════════════════════════════════════
9
+ * ⚠️ SECURITY: This is the 144T backbone, not a replacement for NIST.
10
+ * Both layers must be broken to compromise a message.
11
+ * 144T provides quantum-hard SIS-based integrity independent of NIST.
12
+ * ═══════════════════════════════════════════════════════════════════════════════
13
+ *
14
+ * The math:
15
+ * - YPC-27 operates in ring Z[x]/(x^27 - 1) mod 3
16
+ * - Forging a YPC-27 checksum requires solving the Shortest Vector Problem (SIS)
17
+ * - 144T provides 3^144 ≈ 10^68 address space (~256-bit quantum equivalent)
18
+ * - Combined binding uses polynomial multiplication for non-separability
19
+ *
20
+ * Commitment Structure:
21
+ * {
22
+ * senderAddress: "144-trit address (base64 encoded)",
23
+ * ypc27: "YPC-27 checksum (hex)",
24
+ * binding: "address ⊗ payload polynomial (hex)"
25
+ * }
26
+ *
27
+ * The binding ensures:
28
+ * 1. Address cannot be separated from payload (polynomial non-commutativity)
29
+ * 2. YPC-27 provides lattice-hard integrity independent of SHA/NIST
30
+ * 3. 144T address pins the commitment to a specific mesh location
31
+ *
32
+ * @module security/trit-commitment
33
+ * @version 1.0.0
34
+ * @license MIT
35
+ * @copyright 2026 YAKMESH™ Contributors
36
+ */
37
+
38
+ import { sha3_256 } from '../utils/accel.js';
39
+ import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';
40
+ import { TritAddress, TOTAL_TRITS } from '../oracle/ternary-144t.js';
41
+ import { Poly27, YPC27_SST, DEFAULT_SEED, bytesToTrits, tritsToBytes, N } from '../oracle/ypc27.js';
42
+ import { createLogger } from '../utils/logger.js';
43
+
44
+ const log = createLogger('security:trit-commitment');
45
+
46
+ // =============================================================================
47
+ // CONSTANTS
48
+ // =============================================================================
49
+
50
+ /** Commitment version for future compatibility */
51
+ export const COMMITMENT_VERSION = 1;
52
+
53
+ /** Number of trits extracted from payload hash for binding */
54
+ const BINDING_TRITS = 27;
55
+
56
+ // =============================================================================
57
+ // HELPER FUNCTIONS
58
+ // =============================================================================
59
+
60
+ /**
61
+ * Convert a Poly27 to hex string.
62
+ * Converts trit coefficients to bytes then to hex.
63
+ * @param {Poly27} poly
64
+ * @returns {string}
65
+ */
66
+ function poly27ToHex(poly) {
67
+ const trits = poly.toTypedArray();
68
+ // Pad to 30 trits (divisible by 5 for clean byte packing)
69
+ const padded = new Int8Array(30);
70
+ for (let i = 0; i < N; i++) {
71
+ padded[i] = trits[i];
72
+ }
73
+ const bytes = tritsToBytes(padded);
74
+ return bytesToHex(bytes);
75
+ }
76
+
77
+ /**
78
+ * Convert hex string back to Poly27.
79
+ * @param {string} hex
80
+ * @returns {Poly27}
81
+ */
82
+ function hexToPoly27(hex) {
83
+ return Poly27.fromHex(hex);
84
+ }
85
+
86
+ /**
87
+ * Encode 144 trits as base64 for compact transmission.
88
+ * @param {Int8Array} trits — 144 trits (-1, 0, +1)
89
+ * @returns {string} base64-encoded
90
+ */
91
+ function encodeTrits144(trits) {
92
+ // Pad to 145 trits (divisible by 5)
93
+ const padded = new Int8Array(145);
94
+ for (let i = 0; i < TOTAL_TRITS; i++) {
95
+ padded[i] = trits[i];
96
+ }
97
+ const bytes = tritsToBytes(padded);
98
+ return Buffer.from(bytes).toString('base64');
99
+ }
100
+
101
+ /**
102
+ * Decode base64 to 144 trits.
103
+ * @param {string} encoded — base64-encoded trits
104
+ * @returns {Int8Array}
105
+ */
106
+ function decodeTrits144(encoded) {
107
+ const bytes = new Uint8Array(Buffer.from(encoded, 'base64'));
108
+ const trits = bytesToTrits(bytes);
109
+ // Trim to exactly 144 trits
110
+ return new Int8Array(trits.slice(0, TOTAL_TRITS));
111
+ }
112
+
113
+ /**
114
+ * Extract 27 trits from a SHA3-256 hash for polynomial binding.
115
+ * Uses the first ~6 bytes of the hash.
116
+ * @param {Uint8Array} hash — 32-byte hash
117
+ * @returns {Int8Array} — 27 trits
118
+ */
119
+ function hashToTrits27(hash) {
120
+ // Extract 27 trits from the hash (5 trits per byte, need 6 bytes = 30 trits)
121
+ const trits = bytesToTrits(hash.slice(0, 6));
122
+ return new Int8Array(trits.slice(0, BINDING_TRITS));
123
+ }
124
+
125
+ /**
126
+ * Extract a Poly27 from the first 27 trits of a 144T address.
127
+ * Uses the NODE tier (last 36 trits), taking only the first 27.
128
+ * @param {TritAddress} address — 144-trit address
129
+ * @returns {Poly27}
130
+ */
131
+ function addressToPoly27(address) {
132
+ // Use NODE tier (index 3), which is the identity-specific portion
133
+ const nodeTier = address.getTier(3); // 36 trits
134
+ // Take first 27 trits for polynomial
135
+ const poly27Trits = new Int8Array(nodeTier.slice(0, N));
136
+ return new Poly27(poly27Trits);
137
+ }
138
+
139
+ /**
140
+ * Canonicalize an object for deterministic hashing.
141
+ * Same as NAMCHE gateway's canonicalize function.
142
+ * @param {any} obj
143
+ * @returns {string}
144
+ */
145
+ function canonicalize(obj) {
146
+ if (obj === null || typeof obj !== 'object') {
147
+ return JSON.stringify(obj);
148
+ }
149
+ if (Array.isArray(obj)) {
150
+ return '[' + obj.map(canonicalize).join(',') + ']';
151
+ }
152
+ const keys = Object.keys(obj).sort();
153
+ return '{' + keys.map(k => JSON.stringify(k) + ':' + canonicalize(obj[k])).join(',') + '}';
154
+ }
155
+
156
+ // =============================================================================
157
+ // TRIT COMMITMENT CLASS
158
+ // =============================================================================
159
+
160
+ /**
161
+ * Generate and verify 144T commitments.
162
+ *
163
+ * @example
164
+ * const commitment = TritCommitment.create(payload, senderAddress);
165
+ * // {
166
+ * // version: 1,
167
+ * // senderAddress: "base64-encoded 144T address",
168
+ * // ypc27: "hex checksum",
169
+ * // binding: "hex polynomial binding"
170
+ * // }
171
+ *
172
+ * const isValid = TritCommitment.verify(payload, commitment);
173
+ */
174
+ export class TritCommitment {
175
+ /**
176
+ * Create a 144T commitment for a payload.
177
+ *
178
+ * The commitment binds the sender's 144T address to the payload using:
179
+ * 1. YPC-27 checksum of the canonical payload
180
+ * 2. Polynomial multiplication: addressPoly ⊗ payloadHashPoly
181
+ *
182
+ * @param {Object|string|Uint8Array} payload — message payload (will be canonicalized if object)
183
+ * @param {TritAddress} senderAddress — sender's 144T mesh address
184
+ * @param {Poly27|number[]} [seed] — optional custom seed (defaults to network seed)
185
+ * @returns {Object} commitment object
186
+ */
187
+ static create(payload, senderAddress, seed = DEFAULT_SEED) {
188
+ // Canonicalize payload
189
+ const payloadStr = typeof payload === 'object'
190
+ ? canonicalize(payload)
191
+ : typeof payload === 'string'
192
+ ? payload
193
+ : bytesToHex(payload);
194
+
195
+ const payloadBytes = utf8ToBytes(payloadStr);
196
+
197
+ // 1. Compute YPC-27 checksum with SST rotation
198
+ const hasher = new YPC27_SST(seed);
199
+ hasher.update(payloadBytes);
200
+ const ypc27Hex = hasher.digestHex();
201
+
202
+ // 2. Compute SHA3-256 of payload for polynomial binding
203
+ const payloadHash = sha3_256(payloadBytes);
204
+ const payloadTrits27 = hashToTrits27(payloadHash);
205
+ const payloadPoly = new Poly27(payloadTrits27);
206
+
207
+ // 3. Extract address polynomial
208
+ const addressPoly = addressToPoly27(senderAddress);
209
+
210
+ // 4. Compute binding: address ⊗ payload (cyclic convolution in Z[x]/(x^27-1) mod 3)
211
+ // This is non-separable — you cannot extract addressPoly from the binding
212
+ // without knowing payloadPoly (and vice versa)
213
+ const binding = addressPoly.multiply(payloadPoly);
214
+ const bindingHex = poly27ToHex(binding);
215
+
216
+ // 5. Encode address for transmission
217
+ const addressEncoded = encodeTrits144(senderAddress.toTrits());
218
+
219
+ log.debug('Created 144T commitment', {
220
+ ypc27: ypc27Hex.slice(0, 12) + '...',
221
+ binding: bindingHex.slice(0, 12) + '...'
222
+ });
223
+
224
+ return {
225
+ version: COMMITMENT_VERSION,
226
+ senderAddress: addressEncoded,
227
+ ypc27: ypc27Hex,
228
+ binding: bindingHex,
229
+ };
230
+ }
231
+
232
+ /**
233
+ * Verify a 144T commitment against a payload.
234
+ *
235
+ * @param {Object|string|Uint8Array} payload — original payload
236
+ * @param {Object} commitment — commitment object from create()
237
+ * @param {Poly27|number[]} [seed] — optional custom seed (must match create())
238
+ * @returns {Object} verification result
239
+ */
240
+ static verify(payload, commitment, seed = DEFAULT_SEED) {
241
+ const result = {
242
+ valid: false,
243
+ checks: [],
244
+ reason: null,
245
+ detail: null,
246
+ };
247
+
248
+ try {
249
+ // ─────────────────────────────────────────────────────────────────────
250
+ // CHECK 1: Version compatibility
251
+ // ─────────────────────────────────────────────────────────────────────
252
+ if (commitment.version !== COMMITMENT_VERSION) {
253
+ result.reason = 'VERSION_MISMATCH';
254
+ result.detail = `Expected version ${COMMITMENT_VERSION}, got ${commitment.version}`;
255
+ return result;
256
+ }
257
+ result.checks.push('VERSION_OK');
258
+
259
+ // ─────────────────────────────────────────────────────────────────────
260
+ // CHECK 2: Structure validity
261
+ // ─────────────────────────────────────────────────────────────────────
262
+ const required = ['version', 'senderAddress', 'ypc27', 'binding'];
263
+ for (const field of required) {
264
+ if (!(field in commitment)) {
265
+ result.reason = 'MALFORMED_STRUCTURE';
266
+ result.detail = `Missing required field: ${field}`;
267
+ return result;
268
+ }
269
+ }
270
+ result.checks.push('STRUCTURE_OK');
271
+
272
+ // ─────────────────────────────────────────────────────────────────────
273
+ // CHECK 3: Decode sender address
274
+ // ─────────────────────────────────────────────────────────────────────
275
+ let senderAddress;
276
+ try {
277
+ const addressTrits = decodeTrits144(commitment.senderAddress);
278
+ senderAddress = new TritAddress(addressTrits);
279
+ } catch (e) {
280
+ result.reason = 'INVALID_ADDRESS';
281
+ result.detail = `Failed to decode sender address: ${e.message}`;
282
+ return result;
283
+ }
284
+ result.checks.push('ADDRESS_DECODED');
285
+
286
+ // ─────────────────────────────────────────────────────────────────────
287
+ // CHECK 4: Recompute YPC-27 and compare
288
+ // ─────────────────────────────────────────────────────────────────────
289
+ const payloadStr = typeof payload === 'object'
290
+ ? canonicalize(payload)
291
+ : typeof payload === 'string'
292
+ ? payload
293
+ : bytesToHex(payload);
294
+
295
+ const payloadBytes = utf8ToBytes(payloadStr);
296
+ const hasher = new YPC27_SST(seed);
297
+ hasher.update(payloadBytes);
298
+ const expectedYpc27Hex = hasher.digestHex();
299
+
300
+ if (commitment.ypc27 !== expectedYpc27Hex) {
301
+ result.reason = 'YPC27_MISMATCH';
302
+ result.detail = 'YPC-27 checksum does not match payload';
303
+ return result;
304
+ }
305
+ result.checks.push('YPC27_VALID');
306
+
307
+ // ─────────────────────────────────────────────────────────────────────
308
+ // CHECK 5: Recompute binding and compare
309
+ // ─────────────────────────────────────────────────────────────────────
310
+ const payloadHash = sha3_256(payloadBytes);
311
+ const payloadTrits27 = hashToTrits27(payloadHash);
312
+ const payloadPoly = new Poly27(payloadTrits27);
313
+ const addressPoly = addressToPoly27(senderAddress);
314
+ const expectedBinding = addressPoly.multiply(payloadPoly);
315
+ const expectedBindingHex = poly27ToHex(expectedBinding);
316
+
317
+ if (commitment.binding !== expectedBindingHex) {
318
+ result.reason = 'BINDING_MISMATCH';
319
+ result.detail = 'Polynomial binding does not match address and payload';
320
+ return result;
321
+ }
322
+ result.checks.push('BINDING_VALID');
323
+
324
+ // ═══════════════════════════════════════════════════════════════════════
325
+ // ALL CHECKS PASSED
326
+ // ═══════════════════════════════════════════════════════════════════════
327
+ result.valid = true;
328
+ result.reason = '144T_VERIFIED';
329
+ result.senderAddress = senderAddress;
330
+
331
+ log.debug('144T commitment verified', { checks: result.checks });
332
+
333
+ return result;
334
+
335
+ } catch (error) {
336
+ result.reason = 'VERIFICATION_ERROR';
337
+ result.detail = error.message;
338
+ return result;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Quick check if a commitment appears structurally valid.
344
+ * Does NOT verify cryptographic properties.
345
+ * @param {Object} commitment
346
+ * @returns {boolean}
347
+ */
348
+ static isValidStructure(commitment) {
349
+ if (!commitment || typeof commitment !== 'object') return false;
350
+ if (commitment.version !== COMMITMENT_VERSION) return false;
351
+ const required = ['senderAddress', 'ypc27', 'binding'];
352
+ return required.every(f => typeof commitment[f] === 'string' && commitment[f].length > 0);
353
+ }
354
+ }
355
+
356
+ // =============================================================================
357
+ // DUAL-LAYER MESSAGE FUNCTIONS
358
+ // =============================================================================
359
+
360
+ /**
361
+ * Create a dual-layer signed message (NIST + 144T).
362
+ * This is the backbone security model: both layers must verify.
363
+ *
364
+ * @param {Object} payload — message payload
365
+ * @param {Function} signNIST — function(payload) => hex signature (ML-DSA-65)
366
+ * @param {TritAddress} senderAddress — sender's 144T address
367
+ * @param {Poly27|number[]} [seed] — optional seed
368
+ * @returns {Object} dual-signed message
369
+ */
370
+ export function createDualLayerMessage(payload, signNIST, senderAddress, seed = DEFAULT_SEED) {
371
+ // Canonicalize for determinism
372
+ const payloadStr = canonicalize(payload);
373
+
374
+ // Layer 1: NIST signature (ML-DSA-65)
375
+ const nistSignature = signNIST(payloadStr);
376
+
377
+ // Layer 2: 144T commitment
378
+ const tritCommitment = TritCommitment.create(payload, senderAddress, seed);
379
+
380
+ return {
381
+ payload,
382
+ nistSignature,
383
+ tritCommitment,
384
+ };
385
+ }
386
+
387
+ /**
388
+ * Verify a dual-layer signed message.
389
+ * BOTH layers must pass for the message to be trusted.
390
+ *
391
+ * @param {Object} message — dual-signed message from createDualLayerMessage()
392
+ * @param {Function} verifyNIST — function(payload, signature, publicKey) => boolean
393
+ * @param {string} senderPublicKey — sender's ML-DSA-65 public key (hex)
394
+ * @param {Poly27|number[]} [seed] — optional seed
395
+ * @returns {Object} verification result
396
+ */
397
+ export function verifyDualLayerMessage(message, verifyNIST, senderPublicKey, seed = DEFAULT_SEED) {
398
+ const result = {
399
+ valid: false,
400
+ nistValid: false,
401
+ tritValid: false,
402
+ nistReason: null,
403
+ tritReason: null,
404
+ checks: [],
405
+ };
406
+
407
+ // ─────────────────────────────────────────────────────────────────────────
408
+ // Layer 1: NIST verification
409
+ // ─────────────────────────────────────────────────────────────────────────
410
+ try {
411
+ const payloadStr = canonicalize(message.payload);
412
+ result.nistValid = verifyNIST(payloadStr, message.nistSignature, senderPublicKey);
413
+ if (result.nistValid) {
414
+ result.checks.push('NIST_SIGNATURE_OK');
415
+ } else {
416
+ result.nistReason = 'ML-DSA-65 signature verification failed';
417
+ }
418
+ } catch (e) {
419
+ result.nistReason = `NIST verification error: ${e.message}`;
420
+ }
421
+
422
+ // ─────────────────────────────────────────────────────────────────────────
423
+ // Layer 2: 144T verification
424
+ // ─────────────────────────────────────────────────────────────────────────
425
+ try {
426
+ const tritResult = TritCommitment.verify(message.payload, message.tritCommitment, seed);
427
+ result.tritValid = tritResult.valid;
428
+ if (tritResult.valid) {
429
+ result.checks.push('144T_COMMITMENT_OK');
430
+ } else {
431
+ result.tritReason = `${tritResult.reason}: ${tritResult.detail || ''}`;
432
+ }
433
+ result.tritChecks = tritResult.checks;
434
+ } catch (e) {
435
+ result.tritReason = `144T verification error: ${e.message}`;
436
+ }
437
+
438
+ // ═══════════════════════════════════════════════════════════════════════
439
+ // BOTH layers must pass
440
+ // ═══════════════════════════════════════════════════════════════════════
441
+ result.valid = result.nistValid && result.tritValid;
442
+
443
+ if (result.valid) {
444
+ result.checks.push('DUAL_LAYER_VERIFIED');
445
+ }
446
+
447
+ return result;
448
+ }
449
+
450
+ // =============================================================================
451
+ // EXPORTS
452
+ // =============================================================================
453
+
454
+ export {
455
+ encodeTrits144,
456
+ decodeTrits144,
457
+ hashToTrits27,
458
+ addressToPoly27,
459
+ canonicalize,
460
+ poly27ToHex,
461
+ hexToPoly27,
462
+ };
463
+
464
+ export default TritCommitment;