xoonya 3.1.17 → 3.2.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/README.md +97 -74
- package/RELEASE_NOTES.md +1 -1
- package/START_HERE.md +38 -134
- package/bin/xoonya-first-run.js +22 -10
- package/bin/xoonya.js +61 -29
- package/lib/native_verify.js +1918 -0
- package/package.json +19 -42
- package/scripts/verify_release_candidate.js +243 -116
- package/scripts/verify_vectors.js +351 -104
- package/verify.js +95 -0
- package/.env.example +0 -10
- package/CARRIED_HANDOFF_DEMO.md +0 -60
- package/COMPATIBILITY_NOTE.md +0 -27
- package/CROSS_RUNTIME_POSTURE.md +0 -77
- package/EXAMPLE_PATHS.md +0 -53
- package/FINAL_CONTRACT.md +0 -445
- package/PARTNER_READY_PATH.md +0 -67
- package/PUBLIC_DEMO_SCRIPT.md +0 -79
- package/SERVICE_CONTRACT.md +0 -207
- package/TERMINOLOGY.md +0 -55
- package/WHY_XYTARA_XOONYA.md +0 -43
- package/XNYA_CONFORMANCE_MARK.md +0 -78
- package/XNYA_REFERENCE_IMPLEMENTATIONS.md +0 -157
- package/XOONYA_DEFAULT_PATH_MODEL.md +0 -63
- package/XOONYA_FOLLOWTHROUGH_TRUTH_MODEL.md +0 -63
- package/XOONYA_NATIVE_ATOM_SPEC.md +0 -184
- package/XOONYA_NATIVE_PROOF_FORMAT.md +0 -570
- package/XOONYA_NATIVE_STANDARD_GOVERNANCE.md +0 -119
- package/XOONYA_PROOF_TRUTH_MODEL.md +0 -58
- package/bin/xoonya-release.js +0 -1367
- package/bin/xoonya-review.js +0 -70
- package/examples/integration_boundary_walkthrough.js +0 -37
- package/examples/package_quickstart.js +0 -1007
- package/examples/partner_proof_walkthrough.js +0 -68
- package/examples/proof_review_walkthrough.js +0 -66
- package/examples/review_carried_handoff.js +0 -72
- package/index.js +0 -31
- package/integrations/PROOF_INTEGRATION_PROCESS.md +0 -45
- package/integrations/examples/example-third-party-verifier-registration.record.json +0 -22
- package/integrations/registration-record.schema.json +0 -99
- package/integrations/registry-snapshot.schema.json +0 -36
- package/integrations/registry.js +0 -636
- package/integrations/views.js +0 -36
- package/lib/adapter_certification_contract.js +0 -90
- package/lib/announcement_pack.js +0 -61
- package/lib/artifact_distribution_lane_contract.js +0 -54
- package/lib/asyncapi_contract.js +0 -135
- package/lib/auth_interop_contract.js +0 -69
- package/lib/authority_binding_lifecycle_contract.js +0 -182
- package/lib/bridge_intelligence.js +0 -102
- package/lib/cloudevents_contract.js +0 -79
- package/lib/crypto_agility_matrix.js +0 -131
- package/lib/default_path_contract.js +0 -380
- package/lib/ecosystem_entry.js +0 -64
- package/lib/erc8004_proof_lane_contract.js +0 -64
- package/lib/event_system_lane_contract.js +0 -76
- package/lib/external_proof_import_lane_contract.js +0 -87
- package/lib/feature_control_lane_contract.js +0 -54
- package/lib/followthrough_truth_contract.js +0 -214
- package/lib/framework_lane_contract.js +0 -76
- package/lib/governance_disputes_summary.js +0 -36
- package/lib/governance_intelligence.js +0 -108
- package/lib/identity_interop_contract.js +0 -83
- package/lib/integration_matrix_contract.js +0 -81
- package/lib/launch_narrative.js +0 -53
- package/lib/machine_identity_registry_contract.js +0 -199
- package/lib/major_rails_proof_lane_contract.js +0 -87
- package/lib/offline_verifiability_recovery_contract.js +0 -155
- package/lib/openapi_contract.js +0 -227
- package/lib/operational_receipt_contract.js +0 -165
- package/lib/outreach_proof.js +0 -71
- package/lib/phase_10_closeout_pack.js +0 -45
- package/lib/phase_10_completion_pack.js +0 -76
- package/lib/phase_10_decision_record_pack.js +0 -54
- package/lib/phase_10_decision_resolution_pack.js +0 -53
- package/lib/phase_10_demand_signal_adapters_proof_pack.js +0 -74
- package/lib/phase_10_ecosystem_backlog_triage_proof_pack.js +0 -74
- package/lib/phase_10_freeze_baseline_pack.js +0 -67
- package/lib/phase_10_freeze_review_pack.js +0 -64
- package/lib/phase_10_gate_pack.js +0 -57
- package/lib/phase_10_long_tail_continuity_pack.js +0 -80
- package/lib/phase_10_long_tail_ecosystem_pack.js +0 -68
- package/lib/phase_10_niche_extension_registry_proof_pack.js +0 -74
- package/lib/phase_1_claude_mcp_pack.js +0 -60
- package/lib/phase_1_claude_mcp_proof_pack.js +0 -57
- package/lib/phase_1_ecosystem_pack.js +0 -51
- package/lib/phase_1_openai_codex_pack.js +0 -60
- package/lib/phase_1_openai_codex_proof_pack.js +0 -57
- package/lib/phase_2_base_proof_pack.js +0 -71
- package/lib/phase_2_base_usdc_proof_pack.js +0 -72
- package/lib/phase_2_closeout_pack.js +0 -65
- package/lib/phase_2_completion_pack.js +0 -113
- package/lib/phase_2_decision_record_pack.js +0 -66
- package/lib/phase_2_decision_resolution_pack.js +0 -69
- package/lib/phase_2_eth_proof_pack.js +0 -70
- package/lib/phase_2_evm_base_proof_pack.js +0 -73
- package/lib/phase_2_evm_proof_pack.js +0 -71
- package/lib/phase_2_flip_preview_pack.js +0 -60
- package/lib/phase_2_freeze_review_pack.js +0 -99
- package/lib/phase_2_gate_pack.js +0 -77
- package/lib/phase_2_payment_rails_pack.js +0 -71
- package/lib/phase_2_usdc_proof_pack.js +0 -71
- package/lib/phase_3_brc_proof_pack.js +0 -81
- package/lib/phase_3_bsv_teranode_proof_pack.js +0 -81
- package/lib/phase_3_closeout_pack.js +0 -62
- package/lib/phase_3_completion_pack.js +0 -92
- package/lib/phase_3_decision_record_pack.js +0 -64
- package/lib/phase_3_decision_resolution_pack.js +0 -69
- package/lib/phase_3_freeze_baseline_pack.js +0 -67
- package/lib/phase_3_freeze_review_pack.js +0 -80
- package/lib/phase_3_gate_pack.js +0 -76
- package/lib/phase_3_metanet_proof_pack.js +0 -81
- package/lib/phase_3_native_bsv_pack.js +0 -89
- package/lib/phase_3_native_continuity_pack.js +0 -82
- package/lib/phase_4_attestation_proof_pack.js +0 -75
- package/lib/phase_4_closeout_pack.js +0 -45
- package/lib/phase_4_completion_pack.js +0 -82
- package/lib/phase_4_decision_record_pack.js +0 -54
- package/lib/phase_4_decision_resolution_pack.js +0 -45
- package/lib/phase_4_erc8004_proof_pack.js +0 -76
- package/lib/phase_4_freeze_baseline_pack.js +0 -67
- package/lib/phase_4_freeze_review_pack.js +0 -68
- package/lib/phase_4_gate_pack.js +0 -58
- package/lib/phase_4_identity_registry_proof_pack.js +0 -75
- package/lib/phase_4_identity_trust_pack.js +0 -73
- package/lib/phase_4_trust_continuity_pack.js +0 -86
- package/lib/phase_5_antelope_proof_pack.js +0 -76
- package/lib/phase_5_closeout_pack.js +0 -44
- package/lib/phase_5_completion_pack.js +0 -82
- package/lib/phase_5_decision_record_pack.js +0 -54
- package/lib/phase_5_decision_resolution_pack.js +0 -45
- package/lib/phase_5_freeze_baseline_pack.js +0 -67
- package/lib/phase_5_freeze_review_pack.js +0 -68
- package/lib/phase_5_gate_pack.js +0 -58
- package/lib/phase_5_major_rails_continuity_pack.js +0 -86
- package/lib/phase_5_major_rails_pack.js +0 -74
- package/lib/phase_5_proton_xpr_proof_pack.js +0 -76
- package/lib/phase_5_solana_proof_pack.js +0 -76
- package/lib/phase_6_autogen_proof_pack.js +0 -74
- package/lib/phase_6_closeout_pack.js +0 -46
- package/lib/phase_6_completion_pack.js +0 -77
- package/lib/phase_6_decision_record_pack.js +0 -54
- package/lib/phase_6_decision_resolution_pack.js +0 -53
- package/lib/phase_6_framework_continuity_pack.js +0 -81
- package/lib/phase_6_framework_runtime_pack.js +0 -68
- package/lib/phase_6_freeze_baseline_pack.js +0 -68
- package/lib/phase_6_freeze_review_pack.js +0 -65
- package/lib/phase_6_gate_pack.js +0 -59
- package/lib/phase_6_langchain_proof_pack.js +0 -74
- package/lib/phase_6_langgraph_proof_pack.js +0 -74
- package/lib/phase_6_semantic_kernel_proof_pack.js +0 -74
- package/lib/phase_7_closeout_pack.js +0 -45
- package/lib/phase_7_completion_pack.js +0 -85
- package/lib/phase_7_decision_record_pack.js +0 -53
- package/lib/phase_7_decision_resolution_pack.js +0 -53
- package/lib/phase_7_event_system_continuity_pack.js +0 -89
- package/lib/phase_7_event_system_pack.js +0 -76
- package/lib/phase_7_freeze_baseline_pack.js +0 -74
- package/lib/phase_7_freeze_review_pack.js +0 -65
- package/lib/phase_7_gate_pack.js +0 -58
- package/lib/phase_7_kafka_proof_pack.js +0 -76
- package/lib/phase_7_mqtt_proof_pack.js +0 -76
- package/lib/phase_7_nats_proof_pack.js +0 -76
- package/lib/phase_7_webhook_event_bus_proof_pack.js +0 -76
- package/lib/phase_8_closeout_pack.js +0 -46
- package/lib/phase_8_completion_pack.js +0 -82
- package/lib/phase_8_decision_record_pack.js +0 -54
- package/lib/phase_8_decision_resolution_pack.js +0 -53
- package/lib/phase_8_external_receipt_import_proof_pack.js +0 -74
- package/lib/phase_8_external_result_import_proof_pack.js +0 -74
- package/lib/phase_8_freeze_baseline_pack.js +0 -71
- package/lib/phase_8_freeze_review_pack.js +0 -64
- package/lib/phase_8_gate_pack.js +0 -58
- package/lib/phase_8_proof_bridge_continuity_pack.js +0 -86
- package/lib/phase_8_proof_bridges_pack.js +0 -72
- package/lib/phase_8_proof_bundle_normalization_proof_pack.js +0 -74
- package/lib/phase_9_closeout_pack.js +0 -46
- package/lib/phase_9_completion_pack.js +0 -82
- package/lib/phase_9_custody_refs_proof_pack.js +0 -74
- package/lib/phase_9_decision_record_pack.js +0 -54
- package/lib/phase_9_decision_resolution_pack.js +0 -53
- package/lib/phase_9_freeze_baseline_pack.js +0 -71
- package/lib/phase_9_freeze_review_pack.js +0 -64
- package/lib/phase_9_gate_pack.js +0 -58
- package/lib/phase_9_operator_accounting_bridges_proof_pack.js +0 -74
- package/lib/phase_9_treasury_connectivity_pack.js +0 -72
- package/lib/phase_9_treasury_continuity_pack.js +0 -86
- package/lib/phase_9_treasury_destinations_proof_pack.js +0 -74
- package/lib/phase_program_pack.js +0 -47
- package/lib/proof_bridge_lane_contract.js +0 -82
- package/lib/proof_truth_contract.js +0 -224
- package/lib/provenance_lane_contract.js +0 -54
- package/lib/provider_lane_contract.js +0 -67
- package/lib/public_surface_policy_contract.js +0 -111
- package/lib/publish_plan.js +0 -51
- package/lib/release_candidate.js +0 -50
- package/lib/release_center.js +0 -1037
- package/lib/release_history.js +0 -206
- package/lib/release_manifest.js +0 -114
- package/lib/release_pack.js +0 -391
- package/lib/result_package_trust_lane_contract.js +0 -74
- package/lib/review_intelligence.js +0 -100
- package/lib/role_freeze.js +0 -436
- package/lib/shared_signals_lane_contract.js +0 -54
- package/lib/signed_audit_provenance_contract.js +0 -93
- package/lib/telemetry_lane_contract.js +0 -54
- package/lib/treasury_proof_lane_contract.js +0 -83
- package/lib/trust_intelligence.js +0 -106
- package/lib/trust_portability_boundary_contract.js +0 -66
- package/lib/trust_portability_pack.js +0 -224
- package/lib/verification_service_pack.js +0 -149
- package/proof_sdk.js +0 -6692
- package/reference/python/README.md +0 -35
- package/reference/python/requirements-optional.txt +0 -1
- package/reference/python/verify_vectors.py +0 -223
- package/reference/python/xnya_reference.py +0 -810
- package/reference/rust/Cargo.toml +0 -11
- package/reference/rust/README.md +0 -28
- package/reference/rust/src/lib.rs +0 -87
- package/scripts/registry_cli.js +0 -157
- package/scripts/verify_all.js +0 -603
- package/scripts/verify_control_plane_contracts.js +0 -34
- package/scripts/verify_control_plane_routes.js +0 -70
- package/scripts/verify_examples.js +0 -19
- package/scripts/verify_external_proof_import_gate.js +0 -84
- package/scripts/verify_external_proof_signature.js +0 -142
- package/scripts/verify_forgery_resistance.js +0 -281
- package/scripts/verify_integrations.js +0 -170
- package/scripts/verify_native_hybrid_design_gate.js +0 -114
- package/scripts/verify_paid_execute.js +0 -133
- package/scripts/verify_paywall_flag.js +0 -86
- package/scripts/verify_reference_promotion_gate.js +0 -74
- package/scripts/verify_reference_python.js +0 -49
- package/scripts/verify_reference_python_crypto.js +0 -87
- package/scripts/verify_reference_rust_scaffold.js +0 -50
- package/scripts/verify_service.js +0 -3038
- package/scripts/verify_tooling.js +0 -1251
- package/scripts/verify_trust_portability.js +0 -56
- package/scripts/verify_verification_services.js +0 -56
- package/server.js +0 -4430
|
@@ -1,170 +1,412 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
// Conformance + adversarial vector run for the xoonya verifier.
|
|
4
|
+
//
|
|
5
|
+
// Runs on the standalone verifier (lib/native_verify.js + lib/external_proof_verify.js)
|
|
6
|
+
// with Node built-ins only, so it works identically from the published package and
|
|
7
|
+
// from the source checkout. When the proof engine is present next to this script
|
|
8
|
+
// (source checkout only; proof_sdk.js is never published), it additionally runs an
|
|
9
|
+
// engine-parity cross-check: every vector, every option variant, every freshly
|
|
10
|
+
// emitted bundle and every mutation is verified by BOTH the engine and the
|
|
11
|
+
// standalone verifier and the full result objects must be deep-equal.
|
|
12
|
+
|
|
3
13
|
const assert = require("assert");
|
|
14
|
+
const crypto = require("crypto");
|
|
4
15
|
const fs = require("fs");
|
|
5
16
|
const path = require("path");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
);
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const nv = require("../lib/native_verify");
|
|
18
|
+
const external = require("../lib/external_proof_verify");
|
|
19
|
+
|
|
20
|
+
const ROOT = path.resolve(__dirname, "..");
|
|
21
|
+
const ENGINE_FILE = path.join(ROOT, "proof_sdk.js");
|
|
22
|
+
const REQUIRED_NATIVE_METHODS = Object.freeze([
|
|
23
|
+
"xoonya-native-sha256-v1",
|
|
24
|
+
"xoonya-native-signed-v1",
|
|
25
|
+
"xoonya-native-anchored-v1"
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
function loadVectors(name) {
|
|
29
|
+
return JSON.parse(fs.readFileSync(path.join(ROOT, "vectors", name), "utf8"));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const conformanceVectors = loadVectors("conformance-vectors.json");
|
|
33
|
+
const adversarialVectors = loadVectors("adversarial-vectors.json");
|
|
34
|
+
const nativeAtomVectors = loadVectors("native-atom-vectors.json");
|
|
35
|
+
const nativePayloadProfileVectors = loadVectors("native-payload-profile-vectors.json");
|
|
17
36
|
|
|
18
37
|
function unique(values) {
|
|
19
38
|
return Array.from(new Set(values.filter(Boolean))).sort();
|
|
20
39
|
}
|
|
21
40
|
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
function clone(value) {
|
|
42
|
+
return JSON.parse(JSON.stringify(value));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function flipLastChar(text) {
|
|
46
|
+
const value = String(text || "");
|
|
47
|
+
if (!value) return "A";
|
|
48
|
+
const last = value[value.length - 1];
|
|
49
|
+
return `${value.slice(0, -1)}${last === "A" ? "B" : "A"}`;
|
|
50
|
+
}
|
|
26
51
|
|
|
27
|
-
|
|
52
|
+
function conformanceBundle(vector) {
|
|
53
|
+
return {
|
|
54
|
+
version: vector.expected.proof_bundle_version,
|
|
55
|
+
ceb: nv.canonicalizeEvent(vector.event),
|
|
56
|
+
receipt: vector.expected.receipt,
|
|
57
|
+
anchors: Array.isArray(vector.anchors) ? vector.anchors : undefined
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function atomOptions(vector, defaults) {
|
|
62
|
+
const hasPayload = vector.payload_ascii
|
|
63
|
+
? true
|
|
64
|
+
: vector.payload_hash_sha256 && vector.payload_hash_sha256 !== "00".repeat(32);
|
|
65
|
+
return {
|
|
66
|
+
identity_material_hex: vector.identity_material_hex || defaults.identity_material_hex,
|
|
67
|
+
...(hasPayload ? { payload_bytes: Buffer.from(vector.payload_ascii || defaults.payload_ascii, "utf8") } : {})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Option variants every conformance bundle is verified under (standalone and, in
|
|
72
|
+
// parity mode, engine). Trust-root variants must reject signed/hybrid proofs whose
|
|
73
|
+
// key is not the declared one and leave digest/structural results untouched.
|
|
74
|
+
function verificationOptionVariants(receipt) {
|
|
75
|
+
return [
|
|
76
|
+
{},
|
|
77
|
+
{ strict: true },
|
|
78
|
+
{ expected_public_key_ref: "ed25519-spki-sha256:" + "00".repeat(32) },
|
|
79
|
+
{ trusted_public_key_refs: { [receipt.agent_identity]: { classical: "none", pq: "none" } } }
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function verifyConformance() {
|
|
84
|
+
const results = [];
|
|
85
|
+
let strictModeChecks = 0;
|
|
28
86
|
for (const vector of conformanceVectors.vectors) {
|
|
29
|
-
|
|
30
|
-
|
|
87
|
+
assert.strictEqual(nv.hashEvent(vector.event), vector.expected.event_commitment, `${vector.id} event commitment mismatch`);
|
|
88
|
+
const bundle = conformanceBundle(vector);
|
|
89
|
+
const receipt = bundle.receipt;
|
|
90
|
+
assert.strictEqual(receipt.event_commitment, vector.expected.event_commitment, `${vector.id} receipt commitment mismatch`);
|
|
91
|
+
const verification = nv.verifyProofBundle(bundle);
|
|
92
|
+
assert.strictEqual(verification.valid, true, `${vector.id} proof bundle should verify (${verification.reason})`);
|
|
93
|
+
assert.strictEqual(verification.verification_method, receipt.algorithm, `${vector.id} verification method mismatch`);
|
|
94
|
+
assert.strictEqual(verification.receipt_id, receipt.receipt_id, `${vector.id} receipt id mismatch`);
|
|
31
95
|
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
assert.strictEqual(
|
|
35
|
-
assert.strictEqual(receipt.receipt_id, vector.expected.receipt.receipt_id, `${vector.id} hybrid receipt id mismatch`);
|
|
36
|
-
assert.strictEqual(receipt.agent_identity, vector.expected.receipt.agent_identity, `${vector.id} hybrid agent mismatch`);
|
|
37
|
-
assert.strictEqual(receipt.domain_id, vector.expected.receipt.domain_id, `${vector.id} hybrid domain mismatch`);
|
|
38
|
-
assert.strictEqual(receipt.sequence, vector.expected.receipt.sequence, `${vector.id} hybrid sequence mismatch`);
|
|
39
|
-
assert.strictEqual(receipt.event_commitment, vector.expected.receipt.event_commitment, `${vector.id} hybrid event commitment mismatch`);
|
|
40
|
-
assert.strictEqual(receipt.algorithm, vector.expected.receipt.algorithm, `${vector.id} hybrid algorithm mismatch`);
|
|
41
|
-
assert.strictEqual(receipt.native_proof.method, vector.expected.receipt.native_proof.method, `${vector.id} hybrid method mismatch`);
|
|
42
|
-
assert.strictEqual(receipt.native_proof.hybrid_suite, vector.expected.receipt.native_proof.hybrid_suite, `${vector.id} hybrid suite mismatch`);
|
|
43
|
-
assert.strictEqual(receipt.native_proof.identity_ref, vector.expected.receipt.native_proof.identity_ref, `${vector.id} hybrid identity ref mismatch`);
|
|
44
|
-
assert.strictEqual(receipt.native_proof.hybrid_public_key_ref, vector.expected.receipt.native_proof.hybrid_public_key_ref, `${vector.id} hybrid public key ref mismatch`);
|
|
45
|
-
assert.strictEqual(receipt.native_proof.classical_public_key_ref, vector.expected.receipt.native_proof.classical_public_key_ref, `${vector.id} hybrid classical key ref mismatch`);
|
|
46
|
-
assert.strictEqual(receipt.native_proof.pq_public_key_ref, vector.expected.receipt.native_proof.pq_public_key_ref, `${vector.id} hybrid pq key ref mismatch`);
|
|
47
|
-
assert.deepStrictEqual(receipt.native_proof.classical_public_key_material, vector.expected.receipt.native_proof.classical_public_key_material, `${vector.id} hybrid classical key material mismatch`);
|
|
48
|
-
assert.deepStrictEqual(receipt.native_proof.pq_public_key_material, vector.expected.receipt.native_proof.pq_public_key_material, `${vector.id} hybrid pq key material mismatch`);
|
|
49
|
-
assert.strictEqual(receipt.native_proof.proof_material.signing_material_sha256, vector.expected.receipt.native_proof.proof_material.signing_material_sha256, `${vector.id} hybrid signing material hash mismatch`);
|
|
50
|
-
assert.strictEqual(typeof receipt.native_proof.proof_material.classical_signature, "string", `${vector.id} hybrid classical signature missing`);
|
|
51
|
-
assert.strictEqual(receipt.native_proof.proof_material.classical_signature.length > 10, true, `${vector.id} hybrid classical signature too small`);
|
|
52
|
-
assert.strictEqual(typeof receipt.native_proof.proof_material.pq_signature, "string", `${vector.id} hybrid pq signature missing`);
|
|
53
|
-
assert.strictEqual(receipt.native_proof.proof_material.pq_signature.length > 100, true, `${vector.id} hybrid pq signature too small`);
|
|
54
|
-
assert.strictEqual(
|
|
55
|
-
receipt.signature,
|
|
56
|
-
`xoonya-native-hybrid-v1:${receipt.native_proof.hybrid_suite}:${receipt.native_proof.proof_material.classical_signature}.${receipt.native_proof.proof_material.pq_signature}`,
|
|
57
|
-
`${vector.id} hybrid compact signature mismatch`
|
|
58
|
-
);
|
|
96
|
+
const strict = nv.verifyProofBundle(bundle, { strict: true });
|
|
97
|
+
if (verification.cryptographically_verified) {
|
|
98
|
+
assert.strictEqual(strict.valid, true, `${vector.id} cryptographic method must pass strict mode`);
|
|
59
99
|
} else {
|
|
60
|
-
assert.
|
|
100
|
+
assert.strictEqual(strict.valid, false, `${vector.id} non-cryptographic method must fail strict mode`);
|
|
101
|
+
assert.strictEqual(nv.PROOF_VERIFICATION_STRICT_REJECTION_CODES.includes(strict.reason), true, `${vector.id} strict rejection code mismatch`);
|
|
61
102
|
}
|
|
103
|
+
strictModeChecks += 1;
|
|
62
104
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
const untrusted = nv.verifyProofBundle(bundle, { expected_public_key_ref: "ed25519-spki-sha256:" + "00".repeat(32) });
|
|
106
|
+
if (verification.cryptographically_verified) {
|
|
107
|
+
assert.strictEqual(untrusted.valid, false, `${vector.id} undeclared key must be rejected under a trust root`);
|
|
108
|
+
assert.strictEqual(nv.PROOF_VERIFICATION_TRUST_ROOT_REJECTION_CODES.includes(untrusted.reason), true, `${vector.id} trust root rejection code mismatch`);
|
|
109
|
+
} else {
|
|
110
|
+
assert.strictEqual(untrusted.valid, true, `${vector.id} trust root must not affect non-keyed methods`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
results.push({
|
|
72
114
|
id: vector.id,
|
|
73
115
|
verification_method: verification.verification_method,
|
|
74
|
-
verification_state: verification.verification_state
|
|
116
|
+
verification_state: verification.verification_state,
|
|
117
|
+
verification_class: verification.verification_class,
|
|
118
|
+
cryptographically_verified: verification.cryptographically_verified
|
|
75
119
|
});
|
|
76
120
|
}
|
|
121
|
+
return { results, strictModeChecks };
|
|
122
|
+
}
|
|
77
123
|
|
|
78
|
-
|
|
124
|
+
function verifyAdversarial() {
|
|
125
|
+
const results = [];
|
|
79
126
|
for (const vector of adversarialVectors.vectors) {
|
|
80
127
|
if (vector.kind === "canonicalize_event_error") {
|
|
81
128
|
assert.throws(
|
|
82
|
-
() =>
|
|
129
|
+
() => nv.canonicalizeEvent(vector.event),
|
|
83
130
|
(error) => error && error.message === vector.expected_reason,
|
|
84
131
|
`${vector.id} should throw expected reason`
|
|
85
132
|
);
|
|
86
|
-
|
|
87
|
-
id: vector.id,
|
|
88
|
-
kind: vector.kind,
|
|
89
|
-
reason: vector.expected_reason
|
|
90
|
-
});
|
|
133
|
+
results.push({ id: vector.id, kind: vector.kind, reason: vector.expected_reason });
|
|
91
134
|
continue;
|
|
92
135
|
}
|
|
93
136
|
if (vector.kind === "verify_bundle_reason") {
|
|
94
|
-
const result =
|
|
137
|
+
const result = nv.verifyProofBundle(vector.bundle);
|
|
95
138
|
assert.strictEqual(result.valid, false, `${vector.id} should fail`);
|
|
96
139
|
assert.strictEqual(result.reason, vector.expected_reason, `${vector.id} failure reason mismatch`);
|
|
97
|
-
|
|
98
|
-
id: vector.id,
|
|
99
|
-
kind: vector.kind,
|
|
100
|
-
reason: result.reason
|
|
101
|
-
});
|
|
140
|
+
results.push({ id: vector.id, kind: vector.kind, reason: result.reason });
|
|
102
141
|
continue;
|
|
103
142
|
}
|
|
104
143
|
throw new Error(`${vector.id} has unsupported vector kind`);
|
|
105
144
|
}
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
106
147
|
|
|
107
|
-
|
|
108
|
-
const
|
|
148
|
+
function verifyNativeAtoms() {
|
|
149
|
+
const results = [];
|
|
109
150
|
for (const vector of nativeAtomVectors.vectors) {
|
|
110
|
-
const parsed =
|
|
151
|
+
const parsed = nv.parsexoonyaNativeAtom(vector.atom_hex);
|
|
111
152
|
assert.strictEqual(parsed.atom_version, vector.atom_version, `${vector.id} atom version mismatch`);
|
|
112
153
|
assert.strictEqual(parsed.byte_length, vector.byte_length, `${vector.id} byte length mismatch`);
|
|
113
154
|
assert.strictEqual(parsed.agent_id, vector.agent_id, `${vector.id} agent id mismatch`);
|
|
114
155
|
assert.strictEqual(parsed.payload_hash_sha256, vector.payload_hash_sha256, `${vector.id} payload hash mismatch`);
|
|
115
|
-
const
|
|
116
|
-
const verification = sdk.verifyxoonyaNativeAtom(vector.atom_hex, {
|
|
117
|
-
identity_material_hex: nativeAtomVectors.identity_material_hex,
|
|
118
|
-
...(hasPayload ? { payload_bytes: nativeAtomPayload } : {})
|
|
119
|
-
});
|
|
156
|
+
const verification = nv.verifyxoonyaNativeAtom(vector.atom_hex, atomOptions(vector, nativeAtomVectors));
|
|
120
157
|
assert.strictEqual(verification.valid, true, `${vector.id} should verify`);
|
|
121
158
|
assert.strictEqual(verification.error_code, null, `${vector.id} should not have error code`);
|
|
122
|
-
|
|
123
|
-
id: vector.id,
|
|
124
|
-
atom_version: vector.atom_version,
|
|
125
|
-
byte_length: vector.byte_length
|
|
126
|
-
});
|
|
159
|
+
results.push({ id: vector.id, atom_version: vector.atom_version, byte_length: vector.byte_length });
|
|
127
160
|
}
|
|
128
|
-
|
|
129
|
-
const nativeAtomAdversarialResults = [];
|
|
161
|
+
const adversarial = [];
|
|
130
162
|
for (const vector of nativeAtomVectors.adversarial) {
|
|
131
|
-
const verification =
|
|
132
|
-
identity_material_hex: vector.identity_material_hex || nativeAtomVectors.identity_material_hex,
|
|
133
|
-
...(vector.payload_ascii ? { payload_bytes: Buffer.from(vector.payload_ascii, "utf8") } : {})
|
|
134
|
-
});
|
|
163
|
+
const verification = nv.verifyxoonyaNativeAtom(vector.atom_hex, atomOptions(vector, nativeAtomVectors));
|
|
135
164
|
assert.strictEqual(verification.valid, false, `${vector.id} should fail`);
|
|
136
165
|
assert.strictEqual(verification.reason, vector.expected_reason, `${vector.id} failure reason mismatch`);
|
|
137
166
|
assert.strictEqual(verification.error_code, vector.expected_error_code, `${vector.id} error code mismatch`);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
167
|
+
adversarial.push({ id: vector.id, reason: verification.reason, error_code: verification.error_code });
|
|
168
|
+
}
|
|
169
|
+
return { results, adversarial };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function verifyPayloadProfileAndFrame() {
|
|
173
|
+
const profileVector = nativePayloadProfileVectors.profile_vector;
|
|
174
|
+
const parsed = nv.parsexoonyaNativePayloadProfileV1(profileVector.expected.canonical_bytes_hex);
|
|
175
|
+
assert.strictEqual(parsed.payload_hash_sha256, profileVector.expected.payload_hash_sha256, `${profileVector.id} payload hash mismatch`);
|
|
176
|
+
assert.strictEqual(parsed.schema_hash_sha256, profileVector.expected.schema_hash_sha256, `${profileVector.id} schema hash mismatch`);
|
|
177
|
+
assert.deepStrictEqual(parsed.fields.map((field) => field.field_id), profileVector.expected.field_order, `${profileVector.id} field order mismatch`);
|
|
178
|
+
const profileVerification = nv.verifyxoonyaNativePayloadProfileV1(profileVector.expected.canonical_bytes_hex, {
|
|
179
|
+
payload_hash_sha256: profileVector.expected.payload_hash_sha256,
|
|
180
|
+
schema_ref: profileVector.input.schema_ref,
|
|
181
|
+
allowed_field_ids: profileVector.expected.field_order
|
|
182
|
+
});
|
|
183
|
+
assert.strictEqual(profileVerification.valid, true, `${profileVector.id} should verify`);
|
|
184
|
+
const unknownField = nv.verifyxoonyaNativePayloadProfileV1(profileVector.expected.canonical_bytes_hex, {
|
|
185
|
+
allowed_field_ids: profileVector.expected.field_order.slice(0, -1)
|
|
186
|
+
});
|
|
187
|
+
assert.strictEqual(unknownField.reason, "payload_profile_unknown_field", `${profileVector.id} unknown field policy mismatch`);
|
|
188
|
+
|
|
189
|
+
const frameVector = nativePayloadProfileVectors.line_rate_frame_vector;
|
|
190
|
+
const payloadBytes = Buffer.from(profileVector.expected.canonical_bytes_hex, "hex");
|
|
191
|
+
const frameVerification = nv.verifyxoonyaNativeLineRateFrameV1(frameVector.frame_hex, {
|
|
192
|
+
identity_material_hex: frameVector.identity_material_hex,
|
|
193
|
+
payload_bytes: payloadBytes
|
|
194
|
+
});
|
|
195
|
+
assert.strictEqual(frameVerification.valid, true, `${frameVector.id} should verify (${frameVerification.reason})`);
|
|
196
|
+
assert.strictEqual(frameVerification.parsed_frame.atom_hex, frameVector.atom_hex, `${frameVector.id} atom mismatch`);
|
|
197
|
+
assert.strictEqual(frameVerification.parsed_frame.checksum_hex, frameVector.checksum_hex, `${frameVector.id} checksum mismatch`);
|
|
198
|
+
assert.strictEqual(frameVerification.parsed_frame.frame_byte_length, frameVector.frame_byte_length, `${frameVector.id} frame length mismatch`);
|
|
199
|
+
const tamperedFrame = `${frameVector.frame_hex.slice(0, -1)}${frameVector.frame_hex.endsWith("0") ? "1" : "0"}`;
|
|
200
|
+
const tamperedVerification = nv.verifyxoonyaNativeLineRateFrameV1(tamperedFrame, {
|
|
201
|
+
identity_material_hex: frameVector.identity_material_hex,
|
|
202
|
+
payload_bytes: payloadBytes
|
|
203
|
+
});
|
|
204
|
+
assert.strictEqual(tamperedVerification.reason, "line_rate_frame_checksum_mismatch", `${frameVector.id} tamper reason mismatch`);
|
|
205
|
+
return {
|
|
206
|
+
profile_results: [{ id: profileVector.id, field_count: parsed.field_count }],
|
|
207
|
+
frame_results: [{ id: frameVector.id, frame_byte_length: frameVector.frame_byte_length }]
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Self-test of the detached-signature verifier with throwaway keys: Ed25519 and
|
|
212
|
+
// ML-DSA-65 (FIPS 204) signatures must verify, a flipped signature must not, and a
|
|
213
|
+
// declared trusted-key fingerprint must bind.
|
|
214
|
+
function verifyExternalSignatureSelfTest() {
|
|
215
|
+
const material = Buffer.from("xoonya-verifier-external-signature-self-test", "utf8");
|
|
216
|
+
const checks = {};
|
|
217
|
+
for (const [alg, keyType] of [["EdDSA", "ed25519"], ["ML-DSA-65", "ml-dsa-65"]]) {
|
|
218
|
+
const pair = crypto.generateKeyPairSync(keyType);
|
|
219
|
+
const signature = crypto.sign(null, material, pair.privateKey).toString("base64");
|
|
220
|
+
const publicKeyPem = pair.publicKey.export({ type: "spki", format: "pem" });
|
|
221
|
+
const ok = external.verifyDetachedSignature({ material, signature, public_key: publicKeyPem, algorithm: alg });
|
|
222
|
+
assert.strictEqual(ok.signature_valid, true, `${alg} detached signature should verify`);
|
|
223
|
+
assert.strictEqual(ok.expected_key_match, null, `${alg} no expectation declared`);
|
|
224
|
+
const anchored = external.verifyDetachedSignature({ material, signature, public_key: publicKeyPem, algorithm: alg, expected_key_ref: ok.signing_key_ref });
|
|
225
|
+
assert.strictEqual(anchored.trust_anchored, true, `${alg} declared key must anchor`);
|
|
226
|
+
const wrongKey = external.verifyDetachedSignature({ material, signature, public_key: publicKeyPem, algorithm: alg, expected_key_ref: "nope" });
|
|
227
|
+
assert.strictEqual(wrongKey.trust_anchored, false, `${alg} wrong declared key must not anchor`);
|
|
228
|
+
const tampered = external.verifyDetachedSignature({ material: Buffer.concat([material, Buffer.from("x")]), signature, public_key: publicKeyPem, algorithm: alg });
|
|
229
|
+
assert.strictEqual(tampered.signature_valid, false, `${alg} tampered material must fail`);
|
|
230
|
+
const privateRefused = external.toPublicKeyObject(pair.privateKey.export({ type: "pkcs8", format: "pem" }));
|
|
231
|
+
assert.strictEqual(privateRefused, null, `${alg} private key material must be refused`);
|
|
232
|
+
checks[alg] = true;
|
|
233
|
+
}
|
|
234
|
+
return checks;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Engine-parity cross-check (source checkout only).
|
|
238
|
+
function runEngineParity() {
|
|
239
|
+
// eslint-disable-next-line global-require
|
|
240
|
+
const engine = require(ENGINE_FILE);
|
|
241
|
+
let comparisons = 0;
|
|
242
|
+
const compare = (label, standalone, fromEngine) => {
|
|
243
|
+
assert.deepStrictEqual(standalone, fromEngine, `engine parity mismatch: ${label}`);
|
|
244
|
+
comparisons += 1;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
for (const vector of conformanceVectors.vectors) {
|
|
248
|
+
const bundle = conformanceBundle(vector);
|
|
249
|
+
compare(`${vector.id} hashEvent`, nv.hashEvent(vector.event), engine.hashEvent(vector.event));
|
|
250
|
+
compare(`${vector.id} canonicalizeEvent`, nv.canonicalizeEvent(vector.event), engine.canonicalizeEvent(vector.event));
|
|
251
|
+
for (const options of verificationOptionVariants(bundle.receipt)) {
|
|
252
|
+
compare(`${vector.id} ${JSON.stringify(options)}`, nv.verifyProofBundle(bundle, options), engine.verifyProofBundle(bundle, options));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Freshly emitted by the engine (new ML-DSA randomness for hybrid), verified by both.
|
|
256
|
+
const fresh = engine.buildProofBundle({
|
|
257
|
+
ceb: vector.event,
|
|
258
|
+
receipt_options: vector.receipt_options || {},
|
|
259
|
+
anchors: Array.isArray(vector.anchors) ? vector.anchors : undefined
|
|
142
260
|
});
|
|
261
|
+
const freshStandalone = nv.verifyProofBundle(fresh);
|
|
262
|
+
assert.strictEqual(freshStandalone.valid, true, `${vector.id} engine-emitted bundle must verify standalone (${freshStandalone.reason})`);
|
|
263
|
+
compare(`${vector.id} fresh engine bundle`, freshStandalone, engine.verifyProofBundle(fresh));
|
|
264
|
+
if (vector.expected.receipt.algorithm === "xoonya-native-hybrid-v1") {
|
|
265
|
+
const strip = (receipt) => {
|
|
266
|
+
const copy = clone(receipt);
|
|
267
|
+
delete copy.signature;
|
|
268
|
+
delete copy.native_proof.proof_material.classical_signature;
|
|
269
|
+
delete copy.native_proof.proof_material.pq_signature;
|
|
270
|
+
return copy;
|
|
271
|
+
};
|
|
272
|
+
compare(`${vector.id} fresh hybrid receipt (minus randomized signatures)`, strip(fresh.receipt), strip(vector.expected.receipt));
|
|
273
|
+
} else {
|
|
274
|
+
compare(`${vector.id} fresh receipt equals vector receipt`, fresh.receipt, vector.expected.receipt);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Mutations: both verifiers must reject identically.
|
|
278
|
+
const mutations = {
|
|
279
|
+
signature_flipped: (b) => { b.receipt.signature = flipLastChar(b.receipt.signature); },
|
|
280
|
+
sequence_replayed: (b) => { b.receipt.sequence = `${b.receipt.sequence}0`; },
|
|
281
|
+
algorithm_none: (b) => { b.receipt.algorithm = "none"; },
|
|
282
|
+
algorithm_unknown: (b) => { b.receipt.algorithm = "not-a-method"; },
|
|
283
|
+
agent_identity_swapped: (b) => { b.receipt.agent_identity = `${b.receipt.agent_identity}-other`; },
|
|
284
|
+
event_hash_swapped: (b) => { b.ceb.event_hash = "ff".repeat(32); },
|
|
285
|
+
native_proof_dropped: (b) => { delete b.receipt.native_proof; },
|
|
286
|
+
anchors_dropped: (b) => { delete b.anchors; },
|
|
287
|
+
downgrade_to_digest: (b) => { b.receipt.algorithm = "xoonya-native-sha256-v1"; },
|
|
288
|
+
bundle_version_bad: (b) => { b.version = "proof-bundle/v0"; }
|
|
289
|
+
};
|
|
290
|
+
for (const [name, mutate] of Object.entries(mutations)) {
|
|
291
|
+
const mutated = clone(bundle);
|
|
292
|
+
mutate(mutated);
|
|
293
|
+
compare(`${vector.id} mutation ${name}`, nv.verifyProofBundle(mutated), engine.verifyProofBundle(mutated));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
for (const vector of adversarialVectors.vectors) {
|
|
298
|
+
if (vector.kind === "canonicalize_event_error") {
|
|
299
|
+
let standaloneMessage = null;
|
|
300
|
+
let engineMessage = null;
|
|
301
|
+
try { nv.canonicalizeEvent(vector.event); } catch (error) { standaloneMessage = error.message; }
|
|
302
|
+
try { engine.canonicalizeEvent(vector.event); } catch (error) { engineMessage = error.message; }
|
|
303
|
+
compare(`${vector.id} canonicalize error`, standaloneMessage, engineMessage);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
for (const options of verificationOptionVariants(vector.bundle.receipt || {})) {
|
|
307
|
+
compare(`${vector.id} ${JSON.stringify(options)}`, nv.verifyProofBundle(vector.bundle, options), engine.verifyProofBundle(vector.bundle, options));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
for (const vector of [...nativeAtomVectors.vectors, ...nativeAtomVectors.adversarial]) {
|
|
312
|
+
const options = atomOptions(vector, nativeAtomVectors);
|
|
313
|
+
compare(`${vector.id} atom verify`, nv.verifyxoonyaNativeAtom(vector.atom_hex, options), engine.verifyxoonyaNativeAtom(vector.atom_hex, options));
|
|
314
|
+
let standaloneParsed;
|
|
315
|
+
let engineParsed;
|
|
316
|
+
try { standaloneParsed = nv.parsexoonyaNativeAtom(vector.atom_hex); } catch (error) { standaloneParsed = { error: error.message, code: error.code }; }
|
|
317
|
+
try { engineParsed = engine.parsexoonyaNativeAtom(vector.atom_hex); } catch (error) { engineParsed = { error: error.message, code: error.code }; }
|
|
318
|
+
compare(`${vector.id} atom parse`, standaloneParsed, engineParsed);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const profileHex = nativePayloadProfileVectors.profile_vector.expected.canonical_bytes_hex;
|
|
322
|
+
compare("payload profile parse", nv.parsexoonyaNativePayloadProfileV1(profileHex), engine.parsexoonyaNativePayloadProfileV1(profileHex));
|
|
323
|
+
const frameVector = nativePayloadProfileVectors.line_rate_frame_vector;
|
|
324
|
+
const frameOptions = { identity_material_hex: frameVector.identity_material_hex, payload_bytes: Buffer.from(profileHex, "hex") };
|
|
325
|
+
compare("line-rate frame verify", nv.verifyxoonyaNativeLineRateFrameV1(frameVector.frame_hex, frameOptions), engine.verifyxoonyaNativeLineRateFrameV1(frameVector.frame_hex, frameOptions));
|
|
326
|
+
|
|
327
|
+
// Compatibility receipt verifiers share bytes with the legacy-opreturn vector.
|
|
328
|
+
const legacy = conformanceVectors.vectors.find((vector) => vector.expected.receipt.algorithm === "legacy-opreturn-v1");
|
|
329
|
+
if (legacy) {
|
|
330
|
+
const opreturnHex = legacy.expected.receipt.compatibility.legacy_receipt.opreturn_hex;
|
|
331
|
+
const payload = Buffer.from(nv.canonicalize(nv.canonicalizeEvent(legacy.event)), "utf8");
|
|
332
|
+
compare("legacy receipt verify", nv.verifyReceipt(opreturnHex, payload), engine.verifyReceipt(opreturnHex, payload));
|
|
333
|
+
compare("legacy receipt parse", nv.parseReceipt(opreturnHex), engine.parseReceipt(opreturnHex));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
compare("verification method registry", nv.listProofVerificationMethods(), engine.listProofVerificationMethods());
|
|
337
|
+
compare("verification class registry", nv.listProofVerificationClasses(), engine.listProofVerificationClasses());
|
|
338
|
+
compare("native signature suite registry", nv.listNativeSignatureSuites(), engine.listNativeSignatureSuites());
|
|
339
|
+
compare("native identity type registry", nv.listxoonyaNativeIdentityTypes(), engine.listxoonyaNativeIdentityTypes());
|
|
340
|
+
|
|
341
|
+
return { checked: true, engine_file: path.basename(ENGINE_FILE), comparisons };
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function runVectorVerification(options = {}) {
|
|
345
|
+
assert.strictEqual(conformanceVectors.version, "proof-conformance-v1", "conformance vector version mismatch");
|
|
346
|
+
assert.strictEqual(adversarialVectors.version, "proof-adversarial-v1", "adversarial vector version mismatch");
|
|
347
|
+
assert.strictEqual(nativeAtomVectors.version, "xoonya-native-atom-vectors-v1", "native atom vector version mismatch");
|
|
348
|
+
assert.strictEqual(nativePayloadProfileVectors.version, "xoonya-native-payload-profile-vectors-v1", "native payload profile vector version mismatch");
|
|
349
|
+
|
|
350
|
+
const conformance = verifyConformance();
|
|
351
|
+
const adversarialResults = verifyAdversarial();
|
|
352
|
+
const atoms = verifyNativeAtoms();
|
|
353
|
+
const profileAndFrame = verifyPayloadProfileAndFrame();
|
|
354
|
+
const externalSignatureChecks = verifyExternalSignatureSelfTest();
|
|
355
|
+
|
|
356
|
+
const verificationMethods = unique(conformance.results.map((result) => result.verification_method));
|
|
357
|
+
for (const method of REQUIRED_NATIVE_METHODS) {
|
|
358
|
+
assert.strictEqual(verificationMethods.includes(method), true, `required native method missing: ${method}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const enginePresent = fs.existsSync(ENGINE_FILE);
|
|
362
|
+
let engineParity;
|
|
363
|
+
if (options.engine_parity === false) {
|
|
364
|
+
engineParity = { checked: false, reason: "disabled" };
|
|
365
|
+
} else if (enginePresent) {
|
|
366
|
+
engineParity = runEngineParity();
|
|
367
|
+
} else {
|
|
368
|
+
engineParity = { checked: false, reason: "engine_not_present" };
|
|
369
|
+
}
|
|
370
|
+
if (options.require_engine_parity === true) {
|
|
371
|
+
assert.strictEqual(engineParity.checked, true, "engine parity check required but not run");
|
|
143
372
|
}
|
|
144
373
|
|
|
145
374
|
return {
|
|
146
375
|
ok: true,
|
|
147
376
|
product: "xoonya",
|
|
377
|
+
role: "verifier",
|
|
148
378
|
suite: "proof-conformance-and-adversarial-vectors",
|
|
149
379
|
conformance_version: conformanceVectors.version,
|
|
150
380
|
adversarial_version: adversarialVectors.version,
|
|
151
|
-
|
|
381
|
+
native_atom_version: nativeAtomVectors.version,
|
|
382
|
+
native_payload_profile_version: nativePayloadProfileVectors.version,
|
|
383
|
+
conformance_count: conformance.results.length,
|
|
152
384
|
adversarial_count: adversarialResults.length,
|
|
153
|
-
native_atom_vector_count:
|
|
154
|
-
native_atom_adversarial_count:
|
|
155
|
-
|
|
385
|
+
native_atom_vector_count: atoms.results.length,
|
|
386
|
+
native_atom_adversarial_count: atoms.adversarial.length,
|
|
387
|
+
native_payload_profile_vector_count: profileAndFrame.profile_results.length,
|
|
388
|
+
line_rate_frame_vector_count: profileAndFrame.frame_results.length,
|
|
389
|
+
strict_mode_checks: conformance.strictModeChecks,
|
|
390
|
+
verification_methods: verificationMethods,
|
|
391
|
+
required_native_methods_present: REQUIRED_NATIVE_METHODS.every((method) => verificationMethods.includes(method)),
|
|
156
392
|
adversarial_reasons: unique(adversarialResults.map((result) => result.reason)),
|
|
157
|
-
native_atom_error_codes: unique(
|
|
158
|
-
|
|
393
|
+
native_atom_error_codes: unique(atoms.adversarial.map((result) => result.error_code)),
|
|
394
|
+
external_signature_checks: externalSignatureChecks,
|
|
395
|
+
engine_parity: engineParity,
|
|
396
|
+
conformance_results: conformance.results,
|
|
159
397
|
adversarial_results: adversarialResults,
|
|
160
|
-
native_atom_results:
|
|
161
|
-
native_atom_adversarial_results:
|
|
398
|
+
native_atom_results: atoms.results,
|
|
399
|
+
native_atom_adversarial_results: atoms.adversarial
|
|
162
400
|
};
|
|
163
401
|
}
|
|
164
402
|
|
|
165
403
|
function main() {
|
|
166
|
-
const
|
|
167
|
-
const
|
|
404
|
+
const argv = process.argv.slice(2);
|
|
405
|
+
const json = argv.includes("--json");
|
|
406
|
+
const summary = runVectorVerification({
|
|
407
|
+
engine_parity: argv.includes("--no-engine-parity") ? false : undefined,
|
|
408
|
+
require_engine_parity: argv.includes("--require-engine-parity")
|
|
409
|
+
});
|
|
168
410
|
if (json) {
|
|
169
411
|
process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
170
412
|
return;
|
|
@@ -176,9 +418,13 @@ function main() {
|
|
|
176
418
|
`adversarial vectors: ${summary.adversarial_count}`,
|
|
177
419
|
`native atom vectors: ${summary.native_atom_vector_count}`,
|
|
178
420
|
`native atom adversarial vectors: ${summary.native_atom_adversarial_count}`,
|
|
421
|
+
`native payload profile vectors: ${summary.native_payload_profile_vector_count}`,
|
|
422
|
+
`line-rate frame vectors: ${summary.line_rate_frame_vector_count}`,
|
|
179
423
|
`verification methods: ${summary.verification_methods.join(", ")}`,
|
|
180
424
|
`adversarial reasons: ${summary.adversarial_reasons.join(", ")}`,
|
|
181
|
-
`native atom error codes: ${summary.native_atom_error_codes.join(", ")}
|
|
425
|
+
`native atom error codes: ${summary.native_atom_error_codes.join(", ")}`,
|
|
426
|
+
`external signature checks: ${Object.keys(summary.external_signature_checks).join(", ")}`,
|
|
427
|
+
`engine parity: ${summary.engine_parity.checked ? `${summary.engine_parity.comparisons} comparisons identical` : summary.engine_parity.reason}`
|
|
182
428
|
].join("\n") + "\n"
|
|
183
429
|
);
|
|
184
430
|
}
|
|
@@ -188,5 +434,6 @@ if (require.main === module) {
|
|
|
188
434
|
}
|
|
189
435
|
|
|
190
436
|
module.exports = {
|
|
191
|
-
runVectorVerification
|
|
437
|
+
runVectorVerification,
|
|
438
|
+
REQUIRED_NATIVE_METHODS
|
|
192
439
|
};
|
package/verify.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// xoonya verifier package entry.
|
|
4
|
+
//
|
|
5
|
+
// This package verifies xoonya proofs and naxytra delivery evidence. It carries
|
|
6
|
+
// the verifier only: the proof engine (receipt emission, signing, review,
|
|
7
|
+
// governance, bridges) and the server are a hosted service and are not
|
|
8
|
+
// distributed. Everything here runs on Node built-ins.
|
|
9
|
+
|
|
10
|
+
const nativeVerify = require("./lib/native_verify");
|
|
11
|
+
const externalProofVerify = require("./lib/external_proof_verify");
|
|
12
|
+
const packageJson = require("./package.json");
|
|
13
|
+
|
|
14
|
+
const endpoints = Object.freeze({
|
|
15
|
+
hosted_service: "https://xoonya.onrender.com",
|
|
16
|
+
website: "https://www.naxytra.com",
|
|
17
|
+
product: "https://www.naxytra.com/xoonya",
|
|
18
|
+
agents: "https://www.naxytra.com/agents",
|
|
19
|
+
first_run_kit: "https://www.naxytra.com/v1/first-run-kit"
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function normalizeString(value) {
|
|
23
|
+
return String(value == null ? "" : value).trim();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Verify an external (non-native) signature: a compact JWS, or a detached
|
|
27
|
+
// signature over supplied material. Mirrors the hosted service's
|
|
28
|
+
// proof.verify-signature lane. Reports what can be established from the request
|
|
29
|
+
// alone (signature_valid under signing_key_ref); trust in that key is yours to
|
|
30
|
+
// declare through expected_key_ref.
|
|
31
|
+
function verifyExternalProofSignature(input) {
|
|
32
|
+
const body = input && typeof input === "object" && !Array.isArray(input) ? input : {};
|
|
33
|
+
const sv = body.signature_verification && typeof body.signature_verification === "object" ? body.signature_verification : body;
|
|
34
|
+
const jws = normalizeString(sv.jws || sv.compact_jws);
|
|
35
|
+
if (jws) {
|
|
36
|
+
return {
|
|
37
|
+
ok: true,
|
|
38
|
+
product: "xoonya",
|
|
39
|
+
category: "xoonya-external-proof-signature-verification",
|
|
40
|
+
method: "jws",
|
|
41
|
+
...externalProofVerify.verifyJws(jws, {
|
|
42
|
+
trusted_public_key: sv.trusted_public_key || sv.public_key || null,
|
|
43
|
+
expected_key_ref: sv.expected_key_ref
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (sv.signature) {
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
product: "xoonya",
|
|
51
|
+
category: "xoonya-external-proof-signature-verification",
|
|
52
|
+
method: "detached",
|
|
53
|
+
...externalProofVerify.verifyDetachedSignature({
|
|
54
|
+
material: sv.material !== undefined ? sv.material : body.material,
|
|
55
|
+
signature: sv.signature,
|
|
56
|
+
signature_encoding: sv.signature_encoding,
|
|
57
|
+
public_key: sv.public_key || sv.trusted_public_key,
|
|
58
|
+
algorithm: sv.algorithm,
|
|
59
|
+
expected_key_ref: sv.expected_key_ref
|
|
60
|
+
})
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
product: "xoonya",
|
|
66
|
+
category: "xoonya-external-proof-signature-verification",
|
|
67
|
+
reason: "no_signature_verification_input"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Run the shipped conformance + adversarial vectors through this verifier and
|
|
72
|
+
// return the summary (ok, counts, verification_methods, ...).
|
|
73
|
+
function verifyVectors(options) {
|
|
74
|
+
// eslint-disable-next-line global-require
|
|
75
|
+
return require("./scripts/verify_vectors").runVectorVerification(options || {});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
name: packageJson.name,
|
|
80
|
+
version: packageJson.version,
|
|
81
|
+
role: "verifier",
|
|
82
|
+
endpoints,
|
|
83
|
+
|
|
84
|
+
// Native proof bundles, receipts, atoms, payload profiles, line-rate frames.
|
|
85
|
+
...nativeVerify,
|
|
86
|
+
|
|
87
|
+
// External signatures (compact JWS and detached; Ed25519, ECDSA, RSA, ML-DSA-44/65/87).
|
|
88
|
+
verifyJws: externalProofVerify.verifyJws,
|
|
89
|
+
verifyDetachedSignature: externalProofVerify.verifyDetachedSignature,
|
|
90
|
+
verifyExternalProofSignature,
|
|
91
|
+
toPublicKeyObject: externalProofVerify.toPublicKeyObject,
|
|
92
|
+
looksLikeCompactJws: externalProofVerify.looksLikeCompactJws,
|
|
93
|
+
|
|
94
|
+
verifyVectors
|
|
95
|
+
};
|
package/.env.example
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
XOONYA_HOST=127.0.0.1
|
|
2
|
-
XOONYA_PORT=4310
|
|
3
|
-
# Set to 1 to make every proof-bundle verification strict: only cryptographically verified
|
|
4
|
-
# (native signed / native hybrid) results are valid; digest and structural results are rejected.
|
|
5
|
-
# XOONYA_STRICT_VERIFY=1
|
|
6
|
-
# Whether POST /v1/receipts/emit, /v1/proof-bundles/build, and the proof-center run routes may
|
|
7
|
-
# receive private key material (private_key_pem, classical_private_key_pem, pq_private_key_pem).
|
|
8
|
-
# Unset = accepted locally, rejected when RENDER is set. Set to false on any shared deployment
|
|
9
|
-
# and sign locally with the xoonya SDK or CLI instead.
|
|
10
|
-
# XOONYA_ACCEPT_PRIVATE_KEY_MATERIAL=false
|