@onchaindiligence/agent-evidence 0.1.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/LICENSE +21 -0
- package/README.md +98 -0
- package/conformance/README.md +31 -0
- package/conformance/duplicate-outer-key.json +1 -0
- package/conformance/manifest.json +74 -0
- package/conformance/missing-parent.json +31 -0
- package/conformance/noncanonical-payload.json +31 -0
- package/conformance/rfc8785-vectors.json +31 -0
- package/conformance/valid-full-graph.json +31 -0
- package/dist/canonical.d.ts +14 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +249 -0
- package/dist/canonical.js.map +1 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +9 -0
- package/dist/constants.js.map +1 -0
- package/dist/dsse.d.ts +10 -0
- package/dist/dsse.d.ts.map +1 -0
- package/dist/dsse.js +85 -0
- package/dist/dsse.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph.d.ts +3 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +227 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/records.d.ts +14 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +55 -0
- package/dist/records.js.map +1 -0
- package/dist/schema.d.ts +4 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +45 -0
- package/dist/schema.js.map +1 -0
- package/dist/trust.d.ts +64 -0
- package/dist/trust.d.ts.map +1 -0
- package/dist/trust.js +254 -0
- package/dist/trust.js.map +1 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verifier.d.ts +5 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +489 -0
- package/dist/verifier.js.map +1 -0
- package/examples/withheld-payment.mjs +67 -0
- package/package.json +65 -0
- package/schemas/attestation-key.schema.json +88 -0
- package/schemas/bundle-payload.schema.json +32 -0
- package/schemas/catalog.json +20 -0
- package/schemas/common.schema.json +35 -0
- package/schemas/dsse-envelope.schema.json +34 -0
- package/schemas/portable-file.schema.json +62 -0
- package/schemas/proof.schema.json +98 -0
- package/schemas/record.schema.json +286 -0
package/dist/verifier.js
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { verify as ed25519Verify } from 'node:crypto';
|
|
2
|
+
import { ATTESTATION_ISSUER, ATTESTATION_PURPOSE, ATTESTATION_V2, BUNDLE_PAYLOAD_TYPE, BUNDLE_VERSION, MEDIA_TYPE, } from './constants.js';
|
|
3
|
+
import { canonicalize, enforceLimits, parseJson, parseTimestamp } from './canonical.js';
|
|
4
|
+
import { dssePae } from './dsse.js';
|
|
5
|
+
import { CanonicalizationError, EvidenceValidationError, ParseError, SchemaValidationError, } from './errors.js';
|
|
6
|
+
import { validateBundlePayload } from './graph.js';
|
|
7
|
+
import { validateDocument } from './schema.js';
|
|
8
|
+
import { evaluateKeyLifecycle, TrustPolicy } from './trust.js';
|
|
9
|
+
const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
10
|
+
const BASE64URL_SIGNATURE = /^[A-Za-z0-9_-]{86}$/;
|
|
11
|
+
function result(component, state, code, message, options = {}) {
|
|
12
|
+
const item = {
|
|
13
|
+
component,
|
|
14
|
+
state,
|
|
15
|
+
code,
|
|
16
|
+
message,
|
|
17
|
+
required: options.required ?? true,
|
|
18
|
+
};
|
|
19
|
+
if (options.keyId !== undefined)
|
|
20
|
+
item.key_id = options.keyId;
|
|
21
|
+
if (options.recordId !== undefined)
|
|
22
|
+
item.record_id = options.recordId;
|
|
23
|
+
return item;
|
|
24
|
+
}
|
|
25
|
+
export function overallState(components) {
|
|
26
|
+
const required = components.filter((item) => item.required);
|
|
27
|
+
if (required.some((item) => item.state === 'INVALID'))
|
|
28
|
+
return 'INVALID';
|
|
29
|
+
if (required.some((item) => item.state === 'UNVERIFIABLE'))
|
|
30
|
+
return 'UNVERIFIABLE';
|
|
31
|
+
return 'VALID';
|
|
32
|
+
}
|
|
33
|
+
function report(components, payload) {
|
|
34
|
+
const state = overallState(components);
|
|
35
|
+
const value = {
|
|
36
|
+
state,
|
|
37
|
+
valid: state === 'VALID',
|
|
38
|
+
bundle_id: payload?.bundle_id ?? null,
|
|
39
|
+
components,
|
|
40
|
+
};
|
|
41
|
+
if (payload)
|
|
42
|
+
value.payload = payload;
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function decodeBase64(value, label) {
|
|
46
|
+
if (!BASE64.test(value))
|
|
47
|
+
throw new ParseError(`${label} is not strict padded base64`);
|
|
48
|
+
const decoded = Buffer.from(value, 'base64');
|
|
49
|
+
if (decoded.toString('base64') !== value)
|
|
50
|
+
throw new ParseError(`${label} is not canonical padded base64`);
|
|
51
|
+
return decoded;
|
|
52
|
+
}
|
|
53
|
+
function decodeBase64UrlSignature(value) {
|
|
54
|
+
if (!BASE64URL_SIGNATURE.test(value)) {
|
|
55
|
+
throw new ParseError('attestation signature must be 86-character unpadded base64url');
|
|
56
|
+
}
|
|
57
|
+
const decoded = Buffer.from(value, 'base64url');
|
|
58
|
+
if (decoded.length !== 64 || decoded.toString('base64url') !== value) {
|
|
59
|
+
throw new ParseError('Ed25519 signature must contain 64 canonical base64url bytes');
|
|
60
|
+
}
|
|
61
|
+
return decoded;
|
|
62
|
+
}
|
|
63
|
+
function strictInput(document, policy) {
|
|
64
|
+
let value;
|
|
65
|
+
if (typeof document === 'string' || document instanceof Uint8Array) {
|
|
66
|
+
const bytes = typeof document === 'string' ? Buffer.from(document, 'utf8') : Buffer.from(document);
|
|
67
|
+
if (bytes.length > policy.maxFileSize) {
|
|
68
|
+
throw new ParseError(`portable file exceeds maximum size ${policy.maxFileSize}`);
|
|
69
|
+
}
|
|
70
|
+
value = parseJson(bytes);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
value = parseJson(canonicalize(document));
|
|
74
|
+
}
|
|
75
|
+
if (value === null || Array.isArray(value) || typeof value !== 'object') {
|
|
76
|
+
throw new ParseError('portable file must be a JSON object');
|
|
77
|
+
}
|
|
78
|
+
enforceLimits(value, {
|
|
79
|
+
maxDepth: policy.maxDepth,
|
|
80
|
+
maxStringLength: policy.maxStringLength,
|
|
81
|
+
maxArrayLength: policy.maxArrayLength,
|
|
82
|
+
});
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function verifySignature(key, signature, message) {
|
|
86
|
+
return ed25519Verify(null, Buffer.from(message), key.publicKey, Buffer.from(signature));
|
|
87
|
+
}
|
|
88
|
+
function verifySignatureSet(envelope, payloadBytes, policy, options) {
|
|
89
|
+
const components = [];
|
|
90
|
+
const seen = new Set();
|
|
91
|
+
let validCount = 0;
|
|
92
|
+
for (const signature of envelope.signatures) {
|
|
93
|
+
const keyId = signature.keyid;
|
|
94
|
+
if (seen.has(keyId)) {
|
|
95
|
+
components.push(result(options.component, 'INVALID', 'duplicate-signature-key', 'a DSSE signature set may contain each key ID at most once', { keyId, recordId: options.recordId }));
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
seen.add(keyId);
|
|
99
|
+
const key = policy.key(keyId);
|
|
100
|
+
if (!key) {
|
|
101
|
+
components.push(result(options.component, 'UNVERIFIABLE', 'key-not-trusted', 'signature key is absent from caller-supplied trust', { keyId, recordId: options.recordId }));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
let signatureBytes;
|
|
105
|
+
try {
|
|
106
|
+
signatureBytes = decodeBase64(signature.sig, 'DSSE signature');
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
components.push(result(options.component, 'INVALID', 'signature-encoding', error instanceof Error ? error.message : String(error), { keyId, recordId: options.recordId }));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (signatureBytes.length !== 64
|
|
113
|
+
|| !verifySignature(key, signatureBytes, dssePae(envelope.payloadType, payloadBytes))) {
|
|
114
|
+
components.push(result(options.component, 'INVALID', 'signature-invalid', 'Ed25519 signature does not verify over the exact DSSE PAE bytes', { keyId, recordId: options.recordId }));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const [state, code, message] = evaluateKeyLifecycle(key, options.signedAt, policy);
|
|
118
|
+
components.push(result(options.component, state, code, message, { keyId, recordId: options.recordId }));
|
|
119
|
+
if (state === 'VALID')
|
|
120
|
+
validCount += 1;
|
|
121
|
+
}
|
|
122
|
+
if (validCount < 1) {
|
|
123
|
+
components.push(result(options.component, 'UNVERIFIABLE', 'signature-threshold-not-met', `required one valid caller-trusted source signature, got ${validCount}`, { recordId: options.recordId }));
|
|
124
|
+
}
|
|
125
|
+
return components;
|
|
126
|
+
}
|
|
127
|
+
function javascriptStringify(value) {
|
|
128
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
129
|
+
const parts = Object.entries(value).map(([key, item]) => Buffer.concat([
|
|
130
|
+
Buffer.from(canonicalize(key)),
|
|
131
|
+
Buffer.from(':'),
|
|
132
|
+
Buffer.from(javascriptStringify(item)),
|
|
133
|
+
]));
|
|
134
|
+
return Buffer.concat([Buffer.from('{'), ...parts.flatMap((part, index) => index === parts.length - 1 ? [part] : [part, Buffer.from(',')]), Buffer.from('}')]);
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(value)) {
|
|
137
|
+
const parts = value.map((item) => Buffer.from(javascriptStringify(item)));
|
|
138
|
+
return Buffer.concat([Buffer.from('['), ...parts.flatMap((part, index) => index === parts.length - 1 ? [part] : [part, Buffer.from(',')]), Buffer.from(']')]);
|
|
139
|
+
}
|
|
140
|
+
return canonicalize(value);
|
|
141
|
+
}
|
|
142
|
+
function verifyAttestationProof(proof, policy, recordId) {
|
|
143
|
+
const proofType = String(proof.proof_type);
|
|
144
|
+
const envelope = proof.envelope;
|
|
145
|
+
const attestation = envelope.attestation;
|
|
146
|
+
const keyId = String(attestation.key_id);
|
|
147
|
+
const key = policy.key(keyId);
|
|
148
|
+
if (!key) {
|
|
149
|
+
return result('source-proof', 'UNVERIFIABLE', 'key-not-trusted', 'attestation key is absent from caller-supplied trust', { keyId, recordId });
|
|
150
|
+
}
|
|
151
|
+
let issuedAt;
|
|
152
|
+
let signature;
|
|
153
|
+
try {
|
|
154
|
+
issuedAt = parseTimestamp(String(attestation.issued_at));
|
|
155
|
+
signature = decodeBase64UrlSignature(String(attestation.signature));
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return result('source-proof', 'INVALID', 'attestation-encoding', error instanceof Error ? error.message : String(error), { keyId, recordId });
|
|
159
|
+
}
|
|
160
|
+
let message;
|
|
161
|
+
if (proofType === 'onchaindiligence-attestation-v2') {
|
|
162
|
+
if (attestation.issuer !== ATTESTATION_ISSUER) {
|
|
163
|
+
return result('source-proof', 'INVALID', 'attestation-issuer', 'v2 attestation issuer is not the exact OnChainDiligence issuer', { keyId, recordId });
|
|
164
|
+
}
|
|
165
|
+
if (attestation.purpose !== ATTESTATION_PURPOSE) {
|
|
166
|
+
return result('source-proof', 'INVALID', 'attestation-purpose', 'v2 attestation purpose is not a compliance result', { keyId, recordId });
|
|
167
|
+
}
|
|
168
|
+
message = canonicalize({
|
|
169
|
+
schema_version: ATTESTATION_V2,
|
|
170
|
+
issuer: attestation.issuer,
|
|
171
|
+
purpose: attestation.purpose,
|
|
172
|
+
data: envelope.data,
|
|
173
|
+
issued_at: attestation.issued_at,
|
|
174
|
+
key_id: keyId,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
message = javascriptStringify({
|
|
179
|
+
data: envelope.data,
|
|
180
|
+
issued_at: attestation.issued_at,
|
|
181
|
+
key_id: keyId,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (!verifySignature(key, signature, message)) {
|
|
185
|
+
const legacy = proofType.endsWith('-v1');
|
|
186
|
+
return result('source-proof', legacy ? 'UNVERIFIABLE' : 'INVALID', legacy ? 'legacy-signature-unverifiable' : 'signature-invalid', legacy
|
|
187
|
+
? 'v1 signature did not verify from the object order representable in the canonical bundle'
|
|
188
|
+
: 'attestation signature does not verify', { keyId, recordId });
|
|
189
|
+
}
|
|
190
|
+
const [state, code, messageText] = evaluateKeyLifecycle(key, issuedAt, policy);
|
|
191
|
+
return result('source-proof', state, code, messageText, { keyId, recordId });
|
|
192
|
+
}
|
|
193
|
+
function verifyRecordProofs(payload, policy) {
|
|
194
|
+
const components = [];
|
|
195
|
+
for (const record of payload.records) {
|
|
196
|
+
for (const proof of record.proofs) {
|
|
197
|
+
const proofType = String(proof.proof_type);
|
|
198
|
+
if (proofType === 'external-digest') {
|
|
199
|
+
components.push(result('source-proof', 'VALID', 'external-digest-bound', 'digest is bound by the record ID but does not establish source attribution', { recordId: record.id }));
|
|
200
|
+
}
|
|
201
|
+
else if (proofType === 'onchaindiligence-attestation-v1'
|
|
202
|
+
|| proofType === 'onchaindiligence-attestation-v2') {
|
|
203
|
+
const response = record.statement.response;
|
|
204
|
+
const source = record.statement.source;
|
|
205
|
+
if (source === null || typeof source !== 'object' || Array.isArray(source)
|
|
206
|
+
|| source.id !== ATTESTATION_ISSUER) {
|
|
207
|
+
components.push(result('source-proof', 'INVALID', 'attestation-source-mismatch', 'OnChainDiligence attestation proof requires the exact OnChainDiligence source ID', { recordId: record.id }));
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (record.kind !== 'evidence'
|
|
211
|
+
|| response === null || typeof response !== 'object' || Array.isArray(response)
|
|
212
|
+
|| response.mode !== 'embedded'
|
|
213
|
+
|| Buffer.compare(Buffer.from(canonicalize(response.value)), Buffer.from(canonicalize(proof.envelope))) !== 0) {
|
|
214
|
+
components.push(result('source-proof', 'INVALID', 'attestation-response-mismatch', 'attestation proof must exactly equal the embedded evidence response', { recordId: record.id }));
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
components.push(verifyAttestationProof(proof, policy, record.id));
|
|
218
|
+
}
|
|
219
|
+
else if (proofType === 'dsse-ed25519-v1') {
|
|
220
|
+
const envelope = proof.envelope;
|
|
221
|
+
let proofBytes;
|
|
222
|
+
try {
|
|
223
|
+
proofBytes = decodeBase64(envelope.payload, 'source DSSE payload');
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
components.push(result('source-proof', 'INVALID', 'proof-payload-encoding', error instanceof Error ? error.message : String(error), { recordId: record.id }));
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (envelope.payloadType !== proof.statement_media_type) {
|
|
230
|
+
components.push(result('source-proof', 'INVALID', 'proof-payload-type', 'source DSSE payloadType does not equal statement_media_type', { recordId: record.id }));
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (Buffer.compare(proofBytes, Buffer.from(canonicalize(record.statement))) !== 0) {
|
|
234
|
+
components.push(result('source-proof', 'INVALID', 'proof-statement-mismatch', 'source DSSE payload is not the canonical record statement', { recordId: record.id }));
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
components.push(...verifySignatureSet(envelope, proofBytes, policy, {
|
|
238
|
+
signedAt: null,
|
|
239
|
+
component: 'source-proof',
|
|
240
|
+
recordId: record.id,
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return components;
|
|
246
|
+
}
|
|
247
|
+
function verifyEvidenceSemantics(payload, proofComponents, policy) {
|
|
248
|
+
const components = [];
|
|
249
|
+
const cryptographicTypes = new Set([
|
|
250
|
+
'dsse-ed25519-v1',
|
|
251
|
+
'onchaindiligence-attestation-v1',
|
|
252
|
+
'onchaindiligence-attestation-v2',
|
|
253
|
+
]);
|
|
254
|
+
for (const record of payload.records.filter((candidate) => candidate.kind === 'evidence')) {
|
|
255
|
+
const statement = record.statement;
|
|
256
|
+
const response = statement.response;
|
|
257
|
+
if (response.mode === 'reference') {
|
|
258
|
+
components.push(result('evidence-content', policy.allowDigestOnlyEvidence ? 'VALID' : 'UNVERIFIABLE', policy.allowDigestOnlyEvidence ? 'digest-only-allowed' : 'evidence-content-unavailable', policy.allowDigestOnlyEvidence
|
|
259
|
+
? 'caller policy permits digest-only evidence'
|
|
260
|
+
: 'offline verifier cannot resolve referenced evidence required by default policy', { recordId: record.id }));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
components.push(result('evidence-content', 'VALID', 'evidence-embedded', 'evidence response is embedded and its digest matches', { recordId: record.id }));
|
|
264
|
+
}
|
|
265
|
+
if (statement.trust_mode === 'agent-assertion') {
|
|
266
|
+
components.push(result('trust-mode', 'VALID', 'agent-assertion', 'statement is explicitly limited to an agent assertion', { recordId: record.id }));
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const cryptoProofs = record.proofs.filter((proof) => cryptographicTypes.has(String(proof.proof_type)));
|
|
270
|
+
if (!cryptoProofs.length) {
|
|
271
|
+
components.push(result('trust-mode', 'INVALID', 'cryptographic-proof-missing', `${String(statement.trust_mode)} requires a cryptographic source proof`, { recordId: record.id }));
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const relevant = proofComponents.filter((item) => item.record_id === record.id && item.code !== 'external-digest-bound');
|
|
275
|
+
const state = relevant.some((item) => item.state === 'INVALID')
|
|
276
|
+
? 'INVALID'
|
|
277
|
+
: relevant.some((item) => item.state === 'UNVERIFIABLE') ? 'UNVERIFIABLE' : 'VALID';
|
|
278
|
+
const code = state === 'INVALID' ? 'trust-proof-invalid'
|
|
279
|
+
: state === 'UNVERIFIABLE' ? 'trust-proof-unverifiable' : 'trust-proof-valid';
|
|
280
|
+
components.push(result('trust-mode', state, code, `${String(statement.trust_mode)} is reported exactly and backed by the source-proof result`, { recordId: record.id }));
|
|
281
|
+
}
|
|
282
|
+
return components;
|
|
283
|
+
}
|
|
284
|
+
function verificationMaterialComponents(portable, policy) {
|
|
285
|
+
const components = [];
|
|
286
|
+
if (portable.verification_material.keys.length) {
|
|
287
|
+
components.push(result('verification-material', 'UNVERIFIABLE', 'embedded-keys-untrusted', 'embedded public keys are verification hints, never caller trust', { required: false }));
|
|
288
|
+
}
|
|
289
|
+
for (const _snapshot of portable.verification_material.registry_snapshots) {
|
|
290
|
+
components.push(result('registry-snapshot', 'UNVERIFIABLE', 'snapshot-format-unsupported', 'registry snapshot is preserved but not trusted or verified by v0 core', { required: false }));
|
|
291
|
+
}
|
|
292
|
+
if (policy.requireVerifiedAnchor && !portable.verification_material.anchors.length) {
|
|
293
|
+
components.push(result('anchor', 'UNVERIFIABLE', 'anchor-required-missing', 'caller policy requires an independently verified anchor'));
|
|
294
|
+
}
|
|
295
|
+
for (const _anchor of portable.verification_material.anchors) {
|
|
296
|
+
components.push(result('anchor', 'UNVERIFIABLE', 'anchor-format-unsupported', 'anchor is preserved but no v0 core anchor format is verified', { required: policy.requireVerifiedAnchor }));
|
|
297
|
+
}
|
|
298
|
+
return components;
|
|
299
|
+
}
|
|
300
|
+
function verifyFreshness(payload, policy) {
|
|
301
|
+
const components = [];
|
|
302
|
+
let createdAt;
|
|
303
|
+
try {
|
|
304
|
+
createdAt = parseTimestamp(payload.created_at);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
return [result('freshness', 'INVALID', 'timestamp-invalid', error instanceof Error ? error.message : String(error))];
|
|
308
|
+
}
|
|
309
|
+
if (createdAt.getTime() > policy.now.getTime() + policy.maxFutureSkewMs) {
|
|
310
|
+
components.push(result('freshness', 'INVALID', 'bundle-time-future', 'bundle created_at exceeds allowed clock skew'));
|
|
311
|
+
}
|
|
312
|
+
else if (policy.maxBundleAgeMs !== null && policy.now.getTime() - createdAt.getTime() > policy.maxBundleAgeMs) {
|
|
313
|
+
components.push(result('freshness', 'INVALID', 'bundle-stale', 'bundle exceeds caller-supplied maximum age'));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
components.push(result('freshness', 'VALID', 'bundle-freshness-valid', 'bundle satisfies caller-supplied time policy'));
|
|
317
|
+
}
|
|
318
|
+
const fields = {
|
|
319
|
+
evidence: ['observed_at'],
|
|
320
|
+
decision: ['decided_at'],
|
|
321
|
+
execution: ['submitted_at', 'confirmed_at'],
|
|
322
|
+
run: ['started_at', 'ended_at'],
|
|
323
|
+
};
|
|
324
|
+
for (const record of payload.records) {
|
|
325
|
+
for (const name of fields[record.kind] ?? []) {
|
|
326
|
+
const raw = record.statement[name];
|
|
327
|
+
if (typeof raw === 'string' && parseTimestamp(raw).getTime() > policy.now.getTime() + policy.maxFutureSkewMs) {
|
|
328
|
+
components.push(result('freshness', 'INVALID', 'asserted-time-future', `${record.kind}.${name} exceeds allowed clock skew`, { recordId: record.id }));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (policy.enforceEvidenceExpiration
|
|
332
|
+
&& record.kind === 'evidence'
|
|
333
|
+
&& typeof record.statement.expires_at === 'string'
|
|
334
|
+
&& policy.now.getTime() > parseTimestamp(record.statement.expires_at).getTime()) {
|
|
335
|
+
components.push(result('freshness', 'INVALID', 'evidence-expired', 'evidence expires_at is before policy time', { recordId: record.id }));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return components;
|
|
339
|
+
}
|
|
340
|
+
export function verifyBundle(document, policy) {
|
|
341
|
+
const components = [];
|
|
342
|
+
let portable;
|
|
343
|
+
try {
|
|
344
|
+
portable = strictInput(document, policy);
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
if (error instanceof ParseError || error instanceof CanonicalizationError) {
|
|
348
|
+
return report([result('outer', 'INVALID', 'json-invalid', error.message)]);
|
|
349
|
+
}
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
validateDocument('portable-file.schema.json', portable);
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
if (error instanceof SchemaValidationError) {
|
|
357
|
+
return report([result('outer', 'INVALID', 'schema-invalid', error.message)]);
|
|
358
|
+
}
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
if (portable.media_type !== MEDIA_TYPE || portable.bundle_version !== BUNDLE_VERSION) {
|
|
362
|
+
return report([result('outer', 'INVALID', 'version-unsupported', 'unsupported outer format')]);
|
|
363
|
+
}
|
|
364
|
+
components.push(result('outer', 'VALID', 'outer-valid', 'portable file schema and version are valid'));
|
|
365
|
+
components.push(...verificationMaterialComponents(portable, policy));
|
|
366
|
+
const envelope = portable.envelope;
|
|
367
|
+
if (envelope.payloadType !== BUNDLE_PAYLOAD_TYPE) {
|
|
368
|
+
components.push(result('payload', 'INVALID', 'payload-type-unsupported', 'unsupported DSSE payload type'));
|
|
369
|
+
return report(components);
|
|
370
|
+
}
|
|
371
|
+
let payloadBytes;
|
|
372
|
+
try {
|
|
373
|
+
payloadBytes = decodeBase64(envelope.payload, 'DSSE payload');
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
components.push(result('payload', 'INVALID', 'payload-encoding', error instanceof Error ? error.message : String(error)));
|
|
377
|
+
return report(components);
|
|
378
|
+
}
|
|
379
|
+
const cryptographic = [];
|
|
380
|
+
const seen = new Set();
|
|
381
|
+
let signatureFailure = false;
|
|
382
|
+
for (const signature of envelope.signatures) {
|
|
383
|
+
const keyId = signature.keyid;
|
|
384
|
+
if (seen.has(keyId)) {
|
|
385
|
+
components.push(result('bundle-signature', 'INVALID', 'duplicate-signature-key', 'a DSSE signature set may contain each key ID at most once', { keyId }));
|
|
386
|
+
signatureFailure = true;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
seen.add(keyId);
|
|
390
|
+
const key = policy.key(keyId);
|
|
391
|
+
if (!key) {
|
|
392
|
+
components.push(result('bundle-signature', 'UNVERIFIABLE', 'key-not-trusted', 'bundle key is absent from caller-supplied trust; embedded keys are hints only', { keyId }));
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
let signatureBytes;
|
|
396
|
+
try {
|
|
397
|
+
signatureBytes = decodeBase64(signature.sig, 'DSSE signature');
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
components.push(result('bundle-signature', 'INVALID', 'signature-encoding', error instanceof Error ? error.message : String(error), { keyId }));
|
|
401
|
+
signatureFailure = true;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (signatureBytes.length !== 64
|
|
405
|
+
|| !verifySignature(key, signatureBytes, dssePae(BUNDLE_PAYLOAD_TYPE, payloadBytes))) {
|
|
406
|
+
components.push(result('bundle-signature', 'INVALID', 'signature-invalid', 'bundle signature does not verify over the exact DSSE PAE bytes', { keyId }));
|
|
407
|
+
signatureFailure = true;
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
cryptographic.push([key, keyId]);
|
|
411
|
+
}
|
|
412
|
+
if (signatureFailure)
|
|
413
|
+
return report(components);
|
|
414
|
+
if (!cryptographic.length) {
|
|
415
|
+
components.push(result('bundle-signature', 'UNVERIFIABLE', 'signature-threshold-not-met', 'no bundle signature uses a caller-trusted key'));
|
|
416
|
+
return report(components);
|
|
417
|
+
}
|
|
418
|
+
let payload;
|
|
419
|
+
try {
|
|
420
|
+
const parsed = parseJson(payloadBytes);
|
|
421
|
+
if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {
|
|
422
|
+
throw new ParseError('signed payload must be a JSON object');
|
|
423
|
+
}
|
|
424
|
+
enforceLimits(parsed, {
|
|
425
|
+
maxDepth: policy.maxDepth,
|
|
426
|
+
maxStringLength: policy.maxStringLength,
|
|
427
|
+
maxArrayLength: policy.maxArrayLength,
|
|
428
|
+
});
|
|
429
|
+
payload = parsed;
|
|
430
|
+
validateDocument('bundle-payload.schema.json', payload);
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
if (error instanceof ParseError || error instanceof SchemaValidationError) {
|
|
434
|
+
components.push(result('payload', 'INVALID', 'payload-invalid', error.message));
|
|
435
|
+
return report(components);
|
|
436
|
+
}
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
if (Buffer.compare(Buffer.from(canonicalize(payload)), payloadBytes) !== 0) {
|
|
441
|
+
components.push(result('payload', 'INVALID', 'payload-not-rfc8785', 'signed payload bytes are not their RFC 8785 representation'));
|
|
442
|
+
return report(components, payload);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch (error) {
|
|
446
|
+
if (error instanceof CanonicalizationError) {
|
|
447
|
+
components.push(result('payload', 'INVALID', 'payload-not-ijson', error.message));
|
|
448
|
+
return report(components, payload);
|
|
449
|
+
}
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
if (payload.bundle_version !== BUNDLE_VERSION || portable.bundle_version !== payload.bundle_version) {
|
|
453
|
+
components.push(result('payload', 'INVALID', 'outer-inner-version-mismatch', 'authoritative and routing versions do not match'));
|
|
454
|
+
return report(components, payload);
|
|
455
|
+
}
|
|
456
|
+
components.push(result('payload', 'VALID', 'payload-valid', 'signed payload is canonical v0 JSON'));
|
|
457
|
+
const createdAt = parseTimestamp(payload.created_at);
|
|
458
|
+
let lifecycleCount = 0;
|
|
459
|
+
for (const [key, keyId] of cryptographic) {
|
|
460
|
+
const [state, code, message] = evaluateKeyLifecycle(key, createdAt, policy);
|
|
461
|
+
components.push(result('bundle-signature', state, code, message, { keyId }));
|
|
462
|
+
if (state === 'VALID')
|
|
463
|
+
lifecycleCount += 1;
|
|
464
|
+
}
|
|
465
|
+
const presented = new Set(envelope.signatures.map((signature) => signature.keyid));
|
|
466
|
+
for (const keyId of [...policy.requiredSignatureKeyIds].filter((id) => !presented.has(id)).sort()) {
|
|
467
|
+
components.push(result('bundle-signature', 'UNVERIFIABLE', 'required-signature-missing', 'a caller-required bundle signature is not present', { keyId }));
|
|
468
|
+
}
|
|
469
|
+
if (lifecycleCount < policy.minimumValidSignatures) {
|
|
470
|
+
components.push(result('bundle-signature', 'UNVERIFIABLE', 'signature-threshold-not-met', `required ${policy.minimumValidSignatures} valid signature(s), got ${lifecycleCount}`));
|
|
471
|
+
}
|
|
472
|
+
try {
|
|
473
|
+
validateBundlePayload(payload);
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
if (error instanceof EvidenceValidationError) {
|
|
477
|
+
components.push(result('graph', 'INVALID', 'graph-invalid', error.message));
|
|
478
|
+
return report(components, payload);
|
|
479
|
+
}
|
|
480
|
+
throw error;
|
|
481
|
+
}
|
|
482
|
+
components.push(result('graph', 'VALID', 'graph-valid', 'IDs, roots, DAG, references, and kind rules are valid'));
|
|
483
|
+
const proofComponents = verifyRecordProofs(payload, policy);
|
|
484
|
+
components.push(...proofComponents);
|
|
485
|
+
components.push(...verifyEvidenceSemantics(payload, proofComponents, policy));
|
|
486
|
+
components.push(...verifyFreshness(payload, policy));
|
|
487
|
+
return report(components, payload);
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,GACX,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,qBAAqB,GACtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAuB,WAAW,EAAE,MAAM,YAAY,CAAA;AAanF,MAAM,MAAM,GAAG,kEAAkE,CAAA;AACjF,MAAM,mBAAmB,GAAG,qBAAqB,CAAA;AAEjD,SAAS,MAAM,CACb,SAAiB,EACjB,KAAwB,EACxB,IAAY,EACZ,OAAe,EACf,UAII,EAAE;IAEN,MAAM,IAAI,GAAoB;QAC5B,SAAS;QACT,KAAK;QACL,IAAI;QACJ,OAAO;QACP,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;KACnC,CAAA;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAA;IAC5D,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAA;IACrE,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAsC;IACjE,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC3D,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAA;IACvE,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,cAAc,CAAC;QAAE,OAAO,cAAc,CAAA;IACjF,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,MAAM,CAAC,UAA6B,EAAE,OAAuB;IACpE,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,CAAA;IACtC,MAAM,KAAK,GAAuB;QAChC,KAAK;QACL,KAAK,EAAE,KAAK,KAAK,OAAO;QACxB,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI;QACrC,UAAU;KACX,CAAA;IACD,IAAI,OAAO;QAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAA;IACpC,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,KAAa;IAChD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAA;IACrF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IAC5C,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,KAAK;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,iCAAiC,CAAC,CAAA;IACzG,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAa;IAC7C,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,UAAU,CAAC,+DAA+D,CAAC,CAAA;IACvF,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,KAAK,EAAE,CAAC;QACrE,MAAM,IAAI,UAAU,CAAC,6DAA6D,CAAC,CAAA;IACrF,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,WAAW,CAClB,QAAwE,EACxE,MAAmB;IAEnB,IAAI,KAAgB,CAAA;IACpB,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,YAAY,UAAU,EAAE,CAAC;QACnE,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAClG,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,IAAI,UAAU,CAAC,sCAAsC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;QAClF,CAAC;QACD,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC3C,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxE,MAAM,IAAI,UAAU,CAAC,qCAAqC,CAAC,CAAA;IAC7D,CAAC;IACD,aAAa,CAAC,KAAK,EAAE;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC,CAAA;IACF,OAAO,KAAkC,CAAA;AAC3C,CAAC;AAED,SAAS,eAAe,CAAC,GAAmB,EAAE,SAAqB,EAAE,OAAmB;IACtF,OAAO,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;AACzF,CAAC;AAED,SAAS,kBAAkB,CACzB,QAAsB,EACtB,YAAwB,EACxB,MAAmB,EACnB,OAAwE;IAExE,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAA;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,yBAAyB,EAC5E,2DAA2D,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YACtG,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACf,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,iBAAiB,EACzE,oDAAoD,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YAC/F,SAAQ;QACV,CAAC;QACD,IAAI,cAAsB,CAAA;QAC1B,IAAI,CAAC;YACH,cAAc,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAA;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,oBAAoB,EACvE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YACjG,SAAQ;QACV,CAAC;QACD,IACE,cAAc,CAAC,MAAM,KAAK,EAAE;eACzB,CAAC,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,EACrF,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,mBAAmB,EACtE,iEAAiE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YAC5G,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAClF,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QACvG,IAAI,KAAK,KAAK,OAAO;YAAE,UAAU,IAAI,CAAC,CAAA;IACxC,CAAC;IACD,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,6BAA6B,EACrF,2DAA2D,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IAC7G,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;SACvC,CAAC,CAAC,CAAA;QACH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACvE,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACzE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACvE,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAiB,EACjB,MAAmB,EACnB,QAAgB;IAEhB,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAsB,CAAA;IAC7C,MAAM,WAAW,GAAG,QAAQ,CAAC,WAAyB,CAAA;IACtD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,MAAM,CAAC,cAAc,EAAE,cAAc,EAAE,iBAAiB,EAC7D,sDAAsD,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,IAAI,QAAc,CAAA;IAClB,IAAI,SAAiB,CAAA;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAA;QACxD,SAAS,GAAG,wBAAwB,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAA;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,sBAAsB,EAC7D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IAChF,CAAC;IAED,IAAI,OAAmB,CAAA;IACvB,IAAI,SAAS,KAAK,iCAAiC,EAAE,CAAC;QACpD,IAAI,WAAW,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;YAC9C,OAAO,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,oBAAoB,EAC3D,gEAAgE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1F,CAAC;QACD,IAAI,WAAW,CAAC,OAAO,KAAK,mBAAmB,EAAE,CAAC;YAChD,OAAO,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,qBAAqB,EAC5D,mDAAmD,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC7E,CAAC;QACD,OAAO,GAAG,YAAY,CAAC;YACrB,cAAc,EAAE,cAAc;YAC9B,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,OAAO,EAAE,WAAW,CAAC,OAAO;YAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,mBAAmB,CAAC;YAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,MAAM,EAAE,KAAK;SACd,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QACxC,OAAO,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EAC/D,MAAM,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,mBAAmB,EAC9D,MAAM;YACJ,CAAC,CAAC,yFAAyF;YAC3F,CAAC,CAAC,uCAAuC,EAC3C,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IACxB,CAAC;IACD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,GAAG,oBAAoB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC9E,OAAO,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAsB,EAAE,MAAmB;IACrE,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;YAC1C,IAAI,SAAS,KAAK,iBAAiB,EAAE,CAAC;gBACpC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,EAAE,uBAAuB,EACrE,4EAA4E,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YAC3G,CAAC;iBAAM,IACL,SAAS,KAAK,iCAAiC;mBAC5C,SAAS,KAAK,iCAAiC,EAClD,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAA;gBAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAA;gBACtC,IACE,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;uBAClE,MAAqB,CAAC,EAAE,KAAK,kBAAkB,EACnD,CAAC;oBACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,6BAA6B,EAC7E,kFAAkF,EAClF,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBAC3B,SAAQ;gBACV,CAAC;gBACD,IACE,MAAM,CAAC,IAAI,KAAK,UAAU;uBACvB,QAAQ,KAAK,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;uBAC3E,QAAuB,CAAC,IAAI,KAAK,UAAU;uBAC5C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAE,QAAuB,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAC7H,CAAC;oBACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,+BAA+B,EAC/E,qEAAqE,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBAClG,SAAQ;gBACV,CAAC;gBACD,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;YACnE,CAAC;iBAAM,IAAI,SAAS,KAAK,iBAAiB,EAAE,CAAC;gBAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAmC,CAAA;gBAC1D,IAAI,UAAkB,CAAA;gBACtB,IAAI,CAAC;oBACH,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;gBACpE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,wBAAwB,EACxE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBACnF,SAAQ;gBACV,CAAC;gBACD,IAAI,QAAQ,CAAC,WAAW,KAAK,KAAK,CAAC,oBAAoB,EAAE,CAAC;oBACxD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,oBAAoB,EACpE,6DAA6D,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBAC1F,SAAQ;gBACV,CAAC;gBACD,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBAClF,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,0BAA0B,EAC1E,2DAA2D,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;oBACxF,SAAQ;gBACV,CAAC;gBACD,UAAU,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE;oBAClE,QAAQ,EAAE,IAAI;oBACd,SAAS,EAAE,cAAc;oBACzB,QAAQ,EAAE,MAAM,CAAC,EAAE;iBACpB,CAAC,CAAC,CAAA;YACL,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAAsB,EACtB,eAAkC,EAClC,MAAmB;IAEnB,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;QACjC,iBAAiB;QACjB,iCAAiC;QACjC,iCAAiC;KAClC,CAAC,CAAA;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;QAC1F,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;QAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAsB,CAAA;QACjD,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,EAClG,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,8BAA8B,EACvF,MAAM,CAAC,uBAAuB;gBAC5B,CAAC,CAAC,4CAA4C;gBAC9C,CAAC,CAAC,gFAAgF,EACpF,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC7B,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,EAAE,mBAAmB,EACrE,sDAAsD,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,SAAS,CAAC,UAAU,KAAK,iBAAiB,EAAE,CAAC;YAC/C,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAC7D,uDAAuD,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YACpF,SAAQ;QACV,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QACtG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,EAAE,6BAA6B,EAC3E,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,wCAAwC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YACpG,SAAQ;QACV,CAAC;QACD,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/C,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,KAAK,uBAAuB,CAAC,CAAA;QACxE,MAAM,KAAK,GAAsB,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;YAChF,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAA;QACrF,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB;YACtD,CAAC,CAAC,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,mBAAmB,CAAA;QAC/E,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,EAC9C,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,4DAA4D,EAC3F,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IAC7B,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,8BAA8B,CAAC,QAAwB,EAAE,MAAmB;IACnF,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,IAAI,QAAQ,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC/C,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,uBAAuB,EAAE,cAAc,EAAE,yBAAyB,EACvF,iEAAiE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5F,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,CAAC;QAC1E,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,cAAc,EAAE,6BAA6B,EACvF,uEAAuE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAClG,CAAC;IACD,IAAI,MAAM,CAAC,qBAAqB,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACnF,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,yBAAyB,EACxE,yDAAyD,CAAC,CAAC,CAAA;IAC/D,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,qBAAqB,CAAC,OAAO,EAAE,CAAC;QAC7D,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,2BAA2B,EAC1E,8DAA8D,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAA;IAChH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,OAAsB,EAAE,MAAmB;IAClE,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,IAAI,SAAe,CAAA;IACnB,IAAI,CAAC;QACH,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACtH,CAAC;IACD,IAAI,SAAS,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;QACxE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,oBAAoB,EACjE,8CAA8C,CAAC,CAAC,CAAA;IACpD,CAAC;SAAM,IAAI,MAAM,CAAC,cAAc,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;QAChH,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,EAC3D,4CAA4C,CAAC,CAAC,CAAA;IAClD,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,wBAAwB,EACnE,8CAA8C,CAAC,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,MAAM,GAAoE;QAC9E,QAAQ,EAAE,CAAC,aAAa,CAAC;QACzB,QAAQ,EAAE,CAAC,YAAY,CAAC;QACxB,SAAS,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;QAC3C,GAAG,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC;KAChC,CAAA;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;gBAC7G,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,sBAAsB,EACnE,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,6BAA6B,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YAClF,CAAC;QACH,CAAC;QACD,IACE,MAAM,CAAC,yBAAyB;eAC7B,MAAM,CAAC,IAAI,KAAK,UAAU;eAC1B,OAAO,MAAM,CAAC,SAAS,CAAC,UAAU,KAAK,QAAQ;eAC/C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAC/E,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,kBAAkB,EAC/D,2CAA2C,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,QAAwE,EACxE,MAAmB;IAEnB,MAAM,UAAU,GAAsB,EAAE,CAAA;IACxC,IAAI,QAAwB,CAAA;IAC5B,IAAI,CAAC;QACH,QAAQ,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;YAC1E,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC5E,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IACD,IAAI,CAAC;QACH,gBAAgB,CAAC,2BAA2B,EAAE,QAAQ,CAAC,CAAA;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;YAC3C,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC9E,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,IAAI,QAAQ,CAAC,cAAc,KAAK,cAAc,EAAE,CAAC;QACrF,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,0BAA0B,CAAC,CAAC,CAAC,CAAA;IAChG,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,4CAA4C,CAAC,CAAC,CAAA;IACtG,UAAU,CAAC,IAAI,CAAC,GAAG,8BAA8B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;IAEpE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAA;IAClC,IAAI,QAAQ,CAAC,WAAW,KAAK,mBAAmB,EAAE,CAAC;QACjD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,0BAA0B,EAAE,+BAA+B,CAAC,CAAC,CAAA;QAC1G,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;IAC3B,CAAC;IACD,IAAI,YAAoB,CAAA;IACxB,IAAI,CAAC;QACH,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAC7D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1D,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,aAAa,GAA6C,EAAE,CAAA;IAClE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,IAAI,gBAAgB,GAAG,KAAK,CAAA;IAC5B,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAA;QAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,SAAS,EAAE,yBAAyB,EAC7E,2DAA2D,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;YAC1E,gBAAgB,GAAG,IAAI,CAAA;YACvB,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACf,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,iBAAiB,EAC1E,+EAA+E,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;YAC9F,SAAQ;QACV,CAAC;QACD,IAAI,cAAsB,CAAA;QAC1B,IAAI,CAAC;YACH,cAAc,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAA;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,SAAS,EAAE,oBAAoB,EACxE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;YACrE,gBAAgB,GAAG,IAAI,CAAA;YACvB,SAAQ;QACV,CAAC;QACD,IACE,cAAc,CAAC,MAAM,KAAK,EAAE;eACzB,CAAC,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC,EACpF,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,SAAS,EAAE,mBAAmB,EACvE,gEAAgE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;YAC/E,gBAAgB,GAAG,IAAI,CAAA;YACvB,SAAQ;QACV,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,gBAAgB;QAAE,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;IAC/C,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,6BAA6B,EACtF,+CAA+C,CAAC,CAAC,CAAA;QACnD,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;IAC3B,CAAC;IAED,IAAI,OAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,CAAA;QACtC,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC3E,MAAM,IAAI,UAAU,CAAC,sCAAsC,CAAC,CAAA;QAC9D,CAAC;QACD,aAAa,CAAC,MAAM,EAAE;YACpB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAC,CAAA;QACF,OAAO,GAAG,MAAkC,CAAA;QAC5C,gBAAgB,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAA;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;YAC1E,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/E,OAAO,MAAM,CAAC,UAAU,CAAC,CAAA;QAC3B,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IACD,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3E,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,qBAAqB,EAChE,4DAA4D,CAAC,CAAC,CAAA;YAChE,OAAO,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QACpC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;YAC3C,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;YACjF,OAAO,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QACpC,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IACD,IAAI,OAAO,CAAC,cAAc,KAAK,cAAc,IAAI,QAAQ,CAAC,cAAc,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC;QACpG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,8BAA8B,EACzE,iDAAiD,CAAC,CAAC,CAAA;QACrD,OAAO,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IACpC,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,qCAAqC,CAAC,CAAC,CAAA;IAEnG,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACpD,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,aAAa,EAAE,CAAC;QACzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;QAC3E,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;QAC5E,IAAI,KAAK,KAAK,OAAO;YAAE,cAAc,IAAI,CAAC,CAAA;IAC5C,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;IAClF,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,4BAA4B,EACrF,mDAAmD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IACpE,CAAC;IACD,IAAI,cAAc,GAAG,MAAM,CAAC,sBAAsB,EAAE,CAAC;QACnD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,6BAA6B,EACtF,YAAY,MAAM,CAAC,sBAAsB,4BAA4B,cAAc,EAAE,CAAC,CAAC,CAAA;IAC3F,CAAC;IAED,IAAI,CAAC;QACH,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,uBAAuB,EAAE,CAAC;YAC7C,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;YAC3E,OAAO,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QACpC,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EACpD,uDAAuD,CAAC,CAAC,CAAA;IAC3D,MAAM,eAAe,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC3D,UAAU,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAA;IACnC,UAAU,CAAC,IAAI,CAAC,GAAG,uBAAuB,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7E,UAAU,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IACpD,OAAO,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { generateKeyPairSync } from 'node:crypto'
|
|
2
|
+
import {
|
|
3
|
+
contentId,
|
|
4
|
+
createBundlePayload,
|
|
5
|
+
createEd25519Signer,
|
|
6
|
+
createKeyRecord,
|
|
7
|
+
createRecord,
|
|
8
|
+
sealBundle,
|
|
9
|
+
TrustPolicy,
|
|
10
|
+
verifyBundle,
|
|
11
|
+
} from '@onchaindiligence/agent-evidence'
|
|
12
|
+
|
|
13
|
+
// Concise financial-agent example. It deliberately records non-execution;
|
|
14
|
+
// no blockchain settlement is fabricated.
|
|
15
|
+
const { privateKey, publicKey } = generateKeyPairSync('ed25519')
|
|
16
|
+
const signer = createEd25519Signer(privateKey)
|
|
17
|
+
const key = createKeyRecord(publicKey, { validFrom: '2026-08-28T00:00:00.000Z' })
|
|
18
|
+
const principal = createRecord('principal', {
|
|
19
|
+
principal_id: 'urn:example:treasury', principal_type: 'organization',
|
|
20
|
+
})
|
|
21
|
+
const agent = createRecord('agent', {
|
|
22
|
+
agent_id: 'urn:example:payment-agent', agent_version: '1.0.0', operator_ref: principal.id,
|
|
23
|
+
}, { parents: [principal.id] })
|
|
24
|
+
const mandate = createRecord('mandate', {
|
|
25
|
+
mandate_id: 'INV-1042', principal_ref: principal.id,
|
|
26
|
+
scope: { action: 'pay', recipient: 'vendor-X', asset: 'USDC', chain: 'eip155:5042002' },
|
|
27
|
+
limits: { maximum: '500.00' },
|
|
28
|
+
valid_from: '2026-08-28T00:00:00.000Z', valid_until: '2026-08-29T00:00:00.000Z',
|
|
29
|
+
}, { parents: [principal.id] })
|
|
30
|
+
const run = createRecord('run', {
|
|
31
|
+
run_external_id: 'run-INV-1042', agent_ref: agent.id, mandate_ref: mandate.id,
|
|
32
|
+
started_at: '2026-08-28T12:00:00.000Z',
|
|
33
|
+
}, { parents: [agent.id, mandate.id] })
|
|
34
|
+
const observation = { recipient_verified: false }
|
|
35
|
+
const evidence = createRecord('evidence', {
|
|
36
|
+
evidence_type: 'recipient-check', run_ref: run.id, trust_mode: 'agent-assertion',
|
|
37
|
+
source: { id: 'urn:example:ledger', type: 'internal-ledger' },
|
|
38
|
+
tool: { name: 'recipient-check', version: '1' },
|
|
39
|
+
request: { digest: { sha256: contentId({ invoice: 'INV-1042' }).slice(7) }, media_type: 'application/json' },
|
|
40
|
+
response: { mode: 'embedded', media_type: 'application/json', value: observation,
|
|
41
|
+
digest: { sha256: contentId(observation).slice(7) } },
|
|
42
|
+
observed_at: '2026-08-28T12:00:01.000Z', expires_at: null, scope: { invoice: 'INV-1042' },
|
|
43
|
+
}, { parents: [run.id] })
|
|
44
|
+
const rules = { require_recipient_verification: true }
|
|
45
|
+
const policy = createRecord('policy', {
|
|
46
|
+
policy_id: 'payment-policy', version: '1', digest: { sha256: contentId(rules).slice(7) },
|
|
47
|
+
source: 'https://example.invalid/policy/1', effective_from: '2026-08-28T00:00:00.000Z', policy: rules,
|
|
48
|
+
}, { parents: [run.id] })
|
|
49
|
+
const decision = createRecord('decision', {
|
|
50
|
+
decision_id: 'decision-INV-1042', run_ref: run.id, agent_ref: agent.id,
|
|
51
|
+
decision_type: 'payment-authorization', outcome: { authorized: false }, evidence_refs: [evidence.id],
|
|
52
|
+
policy_ref: policy.id, policy_digest: policy.statement.digest, decided_at: '2026-08-28T12:00:02.000Z',
|
|
53
|
+
}, { parents: [run.id, evidence.id, policy.id] })
|
|
54
|
+
const execution = createRecord('execution', {
|
|
55
|
+
execution_id: 'execution-INV-1042', decision_ref: decision.id,
|
|
56
|
+
execution_type: 'payment-withheld', status: 'withheld-not-submitted',
|
|
57
|
+
submitted_at: '2026-08-28T12:00:03.000Z',
|
|
58
|
+
}, { parents: [decision.id] })
|
|
59
|
+
const payload = createBundlePayload(
|
|
60
|
+
[principal, agent, mandate, run, evidence, policy, decision, execution],
|
|
61
|
+
{ createdAt: '2026-08-28T12:00:04.000Z' },
|
|
62
|
+
)
|
|
63
|
+
const bundle = await sealBundle(payload, signer, { keys: [key] })
|
|
64
|
+
const report = verifyBundle(bundle, TrustPolicy.fromKeyRecords([key], {
|
|
65
|
+
now: new Date('2026-08-28T12:01:00.000Z'),
|
|
66
|
+
}))
|
|
67
|
+
console.log(report.state, payload.bundle_id, execution.statement.status)
|