Skip to content

Commit

Permalink
Merge pull request #42 from keep-starknet-strange/mk/merkle_tree
Browse files Browse the repository at this point in the history
Merkle tree implementation
  • Loading branch information
maciejka authored Aug 9, 2024
2 parents ca21dba + b111786 commit 544e88f
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod validation;

mod state;
mod main;
mod merkle_tree;
90 changes: 90 additions & 0 deletions src/merkle_tree.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use super::utils::double_sha256;

pub fn merkle_root(ref txids: Array<u256>) -> u256 {
let len = txids.len();

if len == 1 {
return *txids.at(0);
}

if len % 2 == 1 {
txids.append(*txids.at(len - 1));
} else {
// CVE-2012-2459 bug fix
assert!(
txids.at(len - 1) != txids.at(len - 2), "unexpected node duplication in merkle tree"
);
}

let mut next_txids = ArrayTrait::new();
let mut i = 0;
while i < len {
next_txids.append(double_sha256(*txids.at(i), *txids.at(i + 1)));
i += 2;
};

merkle_root(ref next_txids)
}

#[cfg(test)]
mod tests {
use super::{merkle_root};

#[test]
#[available_gas(100000000)]
fn test_merkle_root_01() {
let mut txids = array![
0xacd9825be8bece7782ec746a80b52f44d6a8af41c63dbab59b03e29558469682_u256,
];

let expected_merkle_root =
0xacd9825be8bece7782ec746a80b52f44d6a8af41c63dbab59b03e29558469682_u256;

assert_eq!(merkle_root(ref txids), expected_merkle_root);
}

#[test]
#[available_gas(100000000)]
fn test_merkle_root_02() {
let mut txids = array![
0x8710b2819a369672a2bce3d5270e7ae0ea59be2f7ce7f9078341b389098953e0_u256,
0x64efde3a3f3531569cdab031bb31cfeb5c2d8cba62ae1ca5b2913b4ef643fd49_u256
];

let expected_merkle_root =
0x20dadaf81170decafec4b025366b75284dbe31dd42c8da5d25ff62fc4bff5d03_u256;

assert_eq!(merkle_root(ref txids), expected_merkle_root);
}

#[test]
#[available_gas(100000000)]
fn test_merkle_root_03() {
let mut txids = array![
0xd47e03351ee65f73321b684832edc4c840a1fe4bbd04bdb66a8328e5c7796e21_u256,
0xbf304002ea77842b32dc91f1efe681a5a7909f4200e658e2ef2beb2a821101b9_u256,
0x397bdf0bf5a8798f5b10bd95c70bb4a3f42ca14a9a837a4a54cd7de525dc0225_u256,
0xd6ce148117a1cd094cdd5303ae0896cae1b29ad010b6cb0f3d43fa99b5e2c2f7_u256,
0x7d5ad03ebf001acb47aafdf4915e86b7368ed3183c1e95f47280d81bb4ef91f8_u256,
0x69cf63b266ebc862bd4d1a01473703c14bdd3a620f93ec323144c7d2c54529a0_u256,
0x155be8f959b0187d7528a1ff11b3450690047aa96dbbb29a1ae3832b237c8179_u256,
0x727d5fbed290d645ced8776c9031d7c3438454b5faf1f5dc0200dbe84f8e6035_u256,
0xc6056c6021081150a86c092f6785955f757024f41472ad4b0cfd9dd39db8b4a2_u256,
0x83f26f37bb715ec325f25544b6d7ae920fcc073c146c8dd12fbbde31a7ae1d2f_u256,
0xd39bc02ef2b2c5afdb7807b0162b573648d9264d5e9872dbf26a7d480de301cd_u256,
0x3dc087cb9e9d66c4d3e2cf29d23949e7b914db4c3f2114d34f34e97a2a44a169_u256,
0x497d1b0bf7b0c502043fe7201a9696c466f514de3190097ef3b7d0664fc3d0bf_u256,
0xa43dbef675b637c554987e8a1b98be3faf8850f88fa1bdf59b124c2356135a33_u256,
0x4f9cf2c386b34b01d48a01ea31b5c795d1e869b42de78410b3ea1adf658f62a2_u256,
0x46ef4071d3ddfd9443361ef2f4b2d5da7c57eaf59785564782d0d9b95280cb9b_u256,
0xa48c60d6b27fd5c662d7dcd248b528474fd2598d26d51525deea3d225d7260e0_u256,
0x5bb6e10378329bf6e78ce3e0f3abae1fb1c4bc40e1ce1b0e1a5f5db8a7fb1897_u256
];

let expected_merkle_root =
0xe1455aa624aa92fa8b52766199033d66e4d100b39029e69906ae594397d977af_u256;

assert_eq!(merkle_root(ref txids), expected_merkle_root);
}
}

24 changes: 24 additions & 0 deletions src/utils.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::sha256::{compute_sha256_byte_array, compute_sha256_u32_array};
use core::num::traits::{Zero, One, BitSize};
use core::starknet::secp256_trait::Secp256PointTrait;

Expand Down Expand Up @@ -109,3 +110,26 @@ pub fn fast_pow<
base = base * base;
}
}

const TWO_POW_32: u128 = 0x100000000;
const TWO_POW_64: u128 = 0x10000000000000000;
const TWO_POW_96: u128 = 0x1000000000000000000000000;

pub fn double_sha256(a: u256, b: u256) -> u256 {
let mut ba = Default::default();

ba.append_word(a.high.into(), 16);
ba.append_word(a.low.into(), 16);
ba.append_word(b.high.into(), 16);
ba.append_word(b.low.into(), 16);

let mut input1 = Default::default();
input1.append_span(compute_sha256_byte_array(@ba).span());

let [x0, x1, x2, x3, x4, x5, x6, x7] = compute_sha256_u32_array(input1, 0, 0);

u256 {
high: x0.into() * TWO_POW_96 + x1.into() * TWO_POW_64 + x2.into() * TWO_POW_32 + x3.into(),
low: x4.into() * TWO_POW_96 + x5.into() * TWO_POW_64 + x6.into() * TWO_POW_32 + x7.into(),
}
}
15 changes: 3 additions & 12 deletions src/validation.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::state::{Block, ChainState, Transaction, UtreexoState};
use super::merkle_tree::merkle_root;
use super::utils::{shl, shr};
use super::state::{Block, ChainState, Transaction, UtreexoState};

const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000;
pub const REWARD_INITIAL: u256 = 50; // 50 BTC in satoshis => 5000000000 SATS
Expand Down Expand Up @@ -112,11 +113,6 @@ fn adjust_difficulty(self: @ChainState, block: @Block) -> (u32, u32) {
(*self.current_target, *self.epoch_start_time)
}

fn validate_merkle_root(self: @ChainState, block: @Block) -> Result<(), ByteArray> {
// TODO: implement
Result::Ok(())
}

// Helper functions
pub fn bits_to_target(bits: u32) -> Result<u256, felt252> {
// Extract exponent and mantissa
Expand Down Expand Up @@ -204,12 +200,7 @@ fn fee_and_merkle_root(self: @ChainState, block: @Block) -> Result<(u256, u256),
total_fee += tx.fee();
};

Result::Ok((total_fee, merkle_root(txids)))
}

fn merkle_root(txids: Array<u256>) -> u256 {
// TODO: implement
0
Result::Ok((total_fee, merkle_root(ref txids)))
}

fn validate_coinbase(block: @Block, total_fees: u256) -> Result<(), ByteArray> {
Expand Down

0 comments on commit 544e88f

Please sign in to comment.