@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.
- package/README.md +278 -0
- package/dist/checkpoint/engine.d.ts +208 -0
- package/dist/checkpoint/engine.d.ts.map +1 -0
- package/dist/checkpoint/engine.js +369 -0
- package/dist/checkpoint/engine.js.map +1 -0
- package/dist/context/engine.d.ts +197 -0
- package/dist/context/engine.d.ts.map +1 -0
- package/dist/context/engine.js +392 -0
- package/dist/context/engine.js.map +1 -0
- package/dist/core/commitment.d.ts +154 -0
- package/dist/core/commitment.d.ts.map +1 -0
- package/dist/core/commitment.js +305 -0
- package/dist/core/commitment.js.map +1 -0
- package/dist/core/crypto.d.ts +100 -0
- package/dist/core/crypto.d.ts.map +1 -0
- package/dist/core/crypto.js +243 -0
- package/dist/core/crypto.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +234 -0
- package/dist/index.js.map +1 -0
- package/dist/mcca/engine.d.ts +260 -0
- package/dist/mcca/engine.d.ts.map +1 -0
- package/dist/mcca/engine.js +518 -0
- package/dist/mcca/engine.js.map +1 -0
- package/dist/physics/engine.d.ts +165 -0
- package/dist/physics/engine.d.ts.map +1 -0
- package/dist/physics/engine.js +371 -0
- package/dist/physics/engine.js.map +1 -0
- package/dist/tee/engine.d.ts +285 -0
- package/dist/tee/engine.d.ts.map +1 -0
- package/dist/tee/engine.js +505 -0
- package/dist/tee/engine.js.map +1 -0
- package/dist/warrant/engine.d.ts +195 -0
- package/dist/warrant/engine.d.ts.map +1 -0
- package/dist/warrant/engine.js +409 -0
- package/dist/warrant/engine.js.map +1 -0
- package/dist/zk/engine.d.ts +243 -0
- package/dist/zk/engine.d.ts.map +1 -0
- package/dist/zk/engine.js +489 -0
- package/dist/zk/engine.js.map +1 -0
- package/package.json +25 -0
- package/src/__tests__/phase1.test.ts +1120 -0
- package/src/__tests__/phase2-4.test.ts +898 -0
- package/src/checkpoint/engine.ts +532 -0
- package/src/context/engine.ts +598 -0
- package/src/core/commitment.ts +438 -0
- package/src/core/crypto.ts +304 -0
- package/src/index.ts +320 -0
- package/src/mcca/engine.ts +778 -0
- package/src/physics/engine.ts +563 -0
- package/src/tee/engine.ts +810 -0
- package/src/warrant/engine.ts +625 -0
- package/src/zk/engine.ts +730 -0
- 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
|
+
}
|