Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
nullifier_memory_tree.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Nishat], commit: 22d6fc368da0fbe5412f4f7b2890a052aa48d803 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8#include "../hash.hpp"
9#include "../memory_tree.hpp"
12#include "nullifier_leaf.hpp"
13
15
74template <typename HashingPolicy> class NullifierMemoryTree : public MemoryTree<HashingPolicy> {
75
76 public:
77 NullifierMemoryTree(size_t depth, size_t initial_size = 2);
78
79 using MemoryTree<HashingPolicy>::get_hash_path;
80 using MemoryTree<HashingPolicy>::get_sibling_path;
81 using MemoryTree<HashingPolicy>::root;
82 using MemoryTree<HashingPolicy>::update_element;
83
85
86 const std::vector<bb::fr>& get_hashes() { return hashes_; }
93
94 protected:
95 using MemoryTree<HashingPolicy>::depth_;
96 using MemoryTree<HashingPolicy>::hashes_;
97 using MemoryTree<HashingPolicy>::root_;
98 using MemoryTree<HashingPolicy>::total_size_;
100};
101
102template <typename HashingPolicy>
104 : MemoryTree<HashingPolicy>(depth)
105{
107 BB_ASSERT_LTE(depth, 32U);
108 BB_ASSERT_GT(initial_size, 0U);
109 total_size_ = 1UL << depth_;
110 hashes_.resize(total_size_ * 2 - 2);
111
112 // Build the entire tree and fill with 0 hashes.
113 // auto current = WrappedNullifierLeaf<HashingPolicy>(nullifier_leaf::zero()).hash();
114 auto current = fr::zero();
115 size_t layer_size = total_size_;
116 for (size_t offset = 0; offset < hashes_.size(); offset += layer_size, layer_size /= 2) {
117 for (size_t i = 0; i < layer_size; ++i) {
118 hashes_[offset + i] = current;
119 }
120 current = HashingPolicy::hash_pair(current, current);
121 }
122
123 // Insert the initial leaves
124 for (size_t i = 0; i < initial_size; i++) {
125 auto initial_leaf = WrappedNullifierLeaf<HashingPolicy>(
126 indexed_nullifier_leaf{ .value = i, .nextIndex = i + 1, .nextValue = i + 1 });
127 leaves_.push_back(initial_leaf);
128 }
129
131 indexed_nullifier_leaf{ .value = leaves_[initial_size - 1].unwrap().value, .nextIndex = 0, .nextValue = 0 });
132
133 for (size_t i = 0; i < initial_size; ++i) {
134 update_element(i, leaves_[i].hash());
135 }
136}
137
139{
140 // Find the leaf with the value closest and less than `value`
141
142 // If value is 0 we simply append 0 a null NullifierLeaf to the tree
143 fr_sibling_path hash_path;
144 if (value == 0) {
146 hash_path = get_sibling_path(leaves_.size() - 1);
147 if (leaves_.size() >= total_size_) {
148 throw std::runtime_error("NullifierMemoryTree is full");
149 }
150 leaves_.push_back(zero_leaf);
151 update_element(leaves_.size() - 1, zero_leaf.hash());
152 return hash_path;
153 }
154
155 size_t current;
156 bool is_already_present;
157 std::tie(current, is_already_present) = find_closest_leaf(leaves_, value);
158
159 indexed_nullifier_leaf current_leaf = leaves_[current].unwrap();
160 indexed_nullifier_leaf new_leaf = { .value = value,
161 .nextIndex = current_leaf.nextIndex,
162 .nextValue = current_leaf.nextValue };
163
164 if (!is_already_present) {
165 // Update the current leaf to point it to the new leaf
166 current_leaf.nextIndex = leaves_.size();
167 current_leaf.nextValue = value;
168
169 leaves_[current].set(current_leaf);
170
171 if (leaves_.size() >= total_size_) {
172 throw std::runtime_error("NullifierMemoryTree is full");
173 }
174
175 // Insert the new leaf with (nextIndex, nextValue) of the current leaf
176 leaves_.push_back(new_leaf);
177 }
178
179 hash_path = get_sibling_path(current);
180 // Update the old leaf in the tree
181 auto old_leaf_hash = HashingPolicy::hash(current_leaf.get_hash_inputs());
182 size_t old_leaf_index = current;
183 auto root = update_element(old_leaf_index, old_leaf_hash);
184
185 // Insert the new leaf in the tree
186 auto new_leaf_hash = HashingPolicy::hash(new_leaf.get_hash_inputs());
187 size_t new_leaf_index = is_already_present ? old_leaf_index : leaves_.size() - 1;
188 root = update_element(new_leaf_index, new_leaf_hash);
189
190 return hash_path;
191}
192
193} // namespace bb::crypto::merkle_tree
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:113
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
fr_hash_path get_hash_path(size_t index) const
fr_sibling_path get_sibling_path(size_t index) const
std::vector< WrappedNullifierLeaf< HashingPolicy > > leaves_
const WrappedNullifierLeaf< HashingPolicy > get_leaf(size_t index)
const std::vector< WrappedNullifierLeaf< HashingPolicy > > & get_leaves()
NullifierMemoryTree(size_t depth, size_t initial_size=2)
Wrapper for the Nullifier leaf class that allows for 0 values.
static WrappedNullifierLeaf< HashingPolicy > zero()
Generate a zero leaf (call the constructor with no arguments)
ssize_t offset
Definition engine.cpp:62
std::pair< size_t, bool > find_closest_leaf(std::vector< WrappedNullifierLeaf< HashingPolicy > > const &leaves_, fr const &new_value)
std::vector< fr > fr_sibling_path
Definition hash_path.hpp:14
fr_sibling_path get_sibling_path(TypeOfTree &tree, index_t index, bool includeUncommitted=true, bool expected_success=true)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field zero()