Skip to content

Commit

Permalink
feat(nullifier_tree): make empty nullifier tree leaves hash be 0 (Azt…
Browse files Browse the repository at this point in the history
…ecProtocol/barretenberg#360) (AztecProtocol/barretenberg#382)

* feat(nullifier_tree): make empty nullifier tree leaves be 0

* fix: add append zero behaviour and test

* fix: explicit type name

* clean: update class semantics

---------

Co-authored-by: Maddiaa <47148561+cheethas@users.noreply.github.com>
Co-authored-by: cheethas <urmasurda@gmail.com>
Co-authored-by: cheethas <addaboy@gmail.com>
  • Loading branch information
4 people authored Apr 25, 2023
1 parent a9fb463 commit 17ed7b6
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,79 @@ struct nullifier_leaf {
barretenberg::fr hash() const { return stdlib::merkle_tree::hash_multiple_native({ value, nextIndex, nextValue }); }
};

inline std::pair<size_t, bool> find_closest_leaf(std::vector<nullifier_leaf> const& leaves_, fr const& new_value)
/**
* @brief Wrapper for the Nullifier leaf class that allows for 0 values
*
*/
class WrappedNullifierLeaf {

public:
// Initialise with a nullifier leaf
WrappedNullifierLeaf(nullifier_leaf value)
: data(value)
{}
// Initialise an empty leaf
WrappedNullifierLeaf()
: data(std::nullopt)
{}

bool operator==(WrappedNullifierLeaf const&) const = default;

/**
* @brief Pass through the underlying std::optional method
*
* @return true
* @return false
*/
bool has_value() const { return data.has_value(); }

/**
* @brief Return the wrapped nullifier_leaf object
*
* @return nullifier_leaf
*/
nullifier_leaf unwrap() const { return data.value(); }

/**
* @brief Set the wrapped nullifier_leaf object value
*
* @param value
*/
void set(nullifier_leaf value) { data.emplace(value); }

/**
* @brief Return the hash of the wrapped object, other return the zero hash of 0
*
* @return barretenberg::fr
*/
barretenberg::fr hash() const { return data.has_value() ? data.value().hash() : barretenberg::fr::zero(); }

/**
* @brief Generate a zero leaf (call the constructor with no arguments)
*
* @return NullifierLeaf
*/
static WrappedNullifierLeaf zero() { return WrappedNullifierLeaf(); }

private:
// Underlying data
std::optional<nullifier_leaf> data;
};

inline std::pair<size_t, bool> find_closest_leaf(std::vector<WrappedNullifierLeaf> const& leaves_, fr const& new_value)
{
std::vector<uint256_t> diff;
bool repeated = false;
auto new_value_ = uint256_t(new_value);

for (size_t i = 0; i < leaves_.size(); i++) {
auto leaf_value_ = uint256_t(leaves_[i].value);

if (!leaves_[i].has_value()) {
diff.push_back(new_value_);
continue;
}

auto leaf_value_ = uint256_t(leaves_[i].unwrap().value);
if (leaf_value_ > new_value_) {
diff.push_back(leaf_value_);
} else if (leaf_value_ == new_value_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ NullifierMemoryTree::NullifierMemoryTree(size_t depth)
total_size_ = 1UL << depth_;
hashes_.resize(total_size_ * 2 - 2);

// Build the entire tree.
nullifier_leaf zero_leaf = { 0, 0, 0 };
leaves_.push_back(zero_leaf);
auto current = zero_leaf.hash();
update_element(0, current);
// Build the entire tree and fill with 0 hashes.
auto current = WrappedNullifierLeaf::zero().hash();
size_t layer_size = total_size_;
for (size_t offset = 0; offset < hashes_.size(); offset += layer_size, layer_size /= 2) {
for (size_t i = 0; i < layer_size; ++i) {
Expand All @@ -25,30 +22,45 @@ NullifierMemoryTree::NullifierMemoryTree(size_t depth)
current = hash_pair_native(current, current);
}

root_ = current;
// Insert the initial leaf at index 0
auto initial_leaf = WrappedNullifierLeaf(nullifier_leaf{ .value = 0, .nextIndex = 0, .nextValue = 0 });
leaves_.push_back(initial_leaf);
root_ = update_element(0, initial_leaf.hash());
}

fr NullifierMemoryTree::update_element(fr const& value)
{
// Find the leaf with the value closest and less than `value`

// If value is 0 we simply append 0 a null NullifierLeaf to the tree
if (value == 0) {
auto zero_leaf = WrappedNullifierLeaf::zero();
leaves_.push_back(zero_leaf);
return update_element(leaves_.size() - 1, zero_leaf.hash());
}

size_t current;
bool is_already_present;
std::tie(current, is_already_present) = find_closest_leaf(leaves_, value);

nullifier_leaf current_leaf = leaves_[current].unwrap();
nullifier_leaf new_leaf = { .value = value,
.nextIndex = leaves_[current].nextIndex,
.nextValue = leaves_[current].nextValue };
.nextIndex = current_leaf.nextIndex,
.nextValue = current_leaf.nextValue };

if (!is_already_present) {
// Update the current leaf to point it to the new leaf
leaves_[current].nextIndex = leaves_.size();
leaves_[current].nextValue = value;
current_leaf.nextIndex = leaves_.size();
current_leaf.nextValue = value;

leaves_[current].set(current_leaf);

// Insert the new leaf with (nextIndex, nextValue) of the current leaf
leaves_.push_back(new_leaf);
}

// Update the old leaf in the tree
auto old_leaf_hash = leaves_[current].hash();
auto old_leaf_hash = current_leaf.hash();
size_t old_leaf_index = current;
auto root = update_element(old_leaf_index, old_leaf_hash);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ using namespace barretenberg;
* nextVal 10 50 20 30 0 0 0 0
*/
class NullifierMemoryTree : public MemoryTree {

public:
NullifierMemoryTree(size_t depth);

Expand All @@ -78,15 +79,18 @@ class NullifierMemoryTree : public MemoryTree {
fr update_element(fr const& value);

const std::vector<barretenberg::fr>& get_hashes() { return hashes_; }
const std::vector<nullifier_leaf>& get_leaves() { return leaves_; }
const nullifier_leaf& get_leaf(size_t index) { return leaves_[index]; }
const WrappedNullifierLeaf get_leaf(size_t index)
{
return (index < leaves_.size()) ? leaves_[index] : WrappedNullifierLeaf::zero();
}
const std::vector<WrappedNullifierLeaf>& get_leaves() { return leaves_; }

protected:
using MemoryTree::depth_;
using MemoryTree::hashes_;
using MemoryTree::root_;
using MemoryTree::total_size_;
std::vector<nullifier_leaf> leaves_;
std::vector<WrappedNullifierLeaf> leaves_;
};

} // namespace merkle_tree
Expand Down
Loading

0 comments on commit 17ed7b6

Please sign in to comment.