@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,625 @@
1
+ /**
2
+ * mdash v3.0 - Warrant System
3
+ *
4
+ * Speculative warrant issuance with cryptographic invalidation.
5
+ * Target: <10ms activation (cache hit)
6
+ *
7
+ * Invariants:
8
+ * - WARRANT-INV-001: Speculative warrants expire within 60s if not activated
9
+ * - WARRANT-INV-002: Revocation propagates to all caches within 100ms
10
+ * - WARRANT-INV-003: Activated warrants immediately sealed (L1)
11
+ */
12
+
13
+ import {
14
+ Hash,
15
+ Seal,
16
+ Timestamp,
17
+ WarrantId,
18
+ generateWarrantId,
19
+ generateTimestamp,
20
+ sha256Object,
21
+ hmacSeal,
22
+ deriveKey,
23
+ } from '../core/crypto.js';
24
+
25
+ import { CommitmentEngine } from '../core/commitment.js';
26
+
27
+ // ============================================================================
28
+ // WARRANT TYPES
29
+ // ============================================================================
30
+
31
+ export type WarrantState =
32
+ | 'DRAFT'
33
+ | 'PENDING'
34
+ | 'SPECULATIVE'
35
+ | 'ACTIVE'
36
+ | 'REVOKED'
37
+ | 'EXPIRED'
38
+ | 'ARCHIVED';
39
+
40
+ export type WarrantTier = 'T1' | 'T2' | 'T3';
41
+
42
+ export interface WarrantConstraints {
43
+ /** Maximum number of invocations */
44
+ maxCalls?: number;
45
+ /** Maximum execution time (ms) */
46
+ maxTime?: number;
47
+ /** Maximum financial exposure */
48
+ maxAmount?: number;
49
+ /** Allowed destination accounts (for financial) */
50
+ allowedAccounts?: string[];
51
+ /** Required 2FA */
52
+ require2FA?: boolean;
53
+ /** Allowed domains */
54
+ allowedDomains?: string[];
55
+ /** Custom constraints */
56
+ custom?: Record<string, unknown>;
57
+ }
58
+
59
+ export interface Warrant {
60
+ /** Unique warrant identifier */
61
+ id: WarrantId;
62
+ /** Agent this warrant governs */
63
+ agent_id: string;
64
+ /** Policy template reference */
65
+ policy_id: string;
66
+ /** Current state */
67
+ state: WarrantState;
68
+ /** Liability tier */
69
+ tier: WarrantTier;
70
+ /** Operational constraints */
71
+ constraints: WarrantConstraints;
72
+ /** Creation timestamp */
73
+ created_at: Timestamp;
74
+ /** Activation timestamp (null if not yet activated) */
75
+ activated_at: Timestamp | null;
76
+ /** Expiration timestamp */
77
+ expires_at: Timestamp;
78
+ /** Revocation timestamp (null if not revoked) */
79
+ revoked_at: Timestamp | null;
80
+ /** Revocation reason */
81
+ revocation_reason?: string;
82
+ /** Issuer identity */
83
+ issued_by: string;
84
+ /** HMAC seal */
85
+ seal: Seal;
86
+ /** Protocol version */
87
+ version: 'v3.0';
88
+ }
89
+
90
+ export interface SpeculativeWarrant extends Warrant {
91
+ state: 'SPECULATIVE';
92
+ /** Speculative expiry (60s from creation) */
93
+ speculative_expires_at: Timestamp;
94
+ /** Pre-computed activation seal */
95
+ activation_seal: Seal;
96
+ }
97
+
98
+ export interface WarrantEvent {
99
+ warrant_id: WarrantId;
100
+ event_type: 'created' | 'activated' | 'revoked' | 'expired' | 'archived';
101
+ timestamp: Timestamp;
102
+ actor: {
103
+ type: 'user' | 'system';
104
+ id: string;
105
+ email?: string;
106
+ };
107
+ reason: string | undefined;
108
+ previous_state: WarrantState;
109
+ new_state: WarrantState;
110
+ hash: Hash;
111
+ parent_hash: Hash | null;
112
+ }
113
+
114
+ // ============================================================================
115
+ // WARRANT CACHE - For <10ms activation
116
+ // ============================================================================
117
+
118
+ interface CacheEntry {
119
+ warrant: Warrant | SpeculativeWarrant;
120
+ cached_at: number;
121
+ ttl_ms: number;
122
+ }
123
+
124
+ export class WarrantCache {
125
+ private cache: Map<WarrantId, CacheEntry> = new Map();
126
+ private speculative: Map<string, WarrantId[]> = new Map(); // agent_id -> warrant_ids
127
+ private revocations: Set<WarrantId> = new Set();
128
+
129
+ private readonly DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
130
+ private readonly SPECULATIVE_TTL = 60 * 1000; // 60 seconds (WARRANT-INV-001)
131
+
132
+ /**
133
+ * Store a warrant in cache
134
+ */
135
+ set(warrant: Warrant | SpeculativeWarrant, ttl?: number): void {
136
+ const effectiveTtl = warrant.state === 'SPECULATIVE'
137
+ ? this.SPECULATIVE_TTL
138
+ : (ttl || this.DEFAULT_TTL);
139
+
140
+ this.cache.set(warrant.id, {
141
+ warrant,
142
+ cached_at: Date.now(),
143
+ ttl_ms: effectiveTtl,
144
+ });
145
+
146
+ // Track speculative warrants by agent
147
+ if (warrant.state === 'SPECULATIVE') {
148
+ const existing = this.speculative.get(warrant.agent_id) || [];
149
+ existing.push(warrant.id);
150
+ this.speculative.set(warrant.agent_id, existing);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Get a warrant from cache
156
+ * Returns null if not found, expired, or revoked
157
+ */
158
+ get(id: WarrantId): Warrant | SpeculativeWarrant | null {
159
+ // Check revocation first (WARRANT-INV-002)
160
+ if (this.revocations.has(id)) {
161
+ return null;
162
+ }
163
+
164
+ const entry = this.cache.get(id);
165
+ if (!entry) {
166
+ return null;
167
+ }
168
+
169
+ // Check TTL
170
+ if (Date.now() - entry.cached_at > entry.ttl_ms) {
171
+ this.cache.delete(id);
172
+ return null;
173
+ }
174
+
175
+ return entry.warrant;
176
+ }
177
+
178
+ /**
179
+ * Get speculative warrants for an agent
180
+ * For pre-staged activation
181
+ */
182
+ getSpeculativeForAgent(agentId: string): SpeculativeWarrant[] {
183
+ const ids = this.speculative.get(agentId) || [];
184
+ const warrants: SpeculativeWarrant[] = [];
185
+
186
+ for (const id of ids) {
187
+ const warrant = this.get(id);
188
+ if (warrant && warrant.state === 'SPECULATIVE') {
189
+ warrants.push(warrant as SpeculativeWarrant);
190
+ }
191
+ }
192
+
193
+ return warrants;
194
+ }
195
+
196
+ /**
197
+ * Record a revocation
198
+ * Propagates immediately (WARRANT-INV-002)
199
+ */
200
+ revoke(id: WarrantId): void {
201
+ this.revocations.add(id);
202
+ this.cache.delete(id);
203
+
204
+ // Remove from speculative tracking
205
+ for (const [agentId, ids] of this.speculative) {
206
+ const filtered = ids.filter(i => i !== id);
207
+ if (filtered.length !== ids.length) {
208
+ this.speculative.set(agentId, filtered);
209
+ }
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Check if a warrant is revoked
215
+ */
216
+ isRevoked(id: WarrantId): boolean {
217
+ return this.revocations.has(id);
218
+ }
219
+
220
+ /**
221
+ * Clear expired entries
222
+ */
223
+ cleanup(): number {
224
+ let removed = 0;
225
+ const now = Date.now();
226
+
227
+ for (const [id, entry] of this.cache) {
228
+ if (now - entry.cached_at > entry.ttl_ms) {
229
+ this.cache.delete(id);
230
+ removed++;
231
+ }
232
+ }
233
+
234
+ return removed;
235
+ }
236
+
237
+ /**
238
+ * Get cache statistics
239
+ */
240
+ getStats(): {
241
+ size: number;
242
+ speculative: number;
243
+ revocations: number;
244
+ } {
245
+ return {
246
+ size: this.cache.size,
247
+ speculative: Array.from(this.speculative.values()).flat().length,
248
+ revocations: this.revocations.size,
249
+ };
250
+ }
251
+ }
252
+
253
+ // ============================================================================
254
+ // WARRANT ENGINE
255
+ // ============================================================================
256
+
257
+ export class WarrantEngine {
258
+ private key: CryptoKey | null = null;
259
+ private cache: WarrantCache;
260
+ private commitmentEngine: CommitmentEngine;
261
+ private eventLog: WarrantEvent[] = [];
262
+ private lastEventHash: Hash | null = null;
263
+
264
+ constructor(commitmentEngine: CommitmentEngine) {
265
+ this.cache = new WarrantCache();
266
+ this.commitmentEngine = commitmentEngine;
267
+ }
268
+
269
+ /**
270
+ * Initialize the engine with a seal key
271
+ */
272
+ async initialize(sealKey: string): Promise<void> {
273
+ this.key = await deriveKey(sealKey);
274
+ }
275
+
276
+ /**
277
+ * Create a speculative warrant (pre-staged)
278
+ * WARRANT-INV-001: Expires in 60s if not activated
279
+ */
280
+ async createSpeculative(params: {
281
+ agent_id: string;
282
+ policy_id: string;
283
+ tier: WarrantTier;
284
+ constraints: WarrantConstraints;
285
+ duration_ms: number;
286
+ issued_by: string;
287
+ }): Promise<SpeculativeWarrant> {
288
+ if (!this.key) {
289
+ throw new Error('Engine not initialized. Call initialize() first.');
290
+ }
291
+
292
+ const startTime = performance.now();
293
+
294
+ const id = generateWarrantId();
295
+ const now = generateTimestamp();
296
+ const expiresAt = new Date(Date.now() + params.duration_ms).toISOString() as Timestamp;
297
+ const speculativeExpiresAt = new Date(Date.now() + 60000).toISOString() as Timestamp;
298
+
299
+ // Pre-compute activation seal
300
+ const activationData = {
301
+ _v: 1,
302
+ id,
303
+ agent_id: params.agent_id,
304
+ activated: true,
305
+ };
306
+ const activationSeal = await hmacSeal(activationData, this.key);
307
+
308
+ // Seal the warrant
309
+ const warrantData = {
310
+ _v: 1,
311
+ id,
312
+ agent_id: params.agent_id,
313
+ policy_id: params.policy_id,
314
+ state: 'SPECULATIVE',
315
+ tier: params.tier,
316
+ constraints: params.constraints,
317
+ created_at: now,
318
+ expires_at: expiresAt,
319
+ issued_by: params.issued_by,
320
+ };
321
+ const seal = await hmacSeal(warrantData, this.key);
322
+
323
+ const warrant: SpeculativeWarrant = {
324
+ id,
325
+ agent_id: params.agent_id,
326
+ policy_id: params.policy_id,
327
+ state: 'SPECULATIVE',
328
+ tier: params.tier,
329
+ constraints: params.constraints,
330
+ created_at: now,
331
+ activated_at: null,
332
+ expires_at: expiresAt,
333
+ revoked_at: null,
334
+ issued_by: params.issued_by,
335
+ seal,
336
+ version: 'v3.0',
337
+ speculative_expires_at: speculativeExpiresAt,
338
+ activation_seal: activationSeal,
339
+ };
340
+
341
+ // Cache for fast activation
342
+ this.cache.set(warrant);
343
+
344
+ // Log event
345
+ await this.logEvent({
346
+ warrant_id: id,
347
+ event_type: 'created',
348
+ actor: { type: 'user', id: params.issued_by },
349
+ previous_state: 'DRAFT' as WarrantState,
350
+ new_state: 'SPECULATIVE',
351
+ });
352
+
353
+ const elapsed = performance.now() - startTime;
354
+ if (elapsed > 10) {
355
+ console.warn(`Speculative warrant creation exceeded target: ${elapsed.toFixed(2)}ms`);
356
+ }
357
+
358
+ return warrant;
359
+ }
360
+
361
+ /**
362
+ * Activate a speculative warrant
363
+ * Target: <10ms (cache hit)
364
+ * WARRANT-INV-003: Immediately sealed (L1)
365
+ */
366
+ async activate(id: WarrantId): Promise<Warrant> {
367
+ if (!this.key) {
368
+ throw new Error('Engine not initialized. Call initialize() first.');
369
+ }
370
+
371
+ const startTime = performance.now();
372
+
373
+ // Try cache first
374
+ const cached = this.cache.get(id);
375
+ if (!cached) {
376
+ throw new Error(`Warrant not found or expired: ${id}`);
377
+ }
378
+
379
+ if (cached.state !== 'SPECULATIVE') {
380
+ throw new Error(`Warrant not in SPECULATIVE state: ${cached.state}`);
381
+ }
382
+
383
+ const specWarrant = cached as SpeculativeWarrant;
384
+
385
+ // Check speculative expiry (WARRANT-INV-001)
386
+ if (new Date(specWarrant.speculative_expires_at) < new Date()) {
387
+ this.cache.revoke(id);
388
+ throw new Error('Speculative warrant expired (60s limit)');
389
+ }
390
+
391
+ const now = generateTimestamp();
392
+
393
+ // Create activated warrant
394
+ const activatedWarrant: Warrant = {
395
+ id: specWarrant.id,
396
+ agent_id: specWarrant.agent_id,
397
+ policy_id: specWarrant.policy_id,
398
+ state: 'ACTIVE',
399
+ tier: specWarrant.tier,
400
+ constraints: specWarrant.constraints,
401
+ created_at: specWarrant.created_at,
402
+ activated_at: now,
403
+ expires_at: specWarrant.expires_at,
404
+ revoked_at: null,
405
+ issued_by: specWarrant.issued_by,
406
+ seal: specWarrant.seal, // Original seal preserved
407
+ version: 'v3.0',
408
+ };
409
+
410
+ // WARRANT-INV-003: Immediately seal via commitment layer
411
+ await this.commitmentEngine.commit(activatedWarrant, `warrant:${id}`);
412
+
413
+ // Update cache
414
+ this.cache.set(activatedWarrant);
415
+
416
+ // Log event
417
+ await this.logEvent({
418
+ warrant_id: id,
419
+ event_type: 'activated',
420
+ actor: { type: 'system', id: 'warrant-engine' },
421
+ previous_state: 'SPECULATIVE',
422
+ new_state: 'ACTIVE',
423
+ });
424
+
425
+ const elapsed = performance.now() - startTime;
426
+ if (elapsed > 10) {
427
+ console.warn(`Warrant activation exceeded target: ${elapsed.toFixed(2)}ms`);
428
+ }
429
+
430
+ return activatedWarrant;
431
+ }
432
+
433
+ /**
434
+ * Revoke a warrant
435
+ * WARRANT-INV-002: Propagates to all caches within 100ms
436
+ */
437
+ async revoke(id: WarrantId, reason: string, actor: { type: 'user' | 'system'; id: string }): Promise<Warrant> {
438
+ if (!this.key) {
439
+ throw new Error('Engine not initialized. Call initialize() first.');
440
+ }
441
+
442
+ const startTime = performance.now();
443
+
444
+ const warrant = this.cache.get(id);
445
+ if (!warrant) {
446
+ throw new Error(`Warrant not found: ${id}`);
447
+ }
448
+
449
+ if (warrant.state === 'REVOKED' || warrant.state === 'ARCHIVED') {
450
+ throw new Error(`Warrant already ${warrant.state}`);
451
+ }
452
+
453
+ const previousState = warrant.state;
454
+ const now = generateTimestamp();
455
+
456
+ // Create revoked warrant
457
+ const revokedWarrant: Warrant = {
458
+ ...warrant,
459
+ state: 'REVOKED',
460
+ revoked_at: now,
461
+ revocation_reason: reason,
462
+ };
463
+
464
+ // Seal revocation
465
+ await this.commitmentEngine.commit(
466
+ { warrant_id: id, revoked_at: now, reason },
467
+ `revocation:${id}`
468
+ );
469
+
470
+ // WARRANT-INV-002: Immediate cache revocation
471
+ this.cache.revoke(id);
472
+
473
+ // Log event
474
+ await this.logEvent({
475
+ warrant_id: id,
476
+ event_type: 'revoked',
477
+ actor,
478
+ reason,
479
+ previous_state: previousState,
480
+ new_state: 'REVOKED',
481
+ });
482
+
483
+ const elapsed = performance.now() - startTime;
484
+ if (elapsed > 100) {
485
+ console.warn(`Warrant revocation exceeded propagation target: ${elapsed.toFixed(2)}ms`);
486
+ }
487
+
488
+ return revokedWarrant;
489
+ }
490
+
491
+ /**
492
+ * Check if an action is authorized by warrant
493
+ * Returns matching warrant or null
494
+ */
495
+ async checkAuthorization(params: {
496
+ agent_id: string;
497
+ action: string;
498
+ amount?: number;
499
+ domain?: string;
500
+ }): Promise<Warrant | null> {
501
+ const startTime = performance.now();
502
+
503
+ // Get speculative warrants for agent
504
+ const specWarrants = this.cache.getSpeculativeForAgent(params.agent_id);
505
+
506
+ for (const warrant of specWarrants) {
507
+ // Check constraints
508
+ if (this.meetsConstraints(warrant.constraints, params)) {
509
+ // Activate on first matching warrant
510
+ const activated = await this.activate(warrant.id);
511
+
512
+ const elapsed = performance.now() - startTime;
513
+ if (elapsed > 10) {
514
+ console.warn(`Authorization check exceeded target: ${elapsed.toFixed(2)}ms`);
515
+ }
516
+
517
+ return activated;
518
+ }
519
+ }
520
+
521
+ return null;
522
+ }
523
+
524
+ /**
525
+ * Check if action meets warrant constraints
526
+ */
527
+ private meetsConstraints(
528
+ constraints: WarrantConstraints,
529
+ action: { amount?: number; domain?: string }
530
+ ): boolean {
531
+ // Check amount limit
532
+ if (constraints.maxAmount !== undefined && action.amount !== undefined) {
533
+ if (action.amount > constraints.maxAmount) {
534
+ return false;
535
+ }
536
+ }
537
+
538
+ // Check domain allowlist
539
+ if (constraints.allowedDomains && action.domain) {
540
+ if (!constraints.allowedDomains.includes(action.domain)) {
541
+ return false;
542
+ }
543
+ }
544
+
545
+ return true;
546
+ }
547
+
548
+ /**
549
+ * Log a warrant event with hash chain
550
+ */
551
+ private async logEvent(params: {
552
+ warrant_id: WarrantId;
553
+ event_type: WarrantEvent['event_type'];
554
+ actor: WarrantEvent['actor'];
555
+ reason?: string;
556
+ previous_state: WarrantState;
557
+ new_state: WarrantState;
558
+ }): Promise<void> {
559
+ const timestamp = generateTimestamp();
560
+
561
+ const event: WarrantEvent = {
562
+ warrant_id: params.warrant_id,
563
+ event_type: params.event_type,
564
+ timestamp,
565
+ actor: params.actor,
566
+ reason: params.reason,
567
+ previous_state: params.previous_state,
568
+ new_state: params.new_state,
569
+ hash: '' as Hash, // Will be computed
570
+ parent_hash: this.lastEventHash,
571
+ };
572
+
573
+ // Compute event hash
574
+ event.hash = await sha256Object({
575
+ ...event,
576
+ hash: undefined, // Exclude from hash computation
577
+ });
578
+
579
+ this.eventLog.push(event);
580
+ this.lastEventHash = event.hash;
581
+ }
582
+
583
+ /**
584
+ * Get event log for a warrant
585
+ */
586
+ getEventLog(warrantId?: WarrantId): WarrantEvent[] {
587
+ if (warrantId) {
588
+ return this.eventLog.filter(e => e.warrant_id === warrantId);
589
+ }
590
+ return [...this.eventLog];
591
+ }
592
+
593
+ /**
594
+ * Get cache statistics
595
+ */
596
+ getCacheStats(): ReturnType<WarrantCache['getStats']> {
597
+ return this.cache.getStats();
598
+ }
599
+ }
600
+
601
+ // ============================================================================
602
+ // TIER DEFINITIONS
603
+ // ============================================================================
604
+
605
+ export const TIER_LIMITS: Record<WarrantTier, {
606
+ maxExposure: number;
607
+ maxCalls: number;
608
+ requiresApproval: boolean;
609
+ }> = {
610
+ T1: {
611
+ maxExposure: 1000,
612
+ maxCalls: 100,
613
+ requiresApproval: false,
614
+ },
615
+ T2: {
616
+ maxExposure: 100000,
617
+ maxCalls: 1000,
618
+ requiresApproval: false,
619
+ },
620
+ T3: {
621
+ maxExposure: Infinity,
622
+ maxCalls: Infinity,
623
+ requiresApproval: true,
624
+ },
625
+ };