xoonya 2.15.0 → 3.0.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 +44 -19
- package/RELEASE_NOTES.md +8 -8
- package/START_HERE.md +21 -21
- package/XNYA_REFERENCE_IMPLEMENTATIONS.md +3 -3
- package/XOONYA_NATIVE_PROOF_FORMAT.md +27 -4
- package/package.json +2 -2
- package/proof_sdk.js +351 -19
- package/reference/python/verify_vectors.py +14 -0
- package/reference/python/xnya_reference.py +1 -1
- package/scripts/verify_all.js +18 -8
- package/scripts/verify_native_hybrid_design_gate.js +40 -34
- package/scripts/verify_release_candidate.js +4 -3
- package/scripts/verify_service.js +4 -4
- package/scripts/verify_vectors.js +29 -1
- package/vectors/adversarial-vectors.json +96 -27
- package/vectors/conformance-vectors.json +58 -0
package/proof_sdk.js
CHANGED
|
@@ -124,13 +124,15 @@ const NATIVE_SIGNATURE_SUITES = Object.freeze({
|
|
|
124
124
|
id: "ed25519",
|
|
125
125
|
maturity: "implemented",
|
|
126
126
|
public_key_format: "spki-pem",
|
|
127
|
-
verification_posture: "native_verified"
|
|
127
|
+
verification_posture: "native_verified",
|
|
128
|
+
key_type: "ed25519"
|
|
128
129
|
}),
|
|
129
130
|
secp256k1: Object.freeze({
|
|
130
131
|
id: "secp256k1",
|
|
131
132
|
maturity: "implemented",
|
|
132
133
|
public_key_format: "spki-pem",
|
|
133
134
|
verification_posture: "native_verified",
|
|
135
|
+
key_type: "ec",
|
|
134
136
|
curve: "secp256k1",
|
|
135
137
|
signing_hash: "sha256"
|
|
136
138
|
}),
|
|
@@ -139,6 +141,7 @@ const NATIVE_SIGNATURE_SUITES = Object.freeze({
|
|
|
139
141
|
maturity: "implemented",
|
|
140
142
|
public_key_format: "spki-pem",
|
|
141
143
|
verification_posture: "native_verified",
|
|
144
|
+
key_type: "ec",
|
|
142
145
|
curve: "prime256v1",
|
|
143
146
|
signing_hash: "sha256"
|
|
144
147
|
}),
|
|
@@ -165,6 +168,20 @@ const NATIVE_SIGNATURE_SUITES = Object.freeze({
|
|
|
165
168
|
maturity: "planned_pqc",
|
|
166
169
|
public_key_format: "suite_defined",
|
|
167
170
|
verification_posture: "registry_declared_not_yet_verified"
|
|
171
|
+
}),
|
|
172
|
+
"ml-dsa-65": Object.freeze({
|
|
173
|
+
id: "ml-dsa-65",
|
|
174
|
+
maturity: "implemented",
|
|
175
|
+
public_key_format: "spki-pem",
|
|
176
|
+
verification_posture: "native_verified",
|
|
177
|
+
key_type: "ml-dsa-65"
|
|
178
|
+
}),
|
|
179
|
+
"slh-dsa-sha2-128f": Object.freeze({
|
|
180
|
+
id: "slh-dsa-sha2-128f",
|
|
181
|
+
maturity: "implemented",
|
|
182
|
+
public_key_format: "spki-pem",
|
|
183
|
+
verification_posture: "native_verified",
|
|
184
|
+
key_type: "slh-dsa-sha2-128f"
|
|
168
185
|
})
|
|
169
186
|
});
|
|
170
187
|
const XOONYA_NATIVE_IDENTITY_TYPES = Object.freeze({
|
|
@@ -642,6 +659,60 @@ function getNativeSignatureSuite(suiteId) {
|
|
|
642
659
|
return suite ? { ...suite } : null;
|
|
643
660
|
}
|
|
644
661
|
|
|
662
|
+
function listImplementedClassicalNativeSignatureSuites() {
|
|
663
|
+
return listNativeSignatureSuites().filter((suite) => suite.maturity === "implemented" && !suite.id.startsWith("ml-dsa-") && !suite.id.startsWith("slh-dsa-"));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function listImplementedPqNativeSignatureSuites() {
|
|
667
|
+
return listNativeSignatureSuites().filter((suite) => suite.maturity === "implemented" && (suite.id.startsWith("ml-dsa-") || suite.id.startsWith("slh-dsa-")));
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function buildNativeHybridSuiteId(classicalSuiteId, pqSuiteId) {
|
|
671
|
+
const classicalSuite = getNativeSignatureSuite(classicalSuiteId);
|
|
672
|
+
if (!classicalSuite || classicalSuite.maturity !== "implemented") {
|
|
673
|
+
throw new Error("native hybrid classical signature suite not implemented");
|
|
674
|
+
}
|
|
675
|
+
if (classicalSuite.id.startsWith("ml-dsa-") || classicalSuite.id.startsWith("slh-dsa-")) {
|
|
676
|
+
throw new Error("native hybrid classical signature suite must be classical");
|
|
677
|
+
}
|
|
678
|
+
const pqSuite = getNativeSignatureSuite(pqSuiteId);
|
|
679
|
+
if (!pqSuite || pqSuite.maturity !== "implemented") {
|
|
680
|
+
throw new Error("native hybrid pq signature suite not implemented");
|
|
681
|
+
}
|
|
682
|
+
if (!pqSuite.id.startsWith("ml-dsa-") && !pqSuite.id.startsWith("slh-dsa-")) {
|
|
683
|
+
throw new Error("native hybrid pq signature suite must be pq");
|
|
684
|
+
}
|
|
685
|
+
return `${classicalSuite.id}+${pqSuite.id}`;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function parseNativeHybridSuite(hybridSuiteId) {
|
|
689
|
+
const normalized = normalizeString(hybridSuiteId);
|
|
690
|
+
const [classicalSuiteId, pqSuiteId, extra] = normalized.split("+");
|
|
691
|
+
if (!classicalSuiteId || !pqSuiteId || extra) {
|
|
692
|
+
throw new Error("native hybrid signature suite unsupported");
|
|
693
|
+
}
|
|
694
|
+
return {
|
|
695
|
+
id: buildNativeHybridSuiteId(classicalSuiteId, pqSuiteId),
|
|
696
|
+
classical_suite: getNativeSignatureSuite(classicalSuiteId),
|
|
697
|
+
pq_suite: getNativeSignatureSuite(pqSuiteId)
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function listImplementedNativeHybridSuites() {
|
|
702
|
+
const suites = [];
|
|
703
|
+
for (const classicalSuite of listImplementedClassicalNativeSignatureSuites()) {
|
|
704
|
+
for (const pqSuite of listImplementedPqNativeSignatureSuites()) {
|
|
705
|
+
suites.push({
|
|
706
|
+
id: buildNativeHybridSuiteId(classicalSuite.id, pqSuite.id),
|
|
707
|
+
classical_suite: classicalSuite.id,
|
|
708
|
+
pq_suite: pqSuite.id,
|
|
709
|
+
posture: "dual_signature_verified"
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return suites;
|
|
714
|
+
}
|
|
715
|
+
|
|
645
716
|
function listxoonyaNativeIdentityTypes() {
|
|
646
717
|
return Object.values(XOONYA_NATIVE_IDENTITY_TYPES).map((entry) => ({ ...entry }));
|
|
647
718
|
}
|
|
@@ -708,11 +779,21 @@ function nativePublicKeyRefFromPem(publicKeyPem, signatureSuite = "ed25519") {
|
|
|
708
779
|
return `${suite.id}-spki-sha256:${sha256Hex(der)}`;
|
|
709
780
|
}
|
|
710
781
|
|
|
782
|
+
function nativeHybridPublicKeyRefFromPems(classicalPublicKeyPem, pqPublicKeyPem, hybridSuiteId) {
|
|
783
|
+
parseNativeHybridSuite(hybridSuiteId);
|
|
784
|
+
const classicalDer = crypto.createPublicKey(normalizePublicKeyPem(classicalPublicKeyPem)).export({ type: "spki", format: "der" });
|
|
785
|
+
const pqDer = crypto.createPublicKey(normalizePublicKeyPem(pqPublicKeyPem)).export({ type: "spki", format: "der" });
|
|
786
|
+
return `${hybridSuiteId}-hybrid-spki-sha256:${sha256Hex(Buffer.concat([classicalDer, pqDer]))}`;
|
|
787
|
+
}
|
|
788
|
+
|
|
711
789
|
function nativeSigningHashForSuite(suite) {
|
|
712
790
|
return suite && suite.signing_hash ? suite.signing_hash : null;
|
|
713
791
|
}
|
|
714
792
|
|
|
715
793
|
function assertNativeKeyMatchesSuite(keyObject, suite, label) {
|
|
794
|
+
if (suite && suite.key_type && keyObject.asymmetricKeyType !== suite.key_type) {
|
|
795
|
+
throw new Error(`${label} key type must be ${suite.key_type}`);
|
|
796
|
+
}
|
|
716
797
|
if (suite && suite.curve) {
|
|
717
798
|
const details = keyObject.asymmetricKeyDetails || {};
|
|
718
799
|
if (details.namedCurve !== suite.curve) {
|
|
@@ -779,6 +860,132 @@ function buildNativeSignedReceiptProof(receipt, canonicalEvent, options = {}) {
|
|
|
779
860
|
};
|
|
780
861
|
}
|
|
781
862
|
|
|
863
|
+
function buildNativeHybridProofMaterial(receipt, canonicalEvent, proofDescriptor) {
|
|
864
|
+
return {
|
|
865
|
+
identity_ref: proofDescriptor.identity_ref,
|
|
866
|
+
method: XOONYA_NATIVE_HYBRID_METHOD,
|
|
867
|
+
hybrid_suite: proofDescriptor.hybrid_suite,
|
|
868
|
+
hybrid_public_key_ref: proofDescriptor.hybrid_public_key_ref,
|
|
869
|
+
classical_public_key_ref: proofDescriptor.classical_public_key_ref,
|
|
870
|
+
pq_public_key_ref: proofDescriptor.pq_public_key_ref,
|
|
871
|
+
receipt_signing_material: buildCanonicalReceiptSigningMaterial(receipt),
|
|
872
|
+
event_commitment: hashEvent(canonicalEvent),
|
|
873
|
+
standard_version: XOONYA_NATIVE_PROOF_FORMAT_VERSION
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function runtimeSupportsNativeHybridSuite(hybridSuiteId) {
|
|
878
|
+
try {
|
|
879
|
+
const hybridSuite = parseNativeHybridSuite(hybridSuiteId);
|
|
880
|
+
const classicalPair = hybridSuite.classical_suite.id === "secp256k1"
|
|
881
|
+
? crypto.generateKeyPairSync("ec", { namedCurve: "secp256k1" })
|
|
882
|
+
: hybridSuite.classical_suite.id === "p256"
|
|
883
|
+
? crypto.generateKeyPairSync("ec", { namedCurve: "P-256" })
|
|
884
|
+
: crypto.generateKeyPairSync(hybridSuite.classical_suite.key_type);
|
|
885
|
+
const pqPair = crypto.generateKeyPairSync(hybridSuite.pq_suite.key_type);
|
|
886
|
+
const probe = Buffer.from(`xoonya-hybrid-runtime-probe:${hybridSuiteId}`, "utf8");
|
|
887
|
+
const classicalSignature = crypto.sign(nativeSigningHashForSuite(hybridSuite.classical_suite), probe, classicalPair.privateKey);
|
|
888
|
+
const pqSignature = crypto.sign(nativeSigningHashForSuite(hybridSuite.pq_suite), probe, pqPair.privateKey);
|
|
889
|
+
return (
|
|
890
|
+
crypto.verify(nativeSigningHashForSuite(hybridSuite.classical_suite), probe, classicalPair.publicKey, classicalSignature) &&
|
|
891
|
+
crypto.verify(nativeSigningHashForSuite(hybridSuite.pq_suite), probe, pqPair.publicKey, pqSignature)
|
|
892
|
+
);
|
|
893
|
+
} catch (_error) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function buildNativeHybridReceiptProof(receipt, canonicalEvent, options = {}) {
|
|
899
|
+
const classicalSignatureSuite = normalizeString(
|
|
900
|
+
options.classical_signature_suite ||
|
|
901
|
+
options.hybrid_classical_signature_suite ||
|
|
902
|
+
options.native_classical_signature_suite ||
|
|
903
|
+
"ed25519"
|
|
904
|
+
);
|
|
905
|
+
const pqSignatureSuite = normalizeString(
|
|
906
|
+
options.pq_signature_suite ||
|
|
907
|
+
options.hybrid_pq_signature_suite ||
|
|
908
|
+
options.native_pq_signature_suite ||
|
|
909
|
+
"ml-dsa-65"
|
|
910
|
+
);
|
|
911
|
+
const hybridSuite = parseNativeHybridSuite(buildNativeHybridSuiteId(classicalSignatureSuite, pqSignatureSuite));
|
|
912
|
+
if (!runtimeSupportsNativeHybridSuite(hybridSuite.id)) {
|
|
913
|
+
throw new Error("native hybrid runtime validator unavailable");
|
|
914
|
+
}
|
|
915
|
+
const classicalPublicKeyPem = normalizePublicKeyPem(
|
|
916
|
+
options.classical_public_key_pem ||
|
|
917
|
+
options.hybrid_classical_public_key_pem ||
|
|
918
|
+
options.native_classical_public_key_pem
|
|
919
|
+
);
|
|
920
|
+
const classicalPrivateKeyPem = normalizePrivateKeyPem(
|
|
921
|
+
options.classical_private_key_pem ||
|
|
922
|
+
options.hybrid_classical_private_key_pem ||
|
|
923
|
+
options.native_classical_private_key_pem
|
|
924
|
+
);
|
|
925
|
+
const pqPublicKeyPem = normalizePublicKeyPem(
|
|
926
|
+
options.pq_public_key_pem ||
|
|
927
|
+
options.hybrid_pq_public_key_pem ||
|
|
928
|
+
options.native_pq_public_key_pem
|
|
929
|
+
);
|
|
930
|
+
const pqPrivateKeyPem = normalizePrivateKeyPem(
|
|
931
|
+
options.pq_private_key_pem ||
|
|
932
|
+
options.hybrid_pq_private_key_pem ||
|
|
933
|
+
options.native_pq_private_key_pem
|
|
934
|
+
);
|
|
935
|
+
const classicalPublicKey = crypto.createPublicKey(classicalPublicKeyPem);
|
|
936
|
+
const classicalPrivateKey = crypto.createPrivateKey(classicalPrivateKeyPem);
|
|
937
|
+
const pqPublicKey = crypto.createPublicKey(pqPublicKeyPem);
|
|
938
|
+
const pqPrivateKey = crypto.createPrivateKey(pqPrivateKeyPem);
|
|
939
|
+
assertNativeKeyMatchesSuite(classicalPublicKey, hybridSuite.classical_suite, "native hybrid classical public key");
|
|
940
|
+
assertNativeKeyMatchesSuite(classicalPrivateKey, hybridSuite.classical_suite, "native hybrid classical private key");
|
|
941
|
+
assertNativeKeyMatchesSuite(pqPublicKey, hybridSuite.pq_suite, "native hybrid pq public key");
|
|
942
|
+
assertNativeKeyMatchesSuite(pqPrivateKey, hybridSuite.pq_suite, "native hybrid pq private key");
|
|
943
|
+
const identityRef = normalizeString(options.identity_ref || options.native_identity_ref || receipt.agent_identity);
|
|
944
|
+
if (!identityRef) {
|
|
945
|
+
throw new Error("native identity_ref required");
|
|
946
|
+
}
|
|
947
|
+
const classicalPublicKeyRef = nativePublicKeyRefFromPem(classicalPublicKeyPem, hybridSuite.classical_suite.id);
|
|
948
|
+
const pqPublicKeyRef = nativePublicKeyRefFromPem(pqPublicKeyPem, hybridSuite.pq_suite.id);
|
|
949
|
+
const hybridPublicKeyRef = nativeHybridPublicKeyRefFromPems(classicalPublicKeyPem, pqPublicKeyPem, hybridSuite.id);
|
|
950
|
+
const descriptor = {
|
|
951
|
+
identity_ref: identityRef,
|
|
952
|
+
hybrid_suite: hybridSuite.id,
|
|
953
|
+
hybrid_public_key_ref: hybridPublicKeyRef,
|
|
954
|
+
classical_public_key_ref: classicalPublicKeyRef,
|
|
955
|
+
pq_public_key_ref: pqPublicKeyRef
|
|
956
|
+
};
|
|
957
|
+
const signingMaterial = buildNativeHybridProofMaterial(receipt, canonicalEvent, descriptor);
|
|
958
|
+
const signingBytes = Buffer.from(canonicalize(signingMaterial), "utf8");
|
|
959
|
+
const classicalSignature = base64urlEncode(
|
|
960
|
+
crypto.sign(nativeSigningHashForSuite(hybridSuite.classical_suite), signingBytes, classicalPrivateKey)
|
|
961
|
+
);
|
|
962
|
+
const pqSignature = base64urlEncode(
|
|
963
|
+
crypto.sign(nativeSigningHashForSuite(hybridSuite.pq_suite), signingBytes, pqPrivateKey)
|
|
964
|
+
);
|
|
965
|
+
return {
|
|
966
|
+
method: XOONYA_NATIVE_HYBRID_METHOD,
|
|
967
|
+
hybrid_suite: hybridSuite.id,
|
|
968
|
+
identity_ref: identityRef,
|
|
969
|
+
hybrid_public_key_ref: hybridPublicKeyRef,
|
|
970
|
+
classical_public_key_ref: classicalPublicKeyRef,
|
|
971
|
+
pq_public_key_ref: pqPublicKeyRef,
|
|
972
|
+
classical_public_key_material: {
|
|
973
|
+
format: hybridSuite.classical_suite.public_key_format,
|
|
974
|
+
value: classicalPublicKeyPem
|
|
975
|
+
},
|
|
976
|
+
pq_public_key_material: {
|
|
977
|
+
format: hybridSuite.pq_suite.public_key_format,
|
|
978
|
+
value: pqPublicKeyPem
|
|
979
|
+
},
|
|
980
|
+
proof_material: {
|
|
981
|
+
signing_material_sha256: sha256Hex(signingBytes),
|
|
982
|
+
classical_signature: classicalSignature,
|
|
983
|
+
pq_signature: pqSignature
|
|
984
|
+
},
|
|
985
|
+
compact_signature: `${XOONYA_NATIVE_HYBRID_METHOD}:${hybridSuite.id}:${classicalSignature}.${pqSignature}`
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
782
989
|
function normalizeNativeAnchorRefs(anchorRefs, label = "native anchors") {
|
|
783
990
|
if (!Array.isArray(anchorRefs) || anchorRefs.length === 0) {
|
|
784
991
|
throw new Error(`${label} must be a non-empty array`);
|
|
@@ -918,6 +1125,101 @@ function verifyNativeSignedReceiptProof(receipt, ceb) {
|
|
|
918
1125
|
}
|
|
919
1126
|
}
|
|
920
1127
|
|
|
1128
|
+
function verifyNativeHybridReceiptProof(receipt, ceb) {
|
|
1129
|
+
try {
|
|
1130
|
+
const proof = receipt.native_proof;
|
|
1131
|
+
if (!proof || typeof proof !== "object" || Array.isArray(proof)) {
|
|
1132
|
+
return { valid: false, reason: "native_proof_missing" };
|
|
1133
|
+
}
|
|
1134
|
+
if (normalizeString(proof.method) !== XOONYA_NATIVE_HYBRID_METHOD) {
|
|
1135
|
+
return { valid: false, reason: "native_proof_method_mismatch" };
|
|
1136
|
+
}
|
|
1137
|
+
const hybridSuite = parseNativeHybridSuite(proof.hybrid_suite);
|
|
1138
|
+
if (!runtimeSupportsNativeHybridSuite(hybridSuite.id)) {
|
|
1139
|
+
return { valid: false, reason: "native_hybrid_runtime_validator_unavailable" };
|
|
1140
|
+
}
|
|
1141
|
+
const identityRef = normalizeString(proof.identity_ref);
|
|
1142
|
+
if (!identityRef) {
|
|
1143
|
+
return { valid: false, reason: "native_identity_ref_missing" };
|
|
1144
|
+
}
|
|
1145
|
+
const classicalPublicKeyMaterial = proof.classical_public_key_material;
|
|
1146
|
+
const pqPublicKeyMaterial = proof.pq_public_key_material;
|
|
1147
|
+
if (!classicalPublicKeyMaterial || typeof classicalPublicKeyMaterial !== "object" || Array.isArray(classicalPublicKeyMaterial)) {
|
|
1148
|
+
return { valid: false, reason: "native_hybrid_classical_public_key_material_missing" };
|
|
1149
|
+
}
|
|
1150
|
+
if (!pqPublicKeyMaterial || typeof pqPublicKeyMaterial !== "object" || Array.isArray(pqPublicKeyMaterial)) {
|
|
1151
|
+
return { valid: false, reason: "native_hybrid_pq_public_key_material_missing" };
|
|
1152
|
+
}
|
|
1153
|
+
if (normalizeString(classicalPublicKeyMaterial.format) !== hybridSuite.classical_suite.public_key_format) {
|
|
1154
|
+
return { valid: false, reason: "native_hybrid_classical_public_key_format_mismatch" };
|
|
1155
|
+
}
|
|
1156
|
+
if (normalizeString(pqPublicKeyMaterial.format) !== hybridSuite.pq_suite.public_key_format) {
|
|
1157
|
+
return { valid: false, reason: "native_hybrid_pq_public_key_format_mismatch" };
|
|
1158
|
+
}
|
|
1159
|
+
const classicalPublicKeyPem = normalizePublicKeyPem(classicalPublicKeyMaterial.value);
|
|
1160
|
+
const pqPublicKeyPem = normalizePublicKeyPem(pqPublicKeyMaterial.value);
|
|
1161
|
+
const classicalPublicKey = crypto.createPublicKey(classicalPublicKeyPem);
|
|
1162
|
+
const pqPublicKey = crypto.createPublicKey(pqPublicKeyPem);
|
|
1163
|
+
assertNativeKeyMatchesSuite(classicalPublicKey, hybridSuite.classical_suite, "native hybrid classical public key");
|
|
1164
|
+
assertNativeKeyMatchesSuite(pqPublicKey, hybridSuite.pq_suite, "native hybrid pq public key");
|
|
1165
|
+
const expectedClassicalPublicKeyRef = nativePublicKeyRefFromPem(classicalPublicKeyPem, hybridSuite.classical_suite.id);
|
|
1166
|
+
const expectedPqPublicKeyRef = nativePublicKeyRefFromPem(pqPublicKeyPem, hybridSuite.pq_suite.id);
|
|
1167
|
+
const expectedHybridPublicKeyRef = nativeHybridPublicKeyRefFromPems(classicalPublicKeyPem, pqPublicKeyPem, hybridSuite.id);
|
|
1168
|
+
if (normalizeString(proof.classical_public_key_ref) !== expectedClassicalPublicKeyRef) {
|
|
1169
|
+
return { valid: false, reason: "native_hybrid_classical_public_key_ref_mismatch" };
|
|
1170
|
+
}
|
|
1171
|
+
if (normalizeString(proof.pq_public_key_ref) !== expectedPqPublicKeyRef) {
|
|
1172
|
+
return { valid: false, reason: "native_hybrid_pq_public_key_ref_mismatch" };
|
|
1173
|
+
}
|
|
1174
|
+
if (normalizeString(proof.hybrid_public_key_ref) !== expectedHybridPublicKeyRef) {
|
|
1175
|
+
return { valid: false, reason: "native_hybrid_public_key_ref_mismatch" };
|
|
1176
|
+
}
|
|
1177
|
+
const proofMaterial = proof.proof_material;
|
|
1178
|
+
if (!proofMaterial || typeof proofMaterial !== "object" || Array.isArray(proofMaterial)) {
|
|
1179
|
+
return { valid: false, reason: "native_proof_material_missing" };
|
|
1180
|
+
}
|
|
1181
|
+
const classicalSignature = normalizeString(proofMaterial.classical_signature);
|
|
1182
|
+
const pqSignature = normalizeString(proofMaterial.pq_signature);
|
|
1183
|
+
if (!classicalSignature) {
|
|
1184
|
+
return { valid: false, reason: "native_hybrid_classical_signature_missing" };
|
|
1185
|
+
}
|
|
1186
|
+
if (!pqSignature) {
|
|
1187
|
+
return { valid: false, reason: "native_hybrid_pq_signature_missing" };
|
|
1188
|
+
}
|
|
1189
|
+
const expectedCompactSignature = `${XOONYA_NATIVE_HYBRID_METHOD}:${hybridSuite.id}:${classicalSignature}.${pqSignature}`;
|
|
1190
|
+
if (normalizeString(receipt.signature) !== expectedCompactSignature) {
|
|
1191
|
+
return { valid: false, reason: "signature_native_hybrid_mismatch" };
|
|
1192
|
+
}
|
|
1193
|
+
const signingMaterial = buildNativeHybridProofMaterial(receipt, ceb, {
|
|
1194
|
+
identity_ref: identityRef,
|
|
1195
|
+
hybrid_suite: hybridSuite.id,
|
|
1196
|
+
hybrid_public_key_ref: expectedHybridPublicKeyRef,
|
|
1197
|
+
classical_public_key_ref: expectedClassicalPublicKeyRef,
|
|
1198
|
+
pq_public_key_ref: expectedPqPublicKeyRef
|
|
1199
|
+
});
|
|
1200
|
+
const signingBytes = Buffer.from(canonicalize(signingMaterial), "utf8");
|
|
1201
|
+
const expectedSigningHash = sha256Hex(signingBytes);
|
|
1202
|
+
if (normalizeString(proofMaterial.signing_material_sha256).toLowerCase() !== expectedSigningHash) {
|
|
1203
|
+
return { valid: false, reason: "native_hybrid_signing_material_hash_mismatch" };
|
|
1204
|
+
}
|
|
1205
|
+
const classicalSignatureBytes = base64urlDecode(classicalSignature, "native hybrid classical signature");
|
|
1206
|
+
const pqSignatureBytes = base64urlDecode(pqSignature, "native hybrid pq signature");
|
|
1207
|
+
if (!crypto.verify(nativeSigningHashForSuite(hybridSuite.classical_suite), signingBytes, classicalPublicKey, classicalSignatureBytes)) {
|
|
1208
|
+
return { valid: false, reason: "native_hybrid_classical_signature_invalid" };
|
|
1209
|
+
}
|
|
1210
|
+
if (!crypto.verify(nativeSigningHashForSuite(hybridSuite.pq_suite), signingBytes, pqPublicKey, pqSignatureBytes)) {
|
|
1211
|
+
return { valid: false, reason: "native_hybrid_pq_signature_invalid" };
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
valid: true,
|
|
1215
|
+
verification_state: "verified_native_hybrid_signature",
|
|
1216
|
+
signature_suite: hybridSuite.id
|
|
1217
|
+
};
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
return { valid: false, reason: error.message };
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
921
1223
|
function verifyNativeAnchoredReceiptProof(receipt, ceb, bundle) {
|
|
922
1224
|
try {
|
|
923
1225
|
const proof = receipt.native_proof;
|
|
@@ -1026,6 +1328,11 @@ function emitReceipt(event, options = {}) {
|
|
|
1026
1328
|
signature = nativeProof.compact_signature;
|
|
1027
1329
|
delete nativeProof.compact_signature;
|
|
1028
1330
|
}
|
|
1331
|
+
if (!signature && unsignedReceipt.algorithm === XOONYA_NATIVE_HYBRID_METHOD) {
|
|
1332
|
+
nativeProof = buildNativeHybridReceiptProof(unsignedReceipt, canonicalEvent, options);
|
|
1333
|
+
signature = nativeProof.compact_signature;
|
|
1334
|
+
delete nativeProof.compact_signature;
|
|
1335
|
+
}
|
|
1029
1336
|
if (!signature && unsignedReceipt.algorithm === XOONYA_NATIVE_ANCHORED_METHOD) {
|
|
1030
1337
|
nativeProof = buildNativeAnchoredReceiptProof(unsignedReceipt, canonicalEvent, options);
|
|
1031
1338
|
signature = nativeProof.compact_signature;
|
|
@@ -1057,7 +1364,21 @@ function verifyReceiptProofMethod(receipt, ceb, bundle) {
|
|
|
1057
1364
|
return { valid: false, reason: "verification_method_none" };
|
|
1058
1365
|
}
|
|
1059
1366
|
if (algorithm === XOONYA_NATIVE_HYBRID_METHOD) {
|
|
1060
|
-
|
|
1367
|
+
const verification = verifyNativeHybridReceiptProof(receipt, ceb);
|
|
1368
|
+
if (!verification.valid) {
|
|
1369
|
+
return { valid: false, reason: verification.reason };
|
|
1370
|
+
}
|
|
1371
|
+
return {
|
|
1372
|
+
valid: true,
|
|
1373
|
+
method: {
|
|
1374
|
+
id: XOONYA_NATIVE_HYBRID_METHOD,
|
|
1375
|
+
family: "xoonya_native",
|
|
1376
|
+
verification_posture: "native_hybrid_signature_verified",
|
|
1377
|
+
description: "Verifies xoonya's native hybrid proof envelope with a classical and PQ signature bound to one deterministic signing material."
|
|
1378
|
+
},
|
|
1379
|
+
verification_state: verification.verification_state,
|
|
1380
|
+
signature_suite: verification.signature_suite
|
|
1381
|
+
};
|
|
1061
1382
|
}
|
|
1062
1383
|
|
|
1063
1384
|
const method = PROOF_VERIFICATION_METHODS[algorithm];
|
|
@@ -2699,15 +3020,14 @@ function buildxoonyaNativeProofStandard() {
|
|
|
2699
3020
|
method: XOONYA_NATIVE_ANCHORED_METHOD,
|
|
2700
3021
|
maturity: "implemented",
|
|
2701
3022
|
purpose: "native anchor binding for chain, batch, finality, or external attestation references"
|
|
2702
|
-
}
|
|
2703
|
-
],
|
|
2704
|
-
planned_native_methods: [
|
|
3023
|
+
},
|
|
2705
3024
|
{
|
|
2706
3025
|
method: XOONYA_NATIVE_HYBRID_METHOD,
|
|
2707
|
-
maturity: "
|
|
2708
|
-
purpose: "
|
|
3026
|
+
maturity: "implemented",
|
|
3027
|
+
purpose: "dual-signature classical-plus-pq native proof lane for stronger replay-sensitive verification"
|
|
2709
3028
|
}
|
|
2710
3029
|
],
|
|
3030
|
+
planned_native_methods: [],
|
|
2711
3031
|
supported_external_method_families: listProofVerificationMethods()
|
|
2712
3032
|
.filter((method) => method.verification_posture === "structure_verified_external_signature")
|
|
2713
3033
|
.map((method) => ({
|
|
@@ -2839,15 +3159,19 @@ function summarizexoonyaNativeProofStandard() {
|
|
|
2839
3159
|
}
|
|
2840
3160
|
|
|
2841
3161
|
function buildxoonyaNativeHybridReadinessPack() {
|
|
3162
|
+
const implementedHybridSuites = listImplementedNativeHybridSuites();
|
|
3163
|
+
const runtimeSupportedHybridSuites = implementedHybridSuites.filter((suite) => runtimeSupportsNativeHybridSuite(suite.id));
|
|
2842
3164
|
return {
|
|
2843
3165
|
ok: true,
|
|
2844
3166
|
product: "xoonya",
|
|
2845
3167
|
category: "xoonya-native-hybrid-readiness-pack",
|
|
2846
3168
|
pack_version: "xoonya-native-hybrid-readiness-v1",
|
|
2847
3169
|
method: XOONYA_NATIVE_HYBRID_METHOD,
|
|
2848
|
-
status: "
|
|
2849
|
-
posture: "
|
|
2850
|
-
current_decision:
|
|
3170
|
+
status: runtimeSupportedHybridSuites.length > 0 ? "implemented" : "runtime_gated",
|
|
3171
|
+
posture: "dual_signature_classical_plus_pq_lane_without_changing_xnya_atom_core",
|
|
3172
|
+
current_decision: runtimeSupportedHybridSuites.length > 0
|
|
3173
|
+
? "claim_registered_native_hybrid_verification_only_for_runtime_supported_vector_covered_suites"
|
|
3174
|
+
: "runtime_support_missing_for_registered_native_hybrid_verification",
|
|
2851
3175
|
implemented_classical_suites: listNativeSignatureSuites()
|
|
2852
3176
|
.filter((suite) => suite.maturity === "implemented")
|
|
2853
3177
|
.map((suite) => ({
|
|
@@ -2855,6 +3179,12 @@ function buildxoonyaNativeHybridReadinessPack() {
|
|
|
2855
3179
|
public_key_format: suite.public_key_format,
|
|
2856
3180
|
verification_posture: suite.verification_posture
|
|
2857
3181
|
})),
|
|
3182
|
+
implemented_hybrid_suites: runtimeSupportedHybridSuites.map((suite) => ({
|
|
3183
|
+
suite: suite.id,
|
|
3184
|
+
classical_suite: suite.classical_suite,
|
|
3185
|
+
pq_suite: suite.pq_suite,
|
|
3186
|
+
verification_posture: suite.posture
|
|
3187
|
+
})),
|
|
2858
3188
|
gated_candidate_suites: listNativeSignatureSuites()
|
|
2859
3189
|
.filter((suite) => suite.maturity !== "implemented")
|
|
2860
3190
|
.map((suite) => ({
|
|
@@ -2866,7 +3196,6 @@ function buildxoonyaNativeHybridReadinessPack() {
|
|
|
2866
3196
|
promotion_requirements: [
|
|
2867
3197
|
"runtime_validator_available_without_experimental_flags",
|
|
2868
3198
|
"positive_conformance_vectors",
|
|
2869
|
-
"design_gate_adversarial_vector",
|
|
2870
3199
|
"wrong_key_adversarial_vectors",
|
|
2871
3200
|
"tampered_signature_adversarial_vectors",
|
|
2872
3201
|
"downgrade_and_method_confusion_vectors",
|
|
@@ -2877,9 +3206,9 @@ function buildxoonyaNativeHybridReadinessPack() {
|
|
|
2877
3206
|
hybrid_object_model_boundary: {
|
|
2878
3207
|
atom_rule: "XNYA_atom_remains_commitment_only",
|
|
2879
3208
|
envelope_rule: "hybrid_or_pqc_material_lives_in_proof_envelope_or_profile",
|
|
2880
|
-
current_deterministic_reject_reason: "
|
|
3209
|
+
current_deterministic_reject_reason: runtimeSupportedHybridSuites.length > 0 ? null : "native_hybrid_runtime_validator_unavailable",
|
|
2881
3210
|
downgrade_rule: "hybrid_receipts_must_not_verify_as_classical_native_signed_receipts",
|
|
2882
|
-
claim_rule: "
|
|
3211
|
+
claim_rule: "claim_only_registered_runtime_supported_vector_covered_hybrid_suites"
|
|
2883
3212
|
},
|
|
2884
3213
|
linked_surfaces: {
|
|
2885
3214
|
native_standard_ref: "/v1/proof-center/native-standard",
|
|
@@ -2902,6 +3231,8 @@ function summarizexoonyaNativeHybridReadinessPack() {
|
|
|
2902
3231
|
posture: pack.posture,
|
|
2903
3232
|
implemented_classical_suite_count: pack.implemented_classical_suites.length,
|
|
2904
3233
|
implemented_classical_suites: pack.implemented_classical_suites.map((entry) => entry.suite),
|
|
3234
|
+
implemented_hybrid_suite_count: pack.implemented_hybrid_suites.length,
|
|
3235
|
+
implemented_hybrid_suites: pack.implemented_hybrid_suites.map((entry) => entry.suite),
|
|
2905
3236
|
gated_candidate_suite_count: pack.gated_candidate_suites.length,
|
|
2906
3237
|
promotion_requirement_count: pack.promotion_requirements.length,
|
|
2907
3238
|
deterministic_reject_reason: pack.hybrid_object_model_boundary.current_deterministic_reject_reason,
|
|
@@ -3051,7 +3382,7 @@ function buildxoonyaNativeStandardizationPack() {
|
|
|
3051
3382
|
"magic_or_atom_layout_is_changed",
|
|
3052
3383
|
"algorithm_none_is_accepted_as_production_proof",
|
|
3053
3384
|
"external_issuer_truth_is_claimed_without_external_verifier",
|
|
3054
|
-
"
|
|
3385
|
+
"unregistered_or_runtime_unsupported_pqc_or_hybrid_support_is_claimed"
|
|
3055
3386
|
]
|
|
3056
3387
|
},
|
|
3057
3388
|
standard_artifacts: [
|
|
@@ -3287,7 +3618,7 @@ function buildxoonyaNativeReferenceImplementationPack() {
|
|
|
3287
3618
|
"return_stable_error_codes_for_rejects",
|
|
3288
3619
|
"reject_algorithm_none_for_production_native_proofs",
|
|
3289
3620
|
"verify_ed25519_secp256k1_and_p256_only_when_suite_specific_validators_exist",
|
|
3290
|
-
"
|
|
3621
|
+
"verify_registered_native_hybrid_suites_only_when_runtime_support_and_vectors_exist",
|
|
3291
3622
|
"bind_external_methods_without_claiming_external_issuer_truth",
|
|
3292
3623
|
"preserve_anchor_binding_boundary_without_claiming_external_finality_truth"
|
|
3293
3624
|
],
|
|
@@ -3336,7 +3667,6 @@ function buildxoonyaNativeReferenceImplementationPack() {
|
|
|
3336
3667
|
wraps_javascript_runtime: false
|
|
3337
3668
|
},
|
|
3338
3669
|
explicit_non_claims: [
|
|
3339
|
-
"no_pq_or_hybrid_runtime_validation_claim",
|
|
3340
3670
|
"no_live_external_provider_claim",
|
|
3341
3671
|
"no_identity_auth_custody_transport_or_settlement_claim",
|
|
3342
3672
|
"no_python_or_rust_full_reference_claim_until_signature_suite_crypto_full_vector_parity_and_round_trip",
|
|
@@ -3513,7 +3843,8 @@ function buildxoonyaNativeConformanceMarkPack() {
|
|
|
3513
3843
|
"registered_native_methods_verify",
|
|
3514
3844
|
"algorithm_none_is_rejected",
|
|
3515
3845
|
"signature_suite_is_declared_and_registered",
|
|
3516
|
-
"anchor_binding_is_verified_without_external_finality_overclaim"
|
|
3846
|
+
"anchor_binding_is_verified_without_external_finality_overclaim",
|
|
3847
|
+
"registered_native_hybrid_suites_verify_when_runtime_support_is_present"
|
|
3517
3848
|
]
|
|
3518
3849
|
},
|
|
3519
3850
|
{
|
|
@@ -3529,7 +3860,7 @@ function buildxoonyaNativeConformanceMarkPack() {
|
|
|
3529
3860
|
{
|
|
3530
3861
|
claim: "pqc_or_hybrid_verified",
|
|
3531
3862
|
required_extra_evidence: [
|
|
3532
|
-
"
|
|
3863
|
+
"runtime_supported_registered_native_hybrid_suite",
|
|
3533
3864
|
"suite_specific_public_key_rules",
|
|
3534
3865
|
"positive_conformance_vectors",
|
|
3535
3866
|
"adversarial_downgrade_vectors",
|
|
@@ -3568,7 +3899,7 @@ function buildxoonyaNativeConformanceMarkPack() {
|
|
|
3568
3899
|
},
|
|
3569
3900
|
mark_usage_rules: [
|
|
3570
3901
|
"do_not_change_magic_layout_or_fixed_sizes_and_keep_the_mark",
|
|
3571
|
-
"
|
|
3902
|
+
"do_not_claim_unregistered_or_runtime_unsupported_pqc_hybrid_or_live_external_truth_without_extra_evidence",
|
|
3572
3903
|
"do_not_accept_algorithm_none_as_production_proof",
|
|
3573
3904
|
"do_not_remove_adversarial_failures_from_compatibility_evidence",
|
|
3574
3905
|
"do_not_use_the_mark_for_identity_auth_custody_transport_or_settlement_claims"
|
|
@@ -5904,6 +6235,7 @@ module.exports = {
|
|
|
5904
6235
|
getxoonyaNativeIdentityType,
|
|
5905
6236
|
buildNativeReceiptSignature,
|
|
5906
6237
|
buildNativeSignedReceiptProof,
|
|
6238
|
+
buildNativeHybridReceiptProof,
|
|
5907
6239
|
buildNativeAnchoredReceiptProof,
|
|
5908
6240
|
buildProofBundle,
|
|
5909
6241
|
verifyProofBundle,
|
|
@@ -111,6 +111,18 @@ def verify_proof_vectors() -> tuple[int, int, int, int]:
|
|
|
111
111
|
canonical_event = canonicalize_event(event)
|
|
112
112
|
assert_equal(hash_event(canonical_event), expected["event_commitment"], f"{vector['id']} event commitment")
|
|
113
113
|
options = dict(vector.get("receipt_options", {}))
|
|
114
|
+
if expected["receipt"].get("algorithm") == "xoonya-native-hybrid-v1":
|
|
115
|
+
assert_equal(expected["receipt"]["native_proof"]["method"], "xoonya-native-hybrid-v1", f"{vector['id']} native hybrid method")
|
|
116
|
+
bundle = {
|
|
117
|
+
"version": expected["proof_bundle_version"],
|
|
118
|
+
"ceb": canonical_event,
|
|
119
|
+
"receipt": expected["receipt"],
|
|
120
|
+
}
|
|
121
|
+
verification = verify_proof_bundle(bundle)
|
|
122
|
+
assert_equal(verification["valid"], False, f"{vector['id']} python hybrid boundary")
|
|
123
|
+
assert_equal(verification["reason"], "native_hybrid_runtime_unavailable_in_python_candidate", f"{vector['id']} python hybrid reason")
|
|
124
|
+
positive_count += 1
|
|
125
|
+
continue
|
|
114
126
|
if expected["receipt"].get("algorithm") == "xoonya-native-signed-v1":
|
|
115
127
|
assert_equal(expected["receipt"]["native_proof"]["method"], "xoonya-native-signed-v1", f"{vector['id']} native signed method")
|
|
116
128
|
assert_equal(expected["receipt"]["native_proof"]["signature_suite"], options.get("signature_suite"), f"{vector['id']} native signed suite")
|
|
@@ -164,6 +176,8 @@ def verify_proof_vectors() -> tuple[int, int, int, int]:
|
|
|
164
176
|
continue
|
|
165
177
|
result = verify_proof_bundle(vector["bundle"])
|
|
166
178
|
expected_reason = vector["expected_reason"]
|
|
179
|
+
if vector["bundle"].get("receipt", {}).get("algorithm") == "xoonya-native-hybrid-v1":
|
|
180
|
+
expected_reason = "native_hybrid_runtime_unavailable_in_python_candidate"
|
|
167
181
|
if expected_reason == "native_signature_invalid" and not ed25519_available:
|
|
168
182
|
expected_reason = "native_signature_crypto_dependency_missing"
|
|
169
183
|
assert_equal(result["valid"], False, f"{vector['id']} adversarial should fail")
|
|
@@ -755,7 +755,7 @@ def verify_proof_bundle(bundle: dict[str, Any]) -> dict[str, Any]:
|
|
|
755
755
|
if algorithm == "none":
|
|
756
756
|
return {"valid": False, "reason": "verification_method_none"}
|
|
757
757
|
if algorithm == XOONYA_NATIVE_HYBRID_METHOD:
|
|
758
|
-
return {"valid": False, "reason": "
|
|
758
|
+
return {"valid": False, "reason": "native_hybrid_runtime_unavailable_in_python_candidate"}
|
|
759
759
|
if algorithm == LEGACY_OPRETURN_METHOD:
|
|
760
760
|
legacy_receipt = (receipt.get("compatibility") or {}).get("legacy_receipt")
|
|
761
761
|
if not isinstance(legacy_receipt, dict):
|
package/scripts/verify_all.js
CHANGED
|
@@ -251,14 +251,22 @@ function verifyProofBundleConformance() {
|
|
|
251
251
|
ensure(unsupportedVerification.valid === false, "unknown proof method must not verify");
|
|
252
252
|
ensure(unsupportedVerification.reason === "verification_method_unsupported", "unknown proof method reason mismatch");
|
|
253
253
|
|
|
254
|
-
const
|
|
255
|
-
|
|
254
|
+
const hybridClassical = crypto.generateKeyPairSync("ed25519");
|
|
255
|
+
const hybridPq = crypto.generateKeyPairSync("ml-dsa-65");
|
|
256
|
+
const hybridReceipt = sdk.emitReceipt(event, {
|
|
257
|
+
agent_identity: "native-hybrid-agent",
|
|
256
258
|
algorithm: "xoonya-native-hybrid-v1",
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
identity_ref: "did:xoonya:native-hybrid-agent",
|
|
260
|
+
classical_signature_suite: "ed25519",
|
|
261
|
+
pq_signature_suite: "ml-dsa-65",
|
|
262
|
+
classical_public_key_pem: hybridClassical.publicKey.export({ type: "spki", format: "pem" }),
|
|
263
|
+
classical_private_key_pem: hybridClassical.privateKey.export({ type: "pkcs8", format: "pem" }),
|
|
264
|
+
pq_public_key_pem: hybridPq.publicKey.export({ type: "spki", format: "pem" }),
|
|
265
|
+
pq_private_key_pem: hybridPq.privateKey.export({ type: "pkcs8", format: "pem" })
|
|
266
|
+
});
|
|
267
|
+
const hybridVerification = sdk.verifyProofBundle(sdk.buildProofBundle({ ceb: event, receipt: hybridReceipt }));
|
|
268
|
+
ensure(hybridVerification.valid === true, "native hybrid method must verify");
|
|
269
|
+
ensure(hybridVerification.verification_state === "verified_native_hybrid_signature", "native hybrid verification state mismatch");
|
|
262
270
|
|
|
263
271
|
const tamperedNativeReceipt = {
|
|
264
272
|
...nativeReceipt,
|
|
@@ -526,6 +534,7 @@ function main() {
|
|
|
526
534
|
ensure(typeof sdk.verifyxoonyaNativeAtom === "function", "missing verifyxoonyaNativeAtom");
|
|
527
535
|
ensure(typeof sdk.buildNativeReceiptSignature === "function", "missing buildNativeReceiptSignature");
|
|
528
536
|
ensure(typeof sdk.buildNativeSignedReceiptProof === "function", "missing buildNativeSignedReceiptProof");
|
|
537
|
+
ensure(typeof sdk.buildNativeHybridReceiptProof === "function", "missing buildNativeHybridReceiptProof");
|
|
529
538
|
ensure(typeof sdk.buildNativeAnchoredReceiptProof === "function", "missing buildNativeAnchoredReceiptProof");
|
|
530
539
|
ensure(typeof sdk.buildxoonyaNativeAnchorProfile === "function", "missing buildxoonyaNativeAnchorProfile");
|
|
531
540
|
ensure(typeof sdk.summarizexoonyaNativeAnchorProfile === "function", "missing summarizexoonyaNativeAnchorProfile");
|
|
@@ -567,9 +576,10 @@ function main() {
|
|
|
567
576
|
ensure(fs.existsSync(path.resolve(__dirname, "..", "integrations", "registration-record.schema.json")), "missing integration registration schema");
|
|
568
577
|
ensure(fs.existsSync(path.resolve(__dirname, "..", "integrations", "registry-snapshot.schema.json")), "missing integration registry snapshot schema");
|
|
569
578
|
const hybridReadiness = sdk.summarizexoonyaNativeHybridReadinessPack();
|
|
570
|
-
ensure(hybridReadiness.status === "
|
|
579
|
+
ensure(hybridReadiness.status === "implemented", "native hybrid readiness must be implemented");
|
|
571
580
|
ensure(hybridReadiness.implemented_classical_suites.includes("secp256k1"), "native hybrid readiness secp256k1 suite missing");
|
|
572
581
|
ensure(hybridReadiness.implemented_classical_suites.includes("p256"), "native hybrid readiness p256 suite missing");
|
|
582
|
+
ensure(hybridReadiness.implemented_hybrid_suites.includes("ed25519+ml-dsa-65"), "native hybrid readiness ml-dsa suite missing");
|
|
573
583
|
const standardization = sdk.summarizexoonyaNativeStandardizationPack();
|
|
574
584
|
ensure(standardization.canonical_magic === "XNYA", "native standardization magic mismatch");
|
|
575
585
|
ensure(standardization.conformance_forbidden_condition_count >= 4, "native standardization forbidden conditions missing");
|