mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-28 01:16:02 +02:00
fix counter incrementing
This commit is contained in:
parent
84c9a7a305
commit
d86de8da4e
129
src/lib.rs
129
src/lib.rs
|
@ -1114,6 +1114,61 @@ impl OutputReader {
|
|||
}
|
||||
}
|
||||
|
||||
// There's some nontrivial logic here to handle partial blocks, and I don't want to copy-paste
|
||||
// it between the xof and xof_xor cases.
|
||||
#[inline(always)]
|
||||
fn fill_inner(&mut self, mut buf: &mut [u8], xor: bool) {
|
||||
debug_assert!(self.position_within_block < BLOCK_LEN as u8);
|
||||
if self.position_within_block != 0 {
|
||||
// The xof() and xof_xor() APIs can handle a partial block at the end but not a partial
|
||||
// block at the beginning. We handle the beginning case here. Start by computing the
|
||||
// complete block that we need part of.
|
||||
let mut partial_block = [0u8; 64];
|
||||
guts::DETECTED_IMPL.xof(
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
&mut partial_block,
|
||||
);
|
||||
let output_bytes = &partial_block[self.position_within_block as usize..];
|
||||
let take = cmp::min(buf.len(), output_bytes.len());
|
||||
if xor {
|
||||
for byte_index in 0..take {
|
||||
buf[byte_index] ^= output_bytes[byte_index];
|
||||
}
|
||||
} else {
|
||||
buf[..take].copy_from_slice(&output_bytes[..take]);
|
||||
}
|
||||
buf = &mut buf[take..];
|
||||
self.position_within_block += take as u8;
|
||||
if self.position_within_block == BLOCK_LEN as u8 {
|
||||
self.position_within_block = 0;
|
||||
self.inner.counter += 1;
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
return;
|
||||
}
|
||||
}
|
||||
let xof_fn = if xor {
|
||||
guts::Implementation::xof_xor
|
||||
} else {
|
||||
guts::Implementation::xof
|
||||
};
|
||||
xof_fn(
|
||||
&guts::DETECTED_IMPL,
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
buf,
|
||||
);
|
||||
self.inner.counter += (buf.len() / BLOCK_LEN) as u64;
|
||||
self.position_within_block = (buf.len() % BLOCK_LEN) as u8;
|
||||
}
|
||||
|
||||
/// Fill a buffer with output bytes and advance the position of the
|
||||
/// `OutputReader`. This is equivalent to [`Read::read`], except that it
|
||||
/// doesn't return a `Result`. Both methods always fill the entire buffer.
|
||||
|
@ -1129,78 +1184,12 @@ impl OutputReader {
|
|||
/// reading further, the behavior is unspecified.
|
||||
///
|
||||
/// [`Read::read`]: #method.read
|
||||
pub fn fill(&mut self, mut buf: &mut [u8]) {
|
||||
debug_assert!(self.position_within_block < BLOCK_LEN as u8);
|
||||
if self.position_within_block != 0 {
|
||||
let mut partial_block = [0u8; 64];
|
||||
guts::DETECTED_IMPL.xof(
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
&mut partial_block,
|
||||
);
|
||||
let output_bytes = &partial_block[self.position_within_block as usize..];
|
||||
let take = cmp::min(buf.len(), output_bytes.len());
|
||||
buf[..take].copy_from_slice(&output_bytes[..take]);
|
||||
buf = &mut buf[take..];
|
||||
self.position_within_block += take as u8;
|
||||
if self.position_within_block == BLOCK_LEN as u8 {
|
||||
self.position_within_block = 0;
|
||||
self.inner.counter += 1;
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
return;
|
||||
}
|
||||
}
|
||||
guts::DETECTED_IMPL.xof(
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
buf,
|
||||
);
|
||||
self.position_within_block = (buf.len() % BLOCK_LEN) as u8;
|
||||
pub fn fill(&mut self, buf: &mut [u8]) {
|
||||
self.fill_inner(buf, false);
|
||||
}
|
||||
|
||||
pub fn fill_xor(&mut self, mut buf: &mut [u8]) {
|
||||
debug_assert!(self.position_within_block < BLOCK_LEN as u8);
|
||||
if self.position_within_block != 0 {
|
||||
let mut partial_block = [0u8; 64];
|
||||
guts::DETECTED_IMPL.xof(
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
&mut partial_block,
|
||||
);
|
||||
let output_bytes = &partial_block[self.position_within_block as usize..];
|
||||
let take = cmp::min(buf.len(), output_bytes.len());
|
||||
for byte_index in 0..take {
|
||||
buf[byte_index] ^= output_bytes[byte_index];
|
||||
}
|
||||
buf = &mut buf[take..];
|
||||
self.position_within_block += take as u8;
|
||||
if self.position_within_block == BLOCK_LEN as u8 {
|
||||
self.position_within_block = 0;
|
||||
self.inner.counter += 1;
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
return;
|
||||
}
|
||||
}
|
||||
guts::DETECTED_IMPL.xof_xor(
|
||||
&self.inner.block,
|
||||
self.inner.block_len as u32,
|
||||
&self.inner.input_chaining_value,
|
||||
self.inner.counter,
|
||||
self.inner.flags as u32,
|
||||
buf,
|
||||
);
|
||||
self.position_within_block = (buf.len() % BLOCK_LEN) as u8;
|
||||
pub fn fill_xor(&mut self, buf: &mut [u8]) {
|
||||
self.fill_inner(buf, true);
|
||||
}
|
||||
|
||||
/// Return the current read position in the output stream. This is
|
||||
|
|
83
src/test.rs
83
src/test.rs
|
@ -292,51 +292,52 @@ fn test_xof_seek() {
|
|||
|
||||
#[test]
|
||||
fn test_xof_xor() {
|
||||
const STEP: usize = 17;
|
||||
for step in [32, 63, 64, 128, 303] {
|
||||
dbg!(step);
|
||||
let mut ref_hasher = reference_impl::Hasher::new();
|
||||
ref_hasher.update(b"foo");
|
||||
let mut ref_output = [0u8; 1000];
|
||||
ref_hasher.finalize(&mut ref_output);
|
||||
|
||||
let mut ref_hasher = reference_impl::Hasher::new();
|
||||
ref_hasher.update(b"foo");
|
||||
let mut ref_output = [0u8; 1000];
|
||||
ref_hasher.finalize(&mut ref_output);
|
||||
let mut hasher = crate::Hasher::new();
|
||||
hasher.update(b"foo");
|
||||
let mut reader = hasher.finalize_xof();
|
||||
|
||||
let mut hasher = crate::Hasher::new();
|
||||
hasher.update(b"foo");
|
||||
let mut reader = hasher.finalize_xof();
|
||||
let mut test_output = [0u8; 1000];
|
||||
for chunk in test_output.chunks_mut(step) {
|
||||
reader.fill(chunk);
|
||||
}
|
||||
assert_eq!(ref_output, test_output);
|
||||
// Xor'ing the same output should zero the buffer.
|
||||
reader.set_position(0);
|
||||
for chunk in test_output.chunks_mut(step) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!([0u8; 1000], test_output);
|
||||
// Xor'ing the same output again should reproduce the original.
|
||||
reader.set_position(0);
|
||||
for chunk in test_output.chunks_mut(step) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!(ref_output, test_output);
|
||||
|
||||
let mut test_output = [0u8; 1000];
|
||||
for chunk in test_output.chunks_mut(STEP) {
|
||||
reader.fill(chunk);
|
||||
// Repeat the same test but starting at offset 500.
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(step) {
|
||||
reader.fill(chunk);
|
||||
}
|
||||
assert_eq!(ref_output[500..], test_output[..500]);
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(step) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!([0u8; 500], test_output[..500]);
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(step) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!(ref_output[500..], test_output[..500]);
|
||||
}
|
||||
assert_eq!(ref_output, test_output);
|
||||
// Xor'ing the same output should zero the buffer.
|
||||
reader.set_position(0);
|
||||
for chunk in test_output.chunks_mut(STEP) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!([0u8; 1000], test_output);
|
||||
// Xor'ing the same output again should reproduce the original.
|
||||
reader.set_position(0);
|
||||
for chunk in test_output.chunks_mut(STEP) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!(ref_output, test_output);
|
||||
|
||||
// Repeat the same test but starting at offset 500.
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(STEP) {
|
||||
reader.fill(chunk);
|
||||
}
|
||||
assert_eq!(ref_output[500..], test_output[..500]);
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(STEP) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!([0u8; 500], test_output[..500]);
|
||||
reader.set_position(500);
|
||||
for chunk in test_output[..500].chunks_mut(STEP) {
|
||||
reader.fill_xor(chunk);
|
||||
}
|
||||
assert_eq!(ref_output[500..], test_output[..500]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue