fsverity_merkle/
builder.rs
1use crate::{FsVerityHasher, MerkleTree};
6use std::cmp::min;
7
8#[derive(Clone, Debug)]
26pub struct MerkleTreeBuilder {
27 block: Vec<u8>,
30 levels: Vec<Vec<Vec<u8>>>,
31 hasher: FsVerityHasher,
32}
33
34impl MerkleTreeBuilder {
35 pub fn new(hasher: FsVerityHasher) -> Self {
37 MerkleTreeBuilder {
38 block: Vec::with_capacity(hasher.block_size().into()),
39 levels: vec![Vec::new()],
40 hasher,
41 }
42 }
43
44 pub fn write(&mut self, buf: &[u8]) {
48 let block_size = self.hasher.block_size();
49 let buf = if self.block.is_empty() {
51 buf
52 } else {
53 let left = block_size - self.block.len();
54 let prefix = min(buf.len(), left.into());
55 let (buf, rest) = buf.split_at(prefix);
56 self.block.extend_from_slice(buf);
57 if self.block.len() == block_size {
58 self.push_data_hash(self.hasher.hash_block(&self.block[..]));
59 }
60 rest
61 };
62
63 for block in buf.chunks(block_size) {
65 if block.len() == block_size {
66 self.push_data_hash(self.hasher.hash_block(block));
67 } else {
68 self.block.extend_from_slice(block);
69 }
70 }
71 }
72
73 pub fn push_data_hash(&mut self, hash: Vec<u8>) {
76 let hashes_per_block = self.hasher.block_size() / self.hasher.hash_size();
77 self.block.clear();
78 self.levels[0].push(hash);
79 if self.levels[0].len() % hashes_per_block == 0 {
80 self.commit_tail_block(0);
81 }
82 }
83
84 fn commit_tail_block(&mut self, level: usize) {
86 let hashes_per_block = self.hasher.block_size() / self.hasher.hash_size();
87
88 let len = self.levels[level].len();
89 let next_level = level + 1;
90
91 if next_level >= self.levels.len() {
92 self.levels.push(Vec::new());
93 }
94
95 let first_hash = if len % hashes_per_block == 0 {
96 len - hashes_per_block
97 } else {
98 if !self.hasher.fsverity() {
99 for _ in 0..(hashes_per_block - (len % hashes_per_block)) {
100 self.levels[level].push(self.hasher.hash_block(&[]))
101 }
102 }
103 len - (len % hashes_per_block)
104 };
105
106 let hash = self.hasher.hash_hashes(&self.levels[level][first_hash..]);
107
108 self.levels[next_level].push(hash);
109 if self.levels[next_level].len() % hashes_per_block == 0 {
110 self.commit_tail_block(next_level);
111 }
112 }
113
114 pub fn finish(mut self) -> MerkleTree {
117 let hashes_per_block = self.hasher.block_size() / self.hasher.hash_size();
118
119 if !self.block.is_empty() || self.levels[0].is_empty() {
123 self.push_data_hash(self.hasher.hash_block(&self.block[..]));
124 }
125
126 for level in 0.. {
129 if level >= self.levels.len() {
130 break;
131 }
132
133 let len = self.levels[level].len();
134 if len > 1 && len % hashes_per_block != 0 {
135 self.commit_tail_block(level);
136 }
137 }
138
139 MerkleTree::from_levels(self.levels)
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::FsVerityHasherOptions;
147 use hex::FromHex;
148 use test_case::test_case;
149
150 #[allow(clippy::unused_unit)]
154 #[test_case(vec![], "0000000000000000000000000000000000000000000000000000000000000000" ; "test_empty")]
155 #[test_case(vec![0xFF; 8192], "e95eba0e6902ce10c80029e06051080479c696c21b63c3fffa4d7a01aa15e8cb" ; "test_oneblock")]
156 #[test_case(vec![0xFF; 65536], "b4d0d21943e744d999df91cf5efe432744f41d1763a04a75ef6559e04a143857"; "test_small")]
157 #[test_case(vec![0xFF; 2105344], "b4050a226383d94c09c004d59a81b08bed17726b79cf9bd0994931f13213652d"; "test_large")]
158 #[test_case(vec![0xFF; 2109440], "1a07efa041afdf78b86df2c580ec6f8446eb6e802321252996563c14334a5342"; "test_unaligned")]
159 fn sha256_tests_no_salt(input: Vec<u8>, output: &str) {
160 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha256(
161 FsVerityHasherOptions::new(vec![], 4096),
162 ));
163 builder.write(input.as_slice());
164 let tree = builder.finish();
165 let expected: [u8; 32] = FromHex::from_hex(output).unwrap();
166 assert_eq!(expected, tree.root());
167 }
168
169 #[test_case(vec![], "0000000000000000000000000000000000000000000000000000000000000000" ; "test_empty")]
173 #[test_case(vec![0xFF; 8192], "e9c09b505561b9509f93b5c7990ed41427f708480c56306453d505e94076d600" ; "test_oneblock")]
174 #[test_case(vec![0xFF; 65536], "ec6b4dc183833a5665b8d804c6e900f2543b54914f153e4139cb77b261f59615"; "test_small")]
175 #[test_case(vec![0xFF; 2105344], "b433c8b632c79ca9fc2c04913541aa38970ae9da04a43269f67770221e79fe37"; "test_large")]
176 #[test_case(vec![0xFF; 2109440], "fbd261c306f522aba5ac0c70229870594d236634f5afe68fe9656ea04eb4a4fe"; "test_unaligned")]
177 fn sha256_tests_with_salt(input: Vec<u8>, output: &str) {
178 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha256(
179 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
180 ));
181 builder.write(input.as_slice());
182 let tree = builder.finish();
183 let expected: [u8; 32] = FromHex::from_hex(output).unwrap();
184 assert_eq!(expected, tree.root());
185 }
186
187 #[test_case(vec![], "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ; "test_empty")]
191 #[test_case(vec![0xFF; 8192], "9606a93b78555a72b49e583fca582bc5b0411decd879286378d86b5f42190f33b560071063622b3d8e0abc9118e3838dbe77301870743ffc80bd0c910ab3522e" ; "test_oneblock")]
192 #[test_case(vec![0xFF; 65536], "524238523bf3c88f78fba612223d322b3c4290a9ecbd9c61aeb8f1c293b0740083a61a0b2e344b8dc6020ece806ea1d048885db1e77ee9fbaa63c3589f6e403b"; "test_small")]
193 #[test_case(vec![0xFF; 2105344], "51977ac06edd17d32761e27d384f6c437ead6922f0a3fbabc3390d8f6e929bc1d9ff9e4ee34fb060484e8eff272f9cc36fa1cf26361c3258b5d8b87d8144b497"; "test_large")]
194 #[test_case(vec![0xFF; 2109440], "f6e821f7cdd1306031080ff99c4c2d7270c6d6bbaa07f4e3040a5d20a1178af1e4f6377f898166d5835ec22b2fcca6d364711cf0c20862d40f3580b6b6276683"; "test_unaligned")]
195 fn sha512_tests_no_salt(input: Vec<u8>, output: &str) {
196 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha512(
197 FsVerityHasherOptions::new(vec![], 4096),
198 ));
199 builder.write(input.as_slice());
200 let tree = builder.finish();
201 let expected: [u8; 64] = FromHex::from_hex(output).unwrap();
202 assert_eq!(expected, tree.root());
203 }
204
205 #[test_case(vec![], "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ; "test_empty")]
209 #[test_case(vec![0xFF; 8192], "22750472f522bf68a1fe2a66ee1ac57759b322c634d931097b3751e3cd9fe9dd2d8f551631922bf8f675e4b5e3a38e6db11c7df0e5053e80ffbac2c2d7a0105b" ; "test_oneblock")]
210 #[test_case(vec![0xFF; 65536], "4f6a2e16dabf6347b9ae88d5c298befcff0cc71abe1905fa6aefcee14fa5acb89ecbf949daef002d11a9dbb51f211f0eb3e2f7f5e2911b0af2e9fb68c7799a94"; "test_small")]
211 #[test_case(vec![0xFF; 2105344], "a92ddf722dfcf679a64b6364de7f823850f8f856e0ba2c53d66f75cf72d5572bf1d525b3c185e5c39818e2d29997d259f81363daab80a902f86291a71514f891"; "test_large")]
212 #[test_case(vec![0xFF; 2109440], "b6913e8c1d3bb84b467e24667aedad0491ad86f548e849741969688b2526919a380946bebf481ec1ee1bdda86631e10c4a82e7329afdd84db2ac43994a524785"; "test_unaligned")]
213 fn sha512_tests_with_salt(input: Vec<u8>, output: &str) {
214 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha512(
215 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
216 ));
217 builder.write(input.as_slice());
218 let tree = builder.finish();
219 let expected: [u8; 64] = FromHex::from_hex(output).unwrap();
220 assert_eq!(expected, tree.root());
221 }
222
223 #[test]
224 fn test_unaligned_single_block_sha256() {
225 let data = vec![0xFF; 8192];
226 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha256(
227 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
228 ));
229 let (first, second) = &data[..].split_at(1024);
230 builder.write(first);
231 builder.write(second);
232 let tree = builder.finish();
233 let expected: [u8; 32] =
234 FromHex::from_hex("e9c09b505561b9509f93b5c7990ed41427f708480c56306453d505e94076d600")
235 .unwrap();
236 assert_eq!(tree.root(), expected);
237 }
238
239 #[test]
240 fn test_unaligned_single_block_sha512() {
241 let data = vec![0xFF; 8192];
242 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha512(
243 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
244 ));
245 let (first, second) = &data[..].split_at(1024);
246 builder.write(first);
247 builder.write(second);
248 let tree = builder.finish();
249 let expected: [u8; 64] = FromHex::from_hex("22750472f522bf68a1fe2a66ee1ac57759b322c634d931097b3751e3cd9fe9dd2d8f551631922bf8f675e4b5e3a38e6db11c7df0e5053e80ffbac2c2d7a0105b").unwrap();
250 assert_eq!(tree.root(), expected);
251 }
252
253 #[test]
254 fn test_unaligned_n_block_sha256() {
255 let data = vec![0xFF; 65536];
256 let expected: [u8; 32] =
257 FromHex::from_hex("ec6b4dc183833a5665b8d804c6e900f2543b54914f153e4139cb77b261f59615")
258 .unwrap();
259
260 for chunk_size in &[1, 100, 1024, 8193] {
261 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha256(
262 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
263 ));
264 for block in data.as_slice().chunks(*chunk_size) {
265 builder.write(block);
266 }
267 let tree = builder.finish();
268
269 assert_eq!(tree.root(), expected);
270 }
271 }
272
273 #[test]
274 fn test_unaligned_n_block_sha512() {
275 let data = vec![0xFF; 65536];
276 let expected: [u8; 64] = FromHex::from_hex("4f6a2e16dabf6347b9ae88d5c298befcff0cc71abe1905fa6aefcee14fa5acb89ecbf949daef002d11a9dbb51f211f0eb3e2f7f5e2911b0af2e9fb68c7799a94").unwrap();
277
278 for chunk_size in &[1, 100, 1024, 8193] {
279 let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha512(
280 FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
281 ));
282 for block in data.as_slice().chunks(*chunk_size) {
283 builder.write(block);
284 }
285 let tree = builder.finish();
286
287 assert_eq!(tree.root(), expected);
288 }
289 }
290}