@cardanowall/poe-standard 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/carriage.cjs +1972 -0
- package/dist/carriage.cjs.map +1 -0
- package/dist/carriage.d.cts +55 -0
- package/dist/carriage.d.ts +55 -0
- package/dist/carriage.js +1967 -0
- package/dist/carriage.js.map +1 -0
- package/dist/encoder.cjs +29 -77
- package/dist/encoder.cjs.map +1 -1
- package/dist/encoder.d.cts +10 -0
- package/dist/encoder.d.ts +10 -0
- package/dist/encoder.js +29 -77
- package/dist/encoder.js.map +1 -1
- package/dist/error-codes.cjs +129 -37
- package/dist/error-codes.cjs.map +1 -1
- package/dist/error-codes.d.cts +11 -6
- package/dist/error-codes.d.ts +11 -6
- package/dist/error-codes.js +126 -38
- package/dist/error-codes.js.map +1 -1
- package/dist/index.cjs +1085 -838
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -58
- package/dist/index.d.ts +4 -58
- package/dist/index.js +1074 -833
- package/dist/index.js.map +1 -1
- package/dist/schema.cjs +101 -87
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +69 -47
- package/dist/schema.d.ts +69 -47
- package/dist/schema.js +99 -86
- package/dist/schema.js.map +1 -1
- package/dist/validator.cjs +927 -577
- package/dist/validator.cjs.map +1 -1
- package/dist/validator.d.cts +48 -7
- package/dist/validator.d.ts +48 -7
- package/dist/validator.js +927 -578
- package/dist/validator.js.map +1 -1
- package/package.json +8 -2
package/dist/index.cjs
CHANGED
|
@@ -3,95 +3,108 @@
|
|
|
3
3
|
var zod = require('zod');
|
|
4
4
|
|
|
5
5
|
// src/schema.ts
|
|
6
|
-
|
|
7
|
-
zod.z.
|
|
8
|
-
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
var UTF8_ENCODER = new TextEncoder();
|
|
12
|
-
var UriChunkArraySchema = zod.z.array(
|
|
13
|
-
zod.z.string().refine(
|
|
14
|
-
(s3) => {
|
|
15
|
-
const n2 = UTF8_ENCODER.encode(s3).length;
|
|
16
|
-
return n2 >= 1 && n2 <= 64;
|
|
17
|
-
},
|
|
18
|
-
{ params: { code: "CHUNK_TOO_LARGE" } }
|
|
19
|
-
)
|
|
20
|
-
).min(1);
|
|
6
|
+
function textKeyedMap(inner) {
|
|
7
|
+
return zod.z.custom((value) => !(value instanceof Uint8Array), {
|
|
8
|
+
message: "CBOR byte string present where a text-keyed map is required"
|
|
9
|
+
}).pipe(inner);
|
|
10
|
+
}
|
|
21
11
|
var HashDigestSchema = zod.z.instanceof(Uint8Array);
|
|
22
12
|
var HashesMapSchema = zod.z.record(zod.z.string(), HashDigestSchema);
|
|
23
|
-
var
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}).
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
13
|
+
var UriSchema = zod.z.string();
|
|
14
|
+
var MerkleCommitSchema = textKeyedMap(
|
|
15
|
+
zod.z.object({
|
|
16
|
+
alg: zod.z.string(),
|
|
17
|
+
root: zod.z.instanceof(Uint8Array),
|
|
18
|
+
leaf_count: zod.z.union([zod.z.number().int(), zod.z.bigint()]),
|
|
19
|
+
uris: zod.z.array(UriSchema).optional()
|
|
20
|
+
}).strict()
|
|
21
|
+
);
|
|
22
|
+
var SlotSchema = textKeyedMap(
|
|
23
|
+
zod.z.object({
|
|
24
|
+
epk: zod.z.instanceof(Uint8Array).optional(),
|
|
25
|
+
kem_ct: zod.z.instanceof(Uint8Array).optional(),
|
|
26
|
+
wrap: zod.z.instanceof(Uint8Array).optional()
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
var Argon2idParamsSchema = textKeyedMap(
|
|
30
|
+
zod.z.object({
|
|
31
|
+
m: zod.z.union([zod.z.number().int(), zod.z.bigint()]),
|
|
32
|
+
t: zod.z.union([zod.z.number().int(), zod.z.bigint()]),
|
|
33
|
+
p: zod.z.union([zod.z.number().int(), zod.z.bigint()])
|
|
34
|
+
}).strict()
|
|
35
|
+
);
|
|
36
|
+
var PassphraseBlockSchema = textKeyedMap(
|
|
37
|
+
zod.z.object({
|
|
38
|
+
alg: zod.z.string(),
|
|
39
|
+
salt: zod.z.instanceof(Uint8Array).superRefine((bytes, ctx) => {
|
|
40
|
+
if (bytes.length < 16) {
|
|
41
|
+
ctx.addIssue({
|
|
42
|
+
code: "custom",
|
|
43
|
+
path: [],
|
|
44
|
+
message: `passphrase.salt length ${bytes.length} < 16`,
|
|
45
|
+
params: { code: "ENC_PASSPHRASE_SALT_TOO_SHORT" }
|
|
46
|
+
});
|
|
47
|
+
} else if (bytes.length > 64) {
|
|
48
|
+
ctx.addIssue({
|
|
49
|
+
code: "custom",
|
|
50
|
+
path: [],
|
|
51
|
+
message: `passphrase.salt length ${bytes.length} > 64`,
|
|
52
|
+
params: { code: "ENC_PASSPHRASE_SALT_TOO_LONG" }
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
params: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
57
|
+
}).strict()
|
|
58
|
+
);
|
|
59
|
+
var EncScheme1Schema = textKeyedMap(
|
|
60
|
+
zod.z.object({
|
|
61
|
+
scheme: zod.z.literal(1),
|
|
62
|
+
aead: zod.z.string(),
|
|
63
|
+
kem: zod.z.string().optional(),
|
|
64
|
+
nonce: zod.z.instanceof(Uint8Array),
|
|
65
|
+
slots: zod.z.array(SlotSchema).optional(),
|
|
66
|
+
slots_mac: zod.z.instanceof(Uint8Array).refine((b5) => b5.length === 32, {
|
|
67
|
+
params: { code: "ENC_SLOTS_MAC_INVALID_LENGTH" }
|
|
68
|
+
}).optional(),
|
|
69
|
+
passphrase: PassphraseBlockSchema.optional()
|
|
70
|
+
}).strict()
|
|
71
|
+
);
|
|
72
|
+
var EncOpaqueSchema = textKeyedMap(
|
|
73
|
+
zod.z.looseObject({
|
|
74
|
+
scheme: zod.z.union([zod.z.number().int().nonnegative(), zod.z.bigint().nonnegative()])
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
var EncryptionEnvelopeSchema = zod.z.union([EncScheme1Schema, EncOpaqueSchema]);
|
|
78
|
+
var ItemEntrySchema = textKeyedMap(
|
|
79
|
+
zod.z.object({
|
|
80
|
+
hashes: HashesMapSchema,
|
|
81
|
+
uris: zod.z.array(UriSchema).optional(),
|
|
82
|
+
// Captured as `unknown`: the envelope is a union whose disposition
|
|
83
|
+
// (typed scheme-1 vs opaque) depends on identifier support, so the
|
|
84
|
+
// validator's domain pass — not this schema — narrows it.
|
|
85
|
+
enc: zod.z.unknown().optional()
|
|
86
|
+
}).strict()
|
|
87
|
+
);
|
|
88
|
+
var SigEntrySchema = textKeyedMap(
|
|
89
|
+
zod.z.object({
|
|
90
|
+
cose_key: zod.z.instanceof(Uint8Array).optional(),
|
|
91
|
+
cose_sign1: zod.z.instanceof(Uint8Array)
|
|
92
|
+
}).strict()
|
|
93
|
+
);
|
|
83
94
|
var SupersedesSchema = zod.z.instanceof(Uint8Array).refine((b5) => b5.length === 32, {
|
|
84
95
|
params: { code: "SUPERSEDES_TX_INVALID_LENGTH" }
|
|
85
96
|
});
|
|
86
97
|
var VersionLiteralSchema = zod.z.literal(1);
|
|
87
|
-
var PoeRecordSchema =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
var PoeRecordSchema = textKeyedMap(
|
|
99
|
+
zod.z.looseObject({
|
|
100
|
+
v: VersionLiteralSchema,
|
|
101
|
+
items: zod.z.array(ItemEntrySchema).optional(),
|
|
102
|
+
merkle: zod.z.array(MerkleCommitSchema).optional(),
|
|
103
|
+
supersedes: SupersedesSchema.optional(),
|
|
104
|
+
sigs: zod.z.array(SigEntrySchema).optional(),
|
|
105
|
+
crit: zod.z.array(zod.z.string()).optional()
|
|
106
|
+
})
|
|
107
|
+
);
|
|
95
108
|
var TOP_LEVEL_BASE_KEYS = /* @__PURE__ */ new Set([
|
|
96
109
|
"v",
|
|
97
110
|
"items",
|
|
@@ -100,8 +113,8 @@ var TOP_LEVEL_BASE_KEYS = /* @__PURE__ */ new Set([
|
|
|
100
113
|
"sigs",
|
|
101
114
|
"crit"
|
|
102
115
|
]);
|
|
103
|
-
var EXTENSION_KEY_VENDOR_RE = /^x
|
|
104
|
-
var EXTENSION_KEY_COMPANION_RE = /^[a-z]
|
|
116
|
+
var EXTENSION_KEY_VENDOR_RE = /^x-[^\u0000-\u001f\u007f-\u009f]+$/;
|
|
117
|
+
var EXTENSION_KEY_COMPANION_RE = /^[a-z]+-[^\u0000-\u001f\u007f-\u009f]+$/;
|
|
105
118
|
function isExtensionKey(k4) {
|
|
106
119
|
return EXTENSION_KEY_VENDOR_RE.test(k4) || EXTENSION_KEY_COMPANION_RE.test(k4);
|
|
107
120
|
}
|
|
@@ -1767,97 +1780,366 @@ function mapDecodeError(cause) {
|
|
|
1767
1780
|
|
|
1768
1781
|
// src/encoder.ts
|
|
1769
1782
|
function encodePoeRecord(record) {
|
|
1770
|
-
return encodeCanonicalCbor(
|
|
1771
|
-
}
|
|
1772
|
-
function encodeRecordBodyForSigning(record) {
|
|
1773
|
-
const body = recordToCborInternal(
|
|
1783
|
+
return encodeCanonicalCbor(toCborValue(
|
|
1774
1784
|
record,
|
|
1775
1785
|
/* includeSigs */
|
|
1776
|
-
|
|
1777
|
-
);
|
|
1778
|
-
return encodeCanonicalCbor(body);
|
|
1786
|
+
true
|
|
1787
|
+
));
|
|
1779
1788
|
}
|
|
1780
|
-
function
|
|
1781
|
-
return
|
|
1789
|
+
function encodeRecordBodyForSigning(record) {
|
|
1790
|
+
return encodeCanonicalCbor(toCborValue(
|
|
1782
1791
|
record,
|
|
1783
1792
|
/* includeSigs */
|
|
1784
|
-
|
|
1785
|
-
);
|
|
1793
|
+
false
|
|
1794
|
+
));
|
|
1786
1795
|
}
|
|
1787
|
-
function
|
|
1788
|
-
const out = {
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
if (record.crit !== void 0) out["crit"] = record.crit.slice();
|
|
1794
|
-
for (const [k4, v3] of Object.entries(record)) {
|
|
1795
|
-
if (k4 === "v" || k4 === "items" || k4 === "merkle" || k4 === "supersedes" || k4 === "sigs" || k4 === "crit") {
|
|
1796
|
-
continue;
|
|
1797
|
-
}
|
|
1798
|
-
out[k4] = v3;
|
|
1796
|
+
function toCborValue(record, includeSigs) {
|
|
1797
|
+
const out = {};
|
|
1798
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1799
|
+
if (value === void 0) continue;
|
|
1800
|
+
if (!includeSigs && key === "sigs") continue;
|
|
1801
|
+
out[key] = stripUndefined(value);
|
|
1799
1802
|
}
|
|
1800
1803
|
return out;
|
|
1801
1804
|
}
|
|
1802
|
-
function
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
out["uris"] = item.uris.map((chunks) => chunks.slice());
|
|
1805
|
+
function stripUndefined(value) {
|
|
1806
|
+
if (value === null || typeof value !== "object" || value instanceof Uint8Array) {
|
|
1807
|
+
return value;
|
|
1806
1808
|
}
|
|
1807
|
-
if (
|
|
1808
|
-
|
|
1809
|
+
if (Array.isArray(value)) {
|
|
1810
|
+
return value.map((element) => stripUndefined(element));
|
|
1811
|
+
}
|
|
1812
|
+
if (value instanceof Map) {
|
|
1813
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
1814
|
+
for (const [k4, v3] of value) {
|
|
1815
|
+
if (v3 === void 0) continue;
|
|
1816
|
+
out2.set(k4, stripUndefined(v3));
|
|
1817
|
+
}
|
|
1818
|
+
return out2;
|
|
1809
1819
|
}
|
|
1810
|
-
return out;
|
|
1811
|
-
}
|
|
1812
|
-
function hashesToCbor(hashes2) {
|
|
1813
1820
|
const out = {};
|
|
1814
|
-
for (const [
|
|
1815
|
-
|
|
1821
|
+
for (const [k4, v3] of Object.entries(value)) {
|
|
1822
|
+
if (v3 === void 0) continue;
|
|
1823
|
+
out[k4] = stripUndefined(v3);
|
|
1816
1824
|
}
|
|
1817
1825
|
return out;
|
|
1818
1826
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1827
|
+
|
|
1828
|
+
// src/error-codes.ts
|
|
1829
|
+
var ERROR_CODES = [
|
|
1830
|
+
"MALFORMED_CBOR",
|
|
1831
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
1832
|
+
"SCHEMA_MISSING_REQUIRED",
|
|
1833
|
+
"SCHEMA_UNKNOWN_FIELD",
|
|
1834
|
+
"SCHEMA_INVALID_LITERAL",
|
|
1835
|
+
"SCHEMA_EMPTY_RECORD",
|
|
1836
|
+
"HASH_DIGEST_LENGTH_MISMATCH",
|
|
1837
|
+
"UNSUPPORTED_HASH_ALG",
|
|
1838
|
+
"UNSUPPORTED_MERKLE_COMMIT_ALG",
|
|
1839
|
+
"SCHEMA_MERKLE_LEAF_COUNT_INVALID",
|
|
1840
|
+
"INVALID_URI",
|
|
1841
|
+
"CHUNK_TOO_LARGE",
|
|
1842
|
+
"UNAUTHENTICATED_CIPHER_FORBIDDEN",
|
|
1843
|
+
"UNSUPPORTED_AEAD_ALG",
|
|
1844
|
+
"NONCE_LENGTH_MISMATCH",
|
|
1845
|
+
"UNSUPPORTED_ENVELOPE_SCHEME",
|
|
1846
|
+
"ENC_UNSUPPORTED",
|
|
1847
|
+
"ENC_SLOTS_EMPTY",
|
|
1848
|
+
"ENC_SLOT_INVALID_SHAPE",
|
|
1849
|
+
"UNSUPPORTED_KEM_ALG",
|
|
1850
|
+
"ENC_KEM_REQUIRED",
|
|
1851
|
+
"KEM_EPK_LENGTH_MISMATCH",
|
|
1852
|
+
"KEM_CT_LENGTH_MISMATCH",
|
|
1853
|
+
"WRAP_LENGTH_MISMATCH",
|
|
1854
|
+
"ENC_SLOTS_MAC_INVALID_LENGTH",
|
|
1855
|
+
"ENC_SLOTS_MAC_REQUIRED",
|
|
1856
|
+
"ENC_SLOTS_REQUIRED",
|
|
1857
|
+
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
1858
|
+
"ENC_SLOTS_TOO_MANY",
|
|
1859
|
+
"ENC_ENVELOPE_TOO_LARGE",
|
|
1860
|
+
"ENC_EXCLUSIVITY_VIOLATION",
|
|
1861
|
+
"ENC_NO_KEY_PATH",
|
|
1862
|
+
"ENC_REQUIRES_CONTENT_HASH",
|
|
1863
|
+
"ENC_PASSPHRASE_ALG_UNSUPPORTED",
|
|
1864
|
+
"ENC_PASSPHRASE_SALT_TOO_SHORT",
|
|
1865
|
+
"ENC_PASSPHRASE_SALT_TOO_LONG",
|
|
1866
|
+
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
1867
|
+
"ENC_PASSPHRASE_PARAMS_EXCEED_POLICY",
|
|
1868
|
+
"MALFORMED_SIG_COSE_SIGN1",
|
|
1869
|
+
"SIGNATURE_UNSUPPORTED",
|
|
1870
|
+
"SIG_ENTRY_INVALID_SHAPE",
|
|
1871
|
+
"SIG_ENTRY_KID_COSE_KEY_CONFLICT",
|
|
1872
|
+
"SIG_PRIVATE_KEY_LEAKED",
|
|
1873
|
+
"SUPERSEDES_TX_INVALID_LENGTH",
|
|
1874
|
+
"EXTENSION_UNSUPPORTED_CRITICAL",
|
|
1875
|
+
"CRIT_SHAPE_INVALID",
|
|
1876
|
+
"TX_NOT_FOUND",
|
|
1877
|
+
"PROVIDER_UNAVAILABLE",
|
|
1878
|
+
"TX_INTEGRITY_MISMATCH",
|
|
1879
|
+
"METADATA_NOT_FOUND",
|
|
1880
|
+
"INSUFFICIENT_CONFIRMATIONS",
|
|
1881
|
+
"SIGNATURE_INVALID",
|
|
1882
|
+
"SIGNER_KEY_UNRESOLVED",
|
|
1883
|
+
"WALLET_ADDRESS_MISMATCH",
|
|
1884
|
+
"URI_TARGET_FORBIDDEN",
|
|
1885
|
+
"URI_INTEGRITY_MISMATCH",
|
|
1886
|
+
"URI_PROVIDER_INTEGRITY_MISMATCH",
|
|
1887
|
+
"URI_FETCH_FAILED",
|
|
1888
|
+
"CONTENT_UNAVAILABLE",
|
|
1889
|
+
"CONTENT_FETCH_LIMIT_EXCEEDED",
|
|
1890
|
+
"CIPHERTEXT_UNAVAILABLE",
|
|
1891
|
+
"SERVICE_INDEPENDENCE_VIOLATION",
|
|
1892
|
+
"WRONG_DECRYPTION_INPUT_SHAPE",
|
|
1893
|
+
"WRONG_RECIPIENT_KEY",
|
|
1894
|
+
"TAMPERED_HEADER",
|
|
1895
|
+
"TAMPERED_CIPHERTEXT",
|
|
1896
|
+
"KDF_DERIVATION_FAILED",
|
|
1897
|
+
"ENC_PASSPHRASE_UNNORMALIZABLE",
|
|
1898
|
+
"ENC_PASSPHRASE_EMPTY",
|
|
1899
|
+
"SCHEMA_MERKLE_LEAF_COUNT_MISMATCH",
|
|
1900
|
+
"SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED",
|
|
1901
|
+
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
1902
|
+
"MERKLE_ROOT_MISMATCH",
|
|
1903
|
+
"MERKLE_LEAVES_UNAVAILABLE",
|
|
1904
|
+
"MERKLE_UNSUPPORTED",
|
|
1905
|
+
"OUT_OF_PROFILE_SKIPPED"
|
|
1906
|
+
];
|
|
1907
|
+
var ERROR_CODE_PART = Object.freeze({
|
|
1908
|
+
MALFORMED_CBOR: "A",
|
|
1909
|
+
SCHEMA_TYPE_MISMATCH: "A",
|
|
1910
|
+
SCHEMA_MISSING_REQUIRED: "A",
|
|
1911
|
+
SCHEMA_UNKNOWN_FIELD: "A",
|
|
1912
|
+
SCHEMA_INVALID_LITERAL: "A",
|
|
1913
|
+
SCHEMA_EMPTY_RECORD: "A",
|
|
1914
|
+
HASH_DIGEST_LENGTH_MISMATCH: "A",
|
|
1915
|
+
UNSUPPORTED_HASH_ALG: "A",
|
|
1916
|
+
UNSUPPORTED_MERKLE_COMMIT_ALG: "A",
|
|
1917
|
+
SCHEMA_MERKLE_LEAF_COUNT_INVALID: "A",
|
|
1918
|
+
INVALID_URI: "A",
|
|
1919
|
+
CHUNK_TOO_LARGE: "carriage",
|
|
1920
|
+
UNAUTHENTICATED_CIPHER_FORBIDDEN: "A",
|
|
1921
|
+
UNSUPPORTED_AEAD_ALG: "A",
|
|
1922
|
+
NONCE_LENGTH_MISMATCH: "A",
|
|
1923
|
+
UNSUPPORTED_ENVELOPE_SCHEME: "A",
|
|
1924
|
+
ENC_UNSUPPORTED: "A",
|
|
1925
|
+
ENC_SLOTS_EMPTY: "A",
|
|
1926
|
+
ENC_SLOT_INVALID_SHAPE: "A",
|
|
1927
|
+
UNSUPPORTED_KEM_ALG: "A",
|
|
1928
|
+
ENC_KEM_REQUIRED: "A",
|
|
1929
|
+
KEM_EPK_LENGTH_MISMATCH: "A",
|
|
1930
|
+
KEM_CT_LENGTH_MISMATCH: "A",
|
|
1931
|
+
WRAP_LENGTH_MISMATCH: "A",
|
|
1932
|
+
ENC_SLOTS_MAC_INVALID_LENGTH: "A",
|
|
1933
|
+
ENC_SLOTS_MAC_REQUIRED: "A",
|
|
1934
|
+
ENC_SLOTS_REQUIRED: "A",
|
|
1935
|
+
ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "A",
|
|
1936
|
+
ENC_SLOTS_TOO_MANY: "A",
|
|
1937
|
+
ENC_ENVELOPE_TOO_LARGE: "A",
|
|
1938
|
+
ENC_EXCLUSIVITY_VIOLATION: "A",
|
|
1939
|
+
ENC_NO_KEY_PATH: "A",
|
|
1940
|
+
ENC_REQUIRES_CONTENT_HASH: "A",
|
|
1941
|
+
ENC_PASSPHRASE_ALG_UNSUPPORTED: "A",
|
|
1942
|
+
ENC_PASSPHRASE_SALT_TOO_SHORT: "A",
|
|
1943
|
+
ENC_PASSPHRASE_SALT_TOO_LONG: "A",
|
|
1944
|
+
ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "A",
|
|
1945
|
+
ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "A",
|
|
1946
|
+
MALFORMED_SIG_COSE_SIGN1: "A",
|
|
1947
|
+
SIGNATURE_UNSUPPORTED: "A",
|
|
1948
|
+
SIG_ENTRY_INVALID_SHAPE: "A",
|
|
1949
|
+
SIG_ENTRY_KID_COSE_KEY_CONFLICT: "A",
|
|
1950
|
+
SIG_PRIVATE_KEY_LEAKED: "A",
|
|
1951
|
+
SUPERSEDES_TX_INVALID_LENGTH: "A",
|
|
1952
|
+
EXTENSION_UNSUPPORTED_CRITICAL: "A",
|
|
1953
|
+
CRIT_SHAPE_INVALID: "A",
|
|
1954
|
+
TX_NOT_FOUND: "B",
|
|
1955
|
+
PROVIDER_UNAVAILABLE: "B",
|
|
1956
|
+
TX_INTEGRITY_MISMATCH: "B",
|
|
1957
|
+
METADATA_NOT_FOUND: "B",
|
|
1958
|
+
INSUFFICIENT_CONFIRMATIONS: "B",
|
|
1959
|
+
SIGNATURE_INVALID: "B",
|
|
1960
|
+
SIGNER_KEY_UNRESOLVED: "B",
|
|
1961
|
+
WALLET_ADDRESS_MISMATCH: "B",
|
|
1962
|
+
URI_TARGET_FORBIDDEN: "B",
|
|
1963
|
+
URI_INTEGRITY_MISMATCH: "B",
|
|
1964
|
+
URI_PROVIDER_INTEGRITY_MISMATCH: "B",
|
|
1965
|
+
URI_FETCH_FAILED: "B",
|
|
1966
|
+
CONTENT_UNAVAILABLE: "B",
|
|
1967
|
+
CONTENT_FETCH_LIMIT_EXCEEDED: "B",
|
|
1968
|
+
CIPHERTEXT_UNAVAILABLE: "B",
|
|
1969
|
+
SERVICE_INDEPENDENCE_VIOLATION: "B",
|
|
1970
|
+
WRONG_DECRYPTION_INPUT_SHAPE: "B",
|
|
1971
|
+
WRONG_RECIPIENT_KEY: "B",
|
|
1972
|
+
TAMPERED_HEADER: "B",
|
|
1973
|
+
TAMPERED_CIPHERTEXT: "B",
|
|
1974
|
+
KDF_DERIVATION_FAILED: "B",
|
|
1975
|
+
ENC_PASSPHRASE_UNNORMALIZABLE: "B",
|
|
1976
|
+
ENC_PASSPHRASE_EMPTY: "B",
|
|
1977
|
+
SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "B",
|
|
1978
|
+
SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "B",
|
|
1979
|
+
SCHEMA_MERKLE_LEAVES_MALFORMED: "B",
|
|
1980
|
+
MERKLE_ROOT_MISMATCH: "B",
|
|
1981
|
+
MERKLE_LEAVES_UNAVAILABLE: "B",
|
|
1982
|
+
MERKLE_UNSUPPORTED: "B",
|
|
1983
|
+
OUT_OF_PROFILE_SKIPPED: "B"
|
|
1984
|
+
});
|
|
1985
|
+
var STRUCTURAL_ERROR_CODES = Object.freeze(
|
|
1986
|
+
ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "A")
|
|
1987
|
+
);
|
|
1988
|
+
var CARRIAGE_ERROR_CODES = Object.freeze(
|
|
1989
|
+
ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "carriage")
|
|
1990
|
+
);
|
|
1991
|
+
var VERIFIER_ERROR_CODES = Object.freeze(
|
|
1992
|
+
ERROR_CODES.filter((code) => ERROR_CODE_PART[code] === "B")
|
|
1993
|
+
);
|
|
1994
|
+
var SEVERITY = Object.freeze({
|
|
1995
|
+
MALFORMED_CBOR: "error",
|
|
1996
|
+
SCHEMA_TYPE_MISMATCH: "error",
|
|
1997
|
+
SCHEMA_MISSING_REQUIRED: "error",
|
|
1998
|
+
SCHEMA_UNKNOWN_FIELD: "error",
|
|
1999
|
+
SCHEMA_INVALID_LITERAL: "error",
|
|
2000
|
+
SCHEMA_EMPTY_RECORD: "error",
|
|
2001
|
+
HASH_DIGEST_LENGTH_MISMATCH: "error",
|
|
2002
|
+
UNSUPPORTED_HASH_ALG: "error",
|
|
2003
|
+
UNSUPPORTED_MERKLE_COMMIT_ALG: "error",
|
|
2004
|
+
SCHEMA_MERKLE_LEAF_COUNT_INVALID: "error",
|
|
2005
|
+
INVALID_URI: "error",
|
|
2006
|
+
CHUNK_TOO_LARGE: "error",
|
|
2007
|
+
UNAUTHENTICATED_CIPHER_FORBIDDEN: "error",
|
|
2008
|
+
UNSUPPORTED_AEAD_ALG: "error",
|
|
2009
|
+
NONCE_LENGTH_MISMATCH: "error",
|
|
2010
|
+
UNSUPPORTED_ENVELOPE_SCHEME: "error",
|
|
2011
|
+
ENC_UNSUPPORTED: "info",
|
|
2012
|
+
ENC_SLOTS_EMPTY: "error",
|
|
2013
|
+
ENC_SLOT_INVALID_SHAPE: "error",
|
|
2014
|
+
UNSUPPORTED_KEM_ALG: "error",
|
|
2015
|
+
ENC_KEM_REQUIRED: "error",
|
|
2016
|
+
KEM_EPK_LENGTH_MISMATCH: "error",
|
|
2017
|
+
KEM_CT_LENGTH_MISMATCH: "error",
|
|
2018
|
+
WRAP_LENGTH_MISMATCH: "error",
|
|
2019
|
+
ENC_SLOTS_MAC_INVALID_LENGTH: "error",
|
|
2020
|
+
ENC_SLOTS_MAC_REQUIRED: "error",
|
|
2021
|
+
ENC_SLOTS_REQUIRED: "error",
|
|
2022
|
+
ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "error",
|
|
2023
|
+
ENC_SLOTS_TOO_MANY: "error",
|
|
2024
|
+
ENC_ENVELOPE_TOO_LARGE: "error",
|
|
2025
|
+
ENC_EXCLUSIVITY_VIOLATION: "error",
|
|
2026
|
+
ENC_NO_KEY_PATH: "error",
|
|
2027
|
+
ENC_REQUIRES_CONTENT_HASH: "error",
|
|
2028
|
+
ENC_PASSPHRASE_ALG_UNSUPPORTED: "error",
|
|
2029
|
+
ENC_PASSPHRASE_SALT_TOO_SHORT: "error",
|
|
2030
|
+
ENC_PASSPHRASE_SALT_TOO_LONG: "error",
|
|
2031
|
+
ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "error",
|
|
2032
|
+
ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "error",
|
|
2033
|
+
MALFORMED_SIG_COSE_SIGN1: "error",
|
|
2034
|
+
SIGNATURE_UNSUPPORTED: "info",
|
|
2035
|
+
SIG_ENTRY_INVALID_SHAPE: "error",
|
|
2036
|
+
SIG_ENTRY_KID_COSE_KEY_CONFLICT: "error",
|
|
2037
|
+
SIG_PRIVATE_KEY_LEAKED: "error",
|
|
2038
|
+
SUPERSEDES_TX_INVALID_LENGTH: "error",
|
|
2039
|
+
EXTENSION_UNSUPPORTED_CRITICAL: "error",
|
|
2040
|
+
CRIT_SHAPE_INVALID: "error",
|
|
2041
|
+
TX_NOT_FOUND: "error",
|
|
2042
|
+
PROVIDER_UNAVAILABLE: "error",
|
|
2043
|
+
TX_INTEGRITY_MISMATCH: "error",
|
|
2044
|
+
METADATA_NOT_FOUND: "error",
|
|
2045
|
+
INSUFFICIENT_CONFIRMATIONS: "info",
|
|
2046
|
+
SIGNATURE_INVALID: "error",
|
|
2047
|
+
SIGNER_KEY_UNRESOLVED: "error",
|
|
2048
|
+
WALLET_ADDRESS_MISMATCH: "error",
|
|
2049
|
+
URI_TARGET_FORBIDDEN: "error",
|
|
2050
|
+
URI_INTEGRITY_MISMATCH: "error",
|
|
2051
|
+
URI_PROVIDER_INTEGRITY_MISMATCH: "warning",
|
|
2052
|
+
URI_FETCH_FAILED: "warning",
|
|
2053
|
+
CONTENT_UNAVAILABLE: "error",
|
|
2054
|
+
CONTENT_FETCH_LIMIT_EXCEEDED: "error",
|
|
2055
|
+
CIPHERTEXT_UNAVAILABLE: "error",
|
|
2056
|
+
SERVICE_INDEPENDENCE_VIOLATION: "error",
|
|
2057
|
+
WRONG_DECRYPTION_INPUT_SHAPE: "error",
|
|
2058
|
+
WRONG_RECIPIENT_KEY: "error",
|
|
2059
|
+
TAMPERED_HEADER: "error",
|
|
2060
|
+
TAMPERED_CIPHERTEXT: "error",
|
|
2061
|
+
KDF_DERIVATION_FAILED: "error",
|
|
2062
|
+
ENC_PASSPHRASE_UNNORMALIZABLE: "error",
|
|
2063
|
+
ENC_PASSPHRASE_EMPTY: "error",
|
|
2064
|
+
SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "error",
|
|
2065
|
+
SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "error",
|
|
2066
|
+
SCHEMA_MERKLE_LEAVES_MALFORMED: "error",
|
|
2067
|
+
MERKLE_ROOT_MISMATCH: "error",
|
|
2068
|
+
MERKLE_LEAVES_UNAVAILABLE: "warning",
|
|
2069
|
+
MERKLE_UNSUPPORTED: "info",
|
|
2070
|
+
OUT_OF_PROFILE_SKIPPED: "info"
|
|
2071
|
+
});
|
|
2072
|
+
var DUAL_SEVERITY_CODES = /* @__PURE__ */ new Set([
|
|
2073
|
+
"ENC_UNSUPPORTED",
|
|
2074
|
+
"MERKLE_LEAVES_UNAVAILABLE",
|
|
2075
|
+
"MERKLE_UNSUPPORTED",
|
|
2076
|
+
"OUT_OF_PROFILE_SKIPPED"
|
|
2077
|
+
]);
|
|
2078
|
+
function severityOf(code) {
|
|
2079
|
+
return SEVERITY[code];
|
|
1829
2080
|
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
};
|
|
1836
|
-
if (enc.kem !== void 0) out["kem"] = enc.kem;
|
|
1837
|
-
if (enc.slots !== void 0) out["slots"] = enc.slots.map(slotToCbor);
|
|
1838
|
-
if (enc.slots_mac !== void 0) out["slots_mac"] = enc.slots_mac;
|
|
1839
|
-
if (enc.passphrase !== void 0) out["passphrase"] = passphraseToCbor(enc.passphrase);
|
|
1840
|
-
return out;
|
|
2081
|
+
var REGISTRY_INDEX = new Map(
|
|
2082
|
+
ERROR_CODES.map((code, index) => [code, index])
|
|
2083
|
+
);
|
|
2084
|
+
function errorCodeRegistryIndex(code) {
|
|
2085
|
+
return REGISTRY_INDEX.get(code);
|
|
1841
2086
|
}
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2087
|
+
|
|
2088
|
+
// src/carriage.ts
|
|
2089
|
+
var TRANSPORT_CHUNK_MAX_BYTES = 64;
|
|
2090
|
+
function chunkRecordBody(body) {
|
|
2091
|
+
if (body.length === 0) {
|
|
2092
|
+
throw new RangeError("record body must be non-empty; a CBOR value is at least one byte");
|
|
2093
|
+
}
|
|
2094
|
+
const chunks = [];
|
|
2095
|
+
for (let offset = 0; offset < body.length; offset += TRANSPORT_CHUNK_MAX_BYTES) {
|
|
2096
|
+
chunks.push(body.slice(offset, Math.min(offset + TRANSPORT_CHUNK_MAX_BYTES, body.length)));
|
|
1845
2097
|
}
|
|
1846
|
-
return
|
|
2098
|
+
return chunks;
|
|
1847
2099
|
}
|
|
1848
|
-
function
|
|
1849
|
-
return
|
|
1850
|
-
alg: pp.alg,
|
|
1851
|
-
salt: pp.salt,
|
|
1852
|
-
params: pp.params
|
|
1853
|
-
};
|
|
2100
|
+
function encodeLabel309Value(body) {
|
|
2101
|
+
return encodeCanonicalCbor(chunkRecordBody(body));
|
|
1854
2102
|
}
|
|
1855
|
-
function
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
2103
|
+
function reassembleLabel309Value(valueBytes) {
|
|
2104
|
+
let decoded;
|
|
2105
|
+
try {
|
|
2106
|
+
decoded = decodeCanonicalCbor(valueBytes);
|
|
2107
|
+
} catch (cause) {
|
|
2108
|
+
return failure(
|
|
2109
|
+
"MALFORMED_CBOR",
|
|
2110
|
+
`label-309 value failed to decode: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
2111
|
+
);
|
|
1859
2112
|
}
|
|
1860
|
-
|
|
2113
|
+
if (!Array.isArray(decoded)) {
|
|
2114
|
+
return failure(
|
|
2115
|
+
"MALFORMED_CBOR",
|
|
2116
|
+
"label-309 value must be the whole-body chunk array (a CBOR array of byte strings), regardless of body length"
|
|
2117
|
+
);
|
|
2118
|
+
}
|
|
2119
|
+
let total = 0;
|
|
2120
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
2121
|
+
const element = decoded[i];
|
|
2122
|
+
if (!(element instanceof Uint8Array)) {
|
|
2123
|
+
return failure("MALFORMED_CBOR", `chunk array element ${i} is not a byte string`);
|
|
2124
|
+
}
|
|
2125
|
+
if (element.length > TRANSPORT_CHUNK_MAX_BYTES) {
|
|
2126
|
+
return failure(
|
|
2127
|
+
"CHUNK_TOO_LARGE",
|
|
2128
|
+
`chunk array element ${i} is ${element.length} bytes; the ledger caps metadata byte strings at ${TRANSPORT_CHUNK_MAX_BYTES}`
|
|
2129
|
+
);
|
|
2130
|
+
}
|
|
2131
|
+
total += element.length;
|
|
2132
|
+
}
|
|
2133
|
+
const body = new Uint8Array(total);
|
|
2134
|
+
let offset = 0;
|
|
2135
|
+
for (const element of decoded) {
|
|
2136
|
+
body.set(element, offset);
|
|
2137
|
+
offset += element.length;
|
|
2138
|
+
}
|
|
2139
|
+
return { ok: true, body };
|
|
2140
|
+
}
|
|
2141
|
+
function failure(code, message) {
|
|
2142
|
+
return { ok: false, issue: { code, path: [], message, severity: SEVERITY[code] } };
|
|
1861
2143
|
}
|
|
1862
2144
|
|
|
1863
2145
|
// ../../node_modules/.pnpm/@noble+ed25519@3.1.0/node_modules/@noble/ed25519/index.js
|
|
@@ -2389,25 +2671,54 @@ function decodeCoseSign1(bytes) {
|
|
|
2389
2671
|
signature: signatureRaw
|
|
2390
2672
|
};
|
|
2391
2673
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2674
|
+
var CARDANO_POE_ITEM_HASHES_PREFIX = new TextEncoder().encode(
|
|
2675
|
+
"cardano-poe-item-hashes-v1"
|
|
2676
|
+
);
|
|
2394
2677
|
var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
|
|
2395
2678
|
"cardano-poe-slots-transcript-v1"
|
|
2396
2679
|
);
|
|
2680
|
+
var CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX = new TextEncoder().encode(
|
|
2681
|
+
"cardano-poe-passphrase-transcript-v1"
|
|
2682
|
+
);
|
|
2683
|
+
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
2684
|
+
"cardano-poe-slots-mac-v1"
|
|
2685
|
+
);
|
|
2686
|
+
var CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC = new TextEncoder().encode(
|
|
2687
|
+
"cardano-poe-passphrase-mac-v1"
|
|
2688
|
+
);
|
|
2397
2689
|
var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
|
|
2398
2690
|
"cardano-poe-payload-v1"
|
|
2399
2691
|
);
|
|
2400
2692
|
var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
|
|
2401
2693
|
"cardano-poe-payload-passphrase-v1"
|
|
2402
2694
|
);
|
|
2695
|
+
var CARDANO_POE_X25519_KEK_SALT_PREFIX = new TextEncoder().encode(
|
|
2696
|
+
"cardano-poe-x25519-kek-salt-v1"
|
|
2697
|
+
);
|
|
2403
2698
|
var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
|
|
2404
2699
|
"cardano-poe-xwing-kek-salt-v1"
|
|
2405
2700
|
);
|
|
2701
|
+
if (CARDANO_POE_ITEM_HASHES_PREFIX.length !== 26) {
|
|
2702
|
+
throw new Error("CARDANO_POE_ITEM_HASHES_PREFIX byte-length invariant violated (expected 26)");
|
|
2703
|
+
}
|
|
2406
2704
|
if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
|
|
2407
2705
|
throw new Error(
|
|
2408
2706
|
"CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
|
|
2409
2707
|
);
|
|
2410
2708
|
}
|
|
2709
|
+
if (CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX.length !== 36) {
|
|
2710
|
+
throw new Error(
|
|
2711
|
+
"CARDANO_POE_PASSPHRASE_TRANSCRIPT_PREFIX byte-length invariant violated (expected 36)"
|
|
2712
|
+
);
|
|
2713
|
+
}
|
|
2714
|
+
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
2715
|
+
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
2716
|
+
}
|
|
2717
|
+
if (CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC.length !== 29) {
|
|
2718
|
+
throw new Error(
|
|
2719
|
+
"CARDANO_POE_HKDF_INFO_PASSPHRASE_MAC byte-length invariant violated (expected 29)"
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2411
2722
|
if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
|
|
2412
2723
|
throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
|
|
2413
2724
|
}
|
|
@@ -2416,6 +2727,11 @@ if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
|
|
|
2416
2727
|
"CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
|
|
2417
2728
|
);
|
|
2418
2729
|
}
|
|
2730
|
+
if (CARDANO_POE_X25519_KEK_SALT_PREFIX.length !== 30) {
|
|
2731
|
+
throw new Error(
|
|
2732
|
+
"CARDANO_POE_X25519_KEK_SALT_PREFIX byte-length invariant violated (expected 30)"
|
|
2733
|
+
);
|
|
2734
|
+
}
|
|
2419
2735
|
if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
|
|
2420
2736
|
throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
|
|
2421
2737
|
}
|
|
@@ -2425,9 +2741,6 @@ var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
|
|
|
2425
2741
|
var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
|
|
2426
2742
|
"cardano-poe-kek-mlkem768x25519-v1"
|
|
2427
2743
|
);
|
|
2428
|
-
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
2429
|
-
"cardano-poe-slots-mac-v1"
|
|
2430
|
-
);
|
|
2431
2744
|
var ZERO_NONCE_12 = new Uint8Array(12);
|
|
2432
2745
|
if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
|
|
2433
2746
|
throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
|
|
@@ -2437,235 +2750,10 @@ if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
|
|
|
2437
2750
|
"CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
|
|
2438
2751
|
);
|
|
2439
2752
|
}
|
|
2440
|
-
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
2441
|
-
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
2442
|
-
}
|
|
2443
2753
|
if (ZERO_NONCE_12.length !== 12) {
|
|
2444
2754
|
throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
|
|
2445
2755
|
}
|
|
2446
|
-
|
|
2447
|
-
// src/chunked.ts
|
|
2448
|
-
var CHUNK_MAX_BYTES = 64;
|
|
2449
|
-
var UTF8_ENCODER2 = new TextEncoder();
|
|
2450
|
-
function chunkBytes(value) {
|
|
2451
|
-
if (value.length === 0) return [new Uint8Array(0)];
|
|
2452
|
-
const chunks = [];
|
|
2453
|
-
for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
|
|
2454
|
-
chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
|
|
2455
|
-
}
|
|
2456
|
-
return chunks;
|
|
2457
|
-
}
|
|
2458
|
-
function bytesChunkArrayConcat(chunks) {
|
|
2459
|
-
let total = 0;
|
|
2460
|
-
for (const c5 of chunks) total += c5.length;
|
|
2461
|
-
const out = new Uint8Array(total);
|
|
2462
|
-
let offset = 0;
|
|
2463
|
-
for (const c5 of chunks) {
|
|
2464
|
-
out.set(c5, offset);
|
|
2465
|
-
offset += c5.length;
|
|
2466
|
-
}
|
|
2467
|
-
return out;
|
|
2468
|
-
}
|
|
2469
|
-
function reconstructChunkedUri(chunks) {
|
|
2470
|
-
const merged = bytesChunkArrayConcat(chunks.map((c5) => UTF8_ENCODER2.encode(c5)));
|
|
2471
|
-
try {
|
|
2472
|
-
const uri = new TextDecoder("utf-8", { fatal: true }).decode(merged);
|
|
2473
|
-
return { ok: true, uri };
|
|
2474
|
-
} catch (cause) {
|
|
2475
|
-
return {
|
|
2476
|
-
ok: false,
|
|
2477
|
-
code: "INVALID_URI",
|
|
2478
|
-
reason: cause instanceof Error ? cause.message : String(cause)
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
function chunkUri(uri) {
|
|
2483
|
-
const bytes = UTF8_ENCODER2.encode(uri);
|
|
2484
|
-
if (bytes.length === 0) return [""];
|
|
2485
|
-
if (bytes.length <= CHUNK_MAX_BYTES) return [uri];
|
|
2486
|
-
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
2487
|
-
const chunks = [];
|
|
2488
|
-
let cursor = 0;
|
|
2489
|
-
while (cursor < bytes.length) {
|
|
2490
|
-
let end = Math.min(cursor + CHUNK_MAX_BYTES, bytes.length);
|
|
2491
|
-
while (end < bytes.length && (bytes[end] & 192) === 128) end--;
|
|
2492
|
-
chunks.push(decoder.decode(bytes.subarray(cursor, end)));
|
|
2493
|
-
cursor = end;
|
|
2494
|
-
}
|
|
2495
|
-
return chunks;
|
|
2496
|
-
}
|
|
2497
|
-
|
|
2498
|
-
// src/error-codes.ts
|
|
2499
|
-
var STRUCTURAL_ERROR_CODES = [
|
|
2500
|
-
// CBOR decode layer. A single code covers every canonical-decode failure —
|
|
2501
|
-
// malformed/truncated bytes, indefinite-length encodings, non-canonical
|
|
2502
|
-
// (unsorted) map-key ordering, duplicate map keys, non-minimal integers, and
|
|
2503
|
-
// invalid UTF-8 — by design (no separate duplicate-key code).
|
|
2504
|
-
"MALFORMED_CBOR",
|
|
2505
|
-
// Generic schema-layer
|
|
2506
|
-
"SCHEMA_TYPE_MISMATCH",
|
|
2507
|
-
"SCHEMA_MISSING_REQUIRED",
|
|
2508
|
-
"SCHEMA_UNKNOWN_FIELD",
|
|
2509
|
-
"SCHEMA_INVALID_LITERAL",
|
|
2510
|
-
"SCHEMA_EMPTY_RECORD",
|
|
2511
|
-
// Hash-map
|
|
2512
|
-
"HASH_DIGEST_LENGTH_MISMATCH",
|
|
2513
|
-
"UNSUPPORTED_HASH_ALG",
|
|
2514
|
-
// Top-level `merkle[]`
|
|
2515
|
-
"UNSUPPORTED_MERKLE_COMMIT_ALG",
|
|
2516
|
-
// URI / chunking. A chunk whose bytes do not reconstruct to valid UTF-8
|
|
2517
|
-
// surfaces as MALFORMED_CBOR at decode (cbor2 rejects invalid-UTF-8 tstr)
|
|
2518
|
-
// or, in the residual reconstruct guard, as INVALID_URI — there is no
|
|
2519
|
-
// separate codepoint-split code.
|
|
2520
|
-
"INVALID_URI",
|
|
2521
|
-
"CHUNK_TOO_LARGE",
|
|
2522
|
-
// Encryption envelope
|
|
2523
|
-
"UNAUTHENTICATED_CIPHER_FORBIDDEN",
|
|
2524
|
-
"UNSUPPORTED_AEAD_ALG",
|
|
2525
|
-
"NONCE_LENGTH_MISMATCH",
|
|
2526
|
-
"UNSUPPORTED_ENVELOPE_SCHEME",
|
|
2527
|
-
"ENC_SLOTS_EMPTY",
|
|
2528
|
-
"ENC_SLOT_INVALID_SHAPE",
|
|
2529
|
-
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
2530
|
-
"ENC_SLOTS_TOO_MANY",
|
|
2531
|
-
"ENC_ENVELOPE_TOO_LARGE",
|
|
2532
|
-
"UNSUPPORTED_KEM_ALG",
|
|
2533
|
-
"ENC_KEM_REQUIRED",
|
|
2534
|
-
"KEM_EPK_LENGTH_MISMATCH",
|
|
2535
|
-
"KEM_CT_LENGTH_MISMATCH",
|
|
2536
|
-
"WRAP_LENGTH_MISMATCH",
|
|
2537
|
-
"ENC_SLOTS_MAC_INVALID_LENGTH",
|
|
2538
|
-
"ENC_SLOTS_MAC_REQUIRED",
|
|
2539
|
-
"ENC_SLOTS_REQUIRED",
|
|
2540
|
-
"ENC_EXCLUSIVITY_VIOLATION",
|
|
2541
|
-
"ENC_NO_KEY_PATH",
|
|
2542
|
-
"ENC_REQUIRES_CONTENT_HASH",
|
|
2543
|
-
"ENC_PASSPHRASE_ALG_UNSUPPORTED",
|
|
2544
|
-
"ENC_PASSPHRASE_SALT_TOO_SHORT",
|
|
2545
|
-
"ENC_PASSPHRASE_SALT_TOO_LONG",
|
|
2546
|
-
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
2547
|
-
"ENC_PASSPHRASE_PARAMS_EXCEED_POLICY",
|
|
2548
|
-
// Signatures
|
|
2549
|
-
"MALFORMED_SIG_COSE_SIGN1",
|
|
2550
|
-
"SIGNATURE_UNSUPPORTED",
|
|
2551
|
-
"SIG_ENTRY_INVALID_SHAPE",
|
|
2552
|
-
"SIG_ENTRY_KID_COSE_KEY_CONFLICT",
|
|
2553
|
-
"SIG_PRIVATE_KEY_LEAKED",
|
|
2554
|
-
// Supersedence
|
|
2555
|
-
"SUPERSEDES_TX_INVALID_LENGTH",
|
|
2556
|
-
// Forward-compat critical extensions
|
|
2557
|
-
"EXTENSION_UNSUPPORTED_CRITICAL",
|
|
2558
|
-
"CRIT_SHAPE_INVALID"
|
|
2559
|
-
];
|
|
2560
|
-
var VERIFIER_ERROR_CODES = [
|
|
2561
|
-
"METADATA_NOT_FOUND",
|
|
2562
|
-
"INSUFFICIENT_CONFIRMATIONS",
|
|
2563
|
-
"SIGNATURE_INVALID",
|
|
2564
|
-
"SIGNER_KEY_UNRESOLVED",
|
|
2565
|
-
"WALLET_ADDRESS_MISMATCH",
|
|
2566
|
-
"URI_TARGET_FORBIDDEN",
|
|
2567
|
-
"URI_INTEGRITY_MISMATCH",
|
|
2568
|
-
"URI_FETCH_FAILED",
|
|
2569
|
-
"CONTENT_UNAVAILABLE",
|
|
2570
|
-
"CIPHERTEXT_UNAVAILABLE",
|
|
2571
|
-
"PROVIDER_UNAVAILABLE",
|
|
2572
|
-
"SERVICE_INDEPENDENCE_VIOLATION",
|
|
2573
|
-
"WRONG_DECRYPTION_INPUT_SHAPE",
|
|
2574
|
-
"WRONG_RECIPIENT_KEY",
|
|
2575
|
-
"TAMPERED_HEADER",
|
|
2576
|
-
"TAMPERED_CIPHERTEXT",
|
|
2577
|
-
"KDF_DERIVATION_FAILED",
|
|
2578
|
-
"SCHEMA_MERKLE_LEAF_COUNT_MISMATCH",
|
|
2579
|
-
"SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED",
|
|
2580
|
-
"SCHEMA_MERKLE_LEAVES_MALFORMED",
|
|
2581
|
-
"MERKLE_ROOT_MISMATCH",
|
|
2582
|
-
"MERKLE_LEAVES_UNAVAILABLE",
|
|
2583
|
-
"MERKLE_LEAVES_INFORMATIVE_FORM",
|
|
2584
|
-
"MERKLE_UNSUPPORTED",
|
|
2585
|
-
"OUT_OF_PROFILE_SKIPPED"
|
|
2586
|
-
];
|
|
2587
|
-
var ERROR_CODES = [...STRUCTURAL_ERROR_CODES, ...VERIFIER_ERROR_CODES];
|
|
2588
|
-
var SEVERITY = Object.freeze({
|
|
2589
|
-
// --- Part A ---
|
|
2590
|
-
MALFORMED_CBOR: "error",
|
|
2591
|
-
SCHEMA_TYPE_MISMATCH: "error",
|
|
2592
|
-
SCHEMA_MISSING_REQUIRED: "error",
|
|
2593
|
-
SCHEMA_UNKNOWN_FIELD: "error",
|
|
2594
|
-
SCHEMA_INVALID_LITERAL: "error",
|
|
2595
|
-
SCHEMA_EMPTY_RECORD: "error",
|
|
2596
|
-
HASH_DIGEST_LENGTH_MISMATCH: "error",
|
|
2597
|
-
UNSUPPORTED_HASH_ALG: "error",
|
|
2598
|
-
UNSUPPORTED_MERKLE_COMMIT_ALG: "error",
|
|
2599
|
-
INVALID_URI: "error",
|
|
2600
|
-
CHUNK_TOO_LARGE: "error",
|
|
2601
|
-
UNAUTHENTICATED_CIPHER_FORBIDDEN: "error",
|
|
2602
|
-
UNSUPPORTED_AEAD_ALG: "error",
|
|
2603
|
-
NONCE_LENGTH_MISMATCH: "error",
|
|
2604
|
-
UNSUPPORTED_ENVELOPE_SCHEME: "error",
|
|
2605
|
-
ENC_SLOTS_EMPTY: "error",
|
|
2606
|
-
ENC_SLOT_INVALID_SHAPE: "error",
|
|
2607
|
-
ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "error",
|
|
2608
|
-
ENC_SLOTS_TOO_MANY: "error",
|
|
2609
|
-
ENC_ENVELOPE_TOO_LARGE: "error",
|
|
2610
|
-
UNSUPPORTED_KEM_ALG: "error",
|
|
2611
|
-
ENC_KEM_REQUIRED: "error",
|
|
2612
|
-
KEM_EPK_LENGTH_MISMATCH: "error",
|
|
2613
|
-
KEM_CT_LENGTH_MISMATCH: "error",
|
|
2614
|
-
WRAP_LENGTH_MISMATCH: "error",
|
|
2615
|
-
ENC_SLOTS_MAC_INVALID_LENGTH: "error",
|
|
2616
|
-
ENC_SLOTS_MAC_REQUIRED: "error",
|
|
2617
|
-
ENC_SLOTS_REQUIRED: "error",
|
|
2618
|
-
ENC_EXCLUSIVITY_VIOLATION: "error",
|
|
2619
|
-
ENC_NO_KEY_PATH: "error",
|
|
2620
|
-
ENC_REQUIRES_CONTENT_HASH: "error",
|
|
2621
|
-
ENC_PASSPHRASE_ALG_UNSUPPORTED: "error",
|
|
2622
|
-
ENC_PASSPHRASE_SALT_TOO_SHORT: "error",
|
|
2623
|
-
ENC_PASSPHRASE_SALT_TOO_LONG: "error",
|
|
2624
|
-
ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "error",
|
|
2625
|
-
ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "error",
|
|
2626
|
-
MALFORMED_SIG_COSE_SIGN1: "error",
|
|
2627
|
-
SIGNATURE_UNSUPPORTED: "info",
|
|
2628
|
-
SIG_ENTRY_INVALID_SHAPE: "error",
|
|
2629
|
-
SIG_ENTRY_KID_COSE_KEY_CONFLICT: "error",
|
|
2630
|
-
SIG_PRIVATE_KEY_LEAKED: "error",
|
|
2631
|
-
SUPERSEDES_TX_INVALID_LENGTH: "error",
|
|
2632
|
-
EXTENSION_UNSUPPORTED_CRITICAL: "error",
|
|
2633
|
-
CRIT_SHAPE_INVALID: "error",
|
|
2634
|
-
// --- Part B ---
|
|
2635
|
-
METADATA_NOT_FOUND: "error",
|
|
2636
|
-
INSUFFICIENT_CONFIRMATIONS: "info",
|
|
2637
|
-
SIGNATURE_INVALID: "error",
|
|
2638
|
-
SIGNER_KEY_UNRESOLVED: "error",
|
|
2639
|
-
WALLET_ADDRESS_MISMATCH: "error",
|
|
2640
|
-
URI_TARGET_FORBIDDEN: "error",
|
|
2641
|
-
URI_INTEGRITY_MISMATCH: "error",
|
|
2642
|
-
URI_FETCH_FAILED: "warning",
|
|
2643
|
-
CONTENT_UNAVAILABLE: "error",
|
|
2644
|
-
CIPHERTEXT_UNAVAILABLE: "error",
|
|
2645
|
-
PROVIDER_UNAVAILABLE: "error",
|
|
2646
|
-
SERVICE_INDEPENDENCE_VIOLATION: "error",
|
|
2647
|
-
WRONG_DECRYPTION_INPUT_SHAPE: "error",
|
|
2648
|
-
WRONG_RECIPIENT_KEY: "error",
|
|
2649
|
-
TAMPERED_HEADER: "error",
|
|
2650
|
-
TAMPERED_CIPHERTEXT: "error",
|
|
2651
|
-
KDF_DERIVATION_FAILED: "error",
|
|
2652
|
-
SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "error",
|
|
2653
|
-
SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "error",
|
|
2654
|
-
SCHEMA_MERKLE_LEAVES_MALFORMED: "error",
|
|
2655
|
-
MERKLE_ROOT_MISMATCH: "error",
|
|
2656
|
-
MERKLE_LEAVES_UNAVAILABLE: "warning",
|
|
2657
|
-
MERKLE_LEAVES_INFORMATIVE_FORM: "info",
|
|
2658
|
-
// Dual-severity — default reading is `info`; the verifier promotes to
|
|
2659
|
-
// `error` for merkle-only records (no `items[]` content claim was
|
|
2660
|
-
// validated in the same record).
|
|
2661
|
-
MERKLE_UNSUPPORTED: "info",
|
|
2662
|
-
// Dual-severity — default reading is `info` (render mode); strict
|
|
2663
|
-
// end-to-end verifiers promote to `error`.
|
|
2664
|
-
OUT_OF_PROFILE_SKIPPED: "info"
|
|
2665
|
-
});
|
|
2666
|
-
function severityOf(code) {
|
|
2667
|
-
return SEVERITY[code];
|
|
2668
|
-
}
|
|
2756
|
+
new TextEncoder();
|
|
2669
2757
|
|
|
2670
2758
|
// src/validator.ts
|
|
2671
2759
|
var HASH_ALG_LENGTHS = {
|
|
@@ -2676,9 +2764,9 @@ var MERKLE_COMMIT_ALG_LENGTHS = {
|
|
|
2676
2764
|
"rfc9162-sha256": 32
|
|
2677
2765
|
};
|
|
2678
2766
|
var AEAD_NONCE_LENGTHS = {
|
|
2679
|
-
"
|
|
2767
|
+
"chacha20-poly1305-stream64k": 24
|
|
2680
2768
|
};
|
|
2681
|
-
var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]
|
|
2769
|
+
var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]|$)|^(?:rc4|des|3des)(?:[-_]|$)/i;
|
|
2682
2770
|
var KEM_SLOT_DESCRIPTORS = {
|
|
2683
2771
|
x25519: { field: "epk", fieldLength: 32, wrapLength: 48 },
|
|
2684
2772
|
mlkem768x25519: { field: "kem_ct", fieldLength: 1120, wrapLength: 48 }
|
|
@@ -2687,17 +2775,33 @@ var KEM_FIELD_LENGTH_CODE = {
|
|
|
2687
2775
|
epk: "KEM_EPK_LENGTH_MISMATCH",
|
|
2688
2776
|
kem_ct: "KEM_CT_LENGTH_MISMATCH"
|
|
2689
2777
|
};
|
|
2690
|
-
var NONCE_LENGTH = 24;
|
|
2691
|
-
var SLOTS_MAC_LENGTH = 32;
|
|
2692
2778
|
var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
|
|
2693
2779
|
var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
|
|
2694
|
-
|
|
2780
|
+
var UINT32_MAX = 4294967295;
|
|
2781
|
+
var DEFAULT_PASSPHRASE_PARAMS_CEILING = Object.freeze({
|
|
2782
|
+
m: 2097152,
|
|
2783
|
+
// KiB = 2 GiB
|
|
2784
|
+
t: 16,
|
|
2785
|
+
p: 8
|
|
2786
|
+
});
|
|
2787
|
+
var EMPTY_EXTENSION_SET = /* @__PURE__ */ new Set();
|
|
2788
|
+
function resolveOptions(options) {
|
|
2789
|
+
return {
|
|
2790
|
+
supportedCriticalExtensions: options?.supportedCriticalExtensions ?? EMPTY_EXTENSION_SET,
|
|
2791
|
+
role: options?.role ?? "public",
|
|
2792
|
+
maxSlots: options?.maxSlots ?? MAX_SLOTS,
|
|
2793
|
+
maxEncEnvelopeBytes: options?.maxEncEnvelopeBytes ?? MAX_DECODED_ENVELOPE_BYTES,
|
|
2794
|
+
passphraseParamsCeiling: options?.passphraseParamsCeiling === void 0 ? DEFAULT_PASSPHRASE_PARAMS_CEILING : options.passphraseParamsCeiling
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function validatePoeRecord(bytes, options) {
|
|
2798
|
+
const opts = resolveOptions(options);
|
|
2695
2799
|
let decoded;
|
|
2696
2800
|
try {
|
|
2697
2801
|
decoded = decodeCanonicalCbor(bytes);
|
|
2698
2802
|
} catch (cause) {
|
|
2699
2803
|
return {
|
|
2700
|
-
|
|
2804
|
+
valid: false,
|
|
2701
2805
|
issues: [
|
|
2702
2806
|
{
|
|
2703
2807
|
code: "MALFORMED_CBOR",
|
|
@@ -2708,132 +2812,181 @@ function validatePoeRecord(bytes) {
|
|
|
2708
2812
|
]
|
|
2709
2813
|
};
|
|
2710
2814
|
}
|
|
2815
|
+
const nonTextKeyIssues = collectNonTextKeyMapIssues(decoded);
|
|
2816
|
+
if (nonTextKeyIssues.length > 0) {
|
|
2817
|
+
return { valid: false, issues: sortIssues(nonTextKeyIssues) };
|
|
2818
|
+
}
|
|
2711
2819
|
const parse = PoeRecordSchema.safeParse(decoded);
|
|
2712
2820
|
if (!parse.success) {
|
|
2713
|
-
|
|
2714
|
-
return { ok: false, issues };
|
|
2821
|
+
return { valid: false, issues: sortIssues(mapZodIssues(parse.error.issues, decoded)) };
|
|
2715
2822
|
}
|
|
2716
2823
|
const record = parse.data;
|
|
2717
|
-
const
|
|
2718
|
-
|
|
2719
|
-
const info = [];
|
|
2720
|
-
const itemsLen = Array.isArray(record.items) ? record.items.length : 0;
|
|
2721
|
-
const merkleLen = Array.isArray(record.merkle) ? record.merkle.length : 0;
|
|
2722
|
-
if (itemsLen === 0 && merkleLen === 0) {
|
|
2723
|
-
errors.push(
|
|
2724
|
-
issue(
|
|
2725
|
-
"SCHEMA_EMPTY_RECORD",
|
|
2726
|
-
[],
|
|
2727
|
-
"record must carry at least one of items[] or merkle[] non-empty"
|
|
2728
|
-
)
|
|
2729
|
-
);
|
|
2730
|
-
}
|
|
2824
|
+
const issues = [];
|
|
2825
|
+
checkContentCommitmentPresence(record, issues);
|
|
2731
2826
|
const decodedTopKeys = topLevelKeysOf(decoded);
|
|
2732
|
-
|
|
2733
|
-
for (const
|
|
2734
|
-
if (TOP_LEVEL_BASE_KEYS.has(
|
|
2735
|
-
if (isExtensionKey(
|
|
2736
|
-
|
|
2737
|
-
}
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2827
|
+
checkCrit(record, decodedTopKeys, opts.supportedCriticalExtensions, issues);
|
|
2828
|
+
for (const key of decodedTopKeys) {
|
|
2829
|
+
if (TOP_LEVEL_BASE_KEYS.has(key)) continue;
|
|
2830
|
+
if (isExtensionKey(key)) continue;
|
|
2831
|
+
issues.push(issueOf("SCHEMA_UNKNOWN_FIELD", [key], `unknown top-level field: ${key}`));
|
|
2832
|
+
}
|
|
2833
|
+
const items = record.items ?? [];
|
|
2834
|
+
for (let i = 0; i < items.length; i++) {
|
|
2835
|
+
const item = items[i];
|
|
2836
|
+
checkItemHashes(item, i, issues);
|
|
2837
|
+
if (item.uris !== void 0) checkUris(item.uris, ["items", i, "uris"], issues);
|
|
2838
|
+
if (item.enc !== void 0) checkItemEnc(item, i, opts, issues);
|
|
2839
|
+
}
|
|
2840
|
+
const merkle = record.merkle ?? [];
|
|
2841
|
+
for (let i = 0; i < merkle.length; i++) {
|
|
2842
|
+
checkMerkleCommit(merkle[i], i, issues);
|
|
2843
|
+
}
|
|
2844
|
+
if (record.sigs !== void 0) {
|
|
2845
|
+
if (record.sigs.length === 0) {
|
|
2846
|
+
issues.push(
|
|
2847
|
+
issueOf("SCHEMA_TYPE_MISMATCH", ["sigs"], "sigs[] must be non-empty when present")
|
|
2748
2848
|
);
|
|
2749
2849
|
}
|
|
2850
|
+
for (let i = 0; i < record.sigs.length; i++) {
|
|
2851
|
+
checkSigEntry(record.sigs[i], i, issues);
|
|
2852
|
+
}
|
|
2750
2853
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
if (item.uris) checkItemUris(item.uris, ["items", i, "uris"], errors);
|
|
2755
|
-
if (item.enc !== void 0) checkItemEnc(item, i, errors);
|
|
2756
|
-
}
|
|
2757
|
-
for (let i = 0; i < (record.merkle ?? []).length; i++) {
|
|
2758
|
-
const commit = record.merkle[i];
|
|
2759
|
-
checkMerkleCommit(commit, i, errors);
|
|
2854
|
+
const sorted = sortIssues(issues);
|
|
2855
|
+
if (sorted.some((issue) => issue.severity === "error")) {
|
|
2856
|
+
return { valid: false, issues: sorted };
|
|
2760
2857
|
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2858
|
+
const warnings = sorted.filter((issue) => issue.severity === "warning");
|
|
2859
|
+
const info = sorted.filter((issue) => issue.severity === "info");
|
|
2860
|
+
const result = { valid: true, record };
|
|
2861
|
+
if (warnings.length > 0) result.warnings = warnings;
|
|
2862
|
+
if (info.length > 0) result.info = info;
|
|
2863
|
+
return result;
|
|
2864
|
+
}
|
|
2865
|
+
function mapZodIssues(zissues, decodedRoot) {
|
|
2866
|
+
const out = [];
|
|
2867
|
+
for (const zissue of zissues) {
|
|
2868
|
+
if (zissue.code === "unrecognized_keys") {
|
|
2869
|
+
for (const key of zissue.keys) {
|
|
2870
|
+
const path = [...zissue.path, key];
|
|
2871
|
+
const code = unknownKeyCode(path);
|
|
2872
|
+
out.push(issueOf(code, path, `unrecognized key '${key}' in a closed map`));
|
|
2873
|
+
}
|
|
2874
|
+
continue;
|
|
2764
2875
|
}
|
|
2876
|
+
out.push(mapZodIssue(zissue, decodedRoot));
|
|
2765
2877
|
}
|
|
2766
|
-
|
|
2767
|
-
|
|
2878
|
+
return out;
|
|
2879
|
+
}
|
|
2880
|
+
function unknownKeyCode(path) {
|
|
2881
|
+
if (path.length >= 2 && path[0] === "sigs" && typeof path[1] === "number") {
|
|
2882
|
+
return "SIG_ENTRY_INVALID_SHAPE";
|
|
2768
2883
|
}
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2884
|
+
return "SCHEMA_UNKNOWN_FIELD";
|
|
2885
|
+
}
|
|
2886
|
+
function collectNonTextKeyMapIssues(decoded) {
|
|
2887
|
+
const issues = [];
|
|
2888
|
+
const flag = (path) => {
|
|
2889
|
+
issues.push(
|
|
2890
|
+
issueOf(
|
|
2891
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
2892
|
+
path,
|
|
2893
|
+
"CBOR map carries a non-text key where a text-keyed map is required"
|
|
2894
|
+
)
|
|
2895
|
+
);
|
|
2772
2896
|
};
|
|
2773
|
-
if (
|
|
2774
|
-
|
|
2775
|
-
|
|
2897
|
+
if (decoded instanceof Map) {
|
|
2898
|
+
flag([]);
|
|
2899
|
+
return issues;
|
|
2900
|
+
}
|
|
2901
|
+
if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded)) return issues;
|
|
2902
|
+
const record = decoded;
|
|
2903
|
+
for (const field of ["items", "merkle", "sigs"]) {
|
|
2904
|
+
const entries = record[field];
|
|
2905
|
+
if (!Array.isArray(entries)) continue;
|
|
2906
|
+
entries.forEach((entry, i) => {
|
|
2907
|
+
if (entry instanceof Map) {
|
|
2908
|
+
flag([field, i]);
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
if (field !== "items" || entry === null || typeof entry !== "object") return;
|
|
2912
|
+
const item = entry;
|
|
2913
|
+
if (item["hashes"] instanceof Map) flag([field, i, "hashes"]);
|
|
2914
|
+
if (item["enc"] instanceof Map) flag([field, i, "enc"]);
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
return issues;
|
|
2776
2918
|
}
|
|
2777
|
-
function mapZodIssue(zissue,
|
|
2919
|
+
function mapZodIssue(zissue, decodedRoot) {
|
|
2778
2920
|
const path = zissue.path;
|
|
2779
2921
|
const explicit = zissue.params?.code;
|
|
2780
2922
|
if (explicit !== void 0) {
|
|
2781
|
-
return
|
|
2923
|
+
return issueOf(explicit, path, zissue.message);
|
|
2924
|
+
}
|
|
2925
|
+
const valueAtIssue = valueAtPath(decodedRoot, path);
|
|
2926
|
+
if (valueAtIssue instanceof Map) {
|
|
2927
|
+
return issueOf(
|
|
2928
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
2929
|
+
path,
|
|
2930
|
+
"CBOR map carries a non-text key where a text-keyed map is required"
|
|
2931
|
+
);
|
|
2782
2932
|
}
|
|
2783
2933
|
const inSigsEntry = path.length >= 2 && path[0] === "sigs" && typeof path[1] === "number";
|
|
2784
|
-
const isInSlotEntry =
|
|
2785
|
-
if (path.length >= 5 && path[0] === "items" && typeof path[1] === "number" && path[2] === "enc" && path[3] === "slots" && typeof path[4] === "number") {
|
|
2786
|
-
return true;
|
|
2787
|
-
}
|
|
2788
|
-
if (path.length >= 2 && path[0] === "slots" && typeof path[1] === "number") {
|
|
2789
|
-
return true;
|
|
2790
|
-
}
|
|
2791
|
-
return false;
|
|
2792
|
-
})();
|
|
2793
|
-
const valueAtIssue = valueAtPath(decoded, path);
|
|
2934
|
+
const isInSlotEntry = path.length >= 2 && path[0] === "slots" && typeof path[1] === "number";
|
|
2794
2935
|
const isMissing = valueAtIssue === void 0;
|
|
2795
2936
|
switch (zissue.code) {
|
|
2796
2937
|
case "invalid_type":
|
|
2797
|
-
if (isInSlotEntry) return
|
|
2938
|
+
if (isInSlotEntry) return issueOf("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
|
|
2798
2939
|
if (isMissing) {
|
|
2799
|
-
if (inSigsEntry) return
|
|
2800
|
-
return
|
|
2940
|
+
if (inSigsEntry) return issueOf("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
|
|
2941
|
+
return issueOf("SCHEMA_MISSING_REQUIRED", path, zissue.message);
|
|
2801
2942
|
}
|
|
2802
|
-
if (inSigsEntry) return
|
|
2803
|
-
return
|
|
2943
|
+
if (inSigsEntry) return issueOf("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
|
|
2944
|
+
return issueOf("SCHEMA_TYPE_MISMATCH", path, zissue.message);
|
|
2804
2945
|
case "invalid_value":
|
|
2805
|
-
if (
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
path,
|
|
2809
|
-
zissue.message
|
|
2810
|
-
);
|
|
2811
|
-
}
|
|
2812
|
-
return issue("SCHEMA_INVALID_LITERAL", path, zissue.message);
|
|
2813
|
-
case "unrecognized_keys":
|
|
2814
|
-
if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
|
|
2815
|
-
if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
|
|
2816
|
-
return issue("SCHEMA_UNKNOWN_FIELD", path, zissue.message);
|
|
2946
|
+
if (isMissing) return issueOf("SCHEMA_MISSING_REQUIRED", path, zissue.message);
|
|
2947
|
+
return issueOf("SCHEMA_INVALID_LITERAL", path, zissue.message);
|
|
2948
|
+
case "invalid_union":
|
|
2817
2949
|
case "invalid_format":
|
|
2818
2950
|
case "too_big":
|
|
2819
2951
|
case "too_small":
|
|
2820
|
-
if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
|
|
2821
|
-
return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
|
|
2822
|
-
case "invalid_union":
|
|
2823
2952
|
case "invalid_key":
|
|
2824
2953
|
case "invalid_element":
|
|
2825
2954
|
case "custom":
|
|
2826
2955
|
default:
|
|
2827
|
-
if (isInSlotEntry) return
|
|
2828
|
-
if (inSigsEntry) return
|
|
2829
|
-
return
|
|
2956
|
+
if (isInSlotEntry) return issueOf("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
|
|
2957
|
+
if (inSigsEntry) return issueOf("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
|
|
2958
|
+
return issueOf("SCHEMA_TYPE_MISMATCH", path, zissue.message);
|
|
2830
2959
|
}
|
|
2831
2960
|
}
|
|
2832
|
-
function
|
|
2961
|
+
function checkContentCommitmentPresence(record, issues) {
|
|
2962
|
+
const itemsLen = record.items?.length ?? 0;
|
|
2963
|
+
const merkleLen = record.merkle?.length ?? 0;
|
|
2964
|
+
if (itemsLen === 0 && merkleLen === 0) {
|
|
2965
|
+
issues.push(
|
|
2966
|
+
issueOf(
|
|
2967
|
+
"SCHEMA_EMPTY_RECORD",
|
|
2968
|
+
[],
|
|
2969
|
+
"record must carry at least one of items[] or merkle[] non-empty"
|
|
2970
|
+
)
|
|
2971
|
+
);
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
if (record.items !== void 0 && itemsLen === 0) {
|
|
2975
|
+
issues.push(
|
|
2976
|
+
issueOf("SCHEMA_TYPE_MISMATCH", ["items"], "items[] must be non-empty when present")
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2979
|
+
if (record.merkle !== void 0 && merkleLen === 0) {
|
|
2980
|
+
issues.push(
|
|
2981
|
+
issueOf("SCHEMA_TYPE_MISMATCH", ["merkle"], "merkle[] must be non-empty when present")
|
|
2982
|
+
);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
function checkItemHashes(item, idx, issues) {
|
|
2833
2986
|
const entries = Object.entries(item.hashes);
|
|
2834
2987
|
if (entries.length === 0) {
|
|
2835
|
-
|
|
2836
|
-
|
|
2988
|
+
issues.push(
|
|
2989
|
+
issueOf(
|
|
2837
2990
|
"SCHEMA_TYPE_MISMATCH",
|
|
2838
2991
|
["items", idx, "hashes"],
|
|
2839
2992
|
"hashes must be a non-empty CBOR map of <alg-id> -> <digest>"
|
|
@@ -2843,15 +2996,15 @@ function checkItemHashes(item, idx, errors) {
|
|
|
2843
2996
|
}
|
|
2844
2997
|
for (const [alg, digest] of entries) {
|
|
2845
2998
|
if (!(alg in HASH_ALG_LENGTHS)) {
|
|
2846
|
-
|
|
2847
|
-
|
|
2999
|
+
issues.push(
|
|
3000
|
+
issueOf("UNSUPPORTED_HASH_ALG", ["items", idx, "hashes", alg], `unknown hash alg: ${alg}`)
|
|
2848
3001
|
);
|
|
2849
3002
|
continue;
|
|
2850
3003
|
}
|
|
2851
3004
|
const expected = HASH_ALG_LENGTHS[alg];
|
|
2852
3005
|
if (digest.length !== expected) {
|
|
2853
|
-
|
|
2854
|
-
|
|
3006
|
+
issues.push(
|
|
3007
|
+
issueOf(
|
|
2855
3008
|
"HASH_DIGEST_LENGTH_MISMATCH",
|
|
2856
3009
|
["items", idx, "hashes", alg],
|
|
2857
3010
|
`hashes['${alg}'] digest length ${digest.length} != ${expected}`
|
|
@@ -2860,35 +3013,33 @@ function checkItemHashes(item, idx, errors) {
|
|
|
2860
3013
|
}
|
|
2861
3014
|
}
|
|
2862
3015
|
}
|
|
2863
|
-
function
|
|
2864
|
-
uris.
|
|
2865
|
-
|
|
2866
|
-
function validateOneUri(chunks, path, errors) {
|
|
2867
|
-
const reconstructed = reconstructChunkedUri(chunks);
|
|
2868
|
-
if (!reconstructed.ok) {
|
|
2869
|
-
errors.push(issue(reconstructed.code, path, reconstructed.reason));
|
|
3016
|
+
function checkUris(uris, basePath, issues) {
|
|
3017
|
+
if (uris.length === 0) {
|
|
3018
|
+
issues.push(issueOf("SCHEMA_TYPE_MISMATCH", basePath, "uris[] must be non-empty when present"));
|
|
2870
3019
|
return;
|
|
2871
3020
|
}
|
|
2872
|
-
|
|
3021
|
+
uris.forEach((uri, ui) => checkOneUri(uri, [...basePath, ui], issues));
|
|
3022
|
+
}
|
|
3023
|
+
function checkOneUri(uri, path, issues) {
|
|
2873
3024
|
if (uri.includes("#")) {
|
|
2874
|
-
|
|
2875
|
-
|
|
3025
|
+
issues.push(
|
|
3026
|
+
issueOf("INVALID_URI", path, "URI contains a fragment identifier ('#'), which is forbidden")
|
|
2876
3027
|
);
|
|
2877
3028
|
return;
|
|
2878
3029
|
}
|
|
2879
3030
|
const sepIdx = uri.indexOf("://");
|
|
2880
3031
|
if (sepIdx <= 0 || !/^[a-z][a-z0-9+.-]*$/i.test(uri.slice(0, sepIdx))) {
|
|
2881
|
-
|
|
2882
|
-
|
|
3032
|
+
issues.push(
|
|
3033
|
+
issueOf("INVALID_URI", path, "URI is not absolute (missing scheme://hierarchical-part)")
|
|
2883
3034
|
);
|
|
2884
3035
|
return;
|
|
2885
3036
|
}
|
|
2886
3037
|
const scheme = uri.slice(0, sepIdx).toLowerCase();
|
|
2887
3038
|
const rest = uri.slice(sepIdx + "://".length);
|
|
2888
3039
|
if (scheme === "ar") {
|
|
2889
|
-
if (!/^
|
|
2890
|
-
|
|
2891
|
-
|
|
3040
|
+
if (!/^[A-Za-z0-9_-]{43}$/.test(rest)) {
|
|
3041
|
+
issues.push(
|
|
3042
|
+
issueOf(
|
|
2892
3043
|
"INVALID_URI",
|
|
2893
3044
|
path,
|
|
2894
3045
|
"ar:// URI does not match `^ar://[A-Za-z0-9_-]{43}$` (43-char base64url txid, no path/query/fragment)"
|
|
@@ -2901,315 +3052,286 @@ function validateOneUri(chunks, path, errors) {
|
|
|
2901
3052
|
const slashIdx = rest.indexOf("/");
|
|
2902
3053
|
const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
|
|
2903
3054
|
if (!validateCidProfile(cid)) {
|
|
2904
|
-
|
|
2905
|
-
|
|
3055
|
+
issues.push(
|
|
3056
|
+
issueOf("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
|
|
2906
3057
|
);
|
|
2907
3058
|
}
|
|
2908
3059
|
return;
|
|
2909
3060
|
}
|
|
2910
|
-
|
|
2911
|
-
|
|
3061
|
+
issues.push(
|
|
3062
|
+
issueOf("INVALID_URI", path, "unsupported URI scheme; v1 PoE URI set is {ar://, ipfs://}")
|
|
2912
3063
|
);
|
|
2913
3064
|
}
|
|
2914
|
-
function checkItemEnc(item, idx,
|
|
3065
|
+
function checkItemEnc(item, idx, opts, issues) {
|
|
3066
|
+
const encPath = ["items", idx, "enc"];
|
|
2915
3067
|
const hasContentHash = Object.keys(item.hashes).some((alg) => alg in HASH_ALG_LENGTHS);
|
|
2916
3068
|
if (!hasContentHash) {
|
|
2917
|
-
|
|
2918
|
-
|
|
3069
|
+
issues.push(
|
|
3070
|
+
issueOf(
|
|
2919
3071
|
"ENC_REQUIRES_CONTENT_HASH",
|
|
2920
|
-
|
|
2921
|
-
"item carries `enc` but `hashes` has no content-hash entry (sha2-256 or blake2b-256)"
|
|
3072
|
+
encPath,
|
|
3073
|
+
"item carries `enc` but `hashes` has no registered content-hash entry (sha2-256 or blake2b-256)"
|
|
2922
3074
|
)
|
|
2923
3075
|
);
|
|
3076
|
+
}
|
|
3077
|
+
const rawEnc = item.enc;
|
|
3078
|
+
if (rawEnc === null || typeof rawEnc !== "object" || Array.isArray(rawEnc) || rawEnc instanceof Uint8Array) {
|
|
3079
|
+
issues.push(issueOf("SCHEMA_TYPE_MISMATCH", encPath, "enc must be a CBOR map"));
|
|
2924
3080
|
return;
|
|
2925
3081
|
}
|
|
2926
|
-
const
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
3082
|
+
const enc = rawEnc;
|
|
3083
|
+
const envelopeBytes = encodeCanonicalCbor(rawEnc).length;
|
|
3084
|
+
if (envelopeBytes > opts.maxEncEnvelopeBytes) {
|
|
3085
|
+
issues.push(
|
|
3086
|
+
issueOf(
|
|
3087
|
+
"ENC_ENVELOPE_TOO_LARGE",
|
|
3088
|
+
encPath,
|
|
3089
|
+
`decoded envelope is ${envelopeBytes} bytes; the resource bound is ${opts.maxEncEnvelopeBytes}`
|
|
3090
|
+
)
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
const scheme = enc["scheme"];
|
|
3094
|
+
if (scheme === void 0) {
|
|
3095
|
+
issues.push(
|
|
3096
|
+
issueOf("SCHEMA_MISSING_REQUIRED", [...encPath, "scheme"], "enc.scheme is required")
|
|
3097
|
+
);
|
|
2935
3098
|
return;
|
|
2936
3099
|
}
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
"
|
|
2943
|
-
[...basePath, "scheme"],
|
|
2944
|
-
`enc.scheme must be the unsigned integer 1; got ${String(enc.scheme)}`
|
|
3100
|
+
if (!isUint(scheme)) {
|
|
3101
|
+
issues.push(
|
|
3102
|
+
issueOf(
|
|
3103
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3104
|
+
[...encPath, "scheme"],
|
|
3105
|
+
"enc.scheme must be a CBOR unsigned integer"
|
|
2945
3106
|
)
|
|
2946
3107
|
);
|
|
3108
|
+
return;
|
|
2947
3109
|
}
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
3110
|
+
const aead = enc["aead"];
|
|
3111
|
+
if (typeof aead === "string" && UNAUTHENTICATED_CIPHER_RE.test(aead)) {
|
|
3112
|
+
issues.push(
|
|
3113
|
+
issueOf(
|
|
2951
3114
|
"UNAUTHENTICATED_CIPHER_FORBIDDEN",
|
|
2952
|
-
[...
|
|
2953
|
-
`'${
|
|
3115
|
+
[...encPath, "aead"],
|
|
3116
|
+
`'${aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
|
|
2954
3117
|
)
|
|
2955
3118
|
);
|
|
2956
3119
|
return;
|
|
2957
3120
|
}
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
);
|
|
3121
|
+
const kem = enc["kem"];
|
|
3122
|
+
const unsupported = [];
|
|
3123
|
+
if (!(typeof scheme === "number" && scheme === 1)) {
|
|
3124
|
+
unsupported.push({ field: "scheme", code: "UNSUPPORTED_ENVELOPE_SCHEME", id: String(scheme) });
|
|
3125
|
+
}
|
|
3126
|
+
if (typeof kem === "string" && !(kem in KEM_SLOT_DESCRIPTORS)) {
|
|
3127
|
+
unsupported.push({ field: "kem", code: "UNSUPPORTED_KEM_ALG", id: kem });
|
|
3128
|
+
}
|
|
3129
|
+
if (typeof aead === "string" && !(aead in AEAD_NONCE_LENGTHS)) {
|
|
3130
|
+
unsupported.push({ field: "aead", code: "UNSUPPORTED_AEAD_ALG", id: aead });
|
|
3131
|
+
}
|
|
3132
|
+
if (unsupported.length > 0) {
|
|
3133
|
+
const named = unsupported.map((u3) => `${u3.field}=${u3.id}`).join(", ");
|
|
3134
|
+
const message = `envelope uses identifiers this implementation does not support (${named}); the envelope is opaque and only the content-hash claim is validated`;
|
|
3135
|
+
if (opts.role === "recipient_or_strict") {
|
|
3136
|
+
issues.push({ code: "ENC_UNSUPPORTED", path: encPath, message, severity: "error" });
|
|
3137
|
+
for (const u3 of unsupported) {
|
|
3138
|
+
issues.push(
|
|
3139
|
+
issueOf(u3.code, [...encPath, u3.field], `enc.${u3.field} '${u3.id}' is not supported`)
|
|
3140
|
+
);
|
|
3141
|
+
}
|
|
3142
|
+
} else {
|
|
3143
|
+
issues.push({ code: "ENC_UNSUPPORTED", path: encPath, message, severity: "info" });
|
|
3144
|
+
}
|
|
3145
|
+
return;
|
|
3146
|
+
}
|
|
3147
|
+
const internalMapIssues = encInternalNonTextKeyIssues(enc, encPath);
|
|
3148
|
+
if (internalMapIssues.length > 0) {
|
|
3149
|
+
issues.push(...internalMapIssues);
|
|
2962
3150
|
return;
|
|
2963
3151
|
}
|
|
3152
|
+
const encParse = EncScheme1Schema.safeParse(rawEnc);
|
|
3153
|
+
if (!encParse.success) {
|
|
3154
|
+
for (const mapped of mapZodIssues(encParse.error.issues, rawEnc)) {
|
|
3155
|
+
issues.push({ ...mapped, path: [...encPath, ...mapped.path] });
|
|
3156
|
+
}
|
|
3157
|
+
return;
|
|
3158
|
+
}
|
|
3159
|
+
checkScheme1Envelope(encParse.data, rawEnc, encPath, opts, issues);
|
|
3160
|
+
}
|
|
3161
|
+
function encInternalNonTextKeyIssues(enc, encPath) {
|
|
3162
|
+
const issues = [];
|
|
3163
|
+
const flag = (path) => {
|
|
3164
|
+
issues.push(
|
|
3165
|
+
issueOf(
|
|
3166
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3167
|
+
path,
|
|
3168
|
+
"CBOR map carries a non-text key where a text-keyed map is required"
|
|
3169
|
+
)
|
|
3170
|
+
);
|
|
3171
|
+
};
|
|
3172
|
+
const slots = enc["slots"];
|
|
3173
|
+
if (Array.isArray(slots)) {
|
|
3174
|
+
slots.forEach((slot, i) => {
|
|
3175
|
+
if (slot instanceof Map) flag([...encPath, "slots", i]);
|
|
3176
|
+
});
|
|
3177
|
+
}
|
|
3178
|
+
const passphrase = enc["passphrase"];
|
|
3179
|
+
if (passphrase instanceof Map) {
|
|
3180
|
+
flag([...encPath, "passphrase"]);
|
|
3181
|
+
} else if (passphrase !== null && typeof passphrase === "object" && !Array.isArray(passphrase)) {
|
|
3182
|
+
const params = passphrase["params"];
|
|
3183
|
+
if (params instanceof Map) flag([...encPath, "passphrase", "params"]);
|
|
3184
|
+
}
|
|
3185
|
+
return issues;
|
|
3186
|
+
}
|
|
3187
|
+
function checkScheme1Envelope(enc, rawEnc, encPath, opts, issues) {
|
|
2964
3188
|
const expectedNonceLen = AEAD_NONCE_LENGTHS[enc.aead];
|
|
2965
3189
|
if (enc.nonce.length !== expectedNonceLen) {
|
|
2966
|
-
|
|
2967
|
-
|
|
3190
|
+
issues.push(
|
|
3191
|
+
issueOf(
|
|
2968
3192
|
"NONCE_LENGTH_MISMATCH",
|
|
2969
|
-
[...
|
|
3193
|
+
[...encPath, "nonce"],
|
|
2970
3194
|
`nonce length ${enc.nonce.length} != ${expectedNonceLen} for ${enc.aead}`
|
|
2971
3195
|
)
|
|
2972
3196
|
);
|
|
2973
3197
|
}
|
|
2974
|
-
if (enc.kem !== void 0 && !(enc.kem in KEM_SLOT_DESCRIPTORS)) {
|
|
2975
|
-
errors.push(issue("UNSUPPORTED_KEM_ALG", [...basePath, "kem"], `unknown kem alg: ${enc.kem}`));
|
|
2976
|
-
}
|
|
2977
3198
|
const hasSlots = enc.slots !== void 0;
|
|
2978
3199
|
const hasSlotsMac = enc.slots_mac !== void 0;
|
|
2979
3200
|
const hasPassphrase = enc.passphrase !== void 0;
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
3201
|
+
const hasKem = enc.kem !== void 0;
|
|
3202
|
+
if (hasPassphrase && (hasSlots || hasSlotsMac || hasKem)) {
|
|
3203
|
+
issues.push(
|
|
3204
|
+
issueOf(
|
|
3205
|
+
"ENC_EXCLUSIVITY_VIOLATION",
|
|
3206
|
+
encPath,
|
|
3207
|
+
"enc.passphrase is mutually exclusive with kem / slots / slots_mac; exactly one key path is allowed"
|
|
3208
|
+
)
|
|
2983
3209
|
);
|
|
2984
3210
|
}
|
|
2985
3211
|
if (hasSlots && !hasSlotsMac) {
|
|
2986
|
-
|
|
2987
|
-
|
|
3212
|
+
issues.push(
|
|
3213
|
+
issueOf("ENC_SLOTS_MAC_REQUIRED", encPath, "enc.slots present but enc.slots_mac absent")
|
|
2988
3214
|
);
|
|
2989
3215
|
}
|
|
2990
3216
|
if (hasSlotsMac && !hasSlots) {
|
|
2991
|
-
|
|
2992
|
-
|
|
3217
|
+
issues.push(
|
|
3218
|
+
issueOf("ENC_SLOTS_REQUIRED", encPath, "enc.slots_mac present but enc.slots absent")
|
|
2993
3219
|
);
|
|
2994
3220
|
}
|
|
2995
|
-
if (hasSlots &&
|
|
2996
|
-
|
|
3221
|
+
if (hasSlots && !hasKem) {
|
|
3222
|
+
issues.push(issueOf("ENC_KEM_REQUIRED", encPath, "enc.slots present but enc.kem absent"));
|
|
2997
3223
|
}
|
|
2998
3224
|
if (!hasSlots && !hasPassphrase) {
|
|
2999
|
-
|
|
3000
|
-
|
|
3225
|
+
issues.push(
|
|
3226
|
+
issueOf(
|
|
3001
3227
|
"ENC_NO_KEY_PATH",
|
|
3002
|
-
|
|
3228
|
+
encPath,
|
|
3003
3229
|
"enc requires either slots or passphrase \u2014 no on-chain key path otherwise"
|
|
3004
3230
|
)
|
|
3005
3231
|
);
|
|
3006
3232
|
}
|
|
3007
3233
|
if (hasSlots) {
|
|
3008
|
-
const
|
|
3009
|
-
if (
|
|
3010
|
-
|
|
3011
|
-
|
|
3234
|
+
const slots = enc.slots;
|
|
3235
|
+
if (slots.length < 1) {
|
|
3236
|
+
issues.push(
|
|
3237
|
+
issueOf("ENC_SLOTS_EMPTY", [...encPath, "slots"], "slots[] must carry at least one slot")
|
|
3012
3238
|
);
|
|
3013
|
-
} else if (
|
|
3014
|
-
|
|
3015
|
-
|
|
3239
|
+
} else if (slots.length > opts.maxSlots) {
|
|
3240
|
+
issues.push(
|
|
3241
|
+
issueOf(
|
|
3016
3242
|
"ENC_SLOTS_TOO_MANY",
|
|
3017
|
-
[...
|
|
3018
|
-
`slots length ${
|
|
3243
|
+
[...encPath, "slots"],
|
|
3244
|
+
`slots length ${slots.length} exceeds the slot-count bound ${opts.maxSlots}`
|
|
3019
3245
|
)
|
|
3020
3246
|
);
|
|
3021
|
-
} else {
|
|
3022
|
-
const descriptor =
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
seenKemMaterial.add(key);
|
|
3049
|
-
}
|
|
3247
|
+
} else if (hasKem) {
|
|
3248
|
+
const descriptor = KEM_SLOT_DESCRIPTORS[enc.kem];
|
|
3249
|
+
const rawSlotKeys = rawSlotKeySets(rawEnc);
|
|
3250
|
+
const seenKemMaterial = /* @__PURE__ */ new Set();
|
|
3251
|
+
slots.forEach((slot, si) => {
|
|
3252
|
+
const slotPath = [...encPath, "slots", si];
|
|
3253
|
+
checkSlotShape(
|
|
3254
|
+
slot,
|
|
3255
|
+
rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
|
|
3256
|
+
descriptor,
|
|
3257
|
+
enc.kem,
|
|
3258
|
+
slotPath,
|
|
3259
|
+
issues
|
|
3260
|
+
);
|
|
3261
|
+
const material = descriptor.field === "epk" ? slot.epk : slot.kem_ct;
|
|
3262
|
+
if (material !== void 0) {
|
|
3263
|
+
const key = bytesToHex2(material);
|
|
3264
|
+
if (seenKemMaterial.has(key)) {
|
|
3265
|
+
issues.push(
|
|
3266
|
+
issueOf(
|
|
3267
|
+
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
3268
|
+
[...slotPath, descriptor.field],
|
|
3269
|
+
`slot ${si} ${descriptor.field} duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
|
|
3270
|
+
)
|
|
3271
|
+
);
|
|
3272
|
+
} else {
|
|
3273
|
+
seenKemMaterial.add(key);
|
|
3050
3274
|
}
|
|
3051
|
-
});
|
|
3052
|
-
const perSlotBytes = descriptor.fieldLength + descriptor.wrapLength;
|
|
3053
|
-
const decodedEnvelopeBytes = NONCE_LENGTH + SLOTS_MAC_LENGTH + slotCount * perSlotBytes;
|
|
3054
|
-
if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
|
|
3055
|
-
errors.push(
|
|
3056
|
-
issue(
|
|
3057
|
-
"ENC_ENVELOPE_TOO_LARGE",
|
|
3058
|
-
[...basePath, "slots"],
|
|
3059
|
-
`decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
|
|
3060
|
-
)
|
|
3061
|
-
);
|
|
3062
3275
|
}
|
|
3063
|
-
}
|
|
3276
|
+
});
|
|
3064
3277
|
}
|
|
3065
3278
|
}
|
|
3066
3279
|
if (hasPassphrase) {
|
|
3067
|
-
|
|
3068
|
-
const ppPath = [...basePath, "passphrase"];
|
|
3069
|
-
if (!PASSPHRASE_KDF_ALGS.has(pp.alg)) {
|
|
3070
|
-
errors.push(
|
|
3071
|
-
issue(
|
|
3072
|
-
"ENC_PASSPHRASE_ALG_UNSUPPORTED",
|
|
3073
|
-
[...ppPath, "alg"],
|
|
3074
|
-
`unknown passphrase kdf alg: ${pp.alg}`
|
|
3075
|
-
)
|
|
3076
|
-
);
|
|
3077
|
-
return;
|
|
3078
|
-
}
|
|
3079
|
-
if (pp.alg === "argon2id") {
|
|
3080
|
-
const allowed = /* @__PURE__ */ new Set(["m", "t", "p"]);
|
|
3081
|
-
for (const k4 of Object.keys(pp.params)) {
|
|
3082
|
-
if (!allowed.has(k4)) {
|
|
3083
|
-
errors.push(
|
|
3084
|
-
issue(
|
|
3085
|
-
"SCHEMA_UNKNOWN_FIELD",
|
|
3086
|
-
[...ppPath, "params", k4],
|
|
3087
|
-
`unknown argon2id params field: ${k4}`
|
|
3088
|
-
)
|
|
3089
|
-
);
|
|
3090
|
-
}
|
|
3091
|
-
}
|
|
3092
|
-
const p5 = pp.params;
|
|
3093
|
-
const argonInt = (val, name) => {
|
|
3094
|
-
if (typeof val !== "number" || !Number.isInteger(val)) {
|
|
3095
|
-
errors.push(
|
|
3096
|
-
issue(
|
|
3097
|
-
"SCHEMA_TYPE_MISMATCH",
|
|
3098
|
-
[...ppPath, "params", name],
|
|
3099
|
-
`argon2id params.${name} must be a CBOR unsigned integer`
|
|
3100
|
-
)
|
|
3101
|
-
);
|
|
3102
|
-
return null;
|
|
3103
|
-
}
|
|
3104
|
-
return val;
|
|
3105
|
-
};
|
|
3106
|
-
const mVal = argonInt(p5.m, "m");
|
|
3107
|
-
const tVal = argonInt(p5.t, "t");
|
|
3108
|
-
const pVal = argonInt(p5.p, "p");
|
|
3109
|
-
if (mVal !== null && mVal < 65536) {
|
|
3110
|
-
errors.push(
|
|
3111
|
-
issue(
|
|
3112
|
-
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
3113
|
-
[...ppPath, "params", "m"],
|
|
3114
|
-
"argon2id requires m >= 65536 KiB"
|
|
3115
|
-
)
|
|
3116
|
-
);
|
|
3117
|
-
}
|
|
3118
|
-
if (tVal !== null && tVal < 3) {
|
|
3119
|
-
errors.push(
|
|
3120
|
-
issue(
|
|
3121
|
-
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
3122
|
-
[...ppPath, "params", "t"],
|
|
3123
|
-
"argon2id requires t >= 3"
|
|
3124
|
-
)
|
|
3125
|
-
);
|
|
3126
|
-
}
|
|
3127
|
-
if (pVal !== null && pVal < 1) {
|
|
3128
|
-
errors.push(
|
|
3129
|
-
issue(
|
|
3130
|
-
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
3131
|
-
[...ppPath, "params", "p"],
|
|
3132
|
-
"argon2id requires p >= 1"
|
|
3133
|
-
)
|
|
3134
|
-
);
|
|
3135
|
-
}
|
|
3136
|
-
}
|
|
3280
|
+
checkPassphraseBlock(enc.passphrase, [...encPath, "passphrase"], opts, issues);
|
|
3137
3281
|
}
|
|
3138
3282
|
}
|
|
3139
3283
|
var SLOT_KEY_UNIVERSE = /* @__PURE__ */ new Set(["epk", "kem_ct", "wrap"]);
|
|
3140
|
-
function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath,
|
|
3284
|
+
function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, issues) {
|
|
3141
3285
|
const foreignField = descriptor.field === "epk" ? "kem_ct" : "epk";
|
|
3142
3286
|
if (rawKeys.has(foreignField)) {
|
|
3143
|
-
|
|
3144
|
-
|
|
3287
|
+
issues.push(
|
|
3288
|
+
issueOf(
|
|
3145
3289
|
"ENC_SLOT_INVALID_SHAPE",
|
|
3146
3290
|
[...slotPath, foreignField],
|
|
3147
3291
|
`slot carries '${foreignField}' but kem='${kem}' expects '${descriptor.field}'`
|
|
3148
3292
|
)
|
|
3149
3293
|
);
|
|
3150
3294
|
}
|
|
3151
|
-
for (const
|
|
3152
|
-
if (!SLOT_KEY_UNIVERSE.has(
|
|
3153
|
-
|
|
3154
|
-
|
|
3295
|
+
for (const key of rawKeys) {
|
|
3296
|
+
if (!SLOT_KEY_UNIVERSE.has(key)) {
|
|
3297
|
+
issues.push(
|
|
3298
|
+
issueOf(
|
|
3155
3299
|
"ENC_SLOT_INVALID_SHAPE",
|
|
3156
|
-
[...slotPath,
|
|
3157
|
-
`slot carries unexpected key '${
|
|
3300
|
+
[...slotPath, key],
|
|
3301
|
+
`slot carries unexpected key '${key}'; a slot is a 2-key map {${descriptor.field}, wrap}`
|
|
3158
3302
|
)
|
|
3159
3303
|
);
|
|
3160
3304
|
}
|
|
3161
3305
|
}
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
}
|
|
3180
|
-
} else {
|
|
3181
|
-
if (slot.kem_ct === void 0) {
|
|
3182
|
-
errors.push(
|
|
3183
|
-
issue(
|
|
3184
|
-
"ENC_SLOT_INVALID_SHAPE",
|
|
3185
|
-
[...slotPath, "kem_ct"],
|
|
3186
|
-
`slot for kem='${kem}' is missing required 'kem_ct'`
|
|
3187
|
-
)
|
|
3188
|
-
);
|
|
3189
|
-
} else {
|
|
3190
|
-
const reassembled = bytesChunkArrayConcat(slot.kem_ct).length;
|
|
3191
|
-
if (reassembled !== descriptor.fieldLength) {
|
|
3192
|
-
errors.push(
|
|
3193
|
-
issue(
|
|
3194
|
-
KEM_FIELD_LENGTH_CODE.kem_ct,
|
|
3195
|
-
[...slotPath, "kem_ct"],
|
|
3196
|
-
`slot.kem_ct reassembles to ${reassembled} bytes != ${descriptor.fieldLength} for ${kem}`
|
|
3197
|
-
)
|
|
3198
|
-
);
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3306
|
+
const ctField = descriptor.field === "epk" ? slot.epk : slot.kem_ct;
|
|
3307
|
+
if (ctField === void 0) {
|
|
3308
|
+
issues.push(
|
|
3309
|
+
issueOf(
|
|
3310
|
+
"ENC_SLOT_INVALID_SHAPE",
|
|
3311
|
+
[...slotPath, descriptor.field],
|
|
3312
|
+
`slot for kem='${kem}' is missing required '${descriptor.field}'`
|
|
3313
|
+
)
|
|
3314
|
+
);
|
|
3315
|
+
} else if (ctField.length !== descriptor.fieldLength) {
|
|
3316
|
+
issues.push(
|
|
3317
|
+
issueOf(
|
|
3318
|
+
KEM_FIELD_LENGTH_CODE[descriptor.field],
|
|
3319
|
+
[...slotPath, descriptor.field],
|
|
3320
|
+
`slot.${descriptor.field} length ${ctField.length} != ${descriptor.fieldLength} for ${kem}`
|
|
3321
|
+
)
|
|
3322
|
+
);
|
|
3201
3323
|
}
|
|
3202
3324
|
if (slot.wrap === void 0) {
|
|
3203
|
-
|
|
3204
|
-
|
|
3325
|
+
issues.push(
|
|
3326
|
+
issueOf(
|
|
3205
3327
|
"ENC_SLOT_INVALID_SHAPE",
|
|
3206
3328
|
[...slotPath, "wrap"],
|
|
3207
3329
|
`slot for kem='${kem}' is missing required 'wrap'`
|
|
3208
3330
|
)
|
|
3209
3331
|
);
|
|
3210
3332
|
} else if (slot.wrap.length !== descriptor.wrapLength) {
|
|
3211
|
-
|
|
3212
|
-
|
|
3333
|
+
issues.push(
|
|
3334
|
+
issueOf(
|
|
3213
3335
|
"WRAP_LENGTH_MISMATCH",
|
|
3214
3336
|
[...slotPath, "wrap"],
|
|
3215
3337
|
`slot.wrap length ${slot.wrap.length} != ${descriptor.wrapLength}`
|
|
@@ -3217,22 +3339,88 @@ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
|
|
|
3217
3339
|
);
|
|
3218
3340
|
}
|
|
3219
3341
|
}
|
|
3220
|
-
function
|
|
3221
|
-
if (
|
|
3222
|
-
|
|
3342
|
+
function checkPassphraseBlock(pp, ppPath, opts, issues) {
|
|
3343
|
+
if (!PASSPHRASE_KDF_ALGS.has(pp.alg)) {
|
|
3344
|
+
issues.push(
|
|
3345
|
+
issueOf(
|
|
3346
|
+
"ENC_PASSPHRASE_ALG_UNSUPPORTED",
|
|
3347
|
+
[...ppPath, "alg"],
|
|
3348
|
+
`unknown passphrase kdf alg: ${pp.alg}`
|
|
3349
|
+
)
|
|
3350
|
+
);
|
|
3351
|
+
return;
|
|
3223
3352
|
}
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3353
|
+
const paramsPath = [...ppPath, "params"];
|
|
3354
|
+
const params = pp.params;
|
|
3355
|
+
for (const key of Object.keys(params)) {
|
|
3356
|
+
if (key !== "m" && key !== "t" && key !== "p") {
|
|
3357
|
+
issues.push(
|
|
3358
|
+
issueOf(
|
|
3359
|
+
"SCHEMA_UNKNOWN_FIELD",
|
|
3360
|
+
[...paramsPath, key],
|
|
3361
|
+
`unknown argon2id params field: ${key}`
|
|
3362
|
+
)
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
const floors = { m: 65536, t: 3, p: 1 };
|
|
3367
|
+
const ceiling = opts.passphraseParamsCeiling;
|
|
3368
|
+
for (const name of ["m", "t", "p"]) {
|
|
3369
|
+
const value = params[name];
|
|
3370
|
+
if (value === void 0) {
|
|
3371
|
+
issues.push(
|
|
3372
|
+
issueOf(
|
|
3373
|
+
"SCHEMA_MISSING_REQUIRED",
|
|
3374
|
+
[...paramsPath, name],
|
|
3375
|
+
`argon2id params.${name} is required`
|
|
3376
|
+
)
|
|
3377
|
+
);
|
|
3378
|
+
continue;
|
|
3379
|
+
}
|
|
3380
|
+
if (!isUint(value)) {
|
|
3381
|
+
issues.push(
|
|
3382
|
+
issueOf(
|
|
3383
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3384
|
+
[...paramsPath, name],
|
|
3385
|
+
`argon2id params.${name} must be a CBOR unsigned integer`
|
|
3386
|
+
)
|
|
3387
|
+
);
|
|
3388
|
+
continue;
|
|
3389
|
+
}
|
|
3390
|
+
if (!uintWithin(value, 0, UINT32_MAX)) {
|
|
3391
|
+
issues.push(
|
|
3392
|
+
issueOf(
|
|
3393
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3394
|
+
[...paramsPath, name],
|
|
3395
|
+
`argon2id params.${name} exceeds the pinned wire range 0 .. 2^32 - 1`
|
|
3396
|
+
)
|
|
3397
|
+
);
|
|
3398
|
+
continue;
|
|
3399
|
+
}
|
|
3400
|
+
const num = Number(value);
|
|
3401
|
+
if (num < floors[name]) {
|
|
3402
|
+
issues.push(
|
|
3403
|
+
issueOf(
|
|
3404
|
+
"ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
|
|
3405
|
+
[...paramsPath, name],
|
|
3406
|
+
`argon2id requires ${name} >= ${floors[name]}`
|
|
3407
|
+
)
|
|
3408
|
+
);
|
|
3409
|
+
continue;
|
|
3410
|
+
}
|
|
3411
|
+
if (ceiling !== null && num > ceiling[name]) {
|
|
3412
|
+
issues.push(
|
|
3413
|
+
issueOf(
|
|
3414
|
+
"ENC_PASSPHRASE_PARAMS_EXCEED_POLICY",
|
|
3415
|
+
[...paramsPath, name],
|
|
3416
|
+
`argon2id params.${name} = ${num} exceeds the deployment ceiling ${ceiling[name]}`
|
|
3417
|
+
)
|
|
3418
|
+
);
|
|
3419
|
+
}
|
|
3231
3420
|
}
|
|
3232
|
-
return hex;
|
|
3233
3421
|
}
|
|
3234
3422
|
function rawSlotKeySets(rawEnc) {
|
|
3235
|
-
const slots =
|
|
3423
|
+
const slots = rawEnc["slots"];
|
|
3236
3424
|
if (!Array.isArray(slots)) return [];
|
|
3237
3425
|
return slots.map((slot) => {
|
|
3238
3426
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -3244,54 +3432,64 @@ function rawSlotKeySets(rawEnc) {
|
|
|
3244
3432
|
return keys;
|
|
3245
3433
|
});
|
|
3246
3434
|
}
|
|
3247
|
-
function
|
|
3248
|
-
if (value instanceof Map) return value.get(key);
|
|
3249
|
-
if (typeof value === "object" && value !== null) {
|
|
3250
|
-
return value[key];
|
|
3251
|
-
}
|
|
3252
|
-
return void 0;
|
|
3253
|
-
}
|
|
3254
|
-
function checkMerkleCommit(commit, idx, errors) {
|
|
3435
|
+
function checkMerkleCommit(commit, idx, issues) {
|
|
3255
3436
|
const basePath = ["merkle", idx];
|
|
3256
3437
|
if (!(commit.alg in MERKLE_COMMIT_ALG_LENGTHS)) {
|
|
3257
|
-
|
|
3258
|
-
|
|
3438
|
+
issues.push(
|
|
3439
|
+
issueOf(
|
|
3259
3440
|
"UNSUPPORTED_MERKLE_COMMIT_ALG",
|
|
3260
3441
|
[...basePath, "alg"],
|
|
3261
3442
|
`unknown merkle commitment alg: ${commit.alg}`
|
|
3262
3443
|
)
|
|
3263
3444
|
);
|
|
3264
|
-
|
|
3445
|
+
} else {
|
|
3446
|
+
const expected = MERKLE_COMMIT_ALG_LENGTHS[commit.alg];
|
|
3447
|
+
if (commit.root.length !== expected) {
|
|
3448
|
+
issues.push(
|
|
3449
|
+
issueOf(
|
|
3450
|
+
"HASH_DIGEST_LENGTH_MISMATCH",
|
|
3451
|
+
[...basePath, "root"],
|
|
3452
|
+
`merkle entry root length ${commit.root.length} != ${expected} for ${commit.alg}`
|
|
3453
|
+
)
|
|
3454
|
+
);
|
|
3455
|
+
}
|
|
3265
3456
|
}
|
|
3266
|
-
const
|
|
3267
|
-
if (
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
"
|
|
3271
|
-
[...basePath, "
|
|
3272
|
-
|
|
3457
|
+
const leafCount = commit.leaf_count;
|
|
3458
|
+
if (!isUint(leafCount)) {
|
|
3459
|
+
issues.push(
|
|
3460
|
+
issueOf(
|
|
3461
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3462
|
+
[...basePath, "leaf_count"],
|
|
3463
|
+
"leaf_count must be a CBOR unsigned integer"
|
|
3464
|
+
)
|
|
3465
|
+
);
|
|
3466
|
+
} else if (!uintWithin(leafCount, 1, UINT32_MAX)) {
|
|
3467
|
+
issues.push(
|
|
3468
|
+
issueOf(
|
|
3469
|
+
"SCHEMA_MERKLE_LEAF_COUNT_INVALID",
|
|
3470
|
+
[...basePath, "leaf_count"],
|
|
3471
|
+
`leaf_count ${String(leafCount)} is outside the pinned range 1 .. 2^32 - 1`
|
|
3273
3472
|
)
|
|
3274
3473
|
);
|
|
3275
3474
|
}
|
|
3276
|
-
if (commit.uris) {
|
|
3277
|
-
|
|
3475
|
+
if (commit.uris !== void 0) {
|
|
3476
|
+
checkUris(commit.uris, [...basePath, "uris"], issues);
|
|
3278
3477
|
}
|
|
3279
3478
|
}
|
|
3280
|
-
function checkSigEntry(entry, idx,
|
|
3479
|
+
function checkSigEntry(entry, idx, issues) {
|
|
3281
3480
|
if (entry.cose_key !== void 0) {
|
|
3282
3481
|
const keyIssue = inspectCoseKey(entry.cose_key, idx);
|
|
3283
3482
|
if (keyIssue !== null) {
|
|
3284
|
-
|
|
3483
|
+
issues.push(keyIssue);
|
|
3285
3484
|
return;
|
|
3286
3485
|
}
|
|
3287
3486
|
}
|
|
3288
|
-
const merged = bytesChunkArrayConcat(entry.cose_sign1);
|
|
3289
3487
|
let cose;
|
|
3290
3488
|
try {
|
|
3291
|
-
cose = decodeCoseSign1(
|
|
3489
|
+
cose = decodeCoseSign1(entry.cose_sign1);
|
|
3292
3490
|
} catch (cause) {
|
|
3293
|
-
|
|
3294
|
-
|
|
3491
|
+
issues.push(
|
|
3492
|
+
issueOf(
|
|
3295
3493
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3296
3494
|
["sigs", idx],
|
|
3297
3495
|
cause instanceof CoseVerifyError || cause instanceof Error ? cause.message : String(cause)
|
|
@@ -3300,8 +3498,8 @@ function checkSigEntry(entry, idx, errors, info) {
|
|
|
3300
3498
|
return;
|
|
3301
3499
|
}
|
|
3302
3500
|
if (cose.payload !== null) {
|
|
3303
|
-
|
|
3304
|
-
|
|
3501
|
+
issues.push(
|
|
3502
|
+
issueOf(
|
|
3305
3503
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3306
3504
|
["sigs", idx],
|
|
3307
3505
|
"COSE_Sign1 payload must be null (detached); attached form forbidden"
|
|
@@ -3311,8 +3509,8 @@ function checkSigEntry(entry, idx, errors, info) {
|
|
|
3311
3509
|
}
|
|
3312
3510
|
const alg = cose.protectedHeader.get(1);
|
|
3313
3511
|
if (typeof alg !== "number" || !KNOWN_SIG_ALG_IDS.has(alg)) {
|
|
3314
|
-
|
|
3315
|
-
|
|
3512
|
+
issues.push(
|
|
3513
|
+
issueOf(
|
|
3316
3514
|
"SIGNATURE_UNSUPPORTED",
|
|
3317
3515
|
["sigs", idx],
|
|
3318
3516
|
`COSE_Sign1 protected alg ${String(alg)} not in {-8, -19}`
|
|
@@ -3321,8 +3519,8 @@ function checkSigEntry(entry, idx, errors, info) {
|
|
|
3321
3519
|
}
|
|
3322
3520
|
const protectedKid = cose.protectedHeader.get(4);
|
|
3323
3521
|
if (protectedKid instanceof Uint8Array && protectedKid.length === 32 && entry.cose_key !== void 0) {
|
|
3324
|
-
|
|
3325
|
-
|
|
3522
|
+
issues.push(
|
|
3523
|
+
issueOf(
|
|
3326
3524
|
"SIG_ENTRY_KID_COSE_KEY_CONFLICT",
|
|
3327
3525
|
["sigs", idx],
|
|
3328
3526
|
"sigs[i] carries both a 32-byte protected `kid` (path 1) and an inline `cose_key` (path 2); paths are mutually exclusive"
|
|
@@ -3330,12 +3528,12 @@ function checkSigEntry(entry, idx, errors, info) {
|
|
|
3330
3528
|
);
|
|
3331
3529
|
}
|
|
3332
3530
|
}
|
|
3333
|
-
function inspectCoseKey(
|
|
3531
|
+
function inspectCoseKey(keyBytes, i) {
|
|
3334
3532
|
let decoded;
|
|
3335
3533
|
try {
|
|
3336
|
-
decoded = decodeCanonicalCbor(
|
|
3534
|
+
decoded = decodeCanonicalCbor(keyBytes);
|
|
3337
3535
|
} catch (cause) {
|
|
3338
|
-
return
|
|
3536
|
+
return issueOf(
|
|
3339
3537
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3340
3538
|
["sigs", i, "cose_key"],
|
|
3341
3539
|
`sigs[${i}].cose_key failed to decode as cbor<COSE_Key>: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
@@ -3343,20 +3541,14 @@ function inspectCoseKey(keyChunks, i) {
|
|
|
3343
3541
|
}
|
|
3344
3542
|
const getLabel = (label) => {
|
|
3345
3543
|
if (decoded instanceof Map) return decoded.get(label);
|
|
3346
|
-
if (typeof decoded === "object" && decoded !== null) {
|
|
3347
|
-
return decoded[String(label)];
|
|
3348
|
-
}
|
|
3349
3544
|
return void 0;
|
|
3350
3545
|
};
|
|
3351
3546
|
const hasLabel = (label) => {
|
|
3352
3547
|
if (decoded instanceof Map) return decoded.has(label);
|
|
3353
|
-
if (typeof decoded === "object" && decoded !== null) {
|
|
3354
|
-
return Object.prototype.hasOwnProperty.call(decoded, String(label));
|
|
3355
|
-
}
|
|
3356
3548
|
return false;
|
|
3357
3549
|
};
|
|
3358
3550
|
if (hasLabel(-4)) {
|
|
3359
|
-
return
|
|
3551
|
+
return issueOf(
|
|
3360
3552
|
"SIG_PRIVATE_KEY_LEAKED",
|
|
3361
3553
|
["sigs", i, "cose_key"],
|
|
3362
3554
|
"cose_key carries COSE_Key private-key material (label -4, the OKP/EC2 private scalar d); publishing a private key on the permanent ledger is forbidden"
|
|
@@ -3364,7 +3556,7 @@ function inspectCoseKey(keyChunks, i) {
|
|
|
3364
3556
|
}
|
|
3365
3557
|
const kty = getLabel(1);
|
|
3366
3558
|
if (kty !== 1) {
|
|
3367
|
-
return
|
|
3559
|
+
return issueOf(
|
|
3368
3560
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3369
3561
|
["sigs", i, "cose_key"],
|
|
3370
3562
|
`sigs[${i}].cose_key COSE_Key kty (label 1) must be 1 (OKP); got ${String(kty)}`
|
|
@@ -3372,23 +3564,16 @@ function inspectCoseKey(keyChunks, i) {
|
|
|
3372
3564
|
}
|
|
3373
3565
|
const crv = getLabel(-1);
|
|
3374
3566
|
if (crv !== 6) {
|
|
3375
|
-
return
|
|
3567
|
+
return issueOf(
|
|
3376
3568
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3377
3569
|
["sigs", i, "cose_key"],
|
|
3378
3570
|
`sigs[${i}].cose_key COSE_Key crv (label -1) must be 6 (Ed25519); got ${String(crv)}`
|
|
3379
3571
|
);
|
|
3380
3572
|
}
|
|
3381
|
-
if (!hasLabel(-2)) {
|
|
3382
|
-
return issue(
|
|
3383
|
-
"MALFORMED_SIG_COSE_SIGN1",
|
|
3384
|
-
["sigs", i, "cose_key"],
|
|
3385
|
-
`sigs[${i}].cose_key COSE_Key missing label -2 (Ed25519 public-key bytes)`
|
|
3386
|
-
);
|
|
3387
|
-
}
|
|
3388
3573
|
const x5 = getLabel(-2);
|
|
3389
3574
|
if (!(x5 instanceof Uint8Array) || x5.length !== 32) {
|
|
3390
3575
|
const got = x5 instanceof Uint8Array ? `${x5.length}-byte bstr` : typeof x5;
|
|
3391
|
-
return
|
|
3576
|
+
return issueOf(
|
|
3392
3577
|
"MALFORMED_SIG_COSE_SIGN1",
|
|
3393
3578
|
["sigs", i, "cose_key"],
|
|
3394
3579
|
`sigs[${i}].cose_key COSE_Key label -2 must be a 32-byte byte string (Ed25519 public key); got ${got}`
|
|
@@ -3396,6 +3581,58 @@ function inspectCoseKey(keyChunks, i) {
|
|
|
3396
3581
|
}
|
|
3397
3582
|
return null;
|
|
3398
3583
|
}
|
|
3584
|
+
function checkCrit(record, decodedTopKeys, supportedCriticalExtensions, issues) {
|
|
3585
|
+
if (!Array.isArray(record.crit)) return;
|
|
3586
|
+
if (record.crit.length === 0) {
|
|
3587
|
+
issues.push(
|
|
3588
|
+
issueOf(
|
|
3589
|
+
"SCHEMA_TYPE_MISMATCH",
|
|
3590
|
+
["crit"],
|
|
3591
|
+
"crit[] must carry at least one entry when present"
|
|
3592
|
+
)
|
|
3593
|
+
);
|
|
3594
|
+
return;
|
|
3595
|
+
}
|
|
3596
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3597
|
+
for (let i = 0; i < record.crit.length; i++) {
|
|
3598
|
+
const critName = record.crit[i];
|
|
3599
|
+
let reason = null;
|
|
3600
|
+
if (TOP_LEVEL_BASE_KEYS.has(critName)) {
|
|
3601
|
+
reason = `'${critName}' is a base key and MUST NOT appear in crit[]`;
|
|
3602
|
+
} else if (!isExtensionKey(critName)) {
|
|
3603
|
+
reason = `'${critName}' does not match the extension-key form (^x-.+ or ^[a-z]+-.+, no control characters)`;
|
|
3604
|
+
} else if (!decodedTopKeys.has(critName)) {
|
|
3605
|
+
reason = `'${critName}' is named in crit but absent from the record map`;
|
|
3606
|
+
} else if (seen.has(critName)) {
|
|
3607
|
+
reason = `'${critName}' appears more than once in crit[]`;
|
|
3608
|
+
}
|
|
3609
|
+
seen.add(critName);
|
|
3610
|
+
if (reason !== null) {
|
|
3611
|
+
issues.push(issueOf("CRIT_SHAPE_INVALID", ["crit", i], reason));
|
|
3612
|
+
continue;
|
|
3613
|
+
}
|
|
3614
|
+
if (!supportedCriticalExtensions.has(critName)) {
|
|
3615
|
+
issues.push(
|
|
3616
|
+
issueOf(
|
|
3617
|
+
"EXTENSION_UNSUPPORTED_CRITICAL",
|
|
3618
|
+
["crit", i],
|
|
3619
|
+
`crit lists extension '${critName}' that this validator does not implement`
|
|
3620
|
+
)
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
function topLevelKeysOf(decoded) {
|
|
3626
|
+
if (decoded === null || typeof decoded !== "object") return /* @__PURE__ */ new Set();
|
|
3627
|
+
if (decoded instanceof Map) {
|
|
3628
|
+
const out = /* @__PURE__ */ new Set();
|
|
3629
|
+
for (const k4 of decoded.keys()) {
|
|
3630
|
+
if (typeof k4 === "string") out.add(k4);
|
|
3631
|
+
}
|
|
3632
|
+
return out;
|
|
3633
|
+
}
|
|
3634
|
+
return new Set(Object.keys(decoded));
|
|
3635
|
+
}
|
|
3399
3636
|
var ACCEPTED_CIDV1_MULTIBASE = /* @__PURE__ */ new Set(["b", "B", "f", "F", "z"]);
|
|
3400
3637
|
var ACCEPTED_MULTICODECS = /* @__PURE__ */ new Set([85, 112, 113]);
|
|
3401
3638
|
var ACCEPTED_MULTIHASHES = /* @__PURE__ */ new Map([
|
|
@@ -3531,52 +3768,56 @@ function decodeBase58btc(s3) {
|
|
|
3531
3768
|
}
|
|
3532
3769
|
return out;
|
|
3533
3770
|
}
|
|
3534
|
-
function
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
errors.push(
|
|
3539
|
-
issue("SCHEMA_TYPE_MISMATCH", ["crit"], "crit[] must carry at least one entry when present")
|
|
3540
|
-
);
|
|
3541
|
-
return invalid;
|
|
3542
|
-
}
|
|
3543
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3544
|
-
for (let i = 0; i < record.crit.length; i++) {
|
|
3545
|
-
const critName = record.crit[i];
|
|
3546
|
-
let reason = null;
|
|
3547
|
-
if (TOP_LEVEL_BASE_KEYS.has(critName)) {
|
|
3548
|
-
reason = `'${critName}' is a base key and MUST NOT appear in crit[]`;
|
|
3549
|
-
} else if (!isExtensionKey(critName)) {
|
|
3550
|
-
reason = `'${critName}' does not match the extension-key regex (^x-.+ or ^[a-z]+-.+)`;
|
|
3551
|
-
} else if (!decodedTopKeys.has(critName)) {
|
|
3552
|
-
reason = `'${critName}' is named in crit but absent from the record map`;
|
|
3553
|
-
} else if (seen.has(critName)) {
|
|
3554
|
-
reason = `'${critName}' appears more than once in crit[]`;
|
|
3555
|
-
}
|
|
3556
|
-
seen.add(critName);
|
|
3557
|
-
if (reason !== null) {
|
|
3558
|
-
invalid.add(i);
|
|
3559
|
-
errors.push(issue("CRIT_SHAPE_INVALID", ["crit", i], reason));
|
|
3560
|
-
}
|
|
3561
|
-
}
|
|
3562
|
-
return invalid;
|
|
3771
|
+
function bytesToHex2(bytes) {
|
|
3772
|
+
let out = "";
|
|
3773
|
+
for (const b5 of bytes) out += b5.toString(16).padStart(2, "0");
|
|
3774
|
+
return out;
|
|
3563
3775
|
}
|
|
3564
|
-
function
|
|
3565
|
-
if (
|
|
3566
|
-
if (
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
}
|
|
3573
|
-
return new Set(Object.keys(decoded));
|
|
3776
|
+
function isUint(value) {
|
|
3777
|
+
if (typeof value === "number") return Number.isInteger(value) && value >= 0;
|
|
3778
|
+
if (typeof value === "bigint") return value >= 0n;
|
|
3779
|
+
return false;
|
|
3780
|
+
}
|
|
3781
|
+
function uintWithin(value, min, max) {
|
|
3782
|
+
if (typeof value === "bigint") return value >= BigInt(min) && value <= BigInt(max);
|
|
3783
|
+
return value >= min && value <= max;
|
|
3574
3784
|
}
|
|
3575
|
-
function
|
|
3785
|
+
function issueOf(code, path, message) {
|
|
3576
3786
|
return { code, path, message, severity: SEVERITY[code] };
|
|
3577
3787
|
}
|
|
3578
|
-
|
|
3579
|
-
|
|
3788
|
+
var PATH_UTF8 = new TextEncoder();
|
|
3789
|
+
function compareTextSegments(a4, b5) {
|
|
3790
|
+
const ab = PATH_UTF8.encode(a4);
|
|
3791
|
+
const bb = PATH_UTF8.encode(b5);
|
|
3792
|
+
const n2 = Math.min(ab.length, bb.length);
|
|
3793
|
+
for (let i = 0; i < n2; i++) {
|
|
3794
|
+
const d6 = ab[i] - bb[i];
|
|
3795
|
+
if (d6 !== 0) return d6;
|
|
3796
|
+
}
|
|
3797
|
+
return ab.length - bb.length;
|
|
3798
|
+
}
|
|
3799
|
+
function compareIssues(a4, b5) {
|
|
3800
|
+
const ap = a4.path;
|
|
3801
|
+
const bp = b5.path;
|
|
3802
|
+
const n2 = Math.min(ap.length, bp.length);
|
|
3803
|
+
for (let i = 0; i < n2; i++) {
|
|
3804
|
+
const x5 = ap[i];
|
|
3805
|
+
const y7 = bp[i];
|
|
3806
|
+
const xIsNum = typeof x5 === "number";
|
|
3807
|
+
const yIsNum = typeof y7 === "number";
|
|
3808
|
+
if (xIsNum !== yIsNum) return xIsNum ? -1 : 1;
|
|
3809
|
+
if (xIsNum && yIsNum) {
|
|
3810
|
+
if (x5 !== y7) return x5 < y7 ? -1 : 1;
|
|
3811
|
+
} else {
|
|
3812
|
+
const d6 = compareTextSegments(x5, y7);
|
|
3813
|
+
if (d6 !== 0) return d6;
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
if (ap.length !== bp.length) return ap.length - bp.length;
|
|
3817
|
+
return errorCodeRegistryIndex(a4.code) - errorCodeRegistryIndex(b5.code);
|
|
3818
|
+
}
|
|
3819
|
+
function sortIssues(issues) {
|
|
3820
|
+
return [...issues].sort(compareIssues);
|
|
3580
3821
|
}
|
|
3581
3822
|
function valueAtPath(root, path) {
|
|
3582
3823
|
let cur = root;
|
|
@@ -3598,10 +3839,15 @@ function valueAtPath(root, path) {
|
|
|
3598
3839
|
*/
|
|
3599
3840
|
|
|
3600
3841
|
exports.Argon2idParamsSchema = Argon2idParamsSchema;
|
|
3601
|
-
exports.
|
|
3842
|
+
exports.CARRIAGE_ERROR_CODES = CARRIAGE_ERROR_CODES;
|
|
3843
|
+
exports.DEFAULT_PASSPHRASE_PARAMS_CEILING = DEFAULT_PASSPHRASE_PARAMS_CEILING;
|
|
3844
|
+
exports.DUAL_SEVERITY_CODES = DUAL_SEVERITY_CODES;
|
|
3602
3845
|
exports.ERROR_CODES = ERROR_CODES;
|
|
3846
|
+
exports.ERROR_CODE_PART = ERROR_CODE_PART;
|
|
3603
3847
|
exports.EXTENSION_KEY_COMPANION_RE = EXTENSION_KEY_COMPANION_RE;
|
|
3604
3848
|
exports.EXTENSION_KEY_VENDOR_RE = EXTENSION_KEY_VENDOR_RE;
|
|
3849
|
+
exports.EncOpaqueSchema = EncOpaqueSchema;
|
|
3850
|
+
exports.EncScheme1Schema = EncScheme1Schema;
|
|
3605
3851
|
exports.EncryptionEnvelopeSchema = EncryptionEnvelopeSchema;
|
|
3606
3852
|
exports.HashDigestSchema = HashDigestSchema;
|
|
3607
3853
|
exports.HashesMapSchema = HashesMapSchema;
|
|
@@ -3615,16 +3861,17 @@ exports.SigEntrySchema = SigEntrySchema;
|
|
|
3615
3861
|
exports.SlotSchema = SlotSchema;
|
|
3616
3862
|
exports.SupersedesSchema = SupersedesSchema;
|
|
3617
3863
|
exports.TOP_LEVEL_BASE_KEYS = TOP_LEVEL_BASE_KEYS;
|
|
3618
|
-
exports.
|
|
3864
|
+
exports.TRANSPORT_CHUNK_MAX_BYTES = TRANSPORT_CHUNK_MAX_BYTES;
|
|
3865
|
+
exports.UriSchema = UriSchema;
|
|
3619
3866
|
exports.VERIFIER_ERROR_CODES = VERIFIER_ERROR_CODES;
|
|
3620
3867
|
exports.VersionLiteralSchema = VersionLiteralSchema;
|
|
3621
|
-
exports.
|
|
3622
|
-
exports.
|
|
3623
|
-
exports.chunkUri = chunkUri;
|
|
3868
|
+
exports.chunkRecordBody = chunkRecordBody;
|
|
3869
|
+
exports.encodeLabel309Value = encodeLabel309Value;
|
|
3624
3870
|
exports.encodePoeRecord = encodePoeRecord;
|
|
3625
3871
|
exports.encodeRecordBodyForSigning = encodeRecordBodyForSigning;
|
|
3872
|
+
exports.errorCodeRegistryIndex = errorCodeRegistryIndex;
|
|
3626
3873
|
exports.isExtensionKey = isExtensionKey;
|
|
3627
|
-
exports.
|
|
3874
|
+
exports.reassembleLabel309Value = reassembleLabel309Value;
|
|
3628
3875
|
exports.severityOf = severityOf;
|
|
3629
3876
|
exports.validateCidProfile = validateCidProfile;
|
|
3630
3877
|
exports.validatePoeRecord = validatePoeRecord;
|