@longarc/mdash 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 (55) hide show
  1. package/README.md +278 -0
  2. package/dist/checkpoint/engine.d.ts +208 -0
  3. package/dist/checkpoint/engine.d.ts.map +1 -0
  4. package/dist/checkpoint/engine.js +369 -0
  5. package/dist/checkpoint/engine.js.map +1 -0
  6. package/dist/context/engine.d.ts +197 -0
  7. package/dist/context/engine.d.ts.map +1 -0
  8. package/dist/context/engine.js +392 -0
  9. package/dist/context/engine.js.map +1 -0
  10. package/dist/core/commitment.d.ts +154 -0
  11. package/dist/core/commitment.d.ts.map +1 -0
  12. package/dist/core/commitment.js +305 -0
  13. package/dist/core/commitment.js.map +1 -0
  14. package/dist/core/crypto.d.ts +100 -0
  15. package/dist/core/crypto.d.ts.map +1 -0
  16. package/dist/core/crypto.js +243 -0
  17. package/dist/core/crypto.js.map +1 -0
  18. package/dist/index.d.ts +121 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +234 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/mcca/engine.d.ts +260 -0
  23. package/dist/mcca/engine.d.ts.map +1 -0
  24. package/dist/mcca/engine.js +518 -0
  25. package/dist/mcca/engine.js.map +1 -0
  26. package/dist/physics/engine.d.ts +165 -0
  27. package/dist/physics/engine.d.ts.map +1 -0
  28. package/dist/physics/engine.js +371 -0
  29. package/dist/physics/engine.js.map +1 -0
  30. package/dist/tee/engine.d.ts +285 -0
  31. package/dist/tee/engine.d.ts.map +1 -0
  32. package/dist/tee/engine.js +505 -0
  33. package/dist/tee/engine.js.map +1 -0
  34. package/dist/warrant/engine.d.ts +195 -0
  35. package/dist/warrant/engine.d.ts.map +1 -0
  36. package/dist/warrant/engine.js +409 -0
  37. package/dist/warrant/engine.js.map +1 -0
  38. package/dist/zk/engine.d.ts +243 -0
  39. package/dist/zk/engine.d.ts.map +1 -0
  40. package/dist/zk/engine.js +489 -0
  41. package/dist/zk/engine.js.map +1 -0
  42. package/package.json +25 -0
  43. package/src/__tests__/phase1.test.ts +1120 -0
  44. package/src/__tests__/phase2-4.test.ts +898 -0
  45. package/src/checkpoint/engine.ts +532 -0
  46. package/src/context/engine.ts +598 -0
  47. package/src/core/commitment.ts +438 -0
  48. package/src/core/crypto.ts +304 -0
  49. package/src/index.ts +320 -0
  50. package/src/mcca/engine.ts +778 -0
  51. package/src/physics/engine.ts +563 -0
  52. package/src/tee/engine.ts +810 -0
  53. package/src/warrant/engine.ts +625 -0
  54. package/src/zk/engine.ts +730 -0
  55. package/tsconfig.json +21 -0
@@ -0,0 +1,438 @@
1
+ /**
2
+ * mdash v3.0 - Commitment Layer (L1)
3
+ *
4
+ * Sub-millisecond cryptographic commitments.
5
+ * "The seal races the attack."
6
+ *
7
+ * Target Latency:
8
+ * - Commitment seal: <0.5ms P50, <1ms P99
9
+ * - Merkle proof: <0.1ms
10
+ */
11
+
12
+ import {
13
+ Hash,
14
+ Seal,
15
+ Timestamp,
16
+ sha256,
17
+ sha256Object,
18
+ rollingHash,
19
+ hmacSeal,
20
+ hmacVerify,
21
+ deriveKey,
22
+ generateTimestamp,
23
+ constantTimeEqual,
24
+ } from './crypto';
25
+
26
+ // ============================================================================
27
+ // COMMITMENT TYPES
28
+ // ============================================================================
29
+
30
+ export interface Commitment {
31
+ /** Unique commitment identifier */
32
+ id: string;
33
+ /** Operation ID this commitment is associated with */
34
+ operationId?: string;
35
+ /** SHA-256 hash of the committed content */
36
+ content_hash: Hash;
37
+ /** Timestamp of commitment creation */
38
+ committed_at: Timestamp;
39
+ /** HMAC seal binding id + hash + timestamp */
40
+ seal: Seal;
41
+ /** Protocol version for upgrade path */
42
+ version: 'v3.0';
43
+ }
44
+
45
+ export interface CommitmentProof {
46
+ /** The commitment being proven */
47
+ commitment: Commitment;
48
+ /** Merkle path from leaf to root */
49
+ merkle_path: MerklePathNode[];
50
+ /** Root hash at time of commitment */
51
+ root_hash: Hash;
52
+ /** Position in the tree (leaf index) */
53
+ leaf_index: number;
54
+ }
55
+
56
+ export interface MerklePathNode {
57
+ /** Hash value */
58
+ hash: Hash;
59
+ /** Position: 'left' or 'right' relative to current node */
60
+ position: 'left' | 'right';
61
+ }
62
+
63
+ // ============================================================================
64
+ // MERKLE TREE - Incremental for streaming support
65
+ // ============================================================================
66
+
67
+ export class IncrementalMerkleTree {
68
+ private leaves: Hash[] = [];
69
+ private levels: Hash[][] = [];
70
+ private readonly maxDepth: number;
71
+
72
+ constructor(maxDepth: number = 20) {
73
+ this.maxDepth = maxDepth;
74
+ }
75
+
76
+ /**
77
+ * Add a leaf to the tree
78
+ * O(log n) operation
79
+ */
80
+ async addLeaf(hash: Hash): Promise<number> {
81
+ const index = this.leaves.length;
82
+
83
+ if (index >= Math.pow(2, this.maxDepth)) {
84
+ throw new Error(`Tree capacity exceeded: max ${Math.pow(2, this.maxDepth)} leaves`);
85
+ }
86
+
87
+ this.leaves.push(hash);
88
+ await this.updatePath(index);
89
+
90
+ return index;
91
+ }
92
+
93
+ /**
94
+ * Update the Merkle path for a new leaf
95
+ * Incrementally updates only affected nodes
96
+ */
97
+ private async updatePath(leafIndex: number): Promise<void> {
98
+ const leafHash = this.leaves[leafIndex];
99
+ if (!leafHash) {
100
+ throw new Error(`Leaf not found at index ${leafIndex}`);
101
+ }
102
+ let currentHash: Hash = leafHash;
103
+ let currentIndex = leafIndex;
104
+
105
+ for (let level = 0; level < this.maxDepth; level++) {
106
+ const levelArray = this.levels[level] ?? (this.levels[level] = []);
107
+
108
+ const siblingIndex = currentIndex ^ 1; // XOR to get sibling
109
+ const parentIndex = currentIndex >> 1; // Divide by 2
110
+
111
+ // Get sibling hash (empty hash if doesn't exist)
112
+ const siblingHash: Hash = levelArray[siblingIndex] ?? await sha256('');
113
+
114
+ // Store current hash at this level
115
+ levelArray[currentIndex] = currentHash;
116
+
117
+ // Compute parent hash
118
+ if (currentIndex % 2 === 0) {
119
+ currentHash = await rollingHash([currentHash, siblingHash]);
120
+ } else {
121
+ currentHash = await rollingHash([siblingHash, currentHash]);
122
+ }
123
+
124
+ currentIndex = parentIndex;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Get the current root hash
130
+ */
131
+ async getRoot(): Promise<Hash> {
132
+ if (this.leaves.length === 0) {
133
+ return sha256('empty');
134
+ }
135
+
136
+ // Root is at the top level
137
+ const topLevel = this.levels[this.maxDepth - 1];
138
+ return topLevel?.[0] || await sha256('');
139
+ }
140
+
141
+ /**
142
+ * Generate Merkle proof for a leaf
143
+ * O(log n) operation
144
+ */
145
+ async getProof(leafIndex: number): Promise<MerklePathNode[]> {
146
+ if (leafIndex < 0 || leafIndex >= this.leaves.length) {
147
+ throw new Error(`Invalid leaf index: ${leafIndex}`);
148
+ }
149
+
150
+ const path: MerklePathNode[] = [];
151
+ let currentIndex = leafIndex;
152
+
153
+ for (let level = 0; level < this.maxDepth; level++) {
154
+ const siblingIndex = currentIndex ^ 1;
155
+ const levelArray = this.levels[level];
156
+ const siblingHash: Hash = levelArray?.[siblingIndex] ?? await sha256('');
157
+
158
+ path.push({
159
+ hash: siblingHash,
160
+ position: currentIndex % 2 === 0 ? 'right' : 'left',
161
+ });
162
+
163
+ currentIndex = currentIndex >> 1;
164
+ }
165
+
166
+ return path;
167
+ }
168
+
169
+ /**
170
+ * Verify a Merkle proof
171
+ * O(log n) operation
172
+ */
173
+ static async verifyProof(
174
+ leafHash: Hash,
175
+ proof: MerklePathNode[],
176
+ expectedRoot: Hash
177
+ ): Promise<boolean> {
178
+ let currentHash = leafHash;
179
+
180
+ for (const node of proof) {
181
+ if (node.position === 'left') {
182
+ currentHash = await rollingHash([node.hash, currentHash]);
183
+ } else {
184
+ currentHash = await rollingHash([currentHash, node.hash]);
185
+ }
186
+ }
187
+
188
+ return constantTimeEqual(currentHash, expectedRoot);
189
+ }
190
+
191
+ /**
192
+ * Get tree statistics
193
+ */
194
+ getStats(): { leaves: number; depth: number; capacity: number } {
195
+ return {
196
+ leaves: this.leaves.length,
197
+ depth: Math.ceil(Math.log2(this.leaves.length + 1)),
198
+ capacity: Math.pow(2, this.maxDepth),
199
+ };
200
+ }
201
+ }
202
+
203
+ // ============================================================================
204
+ // COMMITMENT ENGINE
205
+ // ============================================================================
206
+
207
+ export class CommitmentEngine {
208
+ private key: CryptoKey | null = null;
209
+ private tree: IncrementalMerkleTree;
210
+ private commitments: Map<string, Commitment> = new Map();
211
+
212
+ constructor(maxTreeDepth: number = 20) {
213
+ this.tree = new IncrementalMerkleTree(maxTreeDepth);
214
+ }
215
+
216
+ /**
217
+ * Initialize the engine with a seal key
218
+ */
219
+ async initialize(sealKey: string): Promise<void> {
220
+ this.key = await deriveKey(sealKey);
221
+ }
222
+
223
+ /**
224
+ * Create a commitment for content
225
+ * Target: <0.5ms P50, <1ms P99
226
+ */
227
+ async commit<T>(content: T, id: string): Promise<Commitment> {
228
+ if (!this.key) {
229
+ throw new Error('Engine not initialized. Call initialize() first.');
230
+ }
231
+
232
+ const startTime = performance.now();
233
+
234
+ // Hash the content
235
+ const contentHash = await sha256Object(content);
236
+ const timestamp = generateTimestamp();
237
+
238
+ // Create the commitment record
239
+ const commitmentData = {
240
+ _v: 1, // Protocol version for upgrade path
241
+ id,
242
+ content_hash: contentHash,
243
+ committed_at: timestamp,
244
+ };
245
+
246
+ // Seal the commitment
247
+ const seal = await hmacSeal(commitmentData, this.key);
248
+
249
+ const commitment: Commitment = {
250
+ id,
251
+ content_hash: contentHash,
252
+ committed_at: timestamp,
253
+ seal,
254
+ version: 'v3.0',
255
+ };
256
+
257
+ // Add to Merkle tree
258
+ await this.tree.addLeaf(contentHash);
259
+
260
+ // Store commitment
261
+ this.commitments.set(id, commitment);
262
+
263
+ const elapsed = performance.now() - startTime;
264
+ if (elapsed > 1) {
265
+ console.warn(`Commitment latency exceeded P99: ${elapsed.toFixed(2)}ms`);
266
+ }
267
+
268
+ return commitment;
269
+ }
270
+
271
+ /**
272
+ * Get a commitment by ID
273
+ */
274
+ getCommitment(id: string): Commitment | undefined {
275
+ return this.commitments.get(id);
276
+ }
277
+
278
+ /**
279
+ * Verify a commitment
280
+ */
281
+ async verify(commitment: Commitment): Promise<boolean> {
282
+ if (!this.key) {
283
+ throw new Error('Engine not initialized. Call initialize() first.');
284
+ }
285
+
286
+ const commitmentData = {
287
+ _v: 1,
288
+ id: commitment.id,
289
+ content_hash: commitment.content_hash,
290
+ committed_at: commitment.committed_at,
291
+ };
292
+
293
+ return hmacVerify(commitmentData, commitment.seal, this.key);
294
+ }
295
+
296
+ /**
297
+ * Generate a proof for a commitment
298
+ */
299
+ async generateProof(id: string): Promise<CommitmentProof> {
300
+ const commitment = this.commitments.get(id);
301
+ if (!commitment) {
302
+ throw new Error(`Commitment not found: ${id}`);
303
+ }
304
+
305
+ // Find leaf index
306
+ const leafIndex = Array.from(this.commitments.keys()).indexOf(id);
307
+
308
+ const merkle_path = await this.tree.getProof(leafIndex);
309
+ const root_hash = await this.tree.getRoot();
310
+
311
+ return {
312
+ commitment,
313
+ merkle_path,
314
+ root_hash,
315
+ leaf_index: leafIndex,
316
+ };
317
+ }
318
+
319
+ /**
320
+ * Verify a proof
321
+ */
322
+ async verifyProof(proof: CommitmentProof): Promise<boolean> {
323
+ // First verify the commitment seal
324
+ const commitmentValid = await this.verify(proof.commitment);
325
+ if (!commitmentValid) {
326
+ return false;
327
+ }
328
+
329
+ // Then verify the Merkle path
330
+ return IncrementalMerkleTree.verifyProof(
331
+ proof.commitment.content_hash,
332
+ proof.merkle_path,
333
+ proof.root_hash
334
+ );
335
+ }
336
+
337
+ /**
338
+ * Get the current Merkle root
339
+ */
340
+ async getRoot(): Promise<Hash> {
341
+ return this.tree.getRoot();
342
+ }
343
+
344
+ /**
345
+ * Get statistics
346
+ */
347
+ getStats(): {
348
+ commitments: number;
349
+ treeStats: { leaves: number; depth: number; capacity: number };
350
+ } {
351
+ return {
352
+ commitments: this.commitments.size,
353
+ treeStats: this.tree.getStats(),
354
+ };
355
+ }
356
+ }
357
+
358
+ // ============================================================================
359
+ // LATENCY MONITORING
360
+ // ============================================================================
361
+
362
+ export interface LatencyMetrics {
363
+ operation: string;
364
+ p50_ms: number;
365
+ p99_ms: number;
366
+ count: number;
367
+ breaches: number;
368
+ }
369
+
370
+ export class LatencyMonitor {
371
+ private metrics: Map<string, number[]> = new Map();
372
+ private thresholds: Map<string, { p50: number; p99: number }> = new Map();
373
+
374
+ constructor() {
375
+ // Default thresholds from v3.0 spec
376
+ this.thresholds.set('commitment_seal', { p50: 0.5, p99: 1 });
377
+ this.thresholds.set('merkle_proof', { p50: 0.05, p99: 0.1 });
378
+ this.thresholds.set('context_chunk_seal', { p50: 2, p99: 5 });
379
+ this.thresholds.set('checkpoint_create', { p50: 0.5, p99: 1 });
380
+ }
381
+
382
+ /**
383
+ * Record a latency sample
384
+ */
385
+ record(operation: string, latencyMs: number): void {
386
+ if (!this.metrics.has(operation)) {
387
+ this.metrics.set(operation, []);
388
+ }
389
+ this.metrics.get(operation)!.push(latencyMs);
390
+ }
391
+
392
+ /**
393
+ * Get metrics for an operation
394
+ */
395
+ getMetrics(operation: string): LatencyMetrics | null {
396
+ const samples = this.metrics.get(operation);
397
+ if (!samples || samples.length === 0) {
398
+ return null;
399
+ }
400
+
401
+ const sorted = [...samples].sort((a, b) => a - b);
402
+ const p50Index = Math.floor(sorted.length * 0.5);
403
+ const p99Index = Math.floor(sorted.length * 0.99);
404
+
405
+ const threshold = this.thresholds.get(operation);
406
+ const p50 = sorted[p50Index] ?? 0;
407
+ const p99 = sorted[p99Index] ?? 0;
408
+
409
+ return {
410
+ operation,
411
+ p50_ms: p50,
412
+ p99_ms: p99,
413
+ count: samples.length,
414
+ breaches: threshold ? samples.filter(s => s > threshold.p99).length : 0,
415
+ };
416
+ }
417
+
418
+ /**
419
+ * Check if operation is within SLA
420
+ */
421
+ isWithinSLA(operation: string): boolean {
422
+ const metrics = this.getMetrics(operation);
423
+ const threshold = this.thresholds.get(operation);
424
+
425
+ if (!metrics || !threshold) {
426
+ return true;
427
+ }
428
+
429
+ return metrics.p99_ms <= threshold.p99;
430
+ }
431
+
432
+ /**
433
+ * Clear metrics
434
+ */
435
+ clear(): void {
436
+ this.metrics.clear();
437
+ }
438
+ }