#![cfg_attr(docsrs, feature(doc_cfg))]
#![no_std]
#[cfg(feature = "std")]
extern crate std;
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::convert::{TryFrom, TryInto};
use core::fmt;
use core::num::TryFromIntError;
use core::ops::{Add, AddAssign, Range, Sub};
use either::Either;
pub mod frontier;
#[cfg(feature = "legacy-api")]
#[cfg_attr(docsrs, doc(cfg(feature = "legacy-api")))]
pub mod witness;
#[cfg(any(test, feature = "test-dependencies"))]
#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
pub mod testing;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Marking {
Marked,
Reference,
None,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Retention<C> {
Ephemeral,
Checkpoint { id: C, marking: Marking },
Marked,
Reference,
}
impl<C> Retention<C> {
pub fn is_checkpoint(&self) -> bool {
matches!(self, Retention::Checkpoint { .. })
}
pub fn is_marked(&self) -> bool {
matches!(
self,
Retention::Marked
| Retention::Checkpoint {
marking: Marking::Marked,
..
}
)
}
pub fn map<'a, D, F: Fn(&'a C) -> D>(&'a self, f: F) -> Retention<D> {
match self {
Retention::Ephemeral => Retention::Ephemeral,
Retention::Checkpoint { id, marking } => Retention::Checkpoint {
id: f(id),
marking: *marking,
},
Retention::Marked => Retention::Marked,
Retention::Reference => Retention::Reference,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Source {
Past(u8),
Future,
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
struct WitnessAddrsIter {
root_level: Level,
current: Address,
ommer_count: u8,
}
impl Iterator for WitnessAddrsIter {
type Item = (Address, Source);
fn next(&mut self) -> Option<(Address, Source)> {
if self.current.level() < self.root_level {
let current = self.current;
let source = if current.is_right_child() {
Source::Past(self.ommer_count)
} else {
Source::Future
};
self.current = current.parent();
if matches!(source, Source::Past(_)) {
self.ommer_count += 1;
}
Some((current.sibling(), source))
} else {
None
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Position(u64);
impl Position {
pub fn is_right_child(&self) -> bool {
self.0 & 0x1 == 1
}
pub fn root_level(&self) -> Level {
Level((u64::BITS - self.0.leading_zeros()) as u8)
}
pub fn past_ommer_count(&self) -> u8 {
(0..self.root_level().0)
.filter(|i| (self.0 >> i) & 0x1 == 1)
.count()
.try_into()
.unwrap() }
pub fn is_complete_subtree(&self, root_level: Level) -> bool {
!(0..(root_level.0)).any(|l| self.0 & (1 << l) == 0)
}
pub fn witness_addrs(&self, root_level: Level) -> impl Iterator<Item = (Address, Source)> {
WitnessAddrsIter {
root_level,
current: Address::from(*self),
ommer_count: 0,
}
}
}
impl From<Position> for u64 {
fn from(p: Position) -> Self {
p.0
}
}
impl From<u64> for Position {
fn from(sz: u64) -> Self {
Self(sz)
}
}
impl Add<u64> for Position {
type Output = Position;
fn add(self, other: u64) -> Self {
Position(self.0 + other)
}
}
impl AddAssign<u64> for Position {
fn add_assign(&mut self, other: u64) {
self.0 += other
}
}
impl Sub<u64> for Position {
type Output = Position;
fn sub(self, other: u64) -> Self {
if self.0 < other {
panic!("position underflow");
}
Position(self.0 - other)
}
}
impl TryFrom<usize> for Position {
type Error = TryFromIntError;
fn try_from(sz: usize) -> Result<Self, Self::Error> {
<u64>::try_from(sz).map(Self)
}
}
impl TryFrom<Position> for usize {
type Error = TryFromIntError;
fn try_from(p: Position) -> Result<Self, Self::Error> {
<usize>::try_from(p.0)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Level(u8);
impl Level {
pub const ZERO: Self = Level(0);
pub const fn new(value: u8) -> Self {
Self(value)
}
pub fn iter_to(self, other: Level) -> impl Iterator<Item = Self> {
(self.0..other.0).map(Level)
}
}
impl Add<u8> for Level {
type Output = Self;
fn add(self, value: u8) -> Self {
Self(self.0 + value)
}
}
impl From<u8> for Level {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<Level> for u8 {
fn from(level: Level) -> u8 {
level.0
}
}
impl From<Level> for u32 {
fn from(level: Level) -> u32 {
level.0.into()
}
}
impl From<Level> for u64 {
fn from(level: Level) -> u64 {
level.0.into()
}
}
impl From<Level> for usize {
fn from(level: Level) -> usize {
level.0 as usize
}
}
impl TryFrom<usize> for Level {
type Error = TryFromIntError;
fn try_from(sz: usize) -> Result<Self, Self::Error> {
<u8>::try_from(sz).map(Self)
}
}
impl Sub<u8> for Level {
type Output = Self;
fn sub(self, value: u8) -> Self {
if self.0 < value {
panic!("underflow")
}
Self(self.0 - value)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address {
level: Level,
index: u64,
}
impl Address {
pub fn from_parts(level: Level, index: u64) -> Self {
Address { level, index }
}
pub fn above_position(level: Level, position: Position) -> Self {
Address {
level,
index: position.0 >> level.0,
}
}
pub fn level(&self) -> Level {
self.level
}
pub fn index(&self) -> u64 {
self.index
}
pub fn parent(&self) -> Address {
Address {
level: self.level + 1,
index: self.index >> 1,
}
}
pub fn sibling(&self) -> Address {
Address {
level: self.level,
index: self.index ^ 1,
}
}
pub fn children(&self) -> Option<(Address, Address)> {
if self.level == Level::from(0) {
None
} else {
let left = Address {
level: self.level - 1,
index: self.index << 1,
};
let right = Address {
level: self.level - 1,
index: (self.index << 1) + 1,
};
Some((left, right))
}
}
pub fn is_ancestor_of(&self, addr: &Self) -> bool {
self.level > addr.level && { addr.index >> (self.level.0 - addr.level.0) == self.index }
}
pub fn common_ancestor(&self, other: &Self) -> Self {
let (higher, lower) = if self.level >= other.level {
(self, other)
} else {
(other, self)
};
let lower_ancestor_idx = lower.index >> (higher.level.0 - lower.level.0);
let index_delta = higher.index ^ lower_ancestor_idx;
let level_delta = (u64::BITS - index_delta.leading_zeros()) as u8;
Address {
level: higher.level + level_delta,
index: core::cmp::max(higher.index, lower_ancestor_idx) >> level_delta,
}
}
pub fn contains(&self, addr: &Self) -> bool {
self == addr || self.is_ancestor_of(addr)
}
pub fn position_range_start(&self) -> Position {
(self.index << self.level.0).into()
}
pub fn position_range_end(&self) -> Position {
((self.index + 1) << self.level.0).into()
}
pub fn max_position(&self) -> Position {
self.position_range_end() - 1
}
pub fn position_range(&self) -> Range<Position> {
Range {
start: self.position_range_start(),
end: self.position_range_end(),
}
}
pub fn context(&self, level: Level) -> Either<Address, Range<u64>> {
if level >= self.level {
Either::Left(Address {
level,
index: self.index >> (level.0 - self.level.0),
})
} else {
let shift = self.level.0 - level.0;
Either::Right(Range {
start: self.index << shift,
end: (self.index + 1) << shift,
})
}
}
pub fn position_cmp(&self, pos: Position) -> Ordering {
let range = self.position_range();
if range.start > pos {
Ordering::Greater
} else if range.end <= pos {
Ordering::Less
} else {
Ordering::Equal
}
}
pub fn is_left_child(&self) -> bool {
self.index & 0x1 == 0
}
pub fn is_right_child(&self) -> bool {
self.index & 0x1 == 1
}
pub fn current_incomplete(&self) -> Address {
let mut index = self.index;
for level in self.level.0.. {
if index & 0x1 == 1 {
index >>= 1;
} else {
return Address {
level: Level(level),
index,
};
}
}
unreachable!("The loop will always terminate via return in at most 64 iterations.")
}
pub fn next_incomplete_parent(&self) -> Address {
if self.is_right_child() {
self.current_incomplete()
} else {
let complete = Address {
level: self.level,
index: self.index + 1,
};
complete.current_incomplete()
}
}
pub fn next_at_level(&self) -> Address {
Address {
level: self.level,
index: self.index + 1,
}
}
}
impl From<Position> for Address {
fn from(p: Position) -> Self {
Address {
level: 0.into(),
index: p.into(),
}
}
}
impl<'a> From<&'a Position> for Address {
fn from(p: &'a Position) -> Self {
Address {
level: 0.into(),
index: (*p).into(),
}
}
}
impl From<Address> for Option<Position> {
fn from(addr: Address) -> Self {
if addr.level == 0.into() {
Some(addr.index.into())
} else {
None
}
}
}
impl<'a> From<&'a Address> for Option<Position> {
fn from(addr: &'a Address) -> Self {
if addr.level == 0.into() {
Some(addr.index.into())
} else {
None
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MerklePath<H, const DEPTH: u8> {
path_elems: Vec<H>,
position: Position,
}
impl<H, const DEPTH: u8> MerklePath<H, DEPTH> {
#[allow(clippy::result_unit_err)]
pub fn from_parts(path_elems: Vec<H>, position: Position) -> Result<Self, ()> {
if path_elems.len() == usize::from(DEPTH) {
Ok(MerklePath {
path_elems,
position,
})
} else {
Err(())
}
}
pub fn path_elems(&self) -> &[H] {
&self.path_elems
}
pub fn position(&self) -> Position {
self.position
}
}
impl<H: Hashable, const DEPTH: u8> MerklePath<H, DEPTH> {
pub fn root(&self, leaf: H) -> H {
self.path_elems
.iter()
.zip(0u8..)
.fold(leaf, |root, (h, i)| {
if (self.position.0 >> i) & 0x1 == 0 {
H::combine(i.into(), &root, h)
} else {
H::combine(i.into(), h, &root)
}
})
}
}
pub trait Hashable: fmt::Debug {
fn empty_leaf() -> Self;
fn combine(level: Level, a: &Self, b: &Self) -> Self;
fn empty_root(level: Level) -> Self
where
Self: Sized,
{
Level::from(0)
.iter_to(level)
.fold(Self::empty_leaf(), |v, lvl| Self::combine(lvl, &v, &v))
}
}
#[cfg(test)]
pub(crate) mod tests {
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::ops::Range;
use either::Either;
use super::{Address, Level, Position, Source};
use crate::MerklePath;
#[test]
fn position_is_complete_subtree() {
assert!(Position(0).is_complete_subtree(Level(0)));
assert!(Position(1).is_complete_subtree(Level(1)));
assert!(!Position(2).is_complete_subtree(Level(1)));
assert!(!Position(2).is_complete_subtree(Level(2)));
assert!(Position(3).is_complete_subtree(Level(2)));
assert!(!Position(4).is_complete_subtree(Level(2)));
assert!(Position(7).is_complete_subtree(Level(3)));
assert!(Position(u32::MAX as u64).is_complete_subtree(Level(32)));
}
#[test]
fn position_past_ommer_count() {
assert_eq!(0, Position(0).past_ommer_count());
assert_eq!(1, Position(1).past_ommer_count());
assert_eq!(1, Position(2).past_ommer_count());
assert_eq!(2, Position(3).past_ommer_count());
assert_eq!(1, Position(4).past_ommer_count());
assert_eq!(3, Position(7).past_ommer_count());
assert_eq!(1, Position(8).past_ommer_count());
}
#[test]
fn position_root_level() {
assert_eq!(Level(0), Position(0).root_level());
assert_eq!(Level(1), Position(1).root_level());
assert_eq!(Level(2), Position(2).root_level());
assert_eq!(Level(2), Position(3).root_level());
assert_eq!(Level(3), Position(4).root_level());
assert_eq!(Level(3), Position(7).root_level());
assert_eq!(Level(4), Position(8).root_level());
}
#[test]
fn position_witness_addrs() {
use Source::*;
let path_elem = |l, i, s| (Address::from_parts(Level::from(l), i), s);
assert_eq!(
vec![path_elem(0, 1, Future), path_elem(1, 1, Future)],
Position::from(0)
.witness_addrs(Level::from(2))
.collect::<Vec<_>>()
);
assert_eq!(
vec![path_elem(0, 3, Future), path_elem(1, 0, Past(0))],
Position::from(2)
.witness_addrs(Level::from(2))
.collect::<Vec<_>>()
);
assert_eq!(
vec![
path_elem(0, 2, Past(0)),
path_elem(1, 0, Past(1)),
path_elem(2, 1, Future)
],
Position::from(3)
.witness_addrs(Level::from(3))
.collect::<Vec<_>>()
);
assert_eq!(
vec![
path_elem(0, 5, Future),
path_elem(1, 3, Future),
path_elem(2, 0, Past(0)),
path_elem(3, 1, Future)
],
Position::from(4)
.witness_addrs(Level::from(4))
.collect::<Vec<_>>()
);
assert_eq!(
vec![
path_elem(0, 7, Future),
path_elem(1, 2, Past(0)),
path_elem(2, 0, Past(1)),
path_elem(3, 1, Future)
],
Position::from(6)
.witness_addrs(Level::from(4))
.collect::<Vec<_>>()
);
}
#[test]
fn address_current_incomplete() {
let addr = |l, i| Address::from_parts(Level(l), i);
assert_eq!(addr(0, 0), addr(0, 0).current_incomplete());
assert_eq!(addr(1, 0), addr(0, 1).current_incomplete());
assert_eq!(addr(0, 2), addr(0, 2).current_incomplete());
assert_eq!(addr(2, 0), addr(0, 3).current_incomplete());
}
#[test]
fn address_next_incomplete_parent() {
let addr = |l, i| Address::from_parts(Level(l), i);
assert_eq!(addr(1, 0), addr(0, 0).next_incomplete_parent());
assert_eq!(addr(1, 0), addr(0, 1).next_incomplete_parent());
assert_eq!(addr(2, 0), addr(0, 2).next_incomplete_parent());
assert_eq!(addr(2, 0), addr(0, 3).next_incomplete_parent());
assert_eq!(addr(3, 0), addr(2, 0).next_incomplete_parent());
assert_eq!(addr(1, 2), addr(0, 4).next_incomplete_parent());
assert_eq!(addr(3, 0), addr(1, 2).next_incomplete_parent());
}
#[test]
fn addr_is_ancestor() {
let l0 = Level(0);
let l1 = Level(1);
assert!(Address::from_parts(l1, 0).is_ancestor_of(&Address::from_parts(l0, 0)));
assert!(Address::from_parts(l1, 0).is_ancestor_of(&Address::from_parts(l0, 1)));
assert!(!Address::from_parts(l1, 0).is_ancestor_of(&Address::from_parts(l0, 2)));
}
#[test]
fn addr_position_range() {
assert_eq!(
Address::from_parts(Level(0), 0).position_range(),
Range {
start: Position(0),
end: Position(1)
}
);
assert_eq!(
Address::from_parts(Level(1), 0).position_range(),
Range {
start: Position(0),
end: Position(2)
}
);
assert_eq!(
Address::from_parts(Level(2), 1).position_range(),
Range {
start: Position(4),
end: Position(8)
}
);
}
#[test]
fn addr_above_position() {
assert_eq!(
Address::above_position(Level(3), Position(9)),
Address::from_parts(Level(3), 1)
);
}
#[test]
fn addr_children() {
assert_eq!(Address::from_parts(Level(0), 1).children(), None);
assert_eq!(
Address::from_parts(Level(3), 1).children(),
Some((
Address::from_parts(Level(2), 2),
Address::from_parts(Level(2), 3),
))
);
}
#[test]
fn addr_is_ancestor_of() {
assert!(Address::from_parts(Level(3), 1).is_ancestor_of(&Address::from_parts(Level(2), 2)));
assert!(Address::from_parts(Level(3), 1).is_ancestor_of(&Address::from_parts(Level(1), 7)));
assert!(!Address::from_parts(Level(3), 1).is_ancestor_of(&Address::from_parts(Level(1), 8)));
}
#[test]
fn addr_context() {
assert_eq!(
Address::from_parts(Level(3), 1).context(Level(0)),
Either::Right(Range { start: 8, end: 16 })
);
assert_eq!(
Address::from_parts(Level(3), 4).context(Level(5)),
Either::Left(Address::from_parts(Level(5), 1))
);
}
#[test]
fn merkle_path_root() {
let path: MerklePath<String, 3> = MerklePath::from_parts(
vec!["a".to_string(), "cd".to_string(), "efgh".to_string()],
Position(1),
)
.unwrap();
assert_eq!(path.root("b".to_string()), "abcdefgh".to_string());
let path: MerklePath<String, 3> = MerklePath::from_parts(
vec!["d".to_string(), "ab".to_string(), "efgh".to_string()],
Position(2),
)
.unwrap();
assert_eq!(path.root("c".to_string()), "abcdefgh".to_string());
}
#[test]
fn addr_common_ancestor() {
assert_eq!(
Address::from_parts(Level(2), 1).common_ancestor(&Address::from_parts(Level(3), 2)),
Address::from_parts(Level(5), 0)
);
assert_eq!(
Address::from_parts(Level(2), 2).common_ancestor(&Address::from_parts(Level(1), 7)),
Address::from_parts(Level(3), 1)
);
assert_eq!(
Address::from_parts(Level(2), 2).common_ancestor(&Address::from_parts(Level(1), 6)),
Address::from_parts(Level(3), 1)
);
assert_eq!(
Address::from_parts(Level(2), 2).common_ancestor(&Address::from_parts(Level(2), 2)),
Address::from_parts(Level(2), 2)
);
assert_eq!(
Address::from_parts(Level(2), 2).common_ancestor(&Address::from_parts(Level(0), 9)),
Address::from_parts(Level(2), 2)
);
assert_eq!(
Address::from_parts(Level(0), 9).common_ancestor(&Address::from_parts(Level(2), 2)),
Address::from_parts(Level(2), 2)
);
assert_eq!(
Address::from_parts(Level(0), 12).common_ancestor(&Address::from_parts(Level(0), 15)),
Address::from_parts(Level(2), 3)
);
assert_eq!(
Address::from_parts(Level(0), 13).common_ancestor(&Address::from_parts(Level(0), 15)),
Address::from_parts(Level(2), 3)
);
assert_eq!(
Address::from_parts(Level(0), 13).common_ancestor(&Address::from_parts(Level(0), 14)),
Address::from_parts(Level(2), 3)
);
assert_eq!(
Address::from_parts(Level(0), 14).common_ancestor(&Address::from_parts(Level(0), 15)),
Address::from_parts(Level(1), 7)
);
assert_eq!(
Address::from_parts(Level(0), 15).common_ancestor(&Address::from_parts(Level(0), 16)),
Address::from_parts(Level(5), 0)
);
}
}