Invariants / CN-WIRE-08

CN-WIRE-08

CN derived enforced

N2N tag-24 CBOR-in-CBOR payload envelopes are constructed and stripped through ONE shared BLUE byte authority in ade_codec (wrap_tag24/unwrap_tag24). Protocol-specific composition lives in ade_network BLUE codecs: a served BlockFetch MsgBlock payload is tag24(bytes([era,block])) (era inside the wrap); a served ChainSync RollForward header is [era_tag, tag24(bytes(header_cbor))] (era_tag outside the wrap). Both compositions are pinned byte-identically against captured cardano-node 11.0.1 wire fixtures, not codec comments. No bare [era,block] may be served over BlockFetch and no bare header over ChainSync RollForward. No hand-rolled tag-24 parse may exist in RED — admission and interop call the shared authority. unwrap_tag24 fails closed (typed error) on non-(0xd8 0x18), wrong inner length, or trailing bytes. The inner bytes are copied verbatim (no re-encode).

Source

docs/planning/phase4-n-x-invariants.md

Cluster
PHASE4-N-X
Introduced in
PHASE4-N-X

Enforcement trace

Tests 24

  • wrap_then_unwrap_is_identity_across_length_classes
  • wrap_emits_canonical_tag24_marker_and_length
  • unwrap_returns_zero_copy_borrow_of_input
  • unwrap_rejects_missing_tag24_marker
  • unwrap_rejects_non_byte_string_payload
  • unwrap_rejects_truncated_inner
  • unwrap_rejects_trailing_bytes
  • inner_bytes_are_verbatim_not_reencoded
  • unwrap_rejects_huge_declared_length_without_panic
  • read_bytes_rejects_overflowing_declared_length
  • read_text_rejects_overflowing_declared_length
  • producer_block_fetch_serve_block_payload_is_tag24_wrapped_and_decodes
  • producer_block_fetch_serve_block_bytes_equal_accepted_block_as_bytes
  • block_body_is_wrapped_cbor_item
  • captured_block_era_index_matches_ade_storage_scheme
  • chain_sync_wire_era_index_is_consensus_index
  • compose_decompose_rollforward_header_round_trips
  • decompose_rollforward_header_rejects_non_tag24_inner
  • conway_rollforward_header_served_shape_matches_oracle
  • producer_chain_sync_serve_roll_forward_header_equals_accepted_block_header_bytes
  • session_transcript_served_block_bytes_equal_admitted_accepted_block_bytes
  • session_transcript_announced_header_matches_served_body_recipe
  • cross_impl_server_pipeline_request_range_returns_decodable_bytes
  • cross_impl_server_pipeline_request_range_byte_identical_to_self_accept_input

Cross-references

Attack rationale

Cardano-specific: a producer that serves bare [era,block] or bare headers is rejected by every real peer — block-fetch payloads and chain-sync headers are CBOR-in-CBOR on the wire. Worse, opaque-byte round-trip tests give false confidence (encode(decode(x))==x while the envelope shape is wrong). Binding both surfaces to one fixture-pinned authority makes a wrong-shape serve and a divergent second parser structurally impossible.

Evidence notes

BlockFetch oracle committed: corpus/network/n2n/block_fetch/local_preprod_tip_msg_01_block.cbor = 82 04 d8 18 59 03 ee 82 03 ... (= [4, tag24(bytes([era,block]))]), captured against docker preprod cardano-node 11.0.1, negotiated N2N v15. ChainSync header shape verified in ade_core_interop/src/follow.rs against a real preprod RollForward frame ([era_tag, tag24(header_cbor)], single wrapper); a committed golden header fixture pinning the SERVED shape is a slice-entry obligation for S3 (Q-1).

Open obligation