xoonya 3.0.1 → 3.1.1

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/proof_sdk.js CHANGED
@@ -154,20 +154,29 @@ const NATIVE_SIGNATURE_SUITES = Object.freeze({
154
154
  dilithium: Object.freeze({
155
155
  id: "dilithium",
156
156
  maturity: "planned_pqc",
157
+ status: "deprecated_placeholder",
158
+ deprecated_alias_of: "ml-dsa-65",
157
159
  public_key_format: "suite_defined",
158
- verification_posture: "registry_declared_not_yet_verified"
160
+ verification_posture: "registry_declared_not_yet_verified",
161
+ description: "Legacy pre-standard placeholder name. Use the implemented FIPS 204 suite `ml-dsa-65` instead; this entry never verifies."
159
162
  }),
160
163
  falcon: Object.freeze({
161
164
  id: "falcon",
162
165
  maturity: "planned_pqc",
166
+ status: "deprecated_placeholder",
167
+ deprecated_alias_of: null,
163
168
  public_key_format: "suite_defined",
164
- verification_posture: "registry_declared_not_yet_verified"
169
+ verification_posture: "registry_declared_not_yet_verified",
170
+ description: "Legacy pre-standard placeholder name (FN-DSA is not yet registered). This entry never verifies."
165
171
  }),
166
172
  "sphincs-plus": Object.freeze({
167
173
  id: "sphincs-plus",
168
174
  maturity: "planned_pqc",
175
+ status: "deprecated_placeholder",
176
+ deprecated_alias_of: "slh-dsa-sha2-128f",
169
177
  public_key_format: "suite_defined",
170
- verification_posture: "registry_declared_not_yet_verified"
178
+ verification_posture: "registry_declared_not_yet_verified",
179
+ description: "Legacy pre-standard placeholder name. Use the implemented FIPS 205 suite `slh-dsa-sha2-128f` instead; this entry never verifies."
171
180
  }),
172
181
  "ml-dsa-65": Object.freeze({
173
182
  id: "ml-dsa-65",
@@ -208,17 +217,23 @@ const XOONYA_NATIVE_IDENTITY_TYPES = Object.freeze({
208
217
  "05": Object.freeze({
209
218
  prefix: "05",
210
219
  id: "dilithium-public-key",
211
- canonical_material: "suite-defined-pqc-public-key-bytes"
220
+ canonical_material: "suite-defined-pqc-public-key-bytes",
221
+ status: "legacy_placeholder",
222
+ description: "Legacy placeholder prefix reserved before FIPS 204 finalization; the implemented PQ suite is `ml-dsa-65`. No verifier binds this prefix to a live suite."
212
223
  }),
213
224
  "06": Object.freeze({
214
225
  prefix: "06",
215
226
  id: "falcon-public-key",
216
- canonical_material: "suite-defined-pqc-public-key-bytes"
227
+ canonical_material: "suite-defined-pqc-public-key-bytes",
228
+ status: "legacy_placeholder",
229
+ description: "Legacy placeholder prefix reserved before FN-DSA standardization. No verifier binds this prefix to a live suite."
217
230
  }),
218
231
  "07": Object.freeze({
219
232
  prefix: "07",
220
233
  id: "sphincs-plus-public-key",
221
- canonical_material: "suite-defined-pqc-public-key-bytes"
234
+ canonical_material: "suite-defined-pqc-public-key-bytes",
235
+ status: "legacy_placeholder",
236
+ description: "Legacy placeholder prefix reserved before FIPS 205 finalization; the implemented PQ suite is `slh-dsa-sha2-128f`. No verifier binds this prefix to a live suite."
222
237
  })
223
238
  });
224
239
  const EXTERNAL_PROOF_IMPORT_METHODS = Object.freeze([
@@ -229,6 +244,53 @@ const EXTERNAL_PROOF_IMPORT_METHODS = Object.freeze([
229
244
  SIGNED_ENVELOPE_METHOD,
230
245
  PARTNER_PROOF_ENVELOPE_METHOD
231
246
  ]);
247
+ const VERIFICATION_CLASS_CRYPTOGRAPHIC = "cryptographic";
248
+ const VERIFICATION_CLASS_DIGEST = "digest";
249
+ const VERIFICATION_CLASS_STRUCTURAL = "structural";
250
+ const VERIFICATION_CLASS_ANCHORED_BINDING = "anchored_binding";
251
+ const PROOF_VERIFICATION_CLASSES = Object.freeze({
252
+ [VERIFICATION_CLASS_CRYPTOGRAPHIC]: Object.freeze({
253
+ id: VERIFICATION_CLASS_CRYPTOGRAPHIC,
254
+ cryptographically_verified: true,
255
+ strict_mode_accepted: true,
256
+ methods: Object.freeze([XOONYA_NATIVE_SIGNED_METHOD, XOONYA_NATIVE_HYBRID_METHOD]),
257
+ description: "A native classical and/or PQ signature was checked against the public key carried in the proof. Identity binding still requires a verifier-supplied trust root."
258
+ }),
259
+ [VERIFICATION_CLASS_DIGEST]: Object.freeze({
260
+ id: VERIFICATION_CLASS_DIGEST,
261
+ cryptographically_verified: false,
262
+ strict_mode_accepted: false,
263
+ methods: Object.freeze([XOONYA_NATIVE_SHA256_METHOD, LEGACY_OPRETURN_METHOD]),
264
+ description: "Only an unkeyed deterministic digest was recomputed. Anyone can produce a valid digest; this proves integrity and replayability, not authorship."
265
+ }),
266
+ [VERIFICATION_CLASS_ANCHORED_BINDING]: Object.freeze({
267
+ id: VERIFICATION_CLASS_ANCHORED_BINDING,
268
+ cryptographically_verified: false,
269
+ strict_mode_accepted: false,
270
+ methods: Object.freeze([XOONYA_NATIVE_ANCHORED_METHOD]),
271
+ description: "An unkeyed digest binding to declared anchor refs was recomputed. External anchor truth and authorship are not verified by xoonya."
272
+ }),
273
+ [VERIFICATION_CLASS_STRUCTURAL]: Object.freeze({
274
+ id: VERIFICATION_CLASS_STRUCTURAL,
275
+ cryptographically_verified: false,
276
+ strict_mode_accepted: false,
277
+ methods: Object.freeze(EXTERNAL_PROOF_IMPORT_METHODS.slice()),
278
+ description: "The envelope shape, method registration, and canonical receipt binding were checked. The external signature itself must be verified by the external verifier stack."
279
+ })
280
+ });
281
+ const STRICT_DIGEST_ONLY_REASON = "digest_only_not_cryptographically_verified";
282
+ const STRICT_EXTERNAL_VERIFICATION_REASON = "external_verification_required";
283
+ const NATIVE_PUBLIC_KEY_NOT_TRUSTED_REASON = "native_public_key_not_trusted";
284
+ const NATIVE_HYBRID_PUBLIC_KEY_NOT_TRUSTED_REASON = "native_hybrid_public_key_not_trusted";
285
+ const PROOF_VERIFICATION_STRICT_REJECTION_CODES = Object.freeze([
286
+ STRICT_DIGEST_ONLY_REASON,
287
+ STRICT_EXTERNAL_VERIFICATION_REASON
288
+ ]);
289
+ const PROOF_VERIFICATION_TRUST_ROOT_REJECTION_CODES = Object.freeze([
290
+ NATIVE_PUBLIC_KEY_NOT_TRUSTED_REASON,
291
+ NATIVE_HYBRID_PUBLIC_KEY_NOT_TRUSTED_REASON
292
+ ]);
293
+ const STRICT_VERIFY_ENV = "XOONYA_STRICT_VERIFY";
232
294
 
233
295
  function sha256Hex(buf) {
234
296
  return crypto.createHash("sha256").update(buf).digest("hex");
@@ -874,7 +936,19 @@ function buildNativeHybridProofMaterial(receipt, canonicalEvent, proofDescriptor
874
936
  };
875
937
  }
876
938
 
939
+ const NATIVE_HYBRID_RUNTIME_SUPPORT_CACHE = new Map();
940
+
877
941
  function runtimeSupportsNativeHybridSuite(hybridSuiteId) {
942
+ const cacheKey = normalizeString(hybridSuiteId);
943
+ if (NATIVE_HYBRID_RUNTIME_SUPPORT_CACHE.has(cacheKey)) {
944
+ return NATIVE_HYBRID_RUNTIME_SUPPORT_CACHE.get(cacheKey);
945
+ }
946
+ const supported = probeNativeHybridRuntimeSupport(cacheKey);
947
+ NATIVE_HYBRID_RUNTIME_SUPPORT_CACHE.set(cacheKey, supported);
948
+ return supported;
949
+ }
950
+
951
+ function probeNativeHybridRuntimeSupport(hybridSuiteId) {
878
952
  try {
879
953
  const hybridSuite = parseNativeHybridSuite(hybridSuiteId);
880
954
  const classicalPair = hybridSuite.classical_suite.id === "secp256k1"
@@ -1053,7 +1127,162 @@ function buildNativeAnchoredReceiptProof(receipt, canonicalEvent, options = {})
1053
1127
  };
1054
1128
  }
1055
1129
 
1056
- function verifyNativeSignedReceiptProof(receipt, ceb) {
1130
+ function strictVerifyEnabledByEnvironment() {
1131
+ const raw = normalizeString(process.env[STRICT_VERIFY_ENV]).toLowerCase();
1132
+ return raw === "1" || raw === "true";
1133
+ }
1134
+
1135
+ function resolveProofVerificationOptions(options) {
1136
+ const source = options && typeof options === "object" && !Array.isArray(options) ? options : {};
1137
+ const trustedPublicKeyRefs = source.trusted_public_key_refs &&
1138
+ typeof source.trusted_public_key_refs === "object" &&
1139
+ !Array.isArray(source.trusted_public_key_refs)
1140
+ ? source.trusted_public_key_refs
1141
+ : null;
1142
+ const expectedPublicKeyRef = normalizeString(source.expected_public_key_ref);
1143
+ const expectedClassicalPublicKeyRef = normalizeString(source.expected_classical_public_key_ref);
1144
+ const expectedPqPublicKeyRef = normalizeString(source.expected_pq_public_key_ref);
1145
+ const expectedHybridPublicKeyRef = normalizeString(source.expected_hybrid_public_key_ref);
1146
+ return {
1147
+ __resolved_verification_options: true,
1148
+ strict: source.strict === true || strictVerifyEnabledByEnvironment(),
1149
+ trust_root_applied: Boolean(
1150
+ trustedPublicKeyRefs ||
1151
+ expectedPublicKeyRef ||
1152
+ expectedClassicalPublicKeyRef ||
1153
+ expectedPqPublicKeyRef ||
1154
+ expectedHybridPublicKeyRef
1155
+ ),
1156
+ expected_public_key_ref: expectedPublicKeyRef,
1157
+ expected_classical_public_key_ref: expectedClassicalPublicKeyRef,
1158
+ expected_pq_public_key_ref: expectedPqPublicKeyRef,
1159
+ expected_hybrid_public_key_ref: expectedHybridPublicKeyRef,
1160
+ trusted_public_key_refs: trustedPublicKeyRefs
1161
+ };
1162
+ }
1163
+
1164
+ function normalizeTrustedPublicKeyRefList(value) {
1165
+ if (value == null) return [];
1166
+ const list = Array.isArray(value) ? value : [value];
1167
+ return list.map((entry) => normalizeString(entry)).filter(Boolean);
1168
+ }
1169
+
1170
+ function lookupTrustedPublicKeyEntry(trustedPublicKeyRefs, identityRef, agentIdentity) {
1171
+ if (!trustedPublicKeyRefs) return undefined;
1172
+ for (const candidate of [normalizeString(identityRef), normalizeString(agentIdentity)]) {
1173
+ if (candidate && Object.prototype.hasOwnProperty.call(trustedPublicKeyRefs, candidate)) {
1174
+ return trustedPublicKeyRefs[candidate];
1175
+ }
1176
+ }
1177
+ return undefined;
1178
+ }
1179
+
1180
+ function trustedPublicKeyRefsForLane(entry, lane) {
1181
+ if (entry == null) return { declared: false, refs: [] };
1182
+ if (typeof entry === "string" || Array.isArray(entry)) {
1183
+ return lane === "classical"
1184
+ ? { declared: true, refs: normalizeTrustedPublicKeyRefList(entry) }
1185
+ : { declared: false, refs: [] };
1186
+ }
1187
+ if (typeof entry !== "object") return { declared: false, refs: [] };
1188
+ const laneValue = lane === "classical"
1189
+ ? (entry.classical != null ? entry.classical : (entry.classical_public_key_ref != null ? entry.classical_public_key_ref : entry.public_key_ref))
1190
+ : lane === "pq"
1191
+ ? (entry.pq != null ? entry.pq : entry.pq_public_key_ref)
1192
+ : (entry.hybrid != null ? entry.hybrid : entry.hybrid_public_key_ref);
1193
+ if (laneValue == null) return { declared: false, refs: [] };
1194
+ return { declared: true, refs: normalizeTrustedPublicKeyRefList(laneValue) };
1195
+ }
1196
+
1197
+ function nativeSignedPublicKeyTrusted(verification, publicKeyRef, identityRef, agentIdentity) {
1198
+ if (!verification || !verification.trust_root_applied) return true;
1199
+ let constrained = false;
1200
+ if (verification.expected_public_key_ref) {
1201
+ constrained = true;
1202
+ if (publicKeyRef !== verification.expected_public_key_ref) return false;
1203
+ }
1204
+ if (verification.expected_classical_public_key_ref) {
1205
+ constrained = true;
1206
+ if (publicKeyRef !== verification.expected_classical_public_key_ref) return false;
1207
+ }
1208
+ if (verification.trusted_public_key_refs) {
1209
+ constrained = true;
1210
+ const entry = lookupTrustedPublicKeyEntry(verification.trusted_public_key_refs, identityRef, agentIdentity);
1211
+ const lane = trustedPublicKeyRefsForLane(entry, "classical");
1212
+ if (!lane.declared || !lane.refs.includes(publicKeyRef)) return false;
1213
+ }
1214
+ return constrained;
1215
+ }
1216
+
1217
+ function nativeHybridPublicKeyTrusted(verification, refs, identityRef, agentIdentity) {
1218
+ if (!verification || !verification.trust_root_applied) return true;
1219
+ let constrained = false;
1220
+ if (verification.expected_public_key_ref) {
1221
+ constrained = true;
1222
+ if (refs.classical !== verification.expected_public_key_ref && refs.hybrid !== verification.expected_public_key_ref) return false;
1223
+ }
1224
+ if (verification.expected_classical_public_key_ref) {
1225
+ constrained = true;
1226
+ if (refs.classical !== verification.expected_classical_public_key_ref) return false;
1227
+ }
1228
+ if (verification.expected_pq_public_key_ref) {
1229
+ constrained = true;
1230
+ if (refs.pq !== verification.expected_pq_public_key_ref) return false;
1231
+ }
1232
+ if (verification.expected_hybrid_public_key_ref) {
1233
+ constrained = true;
1234
+ if (refs.hybrid !== verification.expected_hybrid_public_key_ref) return false;
1235
+ }
1236
+ if (verification.trusted_public_key_refs) {
1237
+ const entry = lookupTrustedPublicKeyEntry(verification.trusted_public_key_refs, identityRef, agentIdentity);
1238
+ const classicalLane = trustedPublicKeyRefsForLane(entry, "classical");
1239
+ const pqLane = trustedPublicKeyRefsForLane(entry, "pq");
1240
+ const hybridLane = trustedPublicKeyRefsForLane(entry, "hybrid");
1241
+ if (!classicalLane.declared && !pqLane.declared && !hybridLane.declared) return false;
1242
+ if (classicalLane.declared && !classicalLane.refs.includes(refs.classical) && !classicalLane.refs.includes(refs.hybrid)) return false;
1243
+ if (pqLane.declared && !pqLane.refs.includes(refs.pq)) return false;
1244
+ if (hybridLane.declared && !hybridLane.refs.includes(refs.hybrid)) return false;
1245
+ constrained = true;
1246
+ }
1247
+ return constrained;
1248
+ }
1249
+
1250
+ function verificationClassForMethod(algorithm) {
1251
+ const normalized = normalizeString(algorithm);
1252
+ for (const entry of Object.values(PROOF_VERIFICATION_CLASSES)) {
1253
+ if (entry.methods.includes(normalized)) return entry.id;
1254
+ }
1255
+ return null;
1256
+ }
1257
+
1258
+ function listProofVerificationClasses() {
1259
+ return Object.values(PROOF_VERIFICATION_CLASSES).map((entry) => ({ ...entry, methods: entry.methods.slice() }));
1260
+ }
1261
+
1262
+ function finalizeProofMethodVerification(result, algorithm, verification) {
1263
+ const verificationClass = verificationClassForMethod(algorithm);
1264
+ const classEntry = verificationClass ? PROOF_VERIFICATION_CLASSES[verificationClass] : null;
1265
+ const decorated = {
1266
+ ...result,
1267
+ verification_class: verificationClass,
1268
+ cryptographically_verified: result.valid === true && Boolean(classEntry && classEntry.cryptographically_verified),
1269
+ strict: verification.strict === true,
1270
+ trust_root_applied: verification.trust_root_applied === true
1271
+ };
1272
+ if (decorated.valid === true && decorated.strict && classEntry && !classEntry.strict_mode_accepted) {
1273
+ return {
1274
+ ...decorated,
1275
+ valid: false,
1276
+ reason: verificationClass === VERIFICATION_CLASS_STRUCTURAL
1277
+ ? STRICT_EXTERNAL_VERIFICATION_REASON
1278
+ : STRICT_DIGEST_ONLY_REASON,
1279
+ cryptographically_verified: false
1280
+ };
1281
+ }
1282
+ return decorated;
1283
+ }
1284
+
1285
+ function verifyNativeSignedReceiptProof(receipt, ceb, verification = null) {
1057
1286
  try {
1058
1287
  const proof = receipt.native_proof;
1059
1288
  if (!proof || typeof proof !== "object" || Array.isArray(proof)) {
@@ -1115,17 +1344,21 @@ function verifyNativeSignedReceiptProof(receipt, ceb) {
1115
1344
  if (!verified) {
1116
1345
  return { valid: false, reason: "native_signature_invalid" };
1117
1346
  }
1347
+ if (!nativeSignedPublicKeyTrusted(verification, expectedPublicKeyRef, identityRef, receipt.agent_identity)) {
1348
+ return { valid: false, reason: NATIVE_PUBLIC_KEY_NOT_TRUSTED_REASON, public_key_ref: expectedPublicKeyRef };
1349
+ }
1118
1350
  return {
1119
1351
  valid: true,
1120
1352
  verification_state: "verified_native_signature",
1121
- signature_suite: suite.id
1353
+ signature_suite: suite.id,
1354
+ public_key_ref: expectedPublicKeyRef
1122
1355
  };
1123
1356
  } catch (error) {
1124
1357
  return { valid: false, reason: error.message };
1125
1358
  }
1126
1359
  }
1127
1360
 
1128
- function verifyNativeHybridReceiptProof(receipt, ceb) {
1361
+ function verifyNativeHybridReceiptProof(receipt, ceb, verification = null) {
1129
1362
  try {
1130
1363
  const proof = receipt.native_proof;
1131
1364
  if (!proof || typeof proof !== "object" || Array.isArray(proof)) {
@@ -1210,10 +1443,27 @@ function verifyNativeHybridReceiptProof(receipt, ceb) {
1210
1443
  if (!crypto.verify(nativeSigningHashForSuite(hybridSuite.pq_suite), signingBytes, pqPublicKey, pqSignatureBytes)) {
1211
1444
  return { valid: false, reason: "native_hybrid_pq_signature_invalid" };
1212
1445
  }
1446
+ const publicKeyRefs = {
1447
+ classical: expectedClassicalPublicKeyRef,
1448
+ pq: expectedPqPublicKeyRef,
1449
+ hybrid: expectedHybridPublicKeyRef
1450
+ };
1451
+ if (!nativeHybridPublicKeyTrusted(verification, publicKeyRefs, identityRef, receipt.agent_identity)) {
1452
+ return {
1453
+ valid: false,
1454
+ reason: NATIVE_HYBRID_PUBLIC_KEY_NOT_TRUSTED_REASON,
1455
+ public_key_ref: expectedHybridPublicKeyRef,
1456
+ classical_public_key_ref: expectedClassicalPublicKeyRef,
1457
+ pq_public_key_ref: expectedPqPublicKeyRef
1458
+ };
1459
+ }
1213
1460
  return {
1214
1461
  valid: true,
1215
1462
  verification_state: "verified_native_hybrid_signature",
1216
- signature_suite: hybridSuite.id
1463
+ signature_suite: hybridSuite.id,
1464
+ public_key_ref: expectedHybridPublicKeyRef,
1465
+ classical_public_key_ref: expectedClassicalPublicKeyRef,
1466
+ pq_public_key_ref: expectedPqPublicKeyRef
1217
1467
  };
1218
1468
  } catch (error) {
1219
1469
  return { valid: false, reason: error.message };
@@ -1355,8 +1605,19 @@ function emitReceipt(event, options = {}) {
1355
1605
  };
1356
1606
  }
1357
1607
 
1358
- function verifyReceiptProofMethod(receipt, ceb, bundle) {
1608
+ function verifyReceiptProofMethod(receipt, ceb, bundle, options = {}) {
1609
+ const verification = options && options.__resolved_verification_options === true
1610
+ ? options
1611
+ : resolveProofVerificationOptions(options);
1359
1612
  const algorithm = normalizeString(receipt.algorithm);
1613
+ return finalizeProofMethodVerification(
1614
+ verifyReceiptProofMethodInner(receipt, ceb, bundle, algorithm, verification),
1615
+ algorithm,
1616
+ verification
1617
+ );
1618
+ }
1619
+
1620
+ function verifyReceiptProofMethodInner(receipt, ceb, bundle, algorithm, verification) {
1360
1621
  if (!algorithm) {
1361
1622
  return { valid: false, reason: "verification_method_missing" };
1362
1623
  }
@@ -1364,9 +1625,9 @@ function verifyReceiptProofMethod(receipt, ceb, bundle) {
1364
1625
  return { valid: false, reason: "verification_method_none" };
1365
1626
  }
1366
1627
  if (algorithm === XOONYA_NATIVE_HYBRID_METHOD) {
1367
- const verification = verifyNativeHybridReceiptProof(receipt, ceb);
1368
- if (!verification.valid) {
1369
- return { valid: false, reason: verification.reason };
1628
+ const hybridVerification = verifyNativeHybridReceiptProof(receipt, ceb, verification);
1629
+ if (!hybridVerification.valid) {
1630
+ return { valid: false, reason: hybridVerification.reason };
1370
1631
  }
1371
1632
  return {
1372
1633
  valid: true,
@@ -1376,8 +1637,11 @@ function verifyReceiptProofMethod(receipt, ceb, bundle) {
1376
1637
  verification_posture: "native_hybrid_signature_verified",
1377
1638
  description: "Verifies xoonya's native hybrid proof envelope with a classical and PQ signature bound to one deterministic signing material."
1378
1639
  },
1379
- verification_state: verification.verification_state,
1380
- signature_suite: verification.signature_suite
1640
+ verification_state: hybridVerification.verification_state,
1641
+ signature_suite: hybridVerification.signature_suite,
1642
+ public_key_ref: hybridVerification.public_key_ref,
1643
+ classical_public_key_ref: hybridVerification.classical_public_key_ref,
1644
+ pq_public_key_ref: hybridVerification.pq_public_key_ref
1381
1645
  };
1382
1646
  }
1383
1647
 
@@ -1428,29 +1692,30 @@ function verifyReceiptProofMethod(receipt, ceb, bundle) {
1428
1692
  }
1429
1693
 
1430
1694
  if (algorithm === XOONYA_NATIVE_SIGNED_METHOD) {
1431
- const verification = verifyNativeSignedReceiptProof(receipt, ceb);
1432
- if (!verification.valid) {
1433
- return { valid: false, reason: verification.reason };
1695
+ const signedVerification = verifyNativeSignedReceiptProof(receipt, ceb, verification);
1696
+ if (!signedVerification.valid) {
1697
+ return { valid: false, reason: signedVerification.reason };
1434
1698
  }
1435
1699
  return {
1436
1700
  valid: true,
1437
1701
  method,
1438
- verification_state: verification.verification_state,
1439
- signature_suite: verification.signature_suite
1702
+ verification_state: signedVerification.verification_state,
1703
+ signature_suite: signedVerification.signature_suite,
1704
+ public_key_ref: signedVerification.public_key_ref
1440
1705
  };
1441
1706
  }
1442
1707
 
1443
1708
  if (algorithm === XOONYA_NATIVE_ANCHORED_METHOD) {
1444
- const verification = verifyNativeAnchoredReceiptProof(receipt, ceb, bundle);
1445
- if (!verification.valid) {
1446
- return { valid: false, reason: verification.reason };
1709
+ const anchoredVerification = verifyNativeAnchoredReceiptProof(receipt, ceb, bundle);
1710
+ if (!anchoredVerification.valid) {
1711
+ return { valid: false, reason: anchoredVerification.reason };
1447
1712
  }
1448
1713
  return {
1449
1714
  valid: true,
1450
1715
  method,
1451
- verification_state: verification.verification_state,
1452
- anchor_count: verification.anchor_count,
1453
- anchor_root_sha256: verification.anchor_root_sha256
1716
+ verification_state: anchoredVerification.verification_state,
1717
+ anchor_count: anchoredVerification.anchor_count,
1718
+ anchor_root_sha256: anchoredVerification.anchor_root_sha256
1454
1719
  };
1455
1720
  }
1456
1721
 
@@ -1503,7 +1768,22 @@ function buildProofBundle(input) {
1503
1768
  };
1504
1769
  }
1505
1770
 
1506
- function verifyProofBundle(bundle) {
1771
+ function verifyProofBundle(bundle, options = {}) {
1772
+ const verification = resolveProofVerificationOptions(options);
1773
+ const result = verifyProofBundleInner(bundle, verification);
1774
+ const algorithm = bundle && bundle.receipt && typeof bundle.receipt === "object" && !Array.isArray(bundle.receipt)
1775
+ ? bundle.receipt.algorithm
1776
+ : null;
1777
+ return {
1778
+ ...result,
1779
+ cryptographically_verified: result.cryptographically_verified === true,
1780
+ verification_class: result.verification_class !== undefined ? result.verification_class : verificationClassForMethod(algorithm),
1781
+ strict: verification.strict,
1782
+ trust_root_applied: verification.trust_root_applied
1783
+ };
1784
+ }
1785
+
1786
+ function verifyProofBundleInner(bundle, verification) {
1507
1787
  try {
1508
1788
  if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
1509
1789
  return { valid: false, reason: "bundle_not_object" };
@@ -1549,9 +1829,14 @@ function verifyProofBundle(bundle) {
1549
1829
  return { valid: false, reason: "signature_missing" };
1550
1830
  }
1551
1831
 
1552
- const methodVerification = verifyReceiptProofMethod(receipt, ceb, bundle);
1832
+ const methodVerification = verifyReceiptProofMethod(receipt, ceb, bundle, verification);
1553
1833
  if (!methodVerification.valid) {
1554
- return { valid: false, reason: methodVerification.reason };
1834
+ return {
1835
+ valid: false,
1836
+ reason: methodVerification.reason,
1837
+ verification_class: methodVerification.verification_class,
1838
+ cryptographically_verified: false
1839
+ };
1555
1840
  }
1556
1841
 
1557
1842
  return {
@@ -1565,7 +1850,12 @@ function verifyProofBundle(bundle) {
1565
1850
  verification_state: methodVerification.verification_state,
1566
1851
  ...(methodVerification.anchor_count != null ? { anchor_count: methodVerification.anchor_count } : {}),
1567
1852
  ...(methodVerification.anchor_root_sha256 ? { anchor_root_sha256: methodVerification.anchor_root_sha256 } : {}),
1568
- ...(methodVerification.signature_suite ? { signature_suite: methodVerification.signature_suite } : {})
1853
+ ...(methodVerification.signature_suite ? { signature_suite: methodVerification.signature_suite } : {}),
1854
+ ...(methodVerification.public_key_ref ? { public_key_ref: methodVerification.public_key_ref } : {}),
1855
+ ...(methodVerification.classical_public_key_ref ? { classical_public_key_ref: methodVerification.classical_public_key_ref } : {}),
1856
+ ...(methodVerification.pq_public_key_ref ? { pq_public_key_ref: methodVerification.pq_public_key_ref } : {}),
1857
+ verification_class: methodVerification.verification_class,
1858
+ cryptographically_verified: methodVerification.cryptographically_verified === true
1569
1859
  };
1570
1860
  } catch (error) {
1571
1861
  return { valid: false, reason: error.message };
@@ -3207,6 +3497,9 @@ function buildxoonyaNativeHybridReadinessPack() {
3207
3497
  atom_rule: "XNYA_atom_remains_commitment_only",
3208
3498
  envelope_rule: "hybrid_or_pqc_material_lives_in_proof_envelope_or_profile",
3209
3499
  current_deterministic_reject_reason: runtimeSupportedHybridSuites.length > 0 ? null : "native_hybrid_runtime_validator_unavailable",
3500
+ trust_root_reject_reason: NATIVE_HYBRID_PUBLIC_KEY_NOT_TRUSTED_REASON,
3501
+ strict_mode_reject_reasons: PROOF_VERIFICATION_STRICT_REJECTION_CODES.slice(),
3502
+ identity_binding_rule: "public_key_ref_is_self_bound_to_carried_key_material_identity_binding_requires_verifier_supplied_trust_root",
3210
3503
  downgrade_rule: "hybrid_receipts_must_not_verify_as_classical_native_signed_receipts",
3211
3504
  claim_rule: "claim_only_registered_runtime_supported_vector_covered_hybrid_suites"
3212
3505
  },
@@ -6228,6 +6521,9 @@ module.exports = {
6228
6521
  hashEvent,
6229
6522
  emitReceipt,
6230
6523
  listProofVerificationMethods,
6524
+ listProofVerificationClasses,
6525
+ PROOF_VERIFICATION_STRICT_REJECTION_CODES,
6526
+ PROOF_VERIFICATION_TRUST_ROOT_REJECTION_CODES,
6231
6527
  getProofVerificationMethod,
6232
6528
  listNativeSignatureSuites,
6233
6529
  getNativeSignatureSuite,
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ const assert = require("assert");
4
+ const {
5
+ summarizeAdapterCertificationContractPack,
6
+ summarizeTrustPortabilityBoundaryContractPack,
7
+ summarizeSignedAuditProvenanceContractPack
8
+ } = require("../index.js");
9
+
10
+ function main() {
11
+ const adapterCertification = summarizeAdapterCertificationContractPack();
12
+ const trustPortabilityBoundary = summarizeTrustPortabilityBoundaryContractPack();
13
+ const signedAuditProvenance = summarizeSignedAuditProvenanceContractPack();
14
+
15
+ assert.strictEqual(adapterCertification.ok, true, "adapter certification summary failed");
16
+ assert.strictEqual(adapterCertification.certification_state_count >= 5, true, "adapter certification state count mismatch");
17
+ assert.strictEqual(adapterCertification.certification_front_count >= 8, true, "adapter certification front count mismatch");
18
+ assert.strictEqual(adapterCertification.required_test_category_count >= 8, true, "adapter certification test category count mismatch");
19
+
20
+ assert.strictEqual(trustPortabilityBoundary.ok, true, "trust portability boundary summary failed");
21
+ assert.strictEqual(trustPortabilityBoundary.portable_axis_count >= 4, true, "trust portability axis count mismatch");
22
+ assert.strictEqual(trustPortabilityBoundary.non_claim_count >= 4, true, "trust portability non-claim count mismatch");
23
+ assert.strictEqual(trustPortabilityBoundary.evidence_requirement_count >= 5, true, "trust portability evidence requirement count mismatch");
24
+
25
+ assert.strictEqual(signedAuditProvenance.ok, true, "signed audit provenance summary failed");
26
+ assert.strictEqual(signedAuditProvenance.evidence_surface_count >= 6, true, "signed audit provenance surface count mismatch");
27
+ assert.strictEqual(signedAuditProvenance.required_field_count >= 7, true, "signed audit provenance required field count mismatch");
28
+ assert.strictEqual(signedAuditProvenance.export_rule_count >= 4, true, "signed audit provenance export rule count mismatch");
29
+
30
+ console.log("xoonya verify:control-plane-contracts passed");
31
+ }
32
+
33
+ main();
34
+
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ const assert = require("assert");
4
+ const { createServer } = require("../server.js");
5
+
6
+ async function getJson(baseUrl, route) {
7
+ const response = await fetch(`${baseUrl}${route}`);
8
+ return {
9
+ status: response.status,
10
+ json: await response.json()
11
+ };
12
+ }
13
+
14
+ async function main() {
15
+ const server = createServer();
16
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
17
+ const address = server.address();
18
+ const baseUrl = `http://127.0.0.1:${address.port}`;
19
+
20
+ try {
21
+ const adapterCertification = await getJson(baseUrl, "/v1/adapter-certification");
22
+ assert.strictEqual(adapterCertification.status, 200, "adapter certification route failed");
23
+ assert.strictEqual(adapterCertification.json.category, "naxytra-adapter-certification-contract", "adapter certification category mismatch");
24
+ assert.strictEqual(adapterCertification.json.certification_fronts.length >= 8, true, "adapter certification front count mismatch");
25
+
26
+ const adapterCertificationSummary = await getJson(baseUrl, "/v1/adapter-certification/summary");
27
+ assert.strictEqual(adapterCertificationSummary.status, 200, "adapter certification summary route failed");
28
+ assert.strictEqual(adapterCertificationSummary.json.certification_state_count >= 5, true, "adapter certification summary count mismatch");
29
+
30
+ const adapterCertificationDetail = await getJson(baseUrl, "/v1/adapter-certification/protocol_front");
31
+ assert.strictEqual(adapterCertificationDetail.status, 200, "adapter certification detail route failed");
32
+ assert.strictEqual(adapterCertificationDetail.json.front.front_id, "protocol_front", "adapter certification detail mismatch");
33
+
34
+ const trustBoundary = await getJson(baseUrl, "/v1/trust-portability-boundary");
35
+ assert.strictEqual(trustBoundary.status, 200, "trust portability boundary route failed");
36
+ assert.strictEqual(trustBoundary.json.category, "naxytra-trust-portability-boundary-contract", "trust portability boundary category mismatch");
37
+ assert.strictEqual(trustBoundary.json.portable_axes.length >= 4, true, "trust portability boundary axis count mismatch");
38
+
39
+ const trustBoundarySummary = await getJson(baseUrl, "/v1/trust-portability-boundary/summary");
40
+ assert.strictEqual(trustBoundarySummary.status, 200, "trust portability boundary summary route failed");
41
+ assert.strictEqual(trustBoundarySummary.json.portable_axis_count >= 4, true, "trust portability boundary summary count mismatch");
42
+
43
+ const trustBoundaryDetail = await getJson(baseUrl, "/v1/trust-portability-boundary/agent_identity_portability");
44
+ assert.strictEqual(trustBoundaryDetail.status, 200, "trust portability boundary detail route failed");
45
+ assert.strictEqual(trustBoundaryDetail.json.axis.axis_id, "agent_identity_portability", "trust portability boundary detail mismatch");
46
+
47
+ const signedAudit = await getJson(baseUrl, "/v1/signed-audit-provenance");
48
+ assert.strictEqual(signedAudit.status, 200, "signed audit provenance route failed");
49
+ assert.strictEqual(signedAudit.json.category, "naxytra-signed-audit-provenance-contract", "signed audit provenance category mismatch");
50
+ assert.strictEqual(signedAudit.json.evidence_surfaces.length >= 6, true, "signed audit provenance evidence surface count mismatch");
51
+
52
+ const signedAuditSummary = await getJson(baseUrl, "/v1/signed-audit-provenance/summary");
53
+ assert.strictEqual(signedAuditSummary.status, 200, "signed audit provenance summary route failed");
54
+ assert.strictEqual(signedAuditSummary.json.evidence_surface_count >= 6, true, "signed audit provenance summary count mismatch");
55
+
56
+ const signedAuditDetail = await getJson(baseUrl, "/v1/signed-audit-provenance/release_provenance");
57
+ assert.strictEqual(signedAuditDetail.status, 200, "signed audit provenance detail route failed");
58
+ assert.strictEqual(signedAuditDetail.json.surface.surface_id, "release_provenance", "signed audit provenance detail mismatch");
59
+ } finally {
60
+ await new Promise((resolve) => server.close(resolve));
61
+ }
62
+
63
+ console.log("xoonya verify:control-plane-routes passed");
64
+ }
65
+
66
+ main().catch((error) => {
67
+ console.error(error);
68
+ process.exit(1);
69
+ });
70
+