Skip to content

Commit dcf2a15

Browse files
[storage] Migrate BMT to codec (#1270)
1 parent b9858d2 commit dcf2a15

4 files changed

Lines changed: 35 additions & 48 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

storage/fuzz/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2021"
88
cargo-fuzz = true
99

1010
[dependencies]
11+
commonware-codec = { workspace = true }
1112
commonware-cryptography = { workspace = true }
1213
commonware-runtime = { workspace = true }
1314
commonware-storage = { workspace = true }

storage/fuzz/fuzz_targets/bmt_operations.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![no_main]
22

33
use arbitrary::Arbitrary;
4+
use commonware_codec::{DecodeExt, Encode};
45
use commonware_cryptography::{hash, sha256::Sha256};
56
use commonware_storage::bmt::{Builder, Proof};
67
use libfuzzer_sys::fuzz_target;
@@ -87,12 +88,12 @@ fn fuzz(input: FuzzInput) {
8788

8889
BmtOperation::SerializeProof => {
8990
if let Some(ref p) = proof {
90-
let _serialized = p.serialize();
91+
let _serialized = p.encode();
9192
}
9293
}
9394

9495
BmtOperation::DeserializeProof { data } => {
95-
if Proof::<Sha256>::deserialize(data).is_ok() {}
96+
if Proof::<Sha256>::decode(&mut data.as_slice()).is_ok() {}
9697
}
9798

9899
BmtOperation::BuildEmptyTree => {

storage/src/bmt/mod.rs

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@
4040
//! assert!(proof.verify(&mut hasher, &digests[1], 1, &root).is_ok());
4141
//! ```
4242
43-
use bytes::Buf;
44-
use commonware_codec::{FixedSize, ReadExt};
43+
use bytes::{Buf, BufMut};
44+
use commonware_codec::{EncodeSize, Read, ReadRangeExt, Write};
4545
use commonware_cryptography::Hasher;
4646
use thiserror::Error;
4747

48+
/// There should never be more than 255 siblings in a proof (would mean the Binary Merkle Tree
49+
/// has more than 2^255 leaves).
50+
const MAX_SIBLINGS: usize = u8::MAX as usize;
51+
4852
/// Errors that can occur when working with a Binary Merkle Tree (BMT).
4953
#[derive(Error, Debug)]
5054
pub enum Error {
@@ -247,53 +251,33 @@ impl<H: Hasher> Proof<H> {
247251
Err(Error::InvalidProof(computed.to_string(), root.to_string()))
248252
}
249253
}
254+
}
250255

251-
/// Serializes the proof as the concatenation of each hash.
252-
pub fn serialize(&self) -> Vec<u8> {
253-
// There should never be more than 255 siblings in a proof (would mean the Binary Merkle Tree
254-
// has more than 2^255 leaves).
255-
assert!(
256-
self.siblings.len() <= u8::MAX as usize,
257-
"too many siblings in proof"
258-
);
259-
260-
// Serialize the proof as the concatenation of each hash.
261-
let bytes_len = self.siblings.len() * H::Digest::SIZE;
262-
let mut bytes = Vec::with_capacity(bytes_len);
263-
for hash in &self.siblings {
264-
bytes.extend_from_slice(hash.as_ref());
265-
}
266-
bytes
256+
impl<H: Hasher> Write for Proof<H> {
257+
fn write(&self, writer: &mut impl BufMut) {
258+
self.siblings.write(writer);
267259
}
260+
}
268261

269-
/// Deserializes a proof from its canonical serialized representation.
270-
pub fn deserialize(mut buf: &[u8]) -> Result<Self, Error> {
271-
// It is ok to have an empty proof (just means the provided leaf is the root).
272-
273-
// If the remaining buffer is not a multiple of the hash size, it's invalid.
274-
if buf.remaining() % H::Digest::SIZE != 0 {
275-
return Err(Error::UnalignedProof);
276-
}
277-
278-
// If the number of siblings is too large, it's invalid.
279-
let num_siblings = buf.len() / H::Digest::SIZE;
280-
if num_siblings > u8::MAX as usize {
281-
return Err(Error::TooManySiblings(num_siblings));
282-
}
262+
impl<H: Hasher> Read for Proof<H> {
263+
type Cfg = ();
283264

284-
// Deserialize the siblings
285-
let mut siblings = Vec::with_capacity(num_siblings);
286-
for _ in 0..num_siblings {
287-
let hash = H::Digest::read(&mut buf).map_err(|_| Error::InvalidDigest)?;
288-
siblings.push(hash);
289-
}
265+
fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
266+
let siblings = Vec::<H::Digest>::read_range(reader, ..=MAX_SIBLINGS)?;
290267
Ok(Self { siblings })
291268
}
292269
}
293270

271+
impl<H: Hasher> EncodeSize for Proof<H> {
272+
fn encode_size(&self) -> usize {
273+
self.siblings.encode_size()
274+
}
275+
}
276+
294277
#[cfg(test)]
295278
mod tests {
296279
use super::*;
280+
use commonware_codec::{DecodeExt, Encode};
297281
use commonware_cryptography::{
298282
hash,
299283
sha256::{Digest, Sha256},
@@ -323,8 +307,8 @@ mod tests {
323307
);
324308

325309
// Serialize and deserialize the proof
326-
let serialized = proof.serialize();
327-
let deserialized = Proof::<Sha256>::deserialize(&serialized).unwrap();
310+
let mut serialized = proof.encode();
311+
let deserialized = Proof::<Sha256>::decode(&mut serialized).unwrap();
328312
assert!(
329313
deserialized
330314
.verify(&mut hasher, leaf, i as u32, &root)
@@ -725,11 +709,11 @@ mod tests {
725709

726710
// Generate a valid proof for leaf at index 1.
727711
let proof = tree.proof(1).unwrap();
728-
let mut serialized = proof.serialize();
712+
let mut serialized = proof.encode();
729713

730714
// Truncate one byte.
731-
serialized.pop();
732-
assert!(Proof::<Sha256>::deserialize(&serialized).is_err());
715+
serialized.truncate(serialized.len() - 1);
716+
assert!(Proof::<Sha256>::decode(&mut serialized).is_err());
733717
}
734718

735719
#[test]
@@ -747,11 +731,11 @@ mod tests {
747731

748732
// Generate a valid proof for leaf at index 1.
749733
let proof = tree.proof(1).unwrap();
750-
let mut serialized = proof.serialize();
734+
let mut serialized = proof.encode();
751735

752736
// Append an extra byte.
753-
serialized.push(0u8);
754-
assert!(Proof::<Sha256>::deserialize(&serialized).is_err());
737+
serialized.extend_from_slice(&[0u8]);
738+
assert!(Proof::<Sha256>::decode(&mut serialized).is_err());
755739
}
756740

757741
#[test]

0 commit comments

Comments
 (0)