refactor: break up accumulator work

buddies-main-deployment
James Prestwich 4 years ago
parent a715cb3d55
commit 445bdd0ce6
No known key found for this signature in database
GPG Key ID: 75A7F5C06D747046
  1. 159
      rust/optics-core/src/accumulator.rs
  2. 69
      rust/optics-core/src/accumulator/incremental.rs
  3. 32
      rust/optics-core/src/accumulator/merkle.rs
  4. 40
      rust/optics-core/src/accumulator/mod.rs
  5. 91
      rust/optics-core/src/accumulator/prover.rs
  6. 9
      rust/optics-core/src/home.rs
  7. 7
      rust/optics-core/src/lib.rs

@ -1,159 +0,0 @@
use crate::{
merkle::{verify_merkle_proof, MerkleTree, ZERO_HASHES},
*,
};
use ethers_core::types::H256;
use sha3::Keccak256;
pub const TREE_DEPTH: usize = 32;
pub const MAX_MESSAGES: u32 = u32::MAX;
#[derive(Debug, Clone, Copy)]
pub struct Proof {
leaf: H256,
index: usize,
path: [H256; TREE_DEPTH],
}
#[derive(Debug, Clone, Copy)]
pub struct IncrementalMerkle {
branch: [H256; TREE_DEPTH],
count: u32,
}
fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
let mut k = Keccak256::new();
k.update(left.as_ref());
k.update(right.as_ref());
let digest = k.finalize();
H256::from_slice(digest.as_slice())
}
impl Default for IncrementalMerkle {
fn default() -> Self {
let mut branch: [H256; TREE_DEPTH] = Default::default();
branch
.iter_mut()
.enumerate()
.for_each(|(i, elem)| *elem = ZERO_HASHES[i]);
Self { branch, count: 0 }
}
}
impl IncrementalMerkle {
pub fn ingest(&mut self, element: H256) {
let mut node = element;
self.count += 1;
let mut size = self.count;
for i in 0..TREE_DEPTH {
if (size & 1) == 1 {
self.branch[i] = node;
return;
}
node = hash_concat(self.branch[i], node);
size /= 2;
}
unreachable!()
}
pub fn root(&self) -> H256 {
let mut node: H256 = Default::default();
let mut size = self.count;
self.branch.iter().enumerate().for_each(|(i, elem)| {
node = if (size & 1) == 1 {
hash_concat(elem, node)
} else {
hash_concat(node, ZERO_HASHES[i])
};
size /= 2;
});
node
}
pub fn count(&self) -> u32 {
self.count
}
pub fn branch(&self) -> &[H256; TREE_DEPTH] {
&self.branch
}
}
#[derive(Debug)]
pub struct IncrementalMerkleProver {
light: IncrementalMerkle,
full: MerkleTree,
}
impl Default for IncrementalMerkleProver {
fn default() -> Self {
let light = IncrementalMerkle::default();
let full = MerkleTree::create(&[], TREE_DEPTH);
Self { light, full }
}
}
impl IncrementalMerkleProver {
pub fn ingest(&mut self, element: H256) -> H256 {
self.light.ingest(element);
self.full.push_leaf(element, TREE_DEPTH).unwrap();
debug_assert_eq!(self.light.root(), self.full.hash());
self.full.hash()
}
pub fn root(&self) -> H256 {
self.full.hash()
}
pub fn count(&self) -> u32 {
self.light.count()
}
pub fn prove(&self, index: usize) -> Result<Proof, ()> {
if index > u32::MAX as usize {
return Err(());
}
let (leaf, hashes) = self.full.generate_proof(index, TREE_DEPTH);
let mut path = [H256::zero(); 32];
path.copy_from_slice(&hashes[..32]);
Ok(Proof { leaf, index, path })
}
pub fn verify(&self, proof: &Proof) -> Result<(), ()> {
if verify_merkle_proof(
proof.leaf,
proof.path.as_ref(),
TREE_DEPTH,
proof.index,
self.root(),
) {
Ok(())
} else {
Err(())
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_test() {
let mut tree = IncrementalMerkleProver::default();
let elements: Vec<_> = (1..32).map(|i| H256::repeat_byte(i as u8)).collect();
tree.ingest(elements[0]);
tree.ingest(elements[1]);
tree.ingest(elements[2]);
assert_eq!(tree.count(), 3);
let idx = 1;
let proof = tree.prove(idx).unwrap();
dbg!(&proof);
tree.verify(&proof).unwrap();
}
}

@ -0,0 +1,69 @@
use crate::accumulator::{TREE_DEPTH, ZERO_HASHES};
use ethers_core::types::H256;
use sha3::{Digest, Keccak256};
#[derive(Debug, Clone, Copy)]
pub struct IncrementalMerkle {
branch: [H256; TREE_DEPTH],
count: u32,
}
fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
let mut k = Keccak256::new();
k.update(left.as_ref());
k.update(right.as_ref());
let digest = k.finalize();
H256::from_slice(digest.as_slice())
}
impl Default for IncrementalMerkle {
fn default() -> Self {
let mut branch: [H256; TREE_DEPTH] = Default::default();
branch
.iter_mut()
.enumerate()
.for_each(|(i, elem)| *elem = ZERO_HASHES[i]);
Self { branch, count: 0 }
}
}
impl IncrementalMerkle {
pub fn ingest(&mut self, element: H256) {
let mut node = element;
self.count += 1;
let mut size = self.count;
for i in 0..TREE_DEPTH {
if (size & 1) == 1 {
self.branch[i] = node;
return;
}
node = hash_concat(self.branch[i], node);
size /= 2;
}
unreachable!()
}
pub fn root(&self) -> H256 {
let mut node: H256 = Default::default();
let mut size = self.count;
self.branch.iter().enumerate().for_each(|(i, elem)| {
node = if (size & 1) == 1 {
hash_concat(elem, node)
} else {
hash_concat(node, ZERO_HASHES[i])
};
size /= 2;
});
node
}
pub fn count(&self) -> u32 {
self.count
}
pub fn branch(&self) -> &[H256; TREE_DEPTH] {
&self.branch
}
}

@ -1,8 +1,8 @@
use ethers_core::types::H256;
use lazy_static::lazy_static;
use sha3::{Digest, Keccak256};
use thiserror::Error;
use crate::accumulator::{hash_concat, EMPTY_SLICE, ZERO_HASHES, ZERO_NODES};
// Some code has been derived from
// https://github.com/sigp/lighthouse/blob/c6baa0eed131c5e8ecc5860778ffc7d4a4c18d2d/consensus/merkle_proof/src/lib.rs#L25
// It has been modified as follows:
@ -12,34 +12,6 @@ use thiserror::Error;
// - remove ring dependency
// In accordance with its license terms, the apache2 license is reproduced below
const MAX_TREE_DEPTH: usize = 32;
const EMPTY_SLICE: &[H256] = &[];
fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
H256::from_slice(
Keccak256::new()
.chain(left.as_ref())
.chain(right.as_ref())
.finalize()
.as_slice(),
)
}
lazy_static! {
/// Zero nodes to act as "synthetic" left and right subtrees of other zero nodes.
pub static ref ZERO_NODES: Vec<MerkleTree> = {
(0..=MAX_TREE_DEPTH).map(MerkleTree::Zero).collect()
};
pub static ref ZERO_HASHES: [H256; MAX_TREE_DEPTH + 1] = {
let mut hashes = [H256::zero(); MAX_TREE_DEPTH + 1];
for i in 0..MAX_TREE_DEPTH {
hashes[i + 1] = hash_concat(hashes[i], hashes[i]);
}
hashes
};
}
/// Right-sparse Merkle tree.
///
/// Efficiently represents a Merkle tree of fixed depth where only the first N

@ -0,0 +1,40 @@
pub mod incremental;
pub mod merkle;
pub mod prover;
pub use prover::Prover;
use ethers_core::types::H256;
use lazy_static::lazy_static;
use sha3::{Digest, Keccak256};
const TREE_DEPTH: usize = 32;
const EMPTY_SLICE: &[ethers_core::types::H256] = &[];
pub(super) fn hash(preimage: impl AsRef<[u8]>) -> H256 {
H256::from_slice(Keccak256::digest(preimage.as_ref()).as_slice())
}
pub(super) fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
H256::from_slice(
Keccak256::new()
.chain(left.as_ref())
.chain(right.as_ref())
.finalize()
.as_slice(),
)
}
lazy_static! {
/// Zero nodes to act as "synthetic" left and right subtrees of other zero nodes.
pub static ref ZERO_NODES: Vec<merkle::MerkleTree> = {
(0..=TREE_DEPTH).map(merkle::MerkleTree::Zero).collect()
};
pub static ref ZERO_HASHES: [H256; TREE_DEPTH + 1] = {
let mut hashes = [H256::zero(); TREE_DEPTH + 1];
for i in 0..TREE_DEPTH {
hashes[i + 1] = hash_concat(hashes[i], hashes[i]);
}
hashes
};
}

@ -0,0 +1,91 @@
use crate::accumulator::{
incremental::IncrementalMerkle,
merkle::{verify_merkle_proof, MerkleTree},
TREE_DEPTH,
};
use ethers_core::types::H256;
#[derive(Debug, Clone, Copy)]
pub struct Proof {
leaf: H256,
index: usize,
path: [H256; TREE_DEPTH],
}
#[derive(Debug)]
pub struct Prover {
light: IncrementalMerkle,
full: MerkleTree,
}
impl Default for Prover {
fn default() -> Self {
let light = IncrementalMerkle::default();
let full = MerkleTree::create(&[], TREE_DEPTH);
Self { light, full }
}
}
impl Prover {
pub fn ingest(&mut self, element: H256) -> H256 {
self.light.ingest(element);
self.full.push_leaf(element, TREE_DEPTH).unwrap();
debug_assert_eq!(self.light.root(), self.full.hash());
self.full.hash()
}
pub fn root(&self) -> H256 {
self.full.hash()
}
pub fn count(&self) -> u32 {
self.light.count()
}
pub fn prove(&self, index: usize) -> Result<Proof, ()> {
if index > u32::MAX as usize {
return Err(());
}
let (leaf, hashes) = self.full.generate_proof(index, TREE_DEPTH);
let mut path = [H256::zero(); 32];
path.copy_from_slice(&hashes[..32]);
Ok(Proof { leaf, index, path })
}
pub fn verify(&self, proof: &Proof) -> Result<(), ()> {
if verify_merkle_proof(
proof.leaf,
proof.path.as_ref(),
TREE_DEPTH,
proof.index,
self.root(),
) {
Ok(())
} else {
Err(())
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_test() {
let mut tree = Prover::default();
let elements: Vec<_> = (1..32).map(|i| H256::repeat_byte(i as u8)).collect();
tree.ingest(elements[0]);
tree.ingest(elements[1]);
tree.ingest(elements[2]);
assert_eq!(tree.count(), 3);
let idx = 1;
let proof = tree.prove(idx).unwrap();
dbg!(&proof);
tree.verify(&proof).unwrap();
}
}

@ -1,7 +1,10 @@
use ethers_core::types::H256;
use ethers_core::types::{Address, H256};
use std::{collections::VecDeque, io::Write};
use crate::{accumulator::*, *};
use crate::{
accumulator::{hash, incremental::IncrementalMerkle},
SignedUpdate, Update,
};
#[derive(Default, Debug, Clone)]
pub struct Waiting {
@ -108,7 +111,7 @@ impl Home<Waiting> {
pub fn enqueue(&mut self, sender: H256, destination: u32, recipient: H256, body: &[u8]) {
let message = format_message(self.origin, sender, destination, recipient, body);
let message_hash = keccak256(message);
let message_hash = hash(&message);
self.state.accumulator.ingest(message_hash);
self.state.queue.push_back(self.state.accumulator.root());
}

@ -1,6 +1,5 @@
pub mod accumulator;
pub mod home;
mod merkle;
pub mod replica;
use ethers_core::types::{Address, Signature, H256};
@ -23,17 +22,13 @@ impl Encode for Signature {
}
}
fn keccak256(buf: impl AsRef<[u8]>) -> H256 {
H256::from_slice(Keccak256::digest(buf.as_ref()).as_slice())
}
fn domain_hash(origin_slip44_id: u32) -> H256 {
H256::from_slice(
Keccak256::new()
.chain(origin_slip44_id.to_be_bytes())
.chain("OPTICS".as_bytes())
.finalize()
.as_slice()
.as_slice(),
)
}

Loading…
Cancel
Save