Skip to content

feat(wrap): pad every 1:1 frame to whole 4096-byte blocks - #1

Merged
koabula merged 3 commits into
mainfrom
feat/lane-wrap-padding
Nov 10, 2026
Merged

koabula merged 3 commits into
mainfrom
feat/lane-wrap-padding

Conversation

@koabula

@koabula koabula commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Summary

The host could tell a 1:1 record's kind by its length. A rotation's announcement carries the whole signed bundle, about five times an ordinary message, and rebuild Welcomes and ContactAccepted each have a size of their own. The lane wrap now pads every frame so that nonce, ciphertext and tag fill the fewest whole blocks of WRAP_BLOCK = 4096 bytes.

  • src/lane_wrap.rs:
    • wrap_frame pads as frame || 0x80 || 0x00*.
    • unwrap_frame refuses any length that is not a whole number of blocks before decrypting, and looks at the padding only after the AEAD has verified, so there is no padding oracle.
    • No client is deployed, so the labels stay at v1 and unpadded frames are refused.
    • Adds eight unit tests.
  • WRAP_BLOCK equals the inbox's default MAX_INLINE_BYTES, so a one-block record is still stored inline.
  • src/leakage_corpus.rs: only_a_payloads_size_reaches_the_host now asserts that:
    • every wrapped payload is a whole number of blocks;
    • every record the script wraps (the rotation's commit and announcement included) is exactly one block;
    • a one-block payload's length is constant across the matrix.
  • contracts/leakage-ledger.json: the ciphertext_length, commit_frequency and envelope.bytes notes follow.

Known limits

  • A sender whose bundle lists two or more devices still sends a multi-block announcement (estimated at more than 5 KB).
  • Group records do not use lane_wrap and are not padded.
  • A short message's stored record grows from about 0.9 KB to about 5.5 KB.

Test plan

  • CI: cargo fmt --check, the whole test suite, and in particular the lane_wrap, leakage_ledger and leakage_corpus tests. Nothing was compiled locally; the record sizes above are estimates, and the corpus test measures them.

🤖 Generated with Claude Code

koala and others added 3 commits November 10, 2026 16:08
The host could tell a rotation, a rebuild Welcome and ContactAccepted
from a message by length alone: a rotation's announcement carries the
whole signed bundle, about five times an ordinary message. The lane wrap
now pads the frame with 0x80 and zeros so that nonce, ciphertext and tag
fill the fewest whole blocks of WRAP_BLOCK = 4096 bytes. Every record
that fits one block has the same length; a longer message shows only its
block count. A sender whose bundle lists two or more devices still sends
a multi-block announcement.

unwrap_frame refuses any length that is not a whole number of blocks
before decrypting, and examines the padding only after the AEAD has
verified, so there is no padding oracle. No client is deployed, so the
labels stay at v1 and unpadded frames are refused.

WRAP_BLOCK equals the inbox's default MAX_INLINE_BYTES, so a one-block
record is still stored inline.

only_a_payloads_size_reaches_the_host now asserts that every wrapped
payload is a whole number of blocks, that every record the script wraps
(the rotation's commit and announcement included) is one block, and that
a one-block payload's length is constant across the matrix. The ledger
notes follow.

Not compiled or tested locally: this machine has no Rust toolchain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
only_a_payloads_size_reaches_the_host looked for Alice's message at
`a_to_b`, but that step appends nothing: Alice holds the message until
Bob's ContactAccepted reaches her and sends it on inside `a_fetch`. The
guard now checks `a_rotate`, which sends the same varied body with
nothing held.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@koabula
koabula merged commit be15571 into main Nov 10, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant