Conversation
0990433 to
b693be2
Compare
9ad9025 to
cfc92e0
Compare
crates/contracts/Cargo.toml
Outdated
d15e987 to
b574a43
Compare
73349f6 to
6ff66b5
Compare
6ff66b5 to
250295e
Compare
| /// Lock collateral on the storage contract (Mint/Fund operation) | ||
| GetStorageAddress { | ||
| /// Collateral and fee UTXO | ||
| #[arg(long = "collateral-utxo")] | ||
| collateral_utxo: OutPoint, | ||
| /// Collateral amount in satoshis (LBTC) | ||
| #[arg(long = "collateral-amount")] | ||
| collateral_amount: u64, | ||
| /// Miner fee in satoshis (LBTC) | ||
| #[arg(long = "fee-amount")] | ||
| fee_amount: u64, | ||
|
|
||
| /// The initial 32-byte data payload to store in the tree at the specified path | ||
| #[arg(long = "storage-bytes", value_parser = parse_hex_32)] | ||
| storage_bytes: [u8; 32], | ||
| /// The path in the Merkle Tree use for the contract logic (e.g., "rrll...") | ||
| #[arg(long = "path", value_parser = parse_bit_path)] | ||
| path: [bool; DEPTH], | ||
|
|
||
| /// Account that will pay for transaction fees and that owns a tokens to send | ||
| #[arg(long = "account-index", default_value_t = 0)] | ||
| account_index: u32, | ||
| /// When set, broadcast the built transaction via Esplora and print txid | ||
| #[arg(long = "broadcast")] | ||
| broadcast: bool, | ||
| }, |
There was a problem hiding this comment.
This command should not broadcast anything, just print the address to which user can send money
There was a problem hiding this comment.
| pub fn build_smt_mint( | |
| pub fn get_storage_address( |
There was a problem hiding this comment.
Move this todo where the validate_amount is defined
There was a problem hiding this comment.
| let change_recipient_script = collateral_tx_out.script_pubkey.clone(); | |
| let mut pst = PartiallySignedTransaction::new_v2(); | |
| let mut collateral_input = Input::from_prevout(collateral_out_point); | |
| collateral_input.witness_utxo = Some(collateral_tx_out.clone()); | |
| pst.add_input(collateral_input); | |
| pst.add_output(Output::new_explicit( | |
| mint_script_pubkey, | |
| collateral_amount, | |
| collateral_asset_id, | |
| None, | |
| )); | |
| if change_amount > 0 { | |
| pst.add_output(Output::new_explicit( | |
| change_recipient_script, | |
| change_amount, | |
| collateral_asset_id, | |
| None, | |
| )); | |
| } | |
| pst.add_output(Output::from_txout(TxOut::new_fee( | |
| fee_amount, | |
| collateral_asset_id, | |
| ))); | |
| pst.extract_tx()? | |
| .verify_tx_amt_proofs(secp256k1::SECP256K1, &[collateral_tx_out])?; | |
| Ok(pst) | |
| // This should be converted to address | |
| Ok(mint_script_pubkey) |
| use std::collections::HashMap; | ||
|
|
||
| use simplicityhl::num::U256; | ||
| use simplicityhl::types::{ResolvedType, TypeConstructible, UIntType}; | ||
| use simplicityhl::value::{UIntValue, ValueConstructible}; | ||
| use simplicityhl::{WitnessValues, str::WitnessName}; | ||
|
|
||
| #[allow(non_camel_case_types)] | ||
| pub type u256 = [u8; 32]; | ||
| pub const DEPTH: usize = 7; | ||
|
|
||
| #[derive(Debug, Clone, bincode::Encode, bincode::Decode, PartialEq, Eq)] | ||
| pub struct SMTWitness { | ||
| key: u256, | ||
| leaf: u256, | ||
| merkle_data: [(u256, bool); DEPTH], | ||
| } | ||
|
|
||
| impl SMTWitness { | ||
| #[must_use] | ||
| pub fn new(key: &u256, leaf: &u256, merkle_data: &[(u256, bool); DEPTH]) -> Self { | ||
| Self { | ||
| key: *key, | ||
| leaf: *leaf, | ||
| merkle_data: *merkle_data, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Default for SMTWitness { | ||
| fn default() -> Self { | ||
| Self { | ||
| key: [0u8; 32], | ||
| leaf: [0u8; 32], | ||
| merkle_data: [([0u8; 32], false); DEPTH], | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Add more context (documentation) about how practically this witness is going to be used (i.e. explain rrrrrr witness argument)
Also if there are nuances, mention them
There was a problem hiding this comment.
| &control_block(cmr, &old_spend_info).serialize(), /*&control_block.serialize()*/ | |
| &control_block(cmr, &old_spend_info).serialize(), |
| use simplicityhl::simplicity::elements::hashes::HashEngine as _; | ||
| use simplicityhl::simplicity::hashes::{Hash, sha256}; | ||
|
|
||
| use super::build_witness::{DEPTH, u256}; | ||
|
|
||
| #[derive(Debug, Clone, bincode::Encode, bincode::Decode, PartialEq, Eq)] | ||
| pub enum TreeNode { | ||
| Leaf { | ||
| leaf_hash: u256, | ||
| }, | ||
| Branch { | ||
| hash: u256, | ||
| left: Box<TreeNode>, | ||
| right: Box<TreeNode>, | ||
| }, | ||
| } | ||
|
|
||
| impl TreeNode { | ||
| pub fn get_hash(&self) -> u256 { | ||
| match self { | ||
| TreeNode::Leaf { leaf_hash } => *leaf_hash, | ||
| TreeNode::Branch { hash, .. } => *hash, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub struct SparseMerkleTree { | ||
| root: Box<TreeNode>, | ||
| precalculate_hashes: [u256; DEPTH], | ||
| } |
There was a problem hiding this comment.
Add more context and documentation (great if there are any links to external sources)
| impl SparseMerkleTree { | ||
| #[must_use] | ||
| pub fn new() -> Self { | ||
| let mut precalculate_hashes = [[0u8; 32]; DEPTH]; | ||
| let mut eng = sha256::Hash::engine(); | ||
| let zero = [0u8; 32]; | ||
| eng.input(&zero); | ||
| precalculate_hashes[0] = *sha256::Hash::from_engine(eng).as_byte_array(); | ||
|
|
||
| for i in 1..DEPTH { | ||
| let mut eng = sha256::Hash::engine(); | ||
| eng.input(&precalculate_hashes[i - 1]); | ||
| eng.input(&precalculate_hashes[i - 1]); | ||
| precalculate_hashes[i] = *sha256::Hash::from_engine(eng).as_byte_array(); | ||
| } | ||
|
|
||
| Self { | ||
| root: Box::new(TreeNode::Leaf { | ||
| leaf_hash: precalculate_hashes[0], | ||
| }), | ||
| precalculate_hashes, | ||
| } | ||
| } | ||
|
|
||
| fn calculate_hash(left: &mut TreeNode, right: &mut TreeNode) -> u256 { | ||
| let mut eng = sha256::Hash::engine(); | ||
| eng.input(&left.get_hash()); | ||
| eng.input(&right.get_hash()); | ||
| *sha256::Hash::from_engine(eng).as_byte_array() | ||
| } | ||
|
|
||
| // Return array of hashes | ||
| fn traverse( | ||
| defaults: &[u256], | ||
| leaf: &u256, | ||
| path: &[bool], | ||
| root: &mut Box<TreeNode>, | ||
| hashes: &mut [u256], | ||
| ) { | ||
| let Some((is_right, remaining_path)) = path.split_first() else { | ||
| let tag = sha256::Hash::hash(b"TapData"); | ||
| let mut eng = sha256::Hash::engine(); | ||
| eng.input(tag.as_byte_array()); | ||
| eng.input(tag.as_byte_array()); | ||
| eng.input(leaf); | ||
|
|
||
| **root = TreeNode::Leaf { | ||
| leaf_hash: *sha256::Hash::from_engine(eng).as_byte_array(), | ||
| }; | ||
| return; | ||
| }; | ||
|
|
||
| let (child_zero, remaining_defaults) = defaults | ||
| .split_last() | ||
| .expect("Defaults length must match path length"); | ||
|
|
||
| if matches!(**root, TreeNode::Leaf { .. }) { | ||
| let new_branch = Box::new(TreeNode::Branch { | ||
| hash: [0u8; 32], | ||
| left: Box::new(TreeNode::Leaf { | ||
| leaf_hash: *child_zero, | ||
| }), | ||
| right: Box::new(TreeNode::Leaf { | ||
| leaf_hash: *child_zero, | ||
| }), | ||
| }); | ||
|
|
||
| *root = new_branch; | ||
| } | ||
|
|
||
| let (current_hash_slot, remaining_hashes) = hashes | ||
| .split_first_mut() | ||
| .expect("Hashes length must match path length"); | ||
|
|
||
| if let TreeNode::Branch { | ||
| ref mut left, | ||
| ref mut right, | ||
| ref mut hash, | ||
| } = **root | ||
| { | ||
| if *is_right { | ||
| *current_hash_slot = left.get_hash(); | ||
| Self::traverse( | ||
| remaining_defaults, | ||
| leaf, | ||
| remaining_path, | ||
| right, | ||
| remaining_hashes, | ||
| ); | ||
| } else { | ||
| *current_hash_slot = right.get_hash(); | ||
| Self::traverse( | ||
| remaining_defaults, | ||
| leaf, | ||
| remaining_path, | ||
| left, | ||
| remaining_hashes, | ||
| ); | ||
| } | ||
|
|
||
| *hash = Self::calculate_hash(left, right); | ||
| } else { | ||
| unreachable!("Should be a branch at this point"); | ||
| } | ||
| } | ||
|
|
||
| // For insert change 0 to leaf. | ||
| // For delete vice versa. | ||
| // And for udpate change old value to new. | ||
| // Then, recalculate hashes | ||
| pub fn update(&mut self, leaf: &u256, path: [bool; DEPTH]) -> [u256; DEPTH] { | ||
| let mut hashes = self.precalculate_hashes; | ||
| Self::traverse( | ||
| &self.precalculate_hashes, | ||
| leaf, | ||
| &path, | ||
| &mut self.root, | ||
| &mut hashes, | ||
| ); | ||
| hashes | ||
| } | ||
| } |
There was a problem hiding this comment.
Here the same, mention nuances, especially attacks, etc
crates/contracts/Cargo.toml
Outdated
There was a problem hiding this comment.
Do not add rand as a independent dep, use rand from the simplicityhl::elements dep
crates/contracts/Cargo.toml
Outdated
There was a problem hiding this comment.
| swap-with-change = [] |
250295e to
2ca279d
Compare
8035e03 to
d19f4d5
Compare
…tion against second preimage attack
d19f4d5 to
93da027
Compare
No description provided.