diff --git a/chacha20/CHANGELOG.md b/chacha20/CHANGELOG.md index be0e886f..3709a604 100644 --- a/chacha20/CHANGELOG.md +++ b/chacha20/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.10.2 (UNRELEASED) +### Fixed +- Use of SSE4.1 intrinsic in SSE2 backend of RNG and legacy (64-bit counter) variants ([#580]) + +[#580]: https://github.com/RustCrypto/stream-ciphers/pull/580 + ## 0.10.1 (2026-06-24) ### Added - `ChaCha20LegacyCore` type and `Nonce` type alias ([#570]) diff --git a/chacha20/src/backends/sse2.rs b/chacha20/src/backends/sse2.rs index f6479a1e..1717a24f 100644 --- a/chacha20/src/backends/sse2.rs +++ b/chacha20/src/backends/sse2.rs @@ -6,13 +6,13 @@ #![allow(clippy::cast_sign_loss, reason = "needs triage")] #![allow(clippy::undocumented_unsafe_blocks, reason = "TODO")] -use crate::{Rounds, Variant}; +use crate::{Rounds, STATE_WORDS, Variant}; #[cfg(feature = "rng")] use crate::ChaChaCore; #[cfg(feature = "cipher")] -use crate::{STATE_WORDS, chacha::Block}; +use crate::chacha::Block; #[cfg(feature = "cipher")] use cipher::{ BlockSizeUser, ParBlocksSizeUser, StreamCipherBackend, StreamCipherClosure, @@ -36,23 +36,22 @@ where F: StreamCipherClosure, V: Variant, { - let state_ptr = state.as_ptr().cast::<__m128i>(); - let mut backend = Backend:: { - v: [ - _mm_loadu_si128(state_ptr.add(0)), - _mm_loadu_si128(state_ptr.add(1)), - _mm_loadu_si128(state_ptr.add(2)), - _mm_loadu_si128(state_ptr.add(3)), - ], - _pd: PhantomData, - }; - + let mut backend = Backend::::new(state); f.call(&mut backend); + backend.save_ctr(state); +} - state[12] = _mm_cvtsi128_si32(backend.v[3]) as u32; - if size_of::() == 8 { - state[13] = _mm_extract_epi32(backend.v[3], 1) as u32; - } +#[inline] +#[target_feature(enable = "sse2")] +#[cfg(feature = "rng")] +pub(crate) unsafe fn rng_inner(core: &mut ChaChaCore, buffer: &mut [u32; 64]) +where + R: Rounds, + V: Variant, +{ + let mut backend = Backend::::new(&core.state); + backend.gen_ks_blocks(buffer); + backend.save_ctr(&mut core.state); } struct Backend { @@ -60,6 +59,21 @@ struct Backend { _pd: PhantomData<(R, V)>, } +impl Backend { + unsafe fn new(state: &[u32; STATE_WORDS]) -> Self { + let state_ptr = state.as_ptr().cast::<__m128i>(); + Self { + v: core::array::from_fn(|i| _mm_loadu_si128(state_ptr.add(i))), + _pd: PhantomData, + } + } + + unsafe fn save_ctr(self, state: &mut [u32; STATE_WORDS]) { + let state_ptr = state.as_mut_ptr().cast::<__m128i>(); + _mm_storeu_si128(state_ptr.add(3), self.v[3]); + } +} + #[cfg(feature = "cipher")] impl BlockSizeUser for Backend { type BlockSize = U64; @@ -88,6 +102,7 @@ impl StreamCipherBackend for Backend { } } } + #[inline(always)] fn gen_par_ks_blocks(&mut self, blocks: &mut cipher::ParBlocks) { unsafe { @@ -108,31 +123,6 @@ impl StreamCipherBackend for Backend { } } -#[inline] -#[target_feature(enable = "sse2")] -#[cfg(feature = "rng")] -pub(crate) unsafe fn rng_inner(core: &mut ChaChaCore, buffer: &mut [u32; 64]) -where - R: Rounds, - V: Variant, -{ - let state_ptr = core.state.as_ptr().cast::<__m128i>(); - let mut backend = Backend:: { - v: [ - _mm_loadu_si128(state_ptr.add(0)), - _mm_loadu_si128(state_ptr.add(1)), - _mm_loadu_si128(state_ptr.add(2)), - _mm_loadu_si128(state_ptr.add(3)), - ], - _pd: PhantomData, - }; - - backend.gen_ks_blocks(buffer); - - core.state[12] = _mm_cvtsi128_si32(backend.v[3]) as u32; - core.state[13] = _mm_extract_epi32(backend.v[3], 1) as u32; -} - #[cfg(feature = "rng")] impl Backend { #[inline(always)]