Skip to content

Commit de527e4

Browse files
committed
Address Chris' comments
* Use debug_assert instead of assert in tlog library * Improve documentation and variable naming for stored hash index * Add link to spec for subtree definition
1 parent 74584ee commit de527e4

2 files changed

Lines changed: 26 additions & 21 deletions

File tree

crates/generic_log_worker/src/log_ops.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,21 +1186,21 @@ pub async fn read_leaf<L: LogEntry>(
11861186
tree_size: u64,
11871187
tree_hash: &Hash,
11881188
) -> Result<L, anyhow::Error> {
1189-
let leaf_shx = tlog_tiles::stored_hash_index(0, leaf_index);
1190-
let tile_reader = tile_reader_for_indexes(tree_size, &[leaf_shx], object).await?;
1189+
let leaf_stored_hash_index = tlog_tiles::stored_hash_index(0, leaf_index);
1190+
let tile_reader = tile_reader_for_indexes(tree_size, &[leaf_stored_hash_index], object).await?;
11911191

11921192
// Verify the leaf tile against the tree hash.
11931193
let hash_reader = TileHashReader::new(tree_size, *tree_hash, &tile_reader);
11941194
let hashes = hash_reader
1195-
.read_hashes(&[leaf_shx])
1195+
.read_hashes(&[leaf_stored_hash_index])
11961196
.map_err(|e| anyhow!(e))?;
11971197
let leaf_hash = hashes.first().ok_or(anyhow!("too many hashes read"))?;
11981198

11991199
// Get the level-0 tile. There will be two level-0 tiles in the reader, so get the one matching the requested hash.
12001200
let Some((level0_tile, level0_tile_bytes)) = tile_reader.0.into_iter().find(|(tile, b)| {
12011201
tile.level() == 0
12021202
&& tile
1203-
.hash_at_index(b, leaf_shx)
1203+
.hash_at_index(b, leaf_stored_hash_index)
12041204
.is_ok_and(|h| h == *leaf_hash)
12051205
}) else {
12061206
bail!("failed to get level-0 tile");

crates/tlog_tiles/src/tlog.rs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,14 @@ pub fn node_hash(left: Hash, right: Hash) -> Hash {
168168
Hash(result.into())
169169
}
170170

171-
/// Maps the tree coordinates `(level, n)` to a dense linear ordering that can be used for hash
172-
/// storage. Hash storage implementations that store hashes in sequential storage can use this
173-
/// function to compute where to read or write a given hash.
171+
/// Maps the tree coordinates `(level, n)` to a dense linear ordering that can
172+
/// be used for hash storage. Hash storage implementations that store hashes in
173+
/// sequential storage can use this function to compute where to read or write a
174+
/// given hash.
174175
///
175-
/// For information about the stored hash index ordering, see section 3.3 of Crosby and Wallach's
176-
/// paper ["Efficient Data Structures for Tamper-Evident
176+
/// The stored hash index ordering is given by post-order (leaf, right, root)
177+
/// traversal of the nodes in the tree. For information, see section 3.3 of
178+
/// Crosby and Wallach's paper ["Efficient Data Structures for Tamper-Evident
177179
/// Logging"](https://www.usenix.org/legacy/event/sec09/tech/full_papers/crosby.pdf).
178180
pub fn stored_hash_index(level: u8, n: u64) -> u64 {
179181
// Level L's n'th hash is written right after level L+1's 2n+1'th hash.
@@ -206,7 +208,7 @@ pub fn split_stored_hash_index(index: u64) -> (u8, u64) {
206208
// so the n we want is in [index/2, index/2+log₂(index)].
207209
let mut n = index / 2;
208210
let mut index_n = stored_hash_index(0, n);
209-
assert!(index_n <= index, "bad math");
211+
debug_assert!(index_n <= index, "bad math");
210212
loop {
211213
// Each new record n adds 1 + trailingZeros(n) hashes.
212214
let x = index_n + 1 + u64::from((n + 1).trailing_zeros());
@@ -282,7 +284,7 @@ pub fn stored_hashes_for_record_hash<R: HashReader>(
282284

283285
// Fetch hashes.
284286
let old = r.read_hashes(&indexes)?;
285-
assert_eq!(old.len(), indexes.len(), "bad read_hashes implementation");
287+
debug_assert_eq!(old.len(), indexes.len(), "bad read_hashes implementation");
286288

287289
// Build new hashes.
288290
let mut h = h;
@@ -366,13 +368,13 @@ pub fn subtree_hash_indexes(n: &Subtree) -> Vec<u64> {
366368
pub fn subtree_hash<R: HashReader>(n: &Subtree, r: &R) -> Result<Hash, TlogError> {
367369
let indexes = n.hash_indexes();
368370
let mut hashes = r.read_hashes(&indexes)?;
369-
assert_eq!(
371+
debug_assert_eq!(
370372
hashes.len(),
371373
indexes.len(),
372374
"bad read_hashes implementation"
373375
);
374376
let hash = n.hash(&mut hashes);
375-
assert!(hashes.is_empty(), "bad math in subtree_hash");
377+
debug_assert!(hashes.is_empty(), "bad math in subtree_hash");
376378
Ok(hash)
377379
}
378380

@@ -416,14 +418,14 @@ pub fn subtree_inclusion_proof<R: HashReader>(
416418
return Ok(vec![]);
417419
}
418420
let mut hashes = r.read_hashes(&indexes)?;
419-
assert_eq!(
421+
debug_assert_eq!(
420422
hashes.len(),
421423
indexes.len(),
422424
"bad read_hashes implementation"
423425
);
424426
// SUBTREE_PROOF(start, start + 1, D_n) = PATH(start, D_n)
425427
let proof = n.subproof(m, &mut hashes, true)?;
426-
assert!(
428+
debug_assert!(
427429
hashes.is_empty(),
428430
"bad index math in prove_subtree_inclusion"
429431
);
@@ -574,13 +576,13 @@ pub fn subtree_consistency_proof<R: HashReader>(
574576
return Ok(vec![]);
575577
}
576578
let mut hashes = r.read_hashes(&indexes)?;
577-
assert_eq!(
579+
debug_assert_eq!(
578580
hashes.len(),
579581
indexes.len(),
580582
"bad read_hashes implementation"
581583
);
582584
let proof = n.subproof(m, &mut hashes, true)?;
583-
assert!(
585+
debug_assert!(
584586
hashes.is_empty(),
585587
"bad index math in subtree_consistency_proof"
586588
);
@@ -759,9 +761,12 @@ fn lsb_set(i: u64) -> bool {
759761
(i & 1) == 1
760762
}
761763

762-
/// A subtree of a Merkle Tree of size `n` is defined by two integers `lo` and `hi` such that:
764+
/// A subtree of a Merkle Tree of size `n` is defined by two integers `lo` and
765+
/// `hi` such that:
763766
/// - 0 ≤ lo < hi ≤ n
764767
/// - if `s` is the smallest power of two `≥ hi - lo`, `lo` is a multple of `s`
768+
///
769+
/// <https://www.ietf.org/archive/id/draft-davidben-tls-merkle-tree-certs-06.html#section-4.1>
765770
#[derive(Debug, PartialEq, Eq)]
766771
pub struct Subtree {
767772
lo: u64,
@@ -878,7 +883,7 @@ impl Subtree {
878883
let mut lo = self.lo;
879884
while lo < self.hi {
880885
let (k, level) = maxpow2(self.hi - lo + 1);
881-
assert!(lo & (k - 1) == 0 && lo < self.hi, "bad math in walk_hash");
886+
debug_assert!(lo & (k - 1) == 0 && lo < self.hi, "bad math in walk_hash");
882887
f(level, lo);
883888
lo += k;
884889
}
@@ -914,7 +919,7 @@ impl Subtree {
914919
};
915920
self.walk_hash(&mut get_hash);
916921

917-
assert!(
922+
debug_assert!(
918923
hashes.len() >= num_hashes,
919924
"not enough hashes for reconstruction"
920925
);
@@ -997,7 +1002,7 @@ impl Subtree {
9971002
// `known` set to false as the right child of `m` was not one of
9981003
// the inputs to the algorithm.
9991004
let (m_left, m_right) = m.children();
1000-
assert!(m_left == left, "expected left children to match");
1005+
debug_assert!(m_left == left, "expected left children to match");
10011006
right.walk_subproof(&m_right, false, f, strategy)?
10021007
};
10031008

0 commit comments

Comments
 (0)