Skip to content

Commit

Permalink
Merge pull request #36 from Davidson-Souza/full-pollard
Browse files Browse the repository at this point in the history
Full pollard
  • Loading branch information
Davidson-Souza authored Aug 11, 2023
2 parents e0e4046 + 275dc77 commit 36461fe
Show file tree
Hide file tree
Showing 9 changed files with 1,034 additions and 27 deletions.
39 changes: 39 additions & 0 deletions examples/full-accumulator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! An example of a full accumulator. A full accumulator is an accumulator that holds all the
//! elements in the set. It's meant for full nodes, that need to prove membership of arbitrary
//! elements. Clients that only need to verify membership should use a Stump instead.
//!

use std::str::FromStr;

use rustreexo::accumulator::{node_hash::NodeHash, pollard::Pollard, proof::Proof, stump::Stump};

fn main() {
let elements = vec![
NodeHash::from_str("b151a956139bb821d4effa34ea95c17560e0135d1e4661fc23cedc3af49dac42")
.unwrap(),
NodeHash::from_str("d3bd63d53c5a70050a28612a2f4b2019f40951a653ae70736d93745efb1124fa")
.unwrap(),
];
// Create a new Pollard, and add the utxos to it
let mut p = Pollard::new();
p.modify(&elements, &[]).unwrap();

// Create a proof that the first utxo is in the Pollard
let (proof, del_hashes) = p.prove(&[elements[0]]).unwrap();
// Verify the proof. Notice how we use the del_hashes returned by `prove` here.
let s = Stump::new()
.modify(&elements, &[], &Proof::default())
.unwrap()
.0;
assert_eq!(s.verify(&proof, &del_hashes,), Ok(true));
// Now we want to update the Pollard, by removing the first utxo, and adding a new one.
// This would be in case we received a new block with a transaction spending the first utxo,
// and creating a new one.
let new_utxo =
NodeHash::from_str("cac74661f4944e6e1fed35df40da951c6e151e7b0c8d65c3ee37d6dfd3bc3ef7")
.unwrap();
p.modify(&[new_utxo], &[elements[0]]).unwrap();

// Now we can prove that the new utxo is in the Pollard.
let _ = p.prove(&[new_utxo]).unwrap();
}
7 changes: 4 additions & 3 deletions examples/proof-update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ fn main() {
.unwrap();
// This should be a valid proof over 0 and 1.
assert_eq!(p.targets(), 2);
assert_eq!(p.verify(&cached_hashes, &s), Ok(true));
assert_eq!(s.verify(&p, &cached_hashes), Ok(true));

// Get a subset of the proof, for the first UTXO only
let p1 = p.get_proof_subset(&cached_hashes, &[0], s.leaves).unwrap();

assert_eq!(p1.verify(&cached_hashes, &s), Ok(true));
assert_eq!(s.verify(&p1, &cached_hashes), Ok(true));

// Assume we have a block that (beyond coinbase) spends our UTXO `0` and creates 7 new UTXOs
// We'll remove `0` as it got spent, and add 1..7 to our cache.
Expand All @@ -57,7 +57,8 @@ fn main() {
update_data,
)
.unwrap();
assert_eq!(p2.verify(&cached_hashes, &stump), Ok(true));
// This should be a valid proof over 1..7
assert_eq!(stump.verify(&p2, &cached_hashes), Ok(true));
}

/// Returns the hashes for UTXOs in the first block in this fictitious example, there's nothing
Expand Down
7 changes: 3 additions & 4 deletions examples/simple-stump-update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn main() {
.0;
// Create a proof that the first utxo is in the Stump.
let proof = Proof::new(vec![0], vec![utxos[1]]);
assert_eq!(proof.verify(&[utxos[0]], &s), Ok(true));
assert_eq!(s.verify(&proof, &[utxos[0]]), Ok(true));

// Now we want to update the Stump, by removing the first utxo, and adding a new one.
// This would be in case we received a new block with a transaction spending the first utxo,
Expand All @@ -35,9 +35,8 @@ fn main() {
NodeHash::from_str("d3bd63d53c5a70050a28612a2f4b2019f40951a653ae70736d93745efb1124fa")
.unwrap();
let s = s.modify(&[new_utxo], &[utxos[0]], &proof).unwrap().0;

// Now we can verify that the new utxo is in the Stump, and the old one is not.
let new_proof = Proof::new(vec![2], vec![new_utxo]);
assert_eq!(new_proof.verify(&[new_utxo], &s), Ok(true));
assert_eq!(proof.verify(&[utxos[0]], &s), Ok(false));
assert_eq!(s.verify(&new_proof, &[new_utxo]), Ok(true));
assert_eq!(s.verify(&proof, &[utxos[0]]), Ok(false));
}
1 change: 1 addition & 0 deletions src/accumulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! only keeps the accumulator's roots, it still trustlessly update this state, not requiring
//! a trusted third party to learn about the current state.
pub mod node_hash;
pub mod pollard;
pub mod proof;
pub mod stump;
pub(super) mod util;
26 changes: 23 additions & 3 deletions src/accumulator/node_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,17 @@
//! assert_eq!(parent, expected_parent);
//! ```
use bitcoin_hashes::{hex, sha256, sha512_256, Hash, HashEngine};
use std::{convert::TryFrom, fmt::Display, ops::Deref, str::FromStr};
use std::{
convert::TryFrom,
fmt::{Debug, Display},
ops::Deref,
str::FromStr,
};

#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, PartialOrd, Ord)]
#[derive(Eq, PartialEq, Copy, Clone, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// NodeHash is a wrapper around a 32 byte array that represents a hash of a node in the tree.
/// # Example
Expand All @@ -52,11 +57,14 @@ use serde::{Deserialize, Serialize};
/// let hash = NodeHash::new([0; 32]);
/// assert_eq!(hash.to_string().as_str(), "0000000000000000000000000000000000000000000000000000000000000000");
/// ```
#[derive(Default)]
pub enum NodeHash {
#[default]
Empty,
Placeholder,
Some([u8; 32]),
}

impl Deref for NodeHash {
type Target = [u8; 32];

Expand All @@ -80,7 +88,19 @@ impl Display for NodeHash {
}
}
}

impl Debug for NodeHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
if let NodeHash::Some(ref inner) = self {
let mut s = String::new();
for byte in inner.iter() {
s.push_str(&format!("{:02x}", byte));
}
write!(f, "{}", s)
} else {
write!(f, "empty")
}
}
}
impl From<sha512_256::Hash> for NodeHash {
fn from(hash: sha512_256::Hash) -> Self {
NodeHash::Some(hash.to_byte_array())
Expand Down
Loading

0 comments on commit 36461fe

Please sign in to comment.