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.
- package/CHANGELOG.md +637 -0
- package/Caddyfile +77 -0
- package/README.md +119 -29
- package/content/api.js +50 -41
- package/content/index.js +1 -2
- package/content/store.js +323 -177
- 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 +274 -114
- 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 +4 -1
- package/mesh/darshan.js +17 -5
- package/mesh/gumba.js +47 -13
- package/mesh/jhilke.js +651 -0
- package/mesh/katha.js +5 -2
- package/mesh/nakpak-routing.js +8 -5
- package/mesh/network.js +724 -34
- package/mesh/pulse-sync.js +4 -1
- 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/yurt.js +72 -17
- 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/packet-checksum.js +201 -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 +6 -5
- 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-sidebar.cjs +164 -0
- package/security/crypto-config.js +4 -3
- package/security/dharma-moderation.js +4 -3
- 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 +18 -5
- package/security/namche-gateway.js +298 -69
- package/security/sakshi.js +102 -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/scripts/update-docs-nav.cjs +0 -194
- package/update-docs-nav.cjs +0 -18
- package/update-nav.ps1 +0 -16
- 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
package/dashboard/index.html
CHANGED
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
</div>
|
|
324
324
|
|
|
325
325
|
<div class="connection-bar">
|
|
326
|
-
<input type="text" id="node-url"
|
|
326
|
+
<input type="text" id="node-url" placeholder="Node HTTP URL">
|
|
327
327
|
<button onclick="connect()">Connect</button>
|
|
328
328
|
<div class="status-indicator">
|
|
329
329
|
<div class="status-dot" id="status-dot"></div>
|
|
@@ -518,10 +518,18 @@
|
|
|
518
518
|
</div>
|
|
519
519
|
|
|
520
520
|
<script>
|
|
521
|
-
|
|
521
|
+
// Default to current origin (where dashboard was loaded from)
|
|
522
|
+
let nodeUrl = window.location.origin;
|
|
522
523
|
let connected = false;
|
|
523
524
|
let refreshInterval = null;
|
|
524
525
|
|
|
526
|
+
// Initialize input field with current origin on load
|
|
527
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
528
|
+
document.getElementById('node-url').value = nodeUrl;
|
|
529
|
+
// Auto-connect since we're served by the node
|
|
530
|
+
connect();
|
|
531
|
+
});
|
|
532
|
+
|
|
525
533
|
// Helper function to format bytes
|
|
526
534
|
function formatBytes(bytes) {
|
|
527
535
|
if (bytes === 0) return '0 B';
|
|
@@ -617,6 +625,13 @@
|
|
|
617
625
|
<div style="margin-top: 0.5rem;">
|
|
618
626
|
Classical: ${crypto.classicalSecurity} | Quantum: ${crypto.quantumSecurity}
|
|
619
627
|
</div>
|
|
628
|
+
${crypto.routingSecurity ? `
|
|
629
|
+
<div style="margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--border);">
|
|
630
|
+
<span style="color: var(--frost)">144T Routing:</span>
|
|
631
|
+
<span style="color: var(--mountain); font-weight: 600;">${crypto.routingSecurity}</span>
|
|
632
|
+
<div style="font-size: 0.75rem; color: var(--text-dim); margin-top: 0.25rem;">3^144 ≈ 10^68 address space • Grover-resistant</div>
|
|
633
|
+
</div>
|
|
634
|
+
` : ''}
|
|
620
635
|
<div style="margin-top: 0.5rem; font-size: 0.75rem;">
|
|
621
636
|
${crypto.nistStandards?.join(' • ') || ''}
|
|
622
637
|
</div>
|
|
@@ -715,8 +730,9 @@
|
|
|
715
730
|
<div style="width: 12px; height: 12px; border-radius: 50%; background: ${statusColor}; box-shadow: 0 0 8px ${statusColor};"></div>
|
|
716
731
|
<span style="font-weight: 600; color: ${statusColor}">${website.status?.toUpperCase() || 'INACTIVE'}</span>
|
|
717
732
|
</div>
|
|
718
|
-
<div>
|
|
733
|
+
<div>Published Manifests: <span style="color: var(--accent)">${website.websites || 0}</span></div>
|
|
719
734
|
<div>.yak Domains: <span style="color: var(--frost)">${website.domains || 0}</span></div>
|
|
735
|
+
<div>Unique Sites: <span style="color: var(--text)">${website.uniqueSites || website.domains || 0}</span></div>
|
|
720
736
|
<div>Files Served: <span style="color: var(--text)">${website.filesServed || 0}</span></div>
|
|
721
737
|
<div>Bytes Served: <span style="color: var(--text)">${formatBytes(website.bytesServed || 0)}</span></div>
|
|
722
738
|
${website.status === 'active' ? `
|
package/database/replication.js
CHANGED
|
@@ -44,6 +44,7 @@ export class ReplicationEngine {
|
|
|
44
44
|
this.dbPath = dbPath;
|
|
45
45
|
this.db = null;
|
|
46
46
|
this.nodeId = mesh.identity.identity.nodeId;
|
|
47
|
+
this.identity = mesh.identity; // For ML-DSA-65 signing/verification
|
|
47
48
|
this.syncInterval = null;
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -98,6 +99,13 @@ export class ReplicationEngine {
|
|
|
98
99
|
// Index already exists
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
// Add signature column for ML-DSA-65 authenticated replication
|
|
103
|
+
try {
|
|
104
|
+
this.db.run(`ALTER TABLE _replication_log ADD COLUMN signature TEXT`);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
// Column already exists
|
|
107
|
+
}
|
|
108
|
+
|
|
101
109
|
this._saveDb();
|
|
102
110
|
log.info('Database initialized', { path: this.dbPath });
|
|
103
111
|
|
|
@@ -143,12 +151,20 @@ export class ReplicationEngine {
|
|
|
143
151
|
if (!REPLICATED_TABLES.includes(tableName)) return;
|
|
144
152
|
|
|
145
153
|
const vectorClock = this._generateVectorClock();
|
|
154
|
+
const dataJson = JSON.stringify(data);
|
|
155
|
+
|
|
156
|
+
// Sign the change payload (ML-DSA-65) for authenticated replication
|
|
157
|
+
const sigPayload = JSON.stringify({
|
|
158
|
+
tableName, rowId: String(rowId), operation, data: dataJson,
|
|
159
|
+
nodeId: this.nodeId, vectorClock,
|
|
160
|
+
});
|
|
161
|
+
const signature = this.identity.sign(sigPayload);
|
|
146
162
|
|
|
147
163
|
this.db.run(
|
|
148
164
|
`INSERT INTO _replication_log
|
|
149
|
-
(table_name, row_id, operation, data, node_id, vector_clock, created_at)
|
|
150
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
151
|
-
[tableName, String(rowId), operation,
|
|
165
|
+
(table_name, row_id, operation, data, node_id, vector_clock, created_at, signature)
|
|
166
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
167
|
+
[tableName, String(rowId), operation, dataJson, this.nodeId, vectorClock, Date.now(), signature]
|
|
152
168
|
);
|
|
153
169
|
|
|
154
170
|
this._saveDb();
|
|
@@ -169,14 +185,20 @@ export class ReplicationEngine {
|
|
|
169
185
|
* Sync with a specific peer
|
|
170
186
|
*/
|
|
171
187
|
async syncWithPeer(peerNodeId) {
|
|
172
|
-
// Get last sync state for this peer
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
188
|
+
// Get last sync state for this peer (parameterized to prevent SQL injection)
|
|
189
|
+
let lastSyncAt = 0;
|
|
190
|
+
try {
|
|
191
|
+
const stmt = this.db.prepare(
|
|
192
|
+
'SELECT last_sync_at FROM _replication_state WHERE peer_node_id = ?'
|
|
193
|
+
);
|
|
194
|
+
stmt.bind([peerNodeId]);
|
|
195
|
+
if (stmt.step()) {
|
|
196
|
+
lastSyncAt = stmt.get()[0] || 0;
|
|
197
|
+
}
|
|
198
|
+
stmt.free();
|
|
199
|
+
} catch (e) {
|
|
200
|
+
log.warn('Failed to query sync state', { peer: peerNodeId.slice(0, 12), error: e.message });
|
|
201
|
+
}
|
|
180
202
|
|
|
181
203
|
// Request changes from peer since last sync
|
|
182
204
|
try {
|
|
@@ -194,15 +216,41 @@ export class ReplicationEngine {
|
|
|
194
216
|
* Apply a replicated change from another node
|
|
195
217
|
*/
|
|
196
218
|
applyChange(change) {
|
|
197
|
-
const { table_name, row_id, operation, data, node_id, vector_clock, created_at } = change;
|
|
219
|
+
const { table_name, row_id, operation, data, node_id, vector_clock, created_at, signature } = change;
|
|
198
220
|
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
221
|
+
// Verify ML-DSA-65 signature before trusting remote change
|
|
222
|
+
if (!signature) {
|
|
223
|
+
log.warn('Rejecting unsigned replication change', { nodeId: node_id?.slice(0, 12), table: table_name });
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
const peerPubKey = this._getPeerPublicKey(node_id);
|
|
227
|
+
if (!peerPubKey) {
|
|
228
|
+
log.warn('Rejecting replication change from unknown node (no public key)', { nodeId: node_id?.slice(0, 12) });
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
const sigPayload = JSON.stringify({
|
|
232
|
+
tableName: table_name, rowId: row_id, operation, data,
|
|
233
|
+
nodeId: node_id, vectorClock: vector_clock,
|
|
234
|
+
});
|
|
235
|
+
if (!this.identity.verify(sigPayload, signature, peerPubKey)) {
|
|
236
|
+
log.warn('Rejecting replication change with invalid signature', { nodeId: node_id?.slice(0, 12), table: table_name });
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Check if we already have this change (parameterized)
|
|
241
|
+
let alreadyExists = false;
|
|
242
|
+
try {
|
|
243
|
+
const stmt = this.db.prepare(
|
|
244
|
+
'SELECT id FROM _replication_log WHERE table_name = ? AND row_id = ? AND vector_clock = ?'
|
|
245
|
+
);
|
|
246
|
+
stmt.bind([table_name, row_id, vector_clock]);
|
|
247
|
+
alreadyExists = stmt.step();
|
|
248
|
+
stmt.free();
|
|
249
|
+
} catch (e) {
|
|
250
|
+
log.warn('Failed to check existing change', { error: e.message });
|
|
251
|
+
}
|
|
204
252
|
|
|
205
|
-
if (
|
|
253
|
+
if (alreadyExists) {
|
|
206
254
|
return false; // Already applied
|
|
207
255
|
}
|
|
208
256
|
|
|
@@ -223,26 +271,31 @@ export class ReplicationEngine {
|
|
|
223
271
|
* Get changes since a timestamp
|
|
224
272
|
*/
|
|
225
273
|
getChangesSince(since, tables = REPLICATED_TABLES) {
|
|
226
|
-
const
|
|
274
|
+
const placeholders = tables.map(() => '?').join(',');
|
|
227
275
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
obj[col] = row[i];
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
276
|
+
try {
|
|
277
|
+
const stmt = this.db.prepare(
|
|
278
|
+
`SELECT * FROM _replication_log
|
|
279
|
+
WHERE created_at > ? AND table_name IN (${placeholders})
|
|
280
|
+
ORDER BY created_at ASC
|
|
281
|
+
LIMIT 1000`
|
|
282
|
+
);
|
|
283
|
+
stmt.bind([since, ...tables]);
|
|
284
|
+
|
|
285
|
+
const columns = stmt.getColumnNames();
|
|
286
|
+
const results = [];
|
|
287
|
+
while (stmt.step()) {
|
|
288
|
+
const row = stmt.get();
|
|
289
|
+
const obj = {};
|
|
290
|
+
columns.forEach((col, i) => { obj[col] = row[i]; });
|
|
291
|
+
results.push(obj);
|
|
292
|
+
}
|
|
293
|
+
stmt.free();
|
|
294
|
+
return results;
|
|
295
|
+
} catch (e) {
|
|
296
|
+
log.warn('Failed to get changes', { error: e.message });
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
246
299
|
}
|
|
247
300
|
|
|
248
301
|
/**
|
|
@@ -264,6 +317,33 @@ export class ReplicationEngine {
|
|
|
264
317
|
|
|
265
318
|
// ===== Private Methods =====
|
|
266
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Resolve a peer's public key from mesh state.
|
|
322
|
+
* Checks WS peers, relay keys, SHERPA registry, and self.
|
|
323
|
+
*/
|
|
324
|
+
_getPeerPublicKey(nodeId) {
|
|
325
|
+
// Self
|
|
326
|
+
if (nodeId === this.nodeId) {
|
|
327
|
+
return this.identity.identity.publicKey;
|
|
328
|
+
}
|
|
329
|
+
// WS peer info
|
|
330
|
+
if (this.mesh?.peers) {
|
|
331
|
+
const peer = this.mesh.peers.get(nodeId);
|
|
332
|
+
if (peer?.identity?.publicKey) return peer.identity.publicKey;
|
|
333
|
+
}
|
|
334
|
+
// Relay peer keys (stored during signed registration)
|
|
335
|
+
if (this.mesh?._relayPeerKeys) {
|
|
336
|
+
const key = this.mesh._relayPeerKeys.get(nodeId);
|
|
337
|
+
if (key) return key;
|
|
338
|
+
}
|
|
339
|
+
// SHERPA registry
|
|
340
|
+
if (this.mesh?.sherpa?.registry) {
|
|
341
|
+
const regPeer = this.mesh.sherpa.registry.get(nodeId);
|
|
342
|
+
if (regPeer?.publicKey) return regPeer.publicKey;
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
267
347
|
_generateVectorClock() {
|
|
268
348
|
const timestamp = Date.now();
|
|
269
349
|
const random = Math.random().toString(36).slice(2, 8);
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Cryptographic Agility in Yakmesh
|
|
2
|
+
|
|
3
|
+
This document formalizes Yakmesh's approach to cryptographic agility—the ability to transition between cryptographic algorithms as standards evolve and new threats emerge.
|
|
4
|
+
|
|
5
|
+
## Current Cryptographic Stack
|
|
6
|
+
|
|
7
|
+
| Purpose | Algorithm | Standard | Security Level |
|
|
8
|
+
|---------|-----------|----------|----------------|
|
|
9
|
+
| **Digital Signatures** | ML-DSA-65/87 | FIPS 204 | NIST Level 3/5 |
|
|
10
|
+
| **Key Encapsulation** | ML-KEM-768/1024 | FIPS 203 | NIST Level 3/5 |
|
|
11
|
+
| **Symmetric Encryption** | AES-256-GCM | FIPS 197 | 256-bit |
|
|
12
|
+
| **Hash Functions** | SHA3-256 | FIPS 202 | 256-bit |
|
|
13
|
+
| **Key Derivation** | HKDF-SHA3-256 | RFC 5869 | 256-bit |
|
|
14
|
+
|
|
15
|
+
## Security Level Selection
|
|
16
|
+
|
|
17
|
+
Yakmesh supports two NIST security levels:
|
|
18
|
+
|
|
19
|
+
### Level 3 (Default)
|
|
20
|
+
- **Signature**: ML-DSA-65 (Dilithium3)
|
|
21
|
+
- **KEM**: ML-KEM-768 (Kyber768)
|
|
22
|
+
- **Classical Security**: ~192 bits
|
|
23
|
+
- **Quantum Security**: ~128 bits
|
|
24
|
+
- **Use Case**: Standard operations, good performance
|
|
25
|
+
|
|
26
|
+
### Level 5 (Paranoid Mode)
|
|
27
|
+
- **Signature**: ML-DSA-87 (Dilithium5)
|
|
28
|
+
- **KEM**: ML-KEM-1024 (Kyber1024)
|
|
29
|
+
- **Classical Security**: ~256 bits
|
|
30
|
+
- **Quantum Security**: ~192 bits
|
|
31
|
+
- **Use Case**: High-security environments, long-term secrets
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
Set security level in `yakmesh.config.js`:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
export default {
|
|
39
|
+
security: {
|
|
40
|
+
level: 5, // 3 = default, 5 = paranoid
|
|
41
|
+
},
|
|
42
|
+
// ... other config
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or programmatically:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
import { setSecurityLevel, SecurityLevel } from 'yakmesh/security/crypto-config';
|
|
50
|
+
setSecurityLevel(SecurityLevel.LEVEL_5);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Algorithm Upgrade Path
|
|
54
|
+
|
|
55
|
+
### When to Upgrade
|
|
56
|
+
|
|
57
|
+
1. **NIST Recommendations Change**: If NIST deprecates an algorithm
|
|
58
|
+
2. **New Attacks Published**: If cryptanalysis weakens security margins
|
|
59
|
+
3. **Performance Improvements**: When newer algorithms offer better performance
|
|
60
|
+
4. **Standard Updates**: When FIPS standards are revised
|
|
61
|
+
|
|
62
|
+
### Upgrade Procedure
|
|
63
|
+
|
|
64
|
+
1. **Announce Deprecation** (T-90 days)
|
|
65
|
+
- Publish security advisory
|
|
66
|
+
- Update documentation
|
|
67
|
+
- Begin dual-algorithm support period
|
|
68
|
+
|
|
69
|
+
2. **Dual Support Period** (90 days)
|
|
70
|
+
- Accept both old and new algorithms
|
|
71
|
+
- Log deprecation warnings for old algorithm usage
|
|
72
|
+
- Allow nodes to upgrade at their own pace
|
|
73
|
+
|
|
74
|
+
3. **Cutover** (T+0)
|
|
75
|
+
- Stop accepting old algorithms for new connections
|
|
76
|
+
- Existing sessions continue until natural expiry
|
|
77
|
+
- All new handshakes require new algorithm
|
|
78
|
+
|
|
79
|
+
4. **Cleanup** (T+30)
|
|
80
|
+
- Remove old algorithm code
|
|
81
|
+
- Update minimum version requirements
|
|
82
|
+
|
|
83
|
+
### Version Negotiation
|
|
84
|
+
|
|
85
|
+
During handshake, nodes exchange supported algorithms:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"supportedAlgorithms": {
|
|
90
|
+
"signature": ["ML-DSA-87", "ML-DSA-65"],
|
|
91
|
+
"kem": ["ML-KEM-1024", "ML-KEM-768"]
|
|
92
|
+
},
|
|
93
|
+
"preferredLevel": 5
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Nodes select the highest mutually-supported level.
|
|
98
|
+
|
|
99
|
+
## Future Algorithm Candidates
|
|
100
|
+
|
|
101
|
+
### Monitoring List
|
|
102
|
+
|
|
103
|
+
| Algorithm | Type | Status | Notes |
|
|
104
|
+
|-----------|------|--------|-------|
|
|
105
|
+
| **X-Wing** | Hybrid KEM | Draft | ML-KEM + X25519 hybrid |
|
|
106
|
+
| **SLH-DSA** | Signature | ✅ **Implemented** | Hash-based backup signatures (v1.7.0) |
|
|
107
|
+
| **HQC** | KEM | Round 4 | Code-based alternative to ML-KEM |
|
|
108
|
+
| **BIKE** | KEM | Round 4 | Code-based alternative |
|
|
109
|
+
|
|
110
|
+
> **Note (v1.7.0):** SLH-DSA is now implemented as backup signatures! Use `signDual()` and `verifyDual()` for defense-in-depth with both lattice-based (ML-DSA) and hash-based (SLH-DSA) algorithms.
|
|
111
|
+
|
|
112
|
+
### Hybrid Approach (Future)
|
|
113
|
+
|
|
114
|
+
When NIST finalizes hybrid standards, Yakmesh will support:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
SharedSecret = KDF(ML-KEM-SharedSecret || X25519-SharedSecret)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This provides defense-in-depth: both PQ and classical algorithms must be broken.
|
|
121
|
+
|
|
122
|
+
## Hash Function Strategy
|
|
123
|
+
|
|
124
|
+
### Current: SHA3-256 Everywhere
|
|
125
|
+
|
|
126
|
+
Yakmesh uses SHA3-256 (Keccak) for all hashing:
|
|
127
|
+
- Content addressing
|
|
128
|
+
- Oracle validation
|
|
129
|
+
- Key derivation context
|
|
130
|
+
- Bloom filter hashing
|
|
131
|
+
|
|
132
|
+
### Rationale
|
|
133
|
+
|
|
134
|
+
1. **SHA3 is Grover-resistant**: 256-bit hash provides 128-bit quantum security
|
|
135
|
+
2. **Different construction**: SHA3 uses sponge construction vs SHA2's Merkle-Damgård
|
|
136
|
+
3. **No length-extension**: SHA3 is immune to length-extension attacks
|
|
137
|
+
4. **Future-proof**: Native 256-bit output without truncation
|
|
138
|
+
|
|
139
|
+
## Backward Compatibility
|
|
140
|
+
|
|
141
|
+
### Node Identity Continuity
|
|
142
|
+
|
|
143
|
+
When upgrading algorithms:
|
|
144
|
+
- Node IDs remain stable (derived from codebase hash)
|
|
145
|
+
- Public keys are regenerated with new algorithm
|
|
146
|
+
- Key rotation is transparent to peers
|
|
147
|
+
|
|
148
|
+
### Message Format
|
|
149
|
+
|
|
150
|
+
Crypto parameters are included in message headers:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"cryptoVersion": "1.6.0",
|
|
155
|
+
"signatureAlgo": "ML-DSA-65",
|
|
156
|
+
"kemAlgo": "ML-KEM-768",
|
|
157
|
+
"hashAlgo": "SHA3-256"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Receivers validate algorithm support before processing.
|
|
162
|
+
|
|
163
|
+
## Security Considerations
|
|
164
|
+
|
|
165
|
+
### Key Storage
|
|
166
|
+
|
|
167
|
+
- Private keys are stored locally in `data/node-key.json`
|
|
168
|
+
- Keys are never transmitted over the network
|
|
169
|
+
- Consider HSM integration for enterprise deployments
|
|
170
|
+
|
|
171
|
+
### Algorithm Downgrades
|
|
172
|
+
|
|
173
|
+
- Yakmesh REJECTS algorithm downgrade attempts
|
|
174
|
+
- If peer offers only deprecated algorithms, connection fails
|
|
175
|
+
- Log all downgrade attempts for security monitoring
|
|
176
|
+
|
|
177
|
+
### Side-Channel Resistance
|
|
178
|
+
|
|
179
|
+
The `@noble/post-quantum` library includes:
|
|
180
|
+
- Constant-time implementations
|
|
181
|
+
- Memory-hard operations where applicable
|
|
182
|
+
- No branching on secret data
|
|
183
|
+
|
|
184
|
+
## Audit Trail
|
|
185
|
+
|
|
186
|
+
All cryptographic changes are logged:
|
|
187
|
+
|
|
188
|
+
| Version | Date | Change | Rationale |
|
|
189
|
+
|---------|------|--------|-----------|
|
|
190
|
+
| 1.0.0 | 2025-12 | Initial ML-DSA-65/ML-KEM-768 | FIPS 203/204 released |
|
|
191
|
+
| 1.4.0 | 2026-01 | Added ANNEX (ML-KEM-768) | P2P encryption |
|
|
192
|
+
| 1.6.0 | 2026-01 | Added Level 5 option | Paranoid mode |
|
|
193
|
+
|
|
194
|
+
## References
|
|
195
|
+
|
|
196
|
+
- [NIST FIPS 203](https://csrc.nist.gov/publications/detail/fips/203/final) - ML-KEM
|
|
197
|
+
- [NIST FIPS 204](https://csrc.nist.gov/publications/detail/fips/204/final) - ML-DSA
|
|
198
|
+
- [NIST FIPS 205](https://csrc.nist.gov/publications/detail/fips/205/final) - SLH-DSA
|
|
199
|
+
- [@noble/post-quantum](https://github.com/paulmillr/noble-post-quantum) - Implementation
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
*Last Updated: 2026-01-17*
|
|
204
|
+
*Document Version: 1.0*
|