Skip to content

Commit a9f0d7b

Browse files
committed
Use enum for data path element following @cjpatton's suggestion
1 parent 4a6a695 commit a9f0d7b

File tree

5 files changed

+86
-65
lines changed

5 files changed

+86
-65
lines changed

crates/ct_worker/src/ctlog.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,12 @@ use std::{
3838
};
3939
use std::{collections::HashMap, fmt::Write};
4040
use thiserror::Error;
41-
use tlog_tiles::{Error as TlogError, Hash, HashReader, Tile, TlogTile, HASH_SIZE};
41+
use tlog_tiles::{Hash, HashReader, PathElem, Tile, TlogError, TlogTile, HASH_SIZE};
4242
use tokio::sync::watch::{self, Receiver, Sender};
4343

4444
/// The maximum tile level is 63 (<c2sp.org/static-ct-api>), so safe to use [`u8::MAX`] as
4545
/// the special level for data tiles. The Go implementation uses -1.
4646
const DATA_TILE_KEY: u8 = u8::MAX;
47-
const DATA_PATH: &str = "data";
4847
const CHECKPOINT_KEY: &str = "checkpoint";
4948

5049
/// Configuration for a CT log.
@@ -235,7 +234,7 @@ impl SequenceState {
235234
.get(&0)
236235
.ok_or(anyhow!("no level 0 tile found"))?
237236
.clone();
238-
data_tile.tile.set_data_with_path(DATA_PATH);
237+
data_tile.tile.set_data_with_path(PathElem::Data);
239238
data_tile.b = object
240239
.fetch(&data_tile.tile.path())
241240
.await?
@@ -719,7 +718,7 @@ fn stage_data_tile(
719718
data_tile: &[u8],
720719
) {
721720
let mut tile = TlogTile::from_index(tlog_tiles::stored_hash_index(0, n - 1));
722-
tile.set_data_with_path(DATA_PATH);
721+
tile.set_data_with_path(PathElem::Data);
723722
edge_tiles.insert(
724723
DATA_TILE_KEY,
725724
TileWithBytes {
@@ -1946,13 +1945,13 @@ mod tests {
19461945
let leaf_hashes = read_tile_hashes(&self.object, c.size(), c.hash(), &indexes).unwrap();
19471946

19481947
let mut last_tile = TlogTile::from_index(tlog_tiles::stored_hash_count(c.size() - 1));
1949-
last_tile.set_data_with_path(DATA_PATH);
1948+
last_tile.set_data_with_path(PathElem::Data);
19501949

19511950
for n in 0..last_tile.level_index() {
19521951
let tile = if n == last_tile.level_index() {
19531952
last_tile
19541953
} else {
1955-
TlogTile::new(0, n, TlogTile::FULL_WIDTH, Some(DATA_PATH))
1954+
TlogTile::new(0, n, TlogTile::FULL_WIDTH, Some(PathElem::Data))
19561955
};
19571956
for (i, entry) in TileIterator::new(
19581957
block_on(self.object.fetch(&tile.path())).unwrap().unwrap(),

crates/static_ct_api/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub use static_ct::*;
1010
#[derive(thiserror::Error, Debug)]
1111
pub enum StaticCTError {
1212
#[error(transparent)]
13-
Tlog(#[from] tlog_tiles::Error),
13+
Tlog(#[from] tlog_tiles::TlogError),
1414
#[error(transparent)]
1515
Signature(#[from] signature::Error),
1616
#[error(transparent)]

crates/tlog_tiles/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ mod tests {
9292
}
9393

9494
#[test]
95-
fn test_certificate_transparency() -> Result<(), Error> {
95+
fn test_certificate_transparency() -> Result<(), TlogError> {
9696
let root: CtTree = http_get("http://ct.googleapis.com/logs/argon2020/ct/v1/get-sth");
9797

9898
let leaf: CtEntries = http_get(

crates/tlog_tiles/src/tile.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
//! - [tile_test.go](https://cs.opensource.google/go/x/mod/+/refs/tags/v0.21.0:sumdb/tlog/tile_test.go)
1717
1818
use crate::tlog::{
19-
node_hash, split_stored_hash_index, stored_hash_index, sub_tree_index, Error, Hash, HashReader,
20-
HASH_SIZE,
19+
node_hash, split_stored_hash_index, stored_hash_index, sub_tree_index, Hash, HashReader,
20+
TlogError, HASH_SIZE,
2121
};
2222
use std::collections::HashMap;
23+
use std::fmt;
2324
use std::str::FromStr;
2425

2526
// To limit the size of any particular directory listing, we encode the (possibly very large)
@@ -49,11 +50,32 @@ const PATH_BASE: u64 = 1000;
4950
/// <https://research.swtch.com/tlog#tiling_a_log>.
5051
#[derive(Debug, Eq, Hash, PartialEq, Default, Clone, Copy)]
5152
pub struct Tile {
52-
h: u8, // height of tile (1 ≤ H ≤ 30)
53-
l: u8, // level in tiling (0 ≤ L ≤ 63)
54-
n: u64, // number within level (0 ≤ N, unbounded)
55-
w: u32, // width of tile (1 ≤ W ≤ 2**H; 2**H is complete tile)
56-
data_path_opt: Option<&'static str>, // whether or not this is a data tile, and the data path element to use for encoding
53+
h: u8, // height of tile (1 ≤ H ≤ 30)
54+
l: u8, // level in tiling (0 ≤ L ≤ 63)
55+
n: u64, // number within level (0 ≤ N, unbounded)
56+
w: u32, // width of tile (1 ≤ W ≤ 2**H; 2**H is complete tile)
57+
data_path_opt: Option<PathElem>, // whether or not this is a data tile, and the data path element to use for encoding
58+
}
59+
60+
#[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)]
61+
pub enum PathElem {
62+
Data,
63+
Entries,
64+
Custom(&'static str),
65+
}
66+
67+
impl fmt::Display for PathElem {
68+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69+
write!(
70+
f,
71+
"{}",
72+
match self {
73+
Self::Data => "data",
74+
Self::Entries => "entries",
75+
Self::Custom(p) => p,
76+
}
77+
)
78+
}
5779
}
5880

5981
impl Tile {
@@ -62,7 +84,7 @@ impl Tile {
6284
/// # Panics
6385
///
6486
/// Panics if any of the tile parameters are outside the valid ranges.
65-
pub fn new(h: u8, l: u8, n: u64, w: u32, data_path_opt: Option<&'static str>) -> Self {
87+
pub fn new(h: u8, l: u8, n: u64, w: u32, data_path_opt: Option<PathElem>) -> Self {
6688
assert!(
6789
(1..=30).contains(&h) && l < 64 && (1..=(1 << h)).contains(&w),
6890
"invalid tile"
@@ -102,9 +124,8 @@ impl Tile {
102124
}
103125

104126
/// Sets `data_path_opt` to convert the tile to a data tile, where `path`
105-
/// determines the path element to use when encoding the tile path
106-
/// (typically "entries" or "data").
107-
pub fn set_data_with_path(&mut self, path: &'static str) {
127+
/// determines the path element to use when encoding the tile path.
128+
pub fn set_data_with_path(&mut self, path: PathElem) {
108129
self.data_path_opt = Some(path);
109130
}
110131

@@ -169,14 +190,14 @@ impl Tile {
169190
///
170191
/// Returns an error if `t` is not `Tile::from_index_internal(t.H,
171192
/// index)` or a wider version, or `data` is not `t`'s tile data (of length at least `t.W*HASH_SIZE`).
172-
pub fn hash_at_index(&self, data: &[u8], index: u64) -> Result<Hash, Error> {
193+
pub fn hash_at_index(&self, data: &[u8], index: u64) -> Result<Hash, TlogError> {
173194
if self.data_path_opt.is_some() || data.len() < self.w as usize * HASH_SIZE {
174-
return Err(Error::InvalidTile);
195+
return Err(TlogError::InvalidTile);
175196
}
176197

177198
let (t1, start, end) = Tile::from_index_internal(self.h, index);
178199
if self.l != t1.l || self.n != t1.n || self.w < t1.w {
179-
return Err(Error::InvalidTile);
200+
return Err(TlogError::InvalidTile);
180201
}
181202

182203
Ok(Tile::subtree_hash(&data[start..end]))
@@ -206,7 +227,7 @@ impl Tile {
206227
&format!(".p/{}", self.w)
207228
};
208229
let l_str = if let Some(elem) = self.data_path_opt {
209-
elem
230+
&elem.to_string()
210231
} else {
211232
&format!("{}", self.l)
212233
};
@@ -259,7 +280,7 @@ impl Tile {
259280

260281
let h = u8::from_str(components[1]).map_err(|_| BadPathError(path.into()))?;
261282
let (l, data_path_opt) = if components[2] == "data" {
262-
(0, Some("data"))
283+
(0, Some(PathElem::Data))
263284
} else {
264285
(
265286
u8::from_str(components[2]).map_err(|_| BadPathError(path.into()))?,
@@ -322,7 +343,7 @@ impl Tile {
322343
/// # Panics
323344
///
324345
/// Panics if `read_hashes` does not return the same number of hashes as passed-in indexes.
325-
pub fn read_data<R: HashReader>(&self, r: &R) -> Result<Vec<u8>, Error> {
346+
pub fn read_data<R: HashReader>(&self, r: &R) -> Result<Vec<u8>, TlogError> {
326347
let mut size = self.w as usize;
327348
if size == 0 {
328349
size = 1 << self.h;
@@ -398,7 +419,7 @@ impl TlogTile {
398419
/// # Panics
399420
///
400421
/// Panics if any of the tile parameters are outside the valid ranges.
401-
pub fn new(l: u8, n: u64, w: u32, data_elem: Option<&'static str>) -> Self {
422+
pub fn new(l: u8, n: u64, w: u32, data_elem: Option<PathElem>) -> Self {
402423
TlogTile(Tile::new(Self::HEIGHT, l, n, w, data_elem))
403424
}
404425

@@ -439,8 +460,8 @@ impl TlogTile {
439460
#[derive(Debug)]
440461
pub struct BadPathError(String);
441462

442-
impl std::fmt::Display for BadPathError {
443-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
463+
impl fmt::Display for BadPathError {
464+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444465
write!(f, "malformed tile path: {}", self.0)
445466
}
446467
}
@@ -465,7 +486,7 @@ pub trait TileReader {
465486
/// # Errors
466487
///
467488
/// Returns an error if unable to read all of the requested tiles.
468-
fn read_tiles(&self, tiles: &[Tile]) -> Result<Vec<Vec<u8>>, Error>;
489+
fn read_tiles(&self, tiles: &[Tile]) -> Result<Vec<Vec<u8>>, TlogError>;
469490

470491
/// Informs the [`TileReader`] that the tile data returned by [`TileReader::read_tiles`] has been
471492
/// confirmed as valid and can be saved in persistent storage (on disk).
@@ -507,7 +528,7 @@ impl HashReader for TileHashReader<'_> {
507528
///
508529
/// Panics if any calls to `Tile::parent` fail to find a parent tile. This differs from the Go
509530
/// implementation which returns an empty Tile{} when it fails to find a parent.
510-
fn read_hashes(&self, indexes: &[u64]) -> Result<Vec<Hash>, Error> {
531+
fn read_hashes(&self, indexes: &[u64]) -> Result<Vec<Hash>, TlogError> {
511532
let h = self.tr.height();
512533

513534
let mut tile_order = HashMap::new(); // tile_order[tileKey(tiles[i])] = i
@@ -536,7 +557,7 @@ impl HashReader for TileHashReader<'_> {
536557
let mut index_tile_order = vec![0; indexes.len()];
537558
for (i, &x) in indexes.iter().enumerate() {
538559
if x >= stored_hash_index(0, self.tree_size) {
539-
return Err(Error::IndexesNotInTree);
560+
return Err(TlogError::IndexesNotInTree);
540561
}
541562

542563
let tile = Tile::from_index(h, x);
@@ -564,7 +585,7 @@ impl HashReader for TileHashReader<'_> {
564585
if p.w != (1 << p.h) {
565586
// Only full tiles have parents.
566587
// This tile has a parent, so it must be full.
567-
return Err(Error::BadMath);
588+
return Err(TlogError::BadMath);
568589
}
569590
tile_order.insert(p, tiles.len());
570591
if k == 0 {
@@ -577,11 +598,11 @@ impl HashReader for TileHashReader<'_> {
577598
// Fetch all the tile data.
578599
let data = self.tr.read_tiles(&tiles)?;
579600
if data.len() != tiles.len() {
580-
return Err(Error::BadMath);
601+
return Err(TlogError::BadMath);
581602
}
582603
for (i, tile) in tiles.iter().enumerate() {
583604
if data[i].len() != tile.w as usize * HASH_SIZE {
584-
return Err(Error::BadMath);
605+
return Err(TlogError::BadMath);
585606
}
586607
}
587608

@@ -595,19 +616,19 @@ impl HashReader for TileHashReader<'_> {
595616
th = node_hash(h, th);
596617
}
597618
if th != self.tree_hash {
598-
return Err(Error::InconsistentTile);
619+
return Err(TlogError::InconsistentTile);
599620
}
600621

601622
// Authenticate full tiles against their parents.
602623
for i in stx.len()..tiles.len() {
603624
let tile = tiles[i];
604625
let p = tile.parent(1, self.tree_size).unwrap();
605626
let Some(j) = tile_order.get(&p) else {
606-
return Err(Error::BadMath);
627+
return Err(TlogError::BadMath);
607628
};
608629
let h = p.hash_at_index(&data[*j], stored_hash_index(p.l * p.h, tile.n))?;
609630
if h != Tile::subtree_hash(&data[i]) {
610-
return Err(Error::InconsistentTile);
631+
return Err(TlogError::InconsistentTile);
611632
}
612633
}
613634

0 commit comments

Comments
 (0)