Rename authentication_path -> witness

This commit is contained in:
Kris Nuttycombe 2022-07-21 18:17:36 -06:00
parent ee93cb8598
commit 6b6548f02e
3 changed files with 76 additions and 121 deletions

View File

@ -153,9 +153,9 @@ impl<H: Hashable + Clone> NonEmptyFrontier<H> {
.0
}
/// Constructs an authentication path for the leaf at the tip of this
/// Constructs a witness for the leaf at the tip of this
/// frontier, given a source of node values that complement this frontier.
pub fn authentication_path<F>(&self, depth: u8, bridge_value_at: F) -> Result<Vec<H>, PathError>
pub fn witness<F>(&self, depth: u8, bridge_value_at: F) -> Result<Vec<H>, PathError>
where
F: Fn(Address) -> Option<H>,
{
@ -349,7 +349,7 @@ impl<H> MerkleBridge<H> {
impl<'a, H: Hashable + Ord + Clone + 'a> MerkleBridge<H> {
/// Constructs a new bridge to follow this one. If mark_current_leaf is true, the successor
/// will track the information necessary to create an authentication path for the leaf most
/// will track the information necessary to create a witness for the leaf most
/// recently appended to this bridge's frontier.
#[must_use]
pub fn successor(&self, mark_current_leaf: bool) -> Self {
@ -443,14 +443,14 @@ impl<'a, H: Hashable + Ord + Clone + 'a> MerkleBridge<H> {
/// path for the specified position by interleaving with values from the prior frontier. This
/// method will panic if the position of the prior frontier does not match this bridge's prior
/// position.
fn authentication_path(
fn witness(
&self,
depth: u8,
prior_frontier: &NonEmptyFrontier<H>,
) -> Result<Vec<H>, PathError> {
assert!(Some(prior_frontier.position()) == self.prior_position);
prior_frontier.authentication_path(depth, |addr| {
prior_frontier.witness(depth, |addr| {
let r = addr.position_range();
if self.frontier.position() < r.start {
Some(H::empty_root(addr.level))
@ -589,8 +589,8 @@ pub struct BridgeTree<H, const DEPTH: u8> {
prior_bridges: Vec<MerkleBridge<H>>,
/// The current (mutable) bridge at the tip of the tree.
current_bridge: Option<MerkleBridge<H>>,
/// A map from positions for which we wish to be able to compute an
/// authentication path to index in the bridges vector.
/// A map from positions for which we wish to be able to compute a
/// witness to index in the bridges vector.
saved: BTreeMap<Position, usize>,
/// A stack of bridge indices to which it's possible to rewind directly.
checkpoints: Vec<Checkpoint>,
@ -774,11 +774,7 @@ impl<H: Hashable + Ord + Clone, const DEPTH: u8> BridgeTree<H, DEPTH> {
)
}
fn authentication_path_inner(
&self,
position: Position,
as_of_root: &H,
) -> Result<Vec<H>, PathError> {
fn witness_inner(&self, position: Position, as_of_root: &H) -> Result<Vec<H>, PathError> {
#[derive(Debug)]
enum AuthBase<'a> {
Current,
@ -861,7 +857,7 @@ impl<H: Hashable + Ord + Clone, const DEPTH: u8> BridgeTree<H, DEPTH> {
}
.ok_or(PathError::BridgeFusionError)?;
successor.authentication_path(DEPTH, prior_frontier)
successor.witness(DEPTH, prior_frontier)
}
}
@ -1021,8 +1017,8 @@ impl<H: Hashable + Ord + Clone, const DEPTH: u8> Tree<H> for BridgeTree<H, DEPTH
}
}
fn authentication_path(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
self.authentication_path_inner(position, as_of_root).ok()
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
self.witness_inner(position, as_of_root).ok()
}
fn garbage_collect(&mut self) {
@ -1149,7 +1145,7 @@ mod tests {
}
#[test]
fn frontier_auth_path() {
fn frontier_witness() {
let mut frontier = NonEmptyFrontier::<String>::new("a".to_string());
for c in 'b'..'h' {
frontier.append(c.to_string());
@ -1164,7 +1160,7 @@ mod tests {
Ok(["h", "ef", "abcd", "xxxxxxxx"]
.map(|v| v.to_string())
.to_vec()),
frontier.authentication_path(4, bridge_value_at)
frontier.witness(4, bridge_value_at)
);
}
@ -1228,8 +1224,8 @@ mod tests {
for pos in tree.saved.keys() {
assert_eq!(
tree.authentication_path(*pos, &tree.root(0).unwrap()),
tree_mut.authentication_path(*pos, &tree.root(0).unwrap())
tree.witness(*pos, &tree.root(0).unwrap()),
tree_mut.witness(*pos, &tree.root(0).unwrap())
);
}
}
@ -1256,8 +1252,8 @@ mod tests {
}
#[test]
fn auth_paths() {
crate::tests::check_auth_paths(BridgeTree::<String, 4>::new);
fn witnesss() {
crate::tests::check_witnesss(BridgeTree::<String, 4>::new);
}
#[test]
@ -1274,7 +1270,7 @@ mod tests {
fn garbage_collect() {
let mut t = BridgeTree::<String, 7>::new(10);
let mut to_unmark = vec![];
let mut has_auth_path = vec![];
let mut has_witness = vec![];
for i in 0usize..100 {
let elem: String = format!("{},", i);
assert!(t.append(&elem), "Append should succeed.");
@ -1286,7 +1282,7 @@ mod tests {
if i > 0 && i % 2 == 0 {
to_unmark.push(Position::from(i));
} else {
has_auth_path.push(Position::from(i));
has_witness.push(Position::from(i));
}
}
if i % 11 == 0 && !to_unmark.is_empty() {
@ -1296,26 +1292,24 @@ mod tests {
}
// 32 = 20 (checkpointed) + 14 (marked) - 2 (marked & checkpointed)
assert_eq!(t.prior_bridges().len(), 20 + 14 - 2);
let auth_paths = has_auth_path
let witnesss = has_witness
.iter()
.map(
|pos| match t.authentication_path_inner(*pos, &t.root(0).unwrap()) {
Ok(path) => path,
Err(e) => panic!("Failed to get auth path: {:?}", e),
},
)
.map(|pos| match t.witness_inner(*pos, &t.root(0).unwrap()) {
Ok(path) => path,
Err(e) => panic!("Failed to get auth path: {:?}", e),
})
.collect::<Vec<_>>();
t.garbage_collect();
// 20 = 32 - 10 (removed checkpoints) + 1 (not removed due to mark) - 3 (removed marks)
assert_eq!(t.prior_bridges().len(), 32 - 10 + 1 - 3);
let retained_auth_paths = has_auth_path
let retained_witnesss = has_witness
.iter()
.map(|pos| {
t.authentication_path(*pos, &t.root(0).unwrap())
t.witness(*pos, &t.root(0).unwrap())
.expect("Must be able to get auth path")
})
.collect::<Vec<_>>();
assert_eq!(auth_paths, retained_auth_paths);
assert_eq!(witnesss, retained_witnesss);
}
#[test]

View File

@ -10,8 +10,8 @@
//! ## Marking
//!
//! Merkle trees are typically used to show that a value exists in the tree via
//! an authentication path. We need an API that allows us to identify the
//! current leaf as a value we wish to compute authentication paths for even as
//! a witness. We need an API that allows us to identify the
//! current leaf as a value we wish to compute witnesss for even as
//! the tree continues to be appended to in the future; this is called
//! maintaining a witness. When we're later uninterested in such a leaf, we can
//! prune a witness and remove all unnecessary information from the structure as
@ -362,11 +362,11 @@ pub trait Tree<H> {
fn current_leaf(&self) -> Option<&H>;
/// Returns the leaf at the specified position if the tree can produce
/// an authentication path for it.
/// a witness for it.
fn get_marked_leaf(&self, position: Position) -> Option<&H>;
/// Marks the current leaf as one for which we're interested in producing
/// an authentication path. Returns an optional value containing the
/// a witness. Returns an optional value containing the
/// current position if successful or if the current value was already
/// marked, or None if the tree is empty.
fn mark(&mut self) -> Option<Position>;
@ -380,12 +380,12 @@ pub trait Tree<H> {
/// requested checkpoint depth.
fn root(&self, checkpoint_depth: usize) -> Option<H>;
/// Obtains an authentication path to the value at the specified position,
/// Obtains a witness to the value at the specified position,
/// as of the tree state corresponding to the given root.
/// Returns `None` if there is no available authentication path to that
/// Returns `None` if there is no available witness to that
/// position or if the root does not correspond to a checkpointed
/// root of the tree.
fn authentication_path(&self, position: Position, as_of_root: &H) -> Option<Vec<H>>;
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>>;
/// Marks the value at the specified position as a value we're no longer
/// interested in maintaining a mark for. Returns true if successful and
@ -577,14 +577,14 @@ pub(crate) mod tests {
assert_eq!(t.root(0).unwrap(), "aaaa____________");
}
pub(crate) fn check_auth_paths<T: Tree<String> + std::fmt::Debug, F: Fn(usize) -> T>(
pub(crate) fn check_witnesss<T: Tree<String> + std::fmt::Debug, F: Fn(usize) -> T>(
new_tree: F,
) {
let mut tree = new_tree(100);
tree.append(&"a".to_string());
tree.mark();
assert_eq!(
tree.authentication_path(Position(0), &tree.root(0).unwrap()),
tree.witness(Position(0), &tree.root(0).unwrap()),
Some(vec![
"_".to_string(),
"__".to_string(),
@ -595,7 +595,7 @@ pub(crate) mod tests {
tree.append(&"b".to_string());
assert_eq!(
tree.authentication_path(0.into(), &tree.root(0).unwrap()),
tree.witness(0.into(), &tree.root(0).unwrap()),
Some(vec![
"b".to_string(),
"__".to_string(),
@ -607,7 +607,7 @@ pub(crate) mod tests {
tree.append(&"c".to_string());
tree.mark();
assert_eq!(
tree.authentication_path(Position(2), &tree.root(0).unwrap()),
tree.witness(Position(2), &tree.root(0).unwrap()),
Some(vec![
"_".to_string(),
"ab".to_string(),
@ -618,7 +618,7 @@ pub(crate) mod tests {
tree.append(&"d".to_string());
assert_eq!(
tree.authentication_path(Position(2), &tree.root(0).unwrap()),
tree.witness(Position(2), &tree.root(0).unwrap()),
Some(vec![
"d".to_string(),
"ab".to_string(),
@ -629,7 +629,7 @@ pub(crate) mod tests {
tree.append(&"e".to_string());
assert_eq!(
tree.authentication_path(Position(2), &tree.root(0).unwrap()),
tree.witness(Position(2), &tree.root(0).unwrap()),
Some(vec![
"d".to_string(),
"ab".to_string(),
@ -648,7 +648,7 @@ pub(crate) mod tests {
tree.append(&"h".to_string());
assert_eq!(
tree.authentication_path(0.into(), &tree.root(0).unwrap()),
tree.witness(0.into(), &tree.root(0).unwrap()),
Some(vec![
"b".to_string(),
"cd".to_string(),
@ -671,7 +671,7 @@ pub(crate) mod tests {
tree.append(&"g".to_string());
assert_eq!(
tree.authentication_path(Position(5), &tree.root(0).unwrap()),
tree.witness(Position(5), &tree.root(0).unwrap()),
Some(vec![
"e".to_string(),
"g_".to_string(),
@ -688,7 +688,7 @@ pub(crate) mod tests {
tree.append(&'l'.to_string());
assert_eq!(
tree.authentication_path(Position(10), &tree.root(0).unwrap()),
tree.witness(Position(10), &tree.root(0).unwrap()),
Some(vec![
"l".to_string(),
"ij".to_string(),
@ -711,7 +711,7 @@ pub(crate) mod tests {
}
assert_eq!(
tree.authentication_path(0.into(), &tree.root(0).unwrap()),
tree.witness(0.into(), &tree.root(0).unwrap()),
Some(vec![
"b".to_string(),
"cd".to_string(),
@ -735,7 +735,7 @@ pub(crate) mod tests {
assert!(tree.rewind());
assert_eq!(
tree.authentication_path(Position(2), &tree.root(0).unwrap()),
tree.witness(Position(2), &tree.root(0).unwrap()),
Some(vec![
"d".to_string(),
"ab".to_string(),
@ -748,10 +748,7 @@ pub(crate) mod tests {
tree.append(&'a'.to_string());
tree.append(&'b'.to_string());
tree.mark();
assert_eq!(
tree.authentication_path(Position(0), &tree.root(0).unwrap()),
None
);
assert_eq!(tree.witness(Position(0), &tree.root(0).unwrap()), None);
let mut tree = new_tree(100);
for c in 'a'..'n' {
@ -764,7 +761,7 @@ pub(crate) mod tests {
tree.append(&'p'.to_string());
assert_eq!(
tree.authentication_path(Position(12), &tree.root(0).unwrap()),
tree.witness(Position(12), &tree.root(0).unwrap()),
Some(vec![
"n".to_string(),
"op".to_string(),
@ -890,14 +887,7 @@ pub(crate) mod tests {
let samples = vec![
vec![append("x"), Checkpoint, Mark, Rewind, unmark(0)],
vec![
append("d"),
Checkpoint,
Mark,
unmark(0),
Rewind,
unmark(0),
],
vec![append("d"), Checkpoint, Mark, unmark(0), Rewind, unmark(0)],
vec![
append("o"),
Checkpoint,
@ -1002,9 +992,9 @@ pub(crate) mod tests {
a
}
fn authentication_path(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
let a = self.inefficient.authentication_path(position, as_of_root);
let b = self.efficient.authentication_path(position, as_of_root);
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>> {
let a = self.inefficient.witness(position, as_of_root);
let b = self.efficient.witness(position, as_of_root);
assert_eq!(a, b);
a
}
@ -1096,7 +1086,7 @@ pub(crate) mod tests {
}
Authpath(p, d) => tree
.root(*d)
.and_then(|root| tree.authentication_path(*p, &root))
.and_then(|root| tree.witness(*p, &root))
.map(|xs| (*p, xs)),
GarbageCollect => None,
}
@ -1114,7 +1104,7 @@ pub(crate) mod tests {
}
}
pub(crate) fn compute_root_from_auth_path<H: Hashable>(
pub(crate) fn compute_root_from_witness<H: Hashable>(
value: H,
position: Position,
path: &[H],
@ -1137,7 +1127,7 @@ pub(crate) mod tests {
}
#[test]
fn test_compute_root_from_auth_path() {
fn test_compute_root_from_witness() {
let expected = SipHashable::combine(
<Level>::from(2),
&SipHashable::combine(
@ -1153,7 +1143,7 @@ pub(crate) mod tests {
);
assert_eq!(
compute_root_from_auth_path::<SipHashable>(
compute_root_from_witness::<SipHashable>(
SipHashable(0),
0.into(),
&[
@ -1170,7 +1160,7 @@ pub(crate) mod tests {
);
assert_eq!(
compute_root_from_auth_path(
compute_root_from_witness(
SipHashable(4),
<Position>::from(4),
&[
@ -1188,30 +1178,12 @@ pub(crate) mod tests {
}
#[test]
fn test_auth_path_consistency() {
fn test_witness_consistency() {
let samples = vec![
// Reduced examples
vec![
append("a"),
append("b"),
Checkpoint,
Mark,
authpath(0, 1),
],
vec![
append("c"),
append("d"),
Mark,
Checkpoint,
authpath(1, 1),
],
vec![
append("e"),
Checkpoint,
Mark,
append("f"),
authpath(0, 1),
],
vec![append("a"), append("b"), Checkpoint, Mark, authpath(0, 1)],
vec![append("c"), append("d"), Mark, Checkpoint, authpath(1, 1)],
vec![append("e"), Checkpoint, Mark, append("f"), authpath(0, 1)],
vec![
append("g"),
Mark,
@ -1334,14 +1306,7 @@ pub(crate) mod tests {
fn test_rewind_remove_mark_consistency() {
let samples = vec![
vec![append("x"), Checkpoint, Mark, Rewind, unmark(0)],
vec![
append("d"),
Checkpoint,
Mark,
unmark(0),
Rewind,
unmark(0),
],
vec![append("d"), Checkpoint, Mark, unmark(0), Rewind, unmark(0)],
vec![
append("o"),
Checkpoint,
@ -1490,9 +1455,7 @@ pub(crate) mod tests {
}
}
Authpath(position, depth) => {
if let Some(path) = tree
.root(*depth)
.and_then(|r| tree.authentication_path(*position, &r))
if let Some(path) = tree.root(*depth).and_then(|r| tree.witness(*position, &r))
{
let value: H = tree_values[<usize>::from(*position)].clone();
let tree_root = tree.root(*depth);
@ -1515,7 +1478,7 @@ pub(crate) mod tests {
prop_assert_eq!(&tree_root.unwrap(), &expected_root);
prop_assert_eq!(
&compute_root_from_auth_path(value, *position, &path),
&compute_root_from_witness(value, *position, &path),
&expected_root
);
}

View File

@ -56,7 +56,7 @@ impl<H: Hashable + PartialEq + Clone> TreeState<H> {
}
/// Returns the leaf at the specified position if the tree can produce
/// an authentication path for it.
/// a witness for it.
fn get_marked_leaf(&self, position: Position) -> Option<&H> {
if self.marks.contains(&position) {
self.leaves.get(<usize>::from(position))
@ -74,10 +74,10 @@ impl<H: Hashable + PartialEq + Clone> TreeState<H> {
})
}
/// Obtains an authentication path to the value at the specified position.
/// Returns `None` if there is no available authentication path to that
/// Obtains a witness to the value at the specified position.
/// Returns `None` if there is no available witness to that
/// value.
fn authentication_path(&self, position: Position) -> Option<Vec<H>> {
fn witness(&self, position: Position) -> Option<Vec<H>> {
if Some(position) <= self.current_position() {
let mut path = vec![];
@ -183,9 +183,9 @@ impl<H: Hashable + PartialEq + Clone + std::fmt::Debug> Tree<H> for CompleteTree
.map(|s| s.root())
}
fn authentication_path(&self, position: Position, root: &H) -> Option<Vec<H>> {
fn witness(&self, position: Position, root: &H) -> Option<Vec<H>> {
// Search for the checkpointed state corresponding to the provided root, and if one is
// found, compute the authentication path as of that root.
// found, compute the witness as of that root.
self.checkpoints
.iter()
.chain(Some(&self.tree_state))
@ -193,7 +193,7 @@ impl<H: Hashable + PartialEq + Clone + std::fmt::Debug> Tree<H> for CompleteTree
.skip_while(|c| !c.marks.contains(&position))
.find_map(|c| {
if &c.root() == root {
c.authentication_path(position)
c.witness(position)
} else {
None
}
@ -251,7 +251,7 @@ pub(crate) fn lazy_root<H: Hashable + Clone>(mut leaves: Vec<H>) -> H {
#[cfg(test)]
mod tests {
use crate::tests::{compute_root_from_auth_path, SipHashable};
use crate::tests::{compute_root_from_witness, SipHashable};
use crate::{Hashable, Level, Position, Tree};
use std::convert::TryFrom;
@ -303,12 +303,12 @@ mod tests {
}
#[test]
fn auth_paths() {
crate::tests::check_auth_paths(|max_c| CompleteTree::<String>::new(4, max_c));
fn witnesss() {
crate::tests::check_witnesss(|max_c| CompleteTree::<String>::new(4, max_c));
}
#[test]
fn correct_auth_path() {
fn correct_witness() {
const DEPTH: usize = 3;
let values = (0..(1 << DEPTH)).into_iter().map(SipHashable);
@ -337,11 +337,9 @@ mod tests {
for i in 0u64..(1 << DEPTH) {
let position = Position::try_from(i).unwrap();
let path = tree
.authentication_path(position, &tree.root(0).unwrap())
.unwrap();
let path = tree.witness(position, &tree.root(0).unwrap()).unwrap();
assert_eq!(
compute_root_from_auth_path(SipHashable(i), position, &path),
compute_root_from_witness(SipHashable(i), position, &path),
expected
);
}