Skip to content

Commit 132713d

Browse files
committed
feat: download BLAKE2X test vectors at test time
1 parent c6ee00d commit 132713d

File tree

6 files changed

+137
-6381
lines changed

6 files changed

+137
-6381
lines changed

blake2/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ rand = "0.8"
2525
paste = "1.0"
2626
serde = { version = "1.0", features = ["derive"] }
2727
serde_json = "1.0"
28+
ureq = "2"
2829

2930
[features]
3031
default = ["alloc"]

blake2/src/macros.rs

Lines changed: 43 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -500,17 +500,16 @@ macro_rules! blake2x_impl {
500500
impl $core_name {
501501
/// Create new core with specified output length.
502502
pub fn new(xof_len: $xof_len_type) -> Self {
503-
// Root hasher construction is delegated to new_blake2x_root_hasher for deduplication and correctness.
504-
$core_name {
505-
root_hasher: Self::new_blake2x_root_hasher(xof_len),
503+
Self {
504+
root_hasher: Self::new_root_hasher(xof_len),
506505
xof_len,
507506
}
508507
}
509508

510509
/// Create new core with specified output length and a key.
511510
pub fn new_with_key(key: &[u8], xof_len: $xof_len_type) -> Self {
512-
$core_name {
513-
root_hasher: Self::new_blake2x_root_hasher_with_key(key, xof_len),
511+
Self {
512+
root_hasher: Self::new_keyed_root_hasher(key, xof_len),
514513
xof_len,
515514
}
516515
}
@@ -520,49 +519,38 @@ macro_rules! blake2x_impl {
520519
/// The Blake2X specification requires the total output length (xof_len) to be
521520
/// incorporated into the parameter block of the root hash computation. This ensures
522521
/// that Blake2X(M, L1) and Blake2X(M, L2) produce different outputs when L1 ≠ L2.
523-
///
524-
/// This helper function encapsulates the word-size specific logic for both
525-
/// Blake2b (64-bit) and Blake2s (32-bit) variants.
526-
fn xof_parameter_adjustment(hasher: &mut $base_core, xof_len: $xof_len_type) {
522+
fn apply_xof_param(hasher: &mut $base_core, xof_len: $xof_len_type) {
527523
let xof_param_vec = if core::mem::size_of::<$word>() == 8 {
528524
// Blake2b: xof_length is a u32 in the high 32-bits of parameter word p[1]
529525
let xof_param_val = ((xof_len as u64) << 32) as $word;
530-
$vec::new(0 as $word, xof_param_val, 0 as $word, 0 as $word)
531-
526+
$vec::new(0, xof_param_val, 0, 0)
532527
} else {
533-
// Blake2s: xof_digest_length is a u32 in parameter word p[3].
534-
// We start with a standard Blake2s parameter block and then
535-
// XOR in the xof_len to modify the h state corresponding to p[3].
536-
let xof_param_val = xof_len as $word;
537-
// The parameter p[3] is the 4th element of the first SIMD vector.
538-
$vec::new(0, 0, 0, xof_param_val)
528+
// Blake2s: xof_digest_length is a u32 in parameter word p[3]
529+
$vec::new(0, 0, 0, xof_len as $word)
539530
};
540531
hasher.h[0] = hasher.h[0] ^ xof_param_vec;
541532
#[cfg(feature = "reset")]
542533
{ hasher.h0[0] = hasher.h0[0] ^ xof_param_vec; }
543534
}
544535

545536
/// Create Blake2 hasher specifically for Blake2X root hash computation.
546-
fn new_blake2x_root_hasher(xof_len: $xof_len_type) -> $base_core {
537+
fn new_root_hasher(xof_len: $xof_len_type) -> $base_core {
547538
let mut hasher = <$base_core>::new_with_params(&[], &[], 0, $hash_size);
548-
Self::xof_parameter_adjustment(&mut hasher, xof_len);
539+
Self::apply_xof_param(&mut hasher, xof_len);
549540
hasher
550541
}
551542

552543
/// Create Blake2 hasher for a keyed Blake2X root hash.
553-
///
554-
/// This is similar to new_blake2x_root_hasher but includes the key length
555-
/// in the parameter block for proper keyed hashing support.
556-
fn new_blake2x_root_hasher_with_key(key: &[u8], xof_len: $xof_len_type) -> $base_core {
544+
fn new_keyed_root_hasher(key: &[u8], xof_len: $xof_len_type) -> $base_core {
557545
let mut hasher = <$base_core>::new_with_params(&[], &[], key.len(), $hash_size);
558-
Self::xof_parameter_adjustment(&mut hasher, xof_len);
546+
Self::apply_xof_param(&mut hasher, xof_len);
559547
hasher
560548
}
561549
}
562550

563551
impl Default for $core_name {
564552
fn default() -> Self {
565-
Self::new(<$xof_len_type>::MAX) // Unknown size by default
553+
Self::new(<$xof_len_type>::MAX)
566554
}
567555
}
568556

@@ -587,10 +575,8 @@ macro_rules! blake2x_impl {
587575
type ReaderCore = $reader_name;
588576

589577
fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
590-
// Finalize the root hash H0
591578
let mut root_output = Output::<$base_core>::default();
592579
self.root_hasher.finalize_variable_core(buffer, &mut root_output);
593-
594580
$reader_name::new(root_output.into(), self.xof_len)
595581
}
596582
}
@@ -628,10 +614,8 @@ macro_rules! blake2x_impl {
628614
serialized_state: &digest::crypto_common::hazmat::SerializedState<Self>,
629615
) -> Result<Self, digest::crypto_common::hazmat::DeserializeStateError> {
630616
let len_bytes = core::mem::size_of::<$xof_len_type>();
631-
let mut xof_len_bytes = [0u8; 8]; // Max size for either u16 or u32
632-
xof_len_bytes[..len_bytes].copy_from_slice(&serialized_state[..len_bytes]);
633617
let xof_len = <$xof_len_type>::from_le_bytes(
634-
xof_len_bytes[..len_bytes].try_into().unwrap()
618+
serialized_state[..len_bytes].try_into().unwrap()
635619
);
636620
Ok(Self::new(xof_len))
637621
}
@@ -642,7 +626,6 @@ macro_rules! blake2x_impl {
642626
pub struct $reader_name {
643627
root_hash: [u8; $hash_size],
644628
node_offset: u32,
645-
position: usize,
646629
remaining: $xof_len_type,
647630
total_xof_len: $xof_len_type,
648631
}
@@ -652,25 +635,13 @@ macro_rules! blake2x_impl {
652635
Self {
653636
root_hash,
654637
node_offset: 0,
655-
position: 0,
656638
remaining: xof_len,
657639
total_xof_len: xof_len,
658640
}
659641
}
660-
}
661-
662-
impl BlockSizeUser for $reader_name {
663-
type BlockSize = $reader_block_size;
664-
}
665-
666642

667-
impl $reader_name {
668643
/// Build expansion node parameter array for Blake2X.
669-
///
670-
/// Creates a unified parameter word array that encodes the expansion node
671-
/// parameters according to the Blake2X specification. This handles the
672-
/// word-size differences between Blake2b and Blake2s variants.
673-
fn build_expansion_node_params(
644+
fn build_node_params(
674645
node_offset: u32,
675646
output_size: usize,
676647
total_xof_len: $xof_len_type
@@ -679,115 +650,77 @@ macro_rules! blake2x_impl {
679650

680651
if core::mem::size_of::<$word>() == 4 {
681652
// Blake2s (32-bit words)
682-
// p[0]: digest_len | key_len (0) | fanout (0) | depth (0)
683653
p[0] = output_size as $word;
684-
// p[1]: leaf_length (should be hash_size for Blake2Xs per specification)
685654
p[1] = $hash_size as $word;
686-
// p[2]: node_offset (the block counter)
687655
p[2] = node_offset as $word;
688-
// p[3]: xof_len(u16) | node_depth(u8, 0) << 16 | inner_len(u8, hash_size) << 24
689-
let xof_len = total_xof_len as $word;
690-
let node_depth = 0 as $word;
691-
let inner_len = $hash_size as $word;
692-
p[3] = xof_len | (node_depth << 16) | (inner_len << 24);
656+
// xof_len(u16) | node_depth(u8, 0) << 16 | inner_len(u8, hash_size) << 24
657+
p[3] = (total_xof_len as $word) | (($hash_size as $word) << 24);
693658
} else {
694659
// Blake2b (64-bit words)
695-
696-
// p[0]: Contains bytes 0-7 with digest_length, key_length, fanout, depth, leaf_length
697-
let digest_length = output_size as u64;
698-
let key_length = 0u64; // No key for expansion nodes
699-
let fanout = 0u64; // Unlimited fanout
700-
let depth = 0u64; // Unlimited depth
701-
let leaf_length = ($hash_size as u64) << 32;
702-
p[0] = (digest_length | (key_length << 8) | (fanout << 16) | (depth << 24) | leaf_length) as $word;
703-
704-
// p[1]: Contains bytes 8-15 with node_offset (with XOF length in upper 32 bits)
705-
// For Blake2b expansion nodes, we include the XOF length in the upper bits
706-
let node_offset_full = ((total_xof_len as u64) << 32) + (node_offset as u64);
707-
p[1] = node_offset_full as $word;
708-
709-
// p[2]: Contains bytes 16-23 with node_depth, inner_length
710-
let node_depth = 0u64; // Leaf level
711-
let inner_length = ($hash_size as u64) << 8;
712-
p[2] = (node_depth | inner_length) as $word;
713-
714-
// p[3..7]: All zeros (already initialized)
660+
// p[0]: digest_length | key_length(0) << 8 | fanout(0) << 16 | depth(0) << 24 | leaf_length << 32
661+
p[0] = (output_size as u64 | (($hash_size as u64) << 32)) as $word;
662+
// p[1]: node_offset with XOF length in upper 32 bits
663+
p[1] = (((total_xof_len as u64) << 32) | (node_offset as u64)) as $word;
664+
// p[2]: node_depth(0) | inner_length << 8
665+
p[2] = (($hash_size as u64) << 8) as $word;
715666
}
716667

717668
p
718669
}
719670

720671
/// Create hasher with expansion node parameter state.
721-
///
722-
/// Initializes a Blake2 hasher with the given parameter array by XORing
723-
/// the initialization vector with the parameter block.
724672
fn create_hasher_with_params(p: &[$word; 8]) -> $base_core {
725-
// Initialize state h = IV ^ p
726-
let h = [
673+
let mut node = <$base_core>::new_with_params(&[], &[], 0, $hash_size);
674+
node.h = [
727675
$vec::new($IV[0], $IV[1], $IV[2], $IV[3]) ^ $vec::new(p[0], p[1], p[2], p[3]),
728676
$vec::new($IV[4], $IV[5], $IV[6], $IV[7]) ^ $vec::new(p[4], p[5], p[6], p[7]),
729677
];
730-
731-
// Create hasher with expansion node parameters
732-
let mut node = <$base_core>::new_with_params(&[], &[], 0, $hash_size);
733-
node.h = h;
734678
#[cfg(feature = "reset")]
735-
{ node.h0 = h; }
736-
679+
{ node.h0 = node.h; }
737680
node
738681
}
739682

740683
/// Blake2X expansion node function.
741-
///
742-
/// Implements B2(node_offset, output_size, H0) from the Blake2X specification.
743-
/// Each expansion node computes Blake2(H0) with specific tree parameters that
744-
/// encode the node offset and output size.
745-
fn expand_node(h0: &[u8; $hash_size], node_offset: u32, output_size: usize, total_xof_len: $xof_len_type) -> [u8; $hash_size] {
746-
// Build expansion node parameter array
747-
let p = Self::build_expansion_node_params(node_offset, output_size, total_xof_len);
748-
749-
// Create the node hasher with the parameter state
684+
fn expand_node(
685+
&self,
686+
node_offset: u32,
687+
output_size: usize
688+
) -> [u8; $hash_size] {
689+
let p = Self::build_node_params(node_offset, output_size, self.total_xof_len);
750690
let mut node_hasher = Self::create_hasher_with_params(&p);
751691

752-
// The hashing logic is now unified for both Blake2b and Blake2s
692+
// Hash the root hash as a single block
753693
let mut buffer = LazyBuffer::default();
754-
buffer.digest_blocks(h0, |blocks| {
694+
buffer.digest_blocks(&self.root_hash, |blocks| {
755695
node_hasher.update_blocks(blocks);
756696
});
757697

758-
// Finalize and return
759-
let mut output = [0u8; $hash_size];
760698
let mut var_output = Output::<$base_core>::default();
761699
node_hasher.finalize_variable_core(&mut buffer, &mut var_output);
700+
701+
let mut output = [0u8; $hash_size];
762702
output[..output_size].copy_from_slice(&var_output[..output_size]);
763703
output
764704
}
765705
}
766706

707+
impl BlockSizeUser for $reader_name {
708+
type BlockSize = $reader_block_size;
709+
}
710+
767711
impl XofReaderCore for $reader_name {
768712
fn read_block(&mut self) -> Block<Self> {
769713
let mut block = Block::<Self>::default();
770714

771715
if self.remaining == 0 {
772-
return block; // Return zeros if no more output needed
716+
return block;
773717
}
774718

775-
// Determine output size for this block
776-
let output_size = if self.remaining >= $hash_size as $xof_len_type {
777-
$hash_size
778-
} else {
779-
self.remaining as usize
780-
};
781-
782-
// Blake2x expansion: Hash H0 with specific tree parameters for this node
783-
let node_output = Self::expand_node(&self.root_hash, self.node_offset, output_size, self.total_xof_len);
784-
785-
// Copy output to block
719+
let output_size = core::cmp::min(self.remaining as usize, $hash_size);
720+
let node_output = self.expand_node(self.node_offset, output_size);
786721
block[..output_size].copy_from_slice(&node_output[..output_size]);
787722

788-
// Update state
789723
self.node_offset += 1;
790-
self.position += output_size;
791724
self.remaining -= output_size as $xof_len_type;
792725

793726
block
@@ -800,7 +733,6 @@ macro_rules! blake2x_impl {
800733
}
801734
}
802735

803-
804736
// Use buffer_xof macro to create the wrapper types
805737
digest::buffer_xof!(
806738
#[doc=$vardoc]

0 commit comments

Comments
 (0)