1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
use std::cmp::{min}; use {Blake2b, Hash, ParameterBlock}; use slice_ext::{SliceExt}; use unbuffered; pub struct Blake2xb { blake2b: Blake2b, parameter_block: ParameterBlock, len: u32, } pub struct Iter { parameter_block: ParameterBlock, block: [u64; 16], block_len: usize, max_out_len: u32, out_len: u32, } impl Blake2xb { pub fn new(len: Option<u32>) -> Self { Self::keyed(len, &[]) } pub fn keyed(len: Option<u32>, key: &[u8]) -> Self { assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2"); let parameter_block = ParameterBlock::new() .set_digest_len(64) .set_key_len(key.len() as u8) .set_fanout(1) .set_max_depth(1) .set_node_offset((len.unwrap_or(u32::max_value()) as u64) << 32); Self::with_parameter_block_keyed(len, key, parameter_block) } pub fn with_parameter_block_keyed(len: Option<u32>, key: &[u8], parameter_block: ParameterBlock) -> Self { assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2"); Blake2xb { blake2b: Blake2b::with_parameter_block_keyed(64, key, parameter_block.clone()), parameter_block: parameter_block, len: len.unwrap_or(u32::max_value()) } } pub fn len(&self) -> usize { self.len as usize } pub fn update(&mut self, data: &[u8]) { self.blake2b.update(data); } pub fn finish(self) -> Iter { let mut block = [0; 16]; block[..8].copy_from_slice(AsRef::<[u64]>::as_ref(&self.blake2b.finish())); let parameter_block = self.parameter_block .set_key_len(0) .set_fanout(0) .set_max_depth(0) .set_max_leaf_len(64) .set_node_depth(0) .set_inner_len(64); Iter { parameter_block: parameter_block, block: block, block_len: 64, max_out_len: self.len, out_len: 0, } } } impl Iter { pub fn new(len: Option<u32>, seed: &[u8]) -> Self { let parameter_block = ParameterBlock::new() .set_max_leaf_len(64) .set_inner_len(64); Self::with_parameter_block(len, seed, parameter_block) } pub fn with_parameter_block(len: Option<u32>, seed: &[u8], parameter_block: ParameterBlock) -> Self { assert!(len.map(|len| len != 0 && len != u32::max_value()).unwrap_or(true), "len must be >= 1 and <= 2^32 - 2"); assert!(seed.len() <= 128, "seed length must be <= 128"); let mut block = [0; 16]; block.as_mut_bytes()[..seed.len()].copy_from_slice(seed); Iter { parameter_block: parameter_block, block: block, block_len: seed.len(), max_out_len: len.unwrap_or(u32::max_value()), out_len: 0 } } pub fn max_out_len(&self) -> usize { self.max_out_len as usize } pub fn out_len(&self) -> usize { self.out_len as usize } } impl Iterator for Iter { type Item = Hash; fn next(&mut self) -> Option<Self::Item> { if self.out_len == self.max_out_len { return None; } let len = min(self.max_out_len - self.out_len, 64); let parameter_block = self.parameter_block.clone() .set_digest_len(len as u8) .set_node_offset((self.out_len as u64 / 64) | ((self.max_out_len as u64) << 32)); self.out_len += len; Some(unbuffered::Blake2b::with_parameter_block(len as usize, parameter_block).finish(&self.block, self.block_len)) } fn size_hint(&self) -> (usize, Option<usize>) { let i = (self.max_out_len - self.out_len) as usize / 64 + if self.max_out_len % 64 != 0 { 1 } else { 0 }; (i, Some(i)) } }