@cardanowall/crypto-core 0.0.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.
Files changed (81) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +192 -0
  3. package/dist/aead.cjs +44 -0
  4. package/dist/aead.cjs.map +1 -0
  5. package/dist/aead.d.cts +38 -0
  6. package/dist/aead.d.ts +38 -0
  7. package/dist/aead.js +38 -0
  8. package/dist/aead.js.map +1 -0
  9. package/dist/cbor.cjs +69 -0
  10. package/dist/cbor.cjs.map +1 -0
  11. package/dist/cbor.d.cts +17 -0
  12. package/dist/cbor.d.ts +17 -0
  13. package/dist/cbor.js +64 -0
  14. package/dist/cbor.js.map +1 -0
  15. package/dist/cose.cjs +430 -0
  16. package/dist/cose.cjs.map +1 -0
  17. package/dist/cose.d.cts +72 -0
  18. package/dist/cose.d.ts +72 -0
  19. package/dist/cose.js +398 -0
  20. package/dist/cose.js.map +1 -0
  21. package/dist/hash.cjs +165 -0
  22. package/dist/hash.cjs.map +1 -0
  23. package/dist/hash.d.cts +30 -0
  24. package/dist/hash.d.ts +30 -0
  25. package/dist/hash.js +155 -0
  26. package/dist/hash.js.map +1 -0
  27. package/dist/index.cjs +1856 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +12 -0
  30. package/dist/index.d.ts +12 -0
  31. package/dist/index.js +1759 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/kdf.cjs +26 -0
  34. package/dist/kdf.cjs.map +1 -0
  35. package/dist/kdf.d.cts +25 -0
  36. package/dist/kdf.d.ts +25 -0
  37. package/dist/kdf.js +23 -0
  38. package/dist/kdf.js.map +1 -0
  39. package/dist/kem.cjs +86 -0
  40. package/dist/kem.cjs.map +1 -0
  41. package/dist/kem.d.cts +47 -0
  42. package/dist/kem.d.ts +47 -0
  43. package/dist/kem.js +73 -0
  44. package/dist/kem.js.map +1 -0
  45. package/dist/merkle.cjs +284 -0
  46. package/dist/merkle.cjs.map +1 -0
  47. package/dist/merkle.d.cts +24 -0
  48. package/dist/merkle.d.ts +24 -0
  49. package/dist/merkle.js +279 -0
  50. package/dist/merkle.js.map +1 -0
  51. package/dist/recipient.cjs +141 -0
  52. package/dist/recipient.cjs.map +1 -0
  53. package/dist/recipient.d.cts +16 -0
  54. package/dist/recipient.d.ts +16 -0
  55. package/dist/recipient.js +135 -0
  56. package/dist/recipient.js.map +1 -0
  57. package/dist/sealed-poe.cjs +851 -0
  58. package/dist/sealed-poe.cjs.map +1 -0
  59. package/dist/sealed-poe.d.cts +134 -0
  60. package/dist/sealed-poe.d.ts +134 -0
  61. package/dist/sealed-poe.js +838 -0
  62. package/dist/sealed-poe.js.map +1 -0
  63. package/dist/seed-derive.cjs +129 -0
  64. package/dist/seed-derive.cjs.map +1 -0
  65. package/dist/seed-derive.d.cts +28 -0
  66. package/dist/seed-derive.d.ts +28 -0
  67. package/dist/seed-derive.js +101 -0
  68. package/dist/seed-derive.js.map +1 -0
  69. package/dist/sig.cjs +77 -0
  70. package/dist/sig.cjs.map +1 -0
  71. package/dist/sig.d.cts +17 -0
  72. package/dist/sig.d.ts +17 -0
  73. package/dist/sig.js +53 -0
  74. package/dist/sig.js.map +1 -0
  75. package/dist/util.cjs +36 -0
  76. package/dist/util.cjs.map +1 -0
  77. package/dist/util.d.cts +5 -0
  78. package/dist/util.d.ts +5 -0
  79. package/dist/util.js +33 -0
  80. package/dist/util.js.map +1 -0
  81. package/package.json +122 -0
@@ -0,0 +1,24 @@
1
+ declare const LEAVES_LIST_FORMAT_V1: "cardano-poe-merkle-leaves-v1";
2
+ declare const TREE_ALG_RFC9162: "rfc9162-sha256";
3
+ type MerkleLeavesListErrorCode = 'SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED' | 'SCHEMA_MERKLE_LEAVES_MALFORMED' | 'SCHEMA_MERKLE_LEAF_COUNT_MISMATCH' | 'MERKLE_ROOT_MISMATCH';
4
+ declare class MerkleLeavesListError extends Error {
5
+ readonly code: MerkleLeavesListErrorCode;
6
+ constructor(code: MerkleLeavesListErrorCode, message?: string);
7
+ }
8
+ interface EncodeLeavesListArgs {
9
+ readonly leaves: ReadonlyArray<Uint8Array>;
10
+ readonly root: Uint8Array;
11
+ readonly leafAlg?: string;
12
+ }
13
+ interface DecodedLeavesList {
14
+ readonly format: typeof LEAVES_LIST_FORMAT_V1;
15
+ readonly treeAlg: typeof TREE_ALG_RFC9162;
16
+ readonly root: Uint8Array;
17
+ readonly leaves: Uint8Array[];
18
+ readonly leafCount: number;
19
+ readonly leafAlg?: string;
20
+ }
21
+ declare function encodeLeavesList(args: EncodeLeavesListArgs): Uint8Array;
22
+ declare function decodeLeavesList(bytes: Uint8Array): DecodedLeavesList;
23
+
24
+ export { type DecodedLeavesList, type EncodeLeavesListArgs, LEAVES_LIST_FORMAT_V1, MerkleLeavesListError, type MerkleLeavesListErrorCode, decodeLeavesList, encodeLeavesList };
@@ -0,0 +1,24 @@
1
+ declare const LEAVES_LIST_FORMAT_V1: "cardano-poe-merkle-leaves-v1";
2
+ declare const TREE_ALG_RFC9162: "rfc9162-sha256";
3
+ type MerkleLeavesListErrorCode = 'SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED' | 'SCHEMA_MERKLE_LEAVES_MALFORMED' | 'SCHEMA_MERKLE_LEAF_COUNT_MISMATCH' | 'MERKLE_ROOT_MISMATCH';
4
+ declare class MerkleLeavesListError extends Error {
5
+ readonly code: MerkleLeavesListErrorCode;
6
+ constructor(code: MerkleLeavesListErrorCode, message?: string);
7
+ }
8
+ interface EncodeLeavesListArgs {
9
+ readonly leaves: ReadonlyArray<Uint8Array>;
10
+ readonly root: Uint8Array;
11
+ readonly leafAlg?: string;
12
+ }
13
+ interface DecodedLeavesList {
14
+ readonly format: typeof LEAVES_LIST_FORMAT_V1;
15
+ readonly treeAlg: typeof TREE_ALG_RFC9162;
16
+ readonly root: Uint8Array;
17
+ readonly leaves: Uint8Array[];
18
+ readonly leafCount: number;
19
+ readonly leafAlg?: string;
20
+ }
21
+ declare function encodeLeavesList(args: EncodeLeavesListArgs): Uint8Array;
22
+ declare function decodeLeavesList(bytes: Uint8Array): DecodedLeavesList;
23
+
24
+ export { type DecodedLeavesList, type EncodeLeavesListArgs, LEAVES_LIST_FORMAT_V1, MerkleLeavesListError, type MerkleLeavesListErrorCode, decodeLeavesList, encodeLeavesList };
package/dist/merkle.js ADDED
@@ -0,0 +1,279 @@
1
+ import { encode, decode, cdeDecodeOptions } from 'cbor2';
2
+ import { sortCoreDeterministic } from 'cbor2/sorts';
3
+ import { sha256 } from '@noble/hashes/sha2.js';
4
+
5
+ // src/cbor/canonical.ts
6
+
7
+ // src/cbor/errors.ts
8
+ var CanonicalCborError = class extends Error {
9
+ code;
10
+ constructor(code, message, options) {
11
+ super(message, options);
12
+ this.name = "CanonicalCborError";
13
+ this.code = code;
14
+ }
15
+ };
16
+
17
+ // src/cbor/canonical.ts
18
+ function encodeCanonicalCbor(value) {
19
+ return encode(value, {
20
+ cde: true,
21
+ collapseBigInts: true,
22
+ rejectDuplicateKeys: true,
23
+ sortKeys: sortCoreDeterministic
24
+ });
25
+ }
26
+ function decodeCanonicalCbor(bytes) {
27
+ try {
28
+ return decode(bytes, {
29
+ ...cdeDecodeOptions,
30
+ rejectStreaming: true,
31
+ rejectDuplicateKeys: true,
32
+ // A CIP-309 record carries integers, byte/text strings, arrays, maps and
33
+ // `null` — and nothing else. Without these rejections the major-type-7
34
+ // surface leaks into the decoder: a float16/32/64 that happens to hold an
35
+ // integral value (e.g. 1.0) silently decodes to the integer 1 and passes
36
+ // a `z.literal(1)` / Number.isInteger schema check, so two byte strings
37
+ // that are NOT byte-identical canonicalise to the same record. That
38
+ // breaks the cross-implementation parity invariant (the Python twin
39
+ // already rejects non-integer `v` / `enc.scheme` outright). Reject the
40
+ // whole non-record surface — floats, negative zero, undefined, and
41
+ // non-{true,false,null} simple values — so any such input surfaces as
42
+ // MALFORMED_CBOR via mapDecodeError rather than decoding to a look-alike.
43
+ rejectFloats: true,
44
+ rejectNegativeZero: true,
45
+ rejectUndefined: true,
46
+ rejectSimple: true
47
+ });
48
+ } catch (cause) {
49
+ throw mapDecodeError(cause);
50
+ }
51
+ }
52
+ function mapDecodeError(cause) {
53
+ const message = cause instanceof Error ? cause.message : String(cause);
54
+ const lower = message.toLowerCase();
55
+ const isIndefinite = lower.includes("streaming") || lower.includes("indefinite");
56
+ const detail = isIndefinite ? `indefinite-length items are not permitted in canonical CBOR: ${message}` : message;
57
+ return new CanonicalCborError("MALFORMED_CBOR", `cbor decode failed: ${detail}`, { cause });
58
+ }
59
+
60
+ // src/util/compare-ct.ts
61
+ function compareCt(a, b) {
62
+ if (a.length !== b.length) return false;
63
+ let diff = 0;
64
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
65
+ return diff === 0;
66
+ }
67
+ var LEAF_PREFIX = 0;
68
+ var NODE_PREFIX = 1;
69
+ var DIGEST_LENGTH = 32;
70
+ function validateLeaves(leaves, fnName) {
71
+ if (leaves.length === 0) {
72
+ throw new Error(`${fnName}: empty leaf list (n == 0 is forbidden by RFC 9162 \xA72.1.1)`);
73
+ }
74
+ for (let i = 0; i < leaves.length; i++) {
75
+ const leaf = leaves[i];
76
+ if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {
77
+ throw new Error(
78
+ `${fnName}: leaf[${i}] must be a Uint8Array(${DIGEST_LENGTH}); got length ${leaf instanceof Uint8Array ? leaf.length : "non-Uint8Array"}`
79
+ );
80
+ }
81
+ }
82
+ }
83
+ function merkleSha2256Root(leaves) {
84
+ validateLeaves(leaves, "merkleSha2256Root");
85
+ return mthRecursive(leaves, 0, leaves.length);
86
+ }
87
+ function largestPow2Lt(n) {
88
+ let k = 1;
89
+ while (k * 2 < n) k *= 2;
90
+ return k;
91
+ }
92
+ function hashLeaf(d) {
93
+ const buf = new Uint8Array(1 + d.length);
94
+ buf[0] = LEAF_PREFIX;
95
+ buf.set(d, 1);
96
+ return sha256(buf);
97
+ }
98
+ function hashNode(left, right) {
99
+ const buf = new Uint8Array(1 + left.length + right.length);
100
+ buf[0] = NODE_PREFIX;
101
+ buf.set(left, 1);
102
+ buf.set(right, 1 + left.length);
103
+ return sha256(buf);
104
+ }
105
+ function mthRecursive(leaves, start, end) {
106
+ const n = end - start;
107
+ if (n === 1) {
108
+ return hashLeaf(leaves[start]);
109
+ }
110
+ const k = largestPow2Lt(n);
111
+ const left = mthRecursive(leaves, start, start + k);
112
+ const right = mthRecursive(leaves, start + k, end);
113
+ return hashNode(left, right);
114
+ }
115
+
116
+ // src/merkle/leaves-list.ts
117
+ var LEAVES_LIST_FORMAT_V1 = "cardano-poe-merkle-leaves-v1";
118
+ var TREE_ALG_RFC9162 = "rfc9162-sha256";
119
+ var DIGEST_LENGTH2 = 32;
120
+ var REGISTERED_FORMATS = /* @__PURE__ */ new Set([LEAVES_LIST_FORMAT_V1]);
121
+ var MerkleLeavesListError = class extends Error {
122
+ code;
123
+ constructor(code, message) {
124
+ super(message ? `${code}: ${message}` : code);
125
+ this.code = code;
126
+ this.name = "MerkleLeavesListError";
127
+ }
128
+ };
129
+ function encodeLeavesList(args) {
130
+ if (!(args.root instanceof Uint8Array) || args.root.length !== DIGEST_LENGTH2) {
131
+ throw new MerkleLeavesListError(
132
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
133
+ `root must be a Uint8Array(${DIGEST_LENGTH2})`
134
+ );
135
+ }
136
+ if (args.leaves.length < 1) {
137
+ throw new MerkleLeavesListError(
138
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
139
+ "leaves array must be non-empty"
140
+ );
141
+ }
142
+ const leavesCopy = [];
143
+ for (let i = 0; i < args.leaves.length; i++) {
144
+ const leaf = args.leaves[i];
145
+ if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
146
+ throw new MerkleLeavesListError(
147
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
148
+ `leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH2})`
149
+ );
150
+ }
151
+ leavesCopy.push(leaf);
152
+ }
153
+ if (args.leafAlg !== void 0 && typeof args.leafAlg !== "string") {
154
+ throw new MerkleLeavesListError(
155
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
156
+ "leaf_alg must be a string when present"
157
+ );
158
+ }
159
+ const map = {
160
+ format: LEAVES_LIST_FORMAT_V1,
161
+ tree_alg: TREE_ALG_RFC9162,
162
+ root: args.root,
163
+ leaves: leavesCopy,
164
+ leaf_count: leavesCopy.length
165
+ };
166
+ if (args.leafAlg !== void 0) {
167
+ map["leaf_alg"] = args.leafAlg;
168
+ }
169
+ return encodeCanonicalCbor(map);
170
+ }
171
+ function decodeLeavesList(bytes) {
172
+ const decoded = decodeCanonicalCbor(bytes);
173
+ if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) {
174
+ throw new MerkleLeavesListError(
175
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
176
+ "leaves-list MUST be a CBOR map"
177
+ );
178
+ }
179
+ const m = decoded;
180
+ const format = m["format"];
181
+ if (typeof format !== "string") {
182
+ throw new MerkleLeavesListError(
183
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
184
+ "format must be a text string"
185
+ );
186
+ }
187
+ if (!REGISTERED_FORMATS.has(format)) {
188
+ throw new MerkleLeavesListError(
189
+ "SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED",
190
+ `format '${format}' is not in the registered set`
191
+ );
192
+ }
193
+ const treeAlg = m["tree_alg"];
194
+ if (treeAlg !== TREE_ALG_RFC9162) {
195
+ throw new MerkleLeavesListError(
196
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
197
+ `tree_alg '${String(treeAlg)}' is not '${TREE_ALG_RFC9162}'`
198
+ );
199
+ }
200
+ const root = m["root"];
201
+ if (!(root instanceof Uint8Array) || root.length !== DIGEST_LENGTH2) {
202
+ throw new MerkleLeavesListError(
203
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
204
+ `root must be a ${DIGEST_LENGTH2}-byte byte string`
205
+ );
206
+ }
207
+ const leavesRaw = m["leaves"];
208
+ if (!Array.isArray(leavesRaw) || leavesRaw.length < 1) {
209
+ throw new MerkleLeavesListError(
210
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
211
+ "leaves must be a non-empty array"
212
+ );
213
+ }
214
+ const leaves = [];
215
+ for (let i = 0; i < leavesRaw.length; i++) {
216
+ const leaf = leavesRaw[i];
217
+ if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH2) {
218
+ throw new MerkleLeavesListError(
219
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
220
+ `leaves[${i}] must be a ${DIGEST_LENGTH2}-byte byte string`
221
+ );
222
+ }
223
+ leaves.push(leaf);
224
+ }
225
+ const leafCountRaw = m["leaf_count"];
226
+ let leafCount;
227
+ if (typeof leafCountRaw === "number" && Number.isInteger(leafCountRaw) && leafCountRaw >= 0) {
228
+ leafCount = leafCountRaw;
229
+ } else if (typeof leafCountRaw === "bigint" && leafCountRaw >= 0n) {
230
+ if (leafCountRaw > BigInt(Number.MAX_SAFE_INTEGER)) {
231
+ throw new MerkleLeavesListError(
232
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
233
+ "leaf_count exceeds Number.MAX_SAFE_INTEGER"
234
+ );
235
+ }
236
+ leafCount = Number(leafCountRaw);
237
+ } else {
238
+ throw new MerkleLeavesListError(
239
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
240
+ "leaf_count must be a non-negative CBOR uint"
241
+ );
242
+ }
243
+ if (leaves.length !== leafCount) {
244
+ throw new MerkleLeavesListError(
245
+ "SCHEMA_MERKLE_LEAF_COUNT_MISMATCH",
246
+ `leaves.length (${leaves.length}) != leaf_count (${leafCount})`
247
+ );
248
+ }
249
+ let leafAlg;
250
+ if (m["leaf_alg"] !== void 0) {
251
+ if (typeof m["leaf_alg"] !== "string") {
252
+ throw new MerkleLeavesListError(
253
+ "SCHEMA_MERKLE_LEAVES_MALFORMED",
254
+ "leaf_alg must be a text string when present"
255
+ );
256
+ }
257
+ leafAlg = m["leaf_alg"];
258
+ }
259
+ const recomputed = merkleSha2256Root(leaves);
260
+ if (!compareCt(recomputed, root)) {
261
+ throw new MerkleLeavesListError(
262
+ "MERKLE_ROOT_MISMATCH",
263
+ "leaves recompute does not match declared root"
264
+ );
265
+ }
266
+ const out = {
267
+ format: LEAVES_LIST_FORMAT_V1,
268
+ treeAlg: TREE_ALG_RFC9162,
269
+ root,
270
+ leaves,
271
+ leafCount,
272
+ ...leafAlg !== void 0 ? { leafAlg } : {}
273
+ };
274
+ return out;
275
+ }
276
+
277
+ export { LEAVES_LIST_FORMAT_V1, MerkleLeavesListError, decodeLeavesList, encodeLeavesList };
278
+ //# sourceMappingURL=merkle.js.map
279
+ //# sourceMappingURL=merkle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cbor/errors.ts","../src/cbor/canonical.ts","../src/util/compare-ct.ts","../src/hash/merkle-sha2-256.ts","../src/merkle/leaves-list.ts"],"names":["DIGEST_LENGTH"],"mappings":"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","file":"merkle.js","sourcesContent":["// Every canonical-CBOR decode violation collapses to the single public CIP-309\n// taxonomy code MALFORMED_CBOR: indefinite-length (streaming) items, duplicate\n// keys, unsorted keys, non-minimal integer encodings, and invalid UTF-8 in text\n// strings. The taxonomy intentionally has one code for all of these; the\n// specific cause survives in the human-readable error message, not as a\n// separate code.\nexport type CanonicalCborErrorCode = 'MALFORMED_CBOR';\n\nexport class CanonicalCborError extends Error {\n readonly code: CanonicalCborErrorCode;\n\n constructor(code: CanonicalCborErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'CanonicalCborError';\n this.code = code;\n }\n}\n","import { cdeDecodeOptions, decode, encode } from 'cbor2';\nimport { sortCoreDeterministic } from 'cbor2/sorts';\n\nimport { CanonicalCborError } from './errors';\n\nexport type CanonicalCborValue =\n | null\n | boolean\n | number\n | bigint\n | string\n | Uint8Array\n | readonly CanonicalCborValue[]\n | { readonly [key: string]: CanonicalCborValue }\n | ReadonlyMap<string | number, CanonicalCborValue>;\n\nexport function encodeCanonicalCbor(value: CanonicalCborValue): Uint8Array {\n return encode(value, {\n cde: true,\n collapseBigInts: true,\n rejectDuplicateKeys: true,\n sortKeys: sortCoreDeterministic,\n });\n}\n\nexport function decodeCanonicalCbor(bytes: Uint8Array): unknown {\n try {\n return decode(bytes, {\n ...cdeDecodeOptions,\n rejectStreaming: true,\n rejectDuplicateKeys: true,\n // A CIP-309 record carries integers, byte/text strings, arrays, maps and\n // `null` — and nothing else. Without these rejections the major-type-7\n // surface leaks into the decoder: a float16/32/64 that happens to hold an\n // integral value (e.g. 1.0) silently decodes to the integer 1 and passes\n // a `z.literal(1)` / Number.isInteger schema check, so two byte strings\n // that are NOT byte-identical canonicalise to the same record. That\n // breaks the cross-implementation parity invariant (the Python twin\n // already rejects non-integer `v` / `enc.scheme` outright). Reject the\n // whole non-record surface — floats, negative zero, undefined, and\n // non-{true,false,null} simple values — so any such input surfaces as\n // MALFORMED_CBOR via mapDecodeError rather than decoding to a look-alike.\n rejectFloats: true,\n rejectNegativeZero: true,\n rejectUndefined: true,\n rejectSimple: true,\n });\n } catch (cause) {\n throw mapDecodeError(cause);\n }\n}\n\nfunction mapDecodeError(cause: unknown): CanonicalCborError {\n const message = cause instanceof Error ? cause.message : String(cause);\n const lower = message.toLowerCase();\n // Every canonical-decode violation collapses to the single public taxonomy\n // code MALFORMED_CBOR: indefinite-length (streaming) items, duplicate keys,\n // non-canonical (unsorted) key ordering, non-minimal integer encodings, and\n // invalid UTF-8 in text strings. cbor2 raises the SAME \"Duplicate or out of\n // order key\" message for both true duplicates AND distinct-but-unsorted keys,\n // so the two are indistinguishable by message — and per the CIP-309 taxonomy\n // both belong under MALFORMED_CBOR anyway. The specific cause survives in the\n // human-readable message below; for indefinite-length we state it explicitly\n // so the diagnostic is not lost when the code is collapsed.\n const isIndefinite = lower.includes('streaming') || lower.includes('indefinite');\n const detail = isIndefinite\n ? `indefinite-length items are not permitted in canonical CBOR: ${message}`\n : message;\n return new CanonicalCborError('MALFORMED_CBOR', `cbor decode failed: ${detail}`, { cause });\n}\n","// Isomorphic constant-time byte-equality. crypto-core is browser-safe by\n// design, so we cannot import `node:crypto.timingSafeEqual` — webpack rejects\n// the `node:` scheme in the browser bundle. A pure-JS XOR loop is constant-time\n// for equal-length inputs; length mismatch is a deliberate early-return (the\n// API surface itself leaks length, same as node's timingSafeEqual which throws).\nexport function compareCt(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n // Lengths are equal and `i` stays in-bounds, so both indexes are always\n // defined — no nullish guard is needed (and one would read as a guard for\n // an impossible case).\n for (let i = 0; i < a.length; i++) diff |= (a[i] as number) ^ (b[i] as number);\n return diff === 0;\n}\n","// RFC 9162 §2.1.1 binary Merkle tree under SHA-256.\n// This implements the algorithm tier identified on the wire as the\n// `rfc9162-sha256` OPT-INFO; the record's `merkle[]` field carries the proof.\n//\n// Construction (RFC 9162 §2.1.1):\n// - Single leaf: MTH({d_0}) = SHA-256(0x00 || d_0)\n// - Internal node: MTH(L) = SHA-256(0x01 || MTH(L[0:k]) || MTH(L[k:n]))\n// where k = largest power of 2 strictly less than n.\n// - Empty trees (n == 0) are FORBIDDEN.\n// - The 0x00 leaf / 0x01 internal prefixes prevent the CVE-2012-2459\n// leaf-vs-internal collision family.\n\nimport { sha256 } from '@noble/hashes/sha2.js';\n\nimport { compareCt } from '../util/compare-ct';\n\nexport const MERKLE_ALG_ID = 'rfc9162-sha256' as const;\n\nconst LEAF_PREFIX = 0x00;\nconst NODE_PREFIX = 0x01;\nconst DIGEST_LENGTH = 32;\n\nfunction validateLeaves(leaves: ReadonlyArray<Uint8Array>, fnName: string): void {\n if (leaves.length === 0) {\n throw new Error(`${fnName}: empty leaf list (n == 0 is forbidden by RFC 9162 §2.1.1)`);\n }\n for (let i = 0; i < leaves.length; i++) {\n const leaf = leaves[i];\n if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {\n throw new Error(\n `${fnName}: leaf[${i}] must be a Uint8Array(${DIGEST_LENGTH}); got length ${\n leaf instanceof Uint8Array ? leaf.length : 'non-Uint8Array'\n }`,\n );\n }\n }\n}\n\nexport function merkleSha2256Root(leaves: ReadonlyArray<Uint8Array>): Uint8Array {\n validateLeaves(leaves, 'merkleSha2256Root');\n return mthRecursive(leaves, 0, leaves.length);\n}\n\nexport function merkleSha2256InclusionProof(\n leaves: ReadonlyArray<Uint8Array>,\n index: number,\n): Uint8Array[] {\n validateLeaves(leaves, 'merkleSha2256InclusionProof');\n if (!Number.isInteger(index) || index < 0 || index >= leaves.length) {\n throw new Error(\n `merkleSha2256InclusionProof: index ${index} out of range [0, ${leaves.length})`,\n );\n }\n return auditPath(leaves, index, 0, leaves.length);\n}\n\n/**\n * Verify an inclusion proof per RFC 9162 §2.1.3.2 (iterative form).\n *\n * `proof` is ordered leaf-to-root: `proof[0]` is the sibling at the leaf\n * level, `proof[m-1]` is the top-level sibling. The fold uses the\n * `sn`/`fn` tracking from RFC 9162: `sn` is the leaf index within the\n * current subtree, `fn` is (subtree_size - 1). At each step, `sn` odd\n * OR `sn == fn` means the current node is a right child (sibling on\n * the left); otherwise it is a left child (sibling on the right).\n * Both shift right by one each iteration. This handles non-power-of-2\n * sizes including the \"promote a lone right subtree\" cases.\n */\nexport function merkleSha2256VerifyInclusion(\n leaf: Uint8Array,\n index: number,\n treeSize: number,\n proof: ReadonlyArray<Uint8Array>,\n root: Uint8Array,\n): boolean {\n if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) return false;\n if (!(root instanceof Uint8Array) || root.length !== DIGEST_LENGTH) return false;\n if (\n !Number.isInteger(index) ||\n !Number.isInteger(treeSize) ||\n treeSize < 1 ||\n index < 0 ||\n index >= treeSize\n ) {\n return false;\n }\n for (let i = 0; i < proof.length; i++) {\n const sibling = proof[i];\n if (!(sibling instanceof Uint8Array) || sibling.length !== DIGEST_LENGTH) {\n return false;\n }\n }\n\n if (treeSize === 1) {\n if (proof.length !== 0 || index !== 0) return false;\n return compareCt(hashLeaf(leaf), root);\n }\n\n let h = hashLeaf(leaf);\n let sn = index;\n let fn = treeSize - 1;\n for (let i = 0; i < proof.length; i++) {\n if (fn === 0) return false;\n const sibling = proof[i] as Uint8Array;\n if ((sn & 1) === 1 || sn === fn) {\n h = hashNode(sibling, h);\n while ((sn & 1) === 0 && sn !== 0) {\n sn >>>= 1;\n fn >>>= 1;\n }\n } else {\n h = hashNode(h, sibling);\n }\n sn >>>= 1;\n fn >>>= 1;\n }\n if (fn !== 0) return false;\n return compareCt(h, root);\n}\n\nfunction largestPow2Lt(n: number): number {\n let k = 1;\n while (k * 2 < n) k *= 2;\n return k;\n}\n\nfunction hashLeaf(d: Uint8Array): Uint8Array {\n const buf = new Uint8Array(1 + d.length);\n buf[0] = LEAF_PREFIX;\n buf.set(d, 1);\n return sha256(buf);\n}\n\nfunction hashNode(left: Uint8Array, right: Uint8Array): Uint8Array {\n const buf = new Uint8Array(1 + left.length + right.length);\n buf[0] = NODE_PREFIX;\n buf.set(left, 1);\n buf.set(right, 1 + left.length);\n return sha256(buf);\n}\n\nfunction mthRecursive(leaves: ReadonlyArray<Uint8Array>, start: number, end: number): Uint8Array {\n const n = end - start;\n if (n === 1) {\n return hashLeaf(leaves[start] as Uint8Array);\n }\n const k = largestPow2Lt(n);\n const left = mthRecursive(leaves, start, start + k);\n const right = mthRecursive(leaves, start + k, end);\n return hashNode(left, right);\n}\n\nfunction auditPath(\n leaves: ReadonlyArray<Uint8Array>,\n i: number,\n start: number,\n end: number,\n): Uint8Array[] {\n const n = end - start;\n if (n === 1) return [];\n const k = largestPow2Lt(n);\n if (i < k) {\n const subPath = auditPath(leaves, i, start, start + k);\n subPath.push(mthRecursive(leaves, start + k, end));\n return subPath;\n }\n const subPath = auditPath(leaves, i - k, start + k, end);\n subPath.push(mthRecursive(leaves, start, start + k));\n return subPath;\n}\n","// Canonical-CBOR codec for the off-chain Merkle leaves-list artefact.\n// The on-chain `merkle[]` field binds to this file via `uris[]` / `leaf_count`;\n// the file itself carries the full leaf set. Canonical CBOR is RFC 8949 §4.2.1.\n//\n// CDDL:\n//\n// leaves-list = {\n// \"format\": \"cardano-poe-merkle-leaves-v1\",\n// \"tree_alg\": \"rfc9162-sha256\",\n// \"root\": bytes .size 32,\n// \"leaves\": [ + bytes .size 32 ],\n// \"leaf_count\": uint,\n// ? \"leaf_alg\": tstr,\n// }\n//\n// Canonical ordering is bytewise-lexicographic on encoded map keys (RFC 8949\n// §4.2.1) so the wire-key order is fixed by `cde:true` regardless of insertion\n// order: root (4B) < format (6B) < leaves (6B) < leaf_alg (8B) < tree_alg (8B)\n// < leaf_count (10B).\n\nimport { decodeCanonicalCbor, encodeCanonicalCbor } from '../cbor/canonical';\nimport { compareCt } from '../util/compare-ct';\nimport { merkleSha2256Root } from '../hash/merkle-sha2-256';\n\nexport const LEAVES_LIST_FORMAT_V1 = 'cardano-poe-merkle-leaves-v1' as const;\nconst TREE_ALG_RFC9162 = 'rfc9162-sha256' as const;\nconst DIGEST_LENGTH = 32;\nconst REGISTERED_FORMATS = new Set<string>([LEAVES_LIST_FORMAT_V1]);\n\nexport type MerkleLeavesListErrorCode =\n | 'SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED'\n | 'SCHEMA_MERKLE_LEAVES_MALFORMED'\n | 'SCHEMA_MERKLE_LEAF_COUNT_MISMATCH'\n | 'MERKLE_ROOT_MISMATCH';\n\nexport class MerkleLeavesListError extends Error {\n readonly code: MerkleLeavesListErrorCode;\n constructor(code: MerkleLeavesListErrorCode, message?: string) {\n super(message ? `${code}: ${message}` : code);\n this.code = code;\n this.name = 'MerkleLeavesListError';\n }\n}\n\nexport interface EncodeLeavesListArgs {\n readonly leaves: ReadonlyArray<Uint8Array>;\n readonly root: Uint8Array;\n readonly leafAlg?: string;\n}\n\nexport interface DecodedLeavesList {\n readonly format: typeof LEAVES_LIST_FORMAT_V1;\n readonly treeAlg: typeof TREE_ALG_RFC9162;\n readonly root: Uint8Array;\n readonly leaves: Uint8Array[];\n readonly leafCount: number;\n readonly leafAlg?: string;\n}\n\nexport function encodeLeavesList(args: EncodeLeavesListArgs): Uint8Array {\n if (!(args.root instanceof Uint8Array) || args.root.length !== DIGEST_LENGTH) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n `root must be a Uint8Array(${DIGEST_LENGTH})`,\n );\n }\n if (args.leaves.length < 1) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaves array must be non-empty',\n );\n }\n const leavesCopy: Uint8Array[] = [];\n for (let i = 0; i < args.leaves.length; i++) {\n const leaf = args.leaves[i];\n if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n `leaves[${i}] must be a Uint8Array(${DIGEST_LENGTH})`,\n );\n }\n leavesCopy.push(leaf);\n }\n if (args.leafAlg !== undefined && typeof args.leafAlg !== 'string') {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaf_alg must be a string when present',\n );\n }\n const map: Record<string, unknown> = {\n format: LEAVES_LIST_FORMAT_V1,\n tree_alg: TREE_ALG_RFC9162,\n root: args.root,\n leaves: leavesCopy,\n leaf_count: leavesCopy.length,\n };\n if (args.leafAlg !== undefined) {\n map['leaf_alg'] = args.leafAlg;\n }\n return encodeCanonicalCbor(map as never);\n}\n\nexport function decodeLeavesList(bytes: Uint8Array): DecodedLeavesList {\n const decoded = decodeCanonicalCbor(bytes);\n if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaves-list MUST be a CBOR map',\n );\n }\n const m = decoded as Record<string, unknown>;\n\n const format = m['format'];\n if (typeof format !== 'string') {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'format must be a text string',\n );\n }\n if (!REGISTERED_FORMATS.has(format)) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_FORMAT_UNSUPPORTED',\n `format '${format}' is not in the registered set`,\n );\n }\n\n const treeAlg = m['tree_alg'];\n if (treeAlg !== TREE_ALG_RFC9162) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n `tree_alg '${String(treeAlg)}' is not '${TREE_ALG_RFC9162}'`,\n );\n }\n\n const root = m['root'];\n if (!(root instanceof Uint8Array) || root.length !== DIGEST_LENGTH) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n `root must be a ${DIGEST_LENGTH}-byte byte string`,\n );\n }\n\n const leavesRaw = m['leaves'];\n if (!Array.isArray(leavesRaw) || leavesRaw.length < 1) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaves must be a non-empty array',\n );\n }\n const leaves: Uint8Array[] = [];\n for (let i = 0; i < leavesRaw.length; i++) {\n const leaf = leavesRaw[i];\n if (!(leaf instanceof Uint8Array) || leaf.length !== DIGEST_LENGTH) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n `leaves[${i}] must be a ${DIGEST_LENGTH}-byte byte string`,\n );\n }\n leaves.push(leaf);\n }\n\n const leafCountRaw = m['leaf_count'];\n let leafCount: number;\n if (typeof leafCountRaw === 'number' && Number.isInteger(leafCountRaw) && leafCountRaw >= 0) {\n leafCount = leafCountRaw;\n } else if (typeof leafCountRaw === 'bigint' && leafCountRaw >= 0n) {\n if (leafCountRaw > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaf_count exceeds Number.MAX_SAFE_INTEGER',\n );\n }\n leafCount = Number(leafCountRaw);\n } else {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaf_count must be a non-negative CBOR uint',\n );\n }\n if (leaves.length !== leafCount) {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAF_COUNT_MISMATCH',\n `leaves.length (${leaves.length}) != leaf_count (${leafCount})`,\n );\n }\n\n let leafAlg: string | undefined;\n if (m['leaf_alg'] !== undefined) {\n if (typeof m['leaf_alg'] !== 'string') {\n throw new MerkleLeavesListError(\n 'SCHEMA_MERKLE_LEAVES_MALFORMED',\n 'leaf_alg must be a text string when present',\n );\n }\n leafAlg = m['leaf_alg'];\n }\n\n const recomputed = merkleSha2256Root(leaves);\n if (!compareCt(recomputed, root)) {\n throw new MerkleLeavesListError(\n 'MERKLE_ROOT_MISMATCH',\n 'leaves recompute does not match declared root',\n );\n }\n\n const out: DecodedLeavesList = {\n format: LEAVES_LIST_FORMAT_V1,\n treeAlg: TREE_ALG_RFC9162,\n root,\n leaves,\n leafCount,\n ...(leafAlg !== undefined ? { leafAlg } : {}),\n };\n return out;\n}\n"]}
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ // src/recipient/bech32.ts
4
+ var BECH32_ALPHABET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
5
+ var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
6
+ var ENCODING_CONST = 1;
7
+ function polymodStep(pre) {
8
+ const b = pre >> 25;
9
+ let chk = (pre & 33554431) << 5;
10
+ for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
11
+ if ((b >> i & 1) === 1) chk ^= POLYMOD_GENERATORS[i];
12
+ }
13
+ return chk;
14
+ }
15
+ function bytesToWords(bytes) {
16
+ const words = [];
17
+ let carry = 0;
18
+ let pos = 0;
19
+ const mask = (1 << 5) - 1;
20
+ for (const n of bytes) {
21
+ carry = carry << 8 | n;
22
+ pos += 8;
23
+ for (; pos >= 5; pos -= 5) words.push(carry >> pos - 5 & mask);
24
+ carry &= (1 << pos) - 1;
25
+ }
26
+ if (pos > 0) words.push(carry << 5 - pos & mask);
27
+ return words;
28
+ }
29
+ function checksum(prefix, words) {
30
+ let chk = 1;
31
+ for (let i = 0; i < prefix.length; i++) {
32
+ const c = prefix.charCodeAt(i);
33
+ if (c < 33 || c > 126) throw new Error(`bech32: invalid prefix (${prefix})`);
34
+ chk = polymodStep(chk) ^ c >> 5;
35
+ }
36
+ chk = polymodStep(chk);
37
+ for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ prefix.charCodeAt(i) & 31;
38
+ for (const v of words) chk = polymodStep(chk) ^ v;
39
+ for (let i = 0; i < 6; i++) chk = polymodStep(chk);
40
+ chk ^= ENCODING_CONST;
41
+ let out = "";
42
+ for (let i = 0; i < 6; i++) out += BECH32_ALPHABET[chk >> 5 * (5 - i) & 31];
43
+ return out;
44
+ }
45
+ function bech32EncodeNoLimit(prefix, bytes) {
46
+ if (prefix.length === 0) throw new Error("bech32: empty prefix");
47
+ const words = bytesToWords(bytes);
48
+ let payload = "";
49
+ for (const w of words) payload += BECH32_ALPHABET[w];
50
+ const lowered = prefix.toLowerCase();
51
+ return `${lowered}1${payload}${checksum(lowered, words)}`;
52
+ }
53
+ function checksumValid(prefix, words) {
54
+ let chk = 1;
55
+ for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ prefix.charCodeAt(i) >> 5;
56
+ chk = polymodStep(chk);
57
+ for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ prefix.charCodeAt(i) & 31;
58
+ for (const v of words) chk = polymodStep(chk) ^ v;
59
+ return chk === ENCODING_CONST;
60
+ }
61
+ function wordsToBytes(words) {
62
+ const out = [];
63
+ let carry = 0;
64
+ let pos = 0;
65
+ for (const w of words) {
66
+ carry = carry << 5 | w;
67
+ pos += 5;
68
+ for (; pos >= 8; pos -= 8) out.push(carry >> pos - 8 & 255);
69
+ carry &= (1 << pos) - 1;
70
+ }
71
+ if (pos >= 5 || carry !== 0) throw new Error("bech32: non-canonical padding");
72
+ return Uint8Array.from(out);
73
+ }
74
+ function bech32DecodeNoLimit(input) {
75
+ if (input.length === 0) throw new Error("bech32: empty string");
76
+ const hasLower = input !== input.toUpperCase();
77
+ const hasUpper = input !== input.toLowerCase();
78
+ if (hasLower && hasUpper) throw new Error("bech32: mixed-case string");
79
+ const s = input.toLowerCase();
80
+ const sep = s.lastIndexOf("1");
81
+ if (sep < 1) throw new Error("bech32: missing human-readable prefix");
82
+ if (s.length - sep - 1 < 6) throw new Error("bech32: data too short for checksum");
83
+ const hrp = s.slice(0, sep);
84
+ for (let i = 0; i < hrp.length; i++) {
85
+ const c = hrp.charCodeAt(i);
86
+ if (c < 33 || c > 126) throw new Error("bech32: invalid prefix character");
87
+ }
88
+ const words = [];
89
+ for (let i = sep + 1; i < s.length; i++) {
90
+ const v = BECH32_ALPHABET.indexOf(s[i]);
91
+ if (v === -1) throw new Error("bech32: invalid data character");
92
+ words.push(v);
93
+ }
94
+ if (!checksumValid(hrp, words)) throw new Error("bech32: bad checksum");
95
+ return { hrp, bytes: wordsToBytes(words.slice(0, words.length - 6)) };
96
+ }
97
+
98
+ // src/recipient/age-recipient.ts
99
+ var X25519_HRP = "age";
100
+ var XWING_HRP = "age1pqc";
101
+ var X25519_PUBLIC_KEY_BYTES = 32;
102
+ var XWING_PUBLIC_KEY_BYTES = 1216;
103
+ function encodeAgeX25519Recipient(publicKey) {
104
+ if (publicKey.length !== X25519_PUBLIC_KEY_BYTES) {
105
+ throw new Error("encodeAgeX25519Recipient: publicKey must be exactly 32 bytes");
106
+ }
107
+ return bech32EncodeNoLimit(X25519_HRP, publicKey);
108
+ }
109
+ function encodeAgeXWingRecipient(publicKey) {
110
+ if (publicKey.length !== XWING_PUBLIC_KEY_BYTES) {
111
+ throw new Error("encodeAgeXWingRecipient: publicKey must be exactly 1216 bytes");
112
+ }
113
+ return bech32EncodeNoLimit(XWING_HRP, publicKey);
114
+ }
115
+ function parseAgeRecipient(recipient) {
116
+ if (typeof recipient !== "string") {
117
+ throw new Error("parseAgeRecipient: recipient must be a string");
118
+ }
119
+ const { hrp, bytes } = bech32DecodeNoLimit(recipient.trim());
120
+ if (hrp === X25519_HRP) {
121
+ if (bytes.length !== X25519_PUBLIC_KEY_BYTES) {
122
+ throw new Error("parseAgeRecipient: age recipient must carry a 32-byte X25519 key");
123
+ }
124
+ return { kem: "x25519", publicKey: bytes };
125
+ }
126
+ if (hrp === XWING_HRP) {
127
+ if (bytes.length !== XWING_PUBLIC_KEY_BYTES) {
128
+ throw new Error("parseAgeRecipient: age1pqc recipient must carry a 1216-byte X-Wing key");
129
+ }
130
+ return { kem: "mlkem768x25519", publicKey: bytes };
131
+ }
132
+ throw new Error(`parseAgeRecipient: unrecognized recipient prefix "${hrp}"`);
133
+ }
134
+
135
+ exports.bech32DecodeNoLimit = bech32DecodeNoLimit;
136
+ exports.bech32EncodeNoLimit = bech32EncodeNoLimit;
137
+ exports.encodeAgeX25519Recipient = encodeAgeX25519Recipient;
138
+ exports.encodeAgeXWingRecipient = encodeAgeXWingRecipient;
139
+ exports.parseAgeRecipient = parseAgeRecipient;
140
+ //# sourceMappingURL=recipient.cjs.map
141
+ //# sourceMappingURL=recipient.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/recipient/bech32.ts","../src/recipient/age-recipient.ts"],"names":[],"mappings":"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","file":"recipient.cjs","sourcesContent":["// Minimal BIP-173 bech32 encoder used to format age-style recipient strings.\n//\n// This package's dependency policy keeps the runtime import graph to a small,\n// audited set of cryptographic libraries, so we inline the exact bech32\n// algorithm here rather than pull in a general-purpose base-encoding library.\n// Output is byte-identical to the no-length-limit form of a standard bech32\n// encoder (`encode(hrp, toWords(bytes))` with the 90-char BIP-173 cap\n// disabled): age recipients exceed that cap — an X-Wing recipient is ~1960\n// characters — so the limit must be off.\n\nconst BECH32_ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\nconst POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\nconst ENCODING_CONST = 1; // BIP-173 bech32 (not bech32m).\n\nfunction polymodStep(pre: number): number {\n const b = pre >> 25;\n let chk = (pre & 0x1ffffff) << 5;\n for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {\n if (((b >> i) & 1) === 1) chk ^= POLYMOD_GENERATORS[i]!;\n }\n return chk;\n}\n\n// 8-bit bytes → 5-bit words, padding the final partial group with zero bits.\nfunction bytesToWords(bytes: Uint8Array): number[] {\n const words: number[] = [];\n let carry = 0;\n let pos = 0;\n const mask = (1 << 5) - 1;\n for (const n of bytes) {\n carry = (carry << 8) | n;\n pos += 8;\n for (; pos >= 5; pos -= 5) words.push((carry >> (pos - 5)) & mask);\n carry &= (1 << pos) - 1;\n }\n if (pos > 0) words.push((carry << (5 - pos)) & mask);\n return words;\n}\n\nfunction checksum(prefix: string, words: number[]): string {\n let chk = 1;\n for (let i = 0; i < prefix.length; i++) {\n const c = prefix.charCodeAt(i);\n if (c < 33 || c > 126) throw new Error(`bech32: invalid prefix (${prefix})`);\n chk = polymodStep(chk) ^ (c >> 5);\n }\n chk = polymodStep(chk);\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) & 0x1f);\n for (const v of words) chk = polymodStep(chk) ^ v;\n for (let i = 0; i < 6; i++) chk = polymodStep(chk);\n chk ^= ENCODING_CONST;\n let out = '';\n for (let i = 0; i < 6; i++) out += BECH32_ALPHABET[(chk >> (5 * (5 - i))) & 31];\n return out;\n}\n\n// Encode raw bytes to a bech32 string with NO length limit. `prefix` is the HRP.\nexport function bech32EncodeNoLimit(prefix: string, bytes: Uint8Array): string {\n if (prefix.length === 0) throw new Error('bech32: empty prefix');\n const words = bytesToWords(bytes);\n let payload = '';\n for (const w of words) payload += BECH32_ALPHABET[w];\n const lowered = prefix.toLowerCase();\n return `${lowered}1${payload}${checksum(lowered, words)}`;\n}\n\n// Recompute the polymod over the HRP + every data word (the trailing six being\n// the checksum) and test it against the encoding constant. True iff the string\n// carries a valid bech32 checksum.\nfunction checksumValid(prefix: string, words: number[]): boolean {\n let chk = 1;\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) >> 5);\n chk = polymodStep(chk);\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) & 0x1f);\n for (const v of words) chk = polymodStep(chk) ^ v;\n return chk === ENCODING_CONST;\n}\n\n// 5-bit words → 8-bit bytes (the inverse of `bytesToWords`). Rejects\n// non-canonical padding: any leftover must be fewer than 5 bits and all zero,\n// matching the zero-fill `bytesToWords` applies to a final partial group.\nfunction wordsToBytes(words: number[]): Uint8Array {\n const out: number[] = [];\n let carry = 0;\n let pos = 0;\n for (const w of words) {\n carry = (carry << 5) | w;\n pos += 5;\n for (; pos >= 8; pos -= 8) out.push((carry >> (pos - 8)) & 0xff);\n carry &= (1 << pos) - 1;\n }\n if (pos >= 5 || carry !== 0) throw new Error('bech32: non-canonical padding');\n return Uint8Array.from(out);\n}\n\n// Decode a bech32 string with NO length limit, verifying the checksum. Returns\n// the lower-cased HRP and the decoded data bytes. The inverse of\n// `bech32EncodeNoLimit`. The separator is the last `1` in the string, so HRPs\n// that themselves contain a `1` (e.g. the `age1pqc` recipient prefix) round-trip\n// correctly.\nexport function bech32DecodeNoLimit(input: string): { hrp: string; bytes: Uint8Array } {\n if (input.length === 0) throw new Error('bech32: empty string');\n const hasLower = input !== input.toUpperCase();\n const hasUpper = input !== input.toLowerCase();\n if (hasLower && hasUpper) throw new Error('bech32: mixed-case string');\n const s = input.toLowerCase();\n const sep = s.lastIndexOf('1');\n if (sep < 1) throw new Error('bech32: missing human-readable prefix');\n if (s.length - sep - 1 < 6) throw new Error('bech32: data too short for checksum');\n const hrp = s.slice(0, sep);\n for (let i = 0; i < hrp.length; i++) {\n const c = hrp.charCodeAt(i);\n if (c < 33 || c > 126) throw new Error('bech32: invalid prefix character');\n }\n const words: number[] = [];\n for (let i = sep + 1; i < s.length; i++) {\n const v = BECH32_ALPHABET.indexOf(s[i]!);\n if (v === -1) throw new Error('bech32: invalid data character');\n words.push(v);\n }\n if (!checksumValid(hrp, words)) throw new Error('bech32: bad checksum');\n return { hrp, bytes: wordsToBytes(words.slice(0, words.length - 6)) };\n}\n","// Encodes a raw KEM public key to a bech32 age-style recipient string — the\n// form a sender uses to address a sealed PoE record.\n//\n// • X25519 (32 bytes) → \"age1…\"\n// • X-Wing / ML-KEM-768 + X25519 (1216 bytes) → \"age1pqc…\"\n//\n// The two HRPs make a recipient self-describing: a parser routes to the right\n// KEM purely from the bech32 prefix. We use the `age1pqc` HRP for the hybrid\n// key (upstream age v1.3.0 claims the shorter `age1pq` HRP for the same X-Wing\n// primitive; `age1pqc` avoids colliding with that wire identifier).\n//\n// The X-Wing public key derives for free from the same identity seed via\n// `deriveMlKem768X25519KeypairFromSeed`, so every identity always has one and\n// can RECEIVE hybrid sealed records even when it publishes via the classical\n// X25519 path.\n\nimport { bech32DecodeNoLimit, bech32EncodeNoLimit } from './bech32';\n\nconst X25519_HRP = 'age';\nconst XWING_HRP = 'age1pqc';\nconst X25519_PUBLIC_KEY_BYTES = 32;\nconst XWING_PUBLIC_KEY_BYTES = 1216;\n\n// The KEM a recipient string addresses, inferred from its bech32 HRP.\nexport type RecipientKem = 'x25519' | 'mlkem768x25519';\n\nexport interface ParsedAgeRecipient {\n readonly kem: RecipientKem;\n readonly publicKey: Uint8Array;\n}\n\nexport function encodeAgeX25519Recipient(publicKey: Uint8Array): string {\n if (publicKey.length !== X25519_PUBLIC_KEY_BYTES) {\n throw new Error('encodeAgeX25519Recipient: publicKey must be exactly 32 bytes');\n }\n return bech32EncodeNoLimit(X25519_HRP, publicKey);\n}\n\nexport function encodeAgeXWingRecipient(publicKey: Uint8Array): string {\n if (publicKey.length !== XWING_PUBLIC_KEY_BYTES) {\n throw new Error('encodeAgeXWingRecipient: publicKey must be exactly 1216 bytes');\n }\n return bech32EncodeNoLimit(XWING_HRP, publicKey);\n}\n\n// Decode an age-style recipient string back to its raw KEM public key, routing\n// on the bech32 HRP. The inverse of `encodeAgeX25519Recipient` /\n// `encodeAgeXWingRecipient`: a sender can take a recipient string a peer shared\n// and recover the exact public key (and which KEM it belongs to) needed to seal\n// a record to them. Surrounding whitespace is tolerated so pasted strings parse.\n// Throws on an unknown HRP, a bad checksum, or a key length that does not match\n// the HRP's KEM.\nexport function parseAgeRecipient(recipient: string): ParsedAgeRecipient {\n if (typeof recipient !== 'string') {\n throw new Error('parseAgeRecipient: recipient must be a string');\n }\n const { hrp, bytes } = bech32DecodeNoLimit(recipient.trim());\n if (hrp === X25519_HRP) {\n if (bytes.length !== X25519_PUBLIC_KEY_BYTES) {\n throw new Error('parseAgeRecipient: age recipient must carry a 32-byte X25519 key');\n }\n return { kem: 'x25519', publicKey: bytes };\n }\n if (hrp === XWING_HRP) {\n if (bytes.length !== XWING_PUBLIC_KEY_BYTES) {\n throw new Error('parseAgeRecipient: age1pqc recipient must carry a 1216-byte X-Wing key');\n }\n return { kem: 'mlkem768x25519', publicKey: bytes };\n }\n throw new Error(`parseAgeRecipient: unrecognized recipient prefix \"${hrp}\"`);\n}\n"]}
@@ -0,0 +1,16 @@
1
+ declare function bech32EncodeNoLimit(prefix: string, bytes: Uint8Array): string;
2
+ declare function bech32DecodeNoLimit(input: string): {
3
+ hrp: string;
4
+ bytes: Uint8Array;
5
+ };
6
+
7
+ type RecipientKem = 'x25519' | 'mlkem768x25519';
8
+ interface ParsedAgeRecipient {
9
+ readonly kem: RecipientKem;
10
+ readonly publicKey: Uint8Array;
11
+ }
12
+ declare function encodeAgeX25519Recipient(publicKey: Uint8Array): string;
13
+ declare function encodeAgeXWingRecipient(publicKey: Uint8Array): string;
14
+ declare function parseAgeRecipient(recipient: string): ParsedAgeRecipient;
15
+
16
+ export { type ParsedAgeRecipient, type RecipientKem, bech32DecodeNoLimit, bech32EncodeNoLimit, encodeAgeX25519Recipient, encodeAgeXWingRecipient, parseAgeRecipient };
@@ -0,0 +1,16 @@
1
+ declare function bech32EncodeNoLimit(prefix: string, bytes: Uint8Array): string;
2
+ declare function bech32DecodeNoLimit(input: string): {
3
+ hrp: string;
4
+ bytes: Uint8Array;
5
+ };
6
+
7
+ type RecipientKem = 'x25519' | 'mlkem768x25519';
8
+ interface ParsedAgeRecipient {
9
+ readonly kem: RecipientKem;
10
+ readonly publicKey: Uint8Array;
11
+ }
12
+ declare function encodeAgeX25519Recipient(publicKey: Uint8Array): string;
13
+ declare function encodeAgeXWingRecipient(publicKey: Uint8Array): string;
14
+ declare function parseAgeRecipient(recipient: string): ParsedAgeRecipient;
15
+
16
+ export { type ParsedAgeRecipient, type RecipientKem, bech32DecodeNoLimit, bech32EncodeNoLimit, encodeAgeX25519Recipient, encodeAgeXWingRecipient, parseAgeRecipient };