From a6069c27058b1862c9ccab6b78f01b29e84e3cd6 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 5 Aug 2026 08:38:16 +0000 Subject: [PATCH 1/2] cipher: document SeekNum encoding conventions and debug panic from_block_byte and into_block_byte use different (block, byte) encodings (keystream-buffer convention with byte in 1..=bs vs. position division with byte in 0..bs) and are not inverses of each other: feeding the output of into_block_byte back into from_block_byte panics in debug builds (debug_assert!(byte != 0) fires for positions at exact block boundaries) and silently computes a wrong position in release builds (e.g. 16 -> 0 for bs=16). Only '# Errors' was documented. Document both conventions, their non-inverse relationship, and the debug panic. Found by running Kani's autoharness (model-checking/kani#3832) over cipher 0.5.2, which reported the debug_assert reachable; the wrapper's try_seek/try_current_pos use the conventions correctly, so this is a documentation gap on the public trait, not a functional bug in the wrapper. Co-authored-by: Kiro --- cipher/src/stream.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index 33902bb19..f1674a51b 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -276,6 +276,18 @@ pub trait SeekNum: Sized { /// Try to get position for block number `block`, byte position inside /// block `byte`, and block size `bs`. /// + /// `block` and `byte` follow the keystream-buffer convention used by + /// `StreamCipherCoreWrapper`: `block` is the number of + /// the *next* keystream block to be generated, and `byte` (in range `1..=bs`) is the + /// number of bytes of the current keystream block that have been consumed, i.e. the + /// computed position is `block * bs - (bs - byte)`. Note that this is *not* the encoding + /// produced by [`into_block_byte`][SeekNum::into_block_byte], so the two methods are not + /// inverses of each other. + /// + /// # Panics + /// If debug assertions are enabled, panics when `byte` is `0` (a value never produced by + /// the keystream-buffer convention described above). + /// /// # Errors /// Returns [`OverflowError`] in the event of a counter overflow. fn from_block_byte( @@ -286,6 +298,12 @@ pub trait SeekNum: Sized { /// Try to get block number and bytes position for given block size `bs`. /// + /// The returned pair follows the position-division convention: `block` is the number of + /// the keystream block containing the position (`self / bs`) and `byte` (in range + /// `0..bs`) is the byte offset within that block (`self % bs`). Note that this is *not* + /// the encoding accepted by [`from_block_byte`][SeekNum::from_block_byte], so the two + /// methods are not inverses of each other. + /// /// # Errors /// Returns [`OverflowError`] in the event of a counter overflow. fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; From 38778618862730501efea82478a4d45ac7e6c742 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 5 Aug 2026 09:37:19 +0000 Subject: [PATCH 2/2] cipher: document full error and panic conditions of SeekNum methods Review feedback: OverflowError is also returned for out-of-range inputs (byte > bs, unconvertible block), and into_block_byte divides by bs, so bs == 0 panics; document both. Co-authored-by: Kiro --- cipher/src/stream.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index f1674a51b..254ae142b 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -289,7 +289,8 @@ pub trait SeekNum: Sized { /// the keystream-buffer convention described above). /// /// # Errors - /// Returns [`OverflowError`] in the event of a counter overflow. + /// Returns [`OverflowError`] when the computed position overflows `Self`, when + /// `byte > bs`, or when `block` cannot be converted into `Self`. fn from_block_byte( block: T, byte: u8, @@ -304,8 +305,12 @@ pub trait SeekNum: Sized { /// the encoding accepted by [`from_block_byte`][SeekNum::from_block_byte], so the two /// methods are not inverses of each other. /// + /// # Panics + /// Panics when `bs` is `0` (division by zero). + /// /// # Errors - /// Returns [`OverflowError`] in the event of a counter overflow. + /// Returns [`OverflowError`] when the block number does not fit into the counter type + /// `T`. fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; }