penumbra_sdk_tct/internal/height.rs
1//! Type level machinery used to statically determine the height of a tree, to ensure the correct
2//! domain separator is used when hashing at any height.
3//!
4//! Because the height of a tree is inferred by the type system, this means that bugs where the
5//! wrong height is used to compute a subtree's hashing domain separator are greatly reduced.
6//!
7//! This module contains type-level code for computing the height of structures and translating an
8//! unary representation good for type-level constraints ([`Succ`] and [`Zero`]) into constant
9//! `u64`s suitable for value-level computation.
10
11use crate::prelude::*;
12
13/// Trait identifying the statically-known height of a given tree element.
14///
15/// This is used to differentiate the hashes at each level of the tree.
16pub trait Height {
17 /// The height of this type above the leaves of the tree.
18 type Height: Path;
19}
20
21/// The constant `u8` associated with each unary height.
22pub trait IsHeight: sealed::IsHeight {
23 /// The number for this height.
24 const HEIGHT: u8;
25}
26
27/// Height zero.
28pub struct Zero;
29
30impl IsHeight for Zero {
31 const HEIGHT: u8 = 0;
32}
33
34/// Height `N + 1`.
35pub struct Succ<N>(N);
36
37impl<N: IsHeight> IsHeight for Succ<N> {
38 const HEIGHT: u8 = if let Some(n) = N::HEIGHT.checked_add(1) {
39 n
40 } else {
41 panic!("height overflow: can't construct something of height > u8::MAX")
42 };
43}
44
45/// Seal the `IsHeight` trait so that only `Succ` and `Zero` can inhabit it.
46mod sealed {
47 use super::{Succ, Zero};
48
49 pub trait IsHeight {}
50 impl IsHeight for Zero {}
51 impl<N: IsHeight> IsHeight for Succ<N> {}
52}