@marcuspuchalla/nachos 0.1.4 → 0.2.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 (56) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/{chunk-RVG2BY32.cjs → chunk-3Z45RBZP.cjs} +96 -42
  3. package/dist/chunk-3Z45RBZP.cjs.map +1 -0
  4. package/dist/{chunk-UMAX5MX5.js → chunk-EDXZTSIA.js} +33 -5
  5. package/dist/chunk-EDXZTSIA.js.map +1 -0
  6. package/dist/{chunk-S4RXO6IB.cjs → chunk-HMUA5KLG.cjs} +48 -20
  7. package/dist/chunk-HMUA5KLG.cjs.map +1 -0
  8. package/dist/{chunk-ZDZ2B5PE.js → chunk-JESIF5IF.js} +7 -3
  9. package/dist/chunk-JESIF5IF.js.map +1 -0
  10. package/dist/{chunk-5IWW5H47.js → chunk-LWNWC2O7.js} +68 -14
  11. package/dist/chunk-LWNWC2O7.js.map +1 -0
  12. package/dist/{chunk-PD72MVTX.cjs → chunk-P6A2OOIY.cjs} +7 -3
  13. package/dist/chunk-P6A2OOIY.cjs.map +1 -0
  14. package/dist/encoder/index.cjs +14 -14
  15. package/dist/encoder/index.d.cts +5 -4
  16. package/dist/encoder/index.d.ts +5 -4
  17. package/dist/encoder/index.js +2 -2
  18. package/dist/index.cjs +46 -27
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +15 -5
  21. package/dist/index.d.ts +15 -5
  22. package/dist/index.js +25 -5
  23. package/dist/index.js.map +1 -1
  24. package/dist/metafile-cjs.json +1 -1
  25. package/dist/metafile-esm.json +1 -1
  26. package/dist/parser/index.cjs +21 -21
  27. package/dist/parser/index.d.cts +2 -2
  28. package/dist/parser/index.d.ts +2 -2
  29. package/dist/parser/index.js +2 -2
  30. package/dist/{types-DvNlfbKB.d.cts → types-eG2qalpr.d.cts} +27 -1
  31. package/dist/{types-DvNlfbKB.d.ts → types-eG2qalpr.d.ts} +27 -1
  32. package/dist/{useCborSimpleEncoder-BoKEmjP9.d.ts → useCborSimpleEncoder-CamvS-_N.d.ts} +7 -1
  33. package/dist/{useCborSimpleEncoder-C_OHxoB8.d.cts → useCborSimpleEncoder-DXgPx62d.d.cts} +7 -1
  34. package/dist/{useCborTag-QpZR-Er2.d.cts → useCborTag-D4d7xG3-.d.cts} +1 -1
  35. package/dist/{useCborTag-BD6Sqp7p.d.ts → useCborTag-TYst1KR6.d.ts} +1 -1
  36. package/package.json +1 -1
  37. package/src/__tests__/audit-fixes.test.ts +141 -0
  38. package/src/encoder/composables/useCborCollectionEncoder.ts +3 -2
  39. package/src/encoder/composables/useCborEncoder.ts +19 -0
  40. package/src/encoder/composables/useCborSimpleEncoder.ts +6 -2
  41. package/src/encoder/types.ts +9 -2
  42. package/src/encoder/utils.ts +33 -1
  43. package/src/index.ts +10 -0
  44. package/src/parser/__tests__/utils-errors.test.ts +11 -3
  45. package/src/parser/composables/useCborCollection.ts +7 -4
  46. package/src/parser/composables/useCborDiagnostic.ts +28 -0
  47. package/src/parser/composables/useCborParser.ts +63 -13
  48. package/src/parser/composables/useCborTag.ts +8 -1
  49. package/src/parser/types.ts +32 -1
  50. package/src/parser/utils.ts +41 -0
  51. package/dist/chunk-5IWW5H47.js.map +0 -1
  52. package/dist/chunk-PD72MVTX.cjs.map +0 -1
  53. package/dist/chunk-RVG2BY32.cjs.map +0 -1
  54. package/dist/chunk-S4RXO6IB.cjs.map +0 -1
  55. package/dist/chunk-UMAX5MX5.js.map +0 -1
  56. package/dist/chunk-ZDZ2B5PE.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,58 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.0] - 2026-06-14 - RFC 8949 audit remediation
9
+
10
+ Resolves the findings of the June 2026 RFC 8949 conformance & security audit.
11
+ All fixes verified empirically against the build and locked in by
12
+ `src/__tests__/audit-fixes.test.ts`.
13
+
14
+ ### Fixed
15
+
16
+ #### Security
17
+ - **(H1) Source-map parse path stack overflow** - `decodeWithSourceMap()` now
18
+ enforces `maxTagDepth` (RUSTSEC-2019-0025). Deeply nested tags previously
19
+ overflowed the call stack with an uncatchable `RangeError`; they now raise a
20
+ clean `Error`, matching `decode()`.
21
+ - **(M2) Encoder depth bypass via tags** - `maxDepth` is now tracked across the
22
+ tagged-value boundary, so deeply nested `{tag,value}` chains can no longer
23
+ bypass the limit and overflow the stack.
24
+ - **(L3) `readUint` precision** - refuses values above `MAX_SAFE_INTEGER`
25
+ instead of silently losing precision; callers must use `readBigUint`.
26
+
27
+ #### Correctness / Conformance
28
+ - **(H2) Map key ordering is now explicit** - canonical mode defaults to
29
+ **length-first** ordering (Cardano CIP-21 / RFC 7049 §3.9) and accepts a new
30
+ `mapKeyOrder: 'length-first' | 'bytewise'` option. `'bytewise'` selects
31
+ RFC 8949 §4.2.1 core deterministic ordering. Applies to both encoding and
32
+ `validateCanonical` decoding.
33
+ - **(M1) Trailing-data well-formedness** - new `allowTrailingData` option
34
+ (default `true`; auto-`false` in `strict` mode) makes `decode()` reject
35
+ bytes left over after the top-level item. Use `parseSequence` for multiple items.
36
+ - **(M4) Shortest-form tag numbers** - `validateCanonical` now rejects
37
+ non-shortest tag number encodings (e.g. `d80100` instead of `c100`).
38
+ - **(M5) Float16 subnormal encoding** - `canBeFloat16` lower bound corrected
39
+ from 2⁻¹⁴ (min normal) to 2⁻²⁴ (min subnormal). The encoder no longer emits
40
+ float32 for representable subnormals, so its output again passes its own
41
+ canonical validator.
42
+
43
+ #### Behavior
44
+ - **(M3) Duplicate map keys** - default `dupMapKeyMode` changed from `'allow'`
45
+ to `'warn'` so duplicates are never silently collapsed in the `Map` view.
46
+ Byte-perfect round-trips are still preserved via `ALL_ENTRIES_SYMBOL`.
47
+
48
+ ### Performance
49
+ - **(L1) Source-map sequences** - `parseSequenceWithSourceMap` uses a zero-copy
50
+ `subarray` view per item instead of re-hex-encoding the buffer tail (O(N²) → O(N)).
51
+
52
+ ### Added
53
+ - `MapKeyOrder` type, `mapKeyOrder` option (parser + encoder), `allowTrailingData`
54
+ option, and `compareBytesLexicographic` / `compareMapKeys` utilities.
55
+ - Diagnostic notation (L5) now renders `CborByteString`/`CborTextString` wrappers,
56
+ unassigned simple values (`simple(N)`), and auto-detects indefinite-length
57
+ arrays/maps/strings.
58
+ - 24 new audit-regression tests.
59
+
8
60
  ## [0.1.4] - 2026-02-22
9
61
 
10
62
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkPD72MVTX_cjs = require('./chunk-PD72MVTX.cjs');
3
+ var chunkP6A2OOIY_cjs = require('./chunk-P6A2OOIY.cjs');
4
4
 
5
5
  // src/parser/utils.ts
6
6
  var hexToBytes = (hex) => {
@@ -41,6 +41,9 @@ var readUint = (buffer, offset, length) => {
41
41
  for (let i = 0; i < length; i++) {
42
42
  result = result * 256 + readByte(buffer, offset + i);
43
43
  }
44
+ if (result > Number.MAX_SAFE_INTEGER) {
45
+ throw new Error(`Value at offset ${offset} (${length} bytes) exceeds MAX_SAFE_INTEGER; use readBigUint`);
46
+ }
44
47
  return result;
45
48
  };
46
49
  var readBigUint = (buffer, offset, length) => {
@@ -207,6 +210,23 @@ function compareBytes(a, b) {
207
210
  }
208
211
  return 0;
209
212
  }
213
+ function compareBytesLexicographic(a, b) {
214
+ if (!a || !b) {
215
+ throw new Error("compareBytesLexicographic: arguments cannot be null or undefined");
216
+ }
217
+ const min = Math.min(a.length, b.length);
218
+ for (let i = 0; i < min; i++) {
219
+ const byteA = a[i];
220
+ const byteB = b[i];
221
+ if (byteA !== byteB) {
222
+ return byteA - byteB;
223
+ }
224
+ }
225
+ return a.length - b.length;
226
+ }
227
+ function compareMapKeys(a, b, order = "length-first") {
228
+ return order === "bytewise" ? compareBytesLexicographic(a, b) : compareBytes(a, b);
229
+ }
210
230
  function serializeValueForComparison(value) {
211
231
  if (value === null) return "null";
212
232
  if (value === void 0) return "undefined";
@@ -314,8 +334,8 @@ function useCborInteger() {
314
334
 
315
335
  // src/parser/composables/useCborString.ts
316
336
  function useCborString() {
317
- const { create: createByteString } = chunkPD72MVTX_cjs.useCborByteString();
318
- const { create: createTextString } = chunkPD72MVTX_cjs.useCborTextString();
337
+ const { create: createByteString } = chunkP6A2OOIY_cjs.useCborByteString();
338
+ const { create: createTextString } = chunkP6A2OOIY_cjs.useCborTextString();
319
339
  const parseLength = (buffer, offset, ai, options) => {
320
340
  if (ai < 24) {
321
341
  return { length: ai, bytesConsumed: 0 };
@@ -771,7 +791,7 @@ function useCborTag() {
771
791
  if (additionalInfo === 31 && !isIndefiniteAllowed) {
772
792
  throw new Error("Indefinite-length encoding is not allowed (strict/canonical mode)");
773
793
  }
774
- const maxDepth = options?.limits?.maxDepth ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxDepth;
794
+ const maxDepth = options?.limits?.maxDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxDepth;
775
795
  if (depth >= maxDepth) {
776
796
  throw new Error(`Maximum nesting depth ${maxDepth} exceeded`);
777
797
  }
@@ -828,7 +848,7 @@ function useCborTag() {
828
848
  if (!foundBreak) {
829
849
  throw new Error("Indefinite-length array missing break code (0xFF)");
830
850
  }
831
- items[chunkPD72MVTX_cjs.INDEFINITE_SYMBOL] = true;
851
+ items[chunkP6A2OOIY_cjs.INDEFINITE_SYMBOL] = true;
832
852
  } else {
833
853
  for (let i = 0; i < length; i++) {
834
854
  if (currentOffset >= buffer.length) {
@@ -854,7 +874,7 @@ function useCborTag() {
854
874
  if (additionalInfo === 31 && !isIndefiniteAllowed) {
855
875
  throw new Error("Indefinite-length encoding is not allowed (strict/canonical mode)");
856
876
  }
857
- const maxDepth = options?.limits?.maxDepth ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxDepth;
877
+ const maxDepth = options?.limits?.maxDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxDepth;
858
878
  if (depth >= maxDepth) {
859
879
  throw new Error(`Maximum nesting depth ${maxDepth} exceeded`);
860
880
  }
@@ -913,7 +933,7 @@ function useCborTag() {
913
933
  if (!foundBreak) {
914
934
  throw new Error("Indefinite-length map missing break code (0xFF)");
915
935
  }
916
- map[chunkPD72MVTX_cjs.INDEFINITE_SYMBOL] = true;
936
+ map[chunkP6A2OOIY_cjs.INDEFINITE_SYMBOL] = true;
917
937
  } else {
918
938
  for (let i = 0; i < length; i++) {
919
939
  if (currentOffset >= buffer.length) {
@@ -1199,11 +1219,14 @@ function useCborTag() {
1199
1219
  if (majorType !== 6) {
1200
1220
  throw new Error(`Expected major type 6 (tag), got ${majorType}`);
1201
1221
  }
1202
- const maxTagDepth = options?.limits?.maxTagDepth ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxTagDepth;
1222
+ const maxTagDepth = options?.limits?.maxTagDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxTagDepth;
1203
1223
  if (tagDepth >= maxTagDepth) {
1204
1224
  throw new Error(`Tag nesting depth ${tagDepth} exceeds limit of ${maxTagDepth}`);
1205
1225
  }
1206
1226
  const { tagNumber, bytesConsumed } = parseTagNumber(buffer, offset + 1, additionalInfo);
1227
+ if (options?.validateCanonical) {
1228
+ validateCanonicalInteger(tagNumber, additionalInfo);
1229
+ }
1207
1230
  let currentOffset = offset + 1 + bytesConsumed;
1208
1231
  if (currentOffset >= buffer.length) {
1209
1232
  throw new Error(`Unexpected end of buffer after tag ${tagNumber}`);
@@ -1432,7 +1455,7 @@ function useCborCollection() {
1432
1455
  if (!foundBreak) {
1433
1456
  throw new Error("Indefinite-length array missing break code (0xFF)");
1434
1457
  }
1435
- items[chunkPD72MVTX_cjs.INDEFINITE_SYMBOL] = true;
1458
+ items[chunkP6A2OOIY_cjs.INDEFINITE_SYMBOL] = true;
1436
1459
  } else {
1437
1460
  if (options?.limits?.maxArrayLength && length > options.limits.maxArrayLength) {
1438
1461
  throw new Error(`Array length ${length} exceeds limit of ${options.limits.maxArrayLength}`);
@@ -1512,7 +1535,7 @@ function useCborCollection() {
1512
1535
  if (!foundBreak) {
1513
1536
  throw new Error("Indefinite-length map missing break code (0xFF)");
1514
1537
  }
1515
- map[chunkPD72MVTX_cjs.INDEFINITE_SYMBOL] = true;
1538
+ map[chunkP6A2OOIY_cjs.INDEFINITE_SYMBOL] = true;
1516
1539
  } else {
1517
1540
  if (options?.limits?.maxMapSize && length > options.limits.maxMapSize) {
1518
1541
  throw new Error(`Map size ${length} exceeds limit of ${options.limits.maxMapSize}`);
@@ -1547,16 +1570,17 @@ function useCborCollection() {
1547
1570
  allEntries.push([keyResult.value, valueResult.value]);
1548
1571
  }
1549
1572
  }
1550
- map[chunkPD72MVTX_cjs.ALL_ENTRIES_SYMBOL] = allEntries;
1573
+ map[chunkP6A2OOIY_cjs.ALL_ENTRIES_SYMBOL] = allEntries;
1551
1574
  if (options?.validateCanonical && keyBytes.length > 1) {
1575
+ const keyOrder = options?.mapKeyOrder ?? "length-first";
1552
1576
  for (let i = 1; i < keyBytes.length; i++) {
1553
1577
  const prevKey = keyBytes[i - 1];
1554
1578
  const currKey = keyBytes[i];
1555
1579
  if (prevKey && currKey) {
1556
- const cmp = compareBytes(prevKey, currKey);
1580
+ const cmp = compareMapKeys(prevKey, currKey, keyOrder);
1557
1581
  if (cmp > 0) {
1558
1582
  throw new Error(
1559
- `Map keys are not in canonical order: key at index ${i} should come before key at index ${i - 1}`
1583
+ `Map keys are not in canonical order (${keyOrder}): key at index ${i} should come before key at index ${i - 1}`
1560
1584
  );
1561
1585
  }
1562
1586
  if (cmp === 0) {
@@ -1603,29 +1627,32 @@ function useCborCollection() {
1603
1627
  // src/parser/composables/useCborParser.ts
1604
1628
  function useCborParser() {
1605
1629
  const mergeOptions = (options) => {
1606
- if (!options) return chunkPD72MVTX_cjs.DEFAULT_OPTIONS;
1630
+ if (!options) return chunkP6A2OOIY_cjs.DEFAULT_OPTIONS;
1607
1631
  const isCanonical = options.validateCanonical ?? (options.strict ? true : false);
1608
1632
  return {
1609
- strict: options.strict ?? chunkPD72MVTX_cjs.DEFAULT_OPTIONS.strict,
1633
+ strict: options.strict ?? chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.strict,
1610
1634
  validateCanonical: isCanonical,
1611
1635
  // RFC 8949 Section 4.2: Deterministic encoding MUST NOT use indefinite-length
1612
- allowIndefinite: options.allowIndefinite ?? (isCanonical || options.strict ? false : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.allowIndefinite),
1636
+ allowIndefinite: options.allowIndefinite ?? (isCanonical || options.strict ? false : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.allowIndefinite),
1613
1637
  // Auto-enable duplicate key rejection for canonical or strict mode
1614
- dupMapKeyMode: options.dupMapKeyMode ?? (isCanonical || options.strict ? "reject" : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.dupMapKeyMode),
1615
- validateUtf8Strict: options.validateUtf8Strict ?? (options.strict ? true : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.validateUtf8Strict),
1616
- validateSetUniqueness: options.validateSetUniqueness ?? (options.strict ? true : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.validateSetUniqueness),
1617
- validateTagSemantics: options.validateTagSemantics ?? (options.strict ? true : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.validateTagSemantics),
1618
- validatePlutusSemantics: options.validatePlutusSemantics ?? (options.strict ? true : chunkPD72MVTX_cjs.DEFAULT_OPTIONS.validatePlutusSemantics),
1638
+ dupMapKeyMode: options.dupMapKeyMode ?? (isCanonical || options.strict ? "reject" : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.dupMapKeyMode),
1639
+ validateUtf8Strict: options.validateUtf8Strict ?? (options.strict ? true : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.validateUtf8Strict),
1640
+ validateSetUniqueness: options.validateSetUniqueness ?? (options.strict ? true : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.validateSetUniqueness),
1641
+ validateTagSemantics: options.validateTagSemantics ?? (options.strict ? true : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.validateTagSemantics),
1642
+ validatePlutusSemantics: options.validatePlutusSemantics ?? (options.strict ? true : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.validatePlutusSemantics),
1643
+ mapKeyOrder: options.mapKeyOrder ?? chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.mapKeyOrder,
1644
+ // Strict mode rejects trailing data after the top-level item (well-formedness).
1645
+ allowTrailingData: options.allowTrailingData ?? (options.strict ? false : chunkP6A2OOIY_cjs.DEFAULT_OPTIONS.allowTrailingData),
1619
1646
  limits: {
1620
- maxInputSize: options.limits?.maxInputSize ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxInputSize,
1621
- maxOutputSize: options.limits?.maxOutputSize ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxOutputSize,
1622
- maxStringLength: options.limits?.maxStringLength ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxStringLength,
1623
- maxArrayLength: options.limits?.maxArrayLength ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxArrayLength,
1624
- maxMapSize: options.limits?.maxMapSize ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxMapSize,
1625
- maxDepth: options.limits?.maxDepth ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxDepth,
1626
- maxTagDepth: options.limits?.maxTagDepth ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxTagDepth,
1627
- maxBignumBytes: options.limits?.maxBignumBytes ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxBignumBytes,
1628
- maxParseTime: options.limits?.maxParseTime ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxParseTime
1647
+ maxInputSize: options.limits?.maxInputSize ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxInputSize,
1648
+ maxOutputSize: options.limits?.maxOutputSize ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxOutputSize,
1649
+ maxStringLength: options.limits?.maxStringLength ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxStringLength,
1650
+ maxArrayLength: options.limits?.maxArrayLength ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxArrayLength,
1651
+ maxMapSize: options.limits?.maxMapSize ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxMapSize,
1652
+ maxDepth: options.limits?.maxDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxDepth,
1653
+ maxTagDepth: options.limits?.maxTagDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxTagDepth,
1654
+ maxBignumBytes: options.limits?.maxBignumBytes ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxBignumBytes,
1655
+ maxParseTime: options.limits?.maxParseTime ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxParseTime
1629
1656
  }
1630
1657
  };
1631
1658
  };
@@ -1650,7 +1677,9 @@ function useCborParser() {
1650
1677
  if (mergedOptions.limits?.maxInputSize && input.length > mergedOptions.limits.maxInputSize) {
1651
1678
  throw new Error(`Input size ${input.length} bytes exceeds limit of ${mergedOptions.limits.maxInputSize} bytes`);
1652
1679
  }
1653
- return dispatchFromBuffer(input, 0, mergedOptions);
1680
+ const bufResult = dispatchFromBuffer(input, 0, mergedOptions);
1681
+ checkTrailingData(bufResult.bytesRead, input.length, mergedOptions);
1682
+ return bufResult;
1654
1683
  }
1655
1684
  const cleanHex = input.replace(/\s+/g, "");
1656
1685
  if (!cleanHex || cleanHex.length === 0) {
@@ -1669,26 +1698,42 @@ function useCborParser() {
1669
1698
  const buffer = hexToBytes(cleanHex);
1670
1699
  const initialByte = readByte(buffer, 0);
1671
1700
  const { majorType } = extractCborHeader(initialByte);
1701
+ let result;
1672
1702
  switch (majorType) {
1673
1703
  case 0:
1674
1704
  // Unsigned integer
1675
1705
  case 1:
1676
- return parseInteger(cleanHex, mergedOptions);
1706
+ result = parseInteger(cleanHex, mergedOptions);
1707
+ break;
1677
1708
  case 2:
1678
1709
  // Byte string
1679
1710
  case 3:
1680
- return parseString(cleanHex, mergedOptions);
1711
+ result = parseString(cleanHex, mergedOptions);
1712
+ break;
1681
1713
  case 4:
1682
- return parseArray(cleanHex, mergedOptions);
1714
+ result = parseArray(cleanHex, mergedOptions);
1715
+ break;
1683
1716
  case 5:
1684
- return parseMap(cleanHex, mergedOptions);
1717
+ result = parseMap(cleanHex, mergedOptions);
1718
+ break;
1685
1719
  case 6:
1686
- return parseTag(cleanHex, mergedOptions);
1720
+ result = parseTag(cleanHex, mergedOptions);
1721
+ break;
1687
1722
  case 7:
1688
- return parseFloatOrSimple(cleanHex, mergedOptions);
1723
+ result = parseFloatOrSimple(cleanHex, mergedOptions);
1724
+ break;
1689
1725
  default:
1690
1726
  throw new Error(`Unknown major type: ${majorType}`);
1691
1727
  }
1728
+ checkTrailingData(result.bytesRead, buffer.length, mergedOptions);
1729
+ return result;
1730
+ };
1731
+ const checkTrailingData = (bytesRead, totalLength, opts) => {
1732
+ if (!opts.allowTrailingData && bytesRead < totalLength) {
1733
+ throw new Error(
1734
+ `Trailing data: ${totalLength - bytesRead} byte(s) remain after the top-level CBOR item (bytesRead=${bytesRead}, length=${totalLength}). Use parseSequence to decode multiple items.`
1735
+ );
1736
+ }
1692
1737
  };
1693
1738
  const parseWithSourceMap = (input, options) => {
1694
1739
  const mergedOptions = mergeOptions(options);
@@ -2185,6 +2230,12 @@ function useCborParser() {
2185
2230
  }
2186
2231
  };
2187
2232
  const parseTagWithMap = (ctx, offset, path, sourceMap) => {
2233
+ const previousTagDepth = ctx.currentTagDepth ?? 0;
2234
+ const maxTagDepth = ctx.options?.limits?.maxTagDepth ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxTagDepth;
2235
+ if (previousTagDepth >= maxTagDepth) {
2236
+ throw new Error(`Tag nesting depth ${previousTagDepth} exceeds limit of ${maxTagDepth}`);
2237
+ }
2238
+ ctx.currentTagDepth = previousTagDepth + 1;
2188
2239
  const startOffset = offset;
2189
2240
  const initialByte = readByte(ctx.buffer, offset);
2190
2241
  const { additionalInfo } = extractCborHeader(initialByte);
@@ -2193,6 +2244,9 @@ function useCborParser() {
2193
2244
  offset + 1,
2194
2245
  additionalInfo
2195
2246
  );
2247
+ if (ctx.options?.validateCanonical) {
2248
+ validateCanonicalInteger(tagNumber, additionalInfo);
2249
+ }
2196
2250
  let currentOffset = offset + 1 + bytesConsumed;
2197
2251
  const headerEnd = currentOffset;
2198
2252
  const tagEntryIndex = sourceMap.length;
@@ -2218,7 +2272,7 @@ function useCborParser() {
2218
2272
  }
2219
2273
  let finalValue = valueResult.value;
2220
2274
  if ((tagNumber === 2 || tagNumber === 3) && finalValue instanceof Uint8Array) {
2221
- const maxBignumBytes = ctx.options?.limits?.maxBignumBytes ?? chunkPD72MVTX_cjs.DEFAULT_LIMITS.maxBignumBytes;
2275
+ const maxBignumBytes = ctx.options?.limits?.maxBignumBytes ?? chunkP6A2OOIY_cjs.DEFAULT_LIMITS.maxBignumBytes;
2222
2276
  if (finalValue.length > maxBignumBytes) {
2223
2277
  throw new Error(
2224
2278
  `Bignum (tag ${tagNumber}) size ${finalValue.length} bytes exceeds limit of ${maxBignumBytes} bytes`
@@ -2237,6 +2291,7 @@ function useCborParser() {
2237
2291
  value: finalValue,
2238
2292
  ...plutusConstr && { plutus: plutusConstr }
2239
2293
  };
2294
+ ctx.currentTagDepth = previousTagDepth;
2240
2295
  return {
2241
2296
  value: taggedValue,
2242
2297
  bytesRead: currentOffset - startOffset
@@ -2315,8 +2370,7 @@ function useCborParser() {
2315
2370
  if (byte === 255) {
2316
2371
  throw new Error(`Unexpected break code (0xff) at offset ${offset}`);
2317
2372
  }
2318
- const remainingHex = Array.from(buffer.slice(offset)).map((b) => b.toString(16).padStart(2, "0")).join("");
2319
- const result = parseWithSourceMap(remainingHex, mergedOptions);
2373
+ const result = parseWithSourceMap(buffer.subarray(offset), mergedOptions);
2320
2374
  const adjustedSourceMap = result.sourceMap.map((entry) => ({
2321
2375
  ...entry,
2322
2376
  start: entry.start + offset,
@@ -2349,5 +2403,5 @@ exports.useCborParser = useCborParser;
2349
2403
  exports.useCborString = useCborString;
2350
2404
  exports.useCborTag = useCborTag;
2351
2405
  exports.validateUtf8Strict = validateUtf8Strict;
2352
- //# sourceMappingURL=chunk-RVG2BY32.cjs.map
2353
- //# sourceMappingURL=chunk-RVG2BY32.cjs.map
2406
+ //# sourceMappingURL=chunk-3Z45RBZP.cjs.map
2407
+ //# sourceMappingURL=chunk-3Z45RBZP.cjs.map