1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::{prelude::*, utils};
use alloc::collections::BTreeMap;
pub fn is_left_index(index: usize) -> bool {
index % 2 == 0
}
pub fn get_sibling_index(index: usize) -> usize {
if is_left_index(index) {
return index + 1;
}
index - 1
}
pub fn sibling_indices(indices: &[usize]) -> Vec<usize> {
indices.iter().cloned().map(get_sibling_index).collect()
}
pub fn parent_index(index: usize) -> usize {
if is_left_index(index) {
return index / 2;
}
get_sibling_index(index) / 2
}
pub fn parent_indices(indices: &[usize]) -> Vec<usize> {
let mut parents: Vec<usize> = indices.iter().cloned().map(parent_index).collect();
parents.dedup();
parents
}
pub fn tree_depth(leaves_count: usize) -> usize {
if leaves_count == 1 {
1
} else {
let val = micromath::F32(leaves_count as f32);
val.log2().ceil().0 as usize
}
}
pub fn uneven_layers(tree_leaves_count: usize) -> BTreeMap<usize, usize> {
let mut leaves_count = tree_leaves_count;
let depth = tree_depth(tree_leaves_count);
let mut uneven_layers = BTreeMap::new();
for index in 0..depth {
let uneven_layer = leaves_count % 2 != 0;
if uneven_layer {
uneven_layers.insert(index, leaves_count);
}
leaves_count = div_ceil(leaves_count, 2);
}
uneven_layers
}
pub fn proof_indices_by_layers(
sorted_leaf_indices: &[usize],
leaves_count: usize,
) -> Vec<Vec<usize>> {
let depth = tree_depth(leaves_count);
let uneven_layers = uneven_layers(leaves_count);
let mut layer_nodes = sorted_leaf_indices.to_vec();
let mut proof_indices: Vec<Vec<usize>> = Vec::new();
for layer_index in 0..depth {
let mut sibling_indices = sibling_indices(&layer_nodes);
if let Some(leaves_count) = uneven_layers.get(&layer_index) {
if let Some(layer_last_node_index) = layer_nodes.last() {
if *layer_last_node_index == leaves_count - 1 {
sibling_indices.pop();
}
}
}
let proof_nodes_indices = utils::collections::difference(&sibling_indices, &layer_nodes);
proof_indices.push(proof_nodes_indices);
layer_nodes = parent_indices(&layer_nodes);
}
proof_indices
}
pub fn div_ceil(x: usize, y: usize) -> usize {
x / y + if x % y != 0 { 1 } else { 0 }
}