Skip to content

Commit

Permalink
compute merkle root implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mubarak23 committed Aug 8, 2024
1 parent 9f1e27c commit 2cc25ee
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 48 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;
88 changes: 88 additions & 0 deletions src/merkle_tree.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use super::utils::double_sha256;

pub fn merkle_root(ref txids: Array<u256>) -> u256 {
let len = txids.len();
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};
use starknet::core::types::FieldElement;

#[test]
fn test_merkle_root() {
let txids = vec![
FieldElement::from_hex_be(
"50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38"
)
.unwrap(),
FieldElement::from_hex_be(
"96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6"
)
.unwrap(),
FieldElement::from_hex_be(
"65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4"
)
.unwrap(),
FieldElement::from_hex_be(
"1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815"
)
.unwrap(),
FieldElement::from_hex_be(
"ec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712"
)
.unwrap(),
FieldElement::from_hex_be(
"5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50"
)
.unwrap(),
FieldElement::from_hex_be(
"0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615"
)
.unwrap(),
FieldElement::from_hex_be(
"d94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711"
)
.unwrap(),
FieldElement::from_hex_be(
"c4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a"
)
.unwrap(),
FieldElement::from_hex_be(
"d4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542"
)
.unwrap(),
FieldElement::from_hex_be(
"b5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351"
)
.unwrap(),
FieldElement::from_hex_be(
"f9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f"
)
.unwrap(),
];
let expected_merkle_root = FieldElement::from_hex_be(
"17663ab10c2e13d92dccb4514b05b18815f5f38af1f21e06931c71d62b36d8af"
)
.unwrap();
assert_eq!(merkle_root(txids), expected_merkle_root);
}
}

26 changes: 24 additions & 2 deletions src/utils.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use core::traits::Into;
use core::traits::TryInto;
use core::sha256::{compute_sha256_byte_array, compute_sha256_u32_array};

// Bitwise shift left for u256
pub fn shl(value: u256, shift: u32) -> u256 {
Expand Down Expand Up @@ -34,3 +33,26 @@ pub fn fast_pow(base: u256, exp: u32) -> u256 {
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(),
}
}
49 changes: 3 additions & 46 deletions src/validation.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::merkle_tree::merkle_root;
use super::utils::{shl, shr, double_sha256};
use super::state::{Block, ChainState, Transaction, UtreexoState};
use super::utils::{shl, shr};

const MAX_TARGET: u256 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000;

Expand Down Expand Up @@ -101,45 +102,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
let exponent: u32 = (bits / 0x1000000);
let mantissa: u32 = bits & 0x00FFFFFF;

// Check if mantissa is valid (should be less than 0x1000000)
if mantissa > 0x7FFFFF && exponent != 0 {
return Result::Err('Invalid mantissa');
}

// Calculate the full target value
let mut target: u256 = mantissa.into();

if exponent == 0 {
// Special case: exponent 0 means we use the mantissa as-is
return Result::Ok(target);
} else if exponent <= 3 {
// For exponents 1, 2, and 3, divide by 256^(3 - exponent) i.e right shift
let shift = 8 * (3 - exponent);
target = shr(target, shift);
} else {
let shift = 8 * (exponent - 3);
target = shl(target, shift);
}

// Ensure the target doesn't exceed the maximum allowed value
if target > MAX_TARGET {
return Result::Err('Target exceeds maximum');
}

Result::Ok(target)
}

pub fn target_to_bits(target: u256) -> Result<u32, felt252> {
if target == 0 {
return Result::Err('Target is zero');
Expand Down Expand Up @@ -193,12 +155,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 2cc25ee

Please sign in to comment.