clvm_fuzzing/
fuzzing_utils.rs1use chia_sha2::Sha256;
2use clvmr::allocator::{Allocator, NodePtr, SExp};
3use std::collections::HashMap;
4use std::collections::hash_map::Entry;
5
6pub fn hash_atom(buf: &[u8]) -> [u8; 32] {
7 let mut ctx = Sha256::new();
8 ctx.update([1_u8]);
9 ctx.update(buf);
10 ctx.finalize()
11}
12
13pub fn hash_pair(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
14 let mut ctx = Sha256::new();
15 ctx.update([2_u8]);
16 ctx.update(left);
17 ctx.update(right);
18 ctx.finalize()
19}
20
21enum TreeOp {
22 SExp(NodePtr),
23 Cons(NodePtr),
24}
25
26pub fn tree_hash(a: &Allocator, node: NodePtr) -> [u8; 32] {
27 let mut hashes = Vec::<[u8; 32]>::new();
28 let mut ops = vec![TreeOp::SExp(node)];
29 let mut cache = HashMap::<NodePtr, [u8; 32]>::new();
30
31 while let Some(op) = ops.pop() {
32 match op {
33 TreeOp::SExp(node) => match cache.entry(node) {
34 Entry::Occupied(e) => hashes.push(*e.get()),
35 Entry::Vacant(e) => match a.sexp(node) {
36 SExp::Atom => {
37 let hash = hash_atom(a.atom(node).as_ref());
38 e.insert(hash);
39 hashes.push(hash);
40 }
41 SExp::Pair(left, right) => {
42 ops.push(TreeOp::Cons(node));
43 ops.push(TreeOp::SExp(left));
44 ops.push(TreeOp::SExp(right));
45 }
46 },
47 },
48 TreeOp::Cons(node) => {
49 let first = hashes.pop().unwrap();
50 let rest = hashes.pop().unwrap();
51 match cache.entry(node) {
52 Entry::Occupied(e) => hashes.push(*e.get()),
53 Entry::Vacant(e) => {
54 let hash = hash_pair(&first, &rest);
55 e.insert(hash);
56 hashes.push(hash);
57 }
58 }
59 }
60 }
61 }
62
63 assert!(hashes.len() == 1);
64 hashes[0]
65}
66
67pub fn visit_tree(a: &Allocator, node: NodePtr, mut visit: impl FnMut(&Allocator, NodePtr)) {
68 let mut nodes = vec![node];
69 let mut visited_index = 0;
70
71 while nodes.len() > visited_index {
72 match a.sexp(nodes[visited_index]) {
73 SExp::Atom => {}
74 SExp::Pair(left, right) => {
75 nodes.push(left);
76 nodes.push(right);
77 }
78 }
79 visited_index += 1;
80 }
81
82 for node in nodes.into_iter().rev() {
84 visit(a, node);
85 }
86}