From 2cc25eec07ac9a8ae18256ac6cbdf53d353d4be0 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 8 Aug 2024 11:37:49 +0100 Subject: [PATCH 1/7] compute merkle root implementation --- src/lib.cairo | 1 + src/merkle_tree.cairo | 88 +++++++++++++++++++++++++++++++++++++++++++ src/utils.cairo | 26 ++++++++++++- src/validation.cairo | 49 ++---------------------- 4 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 src/merkle_tree.cairo diff --git a/src/lib.cairo b/src/lib.cairo index ce41db81..201712a7 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -3,3 +3,4 @@ pub mod validation; mod state; mod main; +mod merkle_tree; diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo new file mode 100644 index 00000000..e04d3d9d --- /dev/null +++ b/src/merkle_tree.cairo @@ -0,0 +1,88 @@ +use super::utils::double_sha256; + +pub fn merkle_root(ref txids: Array) -> 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); + } +} + diff --git a/src/utils.cairo b/src/utils.cairo index 0e542db3..fc4010b0 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -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 { @@ -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(), + } +} diff --git a/src/validation.cairo b/src/validation.cairo index 3ce23b23..177eae3b 100644 --- a/src/validation.cairo +++ b/src/validation.cairo @@ -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; @@ -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 { - // 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 { if target == 0 { return Result::Err('Target is zero'); @@ -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 { - // TODO: implement - 0 + Result::Ok((total_fee, merkle_root(ref txids))) } fn validate_coinbase(block: @Block, total_fees: u256) -> Result<(), ByteArray> { From f9fc168c37e26dfab2165cccf2907650167fddd5 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 8 Aug 2024 14:37:27 +0100 Subject: [PATCH 2/7] fix changes --- src/merkle_tree.cairo | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index e04d3d9d..66836d00 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -28,7 +28,8 @@ mod tests { #[test] fn test_merkle_root() { - let txids = vec![ + + let txids = array![ FieldElement::from_hex_be( "50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38" ) @@ -79,7 +80,7 @@ mod tests { .unwrap(), ]; let expected_merkle_root = FieldElement::from_hex_be( - "17663ab10c2e13d92dccb4514b05b18815f5f38af1f21e06931c71d62b36d8af" + "0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256" ) .unwrap(); assert_eq!(merkle_root(txids), expected_merkle_root); From 651c3148ea6a36da432d7cdcb25f877bf4df1e0a Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 8 Aug 2024 18:55:22 +0100 Subject: [PATCH 3/7] use u256 Array as transaction ids data in test --- src/merkle_tree.cairo | 70 ++++++++++--------------------------------- 1 file changed, 16 insertions(+), 54 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index 533fb8ca..830d40e3 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -30,60 +30,22 @@ mod tests { #[test] fn test_merkle_root() { - let txids = array![ - 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( - "0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256" - ) - .unwrap(); + let txids = array![0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256, + 0x96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6_u256, + 0x65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4_u256, + 0x1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815_u256, + 0xec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712_u256, + 0x5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50_u256, + 0x0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615_256, + 0xd94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711_u256, + 0xc4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a_u256, + 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, + 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, + 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 + ] + + let expected_merkle_root = "0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256" + assert_eq!(merkle_root(txids), expected_merkle_root); } } From 18f05dbc337ddefda149460f342537e68378d360 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 8 Aug 2024 19:03:19 +0100 Subject: [PATCH 4/7] fix end of line --- src/merkle_tree.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index 830d40e3..ca22fc78 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -42,9 +42,9 @@ mod tests { 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 - ] + ]; - let expected_merkle_root = "0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256" + let expected_merkle_root = "0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256"; assert_eq!(merkle_root(txids), expected_merkle_root); } From db66e5d5b3e80b7748c5991b64d21001835b25c9 Mon Sep 17 00:00:00 2001 From: mubarak23 Date: Thu, 8 Aug 2024 21:43:43 +0100 Subject: [PATCH 5/7] use ref in txids --- src/merkle_tree.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index c922e916..a770ebdd 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -24,7 +24,7 @@ pub fn merkle_root(ref txids: Array) -> u256 { #[cfg(test)] mod tests { use super::{merkle_root}; - use starknet::core::types::FieldElement; + #[test] fn test_merkle_root() { @@ -45,6 +45,6 @@ mod tests { let expected_merkle_root = 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256; - assert_eq!(merkle_root(txids), expected_merkle_root); + assert_eq!(merkle_root(ref txids), expected_merkle_root); } } From 178bc9e600b9c2ad3004cd806a975a1da60545a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski=20=40=20StarkWare?= Date: Fri, 9 Aug 2024 14:03:55 +0200 Subject: [PATCH 6/7] fmt --- src/merkle_tree.cairo | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index a770ebdd..d1020477 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -29,18 +29,18 @@ mod tests { #[test] fn test_merkle_root() { let txids = array![ - 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256, - 0x96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6_u256, - 0x65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4_u256, - 0x1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815_u256, - 0xec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712_u256, - 0x5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50_u256, - 0x0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615_u256, - 0xd94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711_u256, - 0xc4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a_u256, - 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, - 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, - 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 + 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256, + 0x96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6_u256, + 0x65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4_u256, + 0x1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815_u256, + 0xec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712_u256, + 0x5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50_u256, + 0x0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615_u256, + 0xd94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711_u256, + 0xc4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a_u256, + 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, + 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, + 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 ]; let expected_merkle_root = 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256; From 1d75d64d97c7b5b9aefa315f4a02d8f2ead22912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski=20=40=20StarkWare?= Date: Fri, 9 Aug 2024 14:06:52 +0200 Subject: [PATCH 7/7] fmt --- src/merkle_tree.cairo | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/merkle_tree.cairo b/src/merkle_tree.cairo index d1020477..89ede39c 100644 --- a/src/merkle_tree.cairo +++ b/src/merkle_tree.cairo @@ -28,20 +28,20 @@ mod tests { #[test] fn test_merkle_root() { - let txids = array![ - 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256, - 0x96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6_u256, - 0x65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4_u256, - 0x1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815_u256, - 0xec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712_u256, - 0x5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50_u256, - 0x0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615_u256, - 0xd94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711_u256, - 0xc4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a_u256, - 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, - 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, - 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 - ]; + let txids = array![ + 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256, + 0x96b8787b1e3abed802cff132c891c2e511edd200b08baa9eb7d8942d7c5423c6_u256, + 0x65e5a4862b807c83b588e0f4122d4ca2d46691d17a1ec1ebce4485dccc3380d4_u256, + 0x1ee9441ddde02f8ffb910613cd509adbc21282c6e34728599f3ae75e972fb815_u256, + 0xec950fc02f71fc06ed71afa4d2c49fcba04777f353a001b0bba9924c63cfe712_u256, + 0x5d874040a77de7182f7a68bf47c02898f519cb3b58092b79fa2cff614a0f4d50_u256, + 0x0a1c958af3e30ad07f659f44f708f8648452d1427463637b9039e5b721699615_u256, + 0xd94d24d2dcaac111f5f638983122b0e55a91aeb999e0e4d58e0952fa346a1711_u256, + 0xc4709bc9f860e5dff01b5fc7b53fb9deecc622214aba710d495bccc7f860af4a_u256, + 0xd4ed5f5e4334c0a4ccce6f706f3c9139ac0f6d2af3343ad3fae5a02fee8df542_u256, + 0xb5aed07505677c8b1c6703742f4558e993d7984dc03d2121d3712d81ee067351_u256, + 0xf9a14bf211c857f61ff9a1de95fc902faebff67c5d4898da8f48c9d306f1f80f_u256 + ]; let expected_merkle_root = 0x50ba87bdd484f07c8c55f76a22982f987c0465fdc345381b4634a70dc0ea0b38_u256;