Skip to main content

fsverity_merkle/
lib.rs

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.
4
5//! `fsverity_merkle` contains types and methods for building and working with fsverity merkle trees.
6
7use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
8
9mod builder;
10pub use crate::builder::MerkleTreeBuilder;
11
12mod tree;
13pub use crate::tree::MerkleTree;
14
15mod util;
16pub use crate::util::{
17    FsVerityDescriptor, FsVerityDescriptorRaw, FsVerityHasher, FsVerityHasherOptions,
18};
19
20mod verifier;
21pub use crate::verifier::MerkleVerifier;
22
23pub const SHA256_SALT_PADDING: u8 = 64;
24pub const SHA512_SALT_PADDING: u8 = 128;
25
26/// A cryptographic hash digest used in a Merkle tree.
27pub trait FsVerityHash:
28    FromBytes
29    + IntoBytes
30    + KnownLayout
31    + Immutable
32    + Clone
33    + Copy
34    + std::fmt::Debug
35    + Send
36    + Sync
37    + PartialEq
38    + Eq
39{
40}
41
42/// SHA-256 verity hash.
43#[repr(transparent)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
45pub struct Sha256Hash([u8; 32]);
46
47impl FsVerityHash for Sha256Hash {}
48
49impl From<[u8; 32]> for Sha256Hash {
50    fn from(bytes: [u8; 32]) -> Self {
51        Self(bytes)
52    }
53}
54
55impl From<Sha256Hash> for [u8; 32] {
56    fn from(hash: Sha256Hash) -> Self {
57        hash.0
58    }
59}
60
61/// SHA-512 verity hash.
62#[repr(transparent)]
63#[derive(Debug, Clone, Copy, PartialEq, Eq, FromBytes, IntoBytes, KnownLayout, Immutable)]
64pub struct Sha512Hash([u8; 64]);
65
66impl FsVerityHash for Sha512Hash {}
67
68impl From<[u8; 64]> for Sha512Hash {
69    fn from(bytes: [u8; 64]) -> Self {
70        Self(bytes)
71    }
72}
73
74impl From<Sha512Hash> for [u8; 64] {
75    fn from(hash: Sha512Hash) -> Self {
76        hash.0
77    }
78}
79
80/// Compute a merkle tree from a `&[u8]` for a particular hasher.
81pub fn from_slice(slice: &[u8], hasher: FsVerityHasher) -> MerkleTree {
82    match hasher {
83        FsVerityHasher::Sha256(_) => from_slice_impl::<Sha256Hash>(slice, hasher),
84        FsVerityHasher::Sha512(_) => from_slice_impl::<Sha512Hash>(slice, hasher),
85    }
86}
87
88fn from_slice_impl<D: FsVerityHash>(slice: &[u8], hasher: FsVerityHasher) -> MerkleTree {
89    let mut builder = MerkleTreeBuilder::<D>::new(hasher);
90    builder.write(slice);
91    builder.finish()
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_from_slice_sha256() {
100        let file = vec![0xFF; 2105344];
101        let hasher = FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096));
102        let expected = MerkleTree::from_data(&file[..], hasher.clone());
103        let actual = from_slice(&file[..], hasher);
104        assert_eq!(expected.root(), actual.root());
105    }
106
107    #[test]
108    fn test_from_slice_sha512() {
109        let file = vec![0xFF; 2105344];
110        let hasher = FsVerityHasher::Sha512(FsVerityHasherOptions::new(vec![0xFF; 8], 4096));
111        let expected = MerkleTree::from_data(&file[..], hasher.clone());
112        let actual = from_slice(&file[..], hasher);
113        assert_eq!(expected.root(), actual.root());
114    }
115}