Skip to content

Commit 3a0668b

Browse files
working addition
Implement basic element addition for Pollard
1 parent 201688d commit 3a0668b

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

src/accumulator/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! only keeps the accumulator's roots, it still trustlessly update this state, not requiring
99
//! a trusted third party to learn about the current state.
1010
pub mod node_hash;
11+
pub mod pollard;
1112
pub mod proof;
1213
pub mod stump;
1314
pub(super) mod util;

src/accumulator/pollard.rs

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use std::fmt::Debug;
2+
use std::{
3+
cell::{Cell, RefCell},
4+
mem::{self, swap},
5+
rc::{Rc, Weak},
6+
};
7+
8+
use super::node_hash::NodeHash;
9+
10+
type Node = Rc<PolNode>;
11+
#[derive(Clone)]
12+
pub struct PolNode {
13+
data: NodeHash,
14+
aunt: Option<Node>,
15+
l_niece: RefCell<Option<Node>>,
16+
r_niece: RefCell<Option<Node>>,
17+
}
18+
19+
impl Debug for PolNode {
20+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21+
write!(f, "{:?}", self.data)
22+
}
23+
}
24+
25+
impl PolNode {
26+
fn new(
27+
data: NodeHash,
28+
aunt: Option<Node>,
29+
l_niece: Option<Node>,
30+
r_niece: Option<Node>,
31+
) -> PolNode {
32+
PolNode {
33+
data,
34+
aunt,
35+
l_niece: RefCell::new(l_niece),
36+
r_niece: RefCell::new(r_niece),
37+
}
38+
}
39+
40+
/// Creates a new [PolNode] and returns it as [Node], i.e [Rc<Box<PolNode>>]
41+
/// If you need a pure PolNode, use `new` instead.
42+
fn new_node(
43+
data: NodeHash,
44+
aunt: Option<Node>,
45+
l_niece: Option<Node>,
46+
r_niece: Option<Node>,
47+
) -> Node {
48+
let node = PolNode {
49+
data,
50+
aunt,
51+
l_niece: RefCell::new(l_niece),
52+
r_niece: RefCell::new(r_niece),
53+
};
54+
55+
node.as_rc()
56+
}
57+
/// Returns the current node as an Reference Counted Container "[Rc]". This is how
58+
/// nodes are stored inside the tree.
59+
fn as_rc(self) -> Node {
60+
Rc::new(self)
61+
}
62+
63+
fn set_aunt(&self, aunt: Option<Node>) -> PolNode {
64+
PolNode {
65+
data: self.data,
66+
aunt,
67+
l_niece: self.clone().l_niece,
68+
r_niece: self.clone().r_niece,
69+
}
70+
}
71+
fn set_nieces(&self, l_niece: Option<Node>, r_niece: Option<Node>) {
72+
self.l_niece.replace(l_niece);
73+
self.r_niece.replace(r_niece);
74+
}
75+
fn chop(&self) {
76+
self.l_niece.replace(None);
77+
self.r_niece.replace(None);
78+
}
79+
}
80+
#[derive(Clone)]
81+
pub struct Pollard {
82+
leaves: usize,
83+
roots: Vec<Node>,
84+
}
85+
impl Pollard {
86+
pub fn modify(&self, utxos: Vec<NodeHash>, _stxos: Vec<NodeHash>) {
87+
let roots = self.roots.clone();
88+
let _roots = Pollard::add(roots, utxos, self.leaves);
89+
}
90+
91+
fn add(mut roots: Vec<Node>, utxos: Vec<NodeHash>, mut num_leaves: usize) -> Vec<Node> {
92+
for utxo in utxos {
93+
roots = Pollard::add_single(roots, utxo, num_leaves);
94+
num_leaves += 1;
95+
}
96+
97+
roots
98+
}
99+
100+
fn add_single(mut roots: Vec<Node>, node: NodeHash, mut num_leaves: usize) -> Vec<Node> {
101+
let mut node = PolNode::new(node, None, None, None).as_rc();
102+
103+
while num_leaves & 1 == 1 {
104+
// If num_leaves & 1 == 1, roots cannot be None
105+
let left_root = roots.pop().unwrap();
106+
107+
left_root.l_niece.swap(&node.l_niece);
108+
left_root.r_niece.swap(&node.r_niece);
109+
110+
let n_hash = NodeHash::parent_hash(&left_root.data.clone(), &node.data.clone());
111+
let new_node = PolNode::new_node(n_hash, None, None, None);
112+
113+
let left_niece = left_root.set_aunt(Some(new_node.clone())).as_rc();
114+
let right_niece = node.set_aunt(Some(new_node.clone())).as_rc();
115+
116+
new_node.set_nieces(Some(left_niece), Some(right_niece));
117+
node = new_node;
118+
119+
// left_root.aunt = new_node.clone();
120+
num_leaves >>= 1;
121+
}
122+
123+
roots.push(node);
124+
roots
125+
}
126+
}
127+
#[cfg(test)]
128+
mod test {
129+
use super::Pollard;
130+
use crate::accumulator::node_hash::NodeHash;
131+
use bitcoin_hashes::{sha256::Hash as Data, Hash, HashEngine};
132+
133+
fn hash_from_u8(value: u8) -> NodeHash {
134+
let mut engine = Data::engine();
135+
136+
engine.input(&[value]);
137+
138+
NodeHash::from(Data::from_engine(engine).as_byte_array())
139+
}
140+
141+
#[test]
142+
fn test_add() {
143+
let values = vec![0, 1, 2, 3, 4, 5, 6, 7];
144+
let hashes = values.into_iter().map(|val| hash_from_u8(val)).collect();
145+
146+
let roots = Pollard::add(vec![], hashes, 0);
147+
assert_eq!(
148+
"b151a956139bb821d4effa34ea95c17560e0135d1e4661fc23cedc3af49dac42",
149+
roots[0].data.to_string().as_str(),
150+
);
151+
}
152+
}

0 commit comments

Comments
 (0)