Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeanmichel7 committed Sep 17, 2024
1 parent e60940a commit cbcd31b
Show file tree
Hide file tree
Showing 5 changed files with 398 additions and 7 deletions.
71 changes: 69 additions & 2 deletions packages/consensus/src/types/utreexo.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
//! Read more about utreexo: https://eprint.iacr.org/2019/611.pdf

use super::transaction::OutPoint;
use core::poseidon::PoseidonTrait;
use core::hash::{HashStateTrait, HashStateExTrait};
use core::fmt::{Display, Formatter, Error};
use utils::hash::Digest;

/// Accumulator representation of the state aka "Compact State Node".
/// Part of the chain state.
Expand All @@ -50,7 +53,7 @@ pub trait UtreexoAccumulator {
///
/// Note that this call also pushes old UTXOs "to the left", to a larger subtree.
/// This mechanism ensures that short-lived outputs have small inclusion proofs.
fn add(ref self: UtreexoState, output: OutPoint);
fn add(ref self: UtreexoState, outpoint_hash: felt252);

/// Verifies inclusion proof for a single output.
fn verify(
Expand All @@ -72,6 +75,70 @@ pub trait UtreexoAccumulator {
fn delete_batch(ref self: UtreexoState, proof: @UtreexoBatchProof);
}

// https://eprint.iacr.org/2019/611.pdf Algorithm 1 AddOne
// p18
// To prevent such an attack, we require that the data inserted into the
// accumulator be not just the hash of a TXO, which is controllable by the
// attacker, but instead the concatenation of the TXO data with the block
// hash in which the TXO is confirmed. The attacker does not know the block
// hash before the TXO is confirmed, and it is not alterable by the attacker
// after confirmation (without significant cost). Verifiers, when inserting into
// the accumulator, perform this concatenation themselves after checking the
// proof of work of the block. Inclusion proofs contain this block hash data so
// that the leaf hash value can be correctly computed.
fn parent_hash(left: felt252, right: felt252, _block_hash: Digest) -> felt252 {
let parent_data = (left, right);
PoseidonTrait::new().update_with(parent_data).finalize()
}

pub impl UtreexoAccumulatorImpl of UtreexoAccumulator {
// https://eprint.iacr.org/2019/611.pdf Algorithm 1 AddOne
fn add(ref self: UtreexoState, outpoint_hash: felt252) {
let mut new_roots: Array<Option<felt252>> = Default::default();
let mut n: felt252 = outpoint_hash;
let mut first_none_found: bool = false;

for root in self
.roots {
if (!first_none_found) {
if (root.is_none()) {
first_none_found = true;
new_roots.append(Option::Some(n));
} else {
n = parent_hash((*root).unwrap(), n, 0x0_u256.into());
new_roots.append(Option::None);
}
} else {
new_roots.append(*root);
}
};

//check if end with Option::None
if (new_roots[new_roots.len() - 1].is_some()) {
new_roots.append(Option::None);
}

self.roots = new_roots.span();
self.num_leaves += 1_u64;
}

fn verify(
self: @UtreexoState, output: @OutPoint, proof: @UtreexoProof
) -> Result<(), UtreexoError> {
Result::Ok(())
}

fn delete(ref self: UtreexoState, proof: @UtreexoProof) {}

fn verify_batch(
self: @UtreexoState, outputs: Span<OutPoint>, proof: @UtreexoBatchProof
) -> Result<(), UtreexoError> {
Result::Ok(())
}

fn delete_batch(ref self: UtreexoState, proof: @UtreexoBatchProof) {}
}

#[derive(Drop, Copy, PartialEq)]
pub enum UtreexoError {}

Expand All @@ -97,7 +164,7 @@ pub struct UtreexoBatchProof {

pub impl UtreexoStateDefault of Default<UtreexoState> {
fn default() -> UtreexoState {
UtreexoState { roots: array![].span(), num_leaves: 0, }
UtreexoState { roots: array![Option::None].span(), num_leaves: 0, }
}
}

Expand Down
182 changes: 179 additions & 3 deletions packages/consensus/src/types/utxo_set.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
//! In order to prove that the UTXOs provided actually belong to the set we use either
//! Utreexo accumulator or local cache.

//input contain outpoint contain output
use core::dict::Felt252Dict;
use core::hash::{HashStateTrait, HashStateExTrait};
use core::poseidon::PoseidonTrait;
use super::utreexo::UtreexoState;
use super::transaction::OutPoint;
use super::utreexo::{UtreexoState, UtreexoAccumulator};

#[derive(Default, Destruct)]
pub struct UtxoSet {
Expand All @@ -32,10 +33,18 @@ pub impl UtxoSetImpl of UtxoSetTrait {
}

fn add(ref self: UtxoSet, output: OutPoint) {
let outpoint_hash = PoseidonTrait::new().update_with(output).finalize();
if output.data.cached {
let outpoint_hash = PoseidonTrait::new().update_with(output).finalize();
self.cache.insert(outpoint_hash, true);
} else { // TODO: update utreexo roots
} else {
self.utreexo_state.add(outpoint_hash);
}
}

// coexistant ?
fn leaves_to_add(ref self: UtxoSet, leaves_hash: Array<felt252>) {
for leave in leaves_hash {
self.utreexo_state.add(leave);
}
}

Expand All @@ -50,3 +59,170 @@ pub impl UtxoSetImpl of UtxoSetTrait {
}
}
}

#[cfg(test)]
mod tests {
use super::{UtxoSet, UtxoSetTrait, OutPoint};
use consensus::types::transaction::TxOut;

use core::hash::{HashStateTrait, HashStateExTrait};
use core::poseidon::PoseidonTrait;

#[test]
/// To check the validity of expected fields, there is a python program from ZeroSync
/// https://github.com/ZeroSync/ZeroSync/blob/main/src/utxo_set/bridge_node.py
/// $ python scripts/data/utreexo.py
fn test_utreexo_add1() {
let mut utxo_set: UtxoSet = UtxoSetTrait::new(Default::default());

// https://learnmeabitcoin.com/explorer/tx/b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082#input-0
// coinbase outpoint
let outpoint1 = OutPoint {
txid: 0x0000000000000000000000000000000000000000000000000000000000000000_u256.into(),
vout: 4294967295,
data: TxOut { value: 0, pk_script: @"0x", cached: false },
block_height: 0,
block_time: 0,
is_coinbase: false
};
let outpoint1: felt252 = PoseidonTrait::new().update_with(outpoint1).finalize();

// add first leave to empty utreexo
utxo_set.leaves_to_add(array![outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::Some(0x291F8F5FC449D42C715B529E542F24A80136D18F4A85DE28829CD3DCAAC1B9C),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add first leave");
assert_eq!(utxo_set.utreexo_state.num_leaves, 1);

// add second leave
utxo_set.leaves_to_add(array![outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::None,
Option::Some(0x738A7C495E564574993BBCB6A62D65C3C570BB81C63801066AF8934649F66F6),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add second leave");
assert_eq!(utxo_set.utreexo_state.num_leaves, 2);

// add thirdth leave
utxo_set.leaves_to_add(array![outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::Some(0x291F8F5FC449D42C715B529E542F24A80136D18F4A85DE28829CD3DCAAC1B9C),
Option::Some(0x738A7C495E564574993BBCB6A62D65C3C570BB81C63801066AF8934649F66F6),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add thirdth leave");
assert_eq!(utxo_set.utreexo_state.num_leaves, 3);

// add fourth leave
utxo_set.leaves_to_add(array![outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::None,
Option::None,
Option::Some(0x25D0DE35DD446E3D35504866FD7A04D4245E01B5908E19EAA70ABA84DD5A1F1),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add fourth leave");
assert_eq!(utxo_set.utreexo_state.num_leaves, 4);

// add fifth leave
utxo_set.leaves_to_add(array![outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::Some(0x291F8F5FC449D42C715B529E542F24A80136D18F4A85DE28829CD3DCAAC1B9C),
Option::None,
Option::Some(0x25D0DE35DD446E3D35504866FD7A04D4245E01B5908E19EAA70ABA84DD5A1F1),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add fifth leave");
assert_eq!(utxo_set.utreexo_state.num_leaves, 5);

// add 3 leaves
utxo_set.leaves_to_add(array![outpoint1, outpoint1, outpoint1]);
let expected: Span<Option<felt252>> = array![
Option::None,
Option::None,
Option::None,
Option::Some(0x708EB39E30B035376EC871F8F17CD3BADAE6A68406B13C3BB671009D56F5AD),
Option::None
]
.span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add 3 leaves");
assert_eq!(utxo_set.utreexo_state.num_leaves, 8);

// add 22 leaves
utxo_set
.leaves_to_add(
array![
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1,
outpoint1
]
);
let expected: Span<Option<felt252>> = [
Option::None(()),
Option::Some(0x738A7C495E564574993BBCB6A62D65C3C570BB81C63801066AF8934649F66F6),
Option::Some(0x25D0DE35DD446E3D35504866FD7A04D4245E01B5908E19EAA70ABA84DD5A1F1),
Option::Some(0x708EB39E30B035376EC871F8F17CD3BADAE6A68406B13C3BB671009D56F5AD),
Option::Some(0x58D6BEF6CFC28638FB4C8271355961F50922BCC1577DD2B6D04E11B7A911702),
Option::None(())
].span();
assert_eq!(utxo_set.utreexo_state.roots, expected, "cannot add 22 leaves");
assert_eq!(utxo_set.utreexo_state.num_leaves, 30);
}
///
/// python scripts/data/utreexo.py
///
/// Roots:
/// ['0x0291f8f5fc449d42c715b529e542f24a80136d18f4a85de28829cd3dcaac1b9c', '', '', '', '', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots:
/// ['', '0x0738a7c495e564574993bbcb6a62d65c3c570bb81c63801066af8934649f66f6', '', '', '', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots: ['0x0291f8f5fc449d42c715b529e542f24a80136d18f4a85de28829cd3dcaac1b9c',
/// '0x0738a7c495e564574993bbcb6a62d65c3c570bb81c63801066af8934649f66f6', '', '', '', '', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots: ['', '', '0x025d0de35dd446e3d35504866fd7a04d4245e01b5908e19eaa70aba84dd5a1f1', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots: ['0x0291f8f5fc449d42c715b529e542f24a80136d18f4a85de28829cd3dcaac1b9c', '',
/// '0x025d0de35dd446e3d35504866fd7a04d4245e01b5908e19eaa70aba84dd5a1f1', '', '', '', '', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots: ['', '', '', '0x00708eb39e30b035376ec871f8f17cd3badae6a68406b13c3bb671009d56f5ad',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
///
/// Roots: ['', '0x0738a7c495e564574993bbcb6a62d65c3c570bb81c63801066af8934649f66f6',
/// '0x025d0de35dd446e3d35504866fd7a04d4245e01b5908e19eaa70aba84dd5a1f1',
/// '0x00708eb39e30b035376ec871f8f17cd3badae6a68406b13c3bb671009d56f5ad',
/// '0x058d6bef6cfc28638fb4c8271355961f50922bcc1577dd2b6d04e11b7a911702', '', '', '', '', '',
/// '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
}
2 changes: 1 addition & 1 deletion scripts/data/client.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#set -o pipefail;

base_dir=".client_cache"

echo "WHOUAAAAASH"
start=${1:-0}
end=${2:-100}
step=${3:-1}
Expand Down
3 changes: 2 additions & 1 deletion scripts/data/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
requests==2.32.3
black==24.8.0
flake8==7.1.1
flake8-black==0.3.6
flake8-black==0.3.6
poseidon_py==0.1.5
Loading

0 comments on commit cbcd31b

Please sign in to comment.