@cardanowall/poe-standard 0.2.0 → 0.4.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/index.cjs CHANGED
@@ -3,95 +3,108 @@
3
3
  var zod = require('zod');
4
4
 
5
5
  // src/schema.ts
6
- var ChunkedBytesArraySchema = zod.z.array(
7
- zod.z.instanceof(Uint8Array).refine((b5) => b5.length >= 1 && b5.length <= 64, {
8
- params: { code: "CHUNK_TOO_LARGE" }
9
- })
10
- ).min(1);
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 MerkleCommitSchema = zod.z.object({
24
- alg: zod.z.string(),
25
- root: zod.z.instanceof(Uint8Array),
26
- leaf_count: zod.z.number().int().min(1),
27
- uris: zod.z.array(UriChunkArraySchema).min(1).optional()
28
- }).strict();
29
- var SlotSchema = zod.z.object({
30
- epk: zod.z.instanceof(Uint8Array).optional(),
31
- kem_ct: ChunkedBytesArraySchema.optional(),
32
- wrap: zod.z.instanceof(Uint8Array).optional()
33
- });
34
- var Argon2idParamsSchema = zod.z.object({
35
- m: zod.z.number().int(),
36
- t: zod.z.number().int(),
37
- p: zod.z.number().int()
38
- }).strict();
39
- var PassphraseBlockSchema = zod.z.object({
40
- alg: zod.z.string(),
41
- salt: zod.z.instanceof(Uint8Array).superRefine((bytes, ctx) => {
42
- if (bytes.length < 16) {
43
- ctx.addIssue({
44
- code: "custom",
45
- path: [],
46
- message: `passphrase.salt length ${bytes.length} < 16`,
47
- params: { code: "ENC_PASSPHRASE_SALT_TOO_SHORT" }
48
- });
49
- } else if (bytes.length > 64) {
50
- ctx.addIssue({
51
- code: "custom",
52
- path: [],
53
- message: `passphrase.salt length ${bytes.length} > 64`,
54
- params: { code: "ENC_PASSPHRASE_SALT_TOO_LONG" }
55
- });
56
- }
57
- }),
58
- params: zod.z.record(zod.z.string(), zod.z.unknown())
59
- }).strict();
60
- var EncryptionEnvelopeSchema = zod.z.object({
61
- scheme: zod.z.unknown(),
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
- var ItemEntrySchema = zod.z.object({
72
- hashes: HashesMapSchema,
73
- uris: zod.z.array(UriChunkArraySchema).min(1).optional(),
74
- // Captured as `unknown` so the validator can run the
75
- // `ENC_REQUIRES_CONTENT_HASH` pre-check ahead of any inner-shape errors
76
- // and surface the most informative code first.
77
- enc: zod.z.unknown().optional()
78
- }).strict();
79
- var SigEntrySchema = zod.z.object({
80
- cose_key: ChunkedBytesArraySchema.optional(),
81
- cose_sign1: ChunkedBytesArraySchema
82
- }).strict();
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 = zod.z.looseObject({
88
- v: VersionLiteralSchema,
89
- items: zod.z.array(ItemEntrySchema).optional(),
90
- merkle: zod.z.array(MerkleCommitSchema).optional(),
91
- supersedes: SupersedesSchema.optional(),
92
- sigs: zod.z.array(SigEntrySchema).optional(),
93
- crit: zod.z.array(zod.z.string()).optional()
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-.+\n?$/;
104
- var EXTENSION_KEY_COMPANION_RE = /^[a-z]+-.+\n?$/;
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(recordToCbor(record));
1771
- }
1772
- function encodeRecordBodyForSigning(record) {
1773
- const body = recordToCborInternal(
1783
+ return encodeCanonicalCbor(toCborValue(
1774
1784
  record,
1775
1785
  /* includeSigs */
1776
- false
1777
- );
1778
- return encodeCanonicalCbor(body);
1786
+ true
1787
+ ));
1779
1788
  }
1780
- function recordToCbor(record) {
1781
- return recordToCborInternal(
1789
+ function encodeRecordBodyForSigning(record) {
1790
+ return encodeCanonicalCbor(toCborValue(
1782
1791
  record,
1783
1792
  /* includeSigs */
1784
- true
1785
- );
1793
+ false
1794
+ ));
1786
1795
  }
1787
- function recordToCborInternal(record, includeSigs) {
1788
- const out = { v: record.v };
1789
- if (record.items !== void 0) out["items"] = record.items.map(itemToCbor);
1790
- if (record.merkle !== void 0) out["merkle"] = record.merkle.map(merkleToCbor);
1791
- if (record.supersedes !== void 0) out["supersedes"] = record.supersedes;
1792
- if (includeSigs && record.sigs !== void 0) out["sigs"] = record.sigs.map(sigEntryToCbor);
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 itemToCbor(item) {
1803
- const out = { hashes: hashesToCbor(item.hashes) };
1804
- if (item.uris !== void 0) {
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 (item.enc !== void 0) {
1808
- out["enc"] = envelopeToCbor(item.enc);
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 [alg, digest] of Object.entries(hashes2)) {
1815
- out[alg] = digest;
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
- function merkleToCbor(commit) {
1820
- const out = {
1821
- alg: commit.alg,
1822
- root: commit.root,
1823
- leaf_count: commit.leaf_count
1824
- };
1825
- if (commit.uris !== void 0) {
1826
- out["uris"] = commit.uris.map((chunks) => chunks.slice());
1827
- }
1828
- return out;
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
- function envelopeToCbor(enc) {
1831
- const out = {
1832
- scheme: enc.scheme,
1833
- aead: enc.aead,
1834
- nonce: enc.nonce
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
- function slotToCbor(slot) {
1843
- if (slot.kem_ct !== void 0) {
1844
- return { kem_ct: slot.kem_ct.map((c5) => c5), wrap: slot.wrap };
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");
1845
2093
  }
1846
- return { epk: slot.epk, wrap: slot.wrap };
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)));
2097
+ }
2098
+ return chunks;
1847
2099
  }
1848
- function passphraseToCbor(pp) {
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 sigEntryToCbor(entry) {
1856
- const out = { cose_sign1: entry.cose_sign1.map((b5) => b5) };
1857
- if (entry.cose_key !== void 0) {
1858
- out["cose_key"] = entry.cose_key.map((b5) => b5);
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
- return out;
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,223 +2671,89 @@ function decodeCoseSign1(bytes) {
2389
2671
  signature: signatureRaw
2390
2672
  };
2391
2673
  }
2392
-
2393
- // src/chunked.ts
2394
- var CHUNK_MAX_BYTES = 64;
2395
- var UTF8_ENCODER2 = new TextEncoder();
2396
- function chunkBytes(value) {
2397
- if (value.length === 0) return [new Uint8Array(0)];
2398
- const chunks = [];
2399
- for (let i = 0; i < value.length; i += CHUNK_MAX_BYTES) {
2400
- chunks.push(value.subarray(i, Math.min(i + CHUNK_MAX_BYTES, value.length)));
2401
- }
2402
- return chunks;
2674
+ var CARDANO_POE_ITEM_HASHES_PREFIX = new TextEncoder().encode(
2675
+ "cardano-poe-item-hashes-v1"
2676
+ );
2677
+ var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
2678
+ "cardano-poe-slots-transcript-v1"
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
+ );
2689
+ var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
2690
+ "cardano-poe-payload-v1"
2691
+ );
2692
+ var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
2693
+ "cardano-poe-payload-passphrase-v1"
2694
+ );
2695
+ var CARDANO_POE_X25519_KEK_SALT_PREFIX = new TextEncoder().encode(
2696
+ "cardano-poe-x25519-kek-salt-v1"
2697
+ );
2698
+ var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
2699
+ "cardano-poe-xwing-kek-salt-v1"
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)");
2403
2703
  }
2404
- function bytesChunkArrayConcat(chunks) {
2405
- let total = 0;
2406
- for (const c5 of chunks) total += c5.length;
2407
- const out = new Uint8Array(total);
2408
- let offset = 0;
2409
- for (const c5 of chunks) {
2410
- out.set(c5, offset);
2411
- offset += c5.length;
2412
- }
2413
- return out;
2704
+ if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
2705
+ throw new Error(
2706
+ "CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
2707
+ );
2414
2708
  }
2415
- function reconstructChunkedUri(chunks) {
2416
- const merged = bytesChunkArrayConcat(chunks.map((c5) => UTF8_ENCODER2.encode(c5)));
2417
- try {
2418
- const uri = new TextDecoder("utf-8", { fatal: true }).decode(merged);
2419
- return { ok: true, uri };
2420
- } catch (cause) {
2421
- return {
2422
- ok: false,
2423
- code: "INVALID_URI",
2424
- reason: cause instanceof Error ? cause.message : String(cause)
2425
- };
2426
- }
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
+ );
2427
2713
  }
2428
- function chunkUri(uri) {
2429
- const bytes = UTF8_ENCODER2.encode(uri);
2430
- if (bytes.length === 0) return [""];
2431
- if (bytes.length <= CHUNK_MAX_BYTES) return [uri];
2432
- const decoder = new TextDecoder("utf-8", { fatal: true });
2433
- const chunks = [];
2434
- let cursor = 0;
2435
- while (cursor < bytes.length) {
2436
- let end = Math.min(cursor + CHUNK_MAX_BYTES, bytes.length);
2437
- while (end < bytes.length && (bytes[end] & 192) === 128) end--;
2438
- chunks.push(decoder.decode(bytes.subarray(cursor, end)));
2439
- cursor = end;
2440
- }
2441
- return chunks;
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)");
2442
2716
  }
2443
-
2444
- // src/error-codes.ts
2445
- var STRUCTURAL_ERROR_CODES = [
2446
- // CBOR decode layer. A single code covers every canonical-decode failure —
2447
- // malformed/truncated bytes, indefinite-length encodings, non-canonical
2448
- // (unsorted) map-key ordering, duplicate map keys, non-minimal integers, and
2449
- // invalid UTF-8 by design (no separate duplicate-key code).
2450
- "MALFORMED_CBOR",
2451
- // Generic schema-layer
2452
- "SCHEMA_TYPE_MISMATCH",
2453
- "SCHEMA_MISSING_REQUIRED",
2454
- "SCHEMA_UNKNOWN_FIELD",
2455
- "SCHEMA_INVALID_LITERAL",
2456
- "SCHEMA_EMPTY_RECORD",
2457
- // Hash-map
2458
- "HASH_DIGEST_LENGTH_MISMATCH",
2459
- "UNSUPPORTED_HASH_ALG",
2460
- // Top-level `merkle[]`
2461
- "UNSUPPORTED_MERKLE_COMMIT_ALG",
2462
- // URI / chunking. A chunk whose bytes do not reconstruct to valid UTF-8
2463
- // surfaces as MALFORMED_CBOR at decode (cbor2 rejects invalid-UTF-8 tstr)
2464
- // or, in the residual reconstruct guard, as INVALID_URI — there is no
2465
- // separate codepoint-split code.
2466
- "INVALID_URI",
2467
- "CHUNK_TOO_LARGE",
2468
- // Encryption envelope
2469
- "UNAUTHENTICATED_CIPHER_FORBIDDEN",
2470
- "UNSUPPORTED_AEAD_ALG",
2471
- "NONCE_LENGTH_MISMATCH",
2472
- "UNSUPPORTED_ENVELOPE_SCHEME",
2473
- "ENC_SLOTS_EMPTY",
2474
- "ENC_SLOT_INVALID_SHAPE",
2475
- "UNSUPPORTED_KEM_ALG",
2476
- "ENC_KEM_REQUIRED",
2477
- "KEM_EPK_LENGTH_MISMATCH",
2478
- "KEM_CT_LENGTH_MISMATCH",
2479
- "WRAP_LENGTH_MISMATCH",
2480
- "ENC_SLOTS_MAC_INVALID_LENGTH",
2481
- "ENC_SLOTS_MAC_REQUIRED",
2482
- "ENC_SLOTS_REQUIRED",
2483
- "ENC_EXCLUSIVITY_VIOLATION",
2484
- "ENC_NO_KEY_PATH",
2485
- "ENC_REQUIRES_CONTENT_HASH",
2486
- "ENC_PASSPHRASE_ALG_UNSUPPORTED",
2487
- "ENC_PASSPHRASE_SALT_TOO_SHORT",
2488
- "ENC_PASSPHRASE_SALT_TOO_LONG",
2489
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
2490
- "ENC_PASSPHRASE_PARAMS_EXCEED_POLICY",
2491
- // Signatures
2492
- "MALFORMED_SIG_COSE_SIGN1",
2493
- "SIGNATURE_UNSUPPORTED",
2494
- "SIG_ENTRY_INVALID_SHAPE",
2495
- "SIG_ENTRY_KID_COSE_KEY_CONFLICT",
2496
- "SIG_PRIVATE_KEY_LEAKED",
2497
- // Supersedence
2498
- "SUPERSEDES_TX_INVALID_LENGTH",
2499
- // Forward-compat critical extensions
2500
- "EXTENSION_UNSUPPORTED_CRITICAL",
2501
- "CRIT_SHAPE_INVALID"
2502
- ];
2503
- var VERIFIER_ERROR_CODES = [
2504
- "METADATA_NOT_FOUND",
2505
- "INSUFFICIENT_CONFIRMATIONS",
2506
- "SIGNATURE_INVALID",
2507
- "SIGNER_KEY_UNRESOLVED",
2508
- "WALLET_ADDRESS_MISMATCH",
2509
- "URI_TARGET_FORBIDDEN",
2510
- "URI_INTEGRITY_MISMATCH",
2511
- "URI_FETCH_FAILED",
2512
- "CONTENT_UNAVAILABLE",
2513
- "CIPHERTEXT_UNAVAILABLE",
2514
- "PROVIDER_UNAVAILABLE",
2515
- "SERVICE_INDEPENDENCE_VIOLATION",
2516
- "WRONG_DECRYPTION_INPUT_SHAPE",
2517
- "WRONG_RECIPIENT_KEY",
2518
- "TAMPERED_HEADER",
2519
- "TAMPERED_CIPHERTEXT",
2520
- "KDF_DERIVATION_FAILED",
2521
- "SCHEMA_MERKLE_LEAF_COUNT_MISMATCH",
2522
- "SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED",
2523
- "SCHEMA_MERKLE_LEAVES_MALFORMED",
2524
- "MERKLE_ROOT_MISMATCH",
2525
- "MERKLE_LEAVES_UNAVAILABLE",
2526
- "MERKLE_LEAVES_INFORMATIVE_FORM",
2527
- "MERKLE_UNSUPPORTED",
2528
- "OUT_OF_PROFILE_SKIPPED"
2529
- ];
2530
- var ERROR_CODES = [...STRUCTURAL_ERROR_CODES, ...VERIFIER_ERROR_CODES];
2531
- var SEVERITY = Object.freeze({
2532
- // --- Part A ---
2533
- MALFORMED_CBOR: "error",
2534
- SCHEMA_TYPE_MISMATCH: "error",
2535
- SCHEMA_MISSING_REQUIRED: "error",
2536
- SCHEMA_UNKNOWN_FIELD: "error",
2537
- SCHEMA_INVALID_LITERAL: "error",
2538
- SCHEMA_EMPTY_RECORD: "error",
2539
- HASH_DIGEST_LENGTH_MISMATCH: "error",
2540
- UNSUPPORTED_HASH_ALG: "error",
2541
- UNSUPPORTED_MERKLE_COMMIT_ALG: "error",
2542
- INVALID_URI: "error",
2543
- CHUNK_TOO_LARGE: "error",
2544
- UNAUTHENTICATED_CIPHER_FORBIDDEN: "error",
2545
- UNSUPPORTED_AEAD_ALG: "error",
2546
- NONCE_LENGTH_MISMATCH: "error",
2547
- UNSUPPORTED_ENVELOPE_SCHEME: "error",
2548
- ENC_SLOTS_EMPTY: "error",
2549
- ENC_SLOT_INVALID_SHAPE: "error",
2550
- UNSUPPORTED_KEM_ALG: "error",
2551
- ENC_KEM_REQUIRED: "error",
2552
- KEM_EPK_LENGTH_MISMATCH: "error",
2553
- KEM_CT_LENGTH_MISMATCH: "error",
2554
- WRAP_LENGTH_MISMATCH: "error",
2555
- ENC_SLOTS_MAC_INVALID_LENGTH: "error",
2556
- ENC_SLOTS_MAC_REQUIRED: "error",
2557
- ENC_SLOTS_REQUIRED: "error",
2558
- ENC_EXCLUSIVITY_VIOLATION: "error",
2559
- ENC_NO_KEY_PATH: "error",
2560
- ENC_REQUIRES_CONTENT_HASH: "error",
2561
- ENC_PASSPHRASE_ALG_UNSUPPORTED: "error",
2562
- ENC_PASSPHRASE_SALT_TOO_SHORT: "error",
2563
- ENC_PASSPHRASE_SALT_TOO_LONG: "error",
2564
- ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW: "error",
2565
- ENC_PASSPHRASE_PARAMS_EXCEED_POLICY: "error",
2566
- MALFORMED_SIG_COSE_SIGN1: "error",
2567
- SIGNATURE_UNSUPPORTED: "info",
2568
- SIG_ENTRY_INVALID_SHAPE: "error",
2569
- SIG_ENTRY_KID_COSE_KEY_CONFLICT: "error",
2570
- SIG_PRIVATE_KEY_LEAKED: "error",
2571
- SUPERSEDES_TX_INVALID_LENGTH: "error",
2572
- EXTENSION_UNSUPPORTED_CRITICAL: "error",
2573
- CRIT_SHAPE_INVALID: "error",
2574
- // --- Part B ---
2575
- METADATA_NOT_FOUND: "error",
2576
- INSUFFICIENT_CONFIRMATIONS: "info",
2577
- SIGNATURE_INVALID: "error",
2578
- SIGNER_KEY_UNRESOLVED: "error",
2579
- WALLET_ADDRESS_MISMATCH: "error",
2580
- URI_TARGET_FORBIDDEN: "error",
2581
- URI_INTEGRITY_MISMATCH: "error",
2582
- URI_FETCH_FAILED: "warning",
2583
- CONTENT_UNAVAILABLE: "error",
2584
- CIPHERTEXT_UNAVAILABLE: "error",
2585
- PROVIDER_UNAVAILABLE: "error",
2586
- SERVICE_INDEPENDENCE_VIOLATION: "error",
2587
- WRONG_DECRYPTION_INPUT_SHAPE: "error",
2588
- WRONG_RECIPIENT_KEY: "error",
2589
- TAMPERED_HEADER: "error",
2590
- TAMPERED_CIPHERTEXT: "error",
2591
- KDF_DERIVATION_FAILED: "error",
2592
- SCHEMA_MERKLE_LEAF_COUNT_MISMATCH: "error",
2593
- SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED: "error",
2594
- SCHEMA_MERKLE_LEAVES_MALFORMED: "error",
2595
- MERKLE_ROOT_MISMATCH: "error",
2596
- MERKLE_LEAVES_UNAVAILABLE: "warning",
2597
- MERKLE_LEAVES_INFORMATIVE_FORM: "info",
2598
- // Dual-severity — default reading is `info`; the verifier promotes to
2599
- // `error` for merkle-only records (no `items[]` content claim was
2600
- // validated in the same record).
2601
- MERKLE_UNSUPPORTED: "info",
2602
- // Dual-severity — default reading is `info` (render mode); strict
2603
- // end-to-end verifiers promote to `error`.
2604
- OUT_OF_PROFILE_SKIPPED: "info"
2605
- });
2606
- function severityOf(code) {
2607
- return SEVERITY[code];
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
+ }
2722
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
2723
+ throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
2724
+ }
2725
+ if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
2726
+ throw new Error(
2727
+ "CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
2728
+ );
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
+ }
2735
+ if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
2736
+ throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
2737
+ }
2738
+ var MAX_SLOTS = 1024;
2739
+ var MAX_DECODED_ENVELOPE_BYTES = 65536;
2740
+ var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
2741
+ var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
2742
+ "cardano-poe-kek-mlkem768x25519-v1"
2743
+ );
2744
+ var ZERO_NONCE_12 = new Uint8Array(12);
2745
+ if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
2746
+ throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
2747
+ }
2748
+ if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
2749
+ throw new Error(
2750
+ "CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
2751
+ );
2752
+ }
2753
+ if (ZERO_NONCE_12.length !== 12) {
2754
+ throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
2608
2755
  }
2756
+ new TextEncoder();
2609
2757
 
2610
2758
  // src/validator.ts
2611
2759
  var HASH_ALG_LENGTHS = {
@@ -2616,9 +2764,9 @@ var MERKLE_COMMIT_ALG_LENGTHS = {
2616
2764
  "rfc9162-sha256": 32
2617
2765
  };
2618
2766
  var AEAD_NONCE_LENGTHS = {
2619
- "xchacha20-poly1305": 24
2767
+ "chacha20-poly1305-stream64k": 24
2620
2768
  };
2621
- var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]|\n?$)|^(?:rc4|des|3des)(?:[-_]|\n?$)/i;
2769
+ var UNAUTHENTICATED_CIPHER_RE = /(?:^|[-_])(?:cbc|ctr|ecb|cfb|ofb)(?:[-_]|$)|^(?:rc4|des|3des)(?:[-_]|$)/i;
2622
2770
  var KEM_SLOT_DESCRIPTORS = {
2623
2771
  x25519: { field: "epk", fieldLength: 32, wrapLength: 48 },
2624
2772
  mlkem768x25519: { field: "kem_ct", fieldLength: 1120, wrapLength: 48 }
@@ -2629,13 +2777,31 @@ var KEM_FIELD_LENGTH_CODE = {
2629
2777
  };
2630
2778
  var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
2631
2779
  var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
2632
- function validatePoeRecord(bytes) {
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);
2633
2799
  let decoded;
2634
2800
  try {
2635
2801
  decoded = decodeCanonicalCbor(bytes);
2636
2802
  } catch (cause) {
2637
2803
  return {
2638
- ok: false,
2804
+ valid: false,
2639
2805
  issues: [
2640
2806
  {
2641
2807
  code: "MALFORMED_CBOR",
@@ -2646,132 +2812,181 @@ function validatePoeRecord(bytes) {
2646
2812
  ]
2647
2813
  };
2648
2814
  }
2815
+ const nonTextKeyIssues = collectNonTextKeyMapIssues(decoded);
2816
+ if (nonTextKeyIssues.length > 0) {
2817
+ return { valid: false, issues: sortIssues(nonTextKeyIssues) };
2818
+ }
2649
2819
  const parse = PoeRecordSchema.safeParse(decoded);
2650
2820
  if (!parse.success) {
2651
- const issues = parse.error.issues.map((issue2) => mapZodIssue(issue2, decoded)).sort(compareIssuePath);
2652
- return { ok: false, issues };
2821
+ return { valid: false, issues: sortIssues(mapZodIssues(parse.error.issues, decoded)) };
2653
2822
  }
2654
2823
  const record = parse.data;
2655
- const errors = [];
2656
- const warnings = [];
2657
- const info = [];
2658
- const itemsLen = Array.isArray(record.items) ? record.items.length : 0;
2659
- const merkleLen = Array.isArray(record.merkle) ? record.merkle.length : 0;
2660
- if (itemsLen === 0 && merkleLen === 0) {
2661
- errors.push(
2662
- issue(
2663
- "SCHEMA_EMPTY_RECORD",
2664
- [],
2665
- "record must carry at least one of items[] or merkle[] non-empty"
2666
- )
2667
- );
2668
- }
2824
+ const issues = [];
2825
+ checkContentCommitmentPresence(record, issues);
2669
2826
  const decodedTopKeys = topLevelKeysOf(decoded);
2670
- const critShapeInvalidIndices = checkCritShape(record, decodedTopKeys, errors);
2671
- for (const k4 of decodedTopKeys) {
2672
- if (TOP_LEVEL_BASE_KEYS.has(k4)) continue;
2673
- if (isExtensionKey(k4)) continue;
2674
- errors.push(issue("SCHEMA_UNKNOWN_FIELD", [k4], `unknown top-level field: ${k4}`));
2675
- }
2676
- if (Array.isArray(record.crit)) {
2677
- for (let i = 0; i < record.crit.length; i++) {
2678
- if (critShapeInvalidIndices.has(i)) continue;
2679
- const critName = record.crit[i];
2680
- errors.push(
2681
- issue(
2682
- "EXTENSION_UNSUPPORTED_CRITICAL",
2683
- ["crit", i],
2684
- `crit lists extension '${critName}' that this validator does not implement`
2685
- )
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")
2686
2848
  );
2687
2849
  }
2850
+ for (let i = 0; i < record.sigs.length; i++) {
2851
+ checkSigEntry(record.sigs[i], i, issues);
2852
+ }
2688
2853
  }
2689
- for (let i = 0; i < (record.items ?? []).length; i++) {
2690
- const item = record.items[i];
2691
- checkItemHashes(item, i, errors);
2692
- if (item.uris) checkItemUris(item.uris, ["items", i, "uris"], errors);
2693
- if (item.enc !== void 0) checkItemEnc(item, i, errors);
2694
- }
2695
- for (let i = 0; i < (record.merkle ?? []).length; i++) {
2696
- const commit = record.merkle[i];
2697
- checkMerkleCommit(commit, i, errors);
2854
+ const sorted = sortIssues(issues);
2855
+ if (sorted.some((issue) => issue.severity === "error")) {
2856
+ return { valid: false, issues: sorted };
2698
2857
  }
2699
- if (record.sigs) {
2700
- for (let i = 0; i < record.sigs.length; i++) {
2701
- checkSigEntry(record.sigs[i], i, errors, info);
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;
2702
2875
  }
2876
+ out.push(mapZodIssue(zissue, decodedRoot));
2703
2877
  }
2704
- if (errors.length > 0) {
2705
- return { ok: false, issues: errors.sort(compareIssuePath) };
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";
2706
2883
  }
2707
- const result = {
2708
- ok: true,
2709
- record
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
+ );
2710
2896
  };
2711
- if (warnings.length > 0) result.warnings = warnings.sort(compareIssuePath);
2712
- if (info.length > 0) result.info = info.sort(compareIssuePath);
2713
- return result;
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;
2714
2918
  }
2715
- function mapZodIssue(zissue, decoded) {
2919
+ function mapZodIssue(zissue, decodedRoot) {
2716
2920
  const path = zissue.path;
2717
2921
  const explicit = zissue.params?.code;
2718
2922
  if (explicit !== void 0) {
2719
- return issue(explicit, path, zissue.message);
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
+ );
2720
2932
  }
2721
2933
  const inSigsEntry = path.length >= 2 && path[0] === "sigs" && typeof path[1] === "number";
2722
- const isInSlotEntry = (() => {
2723
- if (path.length >= 5 && path[0] === "items" && typeof path[1] === "number" && path[2] === "enc" && path[3] === "slots" && typeof path[4] === "number") {
2724
- return true;
2725
- }
2726
- if (path.length >= 2 && path[0] === "slots" && typeof path[1] === "number") {
2727
- return true;
2728
- }
2729
- return false;
2730
- })();
2731
- const valueAtIssue = valueAtPath(decoded, path);
2934
+ const isInSlotEntry = path.length >= 2 && path[0] === "slots" && typeof path[1] === "number";
2732
2935
  const isMissing = valueAtIssue === void 0;
2733
2936
  switch (zissue.code) {
2734
2937
  case "invalid_type":
2735
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2938
+ if (isInSlotEntry) return issueOf("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2736
2939
  if (isMissing) {
2737
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2738
- return issue("SCHEMA_MISSING_REQUIRED", path, zissue.message);
2940
+ if (inSigsEntry) return issueOf("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2941
+ return issueOf("SCHEMA_MISSING_REQUIRED", path, zissue.message);
2739
2942
  }
2740
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2741
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2943
+ if (inSigsEntry) return issueOf("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2944
+ return issueOf("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2742
2945
  case "invalid_value":
2743
- if (path.length === 1 && path[0] === "v") {
2744
- return issue(
2745
- isMissing ? "SCHEMA_MISSING_REQUIRED" : "SCHEMA_INVALID_LITERAL",
2746
- path,
2747
- zissue.message
2748
- );
2749
- }
2750
- return issue("SCHEMA_INVALID_LITERAL", path, zissue.message);
2751
- case "unrecognized_keys":
2752
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2753
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2754
- 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":
2755
2949
  case "invalid_format":
2756
2950
  case "too_big":
2757
2951
  case "too_small":
2758
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2759
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
2760
- case "invalid_union":
2761
2952
  case "invalid_key":
2762
2953
  case "invalid_element":
2763
2954
  case "custom":
2764
2955
  default:
2765
- if (isInSlotEntry) return issue("ENC_SLOT_INVALID_SHAPE", path, zissue.message);
2766
- if (inSigsEntry) return issue("SIG_ENTRY_INVALID_SHAPE", path, zissue.message);
2767
- return issue("SCHEMA_TYPE_MISMATCH", path, zissue.message);
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);
2959
+ }
2960
+ }
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
+ );
2768
2983
  }
2769
2984
  }
2770
- function checkItemHashes(item, idx, errors) {
2985
+ function checkItemHashes(item, idx, issues) {
2771
2986
  const entries = Object.entries(item.hashes);
2772
2987
  if (entries.length === 0) {
2773
- errors.push(
2774
- issue(
2988
+ issues.push(
2989
+ issueOf(
2775
2990
  "SCHEMA_TYPE_MISMATCH",
2776
2991
  ["items", idx, "hashes"],
2777
2992
  "hashes must be a non-empty CBOR map of <alg-id> -> <digest>"
@@ -2781,15 +2996,15 @@ function checkItemHashes(item, idx, errors) {
2781
2996
  }
2782
2997
  for (const [alg, digest] of entries) {
2783
2998
  if (!(alg in HASH_ALG_LENGTHS)) {
2784
- errors.push(
2785
- issue("UNSUPPORTED_HASH_ALG", ["items", idx, "hashes", alg], `unknown hash alg: ${alg}`)
2999
+ issues.push(
3000
+ issueOf("UNSUPPORTED_HASH_ALG", ["items", idx, "hashes", alg], `unknown hash alg: ${alg}`)
2786
3001
  );
2787
3002
  continue;
2788
3003
  }
2789
3004
  const expected = HASH_ALG_LENGTHS[alg];
2790
3005
  if (digest.length !== expected) {
2791
- errors.push(
2792
- issue(
3006
+ issues.push(
3007
+ issueOf(
2793
3008
  "HASH_DIGEST_LENGTH_MISMATCH",
2794
3009
  ["items", idx, "hashes", alg],
2795
3010
  `hashes['${alg}'] digest length ${digest.length} != ${expected}`
@@ -2798,35 +3013,33 @@ function checkItemHashes(item, idx, errors) {
2798
3013
  }
2799
3014
  }
2800
3015
  }
2801
- function checkItemUris(uris, basePath, errors) {
2802
- uris.forEach((chunks, ui) => validateOneUri(chunks, [...basePath, ui], errors));
2803
- }
2804
- function validateOneUri(chunks, path, errors) {
2805
- const reconstructed = reconstructChunkedUri(chunks);
2806
- if (!reconstructed.ok) {
2807
- 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"));
2808
3019
  return;
2809
3020
  }
2810
- const uri = reconstructed.uri;
3021
+ uris.forEach((uri, ui) => checkOneUri(uri, [...basePath, ui], issues));
3022
+ }
3023
+ function checkOneUri(uri, path, issues) {
2811
3024
  if (uri.includes("#")) {
2812
- errors.push(
2813
- issue("INVALID_URI", path, "URI contains a fragment identifier ('#'), which is forbidden")
3025
+ issues.push(
3026
+ issueOf("INVALID_URI", path, "URI contains a fragment identifier ('#'), which is forbidden")
2814
3027
  );
2815
3028
  return;
2816
3029
  }
2817
3030
  const sepIdx = uri.indexOf("://");
2818
3031
  if (sepIdx <= 0 || !/^[a-z][a-z0-9+.-]*$/i.test(uri.slice(0, sepIdx))) {
2819
- errors.push(
2820
- issue("INVALID_URI", path, "URI is not absolute (missing scheme://hierarchical-part)")
3032
+ issues.push(
3033
+ issueOf("INVALID_URI", path, "URI is not absolute (missing scheme://hierarchical-part)")
2821
3034
  );
2822
3035
  return;
2823
3036
  }
2824
3037
  const scheme = uri.slice(0, sepIdx).toLowerCase();
2825
3038
  const rest = uri.slice(sepIdx + "://".length);
2826
3039
  if (scheme === "ar") {
2827
- if (!/^ar:\/\/[A-Za-z0-9_-]{43}$/.test("ar://" + rest)) {
2828
- errors.push(
2829
- issue(
3040
+ if (!/^[A-Za-z0-9_-]{43}$/.test(rest)) {
3041
+ issues.push(
3042
+ issueOf(
2830
3043
  "INVALID_URI",
2831
3044
  path,
2832
3045
  "ar:// URI does not match `^ar://[A-Za-z0-9_-]{43}$` (43-char base64url txid, no path/query/fragment)"
@@ -2839,277 +3052,286 @@ function validateOneUri(chunks, path, errors) {
2839
3052
  const slashIdx = rest.indexOf("/");
2840
3053
  const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
2841
3054
  if (!validateCidProfile(cid)) {
2842
- errors.push(
2843
- issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
3055
+ issues.push(
3056
+ issueOf("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
2844
3057
  );
2845
3058
  }
2846
3059
  return;
2847
3060
  }
2848
- errors.push(
2849
- issue("INVALID_URI", path, "unsupported URI scheme; v1 PoE URI set is {ar://, ipfs://}")
3061
+ issues.push(
3062
+ issueOf("INVALID_URI", path, "unsupported URI scheme; v1 PoE URI set is {ar://, ipfs://}")
2850
3063
  );
2851
3064
  }
2852
- function checkItemEnc(item, idx, errors) {
3065
+ function checkItemEnc(item, idx, opts, issues) {
3066
+ const encPath = ["items", idx, "enc"];
2853
3067
  const hasContentHash = Object.keys(item.hashes).some((alg) => alg in HASH_ALG_LENGTHS);
2854
3068
  if (!hasContentHash) {
2855
- errors.push(
2856
- issue(
3069
+ issues.push(
3070
+ issueOf(
2857
3071
  "ENC_REQUIRES_CONTENT_HASH",
2858
- ["items", idx, "enc"],
2859
- "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)"
2860
3074
  )
2861
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"));
2862
3080
  return;
2863
3081
  }
2864
- const encParse = EncryptionEnvelopeSchema.safeParse(item.enc);
2865
- if (!encParse.success) {
2866
- for (const zissue of encParse.error.issues) {
2867
- const mapped = mapZodIssue(zissue, item.enc);
2868
- errors.push({
2869
- ...mapped,
2870
- path: ["items", idx, "enc", ...mapped.path]
2871
- });
2872
- }
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
+ );
2873
3098
  return;
2874
3099
  }
2875
- const enc = encParse.data;
2876
- const basePath = ["items", idx, "enc"];
2877
- if (typeof enc.scheme !== "number" || !Number.isInteger(enc.scheme) || enc.scheme !== 1) {
2878
- errors.push(
2879
- issue(
2880
- "UNSUPPORTED_ENVELOPE_SCHEME",
2881
- [...basePath, "scheme"],
2882
- `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"
2883
3106
  )
2884
3107
  );
3108
+ return;
2885
3109
  }
2886
- if (UNAUTHENTICATED_CIPHER_RE.test(enc.aead)) {
2887
- errors.push(
2888
- issue(
3110
+ const aead = enc["aead"];
3111
+ if (typeof aead === "string" && UNAUTHENTICATED_CIPHER_RE.test(aead)) {
3112
+ issues.push(
3113
+ issueOf(
2889
3114
  "UNAUTHENTICATED_CIPHER_FORBIDDEN",
2890
- [...basePath, "aead"],
2891
- `'${enc.aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
3115
+ [...encPath, "aead"],
3116
+ `'${aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
2892
3117
  )
2893
3118
  );
2894
3119
  return;
2895
3120
  }
2896
- if (!(enc.aead in AEAD_NONCE_LENGTHS)) {
2897
- errors.push(
2898
- issue("UNSUPPORTED_AEAD_ALG", [...basePath, "aead"], `unknown aead alg: ${enc.aead}`)
2899
- );
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);
3150
+ return;
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
+ }
2900
3157
  return;
2901
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) {
2902
3188
  const expectedNonceLen = AEAD_NONCE_LENGTHS[enc.aead];
2903
3189
  if (enc.nonce.length !== expectedNonceLen) {
2904
- errors.push(
2905
- issue(
3190
+ issues.push(
3191
+ issueOf(
2906
3192
  "NONCE_LENGTH_MISMATCH",
2907
- [...basePath, "nonce"],
3193
+ [...encPath, "nonce"],
2908
3194
  `nonce length ${enc.nonce.length} != ${expectedNonceLen} for ${enc.aead}`
2909
3195
  )
2910
3196
  );
2911
3197
  }
2912
- if (enc.kem !== void 0 && !(enc.kem in KEM_SLOT_DESCRIPTORS)) {
2913
- errors.push(issue("UNSUPPORTED_KEM_ALG", [...basePath, "kem"], `unknown kem alg: ${enc.kem}`));
2914
- }
2915
3198
  const hasSlots = enc.slots !== void 0;
2916
3199
  const hasSlotsMac = enc.slots_mac !== void 0;
2917
3200
  const hasPassphrase = enc.passphrase !== void 0;
2918
- if (hasSlots && hasPassphrase) {
2919
- errors.push(
2920
- issue("ENC_EXCLUSIVITY_VIOLATION", basePath, "enc combines slots with passphrase; pick one")
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
+ )
2921
3209
  );
2922
3210
  }
2923
3211
  if (hasSlots && !hasSlotsMac) {
2924
- errors.push(
2925
- issue("ENC_SLOTS_MAC_REQUIRED", basePath, "enc.slots present but enc.slots_mac absent")
3212
+ issues.push(
3213
+ issueOf("ENC_SLOTS_MAC_REQUIRED", encPath, "enc.slots present but enc.slots_mac absent")
2926
3214
  );
2927
3215
  }
2928
3216
  if (hasSlotsMac && !hasSlots) {
2929
- errors.push(
2930
- issue("ENC_SLOTS_REQUIRED", basePath, "enc.slots_mac present but enc.slots absent")
3217
+ issues.push(
3218
+ issueOf("ENC_SLOTS_REQUIRED", encPath, "enc.slots_mac present but enc.slots absent")
2931
3219
  );
2932
3220
  }
2933
- if (hasSlots && enc.kem === void 0) {
2934
- errors.push(issue("ENC_KEM_REQUIRED", basePath, "enc.slots present but enc.kem absent"));
3221
+ if (hasSlots && !hasKem) {
3222
+ issues.push(issueOf("ENC_KEM_REQUIRED", encPath, "enc.slots present but enc.kem absent"));
2935
3223
  }
2936
3224
  if (!hasSlots && !hasPassphrase) {
2937
- errors.push(
2938
- issue(
3225
+ issues.push(
3226
+ issueOf(
2939
3227
  "ENC_NO_KEY_PATH",
2940
- basePath,
3228
+ encPath,
2941
3229
  "enc requires either slots or passphrase \u2014 no on-chain key path otherwise"
2942
3230
  )
2943
3231
  );
2944
3232
  }
2945
3233
  if (hasSlots) {
2946
- if (enc.slots.length < 1) {
2947
- errors.push(
2948
- issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${enc.slots.length} < 1`)
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")
2949
3238
  );
2950
- }
2951
- const descriptor = enc.kem !== void 0 ? KEM_SLOT_DESCRIPTORS[enc.kem] : void 0;
2952
- if (descriptor !== void 0) {
2953
- const rawSlotKeys = rawSlotKeySets(item.enc);
2954
- enc.slots.forEach((slot, si) => {
3239
+ } else if (slots.length > opts.maxSlots) {
3240
+ issues.push(
3241
+ issueOf(
3242
+ "ENC_SLOTS_TOO_MANY",
3243
+ [...encPath, "slots"],
3244
+ `slots length ${slots.length} exceeds the slot-count bound ${opts.maxSlots}`
3245
+ )
3246
+ );
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];
2955
3253
  checkSlotShape(
2956
3254
  slot,
2957
3255
  rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
2958
3256
  descriptor,
2959
3257
  enc.kem,
2960
- [...basePath, "slots", si],
2961
- errors
3258
+ slotPath,
3259
+ issues
2962
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);
3274
+ }
3275
+ }
2963
3276
  });
2964
3277
  }
2965
3278
  }
2966
3279
  if (hasPassphrase) {
2967
- const pp = enc.passphrase;
2968
- const ppPath = [...basePath, "passphrase"];
2969
- if (!PASSPHRASE_KDF_ALGS.has(pp.alg)) {
2970
- errors.push(
2971
- issue(
2972
- "ENC_PASSPHRASE_ALG_UNSUPPORTED",
2973
- [...ppPath, "alg"],
2974
- `unknown passphrase kdf alg: ${pp.alg}`
2975
- )
2976
- );
2977
- return;
2978
- }
2979
- if (pp.alg === "argon2id") {
2980
- const allowed = /* @__PURE__ */ new Set(["m", "t", "p"]);
2981
- for (const k4 of Object.keys(pp.params)) {
2982
- if (!allowed.has(k4)) {
2983
- errors.push(
2984
- issue(
2985
- "SCHEMA_UNKNOWN_FIELD",
2986
- [...ppPath, "params", k4],
2987
- `unknown argon2id params field: ${k4}`
2988
- )
2989
- );
2990
- }
2991
- }
2992
- const p5 = pp.params;
2993
- const argonInt = (val, name) => {
2994
- if (typeof val !== "number" || !Number.isInteger(val)) {
2995
- errors.push(
2996
- issue(
2997
- "SCHEMA_TYPE_MISMATCH",
2998
- [...ppPath, "params", name],
2999
- `argon2id params.${name} must be a CBOR unsigned integer`
3000
- )
3001
- );
3002
- return null;
3003
- }
3004
- return val;
3005
- };
3006
- const mVal = argonInt(p5.m, "m");
3007
- const tVal = argonInt(p5.t, "t");
3008
- const pVal = argonInt(p5.p, "p");
3009
- if (mVal !== null && mVal < 65536) {
3010
- errors.push(
3011
- issue(
3012
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
3013
- [...ppPath, "params", "m"],
3014
- "argon2id requires m >= 65536 KiB"
3015
- )
3016
- );
3017
- }
3018
- if (tVal !== null && tVal < 3) {
3019
- errors.push(
3020
- issue(
3021
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
3022
- [...ppPath, "params", "t"],
3023
- "argon2id requires t >= 3"
3024
- )
3025
- );
3026
- }
3027
- if (pVal !== null && pVal < 1) {
3028
- errors.push(
3029
- issue(
3030
- "ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW",
3031
- [...ppPath, "params", "p"],
3032
- "argon2id requires p >= 1"
3033
- )
3034
- );
3035
- }
3036
- }
3280
+ checkPassphraseBlock(enc.passphrase, [...encPath, "passphrase"], opts, issues);
3037
3281
  }
3038
3282
  }
3039
3283
  var SLOT_KEY_UNIVERSE = /* @__PURE__ */ new Set(["epk", "kem_ct", "wrap"]);
3040
- function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
3284
+ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, issues) {
3041
3285
  const foreignField = descriptor.field === "epk" ? "kem_ct" : "epk";
3042
3286
  if (rawKeys.has(foreignField)) {
3043
- errors.push(
3044
- issue(
3287
+ issues.push(
3288
+ issueOf(
3045
3289
  "ENC_SLOT_INVALID_SHAPE",
3046
3290
  [...slotPath, foreignField],
3047
3291
  `slot carries '${foreignField}' but kem='${kem}' expects '${descriptor.field}'`
3048
3292
  )
3049
3293
  );
3050
3294
  }
3051
- for (const k4 of rawKeys) {
3052
- if (!SLOT_KEY_UNIVERSE.has(k4)) {
3053
- errors.push(
3054
- issue(
3295
+ for (const key of rawKeys) {
3296
+ if (!SLOT_KEY_UNIVERSE.has(key)) {
3297
+ issues.push(
3298
+ issueOf(
3055
3299
  "ENC_SLOT_INVALID_SHAPE",
3056
- [...slotPath, k4],
3057
- `slot carries unexpected key '${k4}'; a slot is a 2-key map {${descriptor.field}, wrap}`
3300
+ [...slotPath, key],
3301
+ `slot carries unexpected key '${key}'; a slot is a 2-key map {${descriptor.field}, wrap}`
3058
3302
  )
3059
3303
  );
3060
3304
  }
3061
3305
  }
3062
- if (descriptor.field === "epk") {
3063
- if (slot.epk === void 0) {
3064
- errors.push(
3065
- issue(
3066
- "ENC_SLOT_INVALID_SHAPE",
3067
- [...slotPath, "epk"],
3068
- `slot for kem='${kem}' is missing required 'epk'`
3069
- )
3070
- );
3071
- } else if (slot.epk.length !== descriptor.fieldLength) {
3072
- errors.push(
3073
- issue(
3074
- KEM_FIELD_LENGTH_CODE.epk,
3075
- [...slotPath, "epk"],
3076
- `slot.epk length ${slot.epk.length} != ${descriptor.fieldLength} for ${kem}`
3077
- )
3078
- );
3079
- }
3080
- } else {
3081
- if (slot.kem_ct === void 0) {
3082
- errors.push(
3083
- issue(
3084
- "ENC_SLOT_INVALID_SHAPE",
3085
- [...slotPath, "kem_ct"],
3086
- `slot for kem='${kem}' is missing required 'kem_ct'`
3087
- )
3088
- );
3089
- } else {
3090
- const reassembled = bytesChunkArrayConcat(slot.kem_ct).length;
3091
- if (reassembled !== descriptor.fieldLength) {
3092
- errors.push(
3093
- issue(
3094
- KEM_FIELD_LENGTH_CODE.kem_ct,
3095
- [...slotPath, "kem_ct"],
3096
- `slot.kem_ct reassembles to ${reassembled} bytes != ${descriptor.fieldLength} for ${kem}`
3097
- )
3098
- );
3099
- }
3100
- }
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
+ );
3101
3323
  }
3102
3324
  if (slot.wrap === void 0) {
3103
- errors.push(
3104
- issue(
3325
+ issues.push(
3326
+ issueOf(
3105
3327
  "ENC_SLOT_INVALID_SHAPE",
3106
3328
  [...slotPath, "wrap"],
3107
3329
  `slot for kem='${kem}' is missing required 'wrap'`
3108
3330
  )
3109
3331
  );
3110
3332
  } else if (slot.wrap.length !== descriptor.wrapLength) {
3111
- errors.push(
3112
- issue(
3333
+ issues.push(
3334
+ issueOf(
3113
3335
  "WRAP_LENGTH_MISMATCH",
3114
3336
  [...slotPath, "wrap"],
3115
3337
  `slot.wrap length ${slot.wrap.length} != ${descriptor.wrapLength}`
@@ -3117,8 +3339,88 @@ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
3117
3339
  );
3118
3340
  }
3119
3341
  }
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;
3352
+ }
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
+ }
3420
+ }
3421
+ }
3120
3422
  function rawSlotKeySets(rawEnc) {
3121
- const slots = mapLikeGet(rawEnc, "slots");
3423
+ const slots = rawEnc["slots"];
3122
3424
  if (!Array.isArray(slots)) return [];
3123
3425
  return slots.map((slot) => {
3124
3426
  const keys = /* @__PURE__ */ new Set();
@@ -3130,54 +3432,64 @@ function rawSlotKeySets(rawEnc) {
3130
3432
  return keys;
3131
3433
  });
3132
3434
  }
3133
- function mapLikeGet(value, key) {
3134
- if (value instanceof Map) return value.get(key);
3135
- if (typeof value === "object" && value !== null) {
3136
- return value[key];
3137
- }
3138
- return void 0;
3139
- }
3140
- function checkMerkleCommit(commit, idx, errors) {
3435
+ function checkMerkleCommit(commit, idx, issues) {
3141
3436
  const basePath = ["merkle", idx];
3142
3437
  if (!(commit.alg in MERKLE_COMMIT_ALG_LENGTHS)) {
3143
- errors.push(
3144
- issue(
3438
+ issues.push(
3439
+ issueOf(
3145
3440
  "UNSUPPORTED_MERKLE_COMMIT_ALG",
3146
3441
  [...basePath, "alg"],
3147
3442
  `unknown merkle commitment alg: ${commit.alg}`
3148
3443
  )
3149
3444
  );
3150
- return;
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
+ }
3151
3456
  }
3152
- const expected = MERKLE_COMMIT_ALG_LENGTHS[commit.alg];
3153
- if (commit.root.length !== expected) {
3154
- errors.push(
3155
- issue(
3156
- "HASH_DIGEST_LENGTH_MISMATCH",
3157
- [...basePath, "root"],
3158
- `merkle entry root length ${commit.root.length} != ${expected} for ${commit.alg}`
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`
3159
3472
  )
3160
3473
  );
3161
3474
  }
3162
- if (commit.uris) {
3163
- checkItemUris(commit.uris, [...basePath, "uris"], errors);
3475
+ if (commit.uris !== void 0) {
3476
+ checkUris(commit.uris, [...basePath, "uris"], issues);
3164
3477
  }
3165
3478
  }
3166
- function checkSigEntry(entry, idx, errors, info) {
3479
+ function checkSigEntry(entry, idx, issues) {
3167
3480
  if (entry.cose_key !== void 0) {
3168
3481
  const keyIssue = inspectCoseKey(entry.cose_key, idx);
3169
3482
  if (keyIssue !== null) {
3170
- errors.push(keyIssue);
3483
+ issues.push(keyIssue);
3171
3484
  return;
3172
3485
  }
3173
3486
  }
3174
- const merged = bytesChunkArrayConcat(entry.cose_sign1);
3175
3487
  let cose;
3176
3488
  try {
3177
- cose = decodeCoseSign1(merged);
3489
+ cose = decodeCoseSign1(entry.cose_sign1);
3178
3490
  } catch (cause) {
3179
- errors.push(
3180
- issue(
3491
+ issues.push(
3492
+ issueOf(
3181
3493
  "MALFORMED_SIG_COSE_SIGN1",
3182
3494
  ["sigs", idx],
3183
3495
  cause instanceof CoseVerifyError || cause instanceof Error ? cause.message : String(cause)
@@ -3186,8 +3498,8 @@ function checkSigEntry(entry, idx, errors, info) {
3186
3498
  return;
3187
3499
  }
3188
3500
  if (cose.payload !== null) {
3189
- errors.push(
3190
- issue(
3501
+ issues.push(
3502
+ issueOf(
3191
3503
  "MALFORMED_SIG_COSE_SIGN1",
3192
3504
  ["sigs", idx],
3193
3505
  "COSE_Sign1 payload must be null (detached); attached form forbidden"
@@ -3197,8 +3509,8 @@ function checkSigEntry(entry, idx, errors, info) {
3197
3509
  }
3198
3510
  const alg = cose.protectedHeader.get(1);
3199
3511
  if (typeof alg !== "number" || !KNOWN_SIG_ALG_IDS.has(alg)) {
3200
- info.push(
3201
- issue(
3512
+ issues.push(
3513
+ issueOf(
3202
3514
  "SIGNATURE_UNSUPPORTED",
3203
3515
  ["sigs", idx],
3204
3516
  `COSE_Sign1 protected alg ${String(alg)} not in {-8, -19}`
@@ -3207,8 +3519,8 @@ function checkSigEntry(entry, idx, errors, info) {
3207
3519
  }
3208
3520
  const protectedKid = cose.protectedHeader.get(4);
3209
3521
  if (protectedKid instanceof Uint8Array && protectedKid.length === 32 && entry.cose_key !== void 0) {
3210
- errors.push(
3211
- issue(
3522
+ issues.push(
3523
+ issueOf(
3212
3524
  "SIG_ENTRY_KID_COSE_KEY_CONFLICT",
3213
3525
  ["sigs", idx],
3214
3526
  "sigs[i] carries both a 32-byte protected `kid` (path 1) and an inline `cose_key` (path 2); paths are mutually exclusive"
@@ -3216,12 +3528,12 @@ function checkSigEntry(entry, idx, errors, info) {
3216
3528
  );
3217
3529
  }
3218
3530
  }
3219
- function inspectCoseKey(keyChunks, i) {
3531
+ function inspectCoseKey(keyBytes, i) {
3220
3532
  let decoded;
3221
3533
  try {
3222
- decoded = decodeCanonicalCbor(bytesChunkArrayConcat(keyChunks));
3534
+ decoded = decodeCanonicalCbor(keyBytes);
3223
3535
  } catch (cause) {
3224
- return issue(
3536
+ return issueOf(
3225
3537
  "MALFORMED_SIG_COSE_SIGN1",
3226
3538
  ["sigs", i, "cose_key"],
3227
3539
  `sigs[${i}].cose_key failed to decode as cbor<COSE_Key>: ${cause instanceof Error ? cause.message : String(cause)}`
@@ -3229,20 +3541,14 @@ function inspectCoseKey(keyChunks, i) {
3229
3541
  }
3230
3542
  const getLabel = (label) => {
3231
3543
  if (decoded instanceof Map) return decoded.get(label);
3232
- if (typeof decoded === "object" && decoded !== null) {
3233
- return decoded[String(label)];
3234
- }
3235
3544
  return void 0;
3236
3545
  };
3237
3546
  const hasLabel = (label) => {
3238
3547
  if (decoded instanceof Map) return decoded.has(label);
3239
- if (typeof decoded === "object" && decoded !== null) {
3240
- return Object.prototype.hasOwnProperty.call(decoded, String(label));
3241
- }
3242
3548
  return false;
3243
3549
  };
3244
3550
  if (hasLabel(-4)) {
3245
- return issue(
3551
+ return issueOf(
3246
3552
  "SIG_PRIVATE_KEY_LEAKED",
3247
3553
  ["sigs", i, "cose_key"],
3248
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"
@@ -3250,7 +3556,7 @@ function inspectCoseKey(keyChunks, i) {
3250
3556
  }
3251
3557
  const kty = getLabel(1);
3252
3558
  if (kty !== 1) {
3253
- return issue(
3559
+ return issueOf(
3254
3560
  "MALFORMED_SIG_COSE_SIGN1",
3255
3561
  ["sigs", i, "cose_key"],
3256
3562
  `sigs[${i}].cose_key COSE_Key kty (label 1) must be 1 (OKP); got ${String(kty)}`
@@ -3258,23 +3564,16 @@ function inspectCoseKey(keyChunks, i) {
3258
3564
  }
3259
3565
  const crv = getLabel(-1);
3260
3566
  if (crv !== 6) {
3261
- return issue(
3567
+ return issueOf(
3262
3568
  "MALFORMED_SIG_COSE_SIGN1",
3263
3569
  ["sigs", i, "cose_key"],
3264
3570
  `sigs[${i}].cose_key COSE_Key crv (label -1) must be 6 (Ed25519); got ${String(crv)}`
3265
3571
  );
3266
3572
  }
3267
- if (!hasLabel(-2)) {
3268
- return issue(
3269
- "MALFORMED_SIG_COSE_SIGN1",
3270
- ["sigs", i, "cose_key"],
3271
- `sigs[${i}].cose_key COSE_Key missing label -2 (Ed25519 public-key bytes)`
3272
- );
3273
- }
3274
3573
  const x5 = getLabel(-2);
3275
3574
  if (!(x5 instanceof Uint8Array) || x5.length !== 32) {
3276
3575
  const got = x5 instanceof Uint8Array ? `${x5.length}-byte bstr` : typeof x5;
3277
- return issue(
3576
+ return issueOf(
3278
3577
  "MALFORMED_SIG_COSE_SIGN1",
3279
3578
  ["sigs", i, "cose_key"],
3280
3579
  `sigs[${i}].cose_key COSE_Key label -2 must be a 32-byte byte string (Ed25519 public key); got ${got}`
@@ -3282,6 +3581,58 @@ function inspectCoseKey(keyChunks, i) {
3282
3581
  }
3283
3582
  return null;
3284
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
+ }
3285
3636
  var ACCEPTED_CIDV1_MULTIBASE = /* @__PURE__ */ new Set(["b", "B", "f", "F", "z"]);
3286
3637
  var ACCEPTED_MULTICODECS = /* @__PURE__ */ new Set([85, 112, 113]);
3287
3638
  var ACCEPTED_MULTIHASHES = /* @__PURE__ */ new Map([
@@ -3417,52 +3768,56 @@ function decodeBase58btc(s3) {
3417
3768
  }
3418
3769
  return out;
3419
3770
  }
3420
- function checkCritShape(record, decodedTopKeys, errors) {
3421
- const invalid = /* @__PURE__ */ new Set();
3422
- if (!Array.isArray(record.crit)) return invalid;
3423
- if (record.crit.length === 0) {
3424
- errors.push(
3425
- issue("SCHEMA_TYPE_MISMATCH", ["crit"], "crit[] must carry at least one entry when present")
3426
- );
3427
- return invalid;
3428
- }
3429
- const seen = /* @__PURE__ */ new Set();
3430
- for (let i = 0; i < record.crit.length; i++) {
3431
- const critName = record.crit[i];
3432
- let reason = null;
3433
- if (TOP_LEVEL_BASE_KEYS.has(critName)) {
3434
- reason = `'${critName}' is a base key and MUST NOT appear in crit[]`;
3435
- } else if (!isExtensionKey(critName)) {
3436
- reason = `'${critName}' does not match the extension-key regex (^x-.+ or ^[a-z]+-.+)`;
3437
- } else if (!decodedTopKeys.has(critName)) {
3438
- reason = `'${critName}' is named in crit but absent from the record map`;
3439
- } else if (seen.has(critName)) {
3440
- reason = `'${critName}' appears more than once in crit[]`;
3441
- }
3442
- seen.add(critName);
3443
- if (reason !== null) {
3444
- invalid.add(i);
3445
- errors.push(issue("CRIT_SHAPE_INVALID", ["crit", i], reason));
3446
- }
3447
- }
3448
- 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;
3449
3775
  }
3450
- function topLevelKeysOf(decoded) {
3451
- if (decoded === null || typeof decoded !== "object") return /* @__PURE__ */ new Set();
3452
- if (decoded instanceof Map) {
3453
- const out = /* @__PURE__ */ new Set();
3454
- for (const k4 of decoded.keys()) {
3455
- if (typeof k4 === "string") out.add(k4);
3456
- }
3457
- return out;
3458
- }
3459
- 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;
3460
3784
  }
3461
- function issue(code, path, message) {
3785
+ function issueOf(code, path, message) {
3462
3786
  return { code, path, message, severity: SEVERITY[code] };
3463
3787
  }
3464
- function compareIssuePath(a4, b5) {
3465
- return a4.path.join(".").localeCompare(b5.path.join("."));
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);
3466
3821
  }
3467
3822
  function valueAtPath(root, path) {
3468
3823
  let cur = root;
@@ -3484,10 +3839,15 @@ function valueAtPath(root, path) {
3484
3839
  */
3485
3840
 
3486
3841
  exports.Argon2idParamsSchema = Argon2idParamsSchema;
3487
- exports.ChunkedBytesArraySchema = ChunkedBytesArraySchema;
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;
3488
3845
  exports.ERROR_CODES = ERROR_CODES;
3846
+ exports.ERROR_CODE_PART = ERROR_CODE_PART;
3489
3847
  exports.EXTENSION_KEY_COMPANION_RE = EXTENSION_KEY_COMPANION_RE;
3490
3848
  exports.EXTENSION_KEY_VENDOR_RE = EXTENSION_KEY_VENDOR_RE;
3849
+ exports.EncOpaqueSchema = EncOpaqueSchema;
3850
+ exports.EncScheme1Schema = EncScheme1Schema;
3491
3851
  exports.EncryptionEnvelopeSchema = EncryptionEnvelopeSchema;
3492
3852
  exports.HashDigestSchema = HashDigestSchema;
3493
3853
  exports.HashesMapSchema = HashesMapSchema;
@@ -3501,16 +3861,17 @@ exports.SigEntrySchema = SigEntrySchema;
3501
3861
  exports.SlotSchema = SlotSchema;
3502
3862
  exports.SupersedesSchema = SupersedesSchema;
3503
3863
  exports.TOP_LEVEL_BASE_KEYS = TOP_LEVEL_BASE_KEYS;
3504
- exports.UriChunkArraySchema = UriChunkArraySchema;
3864
+ exports.TRANSPORT_CHUNK_MAX_BYTES = TRANSPORT_CHUNK_MAX_BYTES;
3865
+ exports.UriSchema = UriSchema;
3505
3866
  exports.VERIFIER_ERROR_CODES = VERIFIER_ERROR_CODES;
3506
3867
  exports.VersionLiteralSchema = VersionLiteralSchema;
3507
- exports.bytesChunkArrayConcat = bytesChunkArrayConcat;
3508
- exports.chunkBytes = chunkBytes;
3509
- exports.chunkUri = chunkUri;
3868
+ exports.chunkRecordBody = chunkRecordBody;
3869
+ exports.encodeLabel309Value = encodeLabel309Value;
3510
3870
  exports.encodePoeRecord = encodePoeRecord;
3511
3871
  exports.encodeRecordBodyForSigning = encodeRecordBodyForSigning;
3872
+ exports.errorCodeRegistryIndex = errorCodeRegistryIndex;
3512
3873
  exports.isExtensionKey = isExtensionKey;
3513
- exports.reconstructChunkedUri = reconstructChunkedUri;
3874
+ exports.reassembleLabel309Value = reassembleLabel309Value;
3514
3875
  exports.severityOf = severityOf;
3515
3876
  exports.validateCidProfile = validateCidProfile;
3516
3877
  exports.validatePoeRecord = validatePoeRecord;