@riddledc/riddle-proof 0.8.83 → 0.8.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -30
- package/dist/advanced/index.d.cts +1 -1
- package/dist/advanced/index.d.ts +1 -1
- package/dist/advanced/proof-run-engine.d.cts +1 -1
- package/dist/advanced/proof-run-engine.d.ts +1 -1
- package/dist/chunk-AQTCU6W5.js +1086 -0
- package/dist/index.cjs +569 -62
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -2
- package/dist/{proof-run-engine-MiKZt9oY.d.ts → proof-run-engine-BqRoA3Do.d.ts} +3 -3
- package/dist/{proof-run-engine-Baiv6l3A.d.cts → proof-run-engine-DpChFR5H.d.cts} +3 -3
- package/dist/proof-run-engine.d.cts +1 -1
- package/dist/proof-run-engine.d.ts +1 -1
- package/dist/semantic-certificate.cjs +571 -64
- package/dist/semantic-certificate.d.cts +120 -1
- package/dist/semantic-certificate.d.ts +120 -1
- package/dist/semantic-certificate.js +15 -3
- package/package.json +1 -1
- package/dist/chunk-DB5ZHRUP.js +0 -585
|
@@ -20,16 +20,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/semantic-certificate.ts
|
|
21
21
|
var semantic_certificate_exports = {};
|
|
22
22
|
__export(semantic_certificate_exports, {
|
|
23
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES,
|
|
24
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
23
25
|
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION: () => RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
|
|
26
|
+
composeRiddleProofSemanticCertificateClosures: () => composeRiddleProofSemanticCertificateClosures,
|
|
24
27
|
composeRiddleProofSemanticCertificates: () => composeRiddleProofSemanticCertificates,
|
|
28
|
+
createRiddleProofSemanticAtomicCertificateClosure: () => createRiddleProofSemanticAtomicCertificateClosure,
|
|
25
29
|
createRiddleProofSemanticCertificate: () => createRiddleProofSemanticCertificate,
|
|
26
30
|
matchRiddleProofSemanticCertificate: () => matchRiddleProofSemanticCertificate,
|
|
31
|
+
matchRiddleProofSemanticCertificateClosure: () => matchRiddleProofSemanticCertificateClosure,
|
|
27
32
|
parseRiddleProofSemanticCertificate: () => parseRiddleProofSemanticCertificate,
|
|
28
|
-
riddleProofSemanticScopesEqual: () => riddleProofSemanticScopesEqual
|
|
33
|
+
riddleProofSemanticScopesEqual: () => riddleProofSemanticScopesEqual,
|
|
34
|
+
validateRiddleProofSemanticCertificateClosure: () => validateRiddleProofSemanticCertificateClosure
|
|
29
35
|
});
|
|
30
36
|
module.exports = __toCommonJS(semantic_certificate_exports);
|
|
31
37
|
var import_node_crypto = require("crypto");
|
|
32
38
|
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION = "riddle-proof.semantic-certificate.v0";
|
|
39
|
+
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION = "riddle-proof.semantic-certificate-closure.v0";
|
|
40
|
+
var RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES = 4096;
|
|
33
41
|
var SCOPE_FIELDS = [
|
|
34
42
|
"repository",
|
|
35
43
|
"revision",
|
|
@@ -61,7 +69,9 @@ var CERTIFICATE_FIELDS = /* @__PURE__ */ new Set([
|
|
|
61
69
|
"issued_at"
|
|
62
70
|
]);
|
|
63
71
|
function isRecord(value) {
|
|
64
|
-
|
|
72
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
73
|
+
const prototype = Object.getPrototypeOf(value);
|
|
74
|
+
return prototype === Object.prototype || prototype === null;
|
|
65
75
|
}
|
|
66
76
|
function safeErrorMessage(error) {
|
|
67
77
|
try {
|
|
@@ -76,51 +86,129 @@ function safeErrorMessage(error) {
|
|
|
76
86
|
}
|
|
77
87
|
function assertOnlyKeys(record, allowed, context) {
|
|
78
88
|
const allowedSet = new Set(allowed);
|
|
79
|
-
for (const key of
|
|
89
|
+
for (const key of Reflect.ownKeys(record)) {
|
|
90
|
+
if (typeof key !== "string") {
|
|
91
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
92
|
+
}
|
|
80
93
|
if (!allowedSet.has(key)) {
|
|
81
94
|
throw new Error(`${context} contains unsupported field ${key}.`);
|
|
82
95
|
}
|
|
96
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
97
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
98
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function readDenseDataArray(value, context, maximumLength) {
|
|
103
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) {
|
|
104
|
+
throw new Error(`${context} must be a plain array.`);
|
|
105
|
+
}
|
|
106
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
|
|
107
|
+
if (!lengthDescriptor || typeof lengthDescriptor.value !== "number" || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) {
|
|
108
|
+
throw new Error(`${context}.length must be an own data field.`);
|
|
109
|
+
}
|
|
110
|
+
const length = lengthDescriptor.value;
|
|
111
|
+
if (maximumLength !== void 0 && length > maximumLength) {
|
|
112
|
+
throw new Error(`${context} exceeds ${maximumLength} entries.`);
|
|
113
|
+
}
|
|
114
|
+
const indexedElements = [];
|
|
115
|
+
let elementCount = 0;
|
|
116
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
117
|
+
if (key === "length") continue;
|
|
118
|
+
if (typeof key !== "string") {
|
|
119
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
120
|
+
}
|
|
121
|
+
const index = Number(key);
|
|
122
|
+
if (!Number.isInteger(index) || index < 0 || index >= length || index >= 2 ** 32 - 1 || String(index) !== key) {
|
|
123
|
+
throw new Error(`${context} contains unsupported array field ${key}.`);
|
|
124
|
+
}
|
|
125
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
126
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
127
|
+
throw new Error(`${context}[${key}] must be an enumerable data field.`);
|
|
128
|
+
}
|
|
129
|
+
indexedElements.push([index, descriptor.value]);
|
|
130
|
+
elementCount += 1;
|
|
131
|
+
}
|
|
132
|
+
if (elementCount !== length) {
|
|
133
|
+
throw new Error(`${context} must not contain sparse or inherited entries.`);
|
|
134
|
+
}
|
|
135
|
+
indexedElements.sort(([left], [right]) => left - right);
|
|
136
|
+
return indexedElements.map(([, entry]) => entry);
|
|
137
|
+
}
|
|
138
|
+
function requiredField(record, key, context) {
|
|
139
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
140
|
+
if (!descriptor) {
|
|
141
|
+
throw new Error(`${context}.${key} is required.`);
|
|
142
|
+
}
|
|
143
|
+
if (descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
144
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
83
145
|
}
|
|
146
|
+
return descriptor.value;
|
|
147
|
+
}
|
|
148
|
+
function optionalField(record, key) {
|
|
149
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
150
|
+
if (!descriptor) return void 0;
|
|
151
|
+
if (descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
152
|
+
throw new Error(`${key} must be an enumerable data field.`);
|
|
153
|
+
}
|
|
154
|
+
return descriptor.value;
|
|
84
155
|
}
|
|
85
156
|
function requiredString(record, key, context) {
|
|
86
|
-
const value = record
|
|
157
|
+
const value = requiredField(record, key, context);
|
|
87
158
|
if (typeof value !== "string" || !value.trim()) {
|
|
88
159
|
throw new Error(`${context}.${key} must be a non-empty string.`);
|
|
89
160
|
}
|
|
90
161
|
return value.trim();
|
|
91
162
|
}
|
|
92
163
|
function optionalString(record, key, context) {
|
|
93
|
-
if (record
|
|
164
|
+
if (optionalField(record, key) === void 0) return void 0;
|
|
94
165
|
return requiredString(record, key, context);
|
|
95
166
|
}
|
|
96
|
-
function
|
|
167
|
+
function cloneJsonValue(value, context, ancestors = /* @__PURE__ */ new Set()) {
|
|
97
168
|
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
98
|
-
return
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === "number") {
|
|
172
|
+
if (!Number.isFinite(value)) throw new Error(`${context} must contain only finite numbers.`);
|
|
173
|
+
return value;
|
|
99
174
|
}
|
|
100
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
101
175
|
if (Array.isArray(value)) {
|
|
102
|
-
|
|
176
|
+
const elements = readDenseDataArray(value, context);
|
|
177
|
+
if (ancestors.has(value)) throw new Error(`${context} must not be cyclic.`);
|
|
103
178
|
ancestors.add(value);
|
|
104
|
-
const
|
|
179
|
+
const cloned2 = elements.map((entry, index) => cloneJsonValue(entry, `${context}[${index}]`, ancestors));
|
|
105
180
|
ancestors.delete(value);
|
|
106
|
-
return
|
|
181
|
+
return cloned2;
|
|
107
182
|
}
|
|
108
|
-
if (!isRecord(value))
|
|
109
|
-
|
|
110
|
-
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
111
|
-
if (ancestors.has(value)) return false;
|
|
183
|
+
if (!isRecord(value)) throw new Error(`${context} must contain only JSON values.`);
|
|
184
|
+
if (ancestors.has(value)) throw new Error(`${context} must not be cyclic.`);
|
|
112
185
|
ancestors.add(value);
|
|
113
|
-
const
|
|
186
|
+
const cloned = {};
|
|
187
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
188
|
+
if (typeof key !== "string") {
|
|
189
|
+
throw new Error(`${context} contains an unsupported symbol field.`);
|
|
190
|
+
}
|
|
191
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
192
|
+
if (!descriptor || descriptor.enumerable !== true || descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
193
|
+
throw new Error(`${context}.${key} must be an enumerable data field.`);
|
|
194
|
+
}
|
|
195
|
+
Object.defineProperty(cloned, key, {
|
|
196
|
+
value: cloneJsonValue(descriptor.value, `${context}.${key}`, ancestors),
|
|
197
|
+
enumerable: true,
|
|
198
|
+
configurable: true,
|
|
199
|
+
writable: true
|
|
200
|
+
});
|
|
201
|
+
}
|
|
114
202
|
ancestors.delete(value);
|
|
115
|
-
return
|
|
203
|
+
return cloned;
|
|
116
204
|
}
|
|
117
205
|
function parseJsonObject(value, context) {
|
|
118
206
|
if (value === void 0) return void 0;
|
|
119
|
-
if (!isRecord(value)
|
|
207
|
+
if (!isRecord(value)) {
|
|
120
208
|
throw new Error(`${context} must be a JSON object.`);
|
|
121
209
|
}
|
|
122
|
-
const cloned =
|
|
123
|
-
if (!isRecord(cloned)
|
|
210
|
+
const cloned = cloneJsonValue(value, context);
|
|
211
|
+
if (!isRecord(cloned)) {
|
|
124
212
|
throw new Error(`${context} must remain a JSON object when serialized.`);
|
|
125
213
|
}
|
|
126
214
|
return cloned;
|
|
@@ -145,7 +233,7 @@ function parseScope(value, context) {
|
|
|
145
233
|
function parseClaimRef(value, context, allowedExtras = []) {
|
|
146
234
|
if (!isRecord(value)) throw new Error(`${context} must be an object.`);
|
|
147
235
|
assertOnlyKeys(value, ["claim_id", "claim_version", "parameters", ...allowedExtras], context);
|
|
148
|
-
const parameters = parseJsonObject(value
|
|
236
|
+
const parameters = parseJsonObject(optionalField(value, "parameters"), `${context}.parameters`);
|
|
149
237
|
return {
|
|
150
238
|
claim_id: requiredString(value, "claim_id", context),
|
|
151
239
|
claim_version: requiredString(value, "claim_version", context),
|
|
@@ -181,10 +269,11 @@ function parseEvidenceRef(value, context) {
|
|
|
181
269
|
};
|
|
182
270
|
}
|
|
183
271
|
function parseEvidenceBundle(value, context) {
|
|
184
|
-
|
|
272
|
+
const entries = readDenseDataArray(value, context);
|
|
273
|
+
if (entries.length === 0) {
|
|
185
274
|
throw new Error(`${context} must contain at least one evidence reference.`);
|
|
186
275
|
}
|
|
187
|
-
return
|
|
276
|
+
return entries.map((entry, index) => parseEvidenceRef(entry, `${context}[${index}]`));
|
|
188
277
|
}
|
|
189
278
|
function parseContractRef(value, context) {
|
|
190
279
|
if (!isRecord(value)) throw new Error(`${context} must be an object.`);
|
|
@@ -201,30 +290,32 @@ function parseContract(value, context, allowRuntimePredicate = false) {
|
|
|
201
290
|
["contract_id", "contract_version", "label", "claim", ...allowRuntimePredicate ? ["accepts"] : []],
|
|
202
291
|
context
|
|
203
292
|
);
|
|
204
|
-
if (allowRuntimePredicate && typeof value
|
|
293
|
+
if (allowRuntimePredicate && typeof requiredField(value, "accepts", context) !== "function") {
|
|
205
294
|
throw new Error(`${context}.accepts must be a function.`);
|
|
206
295
|
}
|
|
207
296
|
return {
|
|
208
297
|
...parseContractRef(value, context),
|
|
209
|
-
claim: parseClaim(value
|
|
298
|
+
claim: parseClaim(requiredField(value, "claim", context), `${context}.claim`)
|
|
210
299
|
};
|
|
211
300
|
}
|
|
212
301
|
function parseRule(value, context, allowFullPremises = false) {
|
|
213
302
|
if (!isRecord(value)) throw new Error(`${context} must be an object.`);
|
|
214
303
|
assertOnlyKeys(value, ["rule_id", "rule_version", "label", "premises", "conclusion"], context);
|
|
215
|
-
|
|
304
|
+
const premises = requiredField(value, "premises", context);
|
|
305
|
+
const premiseValues = readDenseDataArray(premises, `${context}.premises`);
|
|
306
|
+
if (premiseValues.length === 0) {
|
|
216
307
|
throw new Error(`${context}.premises must contain at least one claim reference.`);
|
|
217
308
|
}
|
|
218
309
|
return {
|
|
219
310
|
rule_id: requiredString(value, "rule_id", context),
|
|
220
311
|
rule_version: requiredString(value, "rule_version", context),
|
|
221
312
|
label: requiredString(value, "label", context),
|
|
222
|
-
premises:
|
|
313
|
+
premises: premiseValues.map((premise, index) => parseClaimRef(
|
|
223
314
|
premise,
|
|
224
315
|
`${context}.premises[${index}]`,
|
|
225
316
|
allowFullPremises ? ["label"] : []
|
|
226
317
|
)),
|
|
227
|
-
conclusion: parseClaim(value
|
|
318
|
+
conclusion: parseClaim(requiredField(value, "conclusion", context), `${context}.conclusion`)
|
|
228
319
|
};
|
|
229
320
|
}
|
|
230
321
|
function parsePremise(value, context) {
|
|
@@ -244,9 +335,9 @@ function parsePremise(value, context) {
|
|
|
244
335
|
certificate_id: requiredString(value, "certificate_id", context),
|
|
245
336
|
derivation_kind: derivationKind,
|
|
246
337
|
assurance,
|
|
247
|
-
scope: parseScope(value
|
|
248
|
-
claim: parseClaim(value
|
|
249
|
-
evidence: parseEvidenceBundle(value
|
|
338
|
+
scope: parseScope(requiredField(value, "scope", context), `${context}.scope`),
|
|
339
|
+
claim: parseClaim(requiredField(value, "claim", context), `${context}.claim`),
|
|
340
|
+
evidence: parseEvidenceBundle(requiredField(value, "evidence", context), `${context}.evidence`)
|
|
250
341
|
};
|
|
251
342
|
}
|
|
252
343
|
function stableJson(value) {
|
|
@@ -276,28 +367,30 @@ function parseDerivation(value, context) {
|
|
|
276
367
|
const kind = requiredString(value, "kind", context);
|
|
277
368
|
if (kind === "contract") {
|
|
278
369
|
assertOnlyKeys(value, ["kind", "assurance", "contract"], context);
|
|
279
|
-
if (value
|
|
370
|
+
if (requiredField(value, "assurance", context) !== "runtime_contract_accepted") {
|
|
280
371
|
throw new Error(`${context}.assurance must be runtime_contract_accepted.`);
|
|
281
372
|
}
|
|
282
373
|
return {
|
|
283
374
|
kind,
|
|
284
375
|
assurance: "runtime_contract_accepted",
|
|
285
|
-
contract: parseContract(value
|
|
376
|
+
contract: parseContract(requiredField(value, "contract", context), `${context}.contract`)
|
|
286
377
|
};
|
|
287
378
|
}
|
|
288
379
|
if (kind === "composition") {
|
|
289
380
|
assertOnlyKeys(value, ["kind", "assurance", "rule", "premises"], context);
|
|
290
|
-
if (value
|
|
381
|
+
if (requiredField(value, "assurance", context) !== "declared_runtime_rule") {
|
|
291
382
|
throw new Error(`${context}.assurance must be declared_runtime_rule.`);
|
|
292
383
|
}
|
|
293
|
-
|
|
384
|
+
const premises = requiredField(value, "premises", context);
|
|
385
|
+
const premiseValues = readDenseDataArray(premises, `${context}.premises`);
|
|
386
|
+
if (premiseValues.length === 0) {
|
|
294
387
|
throw new Error(`${context}.premises must contain at least one certificate premise.`);
|
|
295
388
|
}
|
|
296
389
|
return {
|
|
297
390
|
kind,
|
|
298
391
|
assurance: "declared_runtime_rule",
|
|
299
|
-
rule: parseRule(value
|
|
300
|
-
premises:
|
|
392
|
+
rule: parseRule(requiredField(value, "rule", context), `${context}.rule`),
|
|
393
|
+
premises: premiseValues.map((premise, index) => parsePremise(premise, `${context}.premises[${index}]`))
|
|
301
394
|
};
|
|
302
395
|
}
|
|
303
396
|
throw new Error(`${context}.kind must be contract or composition.`);
|
|
@@ -312,9 +405,25 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
312
405
|
["scope", "evidence", "observation", "contract", "issued_at"],
|
|
313
406
|
"semantic certificate input"
|
|
314
407
|
);
|
|
315
|
-
const scope = parseScope(input
|
|
316
|
-
const evidence = parseEvidenceBundle(
|
|
317
|
-
|
|
408
|
+
const scope = parseScope(requiredField(input, "scope", "semantic certificate input"), "semantic certificate scope");
|
|
409
|
+
const evidence = parseEvidenceBundle(
|
|
410
|
+
requiredField(input, "evidence", "semantic certificate input"),
|
|
411
|
+
"semantic certificate evidence"
|
|
412
|
+
);
|
|
413
|
+
const runtimeContract = requiredField(
|
|
414
|
+
input,
|
|
415
|
+
"contract",
|
|
416
|
+
"semantic certificate input"
|
|
417
|
+
);
|
|
418
|
+
const contract = parseContract(runtimeContract, "semantic certificate contract", true);
|
|
419
|
+
const accepts = requiredField(
|
|
420
|
+
runtimeContract,
|
|
421
|
+
"accepts",
|
|
422
|
+
"semantic certificate contract"
|
|
423
|
+
);
|
|
424
|
+
if (typeof accepts !== "function") {
|
|
425
|
+
throw new Error("semantic certificate contract.accepts must be a function.");
|
|
426
|
+
}
|
|
318
427
|
const contractRef = {
|
|
319
428
|
contract_id: contract.contract_id,
|
|
320
429
|
contract_version: contract.contract_version,
|
|
@@ -323,14 +432,17 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
323
432
|
const claim = contract.claim;
|
|
324
433
|
let accepted;
|
|
325
434
|
try {
|
|
326
|
-
accepted =
|
|
435
|
+
accepted = accepts(
|
|
436
|
+
{ ...scope },
|
|
437
|
+
requiredField(input, "observation", "semantic certificate input")
|
|
438
|
+
) === true;
|
|
327
439
|
} catch (error) {
|
|
328
440
|
return {
|
|
329
441
|
ok: false,
|
|
330
442
|
error: {
|
|
331
443
|
code: "contract_error",
|
|
332
444
|
contract: contractRef,
|
|
333
|
-
message: `Semantic contract evaluation failed: ${
|
|
445
|
+
message: `Semantic contract evaluation failed: ${safeErrorMessage(error)}.`
|
|
334
446
|
}
|
|
335
447
|
};
|
|
336
448
|
}
|
|
@@ -350,29 +462,35 @@ function createRiddleProofSemanticCertificate(input) {
|
|
|
350
462
|
claim,
|
|
351
463
|
evidence,
|
|
352
464
|
derivation: { kind: "contract", assurance: "runtime_contract_accepted", contract },
|
|
353
|
-
issued_at: parseIssuedAt(
|
|
465
|
+
issued_at: parseIssuedAt(
|
|
466
|
+
optionalField(input, "issued_at") || (/* @__PURE__ */ new Date()).toISOString(),
|
|
467
|
+
"semantic certificate issued_at"
|
|
468
|
+
)
|
|
354
469
|
};
|
|
355
470
|
return { ok: true, certificate: withCertificateId(body) };
|
|
356
471
|
}
|
|
357
472
|
function parseRiddleProofSemanticCertificate(value) {
|
|
358
473
|
if (!isRecord(value)) throw new Error("Semantic certificate must be an object.");
|
|
359
|
-
|
|
360
|
-
|
|
474
|
+
const version = optionalField(value, "version");
|
|
475
|
+
if (version !== RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION) {
|
|
476
|
+
throw new Error(`Unsupported Semantic certificate version ${String(version || "missing")}.`);
|
|
361
477
|
}
|
|
362
478
|
for (const field of AUTHORITY_FIELDS) {
|
|
363
479
|
if (Object.prototype.hasOwnProperty.call(value, field)) {
|
|
364
480
|
throw new Error(`Semantic certificate must not contain authority field ${field}.`);
|
|
365
481
|
}
|
|
366
482
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
|
|
483
|
+
assertOnlyKeys(value, [...CERTIFICATE_FIELDS], "Semantic certificate");
|
|
484
|
+
const scope = parseScope(requiredField(value, "scope", "semantic certificate"), "semantic certificate scope");
|
|
485
|
+
const claim = parseClaim(requiredField(value, "claim", "semantic certificate"), "semantic certificate claim");
|
|
486
|
+
const evidence = parseEvidenceBundle(
|
|
487
|
+
requiredField(value, "evidence", "semantic certificate"),
|
|
488
|
+
"semantic certificate evidence"
|
|
489
|
+
);
|
|
490
|
+
const derivation = parseDerivation(
|
|
491
|
+
requiredField(value, "derivation", "semantic certificate"),
|
|
492
|
+
"semantic certificate derivation"
|
|
493
|
+
);
|
|
376
494
|
if (derivation.kind === "contract" && !sameClaimRef(claim, derivation.contract.claim)) {
|
|
377
495
|
throw new Error("Semantic contract-derived claim must match its contract claim.");
|
|
378
496
|
}
|
|
@@ -402,7 +520,10 @@ function parseRiddleProofSemanticCertificate(value) {
|
|
|
402
520
|
claim,
|
|
403
521
|
evidence,
|
|
404
522
|
derivation,
|
|
405
|
-
issued_at: parseIssuedAt(
|
|
523
|
+
issued_at: parseIssuedAt(
|
|
524
|
+
requiredField(value, "issued_at", "semantic certificate"),
|
|
525
|
+
"semantic certificate issued_at"
|
|
526
|
+
)
|
|
406
527
|
};
|
|
407
528
|
const observedId = requiredString(value, "certificate_id", "semantic certificate");
|
|
408
529
|
const expectedId = certificateId(body);
|
|
@@ -412,7 +533,7 @@ function parseRiddleProofSemanticCertificate(value) {
|
|
|
412
533
|
return { ...body, certificate_id: observedId };
|
|
413
534
|
}
|
|
414
535
|
function matchRiddleProofSemanticCertificate(input) {
|
|
415
|
-
if (!isRecord(input)) throw new Error("Semantic certificate match input must be
|
|
536
|
+
if (!isRecord(input)) throw new Error("Semantic certificate match input must be a plain object.");
|
|
416
537
|
assertOnlyKeys(
|
|
417
538
|
input,
|
|
418
539
|
[
|
|
@@ -435,11 +556,11 @@ function matchRiddleProofSemanticCertificate(input) {
|
|
|
435
556
|
);
|
|
436
557
|
}
|
|
437
558
|
const expectedScope = parseScope(
|
|
438
|
-
input
|
|
559
|
+
requiredField(input, "expected_scope", "semantic certificate match input"),
|
|
439
560
|
"semantic certificate match expected_scope"
|
|
440
561
|
);
|
|
441
562
|
const expectedClaim = parseClaimRef(
|
|
442
|
-
input
|
|
563
|
+
requiredField(input, "expected_claim", "semantic certificate match input"),
|
|
443
564
|
"semantic certificate match expected_claim",
|
|
444
565
|
["label"]
|
|
445
566
|
);
|
|
@@ -455,7 +576,9 @@ function matchRiddleProofSemanticCertificate(input) {
|
|
|
455
576
|
}
|
|
456
577
|
let certificate;
|
|
457
578
|
try {
|
|
458
|
-
certificate = parseRiddleProofSemanticCertificate(
|
|
579
|
+
certificate = parseRiddleProofSemanticCertificate(
|
|
580
|
+
requiredField(input, "certificate", "semantic certificate match input")
|
|
581
|
+
);
|
|
459
582
|
} catch (error) {
|
|
460
583
|
return {
|
|
461
584
|
ok: false,
|
|
@@ -540,11 +663,20 @@ function composeRiddleProofSemanticCertificates(input) {
|
|
|
540
663
|
["rule", "certificates", "issued_at"],
|
|
541
664
|
"semantic composition input"
|
|
542
665
|
);
|
|
543
|
-
const rule = parseRule(
|
|
544
|
-
|
|
666
|
+
const rule = parseRule(
|
|
667
|
+
requiredField(input, "rule", "semantic composition input"),
|
|
668
|
+
"semantic composition rule",
|
|
669
|
+
true
|
|
670
|
+
);
|
|
671
|
+
const inputCertificates = requiredField(input, "certificates", "semantic composition input");
|
|
672
|
+
const certificateValues = readDenseDataArray(
|
|
673
|
+
inputCertificates,
|
|
674
|
+
"semantic composition input.certificates"
|
|
675
|
+
);
|
|
676
|
+
if (certificateValues.length === 0) {
|
|
545
677
|
throw new Error("Semantic composition requires at least one certificate.");
|
|
546
678
|
}
|
|
547
|
-
const certificates =
|
|
679
|
+
const certificates = certificateValues.map((certificate) => parseRiddleProofSemanticCertificate(certificate));
|
|
548
680
|
if (certificates.length !== rule.premises.length) {
|
|
549
681
|
return {
|
|
550
682
|
ok: false,
|
|
@@ -599,16 +731,391 @@ function composeRiddleProofSemanticCertificates(input) {
|
|
|
599
731
|
rule,
|
|
600
732
|
premises: certificates.map(premiseFromCertificate)
|
|
601
733
|
},
|
|
602
|
-
issued_at: parseIssuedAt(
|
|
734
|
+
issued_at: parseIssuedAt(
|
|
735
|
+
optionalField(input, "issued_at") || (/* @__PURE__ */ new Date()).toISOString(),
|
|
736
|
+
"semantic certificate issued_at"
|
|
737
|
+
)
|
|
603
738
|
};
|
|
604
739
|
return { ok: true, certificate: withCertificateId(body) };
|
|
605
740
|
}
|
|
741
|
+
function invalidClosure(message) {
|
|
742
|
+
return { ok: false, error: { code: "invalid_closure", message } };
|
|
743
|
+
}
|
|
744
|
+
function firstPremiseSnapshotMismatch(snapshot, certificate) {
|
|
745
|
+
const observed = premiseFromCertificate(certificate);
|
|
746
|
+
if (snapshot.derivation_kind !== observed.derivation_kind) return "derivation_kind";
|
|
747
|
+
if (snapshot.assurance !== observed.assurance) return "assurance";
|
|
748
|
+
if (stableJson(snapshot.scope) !== stableJson(observed.scope)) return "scope";
|
|
749
|
+
if (stableJson(snapshot.claim) !== stableJson(observed.claim)) return "claim";
|
|
750
|
+
if (stableJson(snapshot.evidence) !== stableJson(observed.evidence)) return "evidence";
|
|
751
|
+
return void 0;
|
|
752
|
+
}
|
|
753
|
+
function validateSemanticCertificateClosureInternal(value) {
|
|
754
|
+
if (!isRecord(value)) {
|
|
755
|
+
return invalidClosure("Semantic certificate closure must be a plain object.");
|
|
756
|
+
}
|
|
757
|
+
assertOnlyKeys(
|
|
758
|
+
value,
|
|
759
|
+
["version", "root_certificate_id", "certificates"],
|
|
760
|
+
"Semantic certificate closure"
|
|
761
|
+
);
|
|
762
|
+
if (requiredField(value, "version", "Semantic certificate closure") !== RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION) {
|
|
763
|
+
return invalidClosure("Unsupported Semantic certificate closure version.");
|
|
764
|
+
}
|
|
765
|
+
const rootCertificateId = requiredString(
|
|
766
|
+
value,
|
|
767
|
+
"root_certificate_id",
|
|
768
|
+
"Semantic certificate closure"
|
|
769
|
+
);
|
|
770
|
+
if (!/^rpsc_[0-9a-f]{64}$/u.test(rootCertificateId)) {
|
|
771
|
+
return invalidClosure(
|
|
772
|
+
"Semantic certificate closure.root_certificate_id must be a full rpsc content ID."
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
const inputCertificates = requiredField(
|
|
776
|
+
value,
|
|
777
|
+
"certificates",
|
|
778
|
+
"Semantic certificate closure"
|
|
779
|
+
);
|
|
780
|
+
const certificateValues = readDenseDataArray(
|
|
781
|
+
inputCertificates,
|
|
782
|
+
"Semantic certificate closure.certificates",
|
|
783
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES
|
|
784
|
+
);
|
|
785
|
+
if (certificateValues.length === 0) {
|
|
786
|
+
return invalidClosure("Semantic certificate closure must contain at least one certificate.");
|
|
787
|
+
}
|
|
788
|
+
const certificates = [];
|
|
789
|
+
for (let index = 0; index < certificateValues.length; index += 1) {
|
|
790
|
+
try {
|
|
791
|
+
certificates.push(parseRiddleProofSemanticCertificate(certificateValues[index]));
|
|
792
|
+
} catch (error) {
|
|
793
|
+
return {
|
|
794
|
+
ok: false,
|
|
795
|
+
error: {
|
|
796
|
+
code: "invalid_closure_certificate",
|
|
797
|
+
input_index: index,
|
|
798
|
+
message: `Semantic certificate closure certificate ${index} did not parse: ${safeErrorMessage(error)}`
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const certificatesById = /* @__PURE__ */ new Map();
|
|
804
|
+
const firstIndexById = /* @__PURE__ */ new Map();
|
|
805
|
+
for (let index = 0; index < certificates.length; index += 1) {
|
|
806
|
+
const certificate = certificates[index];
|
|
807
|
+
const firstIndex = firstIndexById.get(certificate.certificate_id);
|
|
808
|
+
if (firstIndex !== void 0) {
|
|
809
|
+
return {
|
|
810
|
+
ok: false,
|
|
811
|
+
error: {
|
|
812
|
+
code: "duplicate_certificate_id",
|
|
813
|
+
certificate_id: certificate.certificate_id,
|
|
814
|
+
first_index: firstIndex,
|
|
815
|
+
duplicate_index: index,
|
|
816
|
+
message: `Semantic certificate closure repeats certificate ${certificate.certificate_id}.`
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
firstIndexById.set(certificate.certificate_id, index);
|
|
821
|
+
certificatesById.set(certificate.certificate_id, certificate);
|
|
822
|
+
}
|
|
823
|
+
const rootCertificate = certificatesById.get(rootCertificateId);
|
|
824
|
+
if (!rootCertificate) {
|
|
825
|
+
return {
|
|
826
|
+
ok: false,
|
|
827
|
+
error: {
|
|
828
|
+
code: "root_certificate_missing",
|
|
829
|
+
root_certificate_id: rootCertificateId,
|
|
830
|
+
message: "Semantic certificate closure does not contain its declared root certificate."
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
const states = /* @__PURE__ */ new Map();
|
|
835
|
+
const stack = [{ certificate: rootCertificate, next_premise_index: 0 }];
|
|
836
|
+
const dependencyFirst = [];
|
|
837
|
+
states.set(rootCertificateId, "visiting");
|
|
838
|
+
while (stack.length > 0) {
|
|
839
|
+
const frame = stack[stack.length - 1];
|
|
840
|
+
const premises = frame.certificate.derivation.kind === "composition" ? frame.certificate.derivation.premises : [];
|
|
841
|
+
if (frame.next_premise_index < premises.length) {
|
|
842
|
+
const premiseIndex = frame.next_premise_index;
|
|
843
|
+
frame.next_premise_index += 1;
|
|
844
|
+
const snapshot = premises[premiseIndex];
|
|
845
|
+
const child = certificatesById.get(snapshot.certificate_id);
|
|
846
|
+
if (!child) {
|
|
847
|
+
return {
|
|
848
|
+
ok: false,
|
|
849
|
+
error: {
|
|
850
|
+
code: "dangling_premise",
|
|
851
|
+
parent_certificate_id: frame.certificate.certificate_id,
|
|
852
|
+
premise_index: premiseIndex,
|
|
853
|
+
premise_certificate_id: snapshot.certificate_id,
|
|
854
|
+
message: `Semantic certificate ${frame.certificate.certificate_id} premise ${premiseIndex} has no full certificate body.`
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
const mismatch = firstPremiseSnapshotMismatch(snapshot, child);
|
|
859
|
+
if (mismatch) {
|
|
860
|
+
return {
|
|
861
|
+
ok: false,
|
|
862
|
+
error: {
|
|
863
|
+
code: "premise_snapshot_mismatch",
|
|
864
|
+
parent_certificate_id: frame.certificate.certificate_id,
|
|
865
|
+
premise_index: premiseIndex,
|
|
866
|
+
premise_certificate_id: snapshot.certificate_id,
|
|
867
|
+
field: mismatch,
|
|
868
|
+
message: `Semantic certificate ${frame.certificate.certificate_id} premise ${premiseIndex} has a different ${mismatch} than its full certificate body.`
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
const childState = states.get(child.certificate_id);
|
|
873
|
+
if (childState === "visiting") {
|
|
874
|
+
const cycleStart = stack.findIndex(
|
|
875
|
+
(candidate) => candidate.certificate.certificate_id === child.certificate_id
|
|
876
|
+
);
|
|
877
|
+
const certificateIds = stack.slice(Math.max(0, cycleStart)).map((candidate) => candidate.certificate.certificate_id);
|
|
878
|
+
certificateIds.push(child.certificate_id);
|
|
879
|
+
return {
|
|
880
|
+
ok: false,
|
|
881
|
+
error: {
|
|
882
|
+
code: "certificate_cycle",
|
|
883
|
+
certificate_ids: certificateIds,
|
|
884
|
+
message: "Semantic certificate closure contains a certificate cycle."
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
if (childState !== "visited") {
|
|
889
|
+
states.set(child.certificate_id, "visiting");
|
|
890
|
+
stack.push({ certificate: child, next_premise_index: 0 });
|
|
891
|
+
}
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
stack.pop();
|
|
895
|
+
states.set(frame.certificate.certificate_id, "visited");
|
|
896
|
+
dependencyFirst.push(frame.certificate);
|
|
897
|
+
}
|
|
898
|
+
if (dependencyFirst.length !== certificates.length) {
|
|
899
|
+
const reachable = new Set(dependencyFirst.map((certificate) => certificate.certificate_id));
|
|
900
|
+
const unreachable = certificates.filter((certificate) => !reachable.has(certificate.certificate_id)).map((certificate) => certificate.certificate_id).sort();
|
|
901
|
+
return {
|
|
902
|
+
ok: false,
|
|
903
|
+
error: {
|
|
904
|
+
code: "unreachable_certificates",
|
|
905
|
+
certificate_ids: unreachable,
|
|
906
|
+
message: "Semantic certificate closure contains certificates unreachable from its root."
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
const closure = {
|
|
911
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
912
|
+
root_certificate_id: rootCertificateId,
|
|
913
|
+
certificates: dependencyFirst
|
|
914
|
+
};
|
|
915
|
+
return { ok: true, closure, root_certificate: rootCertificate };
|
|
916
|
+
}
|
|
917
|
+
function validateRiddleProofSemanticCertificateClosure(value) {
|
|
918
|
+
try {
|
|
919
|
+
return validateSemanticCertificateClosureInternal(value);
|
|
920
|
+
} catch (error) {
|
|
921
|
+
return invalidClosure(
|
|
922
|
+
`Semantic certificate closure did not parse: ${safeErrorMessage(error)}`
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function createRiddleProofSemanticAtomicCertificateClosure(input) {
|
|
927
|
+
if (!isRecord(input)) throw new Error("Semantic certificate closure input must be a plain object.");
|
|
928
|
+
assertOnlyKeys(input, ["certificate"], "Semantic certificate closure input");
|
|
929
|
+
const certificate = requiredField(input, "certificate", "Semantic certificate closure input");
|
|
930
|
+
let parsedCertificate;
|
|
931
|
+
try {
|
|
932
|
+
parsedCertificate = parseRiddleProofSemanticCertificate(certificate);
|
|
933
|
+
} catch (error) {
|
|
934
|
+
return {
|
|
935
|
+
ok: false,
|
|
936
|
+
error: {
|
|
937
|
+
code: "invalid_closure_certificate",
|
|
938
|
+
input_index: 0,
|
|
939
|
+
message: `Semantic certificate closure certificate 0 did not parse: ${safeErrorMessage(error)}`
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
if (parsedCertificate.derivation.kind !== "contract") {
|
|
944
|
+
return invalidClosure(
|
|
945
|
+
"An atomic Semantic certificate closure requires a contract-derived certificate."
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
return validateRiddleProofSemanticCertificateClosure({
|
|
949
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
950
|
+
root_certificate_id: parsedCertificate.certificate_id,
|
|
951
|
+
certificates: [certificate]
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
function composeRiddleProofSemanticCertificateClosures(input) {
|
|
955
|
+
if (!isRecord(input)) throw new Error("Semantic closure composition input must be a plain object.");
|
|
956
|
+
assertOnlyKeys(
|
|
957
|
+
input,
|
|
958
|
+
["rule", "closures", "issued_at"],
|
|
959
|
+
"Semantic closure composition input"
|
|
960
|
+
);
|
|
961
|
+
const inputClosures = requiredField(
|
|
962
|
+
input,
|
|
963
|
+
"closures",
|
|
964
|
+
"Semantic closure composition input"
|
|
965
|
+
);
|
|
966
|
+
const closureValues = readDenseDataArray(
|
|
967
|
+
inputClosures,
|
|
968
|
+
"Semantic closure composition input.closures"
|
|
969
|
+
);
|
|
970
|
+
if (closureValues.length === 0) {
|
|
971
|
+
throw new Error("Semantic closure composition requires at least one closure.");
|
|
972
|
+
}
|
|
973
|
+
const validatedClosures = [];
|
|
974
|
+
for (let index = 0; index < closureValues.length; index += 1) {
|
|
975
|
+
const result = validateRiddleProofSemanticCertificateClosure(closureValues[index]);
|
|
976
|
+
if (!result.ok) {
|
|
977
|
+
return {
|
|
978
|
+
ok: false,
|
|
979
|
+
error: {
|
|
980
|
+
code: "input_closure_invalid",
|
|
981
|
+
input_index: index,
|
|
982
|
+
cause: result.error,
|
|
983
|
+
message: `Semantic input closure ${index} is invalid: ${result.error.message}`
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
validatedClosures.push(result);
|
|
988
|
+
}
|
|
989
|
+
const roots = validatedClosures.map((result) => {
|
|
990
|
+
if (!result.ok) throw new Error("Validated Semantic closure unexpectedly became invalid.");
|
|
991
|
+
return result.root_certificate;
|
|
992
|
+
});
|
|
993
|
+
const composition = composeRiddleProofSemanticCertificates({
|
|
994
|
+
rule: requiredField(input, "rule", "Semantic closure composition input"),
|
|
995
|
+
certificates: roots,
|
|
996
|
+
issued_at: optionalField(input, "issued_at")
|
|
997
|
+
});
|
|
998
|
+
if (!composition.ok) return composition;
|
|
999
|
+
const merged = [];
|
|
1000
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1001
|
+
for (const result of validatedClosures) {
|
|
1002
|
+
if (!result.ok) continue;
|
|
1003
|
+
for (const certificate of result.closure.certificates) {
|
|
1004
|
+
const existing = byId.get(certificate.certificate_id);
|
|
1005
|
+
if (existing) {
|
|
1006
|
+
if (stableJson(existing) !== stableJson(certificate)) {
|
|
1007
|
+
return {
|
|
1008
|
+
ok: false,
|
|
1009
|
+
error: {
|
|
1010
|
+
code: "certificate_id_collision",
|
|
1011
|
+
certificate_id: certificate.certificate_id,
|
|
1012
|
+
message: `Semantic closures contain unequal bodies for ${certificate.certificate_id}.`
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
byId.set(certificate.certificate_id, certificate);
|
|
1019
|
+
merged.push(certificate);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
if (byId.has(composition.certificate.certificate_id)) {
|
|
1023
|
+
return {
|
|
1024
|
+
ok: false,
|
|
1025
|
+
error: {
|
|
1026
|
+
code: "certificate_id_collision",
|
|
1027
|
+
certificate_id: composition.certificate.certificate_id,
|
|
1028
|
+
message: "Semantic composition produced a root ID already present in its premise closures."
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
merged.push(composition.certificate);
|
|
1033
|
+
const validation = validateRiddleProofSemanticCertificateClosure({
|
|
1034
|
+
version: RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
1035
|
+
root_certificate_id: composition.certificate.certificate_id,
|
|
1036
|
+
certificates: merged
|
|
1037
|
+
});
|
|
1038
|
+
if (!validation.ok) {
|
|
1039
|
+
return {
|
|
1040
|
+
ok: false,
|
|
1041
|
+
error: {
|
|
1042
|
+
code: "closure_construction_failed",
|
|
1043
|
+
cause: validation.error,
|
|
1044
|
+
message: `Semantic closure construction failed: ${validation.error.message}`
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
return {
|
|
1049
|
+
ok: true,
|
|
1050
|
+
certificate: composition.certificate,
|
|
1051
|
+
closure: validation.closure
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function matchRiddleProofSemanticCertificateClosure(input) {
|
|
1055
|
+
if (!isRecord(input)) throw new Error("Semantic certificate closure match input must be a plain object.");
|
|
1056
|
+
assertOnlyKeys(
|
|
1057
|
+
input,
|
|
1058
|
+
[
|
|
1059
|
+
"closure",
|
|
1060
|
+
"expected_root_certificate_id",
|
|
1061
|
+
"expected_scope",
|
|
1062
|
+
"expected_claim",
|
|
1063
|
+
"expected_assurance"
|
|
1064
|
+
],
|
|
1065
|
+
"Semantic certificate closure match input"
|
|
1066
|
+
);
|
|
1067
|
+
const validation = validateRiddleProofSemanticCertificateClosure(
|
|
1068
|
+
requiredField(input, "closure", "Semantic certificate closure match input")
|
|
1069
|
+
);
|
|
1070
|
+
if (!validation.ok) return validation;
|
|
1071
|
+
const expectedRootCertificateId = requiredString(
|
|
1072
|
+
input,
|
|
1073
|
+
"expected_root_certificate_id",
|
|
1074
|
+
"Semantic certificate closure match input"
|
|
1075
|
+
);
|
|
1076
|
+
if (!/^rpsc_[0-9a-f]{64}$/u.test(expectedRootCertificateId)) {
|
|
1077
|
+
throw new Error(
|
|
1078
|
+
"Semantic certificate closure match input.expected_root_certificate_id must be a full rpsc content ID."
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
const rootMatch = matchRiddleProofSemanticCertificate({
|
|
1082
|
+
certificate: validation.root_certificate,
|
|
1083
|
+
expected_certificate_id: expectedRootCertificateId,
|
|
1084
|
+
expected_scope: requiredField(
|
|
1085
|
+
input,
|
|
1086
|
+
"expected_scope",
|
|
1087
|
+
"Semantic certificate closure match input"
|
|
1088
|
+
),
|
|
1089
|
+
expected_claim: requiredField(
|
|
1090
|
+
input,
|
|
1091
|
+
"expected_claim",
|
|
1092
|
+
"Semantic certificate closure match input"
|
|
1093
|
+
),
|
|
1094
|
+
expected_assurance: requiredField(
|
|
1095
|
+
input,
|
|
1096
|
+
"expected_assurance",
|
|
1097
|
+
"Semantic certificate closure match input"
|
|
1098
|
+
)
|
|
1099
|
+
});
|
|
1100
|
+
if (!rootMatch.ok) return rootMatch;
|
|
1101
|
+
return {
|
|
1102
|
+
ok: true,
|
|
1103
|
+
closure: validation.closure,
|
|
1104
|
+
root_certificate: rootMatch.certificate
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
606
1107
|
// Annotate the CommonJS export names for ESM import in node:
|
|
607
1108
|
0 && (module.exports = {
|
|
1109
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_MAX_CERTIFICATES,
|
|
1110
|
+
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_CLOSURE_VERSION,
|
|
608
1111
|
RIDDLE_PROOF_SEMANTIC_CERTIFICATE_VERSION,
|
|
1112
|
+
composeRiddleProofSemanticCertificateClosures,
|
|
609
1113
|
composeRiddleProofSemanticCertificates,
|
|
1114
|
+
createRiddleProofSemanticAtomicCertificateClosure,
|
|
610
1115
|
createRiddleProofSemanticCertificate,
|
|
611
1116
|
matchRiddleProofSemanticCertificate,
|
|
1117
|
+
matchRiddleProofSemanticCertificateClosure,
|
|
612
1118
|
parseRiddleProofSemanticCertificate,
|
|
613
|
-
riddleProofSemanticScopesEqual
|
|
1119
|
+
riddleProofSemanticScopesEqual,
|
|
1120
|
+
validateRiddleProofSemanticCertificateClosure
|
|
614
1121
|
});
|