Skip to content

Commit ee349b8

Browse files
committed
docs: reconcile the vectors fixture notes
The merge left two overlaps in vectors/README.md. The producer's chunk-count formula was stated twice, once on the body cipher bullet and once on the chunking bullet added for the trailing empty final chunk. Keep it on the body cipher bullet and narrow the other to what it alone says: a decoder must not re-derive the count that way, because a stream ending in an empty final chunk holds one more chunk than the formula gives for the same plaintext. The framing-case count said three; exact-multiple-go makes four. While correcting it, the "in both directions" claim turned out to cover only two of the cases: single-chunk-go and exact-multiple-go run Go to TS only, so the sentence now names the partial final chunk and the empty file rather than claiming every case. Assisted-by: Claude:claude-opus-5 Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
1 parent 309b108 commit ee349b8

1 file changed

Lines changed: 13 additions & 10 deletions

File tree

vectors/README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ to it and this repo matches it (see [Wire format](#wire-format)).
2828
| `empty-file-ts` | TS seals → Go decrypts | tag 16 |
2929
| `exact-multiple-go` | Go seals → TS decrypts (plaintext is exactly 3 chunks) | tag 16 |
3030

31-
Three framing cases are covered in both directions: a single chunk, a final
32-
partial chunk (the multi-chunk fixtures end mid-chunk), and the empty file. An
33-
empty plaintext encodes as one empty final chunk, so its whole body is a bare
34-
16-byte tag; `TestVectors` asserts the ciphertext length for every fixture.
31+
Four framing cases are covered: a single chunk, a final partial chunk (the
32+
multi-chunk fixtures end mid-chunk), the empty file, and a full final chunk
33+
(`exact-multiple-go`, whose plaintext is exactly 3 chunks). The partial final
34+
chunk and the empty file run in both directions. An empty plaintext encodes as
35+
one empty final chunk, so its whole body is a bare 16-byte tag; `TestVectors`
36+
asserts the ciphertext length for every fixture.
3537

3638
Each `testdata/<name>/` holds `blob.bin` (`envelope‖ciphertext`),
3739
`plaintext.bin`, and `meta.json`.
@@ -63,12 +65,13 @@ recipient = [ {1: alg}, {4: kid, ...}, wrappedKey ] # alg -31 or -5
6365
`baseNonce[7] ‖ chunkIndex[4, big-endian] ‖ lastFlag[1]` (`0x01` on the final
6466
chunk), tag 16 bytes. Chunk count is `max(1, ceil(plaintextLen / chunkSize))`,
6567
so an empty plaintext still seals one (empty) final chunk.
66-
- **Chunking** — a producer writes `ceil(len / chunkSize)` chunks, minimum 1,
67-
with the remainder in the final chunk; empty input is one empty chunk. Both
68-
implementations follow that rule, so `exact-multiple-go` declares 3 chunks
69-
rather than 3 full chunks plus an empty one. A *decoder* also accepts a
70-
trailing empty final chunk, so the declared count is authoritative and must
71-
not be re-derived from the plaintext length.
68+
- **Chunk count on decode** — the formula above is the producer's rule, which
69+
both implementations follow, so `exact-multiple-go` declares 3 chunks rather
70+
than 3 full chunks plus an empty one. A decoder must not re-derive the count
71+
that way: a stream ending in an empty final chunk holds one chunk more than
72+
the formula gives for the same plaintext, and both forms decrypt identically.
73+
The declared count is authoritative, and only the ciphertext length tells the
74+
two forms apart.
7275
- **Body AAD**`Enc_structure = [ context, protected, "" ]`, the **same** for
7376
every chunk. `context` follows the envelope structure per RFC 9052 §5.3:
7477
`"Encrypt"` for a tag-96 envelope, `"Encrypt0"` for tag-16. AAD interop is

0 commit comments

Comments
 (0)