Skip to content

Commit 043b358

Browse files
fix(crypto): fix BLAKE2b finalization for block-aligned inputs in ZIP-243
The blake2b_256_personal function had a manual loop that processed all complete 128-byte blocks with the finalization flag f=0. For inputs whose length is an exact multiple of the block size (e.g. the outputs preimage for 8+ outputs), the finalize call would find an empty buffer and compress a spurious all-zero block as the final block, producing the wrong hash. Fix: remove the manual loop and feed all data through the Lazy buffer (buffer.digest_blocks), which retains the last block until finalize so the correct finalization flag is always applied.
1 parent 8d7f0c5 commit 043b358

1 file changed

Lines changed: 4 additions & 16 deletions

File tree

bitcoin/src/crypto/sighash_zcash.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ use core::borrow::Borrow;
1212
use core::fmt;
1313

1414
use blake2::digest::core_api::{Buffer, UpdateCore};
15-
use blake2::digest::generic_array::GenericArray;
16-
use blake2::digest::typenum::U128;
1715
use blake2::digest::Output;
1816
use blake2::Blake2bVarCore;
1917

@@ -339,22 +337,12 @@ fn zcash_hash_single_output(tx: &Transaction, index: usize) -> [u8; 32] {
339337

340338
/// Compute BLAKE2b-256 hash with personalization for Zcash (ZIP-243).
341339
pub(crate) fn blake2b_256_personal(data: &[u8], personalization: &[u8]) -> [u8; 32] {
342-
// Create a new core with personalization. Parameters: (salt, persona, key_size, output_size)
343340
let mut core = Blake2bVarCore::new_with_params(&[], personalization, 0, 32);
344-
345-
// Process data in 128-byte blocks (BLAKE2b block size)
346-
let block_size = 128;
347-
let mut pos = 0;
348-
349-
while pos + block_size <= data.len() {
350-
let block = GenericArray::<u8, U128>::from_slice(&data[pos..pos + block_size]);
351-
core.update_blocks(core::slice::from_ref(block));
352-
pos += block_size;
353-
}
354-
355-
// Handle final block with padding
341+
// Use the Lazy buffer for all data so the last block is retained in the buffer
342+
// until finalize, ensuring the correct finalization flag even when data.len()
343+
// is an exact multiple of the 128-byte BLAKE2b block size.
356344
let mut buffer: Buffer<Blake2bVarCore> = Default::default();
357-
buffer.digest_blocks(&data[pos..], |blocks| core.update_blocks(blocks));
345+
buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
358346

359347
// Finalize
360348
let mut full_output: Output<Blake2bVarCore> = Default::default();

0 commit comments

Comments
 (0)