diff --git a/wharrgarbl-neko/src/lib.rs b/wharrgarbl-neko/src/lib.rs index 5eb4051..e5c8aff 100644 --- a/wharrgarbl-neko/src/lib.rs +++ b/wharrgarbl-neko/src/lib.rs @@ -148,21 +148,6 @@ impl NekoState { } } - #[inline(always)] - fn advance_position(&mut self, advance: usize) { - let updated = (self.raw_position() as usize) + advance; - debug_assert!((0..=Sec::POS_RATE).contains(&updated)); - if (0..=Sec::POS_RATE).contains(&updated) { - self.position = updated; - } else { - // SAFETY: the type enforces that `updated` is always smaller than - // `RATE * U64_CHUNK` & `u8::MAX`. No operations within NekoState will - // result in an `advance` that increments the `position` beyond a value - // greater than `POS_RATE`. - unsafe { core::hint::unreachable_unchecked() }; - } - } - #[inline(always)] #[must_use] fn should_permute(&self) -> bool { diff --git a/wharrgarbl-neko/src/operators.rs b/wharrgarbl-neko/src/operators.rs index 15af32f..3ef6868 100644 --- a/wharrgarbl-neko/src/operators.rs +++ b/wharrgarbl-neko/src/operators.rs @@ -48,7 +48,13 @@ impl<'s, S: NekoSec> NekoOperateMut<'s, S> { self.data = &mut self.data[advanced..]; // Advance the position state of the neko - self.neko.advance_position(advanced); + // SAFETY: `advanced` will always be an amount that never + // exceeds an increment size that sets the Neko position + // to be bigger than `POS_RATE`, as the value is obtained + // from the zipped count(). + unsafe { + advance_position(&mut self.neko, advanced); + } } } @@ -135,7 +141,13 @@ impl<'s, S: NekoSec> NekoOperate<'s, S> { self.data = &self.data[advanced..]; // Advance the position state of the neko - self.neko.advance_position(advanced); + // SAFETY: `advanced` will always be an amount that never + // exceeds an increment size that sets the Neko position + // to be bigger than `POS_RATE`, as the value is obtained + // from the zipped count(). + unsafe { + advance_position(&mut self.neko, advanced); + } } } @@ -153,3 +165,28 @@ impl<'s, S: NekoSec> NekoOperate<'s, S> { NekoOperate::new(neko, data).operate(|(state, byte)| *state = *byte); } } + +/// # Safety +/// +/// Caller must ensure that `advance_position` is never called with an `advance` +/// value greater than what is allowed, so that the updated position is never +/// greater than `POS_RATE`. +#[inline(always)] +unsafe fn advance_position(neko: &mut NekoState, advance: usize) +where + S: NekoSec, +{ + let updated = (neko.raw_position() as usize) + advance; + debug_assert!((0..=S::POS_RATE).contains(&updated)); + if (0..=S::POS_RATE).contains(&updated) { + neko.position = updated; + } else { + // SAFETY: the type enforces that `updated` is always smaller than + // `RATE * U64_CHUNK` & `u8::MAX`. No operations within NekoState will + // result in an `advance` that increments the `position` beyond a value + // greater than `POS_RATE`. This is upheld by the advance value only being + // given from a zipped count() iterator, which will always provide an + // increment that will never cause position to exceed POS_RATE. + unsafe { core::hint::unreachable_unchecked() }; + } +}