Skip to content

Commit f5ac85f

Browse files
authored
block-buffer: generic implementation of serialization methods (#1200)
1 parent 0e7e6e6 commit f5ac85f

File tree

4 files changed

+56
-75
lines changed

4 files changed

+56
-75
lines changed

block-buffer/CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## UNRELEASED
88
### Added
99
- `ReadBuffer` type ([#823])
10-
- `serialize` and `deserialize` methods ([#823])
1110
- Optional implementation of the `Zeroize` trait ([#963])
11+
- Generic `serialize` and `deserialize` methods ([#1200])
1212

1313
### Changed
1414
- 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
2020
### Removed
2121
- `EagerBuffer::set_data` method. Use the `ReadBuffer` type instead. ([#823])
2222

23-
[#823]: https://github.com/RustCrypto/utils/pull/823
2423
[#963]: https://github.com/RustCrypto/utils/pull/963
2524
[#1115]: https://github.com/RustCrypto/utils/pull/1115
2625
[#1115]: https://github.com/RustCrypto/utils/pull/1116
2726
[#1149]: https://github.com/RustCrypto/utils/pull/1149
27+
[#1200]: https://github.com/RustCrypto/utils/pull/1200
2828

2929
## 0.10.3 (2022-09-04)
3030
### Added

block-buffer/src/lib.rs

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,8 @@
4242

4343
pub use hybrid_array as array;
4444

45-
use array::{
46-
Array, ArraySize,
47-
typenum::{Add1, B1},
48-
};
49-
use core::{fmt, mem::MaybeUninit, ops::Add, ptr, slice};
45+
use array::{Array, ArraySize, typenum::Sum};
46+
use core::{fmt, mem::MaybeUninit, ptr, slice};
5047

5148
#[cfg(feature = "zeroize")]
5249
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -314,6 +311,47 @@ impl<BS: ArraySize, K: BufferKind> BlockBuffer<BS, K> {
314311
}
315312
}
316313

314+
/// Size of serialized `BlockBuffer` in bytes.
315+
pub type SerializedBufferSize<BS, K> = Sum<BS, <K as sealed::Sealed>::Overhead>;
316+
/// `BlockBuffer` serialized as a byte array.
317+
pub type SerializedBuffer<BS, K> = Array<u8, SerializedBufferSize<BS, K>>;
318+
319+
impl<BS: ArraySize, K: BufferKind> BlockBuffer<BS, K>
320+
where
321+
BS: core::ops::Add<K::Overhead>,
322+
Sum<BS, K::Overhead>: ArraySize,
323+
{
324+
/// Serialize buffer into a byte array.
325+
pub fn serialize(&self) -> SerializedBuffer<BS, K> {
326+
let mut buf = SerializedBuffer::<BS, K>::default();
327+
let data = self.get_data();
328+
let (pos, block) = buf.split_at_mut(1);
329+
pos[0] = u8::try_from(data.len()).expect("buffer size is smaller than 256");
330+
block[..data.len()].copy_from_slice(data);
331+
buf
332+
}
333+
334+
/// Deserialize buffer from a byte array.
335+
pub fn deserialize(buf: &SerializedBuffer<BS, K>) -> Result<Self, Error> {
336+
let (pos, block) = buf.split_at(1);
337+
let pos = usize::from(pos[0]);
338+
339+
if !<K as sealed::Sealed>::invariant(pos, BS::USIZE) {
340+
return Err(Error);
341+
}
342+
343+
let (data, tail) = block.split_at(pos);
344+
345+
if tail.iter().any(|&b| b != 0) {
346+
return Err(Error);
347+
}
348+
349+
let mut res = Self::default();
350+
unsafe { res.set_data_unchecked(data) };
351+
Ok(res)
352+
}
353+
}
354+
317355
impl<BS: ArraySize> BlockBuffer<BS, Eager> {
318356
/// Compress remaining data after padding it with `delim`, zeros and
319357
/// the `suffix` bytes. If there is not enough unused space, `compress`
@@ -368,69 +406,6 @@ impl<BS: ArraySize> BlockBuffer<BS, Eager> {
368406
pub fn len128_padding_be(&mut self, data_len: u128, compress: impl FnMut(&Array<u8, BS>)) {
369407
self.digest_pad(0x80, &data_len.to_be_bytes(), compress);
370408
}
371-
372-
/// Serialize buffer into a byte array.
373-
#[inline]
374-
pub fn serialize(&self) -> Array<u8, BS> {
375-
let mut res = Array::<u8, BS>::default();
376-
let data = self.get_data();
377-
res[..data.len()].copy_from_slice(data);
378-
res[BS::USIZE - 1] = data.len() as u8;
379-
res
380-
}
381-
382-
/// Deserialize buffer from a byte array.
383-
#[inline]
384-
pub fn deserialize(buffer: &Array<u8, BS>) -> Result<Self, Error> {
385-
let pos = buffer[BS::USIZE - 1] as usize;
386-
if !<Eager as sealed::Sealed>::invariant(pos, BS::USIZE) {
387-
return Err(Error);
388-
}
389-
if buffer[pos..BS::USIZE - 1].iter().any(|&b| b != 0) {
390-
return Err(Error);
391-
}
392-
Ok(Self {
393-
buffer: MaybeUninit::new(buffer.clone()),
394-
pos: Default::default(),
395-
})
396-
}
397-
}
398-
399-
impl<BS: ArraySize> BlockBuffer<BS, Lazy> {
400-
/// Serialize buffer into a byte array.
401-
#[inline]
402-
pub fn serialize(&self) -> Array<u8, Add1<BS>>
403-
where
404-
BS: Add<B1>,
405-
Add1<BS>: ArraySize,
406-
{
407-
let mut res = Array::<u8, Add1<BS>>::default();
408-
res[0] = self.pos;
409-
let data = self.get_data();
410-
res[1..][..data.len()].copy_from_slice(data);
411-
res
412-
}
413-
414-
/// Deserialize buffer from a byte array.
415-
#[inline]
416-
pub fn deserialize(buffer: &Array<u8, Add1<BS>>) -> Result<Self, Error>
417-
where
418-
BS: Add<B1>,
419-
Add1<BS>: ArraySize,
420-
{
421-
let pos = buffer[0];
422-
if !<Lazy as sealed::Sealed>::invariant(pos as usize, BS::USIZE) {
423-
return Err(Error);
424-
}
425-
if buffer[1..][pos as usize..].iter().any(|&b| b != 0) {
426-
return Err(Error);
427-
}
428-
let buf = Array::try_from(&buffer[1..]).expect("slice has correct length");
429-
Ok(Self {
430-
buffer: MaybeUninit::new(buf),
431-
pos,
432-
})
433-
}
434409
}
435410

436411
#[cfg(feature = "zeroize")]

block-buffer/src/sealed.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use hybrid_array::sizes::{U0, U1};
2+
13
use super::{Array, ArraySize};
24
use core::{mem::MaybeUninit, ptr, slice};
35

@@ -10,6 +12,8 @@ pub trait Sealed {
1012
#[cfg(feature = "zeroize")]
1113
type Pos: Default + Clone + zeroize::Zeroize;
1214

15+
type Overhead: ArraySize;
16+
1317
const NAME: &'static str;
1418

1519
fn get_pos<N: ArraySize>(buf: &Block<N>, pos: &Self::Pos) -> usize;
@@ -26,6 +30,7 @@ pub trait Sealed {
2630

2731
impl Sealed for super::Eager {
2832
type Pos = ();
33+
type Overhead = U0;
2934
const NAME: &'static str = "BlockBuffer<Eager>";
3035

3136
fn get_pos<N: ArraySize>(buf: &Block<N>, _pos: &Self::Pos) -> usize {
@@ -72,6 +77,7 @@ impl Sealed for super::Eager {
7277

7378
impl Sealed for super::Lazy {
7479
type Pos = u8;
80+
type Overhead = U1;
7581
const NAME: &'static str = "BlockBuffer<Lazy>";
7682

7783
fn get_pos<N: ArraySize>(_buf_val: &Block<N>, pos: &Self::Pos) -> usize {

block-buffer/tests/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ fn test_eager_serialize() {
183183
buf1.digest_blocks(&[41, 42], |_| {});
184184

185185
let ser1 = buf1.serialize();
186-
assert_eq!(&ser1[..], &[41, 42, 0, 2]);
186+
assert_eq!(&ser1[..], &[2, 41, 42, 0]);
187187

188188
let mut buf2 = Buf::deserialize(&ser1).unwrap();
189189
assert_eq!(buf1.serialize(), ser1);
@@ -192,7 +192,7 @@ fn test_eager_serialize() {
192192
buf2.digest_blocks(&[43], |_| {});
193193

194194
let ser2 = buf1.serialize();
195-
assert_eq!(&ser2[..], &[41, 42, 43, 3]);
195+
assert_eq!(&ser2[..], &[3, 41, 42, 43]);
196196
assert_eq!(buf1.serialize(), ser2);
197197

198198
let mut buf3 = Buf::deserialize(&ser2).unwrap();
@@ -213,11 +213,11 @@ fn test_eager_serialize() {
213213
let buf = Array([0, 0, 0, 10]);
214214
assert!(Buf::deserialize(&buf).is_err());
215215
// "Garbage" bytes are not zeroized
216-
let buf = Array([1, 0, 0, 0]);
216+
let buf = Array([0, 1, 0, 0]);
217217
assert!(Buf::deserialize(&buf).is_err());
218-
let buf = Array([0, 1, 0, 1]);
218+
let buf = Array([1, 0, 1, 0]);
219219
assert!(Buf::deserialize(&buf).is_err());
220-
let buf = Array([0, 0, 1, 2]);
220+
let buf = Array([2, 0, 0, 1]);
221221
assert!(Buf::deserialize(&buf).is_err());
222222
}
223223

0 commit comments

Comments
 (0)