1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use crate::util::FsVerityHasher;
6use std::io;
78/// A `MerkleTree` contains levels of hashes that can be used to verify the integrity of data.
9///
10/// While a single hash could be used to integrity check some data, if the data (or hash) is
11/// corrupt, a single hash can not determine what part of the data is corrupt. A `MerkleTree`,
12/// however, contains a hash for every block of data, allowing it to identify which blocks of
13/// data are corrupt. A `MerkleTree` also allows individual blocks of data to be verified without
14/// having to verify the rest of the data.
15///
16/// Furthermore, a `MerkleTree` contains multiple levels of hashes, where each level
17/// contains hashes of blocks of hashes of the lower level. The top level always contains a
18/// single hash, the merkle root. This tree of hashes allows a `MerkleTree` to determine which of
19/// its own hashes are corrupt, if any.
20///
21/// # Structure Details
22///
23/// A merkle tree contains levels. A level is a row of the tree, starting at 0 and counting upward.
24/// Level 0 represents the leaves of the tree which contain hashes of chunks of the input stream.
25/// Each level consists of a hash for each block of hashes from the previous level (or, for
26/// level 0, each block of data).
27///
28///
29/// While building a `MerkleTree`, callers pass in an `FsverityHasher` which hashes based on a
30/// particular algorithm and contains the necessary parameters to compute the merkle tree. The
31/// `block size` is determined by the filesystem and the `salt` by the FsverityMetadata struct
32/// stored in fxfs. When computing a hash, if `salt`.len() > 0, the block of data (or hashes) is
33/// prepended by the `salt`.
34///
35/// For level 0, the length of the block is `block size`, except for the last block, which may be
36/// less than `block size`. All other levels use a block length of `block size`.
37#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
38pub struct MerkleTree {
39 levels: Vec<Vec<Vec<u8>>>,
40}
4142impl MerkleTree {
43/// Creates a `MerkleTree` from a well-formed tree of hashes.
44 ///
45 /// A tree of hashes is well-formed iff:
46 /// - The length of the last level is 1.
47 /// - The length of every hash level is the length of the prior hash level divided by
48 /// hashes_per_block (`block size` \ digest length`), rounded up to the nearest
49 /// integer.
50pub fn from_levels(levels: Vec<Vec<Vec<u8>>>) -> MerkleTree {
51 MerkleTree { levels }
52 }
5354/// The root hash of the merkle tree.
55pub fn root(&self) -> &[u8] {
56&self.levels[self.levels.len() - 1][0]
57 }
5859/// Creates a `MerkleTree` from all of the bytes of a `Read`er.
60 ///
61 /// # Examples
62 /// ```
63 /// # use fsverity_merkle::MerkleTree;
64 /// fsverity_merkle::{MerkleTree, FsVerityHasher, FsVerityHasherOptions},
65 /// let data_to_hash = [0xffu8; 8192];
66 /// let hasher = FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096));
67 /// let tree = MerkleTree::from_reader(&data_to_hash[..], hasher).unwrap();
68 /// assert_eq!(
69 /// tree.root().bytes(),
70 /// FromHex::from_hex("e9c09b505561b9509f93b5c7990ed41427f708480c56306453d505e94076d600")
71 /// .unwrap();
72 /// );
73 /// ```
74pub fn from_reader(
75mut reader: impl std::io::Read,
76 hasher: FsVerityHasher,
77 ) -> Result<MerkleTree, io::Error> {
78let block_size = hasher.block_size() as usize;
79let mut builder = crate::builder::MerkleTreeBuilder::new(hasher);
80let mut buf = vec![0u8; block_size];
81loop {
82let size = reader.read(&mut buf)?;
83if size == 0 {
84break;
85 }
86 builder.write(&buf[0..size]);
87 }
88Ok(builder.finish())
89 }
90}
9192impl AsRef<[Vec<Vec<u8>>]> for MerkleTree {
93fn as_ref(&self) -> &[Vec<Vec<u8>>] {
94&self.levels[..]
95 }
96}
9798#[cfg(test)]
99mod tests {
100use super::*;
101use crate::FsVerityHasherOptions;
102use hex::FromHex;
103104impl MerkleTree {
105/// Given the index of a block of data, lookup its hash.
106fn leaf_hash(&self, block: usize) -> &[u8] {
107&self.levels[0][block]
108 }
109 }
110111#[test]
112fn test_single_full_hash_block_sha256() {
113let hasher = FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096));
114let hashes_per_block = hasher.block_size() / hasher.hash_size();
115let mut leafs = Vec::new();
116let mut expected_leafs = Vec::new();
117 {
118let block = vec![0xFF; hasher.block_size()];
119for _i in 0..hashes_per_block {
120 leafs.push(hasher.hash_block(&block));
121 expected_leafs.push(hasher.hash_block(&block));
122 }
123 }
124let root = hasher.hash_hashes(&leafs);
125let tree: MerkleTree = MerkleTree::from_levels(vec![leafs, vec![root.clone()]]);
126assert_eq!(tree.root(), root);
127for (i, leaf) in expected_leafs.iter().enumerate().take(hashes_per_block) {
128assert_eq!(tree.leaf_hash(i), leaf);
129 }
130 }
131132#[test]
133fn test_single_full_hash_block_sha512() {
134let hasher = FsVerityHasher::Sha512(FsVerityHasherOptions::new(vec![0xFF; 8], 4096));
135let hashes_per_block = hasher.block_size() / hasher.hash_size();
136let mut leafs = Vec::new();
137let mut expected_leafs = Vec::new();
138 {
139let block = vec![0xFF; hasher.block_size()];
140for _i in 0..hashes_per_block {
141 leafs.push(hasher.hash_block(&block));
142 expected_leafs.push(hasher.hash_block(&block));
143 }
144 }
145let root = hasher.hash_hashes(&leafs);
146let tree: MerkleTree = MerkleTree::from_levels(vec![leafs, vec![root.clone()]]);
147assert_eq!(tree.root(), root);
148for (i, leaf) in expected_leafs.iter().enumerate().take(hashes_per_block) {
149assert_eq!(tree.leaf_hash(i), leaf);
150 }
151 }
152153#[test]
154fn test_from_reader_empty_sha256() {
155let data_to_hash = [0x00u8; 0];
156let tree = MerkleTree::from_reader(
157&data_to_hash[..],
158 FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096)),
159 )
160 .unwrap();
161let expected: [u8; 32] =
162 FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
163 .unwrap();
164assert_eq!(tree.root(), expected);
165 }
166167#[test]
168fn test_from_reader_empty_sha512() {
169let data_to_hash = [0x00u8; 0];
170let tree = MerkleTree::from_reader(
171&data_to_hash[..],
172 FsVerityHasher::Sha512(FsVerityHasherOptions::new(vec![0xFF; 8], 4096)),
173 )
174 .unwrap();
175let expected: [u8; 64] = FromHex::from_hex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
176assert_eq!(tree.root(), expected);
177 }
178179#[test]
180fn test_from_reader_oneblock_sha256() {
181let data_to_hash = [0xffu8; 8192];
182let tree = MerkleTree::from_reader(
183&data_to_hash[..],
184 FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096)),
185 )
186 .unwrap();
187let expected: [u8; 32] =
188 FromHex::from_hex("e9c09b505561b9509f93b5c7990ed41427f708480c56306453d505e94076d600")
189 .unwrap();
190assert_eq!(tree.root(), expected);
191 }
192193#[test]
194fn test_from_reader_oneblock_sha512() {
195let data_to_hash = [0xffu8; 8192];
196let tree = MerkleTree::from_reader(
197&data_to_hash[..],
198 FsVerityHasher::Sha512(FsVerityHasherOptions::new(vec![0xFF; 8], 4096)),
199 )
200 .unwrap();
201let expected: [u8; 64] = FromHex::from_hex("22750472f522bf68a1fe2a66ee1ac57759b322c634d931097b3751e3cd9fe9dd2d8f551631922bf8f675e4b5e3a38e6db11c7df0e5053e80ffbac2c2d7a0105b").unwrap();
202assert_eq!(tree.root(), expected);
203 }
204205#[test]
206fn test_from_reader_unaligned_sha256() {
207let size = 2_109_440usize;
208let mut the_bytes = Vec::with_capacity(size);
209 the_bytes.extend(std::iter::repeat(0xff).take(size));
210let tree = MerkleTree::from_reader(
211&the_bytes[..],
212 FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 8192)),
213 )
214 .unwrap();
215let expected: [u8; 32] =
216 FromHex::from_hex("fc21b1fbf53a4175470a7328085b5a03b2c87771cda6f1a4dbd1d1d5ce8babd5")
217 .unwrap();
218assert_eq!(tree.root(), expected);
219 }
220221#[test]
222fn test_from_reader_unaligned_sha512() {
223let size = 2_109_440usize;
224let mut the_bytes = Vec::with_capacity(size);
225 the_bytes.extend(std::iter::repeat(0xff).take(size));
226let tree = MerkleTree::from_reader(
227&the_bytes[..],
228 FsVerityHasher::Sha512(FsVerityHasherOptions::new(vec![0xFF; 8], 8192)),
229 )
230 .unwrap();
231let expected: [u8; 64] = FromHex::from_hex("e0b048b63e814157443f42ccef9093482cee056f6afea5b9e26b772effa5077a8bac34ee8f7a877bf219e0f45a999154b0600a319c4bd7d0c9b59f8d17ce0f75").unwrap();
232assert_eq!(tree.root(), expected);
233 }
234}