diff --git a/garnet/public/rust/fuchsia-merkle/src/lib.rs b/garnet/public/rust/fuchsia-merkle/src/lib.rs
index 3aca6057dbb92e9cfbe143069a45a2180bcd59ce..0696f6463aefd44dad46136b797c89893b752d89 100644
--- a/garnet/public/rust/fuchsia-merkle/src/lib.rs
+++ b/garnet/public/rust/fuchsia-merkle/src/lib.rs
@@ -4,6 +4,8 @@
 
 //! `fuchsia_merkle` contains types and methods for building and working with merkle trees.
 
+#![deny(missing_docs)]
+
 /// The size of a single block of data (or hashes), in bytes.
 pub const BLOCK_SIZE: usize = 8192;
 
diff --git a/garnet/public/rust/fuchsia-merkle/src/tree.rs b/garnet/public/rust/fuchsia-merkle/src/tree.rs
index 71697a3665a7bf4198e4227974354f2060fe2ad1..eef8d4ce8d311f3a6b9baf41846a36b86e8c4100 100644
--- a/garnet/public/rust/fuchsia-merkle/src/tree.rs
+++ b/garnet/public/rust/fuchsia-merkle/src/tree.rs
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 use crate::hash::Hash;
+use crate::BLOCK_SIZE;
+use std::io;
 
 /// A `MerkleTree` contains levels of hashes that can be used to verify the integrity of data.
 ///
@@ -50,6 +52,31 @@ impl MerkleTree {
     pub fn root(&self) -> Hash {
         self.levels[self.levels.len() - 1][0]
     }
+
+    /// Creates a `MerkleTree` from all of the bytes of a `Read`er.
+    ///
+    /// # Examples
+    /// ```
+    /// # use fuchsia_merkle::MerkleTree;
+    /// let data_to_hash = [0xffu8; 8192];
+    /// let tree = MerkleTree::from_reader(&data_to_hash[..]).unwrap();
+    /// assert_eq!(
+    ///     tree.root(),
+    ///     "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737".parse().unwrap()
+    /// );
+    /// ```
+    pub fn from_reader(mut reader: impl std::io::Read) -> Result<MerkleTree, io::Error> {
+        let mut builder = crate::builder::MerkleTreeBuilder::new();
+        let mut buf = [0u8; BLOCK_SIZE];
+        loop {
+            let size = reader.read(&mut buf)?;
+            if size == 0 {
+                break;
+            }
+            builder.write(&buf[0..size]);
+        }
+        Ok(builder.finish())
+    }
 }
 
 #[cfg(test)]
@@ -57,7 +84,6 @@ mod tests {
     use super::*;
     use crate::util::HASHES_PER_BLOCK;
     use crate::util::{hash_block, hash_hashes};
-    use crate::BLOCK_SIZE;
 
     impl MerkleTree {
         /// Given the index of a block of data, lookup its hash.
@@ -84,4 +110,57 @@ mod tests {
             assert_eq!(tree.leaf_hash(i), leafs[i]);
         }
     }
+
+    #[test]
+    fn test_from_reader_empty() {
+        let data_to_hash = [0x00u8; 0];
+        let tree = MerkleTree::from_reader(&data_to_hash[..]).unwrap();
+        let expected: Hash =
+            "15ec7bf0b50732b49f8228e07d24365338f9e3ab994b00af08e5a3bffe55fd8b".parse().unwrap();
+        assert_eq!(tree.root(), expected);
+    }
+
+    #[test]
+    fn test_from_reader_oneblock() {
+        let data_to_hash = [0xffu8; 8192];
+        let tree = MerkleTree::from_reader(&data_to_hash[..]).unwrap();
+        let expected: Hash =
+            "68d131bc271f9c192d4f6dcd8fe61bef90004856da19d0f2f514a7f4098b0737".parse().unwrap();
+        assert_eq!(tree.root(), expected);
+    }
+
+    #[test]
+    fn test_from_reader_unaligned() {
+        let size = 2_109_440usize;
+        let mut the_bytes = Vec::with_capacity(size);
+        the_bytes.extend(std::iter::repeat(0xff).take(size));
+        let tree = MerkleTree::from_reader(&the_bytes[..]).unwrap();
+        let expected: Hash =
+            "7577266aa98ce587922fdc668c186e27f3c742fb1b732737153b70ae46973e43".parse().unwrap();
+        assert_eq!(tree.root(), expected);
+    }
+
+    #[test]
+    fn test_from_reader_error_propagation() {
+        const CUSTOM_ERROR_MESSAGE: &str = "merkle tree custom error message";
+        struct ReaderSuccessThenError {
+            been_called: bool,
+        }
+
+        impl std::io::Read for ReaderSuccessThenError {
+            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+                if !self.been_called {
+                    self.been_called = true;
+                    buf[0] = 0;
+                    Ok(1)
+                } else {
+                    Err(io::Error::new(io::ErrorKind::Other, CUSTOM_ERROR_MESSAGE))
+                }
+            }
+        }
+
+        let reader = ReaderSuccessThenError { been_called: false };
+        let result = MerkleTree::from_reader(reader);
+        assert_eq!(result.unwrap_err().to_string(), CUSTOM_ERROR_MESSAGE);
+    }
 }