diff --git a/block-buffer/CHANGELOG.md b/block-buffer/CHANGELOG.md index 0fab6783..196b8303 100644 --- a/block-buffer/CHANGELOG.md +++ b/block-buffer/CHANGELOG.md @@ -7,8 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## UNRELEASED ### Added - `ReadBuffer` type ([#823]) -- `serialize` and `deserialize` methods ([#823]) - Optional implementation of the `Zeroize` trait ([#963]) +- Generic `serialize` and `deserialize` methods ([#1200]) ### Changed - Block sizes must be bigger than 0 and smaller than 256. @@ -20,11 +20,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### 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 [#1149]: https://github.com/RustCrypto/utils/pull/1149 +[#1200]: https://github.com/RustCrypto/utils/pull/1200 ## 0.10.3 (2022-09-04) ### Added diff --git a/block-buffer/src/lib.rs b/block-buffer/src/lib.rs index 851aea51..e92cbca1 100644 --- a/block-buffer/src/lib.rs +++ b/block-buffer/src/lib.rs @@ -42,11 +42,8 @@ pub use hybrid_array as array; -use array::{ - Array, ArraySize, - typenum::{Add1, B1}, -}; -use core::{fmt, mem::MaybeUninit, ops::Add, ptr, slice}; +use array::{Array, ArraySize, typenum::Sum}; +use core::{fmt, mem::MaybeUninit, ptr, slice}; #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -314,6 +311,47 @@ impl BlockBuffer { } } +/// Size of serialized `BlockBuffer` in bytes. +pub type SerializedBufferSize = Sum::Overhead>; +/// `BlockBuffer` serialized as a byte array. +pub type SerializedBuffer = Array>; + +impl BlockBuffer +where + BS: core::ops::Add, + Sum: ArraySize, +{ + /// Serialize buffer into a byte array. + pub fn serialize(&self) -> SerializedBuffer { + let mut buf = SerializedBuffer::::default(); + let data = self.get_data(); + let (pos, block) = buf.split_at_mut(1); + pos[0] = u8::try_from(data.len()).expect("buffer size is smaller than 256"); + block[..data.len()].copy_from_slice(data); + buf + } + + /// Deserialize buffer from a byte array. + pub fn deserialize(buf: &SerializedBuffer) -> Result { + let (pos, block) = buf.split_at(1); + let pos = usize::from(pos[0]); + + if !::invariant(pos, BS::USIZE) { + return Err(Error); + } + + let (data, tail) = block.split_at(pos); + + if tail.iter().any(|&b| b != 0) { + return Err(Error); + } + + let mut res = Self::default(); + unsafe { res.set_data_unchecked(data) }; + Ok(res) + } +} + impl BlockBuffer { /// Compress remaining data after padding it with `delim`, zeros and /// the `suffix` bytes. If there is not enough unused space, `compress` @@ -368,69 +406,6 @@ impl BlockBuffer { 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) -> 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; - res - } - - /// Deserialize buffer from a byte array. - #[inline] - pub fn deserialize(buffer: &Array) -> Result { - let pos = buffer[BS::USIZE - 1] as usize; - if !::invariant(pos, BS::USIZE) { - return Err(Error); - } - if buffer[pos..BS::USIZE - 1].iter().any(|&b| b != 0) { - return Err(Error); - } - Ok(Self { - buffer: MaybeUninit::new(buffer.clone()), - pos: Default::default(), - }) - } -} - -impl BlockBuffer { - /// Serialize buffer into a byte array. - #[inline] - pub fn serialize(&self) -> Array> - where - BS: Add, - Add1: ArraySize, - { - let mut res = Array::>::default(); - res[0] = self.pos; - let data = self.get_data(); - res[1..][..data.len()].copy_from_slice(data); - res - } - - /// Deserialize buffer from a byte array. - #[inline] - pub fn deserialize(buffer: &Array>) -> Result - where - BS: Add, - Add1: ArraySize, - { - let pos = buffer[0]; - if !::invariant(pos as usize, BS::USIZE) { - return Err(Error); - } - if buffer[1..][pos as usize..].iter().any(|&b| b != 0) { - return Err(Error); - } - let buf = Array::try_from(&buffer[1..]).expect("slice has correct length"); - Ok(Self { - buffer: MaybeUninit::new(buf), - pos, - }) - } } #[cfg(feature = "zeroize")] diff --git a/block-buffer/src/sealed.rs b/block-buffer/src/sealed.rs index 0f060826..2be181d2 100644 --- a/block-buffer/src/sealed.rs +++ b/block-buffer/src/sealed.rs @@ -1,3 +1,5 @@ +use hybrid_array::sizes::{U0, U1}; + use super::{Array, ArraySize}; use core::{mem::MaybeUninit, ptr, slice}; @@ -10,6 +12,8 @@ pub trait Sealed { #[cfg(feature = "zeroize")] type Pos: Default + Clone + zeroize::Zeroize; + type Overhead: ArraySize; + const NAME: &'static str; fn get_pos(buf: &Block, pos: &Self::Pos) -> usize; @@ -26,6 +30,7 @@ pub trait Sealed { impl Sealed for super::Eager { type Pos = (); + type Overhead = U0; const NAME: &'static str = "BlockBuffer"; fn get_pos(buf: &Block, _pos: &Self::Pos) -> usize { @@ -72,6 +77,7 @@ impl Sealed for super::Eager { impl Sealed for super::Lazy { type Pos = u8; + type Overhead = U1; const NAME: &'static str = "BlockBuffer"; fn get_pos(_buf_val: &Block, pos: &Self::Pos) -> usize { diff --git a/block-buffer/tests/mod.rs b/block-buffer/tests/mod.rs index 205f457f..241228c7 100644 --- a/block-buffer/tests/mod.rs +++ b/block-buffer/tests/mod.rs @@ -183,7 +183,7 @@ fn test_eager_serialize() { buf1.digest_blocks(&[41, 42], |_| {}); let ser1 = buf1.serialize(); - assert_eq!(&ser1[..], &[41, 42, 0, 2]); + assert_eq!(&ser1[..], &[2, 41, 42, 0]); let mut buf2 = Buf::deserialize(&ser1).unwrap(); assert_eq!(buf1.serialize(), ser1); @@ -192,7 +192,7 @@ fn test_eager_serialize() { buf2.digest_blocks(&[43], |_| {}); let ser2 = buf1.serialize(); - assert_eq!(&ser2[..], &[41, 42, 43, 3]); + assert_eq!(&ser2[..], &[3, 41, 42, 43]); assert_eq!(buf1.serialize(), ser2); let mut buf3 = Buf::deserialize(&ser2).unwrap(); @@ -213,11 +213,11 @@ fn test_eager_serialize() { let buf = Array([0, 0, 0, 10]); assert!(Buf::deserialize(&buf).is_err()); // "Garbage" bytes are not zeroized - let buf = Array([1, 0, 0, 0]); + let buf = Array([0, 1, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); - let buf = Array([0, 1, 0, 1]); + let buf = Array([1, 0, 1, 0]); assert!(Buf::deserialize(&buf).is_err()); - let buf = Array([0, 0, 1, 2]); + let buf = Array([2, 0, 0, 1]); assert!(Buf::deserialize(&buf).is_err()); }