From bb8feb8cae667f7d07bc414c090c45fd1764c9de Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 2 Sep 2026 18:05:06 +1000 Subject: [PATCH 1/4] feat(interop): pin untrusted-decode bounds as a cross-SDK invariant (LAB-2503) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Readers MUST bound nesting depth (32..=1024) and MUST NOT pre-allocate beyond what the input can back; test-vectors/decode-bounds.json pins 10 reject + 2 accept vectors, generated/verified by tools/decode-bounds-reference.py (stdlib; optional msgpack-python leg). Motivation: LAB-2487 measured nested-header amplification in eager decoders. The 82 MB ceiling previously reported for msgpack-python was an artifact of the array16(10000) probe — array32 headers claiming len(input) reach ~8192x input (10 KB -> 67 MB). --- .github/workflows/verify.yml | 2 + CHANGELOG.md | 22 ++++ sdk-feature-matrix.md | 2 +- spec/interop-mode.md | 46 +++++++ spec/wire-format.md | 6 +- test-vectors/decode-bounds.json | 210 +++++++++++++++++++++++++++++++ tools/decode-bounds-reference.py | 193 ++++++++++++++++++++++++++++ 7 files changed, 479 insertions(+), 2 deletions(-) create mode 100644 test-vectors/decode-bounds.json create mode 100644 tools/decode-bounds-reference.py diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index a267e98..578b620 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -34,6 +34,7 @@ jobs: python3 tools/interop-v2-reference.py verify python3 tools/encryption-verify.py python3 tools/wire-format-reference.py verify + python3 tools/decode-bounds-reference.py verify - name: Python reference verify (optional deps — AES-GCM seal + msgpack third-encoder + lz4 C-implementation conformance) run: | @@ -42,6 +43,7 @@ jobs: python3 tools/interop-v2-reference.py verify python3 tools/encryption-verify.py --require-seal python3 tools/wire-format-reference.py verify --require-extras + python3 tools/decode-bounds-reference.py verify - name: JS cross-check (independent encoder + @noble/hashes + WebCrypto) run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 7954064..a1f3511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to the CacheKit Protocol Specification. ## [Unreleased] +### Interop mode — untrusted-decode bounds pinned as a cross-SDK invariant (LAB-2503) + +- New [`spec/interop-mode.md` → Decode bounds](spec/interop-mode.md#decode-bounds): + readers MUST bound nesting depth (≥ 32, ≤ 1024), MUST NOT pre-allocate beyond + what the input can back (Σ declared slots ≤ input bytes − 1; structurally + incomplete documents are rejected without being materialised), and MUST fail + closed with a catchable error. Motivated by the LAB-2487 measurements: nested + collection headers amplify a few KB of input into hundreds of MB of transient + heap in eager decoders (15 KB → ~400 MB in `@msgpack/msgpack`; 10 KB → 67 MB + in `msgpack-python` with `array32` headers claiming `len(input)` — the + "82 MB hard ceiling" previously reported for Python was an artifact of the + `array16(10000)` probe, not a property of the decoder). +- New [`test-vectors/decode-bounds.json`](test-vectors/decode-bounds.json): + 10 reject vectors + 2 accept vectors, generated and verified by + [`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py) + (stdlib; the optional-deps CI leg also proves `msgpack-python` conforms). + Vendored and CI-executed by cachekit-py and cachekit-rs. +- [`spec/wire-format.md` → Security Limits](spec/wire-format.md#security-limits) + cross-references the rules for the payload inside the envelope. +- The single shared depth value stays [protocol#20](https://github.com/cachekit-io/protocol/issues/20)'s + open item; the spec pins the floor/ceiling every SDK already satisfies. + ### Wire format — compressed-byte reproducibility scoped per-vector (LAB-1751) - LZ4 compressed bytes are **not canonical** across conforming block encoders. diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index a1f64e9..9d8bf09 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -285,7 +285,7 @@ its spec: | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | | AAD v0x03 | ✅ Compliant (5 components — every auto serializer appends `original_type`; interop mode is the sole 4-component path) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | -| Test vectors in CI¹⁶ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ✅ interop/v1 (full set) since [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors | ⚠️ Pending | +| Test vectors in CI¹⁶ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) + decode-bounds (LAB-2503) | ✅ interop/v1 (full set) since [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) + decode-bounds (LAB-2503) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors; decode bounds enforced ([#112](https://github.com/cachekit-io/cachekit-ts/pull/112)), `decode-bounds.json` not yet vendored | ⚠️ Pending | | Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Released — PyPI 0.14.0+¹⁷ ([#220](https://github.com/cachekit-io/cachekit-py/pull/220)) | ✅ Released — crates.io 0.4.0+ ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Released — npm 0.1.3+ ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71)) | ❌ Not implemented | > [!NOTE] diff --git a/spec/interop-mode.md b/spec/interop-mode.md index 6948dc2..d0ada36 100644 --- a/spec/interop-mode.md +++ b/spec/interop-mode.md @@ -35,6 +35,7 @@ - [Encryption in Interop Mode](#encryption-in-interop-mode) - [SaaS Considerations](#saas-considerations) - [SDK Implementation Requirements](#sdk-implementation-requirements) + - [Decode bounds](#decode-bounds) - [Design Decisions](#design-decisions) - [Test Vectors](#test-vectors) @@ -438,6 +439,43 @@ strings** (TypeScript has no UUID type): callers MUST use the lowercase hyphenat form, or `"550E8400-…"` from TS will silently miss the key a Python `uuid.UUID` argument produced. +### Decode bounds + +Interop values are read from a backend the SDK does not control, so every decoder +is an untrusted-input parser. A MessagePack collection header costs 1–5 bytes but +may declare up to 2³²−1 elements, and an eager decoder pre-allocates the container +*before* decoding its children; depth-first decoding stacks those allocations, so a +few KB of nested headers can drive hundreds of MB of transient heap (measured +15 KB → ~400 MB in `@msgpack/msgpack` 3.1.3; 10 KB → 67 MB in `msgpack-python` +1.2.1 with `array32` headers claiming `len(input)` elements). A reader MUST +therefore: + +1. **Bound nesting depth.** The bound MUST be at least 32 and MUST NOT exceed 1024. + (Today: TypeScript 100, Rust 100 — `rmp-serde`'s 1024 default overflows a + 2 MiB thread stack in debug builds, an uncatchable abort — Python 1024, fixed + by `msgpack-python`'s iterative C unpacker and not configurable. A single shared value is + [protocol#20](https://github.com/cachekit-io/protocol/issues/20)'s open item; + until it is ratified, writers SHOULD keep values within 32 levels.) +2. **Never pre-allocate beyond what the input can back.** Every declared element or + byte needs at least one input byte, so a structurally incomplete document + (Σ declared slots > input bytes − 1) MUST be rejected *without* materialising it. + Slice-based decoders that size containers lazily satisfy this inherently + (`rmp-serde`); decoders that pre-allocate from headers MUST validate first — a + header-only structural walk (`Unpacker.skip()` in `msgpack-python`, the pre-scan + in `cachekit-ts`) is sufficient. +3. **Fail closed, catchably.** Rejection surfaces as a decode error the SDK read + path turns into a cache miss — never an uncaught crash or an OOM abort. + +These bounds are SDK-owned invariants, not library defaults: each SDK pins them +explicitly and regression-tests them, so a decoder dependency bump cannot silently +re-open the amplifier. +[`test-vectors/decode-bounds.json`](../test-vectors/decode-bounds.json) pins the +bytes every decoder MUST reject (10) and MUST accept (2); the same rules apply to +any other untrusted MessagePack decode in an SDK (auto-mode payloads after the +envelope is unwrapped, invalidation events). The 40× residual — a *legal* payload +still materialises far more than its byte size in language objects — is bounded by +each SDK's input-size cap, not by these rules. + --- ## Design Decisions @@ -472,6 +510,14 @@ not re-litigated by accident. | `encryption_vectors` | 1 | Full HKDF-SHA256 → AES-256-GCM round-trip over plain-msgpack plaintext with the interop AAD (fixed nonce; decrypt-verified) | | `error_vectors` | 9 | Inputs that MUST be rejected (NaN, +Inf and −Inf as independent vectors, int overflow/underflow, naive datetime, bad segments incl. trailing newline). The `error` text is a maintainer note, not a normative message | +[`test-vectors/decode-bounds.json`](../test-vectors/decode-bounds.json) (see +[Decode bounds](#decode-bounds)) adds 10 `reject_vectors` (nested-header bombs, +over-claiming `array32`/`map32`/`bin32`/`str32` headers, a truncated array) and 2 +`accept_vectors` (32-deep nesting, a fully backed `array16`) that every SDK's +untrusted decoder MUST honour; `tools/decode-bounds-reference.py verify` checks the +file against its recipes and, when `msgpack-python` is installed, against the real +decoder. + Inputs use a tagged-JSON convention (`{"$set": …}`, `{"$float": "2.0"}`, `{"$int": "…"}`, `{"$datetime": "…"}`, `{"$uuid": "…"}`, `{"$bytes": ""}`) documented in the file header, because JSON alone cannot express sets, bytes, floats diff --git a/spec/wire-format.md b/spec/wire-format.md index 74e5e89..cebffe1 100644 --- a/spec/wire-format.md +++ b/spec/wire-format.md @@ -377,7 +377,11 @@ let checksum: [u8; 8] = xxh3_64(&original_data).to_be_bytes(); > length header against the remaining input bytes **before** allocating for it — > a 5-byte `bin32` header can otherwise declare a 4 GiB allocation from a > ~30-byte envelope. (Slice-based decoders such as `rmp-serde` satisfy this -> inherently; readers that pre-allocate from length fields must check.) +> inherently; readers that pre-allocate from length fields must check.) The +> payload *inside* the envelope is untrusted MessagePack too — decode it under +> the depth and allocation rules in +> [interop-mode.md → Decode bounds](interop-mode.md#decode-bounds), pinned by +> `test-vectors/decode-bounds.json`. | Limit | Value | Purpose | | :--- | ---: | :--- | diff --git a/test-vectors/decode-bounds.json b/test-vectors/decode-bounds.json new file mode 100644 index 0000000..91ab717 --- /dev/null +++ b/test-vectors/decode-bounds.json @@ -0,0 +1,210 @@ +{ + "version": "1.0.0", + "spec": "spec/interop-mode.md#decode-bounds", + "generator": "tools/decode-bounds-reference.py generate (CPython stdlib)", + "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, auto-mode payloads after the ByteStorage envelope is unwrapped, invalidation events. The bytes are plain MessagePack with no envelope.", + "rules": { + "depth": "Readers MUST bound nesting depth. The bound MUST be >= 32 and MUST be <= 1024; every reject vector tagged 'depth' nests deeper than 1024.", + "overclaim": "Readers MUST NOT pre-allocate for a collection/str/bin header more than the remaining input can back (each element or byte needs >= 1 input byte), and MUST reject a structurally incomplete document. Every reject vector tagged 'overclaim' has declared_slots > input_len - 1 (the root header is the only byte that is not an element).", + "failure_mode": "Rejection MUST surface as a catchable decode error that the SDK read path turns into a cache miss (fail-closed), never an uncaught crash or an OOM abort." + }, + "field_notes": { + "construction": "input = bytes.fromhex(repeat_hex) * count + bytes.fromhex(suffix_hex)", + "nesting_depth": "collection headers along the deepest spine (str/bin count as 0)", + "declared_slots": "sum of every header's declared element/byte count (a nested header counts as one element of its parent)", + "reject_reasons": "which rule(s) the vector violates; a maintainer note, not a normative message" + }, + "reject_vectors": [ + { + "name": "nested_array16_depth_2048", + "description": "2048 nested array16 headers each claiming 10 000 elements, 0 backing bytes. The LAB-2487 amplifier shape: an eager decoder pre-allocates 10 000 slots per level before hitting EOF.", + "construction": { + "repeat_hex": "dc2710", + "count": 2048, + "suffix_hex": "" + }, + "input_hex": "dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710", + "input_len": 6144, + "nesting_depth": 2048, + "declared_slots": 20480000, + "reject_reasons": [ + "depth", + "overclaim" + ] + }, + { + "name": "nested_array32_input_len_depth_1100", + "description": "1100 nested array32 headers each claiming exactly len(input)=5500 elements. Defeats a per-collection cap of len(input): peak pre-allocation is depth x len(input) x slot size.", + "construction": { + "repeat_hex": "dd0000157c", + "count": 1100, + "suffix_hex": "" + }, + "input_hex": "dd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157cdd0000157c", + "input_len": 5500, + "nesting_depth": 1100, + "declared_slots": 6050000, + "reject_reasons": [ + "depth", + "overclaim" + ] + }, + { + "name": "nested_map16_depth_2048", + "description": "Map twin of nested_array16_depth_2048 (map pre-allocation is typically larger per slot).", + "construction": { + "repeat_hex": "de2710", + "count": 2048, + "suffix_hex": "" + }, + "input_hex": "de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710", + "input_len": 6144, + "nesting_depth": 2048, + "declared_slots": 20480000, + "reject_reasons": [ + "depth", + "overclaim" + ] + }, + { + "name": "nested_fixarray_depth_2048_complete", + "description": "Structurally COMPLETE document ([[...[null]...]]) nested 2048 deep: every header is backed, so only the depth bound rejects it. Isolates the depth rule from the allocation rule.", + "construction": { + "repeat_hex": "91", + "count": 2048, + "suffix_hex": "c0" + }, + "input_hex": "9191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191919191c0", + "input_len": 2049, + "nesting_depth": 2048, + "declared_slots": 2048, + "reject_reasons": [ + "depth" + ] + }, + { + "name": "array16_overclaim_shallow", + "description": "One array16 header claiming 10 000 elements with 3 backing bytes.", + "construction": { + "repeat_hex": "dc2710", + "count": 1, + "suffix_hex": "010203" + }, + "input_hex": "dc2710010203", + "input_len": 6, + "nesting_depth": 1, + "declared_slots": 10000, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "array32_max_claim_alone", + "description": "A lone 5-byte array32 header claiming 2^32-1 elements.", + "construction": { + "repeat_hex": "ddffffffff", + "count": 1, + "suffix_hex": "" + }, + "input_hex": "ddffffffff", + "input_len": 5, + "nesting_depth": 1, + "declared_slots": 4294967295, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "map32_max_claim_alone", + "description": "A lone 5-byte map32 header claiming 2^32-1 pairs.", + "construction": { + "repeat_hex": "dfffffffff", + "count": 1, + "suffix_hex": "" + }, + "input_hex": "dfffffffff", + "input_len": 5, + "nesting_depth": 1, + "declared_slots": 4294967295, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "bin32_overclaim", + "description": "bin32 header claiming 2^32-1 bytes with 1 backing byte (a 6-byte document declaring a 4 GiB buffer).", + "construction": { + "repeat_hex": "c6ffffffff", + "count": 1, + "suffix_hex": "41" + }, + "input_hex": "c6ffffffff41", + "input_len": 6, + "nesting_depth": 0, + "declared_slots": 4294967295, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "str32_overclaim", + "description": "str32 twin of bin32_overclaim.", + "construction": { + "repeat_hex": "dbffffffff", + "count": 1, + "suffix_hex": "41" + }, + "input_hex": "dbffffffff41", + "input_len": 6, + "nesting_depth": 0, + "declared_slots": 4294967295, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "fixarray_short_by_one", + "description": "fixarray claiming 5 elements with 4 present: the minimal truncated document.", + "construction": { + "repeat_hex": "95", + "count": 1, + "suffix_hex": "c0c0c0c0" + }, + "input_hex": "95c0c0c0c0", + "input_len": 5, + "nesting_depth": 1, + "declared_slots": 5, + "reject_reasons": [ + "overclaim" + ] + } + ], + "accept_vectors": [ + { + "name": "nested_fixarray_depth_32", + "description": "[[...[null]...]] nested 32 deep, complete. A conforming reader MUST accept it: the depth bound may not be tighter than 32.", + "construction": { + "repeat_hex": "91", + "count": 32, + "suffix_hex": "c0" + }, + "input_hex": "9191919191919191919191919191919191919191919191919191919191919191c0", + "input_len": 33, + "nesting_depth": 32, + "declared_slots": 32 + }, + { + "name": "array16_256_backed_nils", + "description": "array16 header claiming 256 elements with all 256 present. A *16 header that is fully backed by input is legitimate; the allocation rule is about backing, not header width.", + "construction": { + "repeat_hex": "dc0100", + "count": 1, + "suffix_hex": "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0" + }, + "input_hex": "dc0100c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0", + "input_len": 259, + "nesting_depth": 1, + "declared_slots": 256 + } + ] +} diff --git a/tools/decode-bounds-reference.py b/tools/decode-bounds-reference.py new file mode 100644 index 0000000..2b8b369 --- /dev/null +++ b/tools/decode-bounds-reference.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +"""Reference tool for test-vectors/decode-bounds.json (untrusted-decode bounds). + +Why these vectors exist: a MessagePack collection header costs 1-5 bytes but can +declare up to 2^32-1 elements, and an eager decoder pre-allocates the container +BEFORE decoding the children. Depth-first decoding stacks those allocations, so +a few KB of nested headers can drive hundreds of MB of transient heap (measured +15 KB -> ~400 MB in @msgpack/msgpack 3.1.3; 10 KB -> 67 MB in msgpack-python +1.2.1 with array32 headers claiming len(input) elements). Normative rules live +in spec/interop-mode.md "Decode bounds"; this file pins the bytes every SDK's +decoder MUST reject (and two it MUST accept, so the bound cannot over-tighten). + +Usage: + verify (default) stdlib-only. Regenerates every vector from its + `construction` recipe and byte-compares to `input_hex`; checks the + declared depth / slot arithmetic. When `msgpack` (msgpack-python) + is importable, additionally proves the real decoder rejects every + reject vector and accepts every accept vector. + generate Rewrites the vector file from the recipes below. +""" + +from __future__ import annotations + +import json +from pathlib import Path +import sys + +ROOT = Path(__file__).resolve().parents[1] +VECTORS = ROOT / "test-vectors" / "decode-bounds.json" + +# Every SDK's current depth bound is <= MAX_DEPTH_CEILING (ts 100, rs 100, py +# 1024), so a reject vector nested deeper than this is rejected by all of them; +# every SDK accepts at least MIN_DEPTH_FLOOR levels. +MAX_DEPTH_CEILING = 1024 +MIN_DEPTH_FLOOR = 32 + + +def u16(n: int) -> str: + return n.to_bytes(2, "big").hex() + + +def u32(n: int) -> str: + return n.to_bytes(4, "big").hex() + + +def recipe(name: str, description: str, repeat_hex: str, count: int, suffix_hex: str = "", *, + depth: int, slots: int, reasons: list[str]) -> dict: + data = bytes.fromhex(repeat_hex) * count + bytes.fromhex(suffix_hex) + return { + "name": name, + "description": description, + "construction": {"repeat_hex": repeat_hex, "count": count, "suffix_hex": suffix_hex}, + "input_hex": data.hex(), + "input_len": len(data), + "nesting_depth": depth, + "declared_slots": slots, + "reject_reasons": reasons, + } + + +def build() -> dict: + reject = [ + recipe("nested_array16_depth_2048", + "2048 nested array16 headers each claiming 10 000 elements, 0 backing bytes. The LAB-2487 " + "amplifier shape: an eager decoder pre-allocates 10 000 slots per level before hitting EOF.", + "dc" + u16(10000), 2048, depth=2048, slots=2048 * 10000, reasons=["depth", "overclaim"]), + recipe("nested_array32_input_len_depth_1100", + "1100 nested array32 headers each claiming exactly len(input)=5500 elements. Defeats a " + "per-collection cap of len(input): peak pre-allocation is depth x len(input) x slot size.", + "dd" + u32(5500), 1100, depth=1100, slots=1100 * 5500, reasons=["depth", "overclaim"]), + recipe("nested_map16_depth_2048", + "Map twin of nested_array16_depth_2048 (map pre-allocation is typically larger per slot).", + "de" + u16(10000), 2048, depth=2048, slots=2048 * 10000, reasons=["depth", "overclaim"]), + recipe("nested_fixarray_depth_2048_complete", + "Structurally COMPLETE document ([[...[null]...]]) nested 2048 deep: every header is backed, " + "so only the depth bound rejects it. Isolates the depth rule from the allocation rule.", + "91", 2048, "c0", depth=2048, slots=2048, reasons=["depth"]), + recipe("array16_overclaim_shallow", + "One array16 header claiming 10 000 elements with 3 backing bytes.", + "dc" + u16(10000), 1, "010203", depth=1, slots=10000, reasons=["overclaim"]), + recipe("array32_max_claim_alone", + "A lone 5-byte array32 header claiming 2^32-1 elements.", + "dd" + u32(0xFFFFFFFF), 1, depth=1, slots=0xFFFFFFFF, reasons=["overclaim"]), + recipe("map32_max_claim_alone", + "A lone 5-byte map32 header claiming 2^32-1 pairs.", + "df" + u32(0xFFFFFFFF), 1, depth=1, slots=0xFFFFFFFF, reasons=["overclaim"]), + recipe("bin32_overclaim", + "bin32 header claiming 2^32-1 bytes with 1 backing byte (a 6-byte document declaring a 4 GiB buffer).", + "c6" + u32(0xFFFFFFFF), 1, "41", depth=0, slots=0xFFFFFFFF, reasons=["overclaim"]), + recipe("str32_overclaim", + "str32 twin of bin32_overclaim.", + "db" + u32(0xFFFFFFFF), 1, "41", depth=0, slots=0xFFFFFFFF, reasons=["overclaim"]), + recipe("fixarray_short_by_one", + "fixarray claiming 5 elements with 4 present: the minimal truncated document.", + "95", 1, "c0c0c0c0", depth=1, slots=5, reasons=["overclaim"]), + ] + accept = [ + recipe("nested_fixarray_depth_32", + "[[...[null]...]] nested 32 deep, complete. A conforming reader MUST accept it: the depth " + "bound may not be tighter than 32.", + "91", MIN_DEPTH_FLOOR, "c0", depth=MIN_DEPTH_FLOOR, slots=MIN_DEPTH_FLOOR, reasons=[]), + recipe("array16_256_backed_nils", + "array16 header claiming 256 elements with all 256 present. A *16 header that is fully " + "backed by input is legitimate; the allocation rule is about backing, not header width.", + "dc" + u16(256), 1, "c0" * 256, depth=1, slots=256, reasons=[]), + ] + for v in accept: + del v["reject_reasons"] + return { + "version": "1.0.0", + "spec": "spec/interop-mode.md#decode-bounds", + "generator": "tools/decode-bounds-reference.py generate (CPython stdlib)", + "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, auto-mode payloads after " + "the ByteStorage envelope is unwrapped, invalidation events. The bytes are plain MessagePack " + "with no envelope.", + "rules": { + "depth": f"Readers MUST bound nesting depth. The bound MUST be >= {MIN_DEPTH_FLOOR} and MUST be " + f"<= {MAX_DEPTH_CEILING}; every reject vector tagged 'depth' nests deeper than " + f"{MAX_DEPTH_CEILING}.", + "overclaim": "Readers MUST NOT pre-allocate for a collection/str/bin header more than the remaining " + "input can back (each element or byte needs >= 1 input byte), and MUST reject a " + "structurally incomplete document. Every reject vector tagged 'overclaim' has " + "declared_slots > input_len - 1 (the root header is the only byte that is not an element).", + "failure_mode": "Rejection MUST surface as a catchable decode error that the SDK read path turns " + "into a cache miss (fail-closed), never an uncaught crash or an OOM abort.", + }, + "field_notes": { + "construction": "input = bytes.fromhex(repeat_hex) * count + bytes.fromhex(suffix_hex)", + "nesting_depth": "collection headers along the deepest spine (str/bin count as 0)", + "declared_slots": "sum of every header's declared element/byte count (a nested header counts as one element of its parent)", + "reject_reasons": "which rule(s) the vector violates; a maintainer note, not a normative message", + }, + "reject_vectors": reject, + "accept_vectors": accept, + } + + +def check(condition: bool, name: str, detail: str) -> None: + """Fail closed even under ``python -O`` (asserts would be stripped).""" + if not condition: + raise ValueError(f"{name}: {detail}") + + +def verify(document: dict) -> tuple[int, str]: + fresh = build() + check(document == fresh, "document", "vector file differs from the recipes; run `generate`") + for v in document["reject_vectors"] + document["accept_vectors"]: + c = v["construction"] + data = bytes.fromhex(c["repeat_hex"]) * c["count"] + bytes.fromhex(c["suffix_hex"]) + check(data.hex() == v["input_hex"], v["name"], "input_hex does not match construction") + check(len(data) == v["input_len"], v["name"], "input_len mismatch") + reasons = v.get("reject_reasons", []) + check(("depth" in reasons) == (v["nesting_depth"] > MAX_DEPTH_CEILING), v["name"], "depth tag mismatch") + # Slot budget: every declared element (including a nested header) costs >= 1 input + # byte; only the root header is not itself an element. So sum(declared) <= len - 1. + check(("overclaim" in reasons) == (v["declared_slots"] > v["input_len"] - 1), v["name"], "overclaim tag mismatch") + if not reasons: + check(v["nesting_depth"] <= MIN_DEPTH_FLOOR, v["name"], "accept vector deeper than the floor") + + try: + import msgpack # type: ignore[import-not-found] + except ImportError: + return len(document["reject_vectors"]) + len(document["accept_vectors"]), "stdlib only (msgpack absent)" + + for v in document["reject_vectors"]: + data = bytes.fromhex(v["input_hex"]) + try: + msgpack.unpackb(data) + except Exception: # noqa: BLE001 — any decode error is a conforming rejection + continue + raise ValueError(f"{v['name']}: msgpack-python decoded a reject vector") + for v in document["accept_vectors"]: + msgpack.unpackb(bytes.fromhex(v["input_hex"])) + return len(document["reject_vectors"]) + len(document["accept_vectors"]), f"msgpack-python {msgpack.version} conformance" + + +def main() -> None: + mode = sys.argv[1] if len(sys.argv) > 1 else "verify" + if mode == "generate": + VECTORS.write_text(json.dumps(build(), indent=2) + "\n", encoding="utf-8") + print(f"wrote {VECTORS.relative_to(ROOT)}") + return + if mode != "verify": + sys.exit(f"usage: {sys.argv[0]} [verify|generate]") + try: + count, leg = verify(json.loads(VECTORS.read_text(encoding="utf-8"))) + except ValueError as e: + sys.exit(f"decode-bounds verify FAILED: {e}") + print(f"decode-bounds: {count} vectors OK ({leg})") + + +if __name__ == "__main__": + main() From a4bda44fd894455dc9d124fb7fd926b5b4ab846a Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 2 Sep 2026 18:52:30 +1000 Subject: [PATCH 2/4] docs(interop): apply LAB-2503 panel findings to decode-bounds spec and tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rmp-serde is not allocation-free: serde's Vec visitor pre-allocates up to 1 MiB per collection from the declared length; the spec no longer claims slice-based decoders satisfy the allocation rule inherently. - nested_array16/map16 bombs now claim 2000 elements (< input_len) so a per-collection cap of len(input) does not reject them — the vectors must discriminate for msgpack-python too. - Trim repeated measurement prose; verify() drops checks already implied by the recipe equality; 'conformance' wording narrowed to reject/accept. --- CHANGELOG.md | 20 +++++------------ spec/interop-mode.md | 18 +++++++-------- test-vectors/decode-bounds.json | 14 ++++++------ tools/decode-bounds-reference.py | 38 ++++++++++++++------------------ 4 files changed, 38 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f3511..76de96d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,23 +8,15 @@ All notable changes to the CacheKit Protocol Specification. - New [`spec/interop-mode.md` → Decode bounds](spec/interop-mode.md#decode-bounds): readers MUST bound nesting depth (≥ 32, ≤ 1024), MUST NOT pre-allocate beyond - what the input can back (Σ declared slots ≤ input bytes − 1; structurally - incomplete documents are rejected without being materialised), and MUST fail - closed with a catchable error. Motivated by the LAB-2487 measurements: nested - collection headers amplify a few KB of input into hundreds of MB of transient - heap in eager decoders (15 KB → ~400 MB in `@msgpack/msgpack`; 10 KB → 67 MB - in `msgpack-python` with `array32` headers claiming `len(input)` — the - "82 MB hard ceiling" previously reported for Python was an artifact of the - `array16(10000)` probe, not a property of the decoder). -- New [`test-vectors/decode-bounds.json`](test-vectors/decode-bounds.json): - 10 reject vectors + 2 accept vectors, generated and verified by - [`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py) - (stdlib; the optional-deps CI leg also proves `msgpack-python` conforms). - Vendored and CI-executed by cachekit-py and cachekit-rs. + what the input can back (Σ declared slots ≤ input bytes − 1), and MUST fail + closed with a catchable error. Follow-up to the LAB-2487 measurements. +- New [`test-vectors/decode-bounds.json`](test-vectors/decode-bounds.json) + (10 reject + 2 accept) with [`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py); + vendored and CI-executed by cachekit-py and cachekit-rs. - [`spec/wire-format.md` → Security Limits](spec/wire-format.md#security-limits) cross-references the rules for the payload inside the envelope. - The single shared depth value stays [protocol#20](https://github.com/cachekit-io/protocol/issues/20)'s - open item; the spec pins the floor/ceiling every SDK already satisfies. + open item. ### Wire format — compressed-byte reproducibility scoped per-vector (LAB-1751) diff --git a/spec/interop-mode.md b/spec/interop-mode.md index d0ada36..2fcc7ca 100644 --- a/spec/interop-mode.md +++ b/spec/interop-mode.md @@ -451,18 +451,17 @@ few KB of nested headers can drive hundreds of MB of transient heap (measured therefore: 1. **Bound nesting depth.** The bound MUST be at least 32 and MUST NOT exceed 1024. - (Today: TypeScript 100, Rust 100 — `rmp-serde`'s 1024 default overflows a - 2 MiB thread stack in debug builds, an uncatchable abort — Python 1024, fixed - by `msgpack-python`'s iterative C unpacker and not configurable. A single shared value is + (Today: TypeScript 100, Rust 100, Python 1024. A single shared value is [protocol#20](https://github.com/cachekit-io/protocol/issues/20)'s open item; until it is ratified, writers SHOULD keep values within 32 levels.) 2. **Never pre-allocate beyond what the input can back.** Every declared element or byte needs at least one input byte, so a structurally incomplete document (Σ declared slots > input bytes − 1) MUST be rejected *without* materialising it. - Slice-based decoders that size containers lazily satisfy this inherently - (`rmp-serde`); decoders that pre-allocate from headers MUST validate first — a - header-only structural walk (`Unpacker.skip()` in `msgpack-python`, the pre-scan - in `cachekit-ts`) is sufficient. + Do not assume a decoder is lazy: `rmp-serde` reads str/bin lazily but serde's + `Vec` visitor still pre-allocates up to 1 MiB per collection from the + declared length. A header-only structural walk before decoding (the pre-scan in + `cachekit-ts`, `Unpacker.skip()` in `cachekit-py`, `check_structure` in + `cachekit-rs`) is sufficient. 3. **Fail closed, catchably.** Rejection surfaces as a decode error the SDK read path turns into a cache miss — never an uncaught crash or an OOM abort. @@ -515,8 +514,9 @@ not re-litigated by accident. over-claiming `array32`/`map32`/`bin32`/`str32` headers, a truncated array) and 2 `accept_vectors` (32-deep nesting, a fully backed `array16`) that every SDK's untrusted decoder MUST honour; `tools/decode-bounds-reference.py verify` checks the -file against its recipes and, when `msgpack-python` is installed, against the real -decoder. +file against its recipes and, when `msgpack-python` is installed, that the real +decoder rejects/accepts each vector (rejection only — the allocation rule is each +SDK's own guard). Inputs use a tagged-JSON convention (`{"$set": …}`, `{"$float": "2.0"}`, `{"$int": "…"}`, `{"$datetime": "…"}`, `{"$uuid": "…"}`, `{"$bytes": ""}`) diff --git a/test-vectors/decode-bounds.json b/test-vectors/decode-bounds.json index 91ab717..6a58520 100644 --- a/test-vectors/decode-bounds.json +++ b/test-vectors/decode-bounds.json @@ -17,16 +17,16 @@ "reject_vectors": [ { "name": "nested_array16_depth_2048", - "description": "2048 nested array16 headers each claiming 10 000 elements, 0 backing bytes. The LAB-2487 amplifier shape: an eager decoder pre-allocates 10 000 slots per level before hitting EOF.", + "description": "2048 nested array16 headers each claiming 2000 elements, 0 backing bytes. The LAB-2487 amplifier shape: an eager decoder pre-allocates 2000 slots per level before hitting EOF. 2000 < input_len, so a per-collection cap of len(input) does NOT reject it.", "construction": { - "repeat_hex": "dc2710", + "repeat_hex": "dc07d0", "count": 2048, "suffix_hex": "" }, - "input_hex": "dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710dc2710", + "input_hex": "dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0dc07d0", "input_len": 6144, "nesting_depth": 2048, - "declared_slots": 20480000, + "declared_slots": 4096000, "reject_reasons": [ "depth", "overclaim" @@ -53,14 +53,14 @@ "name": "nested_map16_depth_2048", "description": "Map twin of nested_array16_depth_2048 (map pre-allocation is typically larger per slot).", "construction": { - "repeat_hex": "de2710", + "repeat_hex": "de07d0", "count": 2048, "suffix_hex": "" }, - "input_hex": "de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710de2710", + "input_hex": "de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0de07d0", "input_len": 6144, "nesting_depth": 2048, - "declared_slots": 20480000, + "declared_slots": 8192000, "reject_reasons": [ "depth", "overclaim" diff --git a/tools/decode-bounds-reference.py b/tools/decode-bounds-reference.py index 2b8b369..d729416 100644 --- a/tools/decode-bounds-reference.py +++ b/tools/decode-bounds-reference.py @@ -1,21 +1,16 @@ #!/usr/bin/env python3 """Reference tool for test-vectors/decode-bounds.json (untrusted-decode bounds). -Why these vectors exist: a MessagePack collection header costs 1-5 bytes but can -declare up to 2^32-1 elements, and an eager decoder pre-allocates the container -BEFORE decoding the children. Depth-first decoding stacks those allocations, so -a few KB of nested headers can drive hundreds of MB of transient heap (measured -15 KB -> ~400 MB in @msgpack/msgpack 3.1.3; 10 KB -> 67 MB in msgpack-python -1.2.1 with array32 headers claiming len(input) elements). Normative rules live -in spec/interop-mode.md "Decode bounds"; this file pins the bytes every SDK's -decoder MUST reject (and two it MUST accept, so the bound cannot over-tighten). +Normative rules and the measurements behind them: spec/interop-mode.md → Decode +bounds. This file pins the bytes every SDK's decoder MUST reject (10) and MUST +accept (2, so the bound cannot over-tighten). Usage: - verify (default) stdlib-only. Regenerates every vector from its - `construction` recipe and byte-compares to `input_hex`; checks the - declared depth / slot arithmetic. When `msgpack` (msgpack-python) - is importable, additionally proves the real decoder rejects every - reject vector and accepts every accept vector. + verify (default) stdlib-only. Checks the file equals the recipes below and + that each vector's depth/slot tags match its arithmetic. When + `msgpack` (msgpack-python) is importable, additionally checks the + real decoder rejects every reject vector and accepts every accept + vector — rejection only; the allocation rule is each SDK's guard. generate Rewrites the vector file from the recipes below. """ @@ -61,16 +56,17 @@ def recipe(name: str, description: str, repeat_hex: str, count: int, suffix_hex: def build() -> dict: reject = [ recipe("nested_array16_depth_2048", - "2048 nested array16 headers each claiming 10 000 elements, 0 backing bytes. The LAB-2487 " - "amplifier shape: an eager decoder pre-allocates 10 000 slots per level before hitting EOF.", - "dc" + u16(10000), 2048, depth=2048, slots=2048 * 10000, reasons=["depth", "overclaim"]), + "2048 nested array16 headers each claiming 2000 elements, 0 backing bytes. The LAB-2487 " + "amplifier shape: an eager decoder pre-allocates 2000 slots per level before hitting EOF. " + "2000 < input_len, so a per-collection cap of len(input) does NOT reject it.", + "dc" + u16(2000), 2048, depth=2048, slots=2048 * 2000, reasons=["depth", "overclaim"]), recipe("nested_array32_input_len_depth_1100", "1100 nested array32 headers each claiming exactly len(input)=5500 elements. Defeats a " "per-collection cap of len(input): peak pre-allocation is depth x len(input) x slot size.", "dd" + u32(5500), 1100, depth=1100, slots=1100 * 5500, reasons=["depth", "overclaim"]), recipe("nested_map16_depth_2048", "Map twin of nested_array16_depth_2048 (map pre-allocation is typically larger per slot).", - "de" + u16(10000), 2048, depth=2048, slots=2048 * 10000, reasons=["depth", "overclaim"]), + "de" + u16(2000), 2048, depth=2048, slots=2048 * 2 * 2000, reasons=["depth", "overclaim"]), recipe("nested_fixarray_depth_2048_complete", "Structurally COMPLETE document ([[...[null]...]]) nested 2048 deep: every header is backed, " "so only the depth bound rejects it. Isolates the depth rule from the allocation rule.", @@ -144,11 +140,9 @@ def check(condition: bool, name: str, detail: str) -> None: def verify(document: dict) -> tuple[int, str]: fresh = build() check(document == fresh, "document", "vector file differs from the recipes; run `generate`") + # input_hex / input_len are derived from `construction` by recipe(), so the equality + # above already proves them; what still needs checking is the hand-entered tags. for v in document["reject_vectors"] + document["accept_vectors"]: - c = v["construction"] - data = bytes.fromhex(c["repeat_hex"]) * c["count"] + bytes.fromhex(c["suffix_hex"]) - check(data.hex() == v["input_hex"], v["name"], "input_hex does not match construction") - check(len(data) == v["input_len"], v["name"], "input_len mismatch") reasons = v.get("reject_reasons", []) check(("depth" in reasons) == (v["nesting_depth"] > MAX_DEPTH_CEILING), v["name"], "depth tag mismatch") # Slot budget: every declared element (including a nested header) costs >= 1 input @@ -171,7 +165,7 @@ def verify(document: dict) -> tuple[int, str]: raise ValueError(f"{v['name']}: msgpack-python decoded a reject vector") for v in document["accept_vectors"]: msgpack.unpackb(bytes.fromhex(v["input_hex"])) - return len(document["reject_vectors"]) + len(document["accept_vectors"]), f"msgpack-python {msgpack.version} conformance" + return len(document["reject_vectors"]) + len(document["accept_vectors"]), f"msgpack-python {msgpack.version} rejects/accepts as required" def main() -> None: From 277db510a8c7981582b681fb95276ba8da75e429 Mon Sep 17 00:00:00 2001 From: Winston Date: Thu, 3 Sep 2026 09:27:57 +1000 Subject: [PATCH 3/4] fix(tools): address Kody review on decode-bounds-reference (LAB-2503) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Narrow the msgpack-python rejection check from `except Exception` to `except ValueError`. Every msgpack unpack error subclasses ValueError (StackError, FormatError, ExtraData, max_*_len, incomplete input) — verified per vector under msgpack 1.0.3, 1.2.1 C extension and 1.2.1 pure-Python fallback. The broad clause was also wrong on the merits: it would have counted a MemoryError as a "conforming rejection", which is the exact failure the spec's failure_mode rule forbids. Now anything that is not a ValueError propagates and fails the run. Report lines move from print() to logging.info on a stdout handler with a message-only format, matching interop-v2-reference.py and file-backend-reference.py; stdout bytes are unchanged. Kody-Resolved: tools/decode-bounds-reference.py:163:specific exception handling Kody-Resolved: tools/decode-bounds-reference.py:175:print statements with logging --- tools/decode-bounds-reference.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/decode-bounds-reference.py b/tools/decode-bounds-reference.py index d729416..856304a 100644 --- a/tools/decode-bounds-reference.py +++ b/tools/decode-bounds-reference.py @@ -17,6 +17,7 @@ from __future__ import annotations import json +import logging from pathlib import Path import sys @@ -160,7 +161,10 @@ def verify(document: dict) -> tuple[int, str]: data = bytes.fromhex(v["input_hex"]) try: msgpack.unpackb(data) - except Exception: # noqa: BLE001 — any decode error is a conforming rejection + # Every msgpack-python unpack error subclasses ValueError (StackError, FormatError, + # ExtraData, max_*_len, incomplete input). Anything else — MemoryError, RecursionError, + # a crash — is the failure_mode rule being violated, so it must propagate, not count. + except ValueError: continue raise ValueError(f"{v['name']}: msgpack-python decoded a reject vector") for v in document["accept_vectors"]: @@ -172,7 +176,7 @@ def main() -> None: mode = sys.argv[1] if len(sys.argv) > 1 else "verify" if mode == "generate": VECTORS.write_text(json.dumps(build(), indent=2) + "\n", encoding="utf-8") - print(f"wrote {VECTORS.relative_to(ROOT)}") + logging.info("wrote %s", VECTORS.relative_to(ROOT)) return if mode != "verify": sys.exit(f"usage: {sys.argv[0]} [verify|generate]") @@ -180,8 +184,9 @@ def main() -> None: count, leg = verify(json.loads(VECTORS.read_text(encoding="utf-8"))) except ValueError as e: sys.exit(f"decode-bounds verify FAILED: {e}") - print(f"decode-bounds: {count} vectors OK ({leg})") + logging.info("decode-bounds: %d vectors OK (%s)", count, leg) if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stdout) main() From 2d56cce231e193141f09df9316f9afac17a1538e Mon Sep 17 00:00:00 2001 From: Winston Date: Thu, 3 Sep 2026 09:55:38 +1000 Subject: [PATCH 4/4] fix(interop): address CodeRabbit review on decode-bounds (LAB-2503) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tool (tools/decode-bounds-reference.py): - `--require-extras` (same flag as wire-format-reference.py): a missing msgpack is a failure, so CI's optional-deps leg cannot pass without exercising the real decoder. CLI now fails closed on a flag typo, an unknown mode, two modes, or `generate --require-extras`. - MemoryError/RecursionError from unpackb fail the run naming the vector (the spec's failure_mode rule being violated), instead of a bare trace. - map32_max_claim_alone declared_slots counts pairs as two slots, matching nested_map16_depth_2048 and the field note. - Three new reject vectors, each pinning a distinct implementation error: array32_sum_wraps_u32 (running sum = 2^32 exactly, wraps to 0 in u32), map32_half_claim_wraps_u32_mul (per-header 2 x pairs = 2^32 wraps before the add), fixmap_short_by_one (one-slot-per-pair counting accepts it). msgpack-python 1.0.3 / 1.2.1 C / 1.2.1 pure-Python reject all three. - New mutation suite tools/test_decode_bounds_reference.py (11 guards) runs first in verify.yml, per the workflow's mutation-first doctrine. Spec: - interop-mode: map pair = two slots; per-header terms and the running sum MUST use >= 64-bit or checked/saturating arithmetic; overflow rejects. - wire-format: dropped the false "rmp-serde satisfies this inherently" claim (serde's Vec visitor pre-allocates from declared lengths); the envelope bytes are untrusted MessagePack too, so the decode-bounds pre-scan runs before StorageEnvelope is materialised (Retrieve Flow step 2, now in the read-side conformance list). - Matrix/changelog: decode-bounds vendoring is pending cachekit-py#276 and cachekit-rs#73 (both open), not done; footnote 16 lists the vector file. Rejected (replied on the thread): defining the SDK input-size cap at protocol level — that is a per-deployment sizing decision (LAB-2505). CodeRabbit-Resolved: .github/workflows/verify.yml:37:mutation suite CodeRabbit-Resolved: .github/workflows/verify.yml:46:optional-deps leg CodeRabbit-Resolved: sdk-feature-matrix.md:288:footnote 16 CodeRabbit-Resolved: spec/interop-mode.md:459:overflow-safe slot budget CodeRabbit-Resolved: spec/wire-format.md:380:rmp-serde inherently CodeRabbit-Resolved: spec/wire-format.md:384:envelope decode bounds CodeRabbit-Resolved: tools/decode-bounds-reference.py:83:map32 slot convention CodeRabbit-Resolved: tools/decode-bounds-reference.py:135:FBT001 --- .github/workflows/verify.yml | 3 +- CHANGELOG.md | 8 +- sdk-feature-matrix.md | 6 +- spec/interop-mode.md | 17 +++-- spec/wire-format.md | 20 ++--- test-vectors/decode-bounds.json | 58 ++++++++++++-- tools/decode-bounds-reference.py | 71 ++++++++++++----- tools/test_decode_bounds_reference.py | 105 ++++++++++++++++++++++++++ 8 files changed, 242 insertions(+), 46 deletions(-) create mode 100644 tools/test_decode_bounds_reference.py diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 578b620..b202d49 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -30,6 +30,7 @@ jobs: # Mutation suite first, same doctrine as the version-floor guard below: # prove the fail-closed guards still fail before trusting the verify. python3 tools/test_wire_format_reference.py + python3 tools/test_decode_bounds_reference.py python3 tools/interop-reference.py verify python3 tools/interop-v2-reference.py verify python3 tools/encryption-verify.py @@ -43,7 +44,7 @@ jobs: python3 tools/interop-v2-reference.py verify python3 tools/encryption-verify.py --require-seal python3 tools/wire-format-reference.py verify --require-extras - python3 tools/decode-bounds-reference.py verify + python3 tools/decode-bounds-reference.py verify --require-extras - name: JS cross-check (independent encoder + @noble/hashes + WebCrypto) run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 76de96d..5fdbd8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,12 @@ All notable changes to the CacheKit Protocol Specification. what the input can back (Σ declared slots ≤ input bytes − 1), and MUST fail closed with a catchable error. Follow-up to the LAB-2487 measurements. - New [`test-vectors/decode-bounds.json`](test-vectors/decode-bounds.json) - (10 reject + 2 accept) with [`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py); - vendored and CI-executed by cachekit-py and cachekit-rs. + (13 reject + 2 accept) with [`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py) + and its mutation suite; to be vendored and CI-executed by + [cachekit-py#276](https://github.com/cachekit-io/cachekit-py/pull/276) and + [cachekit-rs#73](https://github.com/cachekit-io/cachekit-rs/pull/73) (both open). - [`spec/wire-format.md` → Security Limits](spec/wire-format.md#security-limits) - cross-references the rules for the payload inside the envelope. + cross-references the rules for the envelope bytes and the payload inside them. - The single shared depth value stays [protocol#20](https://github.com/cachekit-io/protocol/issues/20)'s open item. diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 9d8bf09..ef8c4a2 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -280,12 +280,12 @@ its spec: | Requirement | Python | Rust | TypeScript | PHP | | :--- | :---: | :---: | :---: | :---: | | Key generation (Blake2b) | ✅ Compliant | N/A auto mode¹⁴ — interop/v1 keygen ✅ merged ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); `#[cachekit]` mints interop keys ([#35](https://github.com/cachekit-io/cachekit-rs/pull/35)) | ✅ Compliant | ⚠️ Untested | -| Wire format (ByteStorage) | ✅ Compliant¹⁵ | ✅ Canonical (`cachekit-core`) — unused for stored values¹⁵ | ✅ Compliant | ⚠️ Untested | +| Wire format (ByteStorage) | ✅ Compliant¹⁵ — envelope-bytes decode-bounds pre-scan (LAB-2503) pending verification | ✅ Canonical (`cachekit-core`) — unused for stored values¹⁵ | ✅ Compliant — envelope-bytes decode-bounds pre-scan (LAB-2503) pending verification | ⚠️ Untested | | Storage container (auto mode)¹⁵ | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | | AAD v0x03 | ✅ Compliant (5 components — every auto serializer appends `original_type`; interop mode is the sole 4-component path) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | -| Test vectors in CI¹⁶ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) + decode-bounds (LAB-2503) | ✅ interop/v1 (full set) since [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) + decode-bounds (LAB-2503) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors; decode bounds enforced ([#112](https://github.com/cachekit-io/cachekit-ts/pull/112)), `decode-bounds.json` not yet vendored | ⚠️ Pending | +| Test vectors in CI¹⁶ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack); `decode-bounds.json` vendored + CI-executed pending [cachekit-py#276](https://github.com/cachekit-io/cachekit-py/pull/276) (LAB-2503) | ✅ interop/v1 (full set) since [#33](https://github.com/cachekit-io/cachekit-rs/pull/33); `decode-bounds.json` vendored + CI-executed pending [cachekit-rs#73](https://github.com/cachekit-io/cachekit-rs/pull/73) (LAB-2503) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors; decode bounds enforced ([#112](https://github.com/cachekit-io/cachekit-ts/pull/112)), `decode-bounds.json` not yet vendored | ⚠️ Pending | | Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Released — PyPI 0.14.0+¹⁷ ([#220](https://github.com/cachekit-io/cachekit-py/pull/220)) | ✅ Released — crates.io 0.4.0+ ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Released — npm 0.1.3+ ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71)) | ❌ Not implemented | > [!NOTE] @@ -293,7 +293,7 @@ its spec: > > ¹⁵ Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). > -> ¹⁶ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, `python-frame.json`, `file-backend.json` ([`tools/file-backend-reference.py`](tools/file-backend-reference.py)), and — since LAB-423 — `wire-format.json` ([`tools/wire-format-reference.py`](tools/wire-format-reference.py)) against reference implementations. `cache-keys.json` (regenerated by cachekit-py v0.12.0, byte-identical to the v0.5.0 originals) is vendored and CI-verified in cachekit-py since [cachekit-py#229](https://github.com/cachekit-io/cachekit-py/pull/229) (LAB-425). +> ¹⁶ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, `python-frame.json`, `file-backend.json` ([`tools/file-backend-reference.py`](tools/file-backend-reference.py)), and — since LAB-423 — `wire-format.json` ([`tools/wire-format-reference.py`](tools/wire-format-reference.py)), and — since LAB-2503 — `decode-bounds.json` ([`tools/decode-bounds-reference.py`](tools/decode-bounds-reference.py), `verify` in both the stdlib and the optional-deps legs) against reference implementations. `cache-keys.json` (regenerated by cachekit-py v0.12.0, byte-identical to the v0.5.0 originals) is vendored and CI-verified in cachekit-py since [cachekit-py#229](https://github.com/cachekit-io/cachekit-py/pull/229) (LAB-425). > > ¹⁷ Version cells are **floors** (`X+`), not snapshots — they stay true as new versions publish; check the registry for the current release. Python's floor is the first *installable* one: interop merged under the `v0.13.0` tag, but neither `0.12.0` nor `0.13.0` was ever published to PyPI, so `0.14.0` is the earliest PyPI release containing interop mode. Do not "correct" this to 0.13.0 from the cachekit-py changelog alone. diff --git a/spec/interop-mode.md b/spec/interop-mode.md index 2fcc7ca..14acc14 100644 --- a/spec/interop-mode.md +++ b/spec/interop-mode.md @@ -457,6 +457,11 @@ therefore: 2. **Never pre-allocate beyond what the input can back.** Every declared element or byte needs at least one input byte, so a structurally incomplete document (Σ declared slots > input bytes − 1) MUST be rejected *without* materialising it. + A map pair counts as two slots (key + value). Every per-header term and the running + sum MUST be computed in at least 64 bits or with checked/saturating arithmetic, and + an overflow is itself a rejection: two `array32` headers already exceed 2³², and a + 32-bit accumulator that wraps to a small value passes the budget + (`array32_sum_wraps_u32` and `map32_half_claim_wraps_u32_mul` pin the shapes). Do not assume a decoder is lazy: `rmp-serde` reads str/bin lazily but serde's `Vec` visitor still pre-allocates up to 1 MiB per collection from the declared length. A header-only structural walk before decoding (the pre-scan in @@ -469,7 +474,7 @@ These bounds are SDK-owned invariants, not library defaults: each SDK pins them explicitly and regression-tests them, so a decoder dependency bump cannot silently re-open the amplifier. [`test-vectors/decode-bounds.json`](../test-vectors/decode-bounds.json) pins the -bytes every decoder MUST reject (10) and MUST accept (2); the same rules apply to +bytes every decoder MUST reject (13) and MUST accept (2); the same rules apply to any other untrusted MessagePack decode in an SDK (auto-mode payloads after the envelope is unwrapped, invalidation events). The 40× residual — a *legal* payload still materialises far more than its byte size in language objects — is bounded by @@ -510,13 +515,15 @@ not re-litigated by accident. | `error_vectors` | 9 | Inputs that MUST be rejected (NaN, +Inf and −Inf as independent vectors, int overflow/underflow, naive datetime, bad segments incl. trailing newline). The `error` text is a maintainer note, not a normative message | [`test-vectors/decode-bounds.json`](../test-vectors/decode-bounds.json) (see -[Decode bounds](#decode-bounds)) adds 10 `reject_vectors` (nested-header bombs, -over-claiming `array32`/`map32`/`bin32`/`str32` headers, a truncated array) and 2 +[Decode bounds](#decode-bounds)) adds 13 `reject_vectors` (nested-header bombs, +over-claiming `array32`/`map32`/`bin32`/`str32` headers, a truncated array and map, +two shapes that wrap 32-bit slot arithmetic) and 2 `accept_vectors` (32-deep nesting, a fully backed `array16`) that every SDK's untrusted decoder MUST honour; `tools/decode-bounds-reference.py verify` checks the file against its recipes and, when `msgpack-python` is installed, that the real -decoder rejects/accepts each vector (rejection only — the allocation rule is each -SDK's own guard). +decoder rejects/accepts each vector (rejection only — msgpack-python's default limits +reject them, which proves each vector trips a stock decoder's limits; each SDK's explicit bound and +no-pre-allocation guard are tested in that SDK, not here). Inputs use a tagged-JSON convention (`{"$set": …}`, `{"$float": "2.0"}`, `{"$int": "…"}`, `{"$datetime": "…"}`, `{"$uuid": "…"}`, `{"$bytes": ""}`) diff --git a/spec/wire-format.md b/spec/wire-format.md index cebffe1..57a8222 100644 --- a/spec/wire-format.md +++ b/spec/wire-format.md @@ -264,9 +264,9 @@ bytes are therefore - A conforming reader MUST decompress every pinned vector's `compressed_data` to its pinned input, **and MUST enforce [Retrieve Flow](#retrieve-flow) steps - 4, 5 and 9 while doing so.** Read-side conformance is not "the vectors pass": + 2, 4, 5 and 9 while doing so.** Read-side conformance is not "the vectors pass": every pinned vector is well-formed and declares a truthful `original_size`, so - they evidence **none** of those bounds, and a reader that omits all three + they evidence **none** of those bounds, and a reader that omits all four decompresses all of them successfully. The vectors prove decode interoperability; the bounds in [Security Limits](#security-limits) are a separate, non-negotiable obligation that no fixture can demonstrate. @@ -376,12 +376,13 @@ let checksum: [u8; 8] = xxh3_64(&original_data).to_be_bytes(); > Additionally, a decoder MUST validate any declared MessagePack `bin`/array > length header against the remaining input bytes **before** allocating for it — > a 5-byte `bin32` header can otherwise declare a 4 GiB allocation from a -> ~30-byte envelope. (Slice-based decoders such as `rmp-serde` satisfy this -> inherently; readers that pre-allocate from length fields must check.) The -> payload *inside* the envelope is untrusted MessagePack too — decode it under -> the depth and allocation rules in -> [interop-mode.md → Decode bounds](interop-mode.md#decode-bounds), pinned by -> `test-vectors/decode-bounds.json`. +> ~30-byte envelope. No decoder satisfies this inherently — even slice-based +> ones pre-allocate collections from declared lengths. The envelope bytes *and* +> the payload inside them +> are both untrusted MessagePack — decode each under the depth and allocation +> rules in [interop-mode.md → Decode bounds](interop-mode.md#decode-bounds), +> pinned by `test-vectors/decode-bounds.json`, running the structural pre-scan +> before materialising `StorageEnvelope`. | Limit | Value | Purpose | | :--- | ---: | :--- | @@ -443,7 +444,8 @@ Input: raw_data (bytes), format (string, default "msgpack") Input: envelope_bytes 1. Validate: envelope_bytes.length <= 512 MiB -2. Deserialize: envelope = msgpack_decode(envelope_bytes) as StorageEnvelope +2. Deserialize: pre-scan envelope_bytes (decode bounds, see Security Limits), then + envelope = msgpack_decode(envelope_bytes) as StorageEnvelope // accept BOTH element[0] encodings: bin AND array-of-ints 3. Validate: envelope.compressed_data.length <= 512 MiB 4. Validate: envelope.original_size <= 512 MiB diff --git a/test-vectors/decode-bounds.json b/test-vectors/decode-bounds.json index 6a58520..21b9180 100644 --- a/test-vectors/decode-bounds.json +++ b/test-vectors/decode-bounds.json @@ -2,16 +2,16 @@ "version": "1.0.0", "spec": "spec/interop-mode.md#decode-bounds", "generator": "tools/decode-bounds-reference.py generate (CPython stdlib)", - "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, auto-mode payloads after the ByteStorage envelope is unwrapped, invalidation events. The bytes are plain MessagePack with no envelope.", + "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, the ByteStorage envelope bytes before StorageEnvelope is materialised, auto-mode payloads after the envelope is unwrapped, invalidation events. The bytes are plain MessagePack with no envelope.", "rules": { "depth": "Readers MUST bound nesting depth. The bound MUST be >= 32 and MUST be <= 1024; every reject vector tagged 'depth' nests deeper than 1024.", - "overclaim": "Readers MUST NOT pre-allocate for a collection/str/bin header more than the remaining input can back (each element or byte needs >= 1 input byte), and MUST reject a structurally incomplete document. Every reject vector tagged 'overclaim' has declared_slots > input_len - 1 (the root header is the only byte that is not an element).", + "overclaim": "Readers MUST NOT pre-allocate for a collection/str/bin header more than the remaining input can back (each element or byte needs >= 1 input byte), and MUST reject a structurally incomplete document. Every reject vector tagged 'overclaim' has declared_slots > input_len - 1 (the root header is the only byte that is not an element). A map pair counts as two slots (key + value). Every per-header term and the running sum MUST be computed in >= 64 bits or with checked/saturating arithmetic; an overflow is itself a rejection.", "failure_mode": "Rejection MUST surface as a catchable decode error that the SDK read path turns into a cache miss (fail-closed), never an uncaught crash or an OOM abort." }, "field_notes": { "construction": "input = bytes.fromhex(repeat_hex) * count + bytes.fromhex(suffix_hex)", "nesting_depth": "collection headers along the deepest spine (str/bin count as 0)", - "declared_slots": "sum of every header's declared element/byte count (a nested header counts as one element of its parent)", + "declared_slots": "sum of every header's declared element/byte count; a map pair counts as two slots (key + value); a nested header counts as one element of its parent", "reject_reasons": "which rule(s) the vector violates; a maintainer note, not a normative message" }, "reject_vectors": [ @@ -116,7 +116,7 @@ }, { "name": "map32_max_claim_alone", - "description": "A lone 5-byte map32 header claiming 2^32-1 pairs.", + "description": "A lone 5-byte map32 header claiming 2^32-1 pairs (2^33-2 slots: each pair is a key and a value).", "construction": { "repeat_hex": "dfffffffff", "count": 1, @@ -125,7 +125,55 @@ "input_hex": "dfffffffff", "input_len": 5, "nesting_depth": 1, - "declared_slots": 4294967295, + "declared_slots": 8589934590, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "array32_sum_wraps_u32", + "description": "array32 claiming 2^32-1 elements whose first element is an array32 claiming 1: the declared slots sum to exactly 2^32, which a 32-bit accumulator wraps to 0 and then passes the slot budget.", + "construction": { + "repeat_hex": "ddffffffff", + "count": 1, + "suffix_hex": "dd00000001" + }, + "input_hex": "ddffffffffdd00000001", + "input_len": 10, + "nesting_depth": 2, + "declared_slots": 4294967296, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "map32_half_claim_wraps_u32_mul", + "description": "A lone map32 header claiming 2^31 pairs: the per-header term 2 x pairs is exactly 2^32, which a 32-bit multiply wraps to 0 before it is ever added to the budget.", + "construction": { + "repeat_hex": "df80000000", + "count": 1, + "suffix_hex": "" + }, + "input_hex": "df80000000", + "input_len": 5, + "nesting_depth": 1, + "declared_slots": 4294967296, + "reject_reasons": [ + "overclaim" + ] + }, + { + "name": "fixmap_short_by_one", + "description": "fixmap claiming 1 pair with the key present and the value missing: the map twin of fixarray_short_by_one. Counting one slot per pair (instead of two) accepts it.", + "construction": { + "repeat_hex": "81", + "count": 1, + "suffix_hex": "c0" + }, + "input_hex": "81c0", + "input_len": 2, + "nesting_depth": 1, + "declared_slots": 2, "reject_reasons": [ "overclaim" ] diff --git a/tools/decode-bounds-reference.py b/tools/decode-bounds-reference.py index 856304a..5451954 100644 --- a/tools/decode-bounds-reference.py +++ b/tools/decode-bounds-reference.py @@ -2,7 +2,7 @@ """Reference tool for test-vectors/decode-bounds.json (untrusted-decode bounds). Normative rules and the measurements behind them: spec/interop-mode.md → Decode -bounds. This file pins the bytes every SDK's decoder MUST reject (10) and MUST +bounds. This file pins the bytes every SDK's decoder MUST reject (13) and MUST accept (2, so the bound cannot over-tighten). Usage: @@ -10,7 +10,11 @@ that each vector's depth/slot tags match its arithmetic. When `msgpack` (msgpack-python) is importable, additionally checks the real decoder rejects every reject vector and accepts every accept - vector — rejection only; the allocation rule is each SDK's guard. + vector. Rejection only: msgpack-python's own default limits reject + them, which proves each vector trips a stock decoder's limits; each SDK's explicit bound + and no-pre-allocation guard are tested in that SDK, not here. + `--require-extras` turns a missing msgpack into a failure (CI's + optional-deps leg). generate Rewrites the vector file from the recipes below. """ @@ -79,8 +83,20 @@ def build() -> dict: "A lone 5-byte array32 header claiming 2^32-1 elements.", "dd" + u32(0xFFFFFFFF), 1, depth=1, slots=0xFFFFFFFF, reasons=["overclaim"]), recipe("map32_max_claim_alone", - "A lone 5-byte map32 header claiming 2^32-1 pairs.", - "df" + u32(0xFFFFFFFF), 1, depth=1, slots=0xFFFFFFFF, reasons=["overclaim"]), + "A lone 5-byte map32 header claiming 2^32-1 pairs (2^33-2 slots: each pair is a key and a value).", + "df" + u32(0xFFFFFFFF), 1, depth=1, slots=2 * 0xFFFFFFFF, reasons=["overclaim"]), + recipe("array32_sum_wraps_u32", + "array32 claiming 2^32-1 elements whose first element is an array32 claiming 1: the declared " + "slots sum to exactly 2^32, which a 32-bit accumulator wraps to 0 and then passes the slot budget.", + "dd" + u32(0xFFFFFFFF), 1, "dd" + u32(1), depth=2, slots=0xFFFFFFFF + 1, reasons=["overclaim"]), + recipe("map32_half_claim_wraps_u32_mul", + "A lone map32 header claiming 2^31 pairs: the per-header term 2 x pairs is exactly 2^32, which a " + "32-bit multiply wraps to 0 before it is ever added to the budget.", + "df" + u32(0x80000000), 1, depth=1, slots=2 * 0x80000000, reasons=["overclaim"]), + recipe("fixmap_short_by_one", + "fixmap claiming 1 pair with the key present and the value missing: the map twin of " + "fixarray_short_by_one. Counting one slot per pair (instead of two) accepts it.", + "81", 1, "c0", depth=1, slots=2, reasons=["overclaim"]), recipe("bin32_overclaim", "bin32 header claiming 2^32-1 bytes with 1 backing byte (a 6-byte document declaring a 4 GiB buffer).", "c6" + u32(0xFFFFFFFF), 1, "41", depth=0, slots=0xFFFFFFFF, reasons=["overclaim"]), @@ -107,9 +123,9 @@ def build() -> dict: "version": "1.0.0", "spec": "spec/interop-mode.md#decode-bounds", "generator": "tools/decode-bounds-reference.py generate (CPython stdlib)", - "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, auto-mode payloads after " - "the ByteStorage envelope is unwrapped, invalidation events. The bytes are plain MessagePack " - "with no envelope.", + "scope": "Any untrusted MessagePack decode in any SDK: interop/v1 values, the ByteStorage envelope bytes " + "before StorageEnvelope is materialised, auto-mode payloads after the envelope is unwrapped, " + "invalidation events. The bytes are plain MessagePack with no envelope.", "rules": { "depth": f"Readers MUST bound nesting depth. The bound MUST be >= {MIN_DEPTH_FLOOR} and MUST be " f"<= {MAX_DEPTH_CEILING}; every reject vector tagged 'depth' nests deeper than " @@ -117,14 +133,17 @@ def build() -> dict: "overclaim": "Readers MUST NOT pre-allocate for a collection/str/bin header more than the remaining " "input can back (each element or byte needs >= 1 input byte), and MUST reject a " "structurally incomplete document. Every reject vector tagged 'overclaim' has " - "declared_slots > input_len - 1 (the root header is the only byte that is not an element).", + "declared_slots > input_len - 1 (the root header is the only byte that is not an element). " + "A map pair counts as two slots (key + value). Every per-header term and the running sum " + "MUST be computed in >= 64 bits or with checked/saturating arithmetic; an overflow is " + "itself a rejection.", "failure_mode": "Rejection MUST surface as a catchable decode error that the SDK read path turns " "into a cache miss (fail-closed), never an uncaught crash or an OOM abort.", }, "field_notes": { "construction": "input = bytes.fromhex(repeat_hex) * count + bytes.fromhex(suffix_hex)", "nesting_depth": "collection headers along the deepest spine (str/bin count as 0)", - "declared_slots": "sum of every header's declared element/byte count (a nested header counts as one element of its parent)", + "declared_slots": "sum of every header's declared element/byte count; a map pair counts as two slots (key + value); a nested header counts as one element of its parent", "reject_reasons": "which rule(s) the vector violates; a maintainer note, not a normative message", }, "reject_vectors": reject, @@ -132,13 +151,13 @@ def build() -> dict: } -def check(condition: bool, name: str, detail: str) -> None: +def check(condition: bool, name: str, detail: str) -> None: # noqa: FBT001 """Fail closed even under ``python -O`` (asserts would be stripped).""" if not condition: raise ValueError(f"{name}: {detail}") -def verify(document: dict) -> tuple[int, str]: +def verify(document: dict, *, require_extras: bool = False) -> tuple[int, str]: fresh = build() check(document == fresh, "document", "vector file differs from the recipes; run `generate`") # input_hex / input_len are derived from `construction` by recipe(), so the equality @@ -152,41 +171,53 @@ def verify(document: dict) -> tuple[int, str]: if not reasons: check(v["nesting_depth"] <= MIN_DEPTH_FLOOR, v["name"], "accept vector deeper than the floor") + total = len(document["reject_vectors"]) + len(document["accept_vectors"]) try: import msgpack # type: ignore[import-not-found] except ImportError: - return len(document["reject_vectors"]) + len(document["accept_vectors"]), "stdlib only (msgpack absent)" + if require_extras: + raise ValueError("--require-extras set but msgpack is not importable") from None + return total, "stdlib only (msgpack absent)" for v in document["reject_vectors"]: data = bytes.fromhex(v["input_hex"]) try: msgpack.unpackb(data) - # Every msgpack-python unpack error subclasses ValueError (StackError, FormatError, - # ExtraData, max_*_len, incomplete input). Anything else — MemoryError, RecursionError, - # a crash — is the failure_mode rule being violated, so it must propagate, not count. + # unpackb surfaces every unpack failure as a ValueError (StackError, FormatError, + # ExtraData, max_*_len; it wraps OutOfData — the streaming Unpacker does not). Anything + # else is the failure_mode rule being violated, so it must fail the run, not count. except ValueError: continue + except (MemoryError, RecursionError) as e: + raise ValueError(f"{v['name']}: msgpack-python violated failure_mode ({type(e).__name__})") from e raise ValueError(f"{v['name']}: msgpack-python decoded a reject vector") for v in document["accept_vectors"]: msgpack.unpackb(bytes.fromhex(v["input_hex"])) - return len(document["reject_vectors"]) + len(document["accept_vectors"]), f"msgpack-python {msgpack.version} rejects/accepts as required" + return total, f"msgpack-python {msgpack.version} rejects/accepts as required" def main() -> None: - mode = sys.argv[1] if len(sys.argv) > 1 else "verify" + usage = f"usage: {sys.argv[0]} [verify|generate] [--require-extras]" + args = sys.argv[1:] + require_extras = "--require-extras" in args + modes = [a for a in args if a != "--require-extras"] + mode = modes[0] if modes else "verify" + # Fail closed on anything unexpected: a typo in the flag must not silently drop the + # extras requirement CI relies on, and generate has no extras to require. + if len(modes) > 1 or mode not in ("verify", "generate") or (require_extras and mode != "verify"): + sys.exit(usage) if mode == "generate": VECTORS.write_text(json.dumps(build(), indent=2) + "\n", encoding="utf-8") logging.info("wrote %s", VECTORS.relative_to(ROOT)) return - if mode != "verify": - sys.exit(f"usage: {sys.argv[0]} [verify|generate]") try: - count, leg = verify(json.loads(VECTORS.read_text(encoding="utf-8"))) + count, leg = verify(json.loads(VECTORS.read_text(encoding="utf-8")), require_extras=require_extras) except ValueError as e: sys.exit(f"decode-bounds verify FAILED: {e}") logging.info("decode-bounds: %d vectors OK (%s)", count, leg) if __name__ == "__main__": + # stdout, matching the pre-logging behaviour and the other tools' report lines. logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stdout) main() diff --git a/tools/test_decode_bounds_reference.py b/tools/test_decode_bounds_reference.py new file mode 100644 index 0000000..86e8b79 --- /dev/null +++ b/tools/test_decode_bounds_reference.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Mutation tests for decode-bounds-reference.py's fail-closed guards. + +Same doctrine as test_wire_format_reference.py: poison the input and watch each guard +fire, so a guard that degrades to always-pass is caught before `verify` is trusted. +Nothing here touches test-vectors/decode-bounds.json. + +Run: python3 tools/test_decode_bounds_reference.py (exit 1 on any failure) +""" + +from __future__ import annotations + +import copy +import importlib.util +import subprocess +import sys +import types +from collections.abc import Callable +from pathlib import Path +from unittest.mock import patch + +TOOL = Path(__file__).resolve().parent / "decode-bounds-reference.py" +SPEC = importlib.util.spec_from_file_location("dbr", TOOL) +dbr = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(dbr) + + +def expect_raises(name: str, fn: Callable[[], object], needle: str) -> str | None: + try: + fn() + except ValueError as e: + return None if needle in str(e) else f"{name}: raised but message lacks {needle!r}: {e}" + return f"{name}: did not raise" + + +def with_recipes(doc: dict) -> Callable[[], object]: + """Run verify() with build() patched to agree with `doc`, so only the tag checks stand.""" + def run() -> object: + with patch.object(dbr, "build", lambda: copy.deepcopy(doc)): + return dbr.verify(doc) + return run + + +def with_msgpack(unpackb: Callable[[bytes], object] | None, doc: dict, *, require_extras: bool = False) -> Callable[[], object]: + """Run verify() against a fake msgpack module (None = import blocked).""" + def run() -> object: + fake = None + if unpackb is not None: + fake = types.ModuleType("msgpack") + fake.unpackb, fake.version = unpackb, (0, 0, 0) + with patch.dict(sys.modules, {"msgpack": fake}): + return dbr.verify(doc, require_extras=require_extras) + return run + + +def raise_memory_error(_: bytes) -> None: + raise MemoryError + + +def cli_rejects(name: str, *args: str) -> str | None: + """The CLI must exit non-zero on anything it does not understand (fail closed).""" + rc = subprocess.run([sys.executable, str(TOOL), *args], capture_output=True, check=False).returncode + return None if rc != 0 else f"{name}: exit 0 for {args}" + + +def main() -> None: + good = dbr.build() + results: list[str | None] = [] + + dbr.verify(good) # baseline: the real recipes pass + + drifted = copy.deepcopy(good) + drifted["reject_vectors"][0]["input_hex"] = "c0" + drifted["reject_vectors"][0]["input_hex"][2:] + results.append(expect_raises("file drift", lambda: dbr.verify(drifted), "differs from the recipes")) + + bad_depth = copy.deepcopy(good) + bad_depth["reject_vectors"][0]["nesting_depth"] = 5 # tagged 'depth' but no longer deeper than the ceiling + results.append(expect_raises("depth tag", with_recipes(bad_depth), "depth tag mismatch")) + + bad_slots = copy.deepcopy(good) + bad_slots["reject_vectors"][-1]["declared_slots"] = 1 # tagged 'overclaim' but no longer over-claims + results.append(expect_raises("overclaim tag", with_recipes(bad_slots), "overclaim tag mismatch")) + + deep_accept = copy.deepcopy(good) + deep_accept["accept_vectors"][0]["nesting_depth"] = dbr.MIN_DEPTH_FLOOR + 1 + results.append(expect_raises("accept floor", with_recipes(deep_accept), "deeper than the floor")) + + results.append(expect_raises("require-extras", with_msgpack(None, good, require_extras=True), "not importable")) + results.append(expect_raises("decoded reject", with_msgpack(lambda _: None, good), "decoded a reject vector")) + results.append(expect_raises("OOM not counted as reject", with_msgpack(raise_memory_error, good), "violated failure_mode")) + results.append(cli_rejects("flag typo", "verify", "--require-extra")) + results.append(cli_rejects("unknown mode", "bogus")) + results.append(cli_rejects("two modes", "verify", "generate")) + results.append(cli_rejects("generate with extras", "generate", "--require-extras")) + + failures = [f for f in results if f] + for f in failures: + print("FAIL", f, file=sys.stderr) + if failures: + sys.exit(1) + print(f"decode-bounds mutation suite: {len(results)} guards fire as required") + + +if __name__ == "__main__": + main()