Skip to content

Commit 1e3d1b8

Browse files
committed
fixup! pyth: introduce pyth accumulator library
1 parent 85b3641 commit 1e3d1b8

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

pyth/src/accumulators/merkle.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,28 @@ use {
2727
//
2828
// - https://flawed.net.nz/2018/02/21/attacking-merkle-trees-with-a-second-preimage-attack
2929
// - https://en.wikipedia.org/wiki/Merkle_tree#Second_preimage_attack
30+
//
31+
// NOTE: We use a NULL prefix for leaf nodes to distinguish them from the empty message (""), while
32+
// there is no path that allows empty messages this is a safety measure to prevent future
33+
// vulnerabilities being introduced.
3034
const LEAF_PREFIX: &[u8] = &[0];
3135
const NODE_PREFIX: &[u8] = &[1];
36+
const NULL_PREFIX: &[u8] = &[2];
3237

33-
macro_rules! hash_leaf {
34-
{$x:ty, $d:expr} => {
35-
<$x as Hasher>::hashv(&[LEAF_PREFIX, $d])
36-
}
38+
fn hash_leaf<H: Hasher>(leaf: &[u8]) -> H::Hash {
39+
H::hashv(&[LEAF_PREFIX, leaf])
3740
}
3841

39-
macro_rules! hash_node {
40-
{$x:ty, $l:expr, $r:expr} => {
41-
<$x as Hasher>::hashv(&[NODE_PREFIX, $l.as_ref(), $r.as_ref()])
42-
}
42+
fn hash_node<H: Hasher>(l: &H::Hash, r: &H::Hash) -> H::Hash {
43+
H::hashv(&[
44+
NODE_PREFIX,
45+
(if l <= r { l } else { r }).as_ref(),
46+
(if l <= r { r } else { l }).as_ref(),
47+
])
48+
}
49+
50+
fn hash_null<H: Hasher>() -> H::Hash {
51+
H::hashv(&[NULL_PREFIX])
4352
}
4453

4554
#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize)]
@@ -91,20 +100,20 @@ impl<'a, H: Hasher + 'a> Accumulator<'a> for MerkleAccumulator<H> {
91100
type Proof = MerklePath<H>;
92101

93102
fn from_set(items: impl Iterator<Item = &'a [u8]>) -> Option<Self> {
94-
let items: Vec<H::Hash> = items.map(|i| hash_leaf!(H, i)).collect();
103+
let items: Vec<H::Hash> = items.map(|i| hash_leaf::<H>(i)).collect();
95104
Self::new(&items)
96105
}
97106

98107
fn prove(&'a self, item: &[u8]) -> Option<Self::Proof> {
99-
let item = hash_leaf!(H, item);
108+
let item = hash_leaf::<H>(item);
100109
let index = self.nodes.iter().position(|i| i == &item)?;
101110
Some(self.find_path(index))
102111
}
103112

104113
fn check(&'a self, proof: Self::Proof, item: &[u8]) -> bool {
105-
let mut current = hash_leaf!(H, item);
106-
for h in proof.0 {
107-
current = hash_node!(H, current, h);
114+
let mut current = hash_leaf::<H>(item);
115+
for hash in proof.0 {
116+
current = hash_node::<H>(&current, &hash);
108117
}
109118
current == self.root
110119
}
@@ -123,9 +132,9 @@ impl<H: Hasher> MerkleAccumulator<H> {
123132
// Filling the leaf hashes
124133
for i in 0..(1 << depth) {
125134
if i < items.len() {
126-
tree[(1 << depth) + i] = hash_leaf!(H, items[i].as_ref());
135+
tree[(1 << depth) + i] = hash_leaf::<H>(items[i].as_ref());
127136
} else {
128-
tree[(1 << depth) + i] = hash_leaf!(H, "".as_ref());
137+
tree[(1 << depth) + i] = hash_null::<H>();
129138
}
130139
}
131140

@@ -135,7 +144,7 @@ impl<H: Hasher> MerkleAccumulator<H> {
135144
let level_num_nodes = 1 << level;
136145
for i in 0..level_num_nodes {
137146
let id = (1 << level) + i;
138-
tree[id] = hash_node!(H, &tree[id * 2], &tree[id * 2 + 1]);
147+
tree[id] = hash_node::<H>(&tree[id * 2], &tree[id * 2 + 1]);
139148
}
140149
}
141150

pyth/src/hashers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ where
2828
+ Debug
2929
+ Default
3030
+ Eq
31+
+ PartialOrd
3132
+ PartialEq
3233
+ serde::Serialize
3334
+ for<'a> Deserialize<'a>;

0 commit comments

Comments
 (0)