@longarc/mdash 3.1.1 → 3.1.3

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 (178) hide show
  1. package/README.md +86 -23
  2. package/SECURITY.md +254 -0
  3. package/dist/accountability/engine.d.ts +27 -0
  4. package/dist/accountability/engine.d.ts.map +1 -0
  5. package/dist/accountability/engine.js +148 -0
  6. package/dist/accountability/engine.js.map +1 -0
  7. package/dist/accountability/types.d.ts +46 -0
  8. package/dist/accountability/types.d.ts.map +1 -0
  9. package/dist/accountability/types.js +8 -0
  10. package/dist/accountability/types.js.map +1 -0
  11. package/dist/checkpoint/engine.d.ts +2 -2
  12. package/dist/checkpoint/engine.d.ts.map +1 -1
  13. package/dist/checkpoint/engine.js +5 -1
  14. package/dist/checkpoint/engine.js.map +1 -1
  15. package/dist/context/compose.d.ts +62 -0
  16. package/dist/context/compose.d.ts.map +1 -0
  17. package/dist/context/compose.js +286 -0
  18. package/dist/context/compose.js.map +1 -0
  19. package/dist/context/crypto/hash.d.ts +100 -0
  20. package/dist/context/crypto/hash.d.ts.map +1 -0
  21. package/dist/context/crypto/hash.js +248 -0
  22. package/dist/context/crypto/hash.js.map +1 -0
  23. package/dist/context/crypto/hmac.d.ts +80 -0
  24. package/dist/context/crypto/hmac.d.ts.map +1 -0
  25. package/dist/context/crypto/hmac.js +192 -0
  26. package/dist/context/crypto/hmac.js.map +1 -0
  27. package/dist/context/crypto/index.d.ts +7 -0
  28. package/dist/context/crypto/index.d.ts.map +1 -0
  29. package/dist/context/crypto/index.js +7 -0
  30. package/dist/context/crypto/index.js.map +1 -0
  31. package/dist/context/engine-v3.0-backup.d.ts +197 -0
  32. package/dist/context/engine-v3.0-backup.d.ts.map +1 -0
  33. package/dist/context/engine-v3.0-backup.js +392 -0
  34. package/dist/context/engine-v3.0-backup.js.map +1 -0
  35. package/dist/context/engine.d.ts +2 -2
  36. package/dist/context/engine.d.ts.map +1 -1
  37. package/dist/context/engine.js +2 -2
  38. package/dist/context/engine.js.map +1 -1
  39. package/dist/context/fragment.d.ts +99 -0
  40. package/dist/context/fragment.d.ts.map +1 -0
  41. package/dist/context/fragment.js +316 -0
  42. package/dist/context/fragment.js.map +1 -0
  43. package/dist/context/index.d.ts +99 -0
  44. package/dist/context/index.d.ts.map +1 -0
  45. package/dist/context/index.js +180 -0
  46. package/dist/context/index.js.map +1 -0
  47. package/dist/context/provenance.d.ts +80 -0
  48. package/dist/context/provenance.d.ts.map +1 -0
  49. package/dist/context/provenance.js +294 -0
  50. package/dist/context/provenance.js.map +1 -0
  51. package/dist/context/resolve.d.ts +106 -0
  52. package/dist/context/resolve.d.ts.map +1 -0
  53. package/dist/context/resolve.js +440 -0
  54. package/dist/context/resolve.js.map +1 -0
  55. package/dist/context/store.d.ts +156 -0
  56. package/dist/context/store.d.ts.map +1 -0
  57. package/dist/context/store.js +396 -0
  58. package/dist/context/store.js.map +1 -0
  59. package/dist/context/types.d.ts +463 -0
  60. package/dist/context/types.d.ts.map +1 -0
  61. package/dist/context/types.js +94 -0
  62. package/dist/context/types.js.map +1 -0
  63. package/dist/context/utils/atomic.d.ts +76 -0
  64. package/dist/context/utils/atomic.d.ts.map +1 -0
  65. package/dist/context/utils/atomic.js +159 -0
  66. package/dist/context/utils/atomic.js.map +1 -0
  67. package/dist/context/utils/credit.d.ts +65 -0
  68. package/dist/context/utils/credit.d.ts.map +1 -0
  69. package/dist/context/utils/credit.js +164 -0
  70. package/dist/context/utils/credit.js.map +1 -0
  71. package/dist/context/utils/index.d.ts +13 -0
  72. package/dist/context/utils/index.d.ts.map +1 -0
  73. package/dist/context/utils/index.js +13 -0
  74. package/dist/context/utils/index.js.map +1 -0
  75. package/dist/context/utils/utility.d.ts +63 -0
  76. package/dist/context/utils/utility.d.ts.map +1 -0
  77. package/dist/context/utils/utility.js +141 -0
  78. package/dist/context/utils/utility.js.map +1 -0
  79. package/dist/core/commitment.d.ts +26 -3
  80. package/dist/core/commitment.d.ts.map +1 -1
  81. package/dist/core/commitment.js +45 -7
  82. package/dist/core/commitment.js.map +1 -1
  83. package/dist/core/crypto.d.ts +2 -0
  84. package/dist/core/crypto.d.ts.map +1 -1
  85. package/dist/core/crypto.js +12 -0
  86. package/dist/core/crypto.js.map +1 -1
  87. package/dist/index.d.ts +11 -6
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +35 -10
  90. package/dist/index.js.map +1 -1
  91. package/dist/mcca/engine.d.ts.map +1 -1
  92. package/dist/mcca/engine.js +5 -4
  93. package/dist/mcca/engine.js.map +1 -1
  94. package/dist/physics/engine.d.ts +3 -2
  95. package/dist/physics/engine.d.ts.map +1 -1
  96. package/dist/physics/engine.js +37 -3
  97. package/dist/physics/engine.js.map +1 -1
  98. package/dist/provenance/api-handler.d.ts +45 -0
  99. package/dist/provenance/api-handler.d.ts.map +1 -0
  100. package/dist/provenance/api-handler.js +223 -0
  101. package/dist/provenance/api-handler.js.map +1 -0
  102. package/dist/provenance/api-types.d.ts +108 -0
  103. package/dist/provenance/api-types.d.ts.map +1 -0
  104. package/dist/provenance/api-types.js +9 -0
  105. package/dist/provenance/api-types.js.map +1 -0
  106. package/dist/provenance/index.d.ts +6 -0
  107. package/dist/provenance/index.d.ts.map +1 -0
  108. package/dist/provenance/index.js +3 -0
  109. package/dist/provenance/index.js.map +1 -0
  110. package/dist/provenance/provenance-engine.d.ts +63 -0
  111. package/dist/provenance/provenance-engine.d.ts.map +1 -0
  112. package/dist/provenance/provenance-engine.js +311 -0
  113. package/dist/provenance/provenance-engine.js.map +1 -0
  114. package/dist/provenance/types.d.ts +193 -0
  115. package/dist/provenance/types.d.ts.map +1 -0
  116. package/dist/provenance/types.js +9 -0
  117. package/dist/provenance/types.js.map +1 -0
  118. package/dist/tee/engine.d.ts.map +1 -1
  119. package/dist/tee/engine.js +14 -0
  120. package/dist/tee/engine.js.map +1 -1
  121. package/dist/warrant/engine.d.ts +24 -1
  122. package/dist/warrant/engine.d.ts.map +1 -1
  123. package/dist/warrant/engine.js +76 -1
  124. package/dist/warrant/engine.js.map +1 -1
  125. package/dist/zk/engine.d.ts.map +1 -1
  126. package/dist/zk/engine.js +7 -4
  127. package/dist/zk/engine.js.map +1 -1
  128. package/docs/SECURITY-PATCHES.md +170 -0
  129. package/package.json +17 -5
  130. package/src/__tests__/accountability.test.ts +308 -0
  131. package/src/__tests__/l1-verification-modes.test.ts +424 -0
  132. package/src/__tests__/phase1.benchmark.test.ts +94 -0
  133. package/src/__tests__/phase1.test.ts +0 -77
  134. package/src/__tests__/phase2-4.benchmark.test.ts +60 -0
  135. package/src/__tests__/phase2-4.test.ts +1 -52
  136. package/src/__tests__/provenance/api-handler.test.ts +356 -0
  137. package/src/__tests__/provenance/provenance-engine.test.ts +628 -0
  138. package/src/__tests__/sa-2026-008.test.ts +45 -0
  139. package/src/__tests__/sa-2026-009.test.ts +86 -0
  140. package/src/__tests__/sa-2026-010.test.ts +72 -0
  141. package/src/__tests__/sa-2026-012.test.ts +65 -0
  142. package/src/__tests__/sa-2026-nfc.test.ts +40 -0
  143. package/src/__tests__/security.test.ts +786 -0
  144. package/src/accountability/engine.ts +230 -0
  145. package/src/accountability/types.ts +58 -0
  146. package/src/checkpoint/engine.ts +6 -2
  147. package/src/context/__tests__/caret-v0.2.0.test.ts +860 -0
  148. package/src/context/__tests__/integration.test.ts +356 -0
  149. package/src/context/compose.ts +388 -0
  150. package/src/context/crypto/hash.ts +277 -0
  151. package/src/context/crypto/hmac.ts +253 -0
  152. package/src/context/crypto/index.ts +29 -0
  153. package/src/context/engine-v3.0-backup.ts +598 -0
  154. package/src/context/engine.ts +2 -2
  155. package/src/context/fragment.ts +454 -0
  156. package/src/context/index.ts +427 -0
  157. package/src/context/provenance.ts +380 -0
  158. package/src/context/resolve.ts +581 -0
  159. package/src/context/store.ts +503 -0
  160. package/src/context/types.ts +679 -0
  161. package/src/context/utils/atomic.ts +207 -0
  162. package/src/context/utils/credit.ts +224 -0
  163. package/src/context/utils/index.ts +13 -0
  164. package/src/context/utils/utility.ts +200 -0
  165. package/src/core/commitment.ts +130 -68
  166. package/src/core/crypto.ts +13 -0
  167. package/src/index.ts +62 -10
  168. package/src/mcca/engine.ts +5 -4
  169. package/src/physics/engine.ts +42 -5
  170. package/src/provenance/api-handler.ts +248 -0
  171. package/src/provenance/api-types.ts +112 -0
  172. package/src/provenance/index.ts +19 -0
  173. package/src/provenance/provenance-engine.ts +387 -0
  174. package/src/provenance/types.ts +211 -0
  175. package/src/tee/engine.ts +16 -0
  176. package/src/warrant/engine.ts +89 -1
  177. package/src/zk/engine.ts +8 -4
  178. package/tsconfig.json +1 -1
@@ -0,0 +1,387 @@
1
+ /**
2
+ * mdash v3.1 - Provenance Engine
3
+ *
4
+ * Create identity attestations, build provenance chains, verify model provenance.
5
+ *
6
+ * Design Invariants:
7
+ * PROVENANCE-INV-001: Identity attestation is immutable after creation.
8
+ * PROVENANCE-INV-002: Provenance chain hash changes if ANY component changes.
9
+ * PROVENANCE-INV-003: Verdict is deterministic: same chain = same verdict.
10
+ * PROVENANCE-INV-004: ZK proof verifies without access to the chain data.
11
+ * PROVENANCE-INV-005: A model with no identity attestation has verdict.isComplete = false.
12
+ * PROVENANCE-INV-006: Distilled models cannot produce valid provider signatures.
13
+ * PROVENANCE-INV-007: Chain attestation (L1 hash) includes identity + warrants + behavior.
14
+ */
15
+
16
+ import {
17
+ sha256,
18
+ sha256Object,
19
+ rollingHash,
20
+ deterministicStringify,
21
+ generateTimestamp,
22
+ type Hash,
23
+ type Timestamp,
24
+ } from '../core/crypto.js';
25
+
26
+ import type {
27
+ ModelIdentityAttestation,
28
+ ProvenanceChain,
29
+ ProvenanceQuery,
30
+ ProvenanceResponse,
31
+ GlossEntry,
32
+ } from './types.js';
33
+
34
+ /**
35
+ * Drift report shape accepted by the provenance engine.
36
+ * Matches the DriftReport from Kiwi's defense module.
37
+ */
38
+ export interface DriftReportInput {
39
+ compositeScore: number;
40
+ recommendation: string;
41
+ }
42
+
43
+ export class ProvenanceEngine {
44
+ private identities: Map<string, ModelIdentityAttestation> = new Map();
45
+ private chains: Map<string, ProvenanceChain> = new Map();
46
+
47
+ /**
48
+ * Create a model identity attestation.
49
+ *
50
+ * Called when a model is deployed. Seals the model's identity and
51
+ * constraints into an L1 commitment. The attestation becomes the
52
+ * anchor for the provenance chain.
53
+ */
54
+ async createIdentityAttestation(
55
+ model: ModelIdentityAttestation['model'],
56
+ constraints: ModelIdentityAttestation['constraints'],
57
+ deployment: ModelIdentityAttestation['deployment']
58
+ ): Promise<ModelIdentityAttestation> {
59
+ // Validate required fields
60
+ if (!model.name || typeof model.name !== 'string') {
61
+ throw new Error('Model name is required');
62
+ }
63
+ if (!model.version || typeof model.version !== 'string') {
64
+ throw new Error('Model version is required');
65
+ }
66
+ if (!model.provider || typeof model.provider !== 'string') {
67
+ throw new Error('Model provider is required');
68
+ }
69
+ if (!deployment.environment || typeof deployment.environment !== 'string') {
70
+ throw new Error('Deployment environment is required');
71
+ }
72
+
73
+ // Deterministic attestation ID from model + constraints + deployment
74
+ const idInput = deterministicStringify({ model, constraints, deployment });
75
+ const id = await sha256(idInput);
76
+
77
+ // Canonical form for L1 commitment
78
+ const canonicalData = deterministicStringify({
79
+ id,
80
+ model,
81
+ constraints,
82
+ deployment,
83
+ });
84
+ const l1Hash = await sha256(canonicalData);
85
+
86
+ // Provider signature (simulated -- real HSM in production)
87
+ const signatureInput = deterministicStringify({ l1Hash, provider: model.provider });
88
+ const providerSignature = await sha256(signatureInput);
89
+
90
+ const timestamp = generateTimestamp();
91
+
92
+ const attestation: ModelIdentityAttestation = {
93
+ id,
94
+ model,
95
+ constraints,
96
+ deployment,
97
+ attestation: {
98
+ l1Hash,
99
+ timestamp,
100
+ providerSignature,
101
+ },
102
+ };
103
+
104
+ // Store (INV-001: immutable after creation -- we never overwrite)
105
+ const key = `${model.name}:${model.version}`;
106
+ if (!this.identities.has(key)) {
107
+ this.identities.set(key, attestation);
108
+ }
109
+
110
+ return attestation;
111
+ }
112
+
113
+ /**
114
+ * Build a provenance chain for a model.
115
+ *
116
+ * Aggregates identity, warrant history, behavioral record, and
117
+ * drift assessment into a single verifiable chain.
118
+ */
119
+ async buildProvenanceChain(
120
+ identity: ModelIdentityAttestation,
121
+ warrantHashes: string[],
122
+ glossEntries: GlossEntry[],
123
+ driftReport?: DriftReportInput
124
+ ): Promise<ProvenanceChain> {
125
+ // Verify identity attestation hash (INV-001)
126
+ const canonicalData = deterministicStringify({
127
+ id: identity.id,
128
+ model: identity.model,
129
+ constraints: identity.constraints,
130
+ deployment: identity.deployment,
131
+ });
132
+ const expectedHash = await sha256(canonicalData);
133
+ if (expectedHash !== identity.attestation.l1Hash) {
134
+ throw new Error('Identity attestation hash mismatch: attestation may have been tampered with');
135
+ }
136
+
137
+ // Build warrant history summary
138
+ const activeWarrants = warrantHashes.length;
139
+ const revokedWarrants = 0; // In production, would filter by status
140
+ const warrantChainHash = warrantHashes.length > 0
141
+ ? await rollingHash(warrantHashes as Hash[])
142
+ : await sha256('empty-warrant-chain');
143
+
144
+ const warrantHistory = {
145
+ totalWarrants: warrantHashes.length,
146
+ activeWarrants,
147
+ revokedWarrants,
148
+ warrantChainHash,
149
+ };
150
+
151
+ // Build behavioral summary from GLOSS entries
152
+ const sessions = new Set(glossEntries.map(e => e.sessionId));
153
+ const violations = glossEntries.filter(e => e.isViolation).length;
154
+
155
+ const behavioralRecord: ProvenanceChain['behavioralRecord'] = {
156
+ totalSessions: sessions.size,
157
+ totalActions: glossEntries.length,
158
+ violations,
159
+ };
160
+
161
+ if (driftReport) {
162
+ behavioralRecord.latestDriftReport = {
163
+ compositeScore: driftReport.compositeScore,
164
+ recommendation: driftReport.recommendation,
165
+ };
166
+ }
167
+
168
+ // Compute verdict (INV-003: deterministic)
169
+ const flags: string[] = [];
170
+ let confidence = 1.0;
171
+
172
+ const hasIdentity = !!identity.id;
173
+ const hasWarrants = warrantHashes.length > 0;
174
+ const hasBehavior = glossEntries.length > 0;
175
+
176
+ if (!hasWarrants) {
177
+ flags.push('warrant_gap');
178
+ confidence -= 0.3;
179
+ }
180
+
181
+ if (!hasBehavior) {
182
+ flags.push('no_behavior');
183
+ confidence -= 0.2;
184
+ }
185
+
186
+ if (driftReport && driftReport.compositeScore > 0.5) {
187
+ flags.push('drift_detected');
188
+ confidence -= driftReport.compositeScore * 0.3;
189
+ }
190
+
191
+ if (violations > 0) {
192
+ const violationRatio = violations / Math.max(glossEntries.length, 1);
193
+ if (violationRatio > 0.1) {
194
+ flags.push('high_violation_rate');
195
+ confidence -= violationRatio * 0.4;
196
+ }
197
+ }
198
+
199
+ confidence = Math.max(0, Math.min(1, confidence));
200
+
201
+ const isComplete = hasIdentity && hasWarrants && hasBehavior;
202
+
203
+ let assessment: string;
204
+ if (!isComplete) {
205
+ const missing: string[] = [];
206
+ if (!hasIdentity) missing.push('identity');
207
+ if (!hasWarrants) missing.push('warrants');
208
+ if (!hasBehavior) missing.push('behavioral record');
209
+ assessment = `Incomplete provenance chain: missing ${missing.join(', ')}`;
210
+ } else if (driftReport && driftReport.compositeScore > 0.8) {
211
+ assessment = `Model shows significant drift (${driftReport.compositeScore.toFixed(2)}). Recommend quarantine and investigation.`;
212
+ } else if (flags.length === 0) {
213
+ assessment = 'Complete provenance chain with no anomalies detected';
214
+ } else {
215
+ assessment = `Provenance chain complete with flags: ${flags.join(', ')}`;
216
+ }
217
+
218
+ const verdict = { isComplete, confidence, assessment, flags };
219
+
220
+ // Chain attestation: L1 hash of identity + warrants + behavior (INV-007)
221
+ const chainData = deterministicStringify({
222
+ identityHash: identity.attestation.l1Hash,
223
+ warrantChainHash,
224
+ behavioralRecord,
225
+ verdict,
226
+ });
227
+ const chainL1Hash = await sha256(chainData);
228
+ const chainTimestamp = generateTimestamp();
229
+
230
+ const chain: ProvenanceChain = {
231
+ identity,
232
+ warrantHistory,
233
+ behavioralRecord,
234
+ verdict,
235
+ chainAttestation: {
236
+ l1Hash: chainL1Hash,
237
+ timestamp: chainTimestamp,
238
+ },
239
+ };
240
+
241
+ // Store chain for later queries
242
+ const key = `${identity.model.name}:${identity.model.version}`;
243
+ this.chains.set(key, chain);
244
+
245
+ return chain;
246
+ }
247
+
248
+ /**
249
+ * Answer a provenance query.
250
+ *
251
+ * The verification interface. A verifier submits a query, the engine
252
+ * retrieves the relevant chain, and returns a response with optional
253
+ * ZK proof.
254
+ */
255
+ async verifyProvenance(query: ProvenanceQuery): Promise<ProvenanceResponse> {
256
+ const key = query.modelVersion
257
+ ? `${query.modelName}:${query.modelVersion}`
258
+ : this.findLatestVersion(query.modelName);
259
+
260
+ const identity = this.identities.get(key);
261
+ const existingChain = this.chains.get(key);
262
+
263
+ // If no identity exists, return an incomplete chain (INV-005)
264
+ if (!identity) {
265
+ const emptyChain = this.buildEmptyChain(query.modelName, query.modelVersion);
266
+ return this.buildResponse(query, emptyChain);
267
+ }
268
+
269
+ // Use existing chain or build a minimal one from identity alone
270
+ let chain: ProvenanceChain;
271
+ if (existingChain) {
272
+ chain = existingChain;
273
+ } else {
274
+ chain = await this.buildProvenanceChain(identity, [], []);
275
+ }
276
+
277
+ const response = await this.buildResponse(query, chain);
278
+
279
+ // If ZK proof requested (INV-004: verifiable without chain data)
280
+ if (query.generateZkProof) {
281
+ const claim = this.buildZkClaim(query, chain);
282
+ const proofInput = deterministicStringify({ claim, chainHash: chain.chainAttestation.l1Hash });
283
+ const proof = await sha256(proofInput);
284
+ const vkInput = deterministicStringify({ proof, queryType: query.queryType });
285
+ const verificationKey = await sha256(vkInput);
286
+
287
+ response.zkProof = { claim, proof, verificationKey };
288
+ }
289
+
290
+ // If hardware attestation requested, include L2 placeholder
291
+ if (query.requireHardwareAttestation && chain.identity.attestation) {
292
+ chain.identity.attestation.l2Quote = `tee-quote-${chain.identity.attestation.l1Hash.substring(0, 16)}`;
293
+ }
294
+
295
+ return response;
296
+ }
297
+
298
+ /**
299
+ * Look up a stored identity attestation by model key.
300
+ */
301
+ getIdentity(modelName: string, modelVersion?: string): ModelIdentityAttestation | undefined {
302
+ const key = modelVersion
303
+ ? `${modelName}:${modelVersion}`
304
+ : this.findLatestVersion(modelName);
305
+ return this.identities.get(key);
306
+ }
307
+
308
+ /**
309
+ * Look up a stored provenance chain by model key.
310
+ */
311
+ getChain(modelName: string, modelVersion?: string): ProvenanceChain | undefined {
312
+ const key = modelVersion
313
+ ? `${modelName}:${modelVersion}`
314
+ : this.findLatestVersion(modelName);
315
+ return this.chains.get(key);
316
+ }
317
+
318
+ // ------------------------------------------------------------------
319
+ // Private helpers
320
+ // ------------------------------------------------------------------
321
+
322
+ private findLatestVersion(modelName: string): string {
323
+ for (const key of this.identities.keys()) {
324
+ if (key.startsWith(`${modelName}:`)) {
325
+ return key;
326
+ }
327
+ }
328
+ return `${modelName}:unknown`;
329
+ }
330
+
331
+ private buildEmptyChain(modelName: string, modelVersion?: string): ProvenanceChain {
332
+ return {
333
+ identity: {
334
+ id: '',
335
+ model: { name: modelName, version: modelVersion || 'unknown', provider: 'unknown' },
336
+ constraints: {
337
+ safetyTier: 'unknown',
338
+ authorizedDomains: [],
339
+ excludedDomains: [],
340
+ maxContextWindow: 0,
341
+ reasoningEnabled: false,
342
+ custom: {},
343
+ },
344
+ deployment: { environment: 'unknown' },
345
+ attestation: { l1Hash: '', timestamp: '', providerSignature: '' },
346
+ },
347
+ warrantHistory: {
348
+ totalWarrants: 0,
349
+ activeWarrants: 0,
350
+ revokedWarrants: 0,
351
+ warrantChainHash: '',
352
+ },
353
+ behavioralRecord: { totalSessions: 0, totalActions: 0, violations: 0 },
354
+ verdict: {
355
+ isComplete: false,
356
+ confidence: 0,
357
+ assessment: 'No identity attestation found. Model provenance cannot be verified.',
358
+ flags: ['no_identity'],
359
+ },
360
+ chainAttestation: { l1Hash: '', timestamp: '' },
361
+ };
362
+ }
363
+
364
+ private async buildResponse(
365
+ query: ProvenanceQuery,
366
+ chain: ProvenanceChain
367
+ ): Promise<ProvenanceResponse> {
368
+ const timestamp = generateTimestamp();
369
+ const responseData = deterministicStringify({ query, chain, timestamp });
370
+ const responseHash = await sha256(responseData);
371
+
372
+ return { query, chain, timestamp, responseHash };
373
+ }
374
+
375
+ private buildZkClaim(query: ProvenanceQuery, chain: ProvenanceChain): string {
376
+ switch (query.queryType) {
377
+ case 'identity':
378
+ return `Model ${query.modelName} has a valid identity attestation from provider ${chain.identity.model.provider}`;
379
+ case 'constraints':
380
+ return `Model ${query.modelName} operates within safety tier ${chain.identity.constraints.safetyTier}`;
381
+ case 'behavior':
382
+ return `Model ${query.modelName} completed ${chain.behavioralRecord.totalActions} actions with ${chain.behavioralRecord.violations} violations`;
383
+ case 'full_chain':
384
+ return `Model ${query.modelName} has ${chain.verdict.isComplete ? 'complete' : 'incomplete'} provenance with confidence ${chain.verdict.confidence.toFixed(2)}`;
385
+ }
386
+ }
387
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * mdash v3.1 - Model Provenance Attestation Types
3
+ *
4
+ * Proving what a model IS: identity, constraints, and chain of custody.
5
+ * A distilled model has no provenance chain. It can produce similar
6
+ * outputs but cannot prove where its capabilities came from.
7
+ */
8
+
9
+ /**
10
+ * ModelIdentityAttestation: A cryptographic claim about a model's identity.
11
+ *
12
+ * This is NOT the model itself. It's a sealed record that binds:
13
+ * - A model identifier (name, version, hash)
14
+ * - The provider who deployed it
15
+ * - The constraints under which it operates
16
+ * - A timestamp proving when this attestation was created
17
+ *
18
+ * A distilled model cannot produce a valid ModelIdentityAttestation
19
+ * because it lacks the provider's signing authority and the constraint
20
+ * chain that shaped the original model's behavior.
21
+ */
22
+ export interface ModelIdentityAttestation {
23
+ /** Unique attestation ID */
24
+ id: string;
25
+
26
+ /** Model identity */
27
+ model: {
28
+ /** Provider-assigned model name (e.g., "claude-opus-4.6") */
29
+ name: string;
30
+ /** Provider-assigned version */
31
+ version: string;
32
+ /** Hash of model card or capability manifest, if available */
33
+ manifestHash?: string;
34
+ /** Provider identifier */
35
+ provider: string;
36
+ };
37
+
38
+ /** Constraint envelope: what boundaries this model operates within */
39
+ constraints: {
40
+ /** Safety tier (provider-defined) */
41
+ safetyTier: string;
42
+ /** Capability domains this model is authorized for */
43
+ authorizedDomains: string[];
44
+ /** Capability domains explicitly excluded */
45
+ excludedDomains: string[];
46
+ /** Maximum context window (tokens) */
47
+ maxContextWindow: number;
48
+ /** Whether reasoning/chain-of-thought is enabled */
49
+ reasoningEnabled: boolean;
50
+ /** Custom constraint fields (provider-extensible) */
51
+ custom: Record<string, string | number | boolean>;
52
+ };
53
+
54
+ /** Deployment context */
55
+ deployment: {
56
+ /** Where this model is deployed (e.g., "api", "enterprise", "research") */
57
+ environment: string;
58
+ /** Geographic region */
59
+ region?: string;
60
+ /** Tenant/organization ID (if enterprise deployment) */
61
+ tenantId?: string;
62
+ };
63
+
64
+ /** Attestation metadata */
65
+ attestation: {
66
+ /** L1: Commitment hash (Merkle leaf) */
67
+ l1Hash: string;
68
+ /** L2: TEE attestation quote (optional, for hardware-backed deployments) */
69
+ l2Quote?: string;
70
+ /** Timestamp of attestation creation */
71
+ timestamp: string;
72
+ /** Provider signature over the attestation */
73
+ providerSignature: string;
74
+ };
75
+ }
76
+
77
+ /**
78
+ * ProvenanceChain: Links a model identity to its operational history.
79
+ *
80
+ * This is the "chain of custody" for a model. It records:
81
+ * - The identity attestation (who the model claims to be)
82
+ * - The warrant chain (what the model was authorized to do)
83
+ * - The behavioral record (what the model actually did)
84
+ * - The drift assessment (whether behavior matches identity)
85
+ *
86
+ * A legitimate model has a complete provenance chain.
87
+ * A distilled copy has none.
88
+ */
89
+ export interface ProvenanceChain {
90
+ /** The model's identity attestation */
91
+ identity: ModelIdentityAttestation;
92
+
93
+ /** Warrant history: what was this model authorized to do? */
94
+ warrantHistory: {
95
+ totalWarrants: number;
96
+ activeWarrants: number;
97
+ revokedWarrants: number;
98
+ /** Hash of the warrant chain (Merkle root) */
99
+ warrantChainHash: string;
100
+ };
101
+
102
+ /** Behavioral summary from GLOSS */
103
+ behavioralRecord: {
104
+ totalSessions: number;
105
+ totalActions: number;
106
+ violations: number;
107
+ /** Drift assessment from DriftDetector */
108
+ latestDriftReport?: {
109
+ compositeScore: number;
110
+ recommendation: string;
111
+ };
112
+ };
113
+
114
+ /** Provenance verdict */
115
+ verdict: {
116
+ /** Is the chain complete and consistent? */
117
+ isComplete: boolean;
118
+ /** Confidence score (0.0 to 1.0) */
119
+ confidence: number;
120
+ /** Human-readable assessment */
121
+ assessment: string;
122
+ /** Flags (e.g., "drift_detected", "warrant_gap", "identity_mismatch") */
123
+ flags: string[];
124
+ };
125
+
126
+ /** Chain attestation: the provenance chain itself is attested */
127
+ chainAttestation: {
128
+ l1Hash: string;
129
+ timestamp: string;
130
+ };
131
+ }
132
+
133
+ /**
134
+ * ProvenanceQuery: What a verifier asks when checking a model.
135
+ *
136
+ * Use cases:
137
+ * - DoD procurement: "Prove this model is the authorized version"
138
+ * - Export control: "Prove this model hasn't been modified"
139
+ * - Enterprise audit: "Prove this model operated within its constraints"
140
+ * - Insurance underwriting: "Prove this model's behavioral history"
141
+ */
142
+ export interface ProvenanceQuery {
143
+ /** What are we checking? */
144
+ queryType: 'identity' | 'constraints' | 'behavior' | 'full_chain';
145
+
146
+ /** Model identifier to verify */
147
+ modelName: string;
148
+ modelVersion?: string;
149
+
150
+ /** Time window for behavioral verification */
151
+ timeWindow?: {
152
+ start: string;
153
+ end: string;
154
+ };
155
+
156
+ /** Whether to include L2 TEE verification */
157
+ requireHardwareAttestation: boolean;
158
+
159
+ /** Whether to generate L3 ZK proof (for cross-classification verification) */
160
+ generateZkProof: boolean;
161
+ }
162
+
163
+ /**
164
+ * ProvenanceResponse: The answer to a provenance query.
165
+ *
166
+ * If generateZkProof is true, the response includes a proof that
167
+ * can verify the claim WITHOUT revealing the underlying data.
168
+ * This enables cross-classification verification: a NATO ally can
169
+ * verify a US-deployed model meets compliance requirements without
170
+ * seeing classified operational details.
171
+ */
172
+ export interface ProvenanceResponse {
173
+ query: ProvenanceQuery;
174
+ chain: ProvenanceChain;
175
+
176
+ /** If ZK proof requested */
177
+ zkProof?: {
178
+ /** The claim being proven */
179
+ claim: string;
180
+ /** The proof (opaque bytes, verifiable without the chain) */
181
+ proof: string;
182
+ /** Verification key */
183
+ verificationKey: string;
184
+ };
185
+
186
+ /** Response metadata */
187
+ timestamp: string;
188
+ responseHash: string;
189
+ }
190
+
191
+ /**
192
+ * GlossEntry: Minimal behavioral record shape for provenance.
193
+ *
194
+ * This is a protocol-level interface. The full GLOSS entry lives
195
+ * in Kiwi (runtime). Provenance only needs enough to build a
196
+ * behavioral summary.
197
+ */
198
+ export interface GlossEntry {
199
+ /** Entry identifier */
200
+ id: string;
201
+ /** Entry type */
202
+ type: string;
203
+ /** Agent that produced this entry */
204
+ agentId: string;
205
+ /** Session identifier */
206
+ sessionId: string;
207
+ /** Timestamp */
208
+ timestamp: string;
209
+ /** Whether this entry records a violation */
210
+ isViolation?: boolean;
211
+ }
package/src/tee/engine.ts CHANGED
@@ -310,6 +310,12 @@ export class TEEAttestationEngine {
310
310
  this.commitmentEngine = commitmentEngine;
311
311
  this.config = { ...DEFAULT_CONFIG, ...config };
312
312
  this.cache = new AttestationCache(this.config.cacheTTL);
313
+
314
+ // P2 SECURITY: Warn if running in simulated mode
315
+ if (this.config.platform === 'simulated') {
316
+ console.warn('[TEE] WARNING: Running in SIMULATED mode - no hardware attestation');
317
+ console.warn('[TEE] Set teePlatform to "nitro" or "sgx" for production deployments');
318
+ }
313
319
  }
314
320
 
315
321
  /**
@@ -318,6 +324,16 @@ export class TEEAttestationEngine {
318
324
  async initialize(sealKey: string): Promise<void> {
319
325
  this.key = await deriveKey(sealKey);
320
326
 
327
+ // P2 SECURITY: Detect production environment running simulated
328
+ const isProduction = process.env.NODE_ENV === 'production';
329
+ if (isProduction && this.config.platform === 'simulated') {
330
+ console.error('[TEE] CRITICAL: Simulated TEE in production environment');
331
+ console.error('[TEE] Set MDASH_ALLOW_SIMULATED_TEE=true to override (NOT RECOMMENDED)');
332
+ if (!process.env.MDASH_ALLOW_SIMULATED_TEE) {
333
+ throw new Error('Simulated TEE not allowed in production. Set teePlatform to "nitro" or "sgx".');
334
+ }
335
+ }
336
+
321
337
  // Platform-specific initialization
322
338
  if (this.config.platform === 'nitro') {
323
339
  await this.initializeNitro();