Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimized azks #189

Merged
merged 27 commits into from
Jun 2, 2022
Merged

Conversation

eozturk1
Copy link
Contributor

See Issue #186.

With the removal of previous states of HistoryTreeNode, we don't have a need for keeping states for multiple epochs. In result, HistoryTreeNode, HistoryNodeState and HistoryChildState can simply be replaced with TreeNode.

This diff starts this conversion by adding the labels of its (1) left and right children, and (2) its hash to the HistoryTreeNode (not yet re-named). Actual hash updates will be added in the next diffs. Rather than keeping the node hashes at the parent, I will keep them at the node itself.

NOTE: The PR builds with cargo build but not ready for testing. The purpose of the PR is to "get it out there" to get feedback rather than merging it.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Apr 14, 2022
Copy link
Contributor

@slawlor slawlor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits to consider. @eozturk1 are we waiting on @Jasleen1 or @kevinlewi to give it a process pass to see if you're on the right track? There's obviously some clippy and rustfmt issues, but functionally it makes sense to me I think.

use async_recursion::async_recursion;
use log::debug;
use std::convert::TryInto;
use std::marker::{Send, Sync};
use winter_crypto::Hasher;
use winter_crypto::{Hasher};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit ::Hasher

Err(AkdError::HistoryTreeNode(HistoryTreeNodeError::NoChildAtEpoch(epoch, dir_leaf.unwrap())))
}
};
result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if you're just returning result, can you just remove the variable assignment? I.e.

match child_node {
...
}

without the let result = match child_node {...}; result

self.get_value::<_, H>(storage).await?,
let mut leaf_hash = H::hash(&self.hash);
leaf_hash = H::merge(&[
leaf_hash,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: instead of a mut, with multiple assignments can we just do

let leaf_hash = H::merge(&[
  H::hash(&self.hash),
  hash_label::<H>(self.label),
]);

}
Err(e) => Err(AkdError::Storage(e)),
} else {
panic!("Unknown child index or None.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm. I think we're trying to avoid Panic's. Is this something that can never happen? We should then not pass in an optional, or if it could happen return Err

for child in children.iter().take(ARITY) {
let hash_val = optional_history_child_state_to_hash::<H>(child);
new_hash = H::merge(&[new_hash, to_digest::<H>(&hash_val)?]);
// pub(crate) async fn get_value_without_label_at_epoch<S: Storage + Sync + Send, H: Hasher>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is this to be resurrected at some point or just no longer needed? delete it if the latter?

} else if dir == Some(1) {
child_label_to_ret = self.right_child;
} else {
panic!("No child with that index!");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: as before in another spot, are there better options than panic's?

@eozturk1
Copy link
Contributor Author

eozturk1 commented May 9, 2022

@slawlor, @Jasleen1 and I have done an initial pass on the code. This week I'll try and update the tests to matc the new tree construction. I'll also fix the other issues (rustfmt, clippy) and the parts you mentioned.

@eozturk1
Copy link
Contributor Author

eozturk1 commented May 24, 2022

Summary

This PR so far has removed the need for storing states-per-epoch and revised the HistoryTreeNode (referred to as node below) to contain the only (current) state (aka hash), significantly reducing the storage requirements.

Important Changes

  • Each node keeps a label of their left and right children, and its hash.
  • For leaf nodes the hash is over the initial digest and the label. Initial hash is the hash of public key (and epoch, see next steps).
  • For non-leaf nodes, the hash is over the left and right child, and the label.
  • For the root, we use the empty node hash: over the empty value and empty label.
  • The last_epoch has been kept to be used in append-only proofs whereas birth_epoch is not needed anymore.
  • For each call, set_child and update_node_hash writes the updated nodes to the storage for consistency. See below for optimizations over this.
  • Epochs in the functions have been kept for adding them to the hash later.
  • Storage has been removed from function parameters if the function operated on state or children.

Next Steps:

  • Clean up: We should remove the dead-code, debug output, unused HistoryChildState and HistoryNodeState, along with the storage layer code for these nodes.
  • Remove birth epoch: Not needed anymore
  • Clippy: Make sure Clippy passes.
  • Merge with eozturk1:optimized-azks:
  • Difference between get_leaf_node and get_leaf_node_without_hashing: How should they differ?
  • Updating history/audit/lookup tests:
    • tests::test_directory_polling_azks_change
    • tests::test_limited_key_history
    • tests::test_simple_audit
    • tests::test_simple_key_history
    • tests::test_simple_lookup
    • akd_client tests::test_simple_lookup
    • akd_client tests::test_simple_lookup_for_small_tree
    • akd_client tests::test_tombstoned_key_history
  • Updating proof tests:
    • append_only_zks::tests::test_append_only_proof
    • append_only_zks::tests::test_append_only_proof_tiny
    • append_only_zks::tests::test_append_only_proof_very_tiny
    • append_only_zks::tests::test_membership_proof_intermediate
    • append_only_zks::tests::test_membership_proof_permuted
    • append_only_zks::tests::test_nonmembership_proof
    • akd_client tests::test_history_proof_single_epoch
    • akd_client tests::test_history_proof_multiple_epochs
  • High level:
    • memory_tests::test_directory_operations
    • mysql_tests::test_directory_operations
    • mysql_tests::test_lookups
    • mysql_db_tests::test_mysql_db
  • Fix: Verification failure with small trees #144
  • Addition of epoch to the leaf: Leaves should include the latest epoch information in their initial hash. This will allow us to track when a leaf was inserted into the tree.
  • Enabling concurrent read/write operations: During a sequencing operation a node might get updated. This means if a client requests a proof during sequencing, we might return an inconsistent proof (a mix of states from the current and next epochs). To circumvent this, we should keep two hashes in the node and update the second one with the new state while moving the current second state to the first (i.e., shift the state to the left).
    • tests::test_read_during_publish
  • Renaming HistoryTreeNode as TreeNode: No history, only current.

Improvements

  • Tests: We should add more tests for small trees and nodes with non-uniform distribution to increase test coverage for tree creation.
  • Minimizing storage writes: If a node is not written to the storage as soon as it is updated, a dirty-read may occur for consecutive operations. We might be able to minimize these writes by allowing short-term inconsistencies by restructuring the code. Another question to look into is how expensive are these instant-writes? (@afterdusk mentioned we use transactions to minimize the impact)
  • Tree Visualization: Noticed it is hard to track the current state of the tree through logs. Maybe a visual representation could assist us in this?

@kevinlewi
Copy link
Contributor

Discussed in-person with @eozturk1 and @Jasleen1 , let's disable the currently-failing tests and fix clippy, so that we can land and @Jasleen1 can work on top of the changes here (filling in the rest of the checkboxes).

@eozturk1
Copy link
Contributor Author

eozturk1 commented Jun 1, 2022

I have disabled the failing tests and updated the next steps to list those tests.

@kevinlewi
Copy link
Contributor

Not sure what the integration test issue is exactly, but perhaps we can merge into a separate branch so that @Jasleen1 can start working on top of it. cc: @slawlor

@eozturk1 eozturk1 merged commit 3d2f30f into facebook:eozturk1/optimized-azks Jun 2, 2022
@eozturk1 eozturk1 mentioned this pull request Jun 9, 2022
33 tasks
slawlor added a commit that referenced this pull request Jun 23, 2022
* Optimized azks (#189)

* Add left and right child for tree node

* Add hash to HistoryTreeNode

* Update set/get child

* Update hash at parent

* Update hashes in the tree

* Add epoch to set_child for updating last updated epoch

* Remove unnecessary last epoch update (already done in set_child)

* Enable higher level tests

* Update and pass leaf insertion tests

* Pass tree insertion tests

* Remove commented out HistoryTreeNode tests

* Remove commented out unused functions

* Remove printlns

* Remove printlns from AZKS

* Remove storage from function when not needed

* Fix warnings for cargo build and test

* Remove HistoryNodeState and HistoryChildState

* Remove get_epoch_lte_epoch

* Remove HistoryNodeState and HistoryChildState from storage layer

* Remove get_epoch_lte_epoch usage

* Format

* Fix clippy warnings

* Remove birth_epoch

* Disable tests to merge

* Remove needless question mark

* Disable mysql tests

* Disable test_mysql_db test

* Fixed membership and intermediate membership tests

* Fixed non membership tests

* WIP: Fixed key history for optimization

* WIP: Minor bug fixes in key history and updated client to match

* WIP: removed epochs from leaf stored hash

* WIP: Updated audit to match ozks, all but read during publish tests passing

* Minor cleanup

* Added more testing for #144

* Changed HistoryTreeNode to TreeNode

* Uncommented previously commented tests

* Addressed nits

* Removed allow dead code from passing tests

* Removed HistoryTreeNode references, replaced with TreeNode

* Re-ran linting

* Re-ran linting

* Re-ran linting

* Removed birth ep from being read for mysql TreeNode

* Removed birth ep from being read for mysql TreeNode everywhere

* mysql error due to possibly null children for a TreeNode

* Allowing nul for children in mysql -- not working

* Fixing the MySQL db layer

* All tests passing + ran linting

* Fixed descendent spelling

* Reran linting

* Addressing review comments

Co-authored-by: Ercan Ozturk <eoz@fb.com>
Co-authored-by: Harjasleen Malvai <hmalvai@fb.com>
Co-authored-by: Sean Lawlor <seanlawlor@fb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants