Skip to content

Commit 42d3a25

Browse files
k12: fix incorrect hash calculation (#499)
If the length of the merged input string is a multiple of the chunk size, then the previous implementation appends a chaining value for an empty chunk.
1 parent 342dbfa commit 42d3a25

File tree

2 files changed

+72
-24
lines changed

2 files changed

+72
-24
lines changed

k12/src/lib.rs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@ impl<'cs> KangarooTwelveCore<'cs> {
5252
chain_length: 0usize,
5353
}
5454
}
55+
56+
fn process_chunk(&mut self) {
57+
debug_assert!(self.bufpos == CHUNK_SIZE);
58+
if self.chain_length == 0 {
59+
self.final_tshk.update(&self.buffer);
60+
} else {
61+
self.process_chaining_chunk();
62+
}
63+
64+
self.chain_length += 1;
65+
self.buffer = [0u8; CHUNK_SIZE];
66+
self.bufpos = 0;
67+
}
68+
69+
fn process_chaining_chunk(&mut self) {
70+
debug_assert!(self.bufpos != 0);
71+
if self.chain_length == 1 {
72+
self.final_tshk
73+
.update(&[0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
74+
}
75+
76+
let mut result = [0u8; CHAINING_VALUE_SIZE];
77+
self.chain_tshk.update(&self.buffer[..self.bufpos]);
78+
self.chain_tshk.finalize_xof_reset_into(&mut result);
79+
self.final_tshk.update(&result);
80+
}
5581
}
5682

5783
impl HashMarker for KangarooTwelveCore<'_> {}
@@ -68,27 +94,12 @@ impl UpdateCore for KangarooTwelveCore<'_> {
6894
#[inline]
6995
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
7096
for block in blocks {
71-
self.buffer[self.bufpos..self.bufpos + 128].clone_from_slice(block);
72-
self.bufpos += 128;
73-
74-
if self.bufpos != CHUNK_SIZE {
75-
continue;
76-
}
77-
78-
if self.chain_length == 0 {
79-
self.final_tshk.update(&self.buffer);
80-
self.final_tshk
81-
.update(&[0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
82-
} else {
83-
let mut result = [0u8; CHAINING_VALUE_SIZE];
84-
self.chain_tshk.update(&self.buffer);
85-
self.chain_tshk.finalize_xof_reset_into(&mut result);
86-
self.final_tshk.update(&result);
97+
if self.bufpos == CHUNK_SIZE {
98+
self.process_chunk();
8799
}
88100

89-
self.chain_length += 1;
90-
self.buffer = [0u8; CHUNK_SIZE];
91-
self.bufpos = 0;
101+
self.buffer[self.bufpos..self.bufpos + 128].clone_from_slice(block);
102+
self.bufpos += 128;
92103
}
93104
}
94105
}
@@ -107,24 +118,27 @@ impl ExtendableOutputCore for KangarooTwelveCore<'_> {
107118
|block| self.update_blocks(block),
108119
);
109120

121+
if self.bufpos == CHUNK_SIZE && buffer.get_pos() != 0 {
122+
self.process_chunk();
123+
}
124+
110125
// Read leftover data from buffer
111126
self.buffer[self.bufpos..(self.bufpos + buffer.get_pos())]
112127
.copy_from_slice(buffer.get_data());
113128
self.bufpos += buffer.get_pos();
114129

115130
// Calculate final node
116131
if self.chain_length == 0 {
117-
// Input didnot exceed a single chaining value
132+
// Input did not exceed a single chaining value
118133
let tshk = TurboShake128::from_core(<TurboShake128Core>::new(0x07))
119134
.chain(&self.buffer[..self.bufpos])
120135
.finalize_xof_reset();
121136
return KangarooTwelveReaderCore { tshk };
122137
}
138+
123139
// Calculate last chaining value
124-
let mut result = [0u8; CHAINING_VALUE_SIZE];
125-
self.chain_tshk.update(&self.buffer[..self.bufpos]);
126-
self.chain_tshk.finalize_xof_reset_into(&mut result);
127-
self.final_tshk.update(&result);
140+
self.process_chaining_chunk();
141+
128142
// Pad final node calculation
129143
self.final_tshk
130144
.update(length_encode(self.chain_length, &mut lenbuf));

k12/tests/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,37 @@ fn pat_c() {
7373
assert_eq!(result[..], expected[i as usize][..]);
7474
}
7575
}
76+
77+
#[test]
78+
fn input_multiple_of_chunk_size_minus_one() {
79+
// generated with reference python implementation
80+
let expected = [
81+
hex!("1b577636f723643e990cc7d6a659837436fd6a103626600eb8301cd1dbe553d6"),
82+
hex!("e3ded52118ea64eaf04c7531c6ccb95e32924b7c2b87b2ce68ff2f2ee46e84ef"),
83+
hex!("daacf62e434bdd126fbe9e61fae38d1429e9dddfaf8f999095585c3cbf366a4a"),
84+
hex!("eac3722b4b7db10af973ed7ca60e113a19fab895b46476a9aac51ead099e6ba4"),
85+
];
86+
for i in 0..expected.len() {
87+
let len = 8192 * (i + 1) - 1;
88+
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
89+
let result = digest_and_box(&m, 32);
90+
assert_eq!(result[..], expected[i as usize][..]);
91+
}
92+
}
93+
94+
#[test]
95+
fn input_multiple_of_chunk_size() {
96+
// generated with reference python implementation
97+
let expected = [
98+
hex!("48f256f6772f9edfb6a8b661ec92dc93b95ebd05a08a17b39ae3490870c926c3"),
99+
hex!("82778f7f7234c83352e76837b721fbdbb5270b88010d84fa5ab0b61ec8ce0956"),
100+
hex!("f4082a8fe7d1635aa042cd1da63bf235f91c231886c29896f9fe3818c60cd360"),
101+
hex!("d14f8dc243c206004ca8a996997e5ae16a8bdda288f6c90d20d7c43c1a408618"),
102+
];
103+
for i in 0..expected.len() {
104+
let len = 8192 * (i + 1);
105+
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
106+
let result = digest_and_box(&m, 32);
107+
assert_eq!(result[..], expected[i as usize][..]);
108+
}
109+
}

0 commit comments

Comments
 (0)