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.
- package/CHANGELOG.md +637 -0
- package/CONTRIBUTING.md +42 -0
- package/Caddyfile +77 -0
- package/README.md +119 -29
- package/adapters/adapter-mlv-bible/README.md +124 -0
- package/adapters/adapter-mlv-bible/index.js +400 -0
- package/adapters/chat-mod-adapter.js +532 -0
- package/adapters/content-adapter.js +273 -0
- package/content/api.js +50 -41
- package/content/index.js +2 -2
- package/content/store.js +355 -173
- package/dashboard/index.html +19 -3
- package/database/replication.js +117 -37
- package/docs/CRYPTO-AGILITY.md +204 -0
- package/docs/MTLS-RESEARCH.md +367 -0
- package/docs/NAMCHE-SPEC.md +681 -0
- package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
- package/docs/PRECISION-DISCLOSURE.md +96 -0
- package/docs/README.md +76 -0
- package/docs/ROADMAP-2.4.0.md +447 -0
- package/docs/ROADMAP-2.5.0.md +244 -0
- package/docs/SECURITY-AUDIT-REPORT.md +306 -0
- package/docs/SST-INTEGRATION.md +712 -0
- package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
- package/docs/TERNARY-AUDIT-REPORT.md +247 -0
- package/docs/TME-FAQ.md +221 -0
- package/docs/WHITEPAPER.md +623 -0
- package/docs/adapters.html +1001 -0
- package/docs/advanced-systems.html +1045 -0
- package/docs/annex.html +1046 -0
- package/docs/api.html +970 -0
- package/docs/business/response-templates.md +160 -0
- package/docs/c2c.html +1225 -0
- package/docs/cli.html +1332 -0
- package/docs/configuration.html +1248 -0
- package/docs/darshan.html +1085 -0
- package/docs/dharma.html +966 -0
- package/docs/docs-bundle.html +1075 -0
- package/docs/docs.css +3120 -0
- package/docs/docs.js +556 -0
- package/docs/doko.html +969 -0
- package/docs/geo-proof.html +858 -0
- package/docs/getting-started.html +840 -0
- package/docs/gumba-tutorial.html +1144 -0
- package/docs/gumba.html +1098 -0
- package/docs/index.html +914 -0
- package/docs/jhilke.html +1312 -0
- package/docs/karma.html +1100 -0
- package/docs/katha.html +1037 -0
- package/docs/lama.html +978 -0
- package/docs/mandala.html +1067 -0
- package/docs/mani.html +964 -0
- package/docs/mantra.html +967 -0
- package/docs/mesh.html +1409 -0
- package/docs/nakpak.html +869 -0
- package/docs/namche.html +928 -0
- package/docs/nav-order.json +53 -0
- package/docs/prahari.html +1043 -0
- package/docs/prism-bash.min.js +1 -0
- package/docs/prism-javascript.min.js +1 -0
- package/docs/prism-json.min.js +1 -0
- package/docs/prism-tomorrow.min.css +1 -0
- package/docs/prism.min.js +1 -0
- package/docs/privacy.html +699 -0
- package/docs/quick-reference.html +1181 -0
- package/docs/sakshi.html +1402 -0
- package/docs/sandboxing.md +386 -0
- package/docs/seva.html +911 -0
- package/docs/sherpa.html +871 -0
- package/docs/studio.html +860 -0
- package/docs/stupa.html +995 -0
- package/docs/tailwind.min.css +2 -0
- package/docs/tattva.html +1332 -0
- package/docs/terms.html +686 -0
- package/docs/time-server-deployment.md +166 -0
- package/docs/time-sources.html +1392 -0
- package/docs/tivra.html +1127 -0
- package/docs/trademark-policy.html +686 -0
- package/docs/tribhuj.html +1183 -0
- package/docs/trust-security.html +1029 -0
- package/docs/tutorials/backup-recovery.html +654 -0
- package/docs/tutorials/dashboard.html +604 -0
- package/docs/tutorials/domain-setup.html +605 -0
- package/docs/tutorials/host-website.html +456 -0
- package/docs/tutorials/mesh-network.html +505 -0
- package/docs/tutorials/mobile-access.html +445 -0
- package/docs/tutorials/privacy.html +467 -0
- package/docs/tutorials/raspberry-pi.html +600 -0
- package/docs/tutorials/security-basics.html +539 -0
- package/docs/tutorials/share-files.html +431 -0
- package/docs/tutorials/troubleshooting.html +637 -0
- package/docs/tutorials/trust-karma.html +419 -0
- package/docs/tutorials/yak-protocol.html +456 -0
- package/docs/tutorials.html +1034 -0
- package/docs/vani.html +1270 -0
- package/docs/webserver.html +809 -0
- package/docs/yak-protocol.html +940 -0
- package/docs/yak-timeserver-design.md +475 -0
- package/docs/yakapp.html +1015 -0
- package/docs/ypc27.html +1069 -0
- package/docs/yurt.html +1344 -0
- package/embedded-docs/bundle.js +334 -74
- package/gossip/protocol.js +247 -27
- package/identity/key-resolver.js +262 -0
- package/identity/machine-seed.js +632 -0
- package/identity/node-key.js +669 -368
- package/identity/tribhuj-ratchet.js +506 -0
- package/knowledge-base.js +37 -8
- package/launcher/yakmesh.bat +62 -0
- package/launcher/yakmesh.sh +70 -0
- package/mesh/annex.js +462 -108
- package/mesh/beacon-broadcast.js +113 -1
- package/mesh/darshan.js +1718 -0
- package/mesh/gumba.js +1567 -0
- package/mesh/jhilke.js +651 -0
- package/mesh/katha.js +1012 -0
- package/mesh/nakpak-routing.js +8 -5
- package/mesh/network.js +724 -34
- package/mesh/pulse-sync.js +4 -1
- package/mesh/rate-limiter.js +127 -15
- package/mesh/seva.js +526 -0
- package/mesh/sherpa-discovery.js +89 -8
- package/mesh/sybil-defense.js +19 -5
- package/mesh/temporal-encoder.js +4 -3
- package/mesh/vani.js +1364 -0
- package/mesh/yurt.js +1340 -0
- package/models/entropy-sentinel.onnx +0 -0
- package/models/karma-trust.onnx +0 -0
- package/models/manifest.json +43 -0
- package/models/sakshi-anomaly.onnx +0 -0
- package/oracle/code-proof-protocol.js +7 -6
- package/oracle/codebase-lock.js +257 -28
- package/oracle/index.js +74 -15
- package/oracle/ma902-snmp.js +678 -0
- package/oracle/module-sealer.js +5 -3
- package/oracle/network-identity.js +16 -0
- package/oracle/packet-checksum.js +201 -0
- package/oracle/sst.js +579 -0
- package/oracle/ternary-144t.js +714 -0
- package/oracle/ternary-ml.js +481 -0
- package/oracle/time-api.js +239 -0
- package/oracle/time-source.js +137 -47
- package/oracle/validation-oracle-hardened.js +1111 -1071
- package/oracle/validation-oracle.js +4 -2
- package/oracle/ypc27.js +211 -0
- package/package.json +20 -3
- package/protocol/yak-handler.js +35 -9
- package/protocol/yak-protocol.js +28 -13
- package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
- package/reference/cpp/yakmesh_ypc27.cpp +179 -0
- package/sbom.json +87 -0
- package/scripts/security-audit.mjs +264 -0
- package/scripts/update-docs-nav.js +194 -0
- package/scripts/update-docs-sidebar.cjs +164 -0
- package/security/crypto-config.js +4 -3
- package/security/dharma-moderation.js +517 -0
- package/security/doko-identity.js +193 -143
- package/security/domain-consensus.js +86 -85
- package/security/fs-hardening.js +620 -0
- package/security/hardware-attestation.js +5 -3
- package/security/hybrid-trust.js +227 -87
- package/security/karma-rate-limiter.js +692 -0
- package/security/khata-protocol.js +22 -21
- package/security/khata-trust-integration.js +277 -150
- package/security/memory-safety.js +635 -0
- package/security/mesh-auth.js +11 -10
- package/security/mesh-revocation.js +373 -5
- package/security/namche-gateway.js +298 -69
- package/security/sakshi.js +460 -3
- package/security/sangha.js +770 -0
- package/security/secure-config.js +473 -0
- package/security/silicon-parity.js +13 -10
- package/security/steadywatch.js +1142 -0
- package/security/strike-system.js +32 -3
- package/security/temporal-signing.js +488 -0
- package/security/trit-commitment.js +464 -0
- package/server/crypto/annex.js +247 -0
- package/server/darshan-api.js +343 -0
- package/server/index.js +3259 -362
- package/server/komm-api.js +668 -0
- package/utils/accel.js +2273 -0
- package/utils/ternary-id.js +79 -0
- package/utils/verify-worker.js +57 -0
- package/webserver/index.js +95 -5
- package/assets/yakmesh-logo.png +0 -0
- package/assets/yakmesh-logo.svg +0 -80
- package/assets/yakmesh-logo2.png +0 -0
- package/assets/yakmesh-logo2sm.png +0 -0
- package/assets/ymsm.png +0 -0
- package/website/assets/silhouettes/adapters.svg +0 -107
- package/website/assets/silhouettes/api-endpoints.svg +0 -115
- package/website/assets/silhouettes/atomic-clock.svg +0 -83
- package/website/assets/silhouettes/base-camp.svg +0 -81
- package/website/assets/silhouettes/bridge.svg +0 -69
- package/website/assets/silhouettes/docs-bundle.svg +0 -113
- package/website/assets/silhouettes/doko-basket.svg +0 -70
- package/website/assets/silhouettes/fortress.svg +0 -93
- package/website/assets/silhouettes/gateway.svg +0 -54
- package/website/assets/silhouettes/gears.svg +0 -93
- package/website/assets/silhouettes/globe-satellite.svg +0 -67
- package/website/assets/silhouettes/karma-wheel.svg +0 -137
- package/website/assets/silhouettes/lama-council.svg +0 -141
- package/website/assets/silhouettes/mandala-network.svg +0 -169
- package/website/assets/silhouettes/mani-stones.svg +0 -149
- package/website/assets/silhouettes/mantra-wheel.svg +0 -116
- package/website/assets/silhouettes/mesh-nodes.svg +0 -113
- package/website/assets/silhouettes/nakpak.svg +0 -56
- package/website/assets/silhouettes/peak-lightning.svg +0 -73
- package/website/assets/silhouettes/sherpa.svg +0 -69
- package/website/assets/silhouettes/stupa-tower.svg +0 -119
- package/website/assets/silhouettes/tattva-eye.svg +0 -78
- package/website/assets/silhouettes/terminal.svg +0 -74
- package/website/assets/silhouettes/webserver.svg +0 -145
- package/website/assets/silhouettes/yak.svg +0 -78
- package/website/assets/yakmesh-logo.png +0 -0
- package/website/assets/yakmesh-logo.webp +0 -0
- package/website/assets/yakmesh-logo128x140.webp +0 -0
- package/website/assets/yakmesh-logo2.png +0 -0
- package/website/assets/yakmesh-logo2.svg +0 -51
- package/website/assets/yakmesh-logo40x44.webp +0 -0
- package/website/assets/yakmesh.gif +0 -0
- package/website/assets/yakmesh.ico +0 -0
- package/website/assets/yakmesh.jpg +0 -0
- package/website/assets/yakmesh.pdf +0 -0
- package/website/assets/yakmesh.png +0 -0
- package/website/assets/yakmesh.svg +0 -70
- package/website/assets/yakmesh128.webp +0 -0
- package/website/assets/yakmesh32.png +0 -0
- package/website/assets/yakmesh32.svg +0 -65
- package/website/assets/yakmesh32o.ico +0 -2
- package/website/assets/yakmesh32o.svg +0 -65
- 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;
|