@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,563 @@
1
+ /**
2
+ * mdash v3.0 - Physics Engine
3
+ *
4
+ * "Physics" = the laws of agent behavior that cannot be violated.
5
+ * Validates actions against constraints with signed artifacts.
6
+ *
7
+ * Key Concept: Plausibility scoring determines if an action
8
+ * is physically possible given the warrant and context.
9
+ */
10
+
11
+ import {
12
+ Hash,
13
+ Seal,
14
+ Timestamp,
15
+ WarrantId,
16
+ CheckpointId,
17
+ sha256Object,
18
+ hmacSeal,
19
+ deriveKey,
20
+ generateTimestamp,
21
+ } from '../core/crypto';
22
+
23
+ import { Warrant, WarrantConstraints } from '../warrant/engine';
24
+
25
+ // ============================================================================
26
+ // PHYSICS TYPES
27
+ // ============================================================================
28
+
29
+ export type PhysicsViolationType =
30
+ | 'amount_exceeded'
31
+ | 'rate_exceeded'
32
+ | 'domain_forbidden'
33
+ | 'time_forbidden'
34
+ | 'delegation_forbidden'
35
+ | 'scope_violation'
36
+ | 'causality_violation'
37
+ | 'invariant_violation';
38
+
39
+ export interface PhysicsConstraint {
40
+ /** Constraint type */
41
+ type: string;
42
+ /** Constraint parameters */
43
+ params: Record<string, unknown>;
44
+ /** Whether violation should block or warn */
45
+ severity: 'block' | 'warn';
46
+ }
47
+
48
+ export interface PhysicsAction {
49
+ /** Action identifier */
50
+ action_id: string;
51
+ /** Action type */
52
+ type: string;
53
+ /** Agent performing the action */
54
+ agent_id: string;
55
+ /** Warrant authorizing the action */
56
+ warrant_id: WarrantId;
57
+ /** Action parameters */
58
+ params: Record<string, unknown>;
59
+ /** Timestamp */
60
+ timestamp: Timestamp;
61
+ }
62
+
63
+ export interface PhysicsValidation {
64
+ /** Action being validated */
65
+ action: PhysicsAction;
66
+ /** Whether action is valid */
67
+ valid: boolean;
68
+ /** Plausibility score (0-1) */
69
+ score: number;
70
+ /** Violations found */
71
+ violations: PhysicsViolation[];
72
+ /** Validation timestamp */
73
+ validated_at: Timestamp;
74
+ /** Validation hash (for audit) */
75
+ hash: Hash;
76
+ }
77
+
78
+ export interface PhysicsViolation {
79
+ /** Violation type */
80
+ type: PhysicsViolationType;
81
+ /** Constraint that was violated */
82
+ constraint: PhysicsConstraint;
83
+ /** Human-readable message */
84
+ message: string;
85
+ /** Severity */
86
+ severity: 'block' | 'warn';
87
+ }
88
+
89
+ export interface SignedArtifact {
90
+ /** Artifact type */
91
+ type: 'validation' | 'constraint' | 'policy';
92
+ /** Artifact content */
93
+ content: unknown;
94
+ /** Content hash */
95
+ hash: Hash;
96
+ /** HMAC seal */
97
+ seal: Seal;
98
+ /** Creation timestamp */
99
+ created_at: Timestamp;
100
+ /** Version for hot-swap */
101
+ version: string;
102
+ }
103
+
104
+ // ============================================================================
105
+ // PHYSICS POLICIES
106
+ // ============================================================================
107
+
108
+ export interface PhysicsPolicy {
109
+ /** Policy identifier */
110
+ id: string;
111
+ /** Policy name */
112
+ name: string;
113
+ /** Policy version */
114
+ version: string;
115
+ /** Constraints defined by this policy */
116
+ constraints: PhysicsConstraint[];
117
+ /** Whether policy is active */
118
+ active: boolean;
119
+ }
120
+
121
+ // Default policies
122
+ export const DEFAULT_POLICIES: PhysicsPolicy[] = [
123
+ {
124
+ id: 'financial-transfer-v2',
125
+ name: 'Financial Transfer',
126
+ version: '2.0',
127
+ active: true,
128
+ constraints: [
129
+ {
130
+ type: 'max_amount',
131
+ params: { limit: 100000, currency: 'USD' },
132
+ severity: 'block',
133
+ },
134
+ {
135
+ type: 'rate_limit',
136
+ params: { max_per_hour: 10, max_per_day: 50 },
137
+ severity: 'block',
138
+ },
139
+ {
140
+ type: 'allowlist',
141
+ params: { field: 'destination', required: true },
142
+ severity: 'block',
143
+ },
144
+ ],
145
+ },
146
+ {
147
+ id: 'data-access-v1',
148
+ name: 'Data Access',
149
+ version: '1.0',
150
+ active: true,
151
+ constraints: [
152
+ {
153
+ type: 'scope_restriction',
154
+ params: { allowed_tables: [], require_explicit: true },
155
+ severity: 'block',
156
+ },
157
+ {
158
+ type: 'rate_limit',
159
+ params: { max_per_minute: 100 },
160
+ severity: 'warn',
161
+ },
162
+ ],
163
+ },
164
+ {
165
+ id: 'external-api-v1',
166
+ name: 'External API',
167
+ version: '1.0',
168
+ active: true,
169
+ constraints: [
170
+ {
171
+ type: 'domain_allowlist',
172
+ params: { domains: [], require_explicit: true },
173
+ severity: 'block',
174
+ },
175
+ {
176
+ type: 'rate_limit',
177
+ params: { max_per_minute: 60 },
178
+ severity: 'warn',
179
+ },
180
+ ],
181
+ },
182
+ ];
183
+
184
+ // ============================================================================
185
+ // PHYSICS ENGINE
186
+ // ============================================================================
187
+
188
+ export class PhysicsEngine {
189
+ private key: CryptoKey | null = null;
190
+ private policies: Map<string, PhysicsPolicy> = new Map();
191
+ private validationHistory: PhysicsValidation[] = [];
192
+ private rateCounters: Map<string, { count: number; windowStart: number }> = new Map();
193
+
194
+ constructor() {
195
+ // Load default policies
196
+ for (const policy of DEFAULT_POLICIES) {
197
+ this.policies.set(policy.id, policy);
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Initialize the engine with a seal key
203
+ */
204
+ async initialize(sealKey: string): Promise<void> {
205
+ this.key = await deriveKey(sealKey);
206
+ }
207
+
208
+ /**
209
+ * Validate an action against physics constraints
210
+ */
211
+ async validate(
212
+ action: PhysicsAction,
213
+ warrant: Warrant
214
+ ): Promise<PhysicsValidation> {
215
+ if (!this.key) {
216
+ throw new Error('Engine not initialized. Call initialize() first.');
217
+ }
218
+
219
+ const startTime = performance.now();
220
+ const violations: PhysicsViolation[] = [];
221
+
222
+ // Get policy for the warrant
223
+ const policy = this.policies.get(warrant.policy_id);
224
+ if (!policy) {
225
+ violations.push({
226
+ type: 'scope_violation',
227
+ constraint: { type: 'policy_required', params: {}, severity: 'block' },
228
+ message: `Unknown policy: ${warrant.policy_id}`,
229
+ severity: 'block',
230
+ });
231
+ } else {
232
+ // Check each constraint
233
+ for (const constraint of policy.constraints) {
234
+ const violation = await this.checkConstraint(
235
+ constraint,
236
+ action,
237
+ warrant.constraints
238
+ );
239
+ if (violation) {
240
+ violations.push(violation);
241
+ }
242
+ }
243
+ }
244
+
245
+ // Check warrant-level constraints
246
+ const warrantViolations = this.checkWarrantConstraints(action, warrant.constraints);
247
+ violations.push(...warrantViolations);
248
+
249
+ // Check rate limits
250
+ const rateViolation = this.checkRateLimit(action);
251
+ if (rateViolation) {
252
+ violations.push(rateViolation);
253
+ }
254
+
255
+ // Calculate plausibility score
256
+ const blockingViolations = violations.filter(v => v.severity === 'block');
257
+ const score = blockingViolations.length === 0
258
+ ? Math.max(0, 1 - violations.length * 0.1)
259
+ : 0;
260
+
261
+ const now = generateTimestamp();
262
+
263
+ // Create validation record
264
+ const validationData = {
265
+ action,
266
+ valid: blockingViolations.length === 0,
267
+ score,
268
+ violations,
269
+ validated_at: now,
270
+ };
271
+
272
+ const hash = await sha256Object(validationData);
273
+
274
+ const validation: PhysicsValidation = {
275
+ ...validationData,
276
+ hash,
277
+ };
278
+
279
+ // Store in history
280
+ this.validationHistory.push(validation);
281
+
282
+ const elapsed = performance.now() - startTime;
283
+ if (elapsed > 5) {
284
+ console.warn(`Physics validation exceeded target: ${elapsed.toFixed(2)}ms`);
285
+ }
286
+
287
+ return validation;
288
+ }
289
+
290
+ /**
291
+ * Check a specific constraint
292
+ */
293
+ private async checkConstraint(
294
+ constraint: PhysicsConstraint,
295
+ action: PhysicsAction,
296
+ warrantConstraints: WarrantConstraints
297
+ ): Promise<PhysicsViolation | null> {
298
+ switch (constraint.type) {
299
+ case 'max_amount': {
300
+ const amount = action.params.amount as number | undefined;
301
+ const limit = warrantConstraints.maxAmount ?? (constraint.params.limit as number);
302
+
303
+ if (amount !== undefined && amount > limit) {
304
+ return {
305
+ type: 'amount_exceeded',
306
+ constraint,
307
+ message: `Amount ${amount} exceeds limit ${limit}`,
308
+ severity: constraint.severity,
309
+ };
310
+ }
311
+ break;
312
+ }
313
+
314
+ case 'domain_allowlist': {
315
+ const domain = action.params.domain as string | undefined;
316
+ const allowed = warrantConstraints.allowedDomains ?? (constraint.params.domains as string[]);
317
+
318
+ if (domain && allowed.length > 0 && !allowed.includes(domain)) {
319
+ return {
320
+ type: 'domain_forbidden',
321
+ constraint,
322
+ message: `Domain ${domain} not in allowlist`,
323
+ severity: constraint.severity,
324
+ };
325
+ }
326
+ break;
327
+ }
328
+
329
+ case 'allowlist': {
330
+ const field = constraint.params.field as string;
331
+ const value = action.params[field] as string | undefined;
332
+ const allowed = warrantConstraints.allowedAccounts ?? [];
333
+
334
+ if (constraint.params.required && value && allowed.length > 0) {
335
+ // Check suffix matching for account numbers
336
+ const matches = allowed.some(pattern => {
337
+ if (pattern.startsWith('*')) {
338
+ return value.endsWith(pattern.slice(1));
339
+ }
340
+ return value === pattern;
341
+ });
342
+
343
+ if (!matches) {
344
+ return {
345
+ type: 'scope_violation',
346
+ constraint,
347
+ message: `${field} "${value}" not in allowlist`,
348
+ severity: constraint.severity,
349
+ };
350
+ }
351
+ }
352
+ break;
353
+ }
354
+ }
355
+
356
+ return null;
357
+ }
358
+
359
+ /**
360
+ * Check warrant-level constraints
361
+ */
362
+ private checkWarrantConstraints(
363
+ action: PhysicsAction,
364
+ constraints: WarrantConstraints
365
+ ): PhysicsViolation[] {
366
+ const violations: PhysicsViolation[] = [];
367
+
368
+ // Check 2FA requirement
369
+ if (constraints.require2FA && !action.params.has2FA) {
370
+ violations.push({
371
+ type: 'scope_violation',
372
+ constraint: { type: 'require_2fa', params: {}, severity: 'block' },
373
+ message: '2FA required but not provided',
374
+ severity: 'block',
375
+ });
376
+ }
377
+
378
+ return violations;
379
+ }
380
+
381
+ /**
382
+ * Check rate limits
383
+ */
384
+ private checkRateLimit(action: PhysicsAction): PhysicsViolation | null {
385
+ const key = `${action.agent_id}:${action.type}`;
386
+ const now = Date.now();
387
+ const windowMs = 60 * 1000; // 1 minute window
388
+
389
+ let counter = this.rateCounters.get(key);
390
+ if (!counter || now - counter.windowStart > windowMs) {
391
+ counter = { count: 0, windowStart: now };
392
+ }
393
+
394
+ counter.count++;
395
+ this.rateCounters.set(key, counter);
396
+
397
+ // Default rate limit: 100 actions per minute
398
+ const limit = 100;
399
+ if (counter.count > limit) {
400
+ return {
401
+ type: 'rate_exceeded',
402
+ constraint: { type: 'rate_limit', params: { limit }, severity: 'block' },
403
+ message: `Rate limit exceeded: ${counter.count}/${limit} per minute`,
404
+ severity: 'block',
405
+ };
406
+ }
407
+
408
+ return null;
409
+ }
410
+
411
+ /**
412
+ * Create a signed artifact
413
+ */
414
+ async createSignedArtifact(
415
+ type: SignedArtifact['type'],
416
+ content: unknown,
417
+ version: string
418
+ ): Promise<SignedArtifact> {
419
+ if (!this.key) {
420
+ throw new Error('Engine not initialized. Call initialize() first.');
421
+ }
422
+
423
+ const now = generateTimestamp();
424
+ const hash = await sha256Object({ type, content, version, created_at: now });
425
+ const seal = await hmacSeal({ hash, type, version }, this.key);
426
+
427
+ return {
428
+ type,
429
+ content,
430
+ hash,
431
+ seal,
432
+ created_at: now,
433
+ version,
434
+ };
435
+ }
436
+
437
+ /**
438
+ * Hot-swap a policy (for runtime updates)
439
+ */
440
+ async hotSwapPolicy(policy: PhysicsPolicy): Promise<SignedArtifact> {
441
+ // Create signed artifact for audit
442
+ const artifact = await this.createSignedArtifact(
443
+ 'policy',
444
+ policy,
445
+ policy.version
446
+ );
447
+
448
+ // Replace policy
449
+ this.policies.set(policy.id, policy);
450
+
451
+ return artifact;
452
+ }
453
+
454
+ /**
455
+ * Get policy by ID
456
+ */
457
+ getPolicy(id: string): PhysicsPolicy | null {
458
+ return this.policies.get(id) || null;
459
+ }
460
+
461
+ /**
462
+ * Get all policies
463
+ */
464
+ getAllPolicies(): PhysicsPolicy[] {
465
+ return Array.from(this.policies.values());
466
+ }
467
+
468
+ /**
469
+ * Get validation history for an agent
470
+ */
471
+ getValidationHistory(agentId?: string, limit: number = 100): PhysicsValidation[] {
472
+ let history = this.validationHistory;
473
+
474
+ if (agentId) {
475
+ history = history.filter(v => v.action.agent_id === agentId);
476
+ }
477
+
478
+ return history.slice(-limit);
479
+ }
480
+
481
+ /**
482
+ * Get plausibility statistics
483
+ */
484
+ getStats(): {
485
+ totalValidations: number;
486
+ validCount: number;
487
+ invalidCount: number;
488
+ averageScore: number;
489
+ violationsByType: Record<string, number>;
490
+ } {
491
+ const total = this.validationHistory.length;
492
+ const valid = this.validationHistory.filter(v => v.valid).length;
493
+ const scores = this.validationHistory.map(v => v.score);
494
+ const avgScore = scores.length > 0
495
+ ? scores.reduce((a, b) => a + b, 0) / scores.length
496
+ : 0;
497
+
498
+ const violationsByType: Record<string, number> = {};
499
+ for (const validation of this.validationHistory) {
500
+ for (const violation of validation.violations) {
501
+ violationsByType[violation.type] = (violationsByType[violation.type] || 0) + 1;
502
+ }
503
+ }
504
+
505
+ return {
506
+ totalValidations: total,
507
+ validCount: valid,
508
+ invalidCount: total - valid,
509
+ averageScore: avgScore,
510
+ violationsByType,
511
+ };
512
+ }
513
+ }
514
+
515
+ // ============================================================================
516
+ // CAUSALITY CHECKER
517
+ // ============================================================================
518
+
519
+ /**
520
+ * Ensures actions respect causal ordering
521
+ * "Effect cannot precede cause"
522
+ */
523
+ export class CausalityChecker {
524
+ private actionLog: Array<{ action: PhysicsAction; checkpoint: CheckpointId }> = [];
525
+
526
+ /**
527
+ * Record an action with its checkpoint
528
+ */
529
+ record(action: PhysicsAction, checkpoint: CheckpointId): void {
530
+ this.actionLog.push({ action, checkpoint });
531
+ }
532
+
533
+ /**
534
+ * Check if an action would violate causality
535
+ */
536
+ checkCausality(
537
+ _action: PhysicsAction,
538
+ dependencies: CheckpointId[]
539
+ ): { valid: boolean; violation?: string } {
540
+ // All dependencies must be in the log
541
+ for (const dep of dependencies) {
542
+ const found = this.actionLog.some(entry => entry.checkpoint === dep);
543
+ if (!found) {
544
+ return {
545
+ valid: false,
546
+ violation: `Dependency checkpoint ${dep} not found in causal history`,
547
+ };
548
+ }
549
+ }
550
+
551
+ return { valid: true };
552
+ }
553
+
554
+ /**
555
+ * Get causal chain for an action
556
+ */
557
+ getCausalChain(checkpointId: CheckpointId): PhysicsAction[] {
558
+ const index = this.actionLog.findIndex(e => e.checkpoint === checkpointId);
559
+ if (index === -1) return [];
560
+
561
+ return this.actionLog.slice(0, index + 1).map(e => e.action);
562
+ }
563
+ }