From 021e014b6ca79c89bb310b96b02d77a44b5f3ad3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Fri, 27 Sep 2024 17:42:43 +0300 Subject: [PATCH] block-buffer: remove dependency on crypto-common (#1115) Dependency on `crypto-common` causes some annoyances as mentioned in https://github.com/RustCrypto/traits/issues/1662. Instead of using the sealed `BlockSizes` trait, the new code uses monomorphization errors to enforce block size correctness. This is somewhat non-idiomatic, but should be fine in practice since block buffers are usually used with fixed block sizes. After this change `BlockSizes` probably can be removed from `crypto-common`. I decided against vendoring `block-buffer` code into `digest` as was proposed in the linked issue because `block-buffer` has third-party users and having a separate crate should make it a bit easier for reviewers. --- .github/workflows/block-buffer.yml | 9 ++- Cargo.lock | 11 +-- block-buffer/CHANGELOG.md | 8 ++- block-buffer/Cargo.toml | 2 +- block-buffer/src/lib.rs | 106 +++++++++++++++++++++-------- block-buffer/src/read.rs | 34 ++++----- block-buffer/src/sealed.rs | 2 +- block-buffer/tests/mod.rs | 6 +- 8 files changed, 106 insertions(+), 72 deletions(-) diff --git a/.github/workflows/block-buffer.yml b/.github/workflows/block-buffer.yml index c9239652..9b2b308e 100644 --- a/.github/workflows/block-buffer.yml +++ b/.github/workflows/block-buffer.yml @@ -39,11 +39,10 @@ jobs: targets: ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} - # TODO(tarcieri): re-enable after next `crypto-common` release - #minimal-versions: - # uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master - # with: - # working-directory: ${{ github.workflow }} + minimal-versions: + uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master + with: + working-directory: ${{ github.workflow }} test: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 0ee59d28..277babee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,8 +20,8 @@ dependencies = [ name = "block-buffer" version = "0.11.0-rc.1" dependencies = [ - "crypto-common", "hex-literal 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hybrid-array", "zeroize 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -47,15 +47,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crypto-common" -version = "0.2.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa" -dependencies = [ - "hybrid-array", -] - [[package]] name = "dbl" version = "0.4.0-rc.0" diff --git a/block-buffer/CHANGELOG.md b/block-buffer/CHANGELOG.md index c978381d..3d87f2bc 100644 --- a/block-buffer/CHANGELOG.md +++ b/block-buffer/CHANGELOG.md @@ -11,17 +11,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optional implementation of the `Zeroize` trait ([#963]) ### Changed -- Supported block sizes are now bounded by the `crypto_common::BlockSizes` trait, - which is implemented for types from `U1` to `U255` ([#823]) +- Block sizes must be bigger than 0 and smaller than 256. + This is enforced using compile-time monomorphization errors. ([#1115]) - Size of `EagerBuffer` is equal to buffer size, while previously it was equal to buffer size plus one byte ([#823]) -- Edition changed to 2021 and MSRV bumped to 1.56 ([#823]) +- Edition changed to 2021 and MSRV bumped to 1.81 ([#823], [#1116]) ### Removed - `EagerBuffer::set_data` method. Use the `ReadBuffer` type instead. ([#823]) [#823]: https://github.com/RustCrypto/utils/pull/823 [#963]: https://github.com/RustCrypto/utils/pull/963 +[#1115]: https://github.com/RustCrypto/utils/pull/1115 +[#1115]: https://github.com/RustCrypto/utils/pull/1116 ## 0.10.3 (2022-09-04) ### Added diff --git a/block-buffer/Cargo.toml b/block-buffer/Cargo.toml index 36a00b8f..19a6080f 100644 --- a/block-buffer/Cargo.toml +++ b/block-buffer/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" rust-version = "1.81" [dependencies] -crypto-common = "0.2.0-rc.1" +hybrid-array = "0.2.0-rc.10" zeroize = { version = "1.4", optional = true, default-features = false } [dev-dependencies] diff --git a/block-buffer/src/lib.rs b/block-buffer/src/lib.rs index 87b440da..a5b8b5a8 100644 --- a/block-buffer/src/lib.rs +++ b/block-buffer/src/lib.rs @@ -1,4 +1,38 @@ //! Fixed size buffer for block processing of data. +//! +//! # Examples +//! ``` +//! use block_buffer::{EagerBuffer, array::typenum::U4}; +//! +//! let mut buf = EagerBuffer::::default(); +//! +//! let mut accum = Vec::new(); +//! let msg1: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +//! let msg2: &[u8] = &[10, 11, 12]; +//! +//! buf.digest_blocks(msg1, |blocks| accum.extend_from_slice(blocks)); +//! buf.digest_blocks(msg2, |blocks| accum.extend_from_slice(blocks)); +//! +//! assert_eq!(accum.len(), 3); +//! assert_eq!(accum[0], [0, 1, 2, 3]); +//! assert_eq!(accum[1], [4, 5, 6, 7]); +//! assert_eq!(accum[2], [8, 9, 10, 11]); +//! +//! let padded_block = buf.pad_with_zeros(); +//! assert_eq!(padded_block, [12, 0, 0, 0]); +//! ``` +//! +//! Note that block size used with buffers MUST be bigger than zero and smaller than 256. +//! You will get a compilation error with an invalid block size: +//! +//! ```compile_fail +//! use block_buffer::{EagerBuffer, array::typenum::U0}; +//! let buf = EagerBuffer::::default(); +//! ``` +//! ```compile_fail +//! use block_buffer::{EagerBuffer, array::typenum::U256}; +//! let buf = EagerBuffer::::default(); +//! ``` #![no_std] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", @@ -6,14 +40,13 @@ )] #![warn(missing_docs, rust_2018_idioms)] -pub use crypto_common::{array, Block}; +pub use hybrid_array as array; use array::{ typenum::{Add1, B1}, Array, ArraySize, }; use core::{fmt, mem::MaybeUninit, ops::Add, ptr, slice}; -use crypto_common::{BlockSizeUser, BlockSizes}; #[cfg(feature = "zeroize")] use zeroize::Zeroize; @@ -23,9 +56,6 @@ mod sealed; pub use read::ReadBuffer; -/// Block with additional one byte -type BlockP1 = Array>; - /// Trait for buffer kinds. pub trait BufferKind: sealed::Sealed {} @@ -59,18 +89,28 @@ impl fmt::Display for Error { } /// Buffer for block processing of data. -pub struct BlockBuffer { - buffer: MaybeUninit>, +pub struct BlockBuffer { + buffer: MaybeUninit>, pos: K::Pos, } -impl BlockSizeUser for BlockBuffer { - type BlockSize = BS; +impl BlockBuffer { + /// This associated constant is used to assert block size correctness at compile time. + const BLOCK_SIZE_ASSERT: bool = { + if BS::USIZE == 0 { + panic!("Block size can not be equal to zero!"); + } + if BS::USIZE > 255 { + panic!("Block size can not be bigger than 255!"); + } + true + }; } -impl Default for BlockBuffer { +impl Default for BlockBuffer { #[inline] fn default() -> Self { + assert!(Self::BLOCK_SIZE_ASSERT); let mut buffer = MaybeUninit::uninit(); let mut pos = Default::default(); K::set_pos(&mut buffer, &mut pos, 0); @@ -78,7 +118,7 @@ impl Default for BlockBuffer { } } -impl Clone for BlockBuffer { +impl Clone for BlockBuffer { #[inline] fn clone(&self) -> Self { // SAFETY: `BlockBuffer` does not implement `Drop` (i.e. it could be a `Copy` type), @@ -87,7 +127,7 @@ impl Clone for BlockBuffer { } } -impl fmt::Debug for BlockBuffer { +impl fmt::Debug for BlockBuffer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.debug_struct(K::NAME) .field("pos", &self.get_pos()) @@ -97,7 +137,7 @@ impl fmt::Debug for BlockBuffer { } } -impl BlockBuffer { +impl BlockBuffer { /// Create new buffer from slice. /// /// # Panics @@ -112,6 +152,7 @@ impl BlockBuffer { /// Returns an error if slice length is not valid for used buffer kind. #[inline(always)] pub fn try_new(buf: &[u8]) -> Result { + assert!(Self::BLOCK_SIZE_ASSERT); if !K::invariant(buf.len(), BS::USIZE) { return Err(Error); } @@ -126,7 +167,7 @@ impl BlockBuffer { /// Digest data in `input` in blocks of size `BlockSize` using /// the `compress` function, which accepts slice of blocks. #[inline] - pub fn digest_blocks(&mut self, mut input: &[u8], mut compress: impl FnMut(&[Block])) { + pub fn digest_blocks(&mut self, mut input: &[u8], mut compress: impl FnMut(&[Array])) { let pos = self.get_pos(); // using `self.remaining()` for some reason // prevents panic elimination @@ -186,8 +227,8 @@ impl BlockBuffer { /// Pad remaining data with zeros and return resulting block. #[inline(always)] - pub fn pad_with_zeros(&mut self) -> Block { - let mut res = Block::::default(); + pub fn pad_with_zeros(&mut self) -> Array { + let mut res = Array::::default(); let data = self.get_data(); res[..data.len()].copy_from_slice(data); self.reset(); @@ -221,7 +262,7 @@ impl BlockBuffer { /// # Panics /// If `pos` is bigger or equal to block size. #[inline] - pub fn set(&mut self, buf: Block, pos: usize) { + pub fn set(&mut self, buf: Array, pos: usize) { assert!(K::invariant(pos, BS::USIZE)); self.buffer = MaybeUninit::new(buf); // SAFETY: we have asserted that `pos` satisfies the invariant and @@ -271,7 +312,7 @@ impl BlockBuffer { } } -impl BlockBuffer { +impl BlockBuffer { /// Compress remaining data after padding it with `delim`, zeros and /// the `suffix` bytes. If there is not enough unused space, `compress` /// will be called twice. @@ -279,7 +320,12 @@ impl BlockBuffer { /// # Panics /// If suffix length is bigger than block size. #[inline(always)] - pub fn digest_pad(&mut self, delim: u8, suffix: &[u8], mut compress: impl FnMut(&Block)) { + pub fn digest_pad( + &mut self, + delim: u8, + suffix: &[u8], + mut compress: impl FnMut(&Array), + ) { if suffix.len() > BS::USIZE { panic!("suffix is too long"); } @@ -303,28 +349,28 @@ impl BlockBuffer { /// Pad message with 0x80, zeros and 64-bit message length using /// big-endian byte order. #[inline] - pub fn len64_padding_be(&mut self, data_len: u64, compress: impl FnMut(&Block)) { + pub fn len64_padding_be(&mut self, data_len: u64, compress: impl FnMut(&Array)) { self.digest_pad(0x80, &data_len.to_be_bytes(), compress); } /// Pad message with 0x80, zeros and 64-bit message length using /// little-endian byte order. #[inline] - pub fn len64_padding_le(&mut self, data_len: u64, compress: impl FnMut(&Block)) { + pub fn len64_padding_le(&mut self, data_len: u64, compress: impl FnMut(&Array)) { self.digest_pad(0x80, &data_len.to_le_bytes(), compress); } /// Pad message with 0x80, zeros and 128-bit message length using /// big-endian byte order. #[inline] - pub fn len128_padding_be(&mut self, data_len: u128, compress: impl FnMut(&Block)) { + pub fn len128_padding_be(&mut self, data_len: u128, compress: impl FnMut(&Array)) { self.digest_pad(0x80, &data_len.to_be_bytes(), compress); } /// Serialize buffer into a byte array. #[inline] - pub fn serialize(&self) -> Block { - let mut res = Block::::default(); + pub fn serialize(&self) -> Array { + let mut res = Array::::default(); let data = self.get_data(); res[..data.len()].copy_from_slice(data); res[BS::USIZE - 1] = data.len() as u8; @@ -333,7 +379,7 @@ impl BlockBuffer { /// Deserialize buffer from a byte array. #[inline] - pub fn deserialize(buffer: &Block) -> Result { + pub fn deserialize(buffer: &Array) -> Result { let pos = buffer[BS::USIZE - 1] as usize; if !::invariant(pos, BS::USIZE) { return Err(Error); @@ -348,15 +394,15 @@ impl BlockBuffer { } } -impl BlockBuffer { +impl BlockBuffer { /// Serialize buffer into a byte array. #[inline] - pub fn serialize(&self) -> BlockP1 + pub fn serialize(&self) -> Array> where BS: Add, Add1: ArraySize, { - let mut res = BlockP1::::default(); + let mut res = Array::>::default(); res[0] = self.pos; let data = self.get_data(); res[1..][..data.len()].copy_from_slice(data); @@ -365,7 +411,7 @@ impl BlockBuffer { /// Deserialize buffer from a byte array. #[inline] - pub fn deserialize(buffer: &BlockP1) -> Result + pub fn deserialize(buffer: &Array>) -> Result where BS: Add, Add1: ArraySize, @@ -386,7 +432,7 @@ impl BlockBuffer { } #[cfg(feature = "zeroize")] -impl Zeroize for BlockBuffer { +impl Zeroize for BlockBuffer { #[inline] fn zeroize(&mut self) { self.buffer.zeroize(); diff --git a/block-buffer/src/read.rs b/block-buffer/src/read.rs index 1fb5ac66..ef47dd4e 100644 --- a/block-buffer/src/read.rs +++ b/block-buffer/src/read.rs @@ -1,20 +1,16 @@ -use super::{Block, Error}; +use super::{Array, ArraySize, Error}; + use core::{fmt, slice}; -use crypto_common::{BlockSizeUser, BlockSizes}; #[cfg(feature = "zeroize")] use zeroize::Zeroize; /// Buffer for reading block-generated data. -pub struct ReadBuffer { +pub struct ReadBuffer { // The first byte of the block is used as position. - buffer: Block, -} - -impl BlockSizeUser for ReadBuffer { - type BlockSize = BS; + buffer: Array, } -impl fmt::Debug for ReadBuffer { +impl fmt::Debug for ReadBuffer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ReadBuffer") .field("remaining_data", &self.get_pos()) @@ -22,16 +18,16 @@ impl fmt::Debug for ReadBuffer { } } -impl Default for ReadBuffer { +impl Default for ReadBuffer { #[inline] fn default() -> Self { - let mut buffer = Block::::default(); + let mut buffer = Array::::default(); buffer[0] = BS::U8; Self { buffer } } } -impl Clone for ReadBuffer { +impl Clone for ReadBuffer { #[inline] fn clone(&self) -> Self { Self { @@ -40,7 +36,7 @@ impl Clone for ReadBuffer { } } -impl ReadBuffer { +impl ReadBuffer { /// Return current cursor position. #[inline(always)] pub fn get_pos(&self) -> usize { @@ -77,7 +73,7 @@ impl ReadBuffer { /// in `data` with blocks generated by `gen_block`, and save leftover data /// from the last generated block into buffer for future use. #[inline] - pub fn read(&mut self, mut data: &mut [u8], mut gen_block: impl FnMut(&mut Block)) { + pub fn read(&mut self, mut data: &mut [u8], mut gen_block: impl FnMut(&mut Array)) { let pos = self.get_pos(); let r = self.remaining(); let n = data.len(); @@ -113,7 +109,7 @@ impl ReadBuffer { /// Serialize buffer into a byte array. #[inline] - pub fn serialize(&self) -> Block { + pub fn serialize(&self) -> Array { let mut res = self.buffer.clone(); let pos = self.get_pos(); // zeroize "garbage" data @@ -125,7 +121,7 @@ impl ReadBuffer { /// Deserialize buffer from a byte array. #[inline] - pub fn deserialize(buffer: &Block) -> Result { + pub fn deserialize(buffer: &Array) -> Result { let pos = buffer[0]; if pos == 0 || pos > BS::U8 || buffer[1..pos as usize].iter().any(|&b| b != 0) { Err(Error) @@ -138,10 +134,10 @@ impl ReadBuffer { /// Split message into mutable slice of parallel blocks, blocks, and leftover bytes. #[inline(always)] - fn to_blocks_mut(data: &mut [u8]) -> (&mut [Block], &mut [u8]) { + fn to_blocks_mut(data: &mut [u8]) -> (&mut [Array], &mut [u8]) { let nb = data.len() / BS::USIZE; let (left, right) = data.split_at_mut(nb * BS::USIZE); - let p = left.as_mut_ptr() as *mut Block; + let p = left.as_mut_ptr() as *mut Array; // SAFETY: we guarantee that `blocks` does not point outside of `data`, and `p` is valid for // mutation let blocks = unsafe { slice::from_raw_parts_mut(p, nb) }; @@ -150,7 +146,7 @@ impl ReadBuffer { } #[cfg(feature = "zeroize")] -impl Zeroize for ReadBuffer { +impl Zeroize for ReadBuffer { #[inline] fn zeroize(&mut self) { self.buffer.zeroize(); diff --git a/block-buffer/src/sealed.rs b/block-buffer/src/sealed.rs index d4e147a9..0f060826 100644 --- a/block-buffer/src/sealed.rs +++ b/block-buffer/src/sealed.rs @@ -1,4 +1,4 @@ -use crate::array::{Array, ArraySize}; +use super::{Array, ArraySize}; use core::{mem::MaybeUninit, ptr, slice}; type Block = MaybeUninit>; diff --git a/block-buffer/tests/mod.rs b/block-buffer/tests/mod.rs index 55563d0c..f782009b 100644 --- a/block-buffer/tests/mod.rs +++ b/block-buffer/tests/mod.rs @@ -3,7 +3,7 @@ use block_buffer::{ typenum::{U10, U16, U24, U4, U8}, Array, }, - Block, EagerBuffer, LazyBuffer, ReadBuffer, + EagerBuffer, LazyBuffer, ReadBuffer, }; use hex_literal::hex; @@ -82,7 +82,7 @@ fn test_read() { let mut buf = Buf::default(); let mut n = 0u8; - let mut gen = |block: &mut Block| { + let mut gen = |block: &mut Array| { block.iter_mut().for_each(|b| *b = n); n += 1; }; @@ -288,7 +288,7 @@ fn test_read_serialize() { type Buf = ReadBuffer; let mut n = 42u8; - let mut gen = |block: &mut Block| { + let mut gen = |block: &mut Array| { block.iter_mut().for_each(|b| { *b = n; n += 1;