From 837cc31a9305ad15e4245a05c32473ef6a0846e3 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:34:52 -0300 Subject: [PATCH 01/37] use x coordinate as key for aes --- .../key_management/ephemeral_key_holder.rs | 11 ++---- accounts/src/key_management/mod.rs | 34 ++++++------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 9e3a9b1..266cfa3 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -3,6 +3,7 @@ use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; use log::info; use rand::{rngs::OsRng, RngCore}; +use elliptic_curve::point::AffineCoordinates; use super::constants_types::{CipherText, Nonce}; @@ -39,14 +40,8 @@ impl EphemeralKeyHolder { viewing_public_key_receiver: AffinePoint, data: &[u8], ) -> (CipherText, Nonce) { - let key_point = self.calculate_shared_secret_sender(viewing_public_key_receiver); - let binding = serde_json::to_vec(&key_point).unwrap(); - let key_raw = &binding.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap(); - - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); + let shared_secret = self.calculate_shared_secret_sender(viewing_public_key_receiver); + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Aes256Gcm::generate_nonce(&mut OsRng); (cipher.encrypt(&nonce, data).unwrap(), nonce) diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 25673f6..79418ec 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -5,6 +5,7 @@ use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; +use elliptic_curve::point::AffineCoordinates; use crate::account_core::PublicKey; @@ -63,14 +64,8 @@ impl AddressKeyHolder { ciphertext: CipherText, nonce: Nonce, ) -> Result, aes_gcm::Error> { - let key_point = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); - let binding = serde_json::to_vec(&key_point).unwrap(); - let key_raw = &binding.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap(); - - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); + let shared_secret = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); + let cipher = Aes256Gcm::new(&shared_secret.x()); cipher.decrypt(&nonce, ciphertext.as_slice()) } @@ -107,18 +102,22 @@ impl AddressKeyHolder { #[cfg(test)] mod tests { + use std::io::Read; + use aes_gcm::{ aead::{Aead, KeyInit, OsRng}, Aes256Gcm, }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; - use elliptic_curve::ff::Field; + use elliptic_curve::{ff::Field, PrimeField}; use elliptic_curve::group::prime::PrimeCurveAffine; use k256::{AffinePoint, ProjectivePoint, Scalar}; + use elliptic_curve::point::AffineCoordinates; use super::*; + #[test] fn test_new_os_random() { // Ensure that a new AddressKeyHolder instance can be created without errors. @@ -154,22 +153,14 @@ mod tests { let address_key_holder = AddressKeyHolder::new_os_random(); // Generate an ephemeral key and shared secret - let scalar = Scalar::random(OsRng); let ephemeral_public_key_sender = address_key_holder .produce_ephemeral_key_holder() .generate_ephemeral_public_key(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher @@ -315,12 +306,7 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - let cipher = Aes256Gcm::new(&key); + let cipher = Aes256Gcm::new(&shared_secret.x()); let ciphertext = cipher .encrypt(nonce, plaintext.as_ref()) From 7a117150efaab1d3fed7277dc4d4b721b0a2e81a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:36:30 -0300 Subject: [PATCH 02/37] remove usage of deprecated function --- accounts/src/key_management/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 79418ec..712e8a4 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -138,7 +138,7 @@ mod tests { // Generate a random ephemeral public key sender let scalar = Scalar::random(&mut OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); // Calculate shared secret let shared_secret = @@ -216,7 +216,7 @@ mod tests { // Generate ephemeral public key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); @@ -256,7 +256,7 @@ mod tests { // Generate ephemeral public key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); @@ -298,7 +298,7 @@ mod tests { // Generate ephemeral key and shared secret let scalar = Scalar::random(OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); // Encrypt sample data let plaintext = b"Round-trip test data"; From 7572188ab08040dc06ed8b271b0139b91296e9f1 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:37:03 -0300 Subject: [PATCH 03/37] fmt --- accounts/src/key_management/ephemeral_key_holder.rs | 2 +- accounts/src/key_management/mod.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 266cfa3..6210369 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -1,9 +1,9 @@ use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; +use elliptic_curve::point::AffineCoordinates; use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; use log::info; use rand::{rngs::OsRng, RngCore}; -use elliptic_curve::point::AffineCoordinates; use super::constants_types::{CipherText, Nonce}; diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 712e8a4..1e690ac 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -1,11 +1,11 @@ use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; +use elliptic_curve::point::AffineCoordinates; use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; -use elliptic_curve::point::AffineCoordinates; use crate::account_core::PublicKey; @@ -110,14 +110,13 @@ mod tests { }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; - use elliptic_curve::{ff::Field, PrimeField}; use elliptic_curve::group::prime::PrimeCurveAffine; - use k256::{AffinePoint, ProjectivePoint, Scalar}; use elliptic_curve::point::AffineCoordinates; + use elliptic_curve::{ff::Field, PrimeField}; + use k256::{AffinePoint, ProjectivePoint, Scalar}; use super::*; - #[test] fn test_new_os_random() { // Ensure that a new AddressKeyHolder instance can be created without errors. From 74d8fd54d9e794b22c69f62df3196ecf0cec2da2 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Wed, 7 May 2025 16:52:08 -0300 Subject: [PATCH 04/37] fix tests --- .../key_management/ephemeral_key_holder.rs | 2 +- accounts/src/key_management/mod.rs | 26 ++++--------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 6210369..ecfb09e 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -1,4 +1,4 @@ -use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; +use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, KeyInit}; use elliptic_curve::point::AffineCoordinates; use elliptic_curve::PrimeField; use k256::{AffinePoint, FieldBytes, Scalar}; diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 1e690ac..474bd99 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -1,4 +1,4 @@ -use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; +use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; use elliptic_curve::point::AffineCoordinates; @@ -102,17 +102,15 @@ impl AddressKeyHolder { #[cfg(test)] mod tests { - use std::io::Read; - use aes_gcm::{ aead::{Aead, KeyInit, OsRng}, Aes256Gcm, }; use constants_types::{CipherText, Nonce}; use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; + use elliptic_curve::ff::Field; use elliptic_curve::group::prime::PrimeCurveAffine; use elliptic_curve::point::AffineCoordinates; - use elliptic_curve::{ff::Field, PrimeField}; use k256::{AffinePoint, ProjectivePoint, Scalar}; use super::*; @@ -137,7 +135,7 @@ mod tests { // Generate a random ephemeral public key sender let scalar = Scalar::random(&mut OsRng); - let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine(); + let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine(); // Calculate shared secret let shared_secret = @@ -219,15 +217,8 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data with a specific nonce + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher @@ -259,15 +250,8 @@ mod tests { let shared_secret = address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); - // Prepare the encryption key from shared secret - let key_raw = serde_json::to_vec(&shared_secret).unwrap(); - let key_raw_adjust_pre = &key_raw.as_slice()[..32]; - let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap(); - let key: Key = key_raw_adjust.into(); - - let cipher = Aes256Gcm::new(&key); - // Encrypt sample data + let cipher = Aes256Gcm::new(&shared_secret.x()); let nonce = Nonce::from_slice(b"unique nonce"); let plaintext = b"Sensitive data"; let ciphertext = cipher From cde9f0a5c889f0203331f409869c9a835f168852 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 15 May 2025 11:38:37 +0300 Subject: [PATCH 05/37] feat: sparse trees preparation for serialization --- accounts/src/account_core/mod.rs | 38 ++++-- common/src/nullifier_sparse_merkle_tree.rs | 129 +++++++++++++++++---- node_core/src/chain_storage/mod.rs | 26 ++++- node_core/src/executions/de.rs | 15 ++- node_core/src/executions/private_exec.rs | 15 ++- node_core/src/executions/se.rs | 15 ++- sc_core/src/proofs_circuits.rs | 15 ++- sequencer_core/src/lib.rs | 22 +++- utxo/src/utxo_tree.rs | 113 ++++++++++++++---- 9 files changed, 314 insertions(+), 74 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 2d3417c..afa0197 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -7,7 +7,7 @@ use log::info; use serde::Serialize; use utxo::{ utxo_core::{UTXOPayload, UTXO}, - utxo_tree::UTXOSparseMerkleTree, + utxo_tree::{UTXOSparseMerkleTree, UTXOTreeInput}, }; use crate::key_management::{ @@ -100,7 +100,7 @@ impl Account { Ok(()) } - pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { + pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { Ok(self.utxo_tree.insert_items(utxos)?) } @@ -113,6 +113,9 @@ impl Account { asset: Asset, amount: u128, privacy_flag: bool, + utxo_id: u64, + tx_id: u64, + block_id: u64, ) -> Result<()> { let payload_with_asset = UTXOPayload { owner: self.address, @@ -123,7 +126,14 @@ impl Account { let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset)?; - self.utxo_tree.insert_item(asset_utxo)?; + let input_utxo = UTXOTreeInput { + utxo_id, + tx_id, + block_id, + utxo: asset_utxo, + }; + + self.utxo_tree.insert_item(input_utxo)?; Ok(()) } @@ -163,14 +173,24 @@ mod tests { UTXONullifier::default() } - fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> anyhow::Result { + fn generate_dummy_utxo( + address: TreeHashType, + amount: u128, + utxo_id: u64, + ) -> anyhow::Result { let payload = UTXOPayload { owner: address, asset: vec![], amount, privacy_flag: false, }; - UTXO::create_utxo_from_payload(payload) + let utxo = UTXO::create_utxo_from_payload(payload); + utxo.map(|utxo| UTXOTreeInput { + utxo_id, + tx_id: 1, + block_id: 1, + utxo, + }) } #[test] @@ -184,7 +204,7 @@ mod tests { #[test] fn test_mark_spent_utxo() { let mut account = Account::new(); - let utxo = generate_dummy_utxo(account.address, 100).unwrap(); + let utxo = generate_dummy_utxo(account.address, 100, 1).unwrap(); account.add_new_utxo_outputs(vec![utxo]).unwrap(); let mut utxo_nullifier_map = HashMap::new(); @@ -199,8 +219,8 @@ mod tests { #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); - let utxo1 = generate_dummy_utxo(account.address, 100).unwrap(); - let utxo2 = generate_dummy_utxo(account.address, 200).unwrap(); + let utxo1 = generate_dummy_utxo(account.address, 100, 1).unwrap(); + let utxo2 = generate_dummy_utxo(account.address, 200, 2).unwrap(); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); @@ -222,7 +242,7 @@ mod tests { let asset = "dummy_asset"; let amount = 1000u128; - let result = account.add_asset(asset, amount, false); + let result = account.add_asset(asset, amount, false, 1, 1, 1); assert!(result.is_ok()); assert_eq!(account.utxo_tree.store.len(), 1); diff --git a/common/src/nullifier_sparse_merkle_tree.rs b/common/src/nullifier_sparse_merkle_tree.rs index 282fccc..c6707a7 100644 --- a/common/src/nullifier_sparse_merkle_tree.rs +++ b/common/src/nullifier_sparse_merkle_tree.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use monotree::database::MemoryDB; use monotree::hasher::Blake3; use monotree::{Hasher, Monotree, Proof}; @@ -5,10 +7,31 @@ use monotree::{Hasher, Monotree, Proof}; use crate::merkle_tree_public::TreeHashType; use crate::nullifier::UTXONullifier; +#[derive(Debug, Clone)] +pub struct NullifierTreeInput { + pub nullifier_id: u64, + pub tx_id: u64, + pub block_id: u64, + pub nullifier: UTXONullifier, +} + +#[derive(Debug, Clone)] +pub struct TreeTxWithNullifierId { + pub id: u64, + pub nullifiers: BTreeMap, +} + +#[derive(Debug, Clone)] +pub struct TreeBlockWithTxId { + pub id: u64, + pub txs: BTreeMap, +} + pub struct NullifierSparseMerkleTree { pub curr_root: Option, pub tree: Monotree, pub hasher: Blake3, + pub leafs: BTreeMap, } impl NullifierSparseMerkleTree { @@ -17,30 +40,71 @@ impl NullifierSparseMerkleTree { curr_root: None, tree: Monotree::default(), hasher: Blake3::new(), + leafs: BTreeMap::new(), } } - pub fn insert_item(&mut self, nullifier: UTXONullifier) -> Result<(), monotree::Errors> { + pub fn modify_leavs_with_nullifier_input(&mut self, tree_nullifier: NullifierTreeInput) { + self.leafs + .entry(tree_nullifier.block_id) + .and_modify(|tree_block| { + tree_block + .txs + .entry(tree_nullifier.tx_id) + .and_modify(|tree_tx| { + tree_tx + .nullifiers + .insert(tree_nullifier.nullifier_id, tree_nullifier.nullifier); + }) + .or_insert(TreeTxWithNullifierId { + id: tree_nullifier.tx_id, + nullifiers: BTreeMap::new(), + }); + }) + .or_insert(TreeBlockWithTxId { + id: tree_nullifier.block_id, + txs: BTreeMap::new(), + }); + } + + pub fn insert_item( + &mut self, + tree_nullifier: NullifierTreeInput, + ) -> Result<(), monotree::Errors> { let root = self.curr_root.as_ref(); - let new_root = self - .tree - .insert(root, &nullifier.utxo_hash, &nullifier.utxo_hash)?; + let new_root = self.tree.insert( + root, + &tree_nullifier.nullifier.utxo_hash, + &tree_nullifier.nullifier.utxo_hash, + )?; self.curr_root = new_root; + self.modify_leavs_with_nullifier_input(tree_nullifier); + Ok(()) } - pub fn insert_items(&mut self, nullifiers: Vec) -> Result<(), monotree::Errors> { + pub fn insert_items( + &mut self, + tree_nullifiers: Vec, + ) -> Result<(), monotree::Errors> { let root = self.curr_root.as_ref(); - let hashes: Vec = nullifiers.iter().map(|nu| nu.utxo_hash).collect(); + let hashes: Vec = tree_nullifiers + .iter() + .map(|nu| nu.nullifier.utxo_hash) + .collect(); let new_root = self.tree.inserts(root, &hashes, &hashes)?; self.curr_root = new_root; + for tree_nullifier in tree_nullifiers { + self.modify_leavs_with_nullifier_input(tree_nullifier); + } + Ok(()) } @@ -130,6 +194,20 @@ mod tests { UTXONullifier { utxo_hash: hash } } + fn create_nullifier_input( + hash: TreeHashType, + nullifier_id: u64, + tx_id: u64, + block_id: u64, + ) -> NullifierTreeInput { + NullifierTreeInput { + nullifier_id, + tx_id, + block_id, + nullifier: create_nullifier(hash), + } + } + #[test] fn test_new_tree_initialization() { let tree = NullifierSparseMerkleTree::new(); @@ -139,9 +217,9 @@ mod tests { #[test] fn test_insert_single_item() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32]); // Sample 32-byte hash + let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); // Sample 32-byte hash - let result = tree.insert_item(nullifier); + let result = tree.insert_item(tree_nullifier); assert!(result.is_ok()); assert!(tree.curr_root.is_some()); } @@ -149,13 +227,13 @@ mod tests { #[test] fn test_insert_multiple_items() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifiers = vec![ - create_nullifier([1u8; 32]), - create_nullifier([2u8; 32]), - create_nullifier([3u8; 32]), + let tree_nullifiers = vec![ + create_nullifier_input([1u8; 32], 1, 1, 1), + create_nullifier_input([2u8; 32], 2, 1, 1), + create_nullifier_input([3u8; 32], 3, 1, 1), ]; - let result = tree.insert_items(nullifiers); + let result = tree.insert_items(tree_nullifiers); assert!(result.is_ok()); assert!(tree.curr_root.is_some()); } @@ -163,9 +241,9 @@ mod tests { #[test] fn test_search_item_inclusion() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32]); + let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - tree.insert_item(nullifier.clone()).unwrap(); + tree.insert_item(tree_nullifier.clone()).unwrap(); let result = tree.search_item_inclusion([1u8; 32]); assert!(result.is_ok()); @@ -179,13 +257,13 @@ mod tests { #[test] fn test_search_multiple_item_inclusions() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifiers = vec![ - create_nullifier([1u8; 32]), - create_nullifier([2u8; 32]), - create_nullifier([3u8; 32]), + let tree_nullifiers = vec![ + create_nullifier_input([1u8; 32], 1, 1, 1), + create_nullifier_input([2u8; 32], 2, 1, 1), + create_nullifier_input([3u8; 32], 3, 1, 1), ]; - tree.insert_items(nullifiers).unwrap(); + tree.insert_items(tree_nullifiers).unwrap(); let search_hashes = vec![[1u8; 32], [2u8; 32], [99u8; 32]]; let result = tree.search_item_inclusions(&search_hashes); @@ -224,9 +302,9 @@ mod tests { #[test] fn test_insert_and_get_proof_of_existing_item() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32]); + let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - tree.insert_item(nullifier.clone()).unwrap(); + tree.insert_item(tree_nullifier.clone()).unwrap(); let proof_result = tree.get_non_membership_proof([1u8; 32]); assert!(proof_result.is_err()); @@ -235,9 +313,12 @@ mod tests { #[test] fn test_insert_and_get_proofs_of_existing_items() { let mut tree = NullifierSparseMerkleTree::new(); - let nullifiers = vec![create_nullifier([1u8; 32]), create_nullifier([2u8; 32])]; + let tree_nullifiers = vec![ + create_nullifier_input([1u8; 32], 1, 1, 1), + create_nullifier_input([2u8; 32], 2, 1, 1), + ]; - tree.insert_items(nullifiers).unwrap(); + tree.insert_items(tree_nullifiers).unwrap(); let proof_result = tree.get_non_membership_proofs(&[[1u8; 32], [2u8; 32]]); assert!(proof_result.is_err()); diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index f8bcf4e..3500c41 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -10,12 +10,12 @@ use common::{ block::Block, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, - nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, + nullifier_sparse_merkle_tree::{NullifierSparseMerkleTree, NullifierTreeInput}, utxo_commitment::UTXOCommitment, }; use k256::AffinePoint; use public_context::PublicSCContext; -use utxo::utxo_core::UTXO; +use utxo::{utxo_core::UTXO, utxo_tree::UTXOTreeInput}; use crate::ActionData; @@ -54,7 +54,7 @@ impl NodeChainStore { } pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> { - for tx in &block.transactions { + for (tx_id, tx) in block.transactions.iter().enumerate() { if !tx.execution_input.is_empty() { let public_action = serde_json::from_slice::(&tx.execution_input); @@ -101,7 +101,13 @@ impl NodeChainStore { tx.nullifier_created_hashes .clone() .into_iter() - .map(|hash| UTXONullifier { utxo_hash: hash }) + .enumerate() + .map(|(idx, hash)| NullifierTreeInput { + nullifier_id: idx as u64, + tx_id: tx_id as u64, + block_id: block.block_id, + nullifier: UTXONullifier { utxo_hash: hash }, + }) .collect(), )?; @@ -109,7 +115,9 @@ impl NodeChainStore { let ephemeral_public_key_sender = serde_json::from_slice::(&tx.ephemeral_pub_key)?; - for (ciphertext, nonce, tag) in tx.encoded_data.clone() { + for (utxo_id, (ciphertext, nonce, tag)) in + tx.encoded_data.clone().into_iter().enumerate() + { let slice = nonce.as_slice(); let nonce = accounts::key_management::constants_types::Nonce::clone_from_slice(slice); @@ -125,7 +133,13 @@ impl NodeChainStore { serde_json::from_slice::(&decoded_data_curr_acc); if let Ok(utxo) = decoded_utxo_try { if &utxo.owner == acc_id { - acc.utxo_tree.insert_item(utxo)?; + let input_utxo = UTXOTreeInput { + utxo_id: utxo_id as u64, + tx_id: tx_id as u64, + block_id: block.block_id, + utxo, + }; + acc.utxo_tree.insert_item(input_utxo)?; } } } diff --git a/node_core/src/executions/de.rs b/node_core/src/executions/de.rs index f73ba85..ddc5e81 100644 --- a/node_core/src/executions/de.rs +++ b/node_core/src/executions/de.rs @@ -1,4 +1,7 @@ +use std::collections::BTreeMap; + use bincode; +use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, @@ -106,15 +109,25 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { + //There is no need for storage, so ids can be default there + let id = 1; + let mut nsmt = NullifierSparseMerkleTree { curr_root: Option::Some(root_nullifier), tree: Monotree::default(), hasher: Blake3::new(), + leafs: BTreeMap::new(), }; let nullifiers: Vec<_> = nullifiers_proof .into_iter() - .map(|n_p| UTXONullifier { utxo_hash: *n_p }) + .enumerate() + .map(|(idx, n_p)| NullifierTreeInput { + nullifier_id: idx as u64, + tx_id: id, + block_id: id, + nullifier: UTXONullifier { utxo_hash: *n_p }, + }) .collect(); nsmt.insert_items(nullifiers).unwrap(); diff --git a/node_core/src/executions/private_exec.rs b/node_core/src/executions/private_exec.rs index 2e06c86..e3d55a1 100644 --- a/node_core/src/executions/private_exec.rs +++ b/node_core/src/executions/private_exec.rs @@ -1,4 +1,7 @@ +use std::collections::BTreeMap; + use bincode; +use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, @@ -79,15 +82,25 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { + //There is no need for storage, so ids can be default there + let id = 1; + let mut nsmt = NullifierSparseMerkleTree { curr_root: Option::Some(root_nullifier), tree: Monotree::default(), hasher: Blake3::new(), + leafs: BTreeMap::new(), }; let nullifiers: Vec<_> = nullifiers_proof .into_iter() - .map(|n_p| UTXONullifier { utxo_hash: *n_p }) + .enumerate() + .map(|(idx, n_p)| NullifierTreeInput { + nullifier_id: idx as u64, + tx_id: id, + block_id: id, + nullifier: UTXONullifier { utxo_hash: *n_p }, + }) .collect(); nsmt.insert_items(nullifiers).unwrap(); diff --git a/node_core/src/executions/se.rs b/node_core/src/executions/se.rs index d37fee5..f9123c2 100644 --- a/node_core/src/executions/se.rs +++ b/node_core/src/executions/se.rs @@ -1,4 +1,7 @@ +use std::collections::BTreeMap; + use bincode; +use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, @@ -108,15 +111,25 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { + //There is no need for storage, so ids can be default there + let id = 1; + let mut nsmt = NullifierSparseMerkleTree { curr_root: Option::Some(root_nullifier), tree: Monotree::default(), hasher: Blake3::new(), + leafs: BTreeMap::new(), }; let nullifiers: Vec<_> = nullifiers_proof .into_iter() - .map(|n_p| UTXONullifier { utxo_hash: *n_p }) + .enumerate() + .map(|(idx, n_p)| NullifierTreeInput { + nullifier_id: idx as u64, + tx_id: id, + block_id: id, + nullifier: UTXONullifier { utxo_hash: *n_p }, + }) .collect(); nsmt.insert_items(nullifiers).unwrap(); diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 2072e55..3574ec4 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -1,4 +1,7 @@ +use std::collections::BTreeMap; + use bincode; +use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, @@ -81,15 +84,25 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { + //There is no need for storage, so ids can be default there + let id = 1; + let mut nsmt = NullifierSparseMerkleTree { curr_root: Option::Some(root_nullifier), tree: Monotree::default(), hasher: Blake3::new(), + leafs: BTreeMap::new(), }; let nullifiers: Vec<_> = nullifiers_proof .into_iter() - .map(|n_p| UTXONullifier { utxo_hash: *n_p }) + .enumerate() + .map(|(idx, n_p)| NullifierTreeInput { + nullifier_id: idx as u64, + tx_id: id, + block_id: id, + nullifier: UTXONullifier { utxo_hash: *n_p }, + }) .collect(); nsmt.insert_items(nullifiers).unwrap(); diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index d073ffb..647af9b 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -5,6 +5,7 @@ use common::{ block::{Block, HashableBlockData}, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, + nullifier_sparse_merkle_tree::NullifierTreeInput, transaction::{Transaction, TxKind}, utxo_commitment::UTXOCommitment, }; @@ -185,6 +186,8 @@ impl SequencerCore { fn execute_check_transaction_on_state( &mut self, tx: TransactionMempool, + tx_id: u64, + block_id: u64, ) -> Result<(), TransactionMalformationErrorKind> { let Transaction { hash, @@ -199,11 +202,16 @@ impl SequencerCore { .add_tx(UTXOCommitment { hash: *utxo_comm }); } - for nullifier in nullifier_created_hashes { + for (idx, nullifier) in nullifier_created_hashes.iter().enumerate() { self.store .nullifier_store - .insert_item(UTXONullifier { - utxo_hash: *nullifier, + .insert_item(NullifierTreeInput { + nullifier_id: idx as u64, + tx_id, + block_id, + nullifier: UTXONullifier { + utxo_hash: *nullifier, + }, }) .map_err(|err| TransactionMalformationErrorKind::FailedToInsert { tx: hash, @@ -225,12 +233,14 @@ impl SequencerCore { ///Produces new block from transactions in mempool pub fn produce_new_block_with_mempool_transactions(&mut self) -> Result { + let new_block_height = self.chain_height + 1; + let transactions = self .mempool .pop_size(self.sequencer_config.max_num_tx_in_block); - for tx in transactions.clone() { - self.execute_check_transaction_on_state(tx)?; + for (idx, tx) in transactions.clone().into_iter().enumerate() { + self.execute_check_transaction_on_state(tx, idx as u64, new_block_height)?; } let prev_block_hash = self @@ -240,7 +250,7 @@ impl SequencerCore { .hash; let hashable_data = HashableBlockData { - block_id: self.chain_height + 1, + block_id: new_block_height, prev_block_id: self.chain_height, transactions: transactions.into_iter().map(|tx_mem| tx_mem.tx).collect(), data: vec![], diff --git a/utxo/src/utxo_tree.rs b/utxo/src/utxo_tree.rs index 3c0c603..cc84dd9 100644 --- a/utxo/src/utxo_tree.rs +++ b/utxo/src/utxo_tree.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use common::merkle_tree_public::TreeHashType; use monotree::database::MemoryDB; @@ -7,11 +7,32 @@ use monotree::{Hasher, Monotree, Proof}; use crate::utxo_core::UTXO; +#[derive(Debug, Clone)] +pub struct UTXOTreeInput { + pub utxo_id: u64, + pub tx_id: u64, + pub block_id: u64, + pub utxo: UTXO, +} + +#[derive(Debug, Clone)] +pub struct TreeTxWithUTXOId { + pub id: u64, + pub utxos: BTreeMap, +} + +#[derive(Debug, Clone)] +pub struct TreeBlockWithTxId { + pub id: u64, + pub txs: BTreeMap, +} + pub struct UTXOSparseMerkleTree { pub curr_root: Option, pub tree: Monotree, pub hasher: Blake3, pub store: HashMap, + pub leafs: BTreeMap, } impl UTXOSparseMerkleTree { @@ -21,30 +42,58 @@ impl UTXOSparseMerkleTree { tree: Monotree::default(), hasher: Blake3::new(), store: HashMap::new(), + leafs: BTreeMap::new(), } } - pub fn insert_item(&mut self, utxo: UTXO) -> Result<(), monotree::Errors> { + pub fn modify_leavs_with_nullifier_input(&mut self, tree_utxo: UTXOTreeInput) { + self.leafs + .entry(tree_utxo.block_id) + .and_modify(|tree_block| { + tree_block + .txs + .entry(tree_utxo.tx_id) + .and_modify(|tree_tx| { + tree_tx.utxos.insert(tree_utxo.utxo_id, tree_utxo.utxo); + }) + .or_insert(TreeTxWithUTXOId { + id: tree_utxo.tx_id, + utxos: BTreeMap::new(), + }); + }) + .or_insert(TreeBlockWithTxId { + id: tree_utxo.block_id, + txs: BTreeMap::new(), + }); + } + + pub fn insert_item(&mut self, tree_utxo: UTXOTreeInput) -> Result<(), monotree::Errors> { let root = self.curr_root.as_ref(); - let new_root = self.tree.insert(root, &utxo.hash, &utxo.hash)?; - - self.store.insert(utxo.hash, utxo); + let new_root = self + .tree + .insert(root, &tree_utxo.utxo.hash, &tree_utxo.utxo.hash)?; self.curr_root = new_root; + self.store + .insert(tree_utxo.utxo.hash, tree_utxo.utxo.clone()); + self.modify_leavs_with_nullifier_input(tree_utxo); + Ok(()) } - pub fn insert_items(&mut self, utxos: Vec) -> Result<(), monotree::Errors> { + pub fn insert_items(&mut self, tree_utxos: Vec) -> Result<(), monotree::Errors> { let root = self.curr_root.as_ref(); - let hashes: Vec = utxos.iter().map(|item| item.hash).collect(); + let hashes: Vec = tree_utxos.iter().map(|item| item.utxo.hash).collect(); let new_root = self.tree.inserts(root, &hashes, &hashes)?; - for utxo in utxos { - self.store.insert(utxo.hash, utxo); + for tree_utxo in tree_utxos { + self.store + .insert(tree_utxo.utxo.hash, tree_utxo.utxo.clone()); + self.modify_leavs_with_nullifier_input(tree_utxo); } self.curr_root = new_root; @@ -80,17 +129,31 @@ mod tests { use super::*; use crate::utxo_core::{UTXOPayload, UTXO}; - fn sample_utxo_payload() -> UTXOPayload { + fn sample_utxo_payload(amount: u128) -> UTXOPayload { UTXOPayload { owner: AccountId::default(), asset: vec![1, 2, 3], - amount: 10, + amount, privacy_flag: false, } } - fn sample_utxo() -> anyhow::Result { - UTXO::create_utxo_from_payload(sample_utxo_payload()) + fn sample_utxo(amount: u128) -> anyhow::Result { + UTXO::create_utxo_from_payload(sample_utxo_payload(amount)) + } + + fn sample_utxo_input( + utxo_id: u64, + tx_id: u64, + block_id: u64, + amount: u128, + ) -> anyhow::Result { + sample_utxo(amount).map(|utxo| UTXOTreeInput { + utxo_id, + tx_id, + block_id, + utxo, + }) } #[test] @@ -103,7 +166,7 @@ mod tests { #[test] fn test_insert_item() { let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); + let utxo = sample_utxo_input(1, 1, 1, 10).unwrap(); let result = smt.insert_item(utxo.clone()); @@ -111,7 +174,7 @@ mod tests { assert!(result.is_ok()); // Test UTXO is now stored in the tree - assert_eq!(smt.store.get(&utxo.hash).unwrap().hash, utxo.hash); + assert_eq!(smt.store.get(&utxo.utxo.hash).unwrap().hash, utxo.utxo.hash); // Test curr_root is updated assert!(smt.curr_root.is_some()); @@ -120,8 +183,8 @@ mod tests { #[test] fn test_insert_items() { let mut smt = UTXOSparseMerkleTree::new(); - let utxo1 = sample_utxo().unwrap(); - let utxo2 = sample_utxo().unwrap(); + let utxo1 = sample_utxo_input(1, 1, 1, 10).unwrap(); + let utxo2 = sample_utxo_input(2, 1, 1, 11).unwrap(); let result = smt.insert_items(vec![utxo1.clone(), utxo2.clone()]); @@ -129,8 +192,8 @@ mod tests { assert!(result.is_ok()); // Test UTXOs are now stored in the tree - assert!(smt.store.get(&utxo1.hash).is_some()); - assert!(smt.store.get(&utxo2.hash).is_some()); + assert!(smt.store.get(&utxo1.utxo.hash).is_some()); + assert!(smt.store.get(&utxo2.utxo.hash).is_some()); // Test curr_root is updated assert!(smt.curr_root.is_some()); @@ -139,20 +202,20 @@ mod tests { #[test] fn test_get_item_exists() { let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); + let utxo = sample_utxo_input(1, 1, 1, 10).unwrap(); smt.insert_item(utxo.clone()).unwrap(); // Test that the UTXO can be retrieved by hash - let retrieved_utxo = smt.get_item(utxo.hash).unwrap(); + let retrieved_utxo = smt.get_item(utxo.utxo.hash).unwrap(); assert!(retrieved_utxo.is_some()); - assert_eq!(retrieved_utxo.unwrap().hash, utxo.hash); + assert_eq!(retrieved_utxo.unwrap().hash, utxo.utxo.hash); } #[test] fn test_get_item_not_exists() { let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); + let utxo = sample_utxo_input(1, 1, 1, 10).unwrap(); // Insert one UTXO and try to fetch a different hash smt.insert_item(utxo).unwrap(); @@ -167,12 +230,12 @@ mod tests { #[test] fn test_get_membership_proof() { let mut smt = UTXOSparseMerkleTree::new(); - let utxo = sample_utxo().unwrap(); + let utxo = sample_utxo_input(1, 1, 1, 10).unwrap(); smt.insert_item(utxo.clone()).unwrap(); // Fetch membership proof for the inserted UTXO - let proof = smt.get_membership_proof(utxo.hash).unwrap(); + let proof = smt.get_membership_proof(utxo.utxo.hash).unwrap(); // Test proof is generated successfully assert!(proof.is_some()); From 96dc9bd840b6b859a3be115d61c82029e822d5a3 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:37:38 -0400 Subject: [PATCH 06/37] serialize for `HashStorageMerkleTree` --- common/src/merkle_tree_public/merkle_tree.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 16d185e..d5fd72d 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -12,6 +12,24 @@ pub struct HashStorageMerkleTree { tree: MerkleTree, } +impl Serialize for HashStorageMerkleTree { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut vector = self.leaves.iter().collect::>(); + vector.sort_by(|a, b| a.0.cmp(b.0)); + + let mut seq = serializer.serialize_seq(Some(self.leaves.len()))?; + for element in vector.iter() { + seq.serialize_element(element.1)?; + } + seq.end() + } +} + + + pub type PublicTransactionMerkleTree = HashStorageMerkleTree; pub type UTXOCommitmentsMerkleTree = HashStorageMerkleTree; From 0daffaf4ada799228cd17760d7082e641a7dd242 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:37:58 -0400 Subject: [PATCH 07/37] HashStorageMerkleTreeDeserializer --- common/src/merkle_tree_public/merkle_tree.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index d5fd72d..70ca0f4 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -28,6 +28,18 @@ impl Serialize for HashStorageMerkleTree } } +struct HashStorageMerkleTreeDeserializer { + marker: PhantomData HashStorageMerkleTree> +} + +impl HashStorageMerkleTreeDeserializer { + fn new() -> Self { + HashStorageMerkleTreeDeserializer { + marker: PhantomData + } + } +} + pub type PublicTransactionMerkleTree = HashStorageMerkleTree; From 9df2b51813a56e22bae56d195c548abc8a0908af Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:38:36 -0400 Subject: [PATCH 08/37] imple `Visitor` for `HashStorageMerkleTreeDeserializer` --- common/src/merkle_tree_public/merkle_tree.rs | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 70ca0f4..0dc3f6b 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -40,6 +40,32 @@ impl HashStorageMerkleTreeDeserializer { } } +impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de> for HashStorageMerkleTreeDeserializer { + type Value= HashStorageMerkleTree; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("HashStorageMerkleTree key value sequence.") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut vector = vec![]; + + loop { + let opt_key = seq.next_element::()?; + if let Some(value) = opt_key { + vector.push(value); + } else { + break; + } + } + + Ok(HashStorageMerkleTree::new(vector)) + } +} + pub type PublicTransactionMerkleTree = HashStorageMerkleTree; From cdb8e3a08a0876d663858b52c2865f098189c93f Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:39:24 -0400 Subject: [PATCH 09/37] imple`Deserialize` for `HashStorageMerkleTree` --- common/src/merkle_tree_public/merkle_tree.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 0dc3f6b..d769218 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use rs_merkle::{MerkleProof, MerkleTree}; +use serde::{de::{self, SeqAccess, Visitor}, ser::SerializeSeq, Deserialize, Deserializer, Serialize}; use crate::{transaction::Transaction, utxo_commitment::UTXOCommitment}; @@ -66,7 +67,11 @@ impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de> for HashSt } } - +impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> serde::Deserialize<'de> for HashStorageMerkleTree { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_seq(HashStorageMerkleTreeDeserializer::new()) + } +} pub type PublicTransactionMerkleTree = HashStorageMerkleTree; From 2346f06d23ec733a1f15486faa4b63970be4575a Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:39:39 -0400 Subject: [PATCH 10/37] add a test --- common/src/merkle_tree_public/merkle_tree.rs | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index d769218..21275d3 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt, marker::PhantomData}; use rs_merkle::{MerkleProof, MerkleTree}; use serde::{de::{self, SeqAccess, Visitor}, ser::SerializeSeq, Deserialize, Deserializer, Serialize}; @@ -162,7 +162,7 @@ mod tests { use super::*; // Mock implementation of TreeLeavItem trait for testing - #[derive(Debug, Clone, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] struct MockTransaction { pub hash: TreeHashType, } @@ -197,6 +197,24 @@ mod tests { assert!(tree.get_root().is_some()); } + #[test] + fn test_new_merkle_tree_serialize() { + let tx1 = MockTransaction { + hash: get_first_32_bytes("tx1"), + }; + let tx2 = MockTransaction { + hash: get_first_32_bytes("tx2"), + }; + + let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone()]); + + let binding = serde_json::to_vec(&tree).unwrap(); + + let obj: HashStorageMerkleTree = serde_json::from_slice(&binding).unwrap(); + + assert_eq!(tree.leaves, obj.leaves); + } + #[test] fn test_get_tx() { let tx1 = MockTransaction { From b4c0fb935130679f625254f61bc5ef568a390bc6 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 18:40:45 -0400 Subject: [PATCH 11/37] fmt --- common/src/merkle_tree_public/merkle_tree.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 21275d3..1cb84e8 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -1,7 +1,11 @@ use std::{collections::HashMap, fmt, marker::PhantomData}; use rs_merkle::{MerkleProof, MerkleTree}; -use serde::{de::{self, SeqAccess, Visitor}, ser::SerializeSeq, Deserialize, Deserializer, Serialize}; +use serde::{ + de::{self, SeqAccess, Visitor}, + ser::SerializeSeq, + Deserialize, Deserializer, Serialize, +}; use crate::{transaction::Transaction, utxo_commitment::UTXOCommitment}; @@ -30,19 +34,21 @@ impl Serialize for HashStorageMerkleTree } struct HashStorageMerkleTreeDeserializer { - marker: PhantomData HashStorageMerkleTree> + marker: PhantomData HashStorageMerkleTree>, } impl HashStorageMerkleTreeDeserializer { fn new() -> Self { HashStorageMerkleTreeDeserializer { - marker: PhantomData + marker: PhantomData, } } } -impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de> for HashStorageMerkleTreeDeserializer { - type Value= HashStorageMerkleTree; +impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de> + for HashStorageMerkleTreeDeserializer +{ + type Value = HashStorageMerkleTree; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("HashStorageMerkleTree key value sequence.") @@ -67,7 +73,9 @@ impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de> for HashSt } } -impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> serde::Deserialize<'de> for HashStorageMerkleTree { +impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> serde::Deserialize<'de> + for HashStorageMerkleTree +{ fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_seq(HashStorageMerkleTreeDeserializer::new()) } From 4ba4c12a87522fb0c34a66e77dd1aecf5c3da874 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 16 May 2025 19:16:45 -0400 Subject: [PATCH 12/37] rm unused --- common/src/merkle_tree_public/merkle_tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 1cb84e8..64a6343 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt, marker::PhantomData}; use rs_merkle::{MerkleProof, MerkleTree}; use serde::{ - de::{self, SeqAccess, Visitor}, + de::{SeqAccess, Visitor}, ser::SerializeSeq, Deserialize, Deserializer, Serialize, }; From 6aa6c9d34ffc3c58f44264d8ee3c187ba442204c Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:06:06 -0300 Subject: [PATCH 13/37] fmt --- accounts/src/account_core/mod.rs | 4 +--- node_core/src/lib.rs | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 0c7bbdd..38d9e9c 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -5,9 +5,7 @@ use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transac use k256::AffinePoint; use log::info; use serde::Serialize; -use utxo::{ - utxo_core::{UTXOPayload, UTXO}, -}; +use utxo::utxo_core::{UTXOPayload, UTXO}; use crate::key_management::{ constants_types::{CipherText, Nonce}, diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 25be979..5228e9b 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1101,11 +1101,7 @@ impl NodeCore { .map(|new_utxo_hash| { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1555,11 +1551,7 @@ impl NodeCore { .map(|(acc_addr_rec, new_utxo_hash)| { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( From f4b9aaffefcff0e70759fa6b0f18db0e3f5f17be Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:45:35 -0300 Subject: [PATCH 14/37] Remove nullifier attribute --- accounts/src/account_core/mod.rs | 29 +------- sc_core/src/lib.rs | 1 - sc_core/src/utxo_manipulator.rs | 110 ------------------------------- utxo/src/utxo_core.rs | 33 ---------- 4 files changed, 1 insertion(+), 172 deletions(-) delete mode 100644 sc_core/src/utxo_manipulator.rs diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 38d9e9c..280fc57 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, hash::Hash}; use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag}; +use common::{merkle_tree_public::TreeHashType, nullifier::{self, UTXONullifier}, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; @@ -84,19 +84,6 @@ impl Account { .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) } - pub fn mark_spent_utxo( - &mut self, - utxo_nullifier_map: HashMap, - ) -> Result<()> { - for (hash, nullifier) in utxo_nullifier_map { - if let Some(utxo_entry) = self.utxos.get_mut(&hash) { - utxo_entry.consume_utxo(nullifier)?; - } - } - - Ok(()) - } - pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { for utxo in utxos { if self.utxos.contains_key(&utxo.hash) { @@ -184,20 +171,6 @@ mod tests { assert!(account.key_holder.address != [0u8; 32]); // Check if the address is not empty } - #[test] - fn test_mark_spent_utxo() { - let mut account = Account::new(); - let utxo = generate_dummy_utxo(account.address, 100).unwrap(); - account.add_new_utxo_outputs(vec![utxo]).unwrap(); - - let mut utxo_nullifier_map = HashMap::new(); - utxo_nullifier_map.insert(account.address, generate_dummy_utxo_nullifier()); - - let result = account.mark_spent_utxo(utxo_nullifier_map); - - assert!(result.is_ok()); - } - #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); diff --git a/sc_core/src/lib.rs b/sc_core/src/lib.rs index 769813d..a41ab82 100644 --- a/sc_core/src/lib.rs +++ b/sc_core/src/lib.rs @@ -1,4 +1,3 @@ pub mod cryptography; pub mod proofs_circuits; pub mod transaction_payloads_tools; -pub mod utxo_manipulator; diff --git a/sc_core/src/utxo_manipulator.rs b/sc_core/src/utxo_manipulator.rs deleted file mode 100644 index 8bc0e32..0000000 --- a/sc_core/src/utxo_manipulator.rs +++ /dev/null @@ -1,110 +0,0 @@ -use anyhow::Result; -use common::nullifier::UTXONullifier; -use utxo::utxo_core::{UTXOPayload, UTXO}; - -pub fn utxo_change_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - new_owner: [u8; 32], -) -> Result { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount: utxo.amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(UTXO::create_utxo_from_payload(new_payload)?) -} - -pub fn utxo_substact_part_another_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, - new_owner: [u8; 32], -) -> Result<(UTXO, UTXO)> { - if amount > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let diff = utxo.amount - amount; - - let new_payload1 = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_payload2 = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(( - UTXO::create_utxo_from_payload(new_payload1)?, - UTXO::create_utxo_from_payload(new_payload2)?, - )) -} - -pub fn utxo_substract_part( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, -) -> Result<(UTXO, UTXO)> { - let new_owner = utxo.owner; - - utxo_substact_part_another_owner(utxo, nullifier, amount, new_owner) -} - -pub fn utxo_split_n_users( - utxo: &mut UTXO, - nullifier: UTXONullifier, - users_amounts: Vec<([u8; 32], u128)>, -) -> Result> { - let cumulative_diff = users_amounts - .iter() - .fold(0, |acc, (_, amount)| acc + *amount); - - if cumulative_diff > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let mut utxo_res = vec![]; - - for (new_owner, amount) in users_amounts { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - if cumulative_diff != utxo.amount { - let new_payload = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: utxo.amount - cumulative_diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - utxo.consume_utxo(nullifier)?; - - Ok(utxo_res) -} diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index a4777b3..c470968 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -12,7 +12,6 @@ pub type Asset = Vec; pub struct UTXO { pub hash: TreeHashType, pub owner: AccountId, - pub nullifier: Option, pub asset: Asset, // TODO: change to u256 pub amount: u128, @@ -41,23 +40,12 @@ impl UTXO { Ok(Self { hash, owner: payload_with_asset.owner, - nullifier: None, asset: payload_with_asset.asset, amount: payload_with_asset.amount, privacy_flag: payload_with_asset.privacy_flag, }) } - pub fn consume_utxo(&mut self, nullifier: UTXONullifier) -> Result<()> { - if self.nullifier.is_some() { - anyhow::bail!("UTXO already consumed"); - } else { - self.nullifier = Some(nullifier); - } - - Ok(()) - } - pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result { Ok(serde_json::from_slice(&self.asset)?) } @@ -74,10 +62,6 @@ impl UTXO { pub fn log(&self) { info!("UTXO hash is {:?}", hex::encode(self.hash)); info!("UTXO owner is {:?}", hex::encode(self.owner)); - info!( - "UTXO nullifier is {:?}", - self.nullifier.clone().map(|val| hex::encode(val.utxo_hash)) - ); info!("UTXO asset is {:?}", hex::encode(self.asset.clone())); info!("UTXO amount is {:?}", self.amount); info!("UTXO privacy_flag is {:?}", self.privacy_flag); @@ -127,23 +111,6 @@ mod tests { // Ensure hash is created and the UTXO fields are correctly assigned assert_eq!(utxo.owner, payload.owner); assert_eq!(utxo.asset, payload.asset); - assert!(utxo.nullifier.is_none()); - } - - #[test] - fn test_consume_utxo() { - let payload = sample_payload(); - let mut utxo = UTXO::create_utxo_from_payload(payload).unwrap(); - - let nullifier = sample_nullifier(); - - // First consumption should succeed - assert!(utxo.consume_utxo(nullifier.clone()).is_ok()); - assert_eq!(utxo.nullifier, Some(nullifier)); - - // Second consumption should fail - let result = utxo.consume_utxo(sample_nullifier()); - assert!(result.is_err()); } #[test] From efcd7976485418025caa03fe69e50a2e0afb30e5 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:54:11 -0300 Subject: [PATCH 15/37] fmt --- accounts/src/account_core/mod.rs | 6 +++++- utxo/src/utxo_core.rs | 10 +--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 280fc57..d19ebab 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,7 +1,11 @@ use std::{collections::HashMap, hash::Hash}; use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::{self, UTXONullifier}, transaction::Tag}; +use common::{ + merkle_tree_public::TreeHashType, + nullifier::{self, UTXONullifier}, + transaction::Tag, +}; use k256::AffinePoint; use log::info; use serde::Serialize; diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index c470968..3a3074e 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, AccountId}; +use common::{merkle_tree_public::TreeHashType, AccountId}; use log::info; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; @@ -82,14 +82,6 @@ mod tests { AccountId::default() } - fn sample_nullifier() -> UTXONullifier { - UTXONullifier::default() - } - - fn sample_tree_hash() -> TreeHashType { - TreeHashType::default() - } - fn sample_payload() -> UTXOPayload { UTXOPayload { owner: sample_account(), From b6700f8adb01f8bb2361c197fa9aee2e3a41983f Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:21:43 -0300 Subject: [PATCH 16/37] fmt --- accounts/src/account_core/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 38d9e9c..d5f5e90 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, hash::Hash}; +use std::collections::HashMap; use anyhow::Result; use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag}; From ef5d0260743ec41507c4a5bdf9c9f6a4c4d53219 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:23:35 -0300 Subject: [PATCH 17/37] fix tests --- accounts/src/account_core/mod.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index d19ebab..ea2f329 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,9 +1,8 @@ -use std::{collections::HashMap, hash::Hash}; +use std::collections::HashMap; use anyhow::Result; use common::{ merkle_tree_public::TreeHashType, - nullifier::{self, UTXONullifier}, transaction::Tag, }; use k256::AffinePoint; @@ -153,10 +152,6 @@ impl Default for Account { mod tests { use super::*; - fn generate_dummy_utxo_nullifier() -> UTXONullifier { - UTXONullifier::default() - } - fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> anyhow::Result { let payload = UTXOPayload { owner: address, From 67422a5cd8588c39dcda18a76df158cdab131059 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:33:38 -0300 Subject: [PATCH 18/37] fmt --- accounts/src/account_core/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index ea2f329..32c5359 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,10 +1,7 @@ use std::collections::HashMap; use anyhow::Result; -use common::{ - merkle_tree_public::TreeHashType, - transaction::Tag, -}; +use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; From 00fe02c1d102918fb679efc74f4c7e1017ce99d6 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 21 May 2025 08:34:03 +0300 Subject: [PATCH 19/37] fix: merge updates --- accounts/src/account_core/mod.rs | 25 ++++++------------------- node_core/src/chain_storage/mod.rs | 6 ++---- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 813f6fc..d5f5e90 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -116,9 +116,6 @@ impl Account { asset: Asset, amount: u128, privacy_flag: bool, - utxo_id: u64, - tx_id: u64, - block_id: u64, ) -> Result<()> { let payload_with_asset = UTXOPayload { owner: self.address, @@ -169,24 +166,14 @@ mod tests { UTXONullifier::default() } - fn generate_dummy_utxo( - address: TreeHashType, - amount: u128, - utxo_id: u64, - ) -> anyhow::Result { + fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> anyhow::Result { let payload = UTXOPayload { owner: address, asset: vec![], amount, privacy_flag: false, }; - let utxo = UTXO::create_utxo_from_payload(payload); - utxo.map(|utxo| UTXOTreeInput { - utxo_id, - tx_id: 1, - block_id: 1, - utxo, - }) + UTXO::create_utxo_from_payload(payload) } #[test] @@ -200,7 +187,7 @@ mod tests { #[test] fn test_mark_spent_utxo() { let mut account = Account::new(); - let utxo = generate_dummy_utxo(account.address, 100, 1).unwrap(); + let utxo = generate_dummy_utxo(account.address, 100).unwrap(); account.add_new_utxo_outputs(vec![utxo]).unwrap(); let mut utxo_nullifier_map = HashMap::new(); @@ -214,8 +201,8 @@ mod tests { #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); - let utxo1 = generate_dummy_utxo(account.address, 100, 1).unwrap(); - let utxo2 = generate_dummy_utxo(account.address, 200, 2).unwrap(); + let utxo1 = generate_dummy_utxo(account.address, 100).unwrap(); + let utxo2 = generate_dummy_utxo(account.address, 200).unwrap(); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); @@ -237,7 +224,7 @@ mod tests { let asset = "dummy_asset"; let amount = 1000u128; - let result = account.add_asset(asset, amount, false, 1, 1, 1); + let result = account.add_asset(asset, amount, false); assert!(result.is_ok()); assert_eq!(account.utxos.len(), 1); diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index c4eef13..90c9cb1 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -15,7 +15,7 @@ use common::{ }; use k256::AffinePoint; use public_context::PublicSCContext; -use utxo::{utxo_core::UTXO, utxo_tree::UTXOTreeInput}; +use utxo::utxo_core::UTXO; use crate::ActionData; @@ -115,9 +115,7 @@ impl NodeChainStore { let ephemeral_public_key_sender = serde_json::from_slice::(&tx.ephemeral_pub_key)?; - for (utxo_id, (ciphertext, nonce, tag)) in - tx.encoded_data.clone().into_iter().enumerate() - { + for (ciphertext, nonce, tag) in tx.encoded_data.clone() { let slice = nonce.as_slice(); let nonce = accounts::key_management::constants_types::Nonce::clone_from_slice(slice); From 00297db3ab1a080fe45cb0926e71e74f70acf233 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 22 May 2025 00:13:17 +0300 Subject: [PATCH 20/37] feat: indexed tree migration 1 --- Cargo.lock | 504 +++++---------------- Cargo.toml | 2 +- common/Cargo.toml | 2 +- common/src/indexed_merkle_tree.rs | 248 ++++++++++ common/src/lib.rs | 5 +- common/src/nullifier_sparse_merkle_tree.rs | 326 ------------- node_core/Cargo.toml | 2 +- node_core/src/chain_storage/mod.rs | 23 +- node_core/src/executions/de.rs | 50 +- node_core/src/executions/private_exec.rs | 50 +- node_core/src/executions/se.rs | 50 +- node_core/src/lib.rs | 2 +- node_rpc/src/types/err_rpc.rs | 1 - sc_core/Cargo.toml | 2 +- sc_core/src/proofs_circuits.rs | 66 +-- sequencer_core/src/lib.rs | 18 +- sequencer_core/src/sequencer_store/mod.rs | 6 +- utxo/Cargo.toml | 2 +- 18 files changed, 433 insertions(+), 926 deletions(-) create mode 100644 common/src/indexed_merkle_tree.rs delete mode 100644 common/src/nullifier_sparse_merkle_tree.rs diff --git a/Cargo.lock b/Cargo.lock index 8c84dec..b294ce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "utxo", ] @@ -132,7 +132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", - "cfg-if 1.0.0", + "cfg-if", "http 0.2.12", "regex", "regex-lite", @@ -204,7 +204,7 @@ dependencies = [ "ahash 0.7.8", "bytes", "bytestring", - "cfg-if 1.0.0", + "cfg-if", "derive_more 0.99.19", "encoding_rs", "futures-core", @@ -284,7 +284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -293,7 +293,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -309,15 +309,9 @@ dependencies = [ "cipher", "ctr", "ghash", - "subtle 2.6.1", + "subtle", ] -[[package]] -name = "ahash" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" - [[package]] name = "ahash" version = "0.7.8" @@ -335,7 +329,7 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "version_check", "zerocopy 0.7.35", @@ -411,10 +405,10 @@ dependencies = [ "ark-std", "blake2", "derivative", - "digest 0.10.7", + "digest", "fnv", "merlin", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -459,13 +453,13 @@ dependencies = [ "ark-ff-macros", "ark-serialize", "ark-std", - "arrayvec 0.7.6", - "digest 0.10.7", + "arrayvec", + "digest", "educe", "itertools 0.13.0", "num-bigint 0.4.6", "num-traits", - "paste 1.0.15", + "paste", "zeroize", ] @@ -559,8 +553,8 @@ checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", - "arrayvec 0.7.6", - "digest 0.10.7", + "arrayvec", + "digest", "num-bigint 0.4.6", ] @@ -603,27 +597,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.6" @@ -669,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line 0.24.2", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object 0.36.7", @@ -773,32 +746,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq", -] - -[[package]] -name = "blake3" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667d945f23cefed0b5f973af35c4bc3319caa6776fbda270e4897d8504afa8e4" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "cc", - "cfg-if 0.1.10", - "constant_time_eq", - "crypto-mac", - "digest 0.8.1", + "digest", ] [[package]] @@ -807,34 +755,24 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] -name = "block-padding" -version = "0.1.5" +name = "bls12_381" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" dependencies = [ - "byte-tools", + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -878,12 +816,6 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytemuck" version = "1.22.0" @@ -990,12 +922,6 @@ dependencies = [ "nom", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -1081,15 +1007,15 @@ dependencies = [ "anyhow", "elliptic-curve", "hex", + "indexed-merkle-tree", "log", - "monotree", "reqwest 0.11.27", "risc0-zkvm", "rs_merkle", "secp256k1-zkp", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "thiserror 1.0.69", ] @@ -1112,12 +1038,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "convert_case" version = "0.4.0" @@ -1157,7 +1077,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1175,7 +1095,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1224,9 +1144,9 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -1236,21 +1156,11 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "rand_core 0.6.4", "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array 0.12.4", - "subtle 1.0.0", -] - [[package]] name = "ctr" version = "0.9.2" @@ -1447,25 +1357,16 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -1527,7 +1428,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac1e888d6830712d565b2f3a974be3200be9296bc1b03db8251a4cbf18a4a34" dependencies = [ - "digest 0.10.7", + "digest", "futures", "rand 0.8.5", "reqwest 0.12.15", @@ -1552,7 +1453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "serdect", @@ -1592,15 +1493,15 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", - "generic-array 0.14.7", + "generic-array", "group", "pkcs8", "rand_core 0.6.4", "sec1", "serdect", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -1622,7 +1523,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1704,12 +1605,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1732,7 +1627,7 @@ dependencies = [ "byteorder", "ff_derive", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -1927,15 +1822,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1947,24 +1833,13 @@ dependencies = [ "zeroize", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -1977,7 +1852,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "r-efi", @@ -1991,7 +1866,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.1", + "opaque-debug", "polyval", ] @@ -2034,7 +1909,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -2065,16 +1940,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" -dependencies = [ - "ahash 0.3.8", - "autocfg", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -2170,7 +2035,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -2501,6 +2366,23 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" +[[package]] +name = "indexed-merkle-tree" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86e7e0a70243eb602dba292003d26682c23cff528c5b3c06c002d242a26d865" +dependencies = [ + "anyhow", + "bls12_381", + "borsh", + "hex", + "num", + "num-bigint 0.4.6", + "num-traits", + "serde", + "sha2", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -2527,7 +2409,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -2624,12 +2506,12 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.8", + "sha2", "signature", ] @@ -2698,7 +2580,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-targets 0.52.6", ] @@ -2970,7 +2852,7 @@ dependencies = [ "foreign-types 0.5.0", "log", "objc", - "paste 1.0.15", + "paste", ] [[package]] @@ -3012,25 +2894,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "monotree" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6724f66abef26ea20981177c87a500f2416a420d96daf50c5d96d97a10892d5f" -dependencies = [ - "blake2-rfc", - "blake3", - "digest 0.8.1", - "hashbrown 0.7.2", - "hex", - "num", - "paste 0.1.18", - "rand 0.7.3", - "scopeguard", - "sha2 0.8.2", - "sha3", -] - [[package]] name = "native-tls" version = "0.2.14" @@ -3055,7 +2918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" dependencies = [ "matrixmultiply", - "num-complex 0.4.6", + "num-complex", "num-integer", "num-traits", "portable-atomic", @@ -3093,9 +2956,9 @@ dependencies = [ "elliptic-curve", "env_logger", "hex", + "indexed-merkle-tree", "k256", "log", - "monotree", "rand 0.8.5", "reqwest 0.11.27", "risc0-zkvm", @@ -3103,7 +2966,7 @@ dependencies = [ "secp256k1-zkp", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "storage", "tempfile", "thiserror 1.0.69", @@ -3164,12 +3027,6 @@ dependencies = [ "zkvm", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "7.1.3" @@ -3182,29 +3039,18 @@ dependencies = [ [[package]] name = "num" -version = "0.2.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint 0.2.6", - "num-complex 0.2.4", + "num-bigint 0.4.6", + "num-complex", "num-integer", "num-iter", "num-rational", "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.3.3" @@ -3226,16 +3072,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-complex" version = "0.4.6" @@ -3284,12 +3120,11 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.2.4" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", - "num-bigint 0.2.6", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -3348,12 +3183,6 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opaque-debug" version = "0.3.1" @@ -3367,7 +3196,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ "bitflags 2.9.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types 0.3.2", "libc", "once_cell", @@ -3432,38 +3261,19 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "paste-impl" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" -dependencies = [ - "proc-macro-hack", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -3510,9 +3320,9 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug", "universal-hash", ] @@ -3602,12 +3412,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.94" @@ -3648,7 +3452,7 @@ checksum = "fa9dae7b05c02ec1a6bc9bcf20d8bc64a7dcbf57934107902a872014899b741f" dependencies = [ "anyhow", "byteorder", - "cfg-if 1.0.0", + "cfg-if", "itertools 0.10.5", "once_cell", "parking_lot", @@ -3729,19 +3533,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -3764,16 +3555,6 @@ dependencies = [ "zerocopy 0.8.24", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -3794,15 +3575,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -3821,15 +3593,6 @@ dependencies = [ "getrandom 0.3.2", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rawpointer" version = "0.2.1" @@ -4004,7 +3767,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -4014,7 +3777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if 1.0.0", + "cfg-if", "getrandom 0.2.15", "libc", "untrusted", @@ -4078,7 +3841,7 @@ dependencies = [ "glob", "hex", "rayon", - "sha2 0.10.8", + "sha2", "tempfile", ] @@ -4089,9 +3852,9 @@ source = "git+https://github.com/risc0/risc0.git?branch=release-2.0#fdd54f961b84 dependencies = [ "anyhow", "bytemuck", - "cfg-if 1.0.0", + "cfg-if", "keccak", - "paste 1.0.15", + "paste", "rayon", "risc0-binfmt", "risc0-circuit-keccak-sys", @@ -4125,7 +3888,7 @@ source = "git+https://github.com/risc0/risc0.git?branch=release-2.0#fdd54f961b84 dependencies = [ "anyhow", "bytemuck", - "cfg-if 1.0.0", + "cfg-if", "cust", "downloader", "hex", @@ -4138,7 +3901,7 @@ dependencies = [ "risc0-sys", "risc0-zkp", "serde", - "sha2 0.10.8", + "sha2", "tracing", "zip", ] @@ -4165,13 +3928,13 @@ dependencies = [ "bit-vec", "bytemuck", "byteorder", - "cfg-if 1.0.0", + "cfg-if", "derive_more 2.0.1", "enum-map", "malachite", "num-derive", "num-traits", - "paste 1.0.15", + "paste", "postcard", "rand 0.8.5", "rayon", @@ -4266,16 +4029,16 @@ dependencies = [ "blake2", "borsh", "bytemuck", - "cfg-if 1.0.0", + "cfg-if", "cust", - "digest 0.10.7", + "digest", "ff", "hex", "hex-literal", "metal", "ndarray", "parking_lot", - "paste 1.0.15", + "paste", "rand 0.8.5", "rand_core 0.6.4", "rayon", @@ -4283,7 +4046,7 @@ dependencies = [ "risc0-sys", "risc0-zkvm-platform", "serde", - "sha2 0.10.8", + "sha2", "stability", "tracing", ] @@ -4327,7 +4090,7 @@ dependencies = [ "rzup", "semver", "serde", - "sha2 0.10.8", + "sha2", "stability", "tempfile", "tracing", @@ -4340,7 +4103,7 @@ version = "2.0.1" source = "git+https://github.com/risc0/risc0.git?branch=release-2.0#fdd54f961b84b38831a8a488b9d67534a02d80a2" dependencies = [ "bytemuck", - "cfg-if 1.0.0", + "cfg-if", "getrandom 0.2.15", "libm", "stability", @@ -4363,7 +4126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001" dependencies = [ "downcast-rs", - "paste 1.0.15", + "paste", ] [[package]] @@ -4372,7 +4135,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" dependencies = [ - "sha2 0.10.8", + "sha2", ] [[package]] @@ -4438,7 +4201,7 @@ dependencies = [ "ring", "rustls-pki-types", "rustls-webpki", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -4530,16 +4293,16 @@ dependencies = [ "elliptic-curve", "env_logger", "hex", + "indexed-merkle-tree", "k256", "light-poseidon", "log", - "monotree", "rand 0.8.5", "risc0-zkvm", "secp256k1-zkp", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "storage", "utxo", ] @@ -4567,10 +4330,10 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array", "pkcs8", "serdect", - "subtle 2.6.1", + "subtle", "zeroize", ] @@ -4782,21 +4545,9 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", + "digest", ] [[package]] @@ -4805,22 +4556,9 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", - "keccak", - "opaque-debug 0.2.3", + "digest", ] [[package]] @@ -4844,7 +4582,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", + "digest", "rand_core 0.6.4", ] @@ -4990,12 +4728,6 @@ dependencies = [ "syn 2.0.100", ] -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - [[package]] name = "subtle" version = "2.6.1" @@ -5398,7 +5130,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "static_assertions", ] @@ -5457,7 +5189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.6.1", + "subtle", ] [[package]] @@ -5497,11 +5229,11 @@ dependencies = [ "common", "env_logger", "hex", + "indexed-merkle-tree", "log", - "monotree", "serde", "serde_json", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -5554,12 +5286,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5581,7 +5307,7 @@ version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -5607,7 +5333,7 @@ version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "once_cell", "wasm-bindgen", @@ -6002,7 +5728,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index 59417cd..edad918 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ lru = "0.7.8" thiserror = "1.0" rs_merkle = "1.4" sha2 = "0.10.8" -monotree = "0.1.5" hex = "0.4.3" aes-gcm = "0.10.3" toml = "0.7.4" @@ -46,6 +45,7 @@ tempfile = "3.14.0" light-poseidon = "0.3.0" ark-bn254 = "0.5.0" ark-ff = "0.5.0" +indexed-merkle-tree = "0.6.2" rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/common/Cargo.toml b/common/Cargo.toml index f3327ea..4d2f52b 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -9,7 +9,7 @@ thiserror.workspace = true serde_json.workspace = true serde.workspace = true reqwest.workspace = true -monotree.workspace = true +indexed-merkle-tree.workspace = true risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.0" } rs_merkle.workspace = true diff --git a/common/src/indexed_merkle_tree.rs b/common/src/indexed_merkle_tree.rs new file mode 100644 index 0000000..e8df6b5 --- /dev/null +++ b/common/src/indexed_merkle_tree.rs @@ -0,0 +1,248 @@ +use crate::merkle_tree_public::TreeHashType; + +use anyhow::Result; +use indexed_merkle_tree::node::Node; +use indexed_merkle_tree::tree::{IndexedMerkleTree, NonMembershipProof}; +use indexed_merkle_tree::Hash; + +pub struct IndexedMerkleTreeWrapper { + pub tree: IndexedMerkleTree, + pub leaf_len: usize, + //pub leafs: BTreeMap, +} + +impl IndexedMerkleTreeWrapper { + pub fn new() -> Self { + Self { + //Will not panic + //Deterministic operation + tree: IndexedMerkleTree::new(vec![]).unwrap(), + leaf_len: 0, + } + } + + pub fn get_curr_root(&self) -> Result { + //HELP + // self.tree.get_root().map(|node| + // serde_json::from_str::>(&serde_json::to_string(node).unwrap())[0] + // ) + Ok([0; 32]) + } + + pub fn insert_item(&mut self, hash: TreeHashType) -> Result<()> { + let left_parity = self.leaf_len / 2; + let mut node = match left_parity { + 0 => Node::new_leaf(true, Hash::new(hash), Hash::new(hash), Node::TAIL), + 1 => Node::new_leaf(false, Hash::new(hash), Hash::new(hash), Node::TAIL), + _ => unreachable!(), + }; + + self.tree.insert_node(&mut node)?; + + self.leaf_len += 1; + + Ok(()) + } + + pub fn insert_items(&mut self, tree_nullifiers: Vec) -> Result<()> { + for tree_nullifier in tree_nullifiers { + self.insert_item(tree_nullifier)?; + } + + Ok(()) + } + + pub fn search_item_inclusion(&mut self, nullifier_hash: TreeHashType) -> bool { + self.tree + .find_leaf_by_label(&Hash::new(nullifier_hash)) + .is_some() + } + + pub fn search_item_inclusions(&mut self, nullifier_hashes: &[TreeHashType]) -> Vec { + let mut inclusions = vec![]; + + for nullifier_hash in nullifier_hashes { + let is_included = self.search_item_inclusion(*nullifier_hash); + + inclusions.push(is_included); + } + + inclusions + } + + pub fn get_non_membership_proof( + &mut self, + nullifier_hash: TreeHashType, + ) -> Result { + let node = Node::new_leaf( + false, + Hash::new(nullifier_hash), + Hash::new(nullifier_hash), + Node::TAIL, + ); + + self.tree.generate_non_membership_proof(&node) + } + + #[allow(clippy::type_complexity)] + pub fn get_non_membership_proofs( + &mut self, + nullifier_hashes: &[TreeHashType], + ) -> Result> { + let mut non_membership_proofs = vec![]; + + for nullifier_hash in nullifier_hashes { + let non_mem_proof = self.get_non_membership_proof(*nullifier_hash)?; + + non_membership_proofs.push(non_mem_proof); + } + + Ok(non_membership_proofs) + } +} + +impl Default for IndexedMerkleTreeWrapper { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + // use super::*; + // use crate::nullifier::UTXONullifier; + + // fn create_nullifier(hash: TreeHashType) -> UTXONullifier { + // UTXONullifier { utxo_hash: hash } + // } + + // fn create_nullifier_input( + // hash: TreeHashType, + // nullifier_id: u64, + // tx_id: u64, + // block_id: u64, + // ) -> NullifierTreeInput { + // NullifierTreeInput { + // nullifier_id, + // tx_id, + // block_id, + // nullifier: create_nullifier(hash), + // } + // } + + // #[test] + // fn test_new_tree_initialization() { + // let tree = IndexedMerkleTree::new(); + // assert!(tree.curr_root.is_none()); + // } + + // #[test] + // fn test_insert_single_item() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); // Sample 32-byte hash + + // let result = tree.insert_item(tree_nullifier); + // assert!(result.is_ok()); + // assert!(tree.curr_root.is_some()); + // } + + // #[test] + // fn test_insert_multiple_items() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifiers = vec![ + // create_nullifier_input([1u8; 32], 1, 1, 1), + // create_nullifier_input([2u8; 32], 2, 1, 1), + // create_nullifier_input([3u8; 32], 3, 1, 1), + // ]; + + // let result = tree.insert_items(tree_nullifiers); + // assert!(result.is_ok()); + // assert!(tree.curr_root.is_some()); + // } + + // #[test] + // fn test_search_item_inclusion() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); + + // tree.insert_item(tree_nullifier.clone()).unwrap(); + + // let result = tree.search_item_inclusion([1u8; 32]); + // assert!(result.is_ok()); + // assert_eq!(result.unwrap(), true); + + // let non_existing = tree.search_item_inclusion([99u8; 32]); + // assert!(non_existing.is_ok()); + // assert_eq!(non_existing.unwrap(), false); + // } + + // #[test] + // fn test_search_multiple_item_inclusions() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifiers = vec![ + // create_nullifier_input([1u8; 32], 1, 1, 1), + // create_nullifier_input([2u8; 32], 2, 1, 1), + // create_nullifier_input([3u8; 32], 3, 1, 1), + // ]; + + // tree.insert_items(tree_nullifiers).unwrap(); + + // let search_hashes = vec![[1u8; 32], [2u8; 32], [99u8; 32]]; + // let result = tree.search_item_inclusions(&search_hashes); + // assert!(result.is_ok()); + + // let expected_results = vec![true, true, false]; + // assert_eq!(result.unwrap(), expected_results); + // } + + // #[test] + // fn test_non_membership_proof() { + // let mut tree = IndexedMerkleTree::new(); + // let non_member_hash = [5u8; 32]; + + // let result = tree.get_non_membership_proof(non_member_hash); + // assert!(result.is_ok()); + + // let (proof, root) = result.unwrap(); + // assert!(root.is_none()); + // } + + // #[test] + // fn test_non_membership_proofs_multiple() { + // let mut tree = IndexedMerkleTree::new(); + // let non_member_hashes = vec![[5u8; 32], [6u8; 32], [7u8; 32]]; + + // let result = tree.get_non_membership_proofs(&non_member_hashes); + // assert!(result.is_ok()); + + // let proofs = result.unwrap(); + // for (proof, root) in proofs { + // assert!(root.is_none()); + // } + // } + + // #[test] + // fn test_insert_and_get_proof_of_existing_item() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); + + // tree.insert_item(tree_nullifier.clone()).unwrap(); + + // let proof_result = tree.get_non_membership_proof([1u8; 32]); + // assert!(proof_result.is_err()); + // } + + // #[test] + // fn test_insert_and_get_proofs_of_existing_items() { + // let mut tree = IndexedMerkleTree::new(); + // let tree_nullifiers = vec![ + // create_nullifier_input([1u8; 32], 1, 1, 1), + // create_nullifier_input([2u8; 32], 2, 1, 1), + // ]; + + // tree.insert_items(tree_nullifiers).unwrap(); + + // let proof_result = tree.get_non_membership_proofs(&[[1u8; 32], [2u8; 32]]); + // assert!(proof_result.is_err()); + // } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index a13fdd4..9e238e2 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,10 +3,9 @@ use serde::Deserialize; pub mod block; pub mod commitment; -pub mod commitments_sparse_merkle_tree; +pub mod indexed_merkle_tree; pub mod merkle_tree_public; pub mod nullifier; -pub mod nullifier_sparse_merkle_tree; pub mod rpc_primitives; pub mod transaction; pub mod utxo_commitment; @@ -67,8 +66,6 @@ pub enum ExecutionFailureKind { AmountMismatchError, #[error("Sequencer client error: {0:?}")] SequencerClientError(#[from] SequencerClientError), - #[error("Datebase returned error : {0:?}")] - MonoTreeError(#[from] monotree::Errors), #[error("Insufficient gas for operation")] InsufficientGasError, #[error("Can not pay for operation")] diff --git a/common/src/nullifier_sparse_merkle_tree.rs b/common/src/nullifier_sparse_merkle_tree.rs deleted file mode 100644 index c6707a7..0000000 --- a/common/src/nullifier_sparse_merkle_tree.rs +++ /dev/null @@ -1,326 +0,0 @@ -use std::collections::BTreeMap; - -use monotree::database::MemoryDB; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree, Proof}; - -use crate::merkle_tree_public::TreeHashType; -use crate::nullifier::UTXONullifier; - -#[derive(Debug, Clone)] -pub struct NullifierTreeInput { - pub nullifier_id: u64, - pub tx_id: u64, - pub block_id: u64, - pub nullifier: UTXONullifier, -} - -#[derive(Debug, Clone)] -pub struct TreeTxWithNullifierId { - pub id: u64, - pub nullifiers: BTreeMap, -} - -#[derive(Debug, Clone)] -pub struct TreeBlockWithTxId { - pub id: u64, - pub txs: BTreeMap, -} - -pub struct NullifierSparseMerkleTree { - pub curr_root: Option, - pub tree: Monotree, - pub hasher: Blake3, - pub leafs: BTreeMap, -} - -impl NullifierSparseMerkleTree { - pub fn new() -> Self { - NullifierSparseMerkleTree { - curr_root: None, - tree: Monotree::default(), - hasher: Blake3::new(), - leafs: BTreeMap::new(), - } - } - - pub fn modify_leavs_with_nullifier_input(&mut self, tree_nullifier: NullifierTreeInput) { - self.leafs - .entry(tree_nullifier.block_id) - .and_modify(|tree_block| { - tree_block - .txs - .entry(tree_nullifier.tx_id) - .and_modify(|tree_tx| { - tree_tx - .nullifiers - .insert(tree_nullifier.nullifier_id, tree_nullifier.nullifier); - }) - .or_insert(TreeTxWithNullifierId { - id: tree_nullifier.tx_id, - nullifiers: BTreeMap::new(), - }); - }) - .or_insert(TreeBlockWithTxId { - id: tree_nullifier.block_id, - txs: BTreeMap::new(), - }); - } - - pub fn insert_item( - &mut self, - tree_nullifier: NullifierTreeInput, - ) -> Result<(), monotree::Errors> { - let root = self.curr_root.as_ref(); - - let new_root = self.tree.insert( - root, - &tree_nullifier.nullifier.utxo_hash, - &tree_nullifier.nullifier.utxo_hash, - )?; - - self.curr_root = new_root; - - self.modify_leavs_with_nullifier_input(tree_nullifier); - - Ok(()) - } - - pub fn insert_items( - &mut self, - tree_nullifiers: Vec, - ) -> Result<(), monotree::Errors> { - let root = self.curr_root.as_ref(); - - let hashes: Vec = tree_nullifiers - .iter() - .map(|nu| nu.nullifier.utxo_hash) - .collect(); - - let new_root = self.tree.inserts(root, &hashes, &hashes)?; - - self.curr_root = new_root; - - for tree_nullifier in tree_nullifiers { - self.modify_leavs_with_nullifier_input(tree_nullifier); - } - - Ok(()) - } - - pub fn search_item_inclusion( - &mut self, - nullifier_hash: TreeHashType, - ) -> Result { - self.tree - .get(self.curr_root.as_ref(), &nullifier_hash) - .map(|data| data.is_some()) - } - - pub fn search_item_inclusions( - &mut self, - nullifier_hashes: &[TreeHashType], - ) -> Result, monotree::Errors> { - let mut inclusions = vec![]; - - for nullifier_hash in nullifier_hashes { - let is_included = self - .tree - .get(self.curr_root.as_ref(), nullifier_hash) - .map(|data| data.is_some())?; - - inclusions.push(is_included); - } - - Ok(inclusions) - } - - pub fn get_non_membership_proof( - &mut self, - nullifier_hash: TreeHashType, - ) -> Result<(Option, Option), monotree::Errors> { - let is_member = self.search_item_inclusion(nullifier_hash)?; - - if is_member { - Err(monotree::Errors::new("Is a member")) - } else { - Ok(( - self.tree - .get_merkle_proof(self.curr_root.as_ref(), &nullifier_hash)?, - self.curr_root, - )) - } - } - - #[allow(clippy::type_complexity)] - pub fn get_non_membership_proofs( - &mut self, - nullifier_hashes: &[TreeHashType], - ) -> Result, Option)>, monotree::Errors> { - let mut non_membership_proofs = vec![]; - - for nullifier_hash in nullifier_hashes { - let is_member = self.search_item_inclusion(*nullifier_hash)?; - - if is_member { - return Err(monotree::Errors::new( - format!("{nullifier_hash:?} Is a member").as_str(), - )); - } else { - non_membership_proofs.push(( - self.tree - .get_merkle_proof(self.curr_root.as_ref(), nullifier_hash)?, - self.curr_root, - )) - }; - } - - Ok(non_membership_proofs) - } -} - -impl Default for NullifierSparseMerkleTree { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::nullifier::UTXONullifier; - - fn create_nullifier(hash: TreeHashType) -> UTXONullifier { - UTXONullifier { utxo_hash: hash } - } - - fn create_nullifier_input( - hash: TreeHashType, - nullifier_id: u64, - tx_id: u64, - block_id: u64, - ) -> NullifierTreeInput { - NullifierTreeInput { - nullifier_id, - tx_id, - block_id, - nullifier: create_nullifier(hash), - } - } - - #[test] - fn test_new_tree_initialization() { - let tree = NullifierSparseMerkleTree::new(); - assert!(tree.curr_root.is_none()); - } - - #[test] - fn test_insert_single_item() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); // Sample 32-byte hash - - let result = tree.insert_item(tree_nullifier); - assert!(result.is_ok()); - assert!(tree.curr_root.is_some()); - } - - #[test] - fn test_insert_multiple_items() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifiers = vec![ - create_nullifier_input([1u8; 32], 1, 1, 1), - create_nullifier_input([2u8; 32], 2, 1, 1), - create_nullifier_input([3u8; 32], 3, 1, 1), - ]; - - let result = tree.insert_items(tree_nullifiers); - assert!(result.is_ok()); - assert!(tree.curr_root.is_some()); - } - - #[test] - fn test_search_item_inclusion() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - - tree.insert_item(tree_nullifier.clone()).unwrap(); - - let result = tree.search_item_inclusion([1u8; 32]); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); - - let non_existing = tree.search_item_inclusion([99u8; 32]); - assert!(non_existing.is_ok()); - assert_eq!(non_existing.unwrap(), false); - } - - #[test] - fn test_search_multiple_item_inclusions() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifiers = vec![ - create_nullifier_input([1u8; 32], 1, 1, 1), - create_nullifier_input([2u8; 32], 2, 1, 1), - create_nullifier_input([3u8; 32], 3, 1, 1), - ]; - - tree.insert_items(tree_nullifiers).unwrap(); - - let search_hashes = vec![[1u8; 32], [2u8; 32], [99u8; 32]]; - let result = tree.search_item_inclusions(&search_hashes); - assert!(result.is_ok()); - - let expected_results = vec![true, true, false]; - assert_eq!(result.unwrap(), expected_results); - } - - #[test] - fn test_non_membership_proof() { - let mut tree = NullifierSparseMerkleTree::new(); - let non_member_hash = [5u8; 32]; - - let result = tree.get_non_membership_proof(non_member_hash); - assert!(result.is_ok()); - - let (proof, root) = result.unwrap(); - assert!(root.is_none()); - } - - #[test] - fn test_non_membership_proofs_multiple() { - let mut tree = NullifierSparseMerkleTree::new(); - let non_member_hashes = vec![[5u8; 32], [6u8; 32], [7u8; 32]]; - - let result = tree.get_non_membership_proofs(&non_member_hashes); - assert!(result.is_ok()); - - let proofs = result.unwrap(); - for (proof, root) in proofs { - assert!(root.is_none()); - } - } - - #[test] - fn test_insert_and_get_proof_of_existing_item() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - - tree.insert_item(tree_nullifier.clone()).unwrap(); - - let proof_result = tree.get_non_membership_proof([1u8; 32]); - assert!(proof_result.is_err()); - } - - #[test] - fn test_insert_and_get_proofs_of_existing_items() { - let mut tree = NullifierSparseMerkleTree::new(); - let tree_nullifiers = vec![ - create_nullifier_input([1u8; 32], 1, 1, 1), - create_nullifier_input([2u8; 32], 2, 1, 1), - ]; - - tree.insert_items(tree_nullifiers).unwrap(); - - let proof_result = tree.get_non_membership_proofs(&[[1u8; 32], [2u8; 32]]); - assert!(proof_result.is_err()); - } -} diff --git a/node_core/Cargo.toml b/node_core/Cargo.toml index d948e79..2b59783 100644 --- a/node_core/Cargo.toml +++ b/node_core/Cargo.toml @@ -12,7 +12,7 @@ serde.workspace = true rand.workspace = true k256.workspace = true sha2.workspace = true -monotree.workspace = true +indexed-merkle-tree.workspace = true bincode.workspace = true elliptic-curve.workspace = true reqwest.workspace = true diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 90c9cb1..7fb3d85 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -8,9 +8,9 @@ use anyhow::Result; use block_store::NodeBlockStore; use common::{ block::Block, + indexed_merkle_tree::IndexedMerkleTreeWrapper, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, - nullifier_sparse_merkle_tree::{NullifierSparseMerkleTree, NullifierTreeInput}, utxo_commitment::UTXOCommitment, }; use k256::AffinePoint; @@ -26,7 +26,7 @@ pub mod public_context; pub struct NodeChainStore { pub acc_map: HashMap, pub block_store: NodeBlockStore, - pub nullifier_store: NullifierSparseMerkleTree, + pub nullifier_store: IndexedMerkleTreeWrapper, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, } @@ -34,7 +34,7 @@ pub struct NodeChainStore { impl NodeChainStore { pub fn new_with_genesis(home_dir: &Path, genesis_block: Block) -> Self { let acc_map = HashMap::new(); - let nullifier_store = NullifierSparseMerkleTree::default(); + let nullifier_store = IndexedMerkleTreeWrapper::default(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); @@ -97,19 +97,8 @@ impl NodeChainStore { .collect(), ); - self.nullifier_store.insert_items( - tx.nullifier_created_hashes - .clone() - .into_iter() - .enumerate() - .map(|(idx, hash)| NullifierTreeInput { - nullifier_id: idx as u64, - tx_id: tx_id as u64, - block_id: block.block_id, - nullifier: UTXONullifier { utxo_hash: hash }, - }) - .collect(), - )?; + self.nullifier_store + .insert_items(tx.nullifier_created_hashes.clone())?; if !tx.encoded_data.is_empty() { let ephemeral_public_key_sender = @@ -159,7 +148,7 @@ impl NodeChainStore { caller_address: caller, caller_balance: self.acc_map.get(&caller).unwrap().balance, account_masks, - nullifier_store_root: self.nullifier_store.curr_root.unwrap_or([0; 32]), + nullifier_store_root: self.nullifier_store.get_curr_root().unwrap_or([0; 32]), comitment_store_root: self.utxo_commitments_store.get_root().unwrap_or([0; 32]), pub_tx_store_root: self.pub_tx_store.get_root().unwrap_or([0; 32]), } diff --git a/node_core/src/executions/de.rs b/node_core/src/executions/de.rs index ddc5e81..68acb7b 100644 --- a/node_core/src/executions/de.rs +++ b/node_core/src/executions/de.rs @@ -1,14 +1,10 @@ use std::collections::BTreeMap; use bincode; -use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ - commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, - nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, + commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, }; use k256::Scalar; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree}; use rand::thread_rng; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; use sha2::{Digest, Sha256}; @@ -80,24 +76,16 @@ pub fn validate_in_commitments_proof( // Replace with Merkle proof verification logic. // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - let mut nsmt = CommitmentsSparseMerkleTree { - curr_root: Option::Some(root_commitment), - tree: Monotree::default(), - hasher: Blake3::new(), - }; + let mut nsmt = IndexedMerkleTreeWrapper::new(); let commitments: Vec<_> = in_commitments_proof .into_iter() - .map(|n_p| Commitment { - commitment_hash: n_p.clone(), - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(in_commitment.clone()) - .unwrap() - .1 - .is_some() + nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) + .is_ok() } // Validate non-membership proof for nullifiers @@ -109,32 +97,16 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { - //There is no need for storage, so ids can be default there - let id = 1; + let mut nsmt = IndexedMerkleTreeWrapper::new(); - let mut nsmt = NullifierSparseMerkleTree { - curr_root: Option::Some(root_nullifier), - tree: Monotree::default(), - hasher: Blake3::new(), - leafs: BTreeMap::new(), - }; - - let nullifiers: Vec<_> = nullifiers_proof + let commitments: Vec<_> = nullifiers_proof .into_iter() - .enumerate() - .map(|(idx, n_p)| NullifierTreeInput { - nullifier_id: idx as u64, - tx_id: id, - block_id: id, - nullifier: UTXONullifier { utxo_hash: *n_p }, - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); - nsmt.insert_items(nullifiers).unwrap(); + nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(nullifier) - .unwrap() - .1 - .is_none() + nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) + .is_ok() } // Check balances diff --git a/node_core/src/executions/private_exec.rs b/node_core/src/executions/private_exec.rs index e3d55a1..4f61bd3 100644 --- a/node_core/src/executions/private_exec.rs +++ b/node_core/src/executions/private_exec.rs @@ -1,14 +1,10 @@ use std::collections::BTreeMap; use bincode; -use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ - commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, - nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, + commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, }; use k256::Scalar; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree}; use sha2::{Digest, Sha256}; use utxo::utxo_core::UTXO; @@ -53,24 +49,16 @@ pub fn validate_in_commitments_proof( // Replace with Merkle proof verification logic. // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - let mut nsmt = CommitmentsSparseMerkleTree { - curr_root: Option::Some(root_commitment), - tree: Monotree::default(), - hasher: Blake3::new(), - }; + let mut nsmt = IndexedMerkleTreeWrapper::new(); let commitments: Vec<_> = in_commitments_proof .into_iter() - .map(|n_p| Commitment { - commitment_hash: n_p.clone(), - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(in_commitment.clone()) - .unwrap() - .1 - .is_some() + nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) + .is_ok() } // Validate non-membership proof for nullifiers @@ -82,32 +70,16 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { - //There is no need for storage, so ids can be default there - let id = 1; + let mut nsmt = IndexedMerkleTreeWrapper::new(); - let mut nsmt = NullifierSparseMerkleTree { - curr_root: Option::Some(root_nullifier), - tree: Monotree::default(), - hasher: Blake3::new(), - leafs: BTreeMap::new(), - }; - - let nullifiers: Vec<_> = nullifiers_proof + let commitments: Vec<_> = nullifiers_proof .into_iter() - .enumerate() - .map(|(idx, n_p)| NullifierTreeInput { - nullifier_id: idx as u64, - tx_id: id, - block_id: id, - nullifier: UTXONullifier { utxo_hash: *n_p }, - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); - nsmt.insert_items(nullifiers).unwrap(); + nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(nullifier) - .unwrap() - .1 - .is_none() + nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) + .is_ok() } #[allow(unused)] diff --git a/node_core/src/executions/se.rs b/node_core/src/executions/se.rs index f9123c2..6b7285c 100644 --- a/node_core/src/executions/se.rs +++ b/node_core/src/executions/se.rs @@ -1,14 +1,10 @@ use std::collections::BTreeMap; use bincode; -use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ - commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, - nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, + commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, }; use k256::Scalar; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree}; use rand::thread_rng; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; use sha2::{Digest, Sha256}; @@ -80,24 +76,16 @@ pub fn validate_in_commitments_proof( root_commitment: Vec, in_commitments_proof: &[Vec], ) -> bool { - let mut nsmt = CommitmentsSparseMerkleTree { - curr_root: Option::Some(root_commitment), - tree: Monotree::default(), - hasher: Blake3::new(), - }; + let mut nsmt = IndexedMerkleTreeWrapper::new(); let commitments: Vec<_> = in_commitments_proof .into_iter() - .map(|n_p| Commitment { - commitment_hash: n_p.clone(), - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec()) - .unwrap() - .1 - .is_some() + nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec().try_into().unwrap()) + .is_ok() } // Validate non-membership proof for nullifiers @@ -111,32 +99,16 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { - //There is no need for storage, so ids can be default there - let id = 1; + let mut nsmt = IndexedMerkleTreeWrapper::new(); - let mut nsmt = NullifierSparseMerkleTree { - curr_root: Option::Some(root_nullifier), - tree: Monotree::default(), - hasher: Blake3::new(), - leafs: BTreeMap::new(), - }; - - let nullifiers: Vec<_> = nullifiers_proof + let commitments: Vec<_> = nullifiers_proof .into_iter() - .enumerate() - .map(|(idx, n_p)| NullifierTreeInput { - nullifier_id: idx as u64, - tx_id: id, - block_id: id, - nullifier: UTXONullifier { utxo_hash: *n_p }, - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); - nsmt.insert_items(nullifiers).unwrap(); + nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(nullifier) - .unwrap() - .1 - .is_none() + nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) + .is_ok() } // Check balances diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 5228e9b..5fc9289 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -167,7 +167,7 @@ impl NodeCore { pub async fn get_roots(&self) -> [[u8; 32]; 3] { let storage = self.storage.read().await; [ - storage.nullifier_store.curr_root.unwrap_or([0; 32]), + storage.nullifier_store.get_curr_root().unwrap_or([0; 32]), storage.utxo_commitments_store.get_root().unwrap_or([0; 32]), storage.pub_tx_store.get_root().unwrap_or([0; 32]), ] diff --git a/node_rpc/src/types/err_rpc.rs b/node_rpc/src/types/err_rpc.rs index e1ace1f..0e75f7a 100644 --- a/node_rpc/src/types/err_rpc.rs +++ b/node_rpc/src/types/err_rpc.rs @@ -81,6 +81,5 @@ pub fn cast_common_execution_error_into_rpc_error(comm_exec_err: ExecutionFailur ExecutionFailureKind::SequencerClientError(seq_cli_err) => { cast_seq_client_error_into_rpc_error(seq_cli_err) } - ExecutionFailureKind::MonoTreeError(_) => RpcError::new_internal_error(None, &error_string), } } diff --git a/sc_core/Cargo.toml b/sc_core/Cargo.toml index 55ba888..4401ddb 100644 --- a/sc_core/Cargo.toml +++ b/sc_core/Cargo.toml @@ -12,7 +12,7 @@ serde.workspace = true rand.workspace = true k256.workspace = true sha2.workspace = true -monotree.workspace = true +indexed-merkle-tree.workspace = true bincode.workspace = true elliptic-curve.workspace = true hex.workspace = true diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 3574ec4..5bc63ae 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -1,14 +1,10 @@ use std::collections::BTreeMap; use bincode; -use common::nullifier_sparse_merkle_tree::NullifierTreeInput; use common::{ - commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, - nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, + commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, }; use k256::Scalar; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree}; use rand::{thread_rng, RngCore}; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; use sha2::{Digest, Sha256}; @@ -55,24 +51,16 @@ pub fn validate_in_commitments_proof( // Replace with Merkle proof verification logic. // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - let mut nsmt = CommitmentsSparseMerkleTree { - curr_root: Option::Some(root_commitment), - tree: Monotree::default(), - hasher: Blake3::new(), - }; + let mut nsmt = IndexedMerkleTreeWrapper::new(); let commitments: Vec<_> = in_commitments_proof .into_iter() - .map(|n_p| Commitment { - commitment_hash: n_p.clone(), - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(in_commitment.clone()) - .unwrap() - .1 - .is_some() + nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) + .is_ok() } // Validate non-membership proof for nullifiers @@ -84,32 +72,16 @@ pub fn validate_nullifiers_proof( root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { - //There is no need for storage, so ids can be default there - let id = 1; + let mut nsmt = IndexedMerkleTreeWrapper::new(); - let mut nsmt = NullifierSparseMerkleTree { - curr_root: Option::Some(root_nullifier), - tree: Monotree::default(), - hasher: Blake3::new(), - leafs: BTreeMap::new(), - }; - - let nullifiers: Vec<_> = nullifiers_proof + let commitments: Vec<_> = nullifiers_proof .into_iter() - .enumerate() - .map(|(idx, n_p)| NullifierTreeInput { - nullifier_id: idx as u64, - tx_id: id, - block_id: id, - nullifier: UTXONullifier { utxo_hash: *n_p }, - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); - nsmt.insert_items(nullifiers).unwrap(); + nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(nullifier) - .unwrap() - .1 - .is_none() + nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) + .is_ok() } #[allow(unused)] @@ -277,24 +249,16 @@ pub fn validate_in_commitments_proof_se( root_commitment: Vec, in_commitments_proof: &[Vec], ) -> bool { - let mut nsmt = CommitmentsSparseMerkleTree { - curr_root: Option::Some(root_commitment), - tree: Monotree::default(), - hasher: Blake3::new(), - }; + let mut nsmt = IndexedMerkleTreeWrapper::new(); let commitments: Vec<_> = in_commitments_proof .into_iter() - .map(|n_p| Commitment { - commitment_hash: n_p.clone(), - }) + .map(|n_p| n_p.clone().try_into().unwrap()) .collect(); nsmt.insert_items(commitments).unwrap(); - nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec()) - .unwrap() - .1 - .is_some() + nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec().try_into().unwrap()) + .is_ok() } // Generate nullifiers SE diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 647af9b..4a055d8 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -5,7 +5,6 @@ use common::{ block::{Block, HashableBlockData}, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, - nullifier_sparse_merkle_tree::NullifierTreeInput, transaction::{Transaction, TxKind}, utxo_commitment::UTXOCommitment, }; @@ -62,7 +61,10 @@ impl SequencerCore { pub fn get_tree_roots(&self) -> [[u8; 32]; 3] { [ - self.store.nullifier_store.curr_root.unwrap_or([0; 32]), + self.store + .nullifier_store + .get_curr_root() + .unwrap_or([0; 32]), self.store .utxo_commitments_store .get_root() @@ -139,7 +141,6 @@ impl SequencerCore { self.store .nullifier_store .search_item_inclusion(*nullifier_hash) - .unwrap_or(false) }) .any(|check| check); let utxo_commitments_check = utxo_commitments_created_hashes @@ -202,17 +203,10 @@ impl SequencerCore { .add_tx(UTXOCommitment { hash: *utxo_comm }); } - for (idx, nullifier) in nullifier_created_hashes.iter().enumerate() { + for nullifier in nullifier_created_hashes.iter() { self.store .nullifier_store - .insert_item(NullifierTreeInput { - nullifier_id: idx as u64, - tx_id, - block_id, - nullifier: UTXONullifier { - utxo_hash: *nullifier, - }, - }) + .insert_item(*nullifier) .map_err(|err| TransactionMalformationErrorKind::FailedToInsert { tx: hash, details: format!("{err:?}"), diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index fd09d93..592e61e 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -4,8 +4,8 @@ use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ block::{Block, HashableBlockData}, + indexed_merkle_tree::IndexedMerkleTreeWrapper, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, - nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, }; use rand::{rngs::OsRng, RngCore}; @@ -15,7 +15,7 @@ pub mod block_store; pub struct SequecerChainStore { pub acc_store: SequencerAccountsStore, pub block_store: SequecerBlockStore, - pub nullifier_store: NullifierSparseMerkleTree, + pub nullifier_store: IndexedMerkleTreeWrapper, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, } @@ -23,7 +23,7 @@ pub struct SequecerChainStore { impl SequecerChainStore { pub fn new_with_genesis(home_dir: &Path, genesis_id: u64, is_genesis_random: bool) -> Self { let acc_store = SequencerAccountsStore::default(); - let nullifier_store = NullifierSparseMerkleTree::default(); + let nullifier_store = IndexedMerkleTreeWrapper::default(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); diff --git a/utxo/Cargo.toml b/utxo/Cargo.toml index 9b99cf9..e7b35ef 100644 --- a/utxo/Cargo.toml +++ b/utxo/Cargo.toml @@ -9,7 +9,7 @@ serde_json.workspace = true env_logger.workspace = true log.workspace = true serde.workspace = true -monotree.workspace = true +indexed-merkle-tree.workspace = true sha2.workspace = true hex.workspace = true From cb22a95df25bfac699fd49b37ae43558e8ae5cc5 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 23 May 2025 09:04:04 +0300 Subject: [PATCH 21/37] fix: smt/imt replaced with sets --- common/src/commitments_sparse_merkle_tree.rs | 283 ------------------ common/src/indexed_merkle_tree.rs | 248 --------------- common/src/lib.rs | 1 - common/src/nullifier.rs | 2 +- common/src/rpc_primitives/requests.rs | 4 +- node_core/src/chain_storage/mod.rs | 15 +- node_core/src/chain_storage/public_context.rs | 5 - node_core/src/executions/de.rs | 217 -------------- node_core/src/executions/mod.rs | 3 - node_core/src/executions/private_exec.rs | 118 -------- node_core/src/executions/se.rs | 171 ----------- node_core/src/lib.rs | 9 +- node_core/src/sequencer_client/json.rs | 4 +- node_core/src/sequencer_client/mod.rs | 2 +- sc_core/src/proofs_circuits.rs | 44 +-- sequencer_core/src/lib.rs | 27 +- sequencer_core/src/sequencer_store/mod.rs | 9 +- 17 files changed, 35 insertions(+), 1127 deletions(-) delete mode 100644 common/src/commitments_sparse_merkle_tree.rs delete mode 100644 common/src/indexed_merkle_tree.rs delete mode 100644 node_core/src/executions/de.rs delete mode 100644 node_core/src/executions/mod.rs delete mode 100644 node_core/src/executions/private_exec.rs delete mode 100644 node_core/src/executions/se.rs diff --git a/common/src/commitments_sparse_merkle_tree.rs b/common/src/commitments_sparse_merkle_tree.rs deleted file mode 100644 index 3182275..0000000 --- a/common/src/commitments_sparse_merkle_tree.rs +++ /dev/null @@ -1,283 +0,0 @@ -use monotree::database::MemoryDB; -use monotree::hasher::Blake3; -use monotree::{Hasher, Monotree, Proof}; - -use crate::commitment::Commitment; -use crate::merkle_tree_public::CommitmentHashType; - -pub struct CommitmentsSparseMerkleTree { - pub curr_root: Option, - pub tree: Monotree, - pub hasher: Blake3, -} - -impl CommitmentsSparseMerkleTree { - pub fn new() -> Self { - CommitmentsSparseMerkleTree { - curr_root: None, - tree: Monotree::default(), - hasher: Blake3::new(), - } - } - - pub fn insert_item(&mut self, commitment: Commitment) -> Result<(), monotree::Errors> { - let root = self - .curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()); - - let new_root = self.tree.insert( - root, - &commitment.commitment_hash[0..32].try_into().unwrap(), - &commitment.commitment_hash[0..32].try_into().unwrap(), - )?; - - self.curr_root = new_root.map(|val| val.to_vec()); - - Ok(()) - } - - pub fn insert_items(&mut self, commitments: Vec) -> Result<(), monotree::Errors> { - let root = self - .curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()); - - let hashes: Vec<_> = commitments - .iter() - .map(|val| val.commitment_hash[0..32].try_into().unwrap()) - .collect::>(); - - let new_root = self.tree.inserts(root, &hashes, &hashes)?; - - self.curr_root = new_root.map(|val| val[0..32].try_into().unwrap()); - - Ok(()) - } - - pub fn search_item_inclusion( - &mut self, - commitment_hash: CommitmentHashType, - ) -> Result { - self.tree - .get( - self.curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()), - &commitment_hash[0..32].try_into().unwrap(), - ) - .map(|data| data.is_some()) - } - - pub fn search_item_inclusions( - &mut self, - commitment_hashes: &[CommitmentHashType], - ) -> Result, monotree::Errors> { - let mut inclusions = vec![]; - - for nullifier_hash in commitment_hashes { - let is_included = self - .tree - .get( - self.curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()), - nullifier_hash[0..32].try_into().unwrap(), - ) - .map(|data| data.is_some())?; - - inclusions.push(is_included); - } - - Ok(inclusions) - } - - pub fn get_non_membership_proof( - &mut self, - commitment_hash: CommitmentHashType, - ) -> Result<(Option, Option), monotree::Errors> { - let is_member = self.search_item_inclusion(commitment_hash.clone())?; - - if is_member { - Err(monotree::Errors::new("Is a member")) - } else { - Ok(( - self.tree.get_merkle_proof( - self.curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()), - &commitment_hash, - )?, - self.curr_root.clone(), - )) - } - } - - #[allow(clippy::type_complexity)] - pub fn get_non_membership_proofs( - &mut self, - commitment_hashes: &[CommitmentHashType], - ) -> Result, Option)>, monotree::Errors> { - let mut non_membership_proofs = vec![]; - - for commitment_hash in commitment_hashes { - let is_member = self.search_item_inclusion(commitment_hash.clone())?; - - if is_member { - return Err(monotree::Errors::new( - format!("{commitment_hash:?} Is a member").as_str(), - )); - } else { - non_membership_proofs.push(( - self.tree.get_merkle_proof( - self.curr_root - .as_ref() - .map(|val| val[0..32].try_into().unwrap()), - commitment_hash, - )?, - self.curr_root.clone(), - )) - }; - } - - Ok(non_membership_proofs) - } -} - -impl Default for CommitmentsSparseMerkleTree { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::nullifier::UTXONullifier; - use monotree::database::MemoryDB; - use monotree::hasher::Blake3; - use monotree::Monotree; - - fn create_nullifier(hash: CommitmentHashType) -> Commitment { - Commitment { - commitment_hash: hash, - } - } - - #[test] - fn test_new_tree_initialization() { - let tree = CommitmentsSparseMerkleTree::new(); - assert!(tree.curr_root.is_none()); - } - - #[test] - fn test_insert_single_item() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32].to_vec()); // Sample 32-byte hash - - let result = tree.insert_item(nullifier); - assert!(result.is_ok()); - assert!(tree.curr_root.is_some()); - } - - #[test] - fn test_insert_multiple_items() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifiers = vec![ - create_nullifier([1u8; 32].to_vec()), - create_nullifier([2u8; 32].to_vec()), - create_nullifier([3u8; 32].to_vec()), - ]; - - let result = tree.insert_items(nullifiers); - assert!(result.is_ok()); - assert!(tree.curr_root.is_some()); - } - - #[test] - fn test_search_item_inclusion() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32].to_vec()); - - tree.insert_item(nullifier.clone()).unwrap(); - - let result = tree.search_item_inclusion([1u8; 32].to_vec()); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); - - let non_existing = tree.search_item_inclusion([99u8; 32].to_vec()); - assert!(non_existing.is_ok()); - assert_eq!(non_existing.unwrap(), false); - } - - #[test] - fn test_search_multiple_item_inclusions() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifiers = vec![ - create_nullifier([1u8; 32].to_vec()), - create_nullifier([2u8; 32].to_vec()), - create_nullifier([3u8; 32].to_vec()), - ]; - - tree.insert_items(nullifiers).unwrap(); - - let search_hashes = vec![[1u8; 32].to_vec(), [2u8; 32].to_vec(), [99u8; 32].to_vec()]; - let result = tree.search_item_inclusions(&search_hashes); - assert!(result.is_ok()); - - let expected_results = vec![true, true, false]; - assert_eq!(result.unwrap(), expected_results); - } - - #[test] - fn test_non_membership_proof() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let non_member_hash = [5u8; 32].to_vec(); - - let result = tree.get_non_membership_proof(non_member_hash); - assert!(result.is_ok()); - - let (proof, root) = result.unwrap(); - assert!(root.is_none()); - } - - #[test] - fn test_non_membership_proofs_multiple() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let non_member_hashes = vec![[5u8; 32].to_vec(), [6u8; 32].to_vec(), [7u8; 32].to_vec()]; - - let result = tree.get_non_membership_proofs(&non_member_hashes); - assert!(result.is_ok()); - - let proofs = result.unwrap(); - for (proof, root) in proofs { - assert!(root.is_none()); - } - } - - #[test] - fn test_insert_and_get_proof_of_existing_item() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifier = create_nullifier([1u8; 32].to_vec()); - - tree.insert_item(nullifier.clone()).unwrap(); - - let proof_result = tree.get_non_membership_proof([1u8; 32].to_vec()); - assert!(proof_result.is_err()); - } - - #[test] - fn test_insert_and_get_proofs_of_existing_items() { - let mut tree = CommitmentsSparseMerkleTree::new(); - let nullifiers = vec![ - create_nullifier([1u8; 32].to_vec()), - create_nullifier([2u8; 32].to_vec()), - ]; - - tree.insert_items(nullifiers).unwrap(); - - let proof_result = - tree.get_non_membership_proofs(&[[1u8; 32].to_vec(), [2u8; 32].to_vec()]); - assert!(proof_result.is_err()); - } -} diff --git a/common/src/indexed_merkle_tree.rs b/common/src/indexed_merkle_tree.rs deleted file mode 100644 index e8df6b5..0000000 --- a/common/src/indexed_merkle_tree.rs +++ /dev/null @@ -1,248 +0,0 @@ -use crate::merkle_tree_public::TreeHashType; - -use anyhow::Result; -use indexed_merkle_tree::node::Node; -use indexed_merkle_tree::tree::{IndexedMerkleTree, NonMembershipProof}; -use indexed_merkle_tree::Hash; - -pub struct IndexedMerkleTreeWrapper { - pub tree: IndexedMerkleTree, - pub leaf_len: usize, - //pub leafs: BTreeMap, -} - -impl IndexedMerkleTreeWrapper { - pub fn new() -> Self { - Self { - //Will not panic - //Deterministic operation - tree: IndexedMerkleTree::new(vec![]).unwrap(), - leaf_len: 0, - } - } - - pub fn get_curr_root(&self) -> Result { - //HELP - // self.tree.get_root().map(|node| - // serde_json::from_str::>(&serde_json::to_string(node).unwrap())[0] - // ) - Ok([0; 32]) - } - - pub fn insert_item(&mut self, hash: TreeHashType) -> Result<()> { - let left_parity = self.leaf_len / 2; - let mut node = match left_parity { - 0 => Node::new_leaf(true, Hash::new(hash), Hash::new(hash), Node::TAIL), - 1 => Node::new_leaf(false, Hash::new(hash), Hash::new(hash), Node::TAIL), - _ => unreachable!(), - }; - - self.tree.insert_node(&mut node)?; - - self.leaf_len += 1; - - Ok(()) - } - - pub fn insert_items(&mut self, tree_nullifiers: Vec) -> Result<()> { - for tree_nullifier in tree_nullifiers { - self.insert_item(tree_nullifier)?; - } - - Ok(()) - } - - pub fn search_item_inclusion(&mut self, nullifier_hash: TreeHashType) -> bool { - self.tree - .find_leaf_by_label(&Hash::new(nullifier_hash)) - .is_some() - } - - pub fn search_item_inclusions(&mut self, nullifier_hashes: &[TreeHashType]) -> Vec { - let mut inclusions = vec![]; - - for nullifier_hash in nullifier_hashes { - let is_included = self.search_item_inclusion(*nullifier_hash); - - inclusions.push(is_included); - } - - inclusions - } - - pub fn get_non_membership_proof( - &mut self, - nullifier_hash: TreeHashType, - ) -> Result { - let node = Node::new_leaf( - false, - Hash::new(nullifier_hash), - Hash::new(nullifier_hash), - Node::TAIL, - ); - - self.tree.generate_non_membership_proof(&node) - } - - #[allow(clippy::type_complexity)] - pub fn get_non_membership_proofs( - &mut self, - nullifier_hashes: &[TreeHashType], - ) -> Result> { - let mut non_membership_proofs = vec![]; - - for nullifier_hash in nullifier_hashes { - let non_mem_proof = self.get_non_membership_proof(*nullifier_hash)?; - - non_membership_proofs.push(non_mem_proof); - } - - Ok(non_membership_proofs) - } -} - -impl Default for IndexedMerkleTreeWrapper { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - // use super::*; - // use crate::nullifier::UTXONullifier; - - // fn create_nullifier(hash: TreeHashType) -> UTXONullifier { - // UTXONullifier { utxo_hash: hash } - // } - - // fn create_nullifier_input( - // hash: TreeHashType, - // nullifier_id: u64, - // tx_id: u64, - // block_id: u64, - // ) -> NullifierTreeInput { - // NullifierTreeInput { - // nullifier_id, - // tx_id, - // block_id, - // nullifier: create_nullifier(hash), - // } - // } - - // #[test] - // fn test_new_tree_initialization() { - // let tree = IndexedMerkleTree::new(); - // assert!(tree.curr_root.is_none()); - // } - - // #[test] - // fn test_insert_single_item() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); // Sample 32-byte hash - - // let result = tree.insert_item(tree_nullifier); - // assert!(result.is_ok()); - // assert!(tree.curr_root.is_some()); - // } - - // #[test] - // fn test_insert_multiple_items() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifiers = vec![ - // create_nullifier_input([1u8; 32], 1, 1, 1), - // create_nullifier_input([2u8; 32], 2, 1, 1), - // create_nullifier_input([3u8; 32], 3, 1, 1), - // ]; - - // let result = tree.insert_items(tree_nullifiers); - // assert!(result.is_ok()); - // assert!(tree.curr_root.is_some()); - // } - - // #[test] - // fn test_search_item_inclusion() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - - // tree.insert_item(tree_nullifier.clone()).unwrap(); - - // let result = tree.search_item_inclusion([1u8; 32]); - // assert!(result.is_ok()); - // assert_eq!(result.unwrap(), true); - - // let non_existing = tree.search_item_inclusion([99u8; 32]); - // assert!(non_existing.is_ok()); - // assert_eq!(non_existing.unwrap(), false); - // } - - // #[test] - // fn test_search_multiple_item_inclusions() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifiers = vec![ - // create_nullifier_input([1u8; 32], 1, 1, 1), - // create_nullifier_input([2u8; 32], 2, 1, 1), - // create_nullifier_input([3u8; 32], 3, 1, 1), - // ]; - - // tree.insert_items(tree_nullifiers).unwrap(); - - // let search_hashes = vec![[1u8; 32], [2u8; 32], [99u8; 32]]; - // let result = tree.search_item_inclusions(&search_hashes); - // assert!(result.is_ok()); - - // let expected_results = vec![true, true, false]; - // assert_eq!(result.unwrap(), expected_results); - // } - - // #[test] - // fn test_non_membership_proof() { - // let mut tree = IndexedMerkleTree::new(); - // let non_member_hash = [5u8; 32]; - - // let result = tree.get_non_membership_proof(non_member_hash); - // assert!(result.is_ok()); - - // let (proof, root) = result.unwrap(); - // assert!(root.is_none()); - // } - - // #[test] - // fn test_non_membership_proofs_multiple() { - // let mut tree = IndexedMerkleTree::new(); - // let non_member_hashes = vec![[5u8; 32], [6u8; 32], [7u8; 32]]; - - // let result = tree.get_non_membership_proofs(&non_member_hashes); - // assert!(result.is_ok()); - - // let proofs = result.unwrap(); - // for (proof, root) in proofs { - // assert!(root.is_none()); - // } - // } - - // #[test] - // fn test_insert_and_get_proof_of_existing_item() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifier = create_nullifier_input([1u8; 32], 1, 1, 1); - - // tree.insert_item(tree_nullifier.clone()).unwrap(); - - // let proof_result = tree.get_non_membership_proof([1u8; 32]); - // assert!(proof_result.is_err()); - // } - - // #[test] - // fn test_insert_and_get_proofs_of_existing_items() { - // let mut tree = IndexedMerkleTree::new(); - // let tree_nullifiers = vec![ - // create_nullifier_input([1u8; 32], 1, 1, 1), - // create_nullifier_input([2u8; 32], 2, 1, 1), - // ]; - - // tree.insert_items(tree_nullifiers).unwrap(); - - // let proof_result = tree.get_non_membership_proofs(&[[1u8; 32], [2u8; 32]]); - // assert!(proof_result.is_err()); - // } -} diff --git a/common/src/lib.rs b/common/src/lib.rs index 9e238e2..46868d9 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,7 +3,6 @@ use serde::Deserialize; pub mod block; pub mod commitment; -pub mod indexed_merkle_tree; pub mod merkle_tree_public; pub mod nullifier; pub mod rpc_primitives; diff --git a/common/src/nullifier.rs b/common/src/nullifier.rs index 5033fa6..2c95741 100644 --- a/common/src/nullifier.rs +++ b/common/src/nullifier.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::merkle_tree_public::TreeHashType; //ToDo: Update Nullifier model, when it is clear -#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)] ///General nullifier object pub struct UTXONullifier { pub utxo_hash: TreeHashType, diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 92e0abe..6cad01d 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -21,8 +21,8 @@ pub struct RegisterAccountRequest { #[derive(Serialize, Deserialize, Debug)] pub struct SendTxRequest { pub transaction: Transaction, - ///Nullifier Root, UTXO Commitment Root, Pub Tx Root - pub tx_roots: [[u8; 32]; 3], + ///UTXO Commitment Root, Pub Tx Root + pub tx_roots: [[u8; 32]; 2], } #[derive(Serialize, Deserialize, Debug)] diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 7fb3d85..a6196f1 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -1,5 +1,5 @@ use std::{ - collections::{BTreeMap, HashMap}, + collections::{BTreeMap, HashMap, HashSet}, path::Path, }; @@ -8,7 +8,6 @@ use anyhow::Result; use block_store::NodeBlockStore; use common::{ block::Block, - indexed_merkle_tree::IndexedMerkleTreeWrapper, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, utxo_commitment::UTXOCommitment, @@ -26,7 +25,7 @@ pub mod public_context; pub struct NodeChainStore { pub acc_map: HashMap, pub block_store: NodeBlockStore, - pub nullifier_store: IndexedMerkleTreeWrapper, + pub nullifier_store: HashSet, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, } @@ -34,7 +33,7 @@ pub struct NodeChainStore { impl NodeChainStore { pub fn new_with_genesis(home_dir: &Path, genesis_block: Block) -> Self { let acc_map = HashMap::new(); - let nullifier_store = IndexedMerkleTreeWrapper::default(); + let nullifier_store = HashSet::new(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); @@ -54,7 +53,7 @@ impl NodeChainStore { } pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> { - for (tx_id, tx) in block.transactions.iter().enumerate() { + for tx in &block.transactions { if !tx.execution_input.is_empty() { let public_action = serde_json::from_slice::(&tx.execution_input); @@ -97,8 +96,9 @@ impl NodeChainStore { .collect(), ); - self.nullifier_store - .insert_items(tx.nullifier_created_hashes.clone())?; + for nullifier in tx.nullifier_created_hashes.iter() { + self.nullifier_store.insert(UTXONullifier { utxo_hash: *nullifier }); + } if !tx.encoded_data.is_empty() { let ephemeral_public_key_sender = @@ -148,7 +148,6 @@ impl NodeChainStore { caller_address: caller, caller_balance: self.acc_map.get(&caller).unwrap().balance, account_masks, - nullifier_store_root: self.nullifier_store.get_curr_root().unwrap_or([0; 32]), comitment_store_root: self.utxo_commitments_store.get_root().unwrap_or([0; 32]), pub_tx_store_root: self.pub_tx_store.get_root().unwrap_or([0; 32]), } diff --git a/node_core/src/chain_storage/public_context.rs b/node_core/src/chain_storage/public_context.rs index 5d5ceb6..438fa50 100644 --- a/node_core/src/chain_storage/public_context.rs +++ b/node_core/src/chain_storage/public_context.rs @@ -9,7 +9,6 @@ pub const CALLER_ADDRESS: &str = "caller_address"; pub const CALLER_BALANCE: &str = "caller_balance"; pub const ACCOUNT_MASKS_KEYS_SORTED: &str = "account_masks_keys_sorted"; pub const ACCOUNT_MASKS_VALUES_SORTED: &str = "account_masks_values_sorted"; -pub const NULLIFIER_STORE_ROOT: &str = "nullifier_store_root"; pub const COMMITMENT_STORE_ROOT: &str = "commitment_store_root"; pub const PUT_TX_STORE_ROOT: &str = "put_tx_store_root"; @@ -18,7 +17,6 @@ pub struct PublicSCContext { pub caller_address: AccountAddress, pub caller_balance: u64, pub account_masks: BTreeMap, - pub nullifier_store_root: TreeHashType, pub comitment_store_root: TreeHashType, pub pub_tx_store_root: TreeHashType, } @@ -41,7 +39,6 @@ impl Serialize for PublicSCContext { s.serialize_field(CALLER_BALANCE, &self.caller_balance)?; s.serialize_field(ACCOUNT_MASKS_KEYS_SORTED, &account_masks_keys)?; s.serialize_field(ACCOUNT_MASKS_VALUES_SORTED, &account_mask_values)?; - s.serialize_field(NULLIFIER_STORE_ROOT, &self.nullifier_store_root)?; s.serialize_field(COMMITMENT_STORE_ROOT, &self.comitment_store_root)?; s.serialize_field(PUT_TX_STORE_ROOT, &self.pub_tx_store_root)?; @@ -100,7 +97,6 @@ mod tests { fn create_test_context() -> PublicSCContext { let caller_address = [1; 32]; - let nullifier_store_root = [2; 32]; let comitment_store_root = [3; 32]; let pub_tx_store_root = [4; 32]; @@ -118,7 +114,6 @@ mod tests { caller_address, caller_balance: 100, account_masks, - nullifier_store_root, comitment_store_root, pub_tx_store_root, } diff --git a/node_core/src/executions/de.rs b/node_core/src/executions/de.rs deleted file mode 100644 index 68acb7b..0000000 --- a/node_core/src/executions/de.rs +++ /dev/null @@ -1,217 +0,0 @@ -use std::collections::BTreeMap; - -use bincode; -use common::{ - commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, -}; -use k256::Scalar; -use rand::thread_rng; -use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; -use sha2::{Digest, Sha256}; -use utxo::utxo_core::UTXO; - -#[allow(unused)] -fn commitment_secrets_random(value: u64) -> CommitmentSecrets { - CommitmentSecrets { - value, - value_blinding_factor: Tweak::new(&mut thread_rng()), - generator_blinding_factor: Tweak::new(&mut thread_rng()), - } -} - -pub fn tag_random() -> Tag { - use rand::thread_rng; - use rand::RngCore; - - let mut bytes = [0u8; 32]; - thread_rng().fill_bytes(&mut bytes); - - Tag::from(bytes) -} - -pub fn commit(comm: &CommitmentSecrets, tag: Tag) -> PedersenCommitment { - let generator = Generator::new_blinded(SECP256K1, tag, comm.generator_blinding_factor); - - PedersenCommitment::new(SECP256K1, comm.value, comm.value_blinding_factor, generator) -} - -fn hash(input: &[u8]) -> Vec { - Sha256::digest(input).to_vec() -} - -// Generate nullifiers - -// takes the input_utxo and nsk -// returns the nullifiers[i], where the nullifier[i] = hash(in_commitments[i] || nsk) where the hash function -pub fn generate_nullifiers(input_utxo: &UTXO, nsk: &[u8]) -> Vec { - let mut input = bincode::serialize(input_utxo).unwrap().to_vec(); - input.extend_from_slice(nsk); - hash(&input) -} - -// Generate commitments for output UTXOs - -// uses the list of input_utxos[] -// returns in_commitments[] where each in_commitments[i] = Commitment(in_utxos[i]) where the commitment -pub fn generate_commitments(input_utxos: &[UTXO]) -> Vec> { - input_utxos - .iter() - .map(|utxo| { - let serialized = bincode::serialize(utxo).unwrap(); // Serialize UTXO. - hash(&serialized) - }) - .collect() -} - -// Validate inclusion proof for in_commitments - -// takes the in_commitments[i] as a leaf, the root hash root_commitment and the path in_commitments_proofs[i][], -// returns True if the in_commitments[i] is in the tree with root hash root_commitment otherwise returns False, as membership proof. -pub fn validate_in_commitments_proof( - in_commitment: &Vec, - root_commitment: Vec, - in_commitments_proof: &[Vec], -) -> bool { - // Placeholder implementation. - // Replace with Merkle proof verification logic. - // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = in_commitments_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) - .is_ok() -} - -// Validate non-membership proof for nullifiers - -// takes the nullifiers[i], path nullifiers_proof[i][] and the root hash root_nullifier, -// returns True if the nullifiers[i] is not in the tree with root hash root_nullifier otherwise returns False, as non-membership proof. -pub fn validate_nullifiers_proof( - nullifier: [u8; 32], - root_nullifier: [u8; 32], - nullifiers_proof: &[[u8; 32]], -) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = nullifiers_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) - .is_ok() -} - -// Check balances - -// takes the public_info and output_utxos[], -// returns the True if the token amount in public_info matches the sum of all output_utxos[], otherwise return False. -pub fn check_balances(public_info: u128, output_utxos: &[UTXO]) -> bool { - let total_output: u128 = output_utxos.iter().map(|utxo| utxo.amount).sum(); - public_info == total_output -} - -// Verify Pedersen commitment - -// takes the public_info, secret_r and pedersen_commitment and -// checks that commitment(public_info,secret_r) is equal pedersen_commitment where the commitment is pedersen commitment. -pub fn verify_commitment( - public_info: u64, - secret_r: &[u8], - pedersen_commitment: &PedersenCommitment, -) -> bool { - let commitment_secrets = CommitmentSecrets { - value: public_info, - value_blinding_factor: Tweak::from_slice(secret_r).unwrap(), - generator_blinding_factor: Tweak::new(&mut thread_rng()), - }; - - let tag = tag_random(); - let commitment = commit(&commitment_secrets, tag); - - commitment == *pedersen_commitment -} - -// new_commitment -pub fn new_commitment(public_info: u64, secret_r: &[u8]) -> (Tweak, &[u8], PedersenCommitment) { - let generator_blinding_factor = Tweak::new(&mut thread_rng()); - let commitment_secrets = CommitmentSecrets { - value: public_info, - value_blinding_factor: Tweak::from_slice(secret_r).unwrap(), - generator_blinding_factor, - }; - - let tag = tag_random(); - let commitment = commit(&commitment_secrets, tag); - - (generator_blinding_factor, secret_r, commitment) -} - -// new_commitment for a Vec of values -pub fn new_commitment_vec( - public_info_vec: Vec, - secret_r: &[u8], -) -> (Tweak, &[u8], Vec) { - let generator_blinding_factor = Tweak::new(&mut thread_rng()); - let tag = tag_random(); - - let vec_commitments = public_info_vec - .into_iter() - .map(|public_info| { - let commitment_secrets = CommitmentSecrets { - value: public_info, - value_blinding_factor: Tweak::from_slice(secret_r).unwrap(), - generator_blinding_factor, - }; - - commit(&commitment_secrets, tag) - }) - .collect(); - - (generator_blinding_factor, secret_r, vec_commitments) -} - -#[allow(unused)] -fn de_kernel( - root_commitment: &[u8], - root_nullifier: [u8; 32], - public_info: u64, - input_utxos: &[UTXO], - in_commitments_proof: &[Vec], - nullifiers_proof: &[[u8; 32]], - nullifier_secret_key: Scalar, -) -> (Vec, Vec>) { - check_balances(public_info as u128, input_utxos); - - let nullifiers: Vec<_> = input_utxos - .into_iter() - .map(|utxo| generate_nullifiers(&utxo, &nullifier_secret_key.to_bytes())) - .collect(); - - let in_commitments = generate_commitments(&input_utxos); - - for in_commitment in in_commitments { - validate_in_commitments_proof( - &in_commitment, - root_commitment.to_vec(), - in_commitments_proof, - ); - } - - for nullifier in nullifiers.iter() { - validate_nullifiers_proof( - nullifier[0..32].try_into().unwrap(), - root_nullifier, - nullifiers_proof, - ); - } - - (vec![], nullifiers) -} diff --git a/node_core/src/executions/mod.rs b/node_core/src/executions/mod.rs deleted file mode 100644 index 7c9d33e..0000000 --- a/node_core/src/executions/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod de; -pub mod private_exec; -pub mod se; diff --git a/node_core/src/executions/private_exec.rs b/node_core/src/executions/private_exec.rs deleted file mode 100644 index 4f61bd3..0000000 --- a/node_core/src/executions/private_exec.rs +++ /dev/null @@ -1,118 +0,0 @@ -use std::collections::BTreeMap; - -use bincode; -use common::{ - commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, -}; -use k256::Scalar; -use sha2::{Digest, Sha256}; -use utxo::utxo_core::UTXO; - -fn hash(input: &[u8]) -> Vec { - Sha256::digest(input).to_vec() -} - -// Generate nullifiers - -// takes the input_utxo and nsk -// returns the nullifiers[i], where the nullifier[i] = hash(in_commitments[i] || nsk) where the hash function -pub fn generate_nullifiers(input_utxo: &UTXO, nsk: &[u8]) -> Vec { - let mut input = bincode::serialize(input_utxo).unwrap().to_vec(); - input.extend_from_slice(nsk); - hash(&input) -} - -// Generate commitments for output UTXOs - -// uses the list of input_utxos[] -// returns in_commitments[] where each in_commitments[i] = Commitment(in_utxos[i]) where the commitment -pub fn generate_commitments(input_utxos: &[UTXO]) -> Vec> { - input_utxos - .iter() - .map(|utxo| { - let serialized = bincode::serialize(utxo).unwrap(); // Serialize UTXO. - hash(&serialized) - }) - .collect() -} - -// Validate inclusion proof for in_commitments - -// takes the in_commitments[i] as a leaf, the root hash root_commitment and the path in_commitments_proofs[i][], -// returns True if the in_commitments[i] is in the tree with root hash root_commitment otherwise returns False, as membership proof. -pub fn validate_in_commitments_proof( - in_commitment: &Vec, - root_commitment: Vec, - in_commitments_proof: &[Vec], -) -> bool { - // Placeholder implementation. - // Replace with Merkle proof verification logic. - // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = in_commitments_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) - .is_ok() -} - -// Validate non-membership proof for nullifiers - -// takes the nullifiers[i], path nullifiers_proof[i][] and the root hash root_nullifier, -// returns True if the nullifiers[i] is not in the tree with root hash root_nullifier otherwise returns False, as non-membership proof. -pub fn validate_nullifiers_proof( - nullifier: [u8; 32], - root_nullifier: [u8; 32], - nullifiers_proof: &[[u8; 32]], -) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = nullifiers_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) - .is_ok() -} - -#[allow(unused)] -fn private_kernel( - root_commitment: &[u8], - root_nullifier: [u8; 32], - input_utxos: &[UTXO], - in_commitments_proof: &[Vec], - nullifiers_proof: &[[u8; 32]], - nullifier_secret_key: Scalar, -) -> (Vec, Vec>) { - let nullifiers: Vec<_> = input_utxos - .into_iter() - .map(|utxo| generate_nullifiers(&utxo, &nullifier_secret_key.to_bytes())) - .collect(); - - let in_commitments = generate_commitments(&input_utxos); - - for in_commitment in in_commitments { - validate_in_commitments_proof( - &in_commitment, - root_commitment.to_vec(), - in_commitments_proof, - ); - } - - for nullifier in nullifiers.iter() { - validate_nullifiers_proof( - nullifier[0..32].try_into().unwrap(), - root_nullifier, - nullifiers_proof, - ); - } - - (vec![], nullifiers) -} diff --git a/node_core/src/executions/se.rs b/node_core/src/executions/se.rs deleted file mode 100644 index 6b7285c..0000000 --- a/node_core/src/executions/se.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::collections::BTreeMap; - -use bincode; -use common::{ - commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, -}; -use k256::Scalar; -use rand::thread_rng; -use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; -use sha2::{Digest, Sha256}; -use utxo::utxo_core::UTXO; - -#[allow(unused)] -fn commitment_secrets_random(value: u64) -> CommitmentSecrets { - CommitmentSecrets { - value, - value_blinding_factor: Tweak::new(&mut thread_rng()), - generator_blinding_factor: Tweak::new(&mut thread_rng()), - } -} - -pub fn tag_random() -> Tag { - use rand::thread_rng; - use rand::RngCore; - - let mut bytes = [0u8; 32]; - thread_rng().fill_bytes(&mut bytes); - - Tag::from(bytes) -} - -pub fn commit(comm: &CommitmentSecrets, tag: Tag) -> PedersenCommitment { - let generator = Generator::new_blinded(SECP256K1, tag, comm.generator_blinding_factor); - - PedersenCommitment::new(SECP256K1, comm.value, comm.value_blinding_factor, generator) -} - -fn hash(input: &[u8]) -> Vec { - Sha256::digest(input).to_vec() -} - -// Generate nullifiers - -// takes the pedersen_commitment and nsk then -// returns a list of nullifiers, where the nullifier = hash(pedersen_commitment || nsk) where the hash function will be determined - -pub fn generate_nullifiers(pedersen_commitment: &PedersenCommitment, nsk: &[u8]) -> Vec { - let mut input = pedersen_commitment.serialize().to_vec(); - input.extend_from_slice(nsk); - hash(&input) -} - -// Generate commitments for output UTXOs - -// uses the list of output_utxos[] and -// returns out_commitments[] where each out_commitments[i] = Commitment(output_utxos[i]) -// where the commitment will be determined -pub fn generate_commitments(output_utxos: &[UTXO]) -> Vec> { - output_utxos - .iter() - .map(|utxo| { - let serialized = bincode::serialize(utxo).unwrap(); // Serialize UTXO. - hash(&serialized) - }) - .collect() -} - -// Validate inclusion proof for in_commitments - -// takes the pedersen_commitment as a leaf, the root hash root_commitment and the path in_commitments_proof[], -// returns True if the pedersen_commitment is in the tree with root hash root_commitment -// otherwise -// returns False, as membership proof. -pub fn validate_in_commitments_proof( - pedersen_commitment: &PedersenCommitment, - root_commitment: Vec, - in_commitments_proof: &[Vec], -) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = in_commitments_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec().try_into().unwrap()) - .is_ok() -} - -// Validate non-membership proof for nullifiers - -// takes the nullifier, path nullifiers_proof[] and the root hash root_nullifier, -// returns True if the nullifier is not in the tree with root hash root_nullifier -// otherwise -// returns False, as non-membership proof. -pub fn validate_nullifiers_proof( - nullifier: [u8; 32], - root_nullifier: [u8; 32], - nullifiers_proof: &[[u8; 32]], -) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = nullifiers_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) - .is_ok() -} - -// Check balances - -// takes the public_info and output_utxos[], -// returns the True if the token amount in public_info matches the sum of all output_utxos[], otherwise return False. -pub fn check_balances(public_info: u128, output_utxos: &[UTXO]) -> bool { - let total_output: u128 = output_utxos.iter().map(|utxo| utxo.amount).sum(); - public_info == total_output -} - -// Verify Pedersen commitment - -// takes the public_info, secret_r and pedersen_commitment and -// checks that commitment(public_info,secret_r) is equal pedersen_commitment where the commitment is pedersen commitment. -pub fn verify_commitment( - public_info: u64, - secret_r: &[u8], - pedersen_commitment: &PedersenCommitment, -) -> bool { - let commitment_secrets = CommitmentSecrets { - value: public_info, - value_blinding_factor: Tweak::from_slice(secret_r).unwrap(), - generator_blinding_factor: Tweak::new(&mut thread_rng()), - }; - - let tag = tag_random(); - let commitment = commit(&commitment_secrets, tag); - - commitment == *pedersen_commitment -} - -#[allow(unused)] -fn se_kernel( - root_commitment: &[u8], - root_nullifier: [u8; 32], - public_info: u64, - pedersen_commitment: PedersenCommitment, - secret_r: &[u8], - output_utxos: &[UTXO], - in_commitments_proof: &[Vec], - nullifiers_proof: &[[u8; 32]], - nullifier_secret_key: Scalar, -) -> (Vec, Vec>, Vec) { - check_balances(public_info as u128, output_utxos); - - let out_commitments = generate_commitments(output_utxos); - - let nullifier = generate_nullifiers(&pedersen_commitment, &nullifier_secret_key.to_bytes()); - - validate_in_commitments_proof( - &pedersen_commitment, - root_commitment.to_vec(), - in_commitments_proof, - ); - - verify_commitment(public_info, secret_r, &pedersen_commitment); - - (vec![], out_commitments, nullifier) -} diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 5fc9289..c36c34f 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -10,9 +10,8 @@ use anyhow::Result; use chain_storage::NodeChainStore; use common::transaction::{Transaction, TransactionPayload, TxKind}; use config::NodeConfig; -use executions::private_exec::{generate_commitments, generate_nullifiers}; use log::info; -use sc_core::proofs_circuits::pedersen_commitment_vec; +use sc_core::proofs_circuits::{generate_commitments, generate_nullifiers, generate_nullifiers_se, pedersen_commitment_vec}; use sequencer_client::{json::SendTxResponse, SequencerClient}; use serde::{Deserialize, Serialize}; use storage::sc_db_utils::DataBlobChangeVariant; @@ -28,7 +27,6 @@ pub const BLOCK_GEN_DELAY_SECS: u64 = 20; pub mod chain_storage; pub mod config; -pub mod executions; ///Module, which includes pre start setup helperfunctions pub mod pre_start; pub mod sequencer_client; @@ -164,10 +162,9 @@ impl NodeCore { }) } - pub async fn get_roots(&self) -> [[u8; 32]; 3] { + pub async fn get_roots(&self) -> [[u8; 32]; 2] { let storage = self.storage.read().await; [ - storage.nullifier_store.get_curr_root().unwrap_or([0; 32]), storage.utxo_commitments_store.get_root().unwrap_or([0; 32]), storage.pub_tx_store.get_root().unwrap_or([0; 32]), ] @@ -651,7 +648,7 @@ impl NodeCore { ) .unwrap(); - let nullifier = executions::se::generate_nullifiers( + let nullifier = generate_nullifiers_se( &commitment, &account .key_holder diff --git a/node_core/src/sequencer_client/json.rs b/node_core/src/sequencer_client/json.rs index 0c5373b..df94ca2 100644 --- a/node_core/src/sequencer_client/json.rs +++ b/node_core/src/sequencer_client/json.rs @@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct SendTxRequest { pub transaction: Transaction, - ///Nullifier Root, UTXO Commitment Root, Pub Tx Root - pub tx_roots: [[u8; 32]; 3], + ///UTXO Commitment Root, Pub Tx Root + pub tx_roots: [[u8; 32]; 2], } //Responses diff --git a/node_core/src/sequencer_client/mod.rs b/node_core/src/sequencer_client/mod.rs index bc40a3a..7accd5f 100644 --- a/node_core/src/sequencer_client/mod.rs +++ b/node_core/src/sequencer_client/mod.rs @@ -73,7 +73,7 @@ impl SequencerClient { pub async fn send_tx( &self, transaction: Transaction, - tx_roots: [[u8; 32]; 3], + tx_roots: [[u8; 32]; 2], ) -> Result { let tx_req = SendTxRequest { transaction, diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 5bc63ae..d7c27d6 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -1,9 +1,4 @@ -use std::collections::BTreeMap; - use bincode; -use common::{ - commitment::Commitment, indexed_merkle_tree::IndexedMerkleTreeWrapper, nullifier::UTXONullifier, -}; use k256::Scalar; use rand::{thread_rng, RngCore}; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; @@ -44,23 +39,14 @@ pub fn generate_commitments(input_utxos: &[UTXO]) -> Vec> { // returns True if the in_commitments[i] is in the tree with root hash root_commitment otherwise returns False, as membership proof. pub fn validate_in_commitments_proof( in_commitment: &Vec, - root_commitment: Vec, + _root_commitment: Vec, in_commitments_proof: &[Vec], ) -> bool { // Placeholder implementation. // Replace with Merkle proof verification logic. // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = in_commitments_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(in_commitment.clone().try_into().unwrap()) - .is_ok() + in_commitments_proof.contains(in_commitment) } // Validate non-membership proof for nullifiers @@ -69,19 +55,10 @@ pub fn validate_in_commitments_proof( // returns True if the nullifiers[i] is not in the tree with root hash root_nullifier otherwise returns False, as non-membership proof. pub fn validate_nullifiers_proof( nullifier: [u8; 32], - root_nullifier: [u8; 32], + _root_nullifier: [u8; 32], nullifiers_proof: &[[u8; 32]], ) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = nullifiers_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(nullifier.clone().try_into().unwrap()) - .is_ok() + !nullifiers_proof.contains(&nullifier) } #[allow(unused)] @@ -246,19 +223,10 @@ fn de_kernel( // returns False, as membership proof. pub fn validate_in_commitments_proof_se( pedersen_commitment: &PedersenCommitment, - root_commitment: Vec, + _root_commitment: Vec, in_commitments_proof: &[Vec], ) -> bool { - let mut nsmt = IndexedMerkleTreeWrapper::new(); - - let commitments: Vec<_> = in_commitments_proof - .into_iter() - .map(|n_p| n_p.clone().try_into().unwrap()) - .collect(); - nsmt.insert_items(commitments).unwrap(); - - nsmt.get_non_membership_proof(pedersen_commitment.serialize().to_vec().try_into().unwrap()) - .is_ok() + in_commitments_proof.contains(&pedersen_commitment.serialize().to_vec()) } // Generate nullifiers SE diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 4a055d8..05aac2b 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -59,12 +59,8 @@ impl SequencerCore { } } - pub fn get_tree_roots(&self) -> [[u8; 32]; 3] { + pub fn get_tree_roots(&self) -> [[u8; 32]; 2] { [ - self.store - .nullifier_store - .get_curr_root() - .unwrap_or([0; 32]), self.store .utxo_commitments_store .get_root() @@ -76,7 +72,7 @@ impl SequencerCore { pub fn transaction_pre_check( &mut self, tx: &Transaction, - tx_roots: [[u8; 32]; 3], + tx_roots: [[u8; 32]; 2], ) -> Result<(), TransactionMalformationErrorKind> { let Transaction { hash, @@ -140,7 +136,7 @@ impl SequencerCore { .map(|nullifier_hash| { self.store .nullifier_store - .search_item_inclusion(*nullifier_hash) + .contains(&UTXONullifier { utxo_hash: *nullifier_hash }) }) .any(|check| check); let utxo_commitments_check = utxo_commitments_created_hashes @@ -175,7 +171,7 @@ impl SequencerCore { pub fn push_tx_into_mempool_pre_check( &mut self, item: TransactionMempool, - tx_roots: [[u8; 32]; 3], + tx_roots: [[u8; 32]; 2], ) -> Result<(), TransactionMalformationErrorKind> { self.transaction_pre_check(&item.tx, tx_roots)?; @@ -187,11 +183,10 @@ impl SequencerCore { fn execute_check_transaction_on_state( &mut self, tx: TransactionMempool, - tx_id: u64, - block_id: u64, ) -> Result<(), TransactionMalformationErrorKind> { let Transaction { - hash, + // ToDo: remove hashing of transactions on node side [Issue #66] + hash: _, ref utxo_commitments_created_hashes, ref nullifier_created_hashes, .. @@ -206,11 +201,7 @@ impl SequencerCore { for nullifier in nullifier_created_hashes.iter() { self.store .nullifier_store - .insert_item(*nullifier) - .map_err(|err| TransactionMalformationErrorKind::FailedToInsert { - tx: hash, - details: format!("{err:?}"), - })?; + .insert(UTXONullifier{ utxo_hash: *nullifier}); } self.store.pub_tx_store.add_tx(tx.tx); @@ -233,8 +224,8 @@ impl SequencerCore { .mempool .pop_size(self.sequencer_config.max_num_tx_in_block); - for (idx, tx) in transactions.clone().into_iter().enumerate() { - self.execute_check_transaction_on_state(tx, idx as u64, new_block_height)?; + for tx in &transactions { + self.execute_check_transaction_on_state(tx.clone())?; } let prev_block_hash = self diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 592e61e..5d28abd 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -1,11 +1,10 @@ -use std::path::Path; +use std::{collections::HashSet, path::Path}; use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ block::{Block, HashableBlockData}, - indexed_merkle_tree::IndexedMerkleTreeWrapper, - merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, + merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, }; use rand::{rngs::OsRng, RngCore}; @@ -15,7 +14,7 @@ pub mod block_store; pub struct SequecerChainStore { pub acc_store: SequencerAccountsStore, pub block_store: SequecerBlockStore, - pub nullifier_store: IndexedMerkleTreeWrapper, + pub nullifier_store: HashSet, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, } @@ -23,7 +22,7 @@ pub struct SequecerChainStore { impl SequecerChainStore { pub fn new_with_genesis(home_dir: &Path, genesis_id: u64, is_genesis_random: bool) -> Self { let acc_store = SequencerAccountsStore::default(); - let nullifier_store = IndexedMerkleTreeWrapper::default(); + let nullifier_store = HashSet::new(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); From 9bf0ec9de7608d4820e3d48a81b4d071c4aff830 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 23 May 2025 09:07:53 +0300 Subject: [PATCH 22/37] fix: fmt --- node_core/src/chain_storage/mod.rs | 4 +++- node_core/src/lib.rs | 4 +++- sequencer_core/src/lib.rs | 14 +++++++------- sequencer_core/src/sequencer_store/mod.rs | 3 ++- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index a6196f1..26bb809 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -97,7 +97,9 @@ impl NodeChainStore { ); for nullifier in tx.nullifier_created_hashes.iter() { - self.nullifier_store.insert(UTXONullifier { utxo_hash: *nullifier }); + self.nullifier_store.insert(UTXONullifier { + utxo_hash: *nullifier, + }); } if !tx.encoded_data.is_empty() { diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index c36c34f..ca412c4 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -11,7 +11,9 @@ use chain_storage::NodeChainStore; use common::transaction::{Transaction, TransactionPayload, TxKind}; use config::NodeConfig; use log::info; -use sc_core::proofs_circuits::{generate_commitments, generate_nullifiers, generate_nullifiers_se, pedersen_commitment_vec}; +use sc_core::proofs_circuits::{ + generate_commitments, generate_nullifiers, generate_nullifiers_se, pedersen_commitment_vec, +}; use sequencer_client::{json::SendTxResponse, SequencerClient}; use serde::{Deserialize, Serialize}; use storage::sc_db_utils::DataBlobChangeVariant; diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 05aac2b..ca07f6a 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -134,9 +134,9 @@ impl SequencerCore { let nullifier_tree_check = nullifier_created_hashes .iter() .map(|nullifier_hash| { - self.store - .nullifier_store - .contains(&UTXONullifier { utxo_hash: *nullifier_hash }) + self.store.nullifier_store.contains(&UTXONullifier { + utxo_hash: *nullifier_hash, + }) }) .any(|check| check); let utxo_commitments_check = utxo_commitments_created_hashes @@ -185,7 +185,7 @@ impl SequencerCore { tx: TransactionMempool, ) -> Result<(), TransactionMalformationErrorKind> { let Transaction { - // ToDo: remove hashing of transactions on node side [Issue #66] + // ToDo: remove hashing of transactions on node side [Issue #66] hash: _, ref utxo_commitments_created_hashes, ref nullifier_created_hashes, @@ -199,9 +199,9 @@ impl SequencerCore { } for nullifier in nullifier_created_hashes.iter() { - self.store - .nullifier_store - .insert(UTXONullifier{ utxo_hash: *nullifier}); + self.store.nullifier_store.insert(UTXONullifier { + utxo_hash: *nullifier, + }); } self.store.pub_tx_store.add_tx(tx.tx); diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 5d28abd..322c99d 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -4,7 +4,8 @@ use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ block::{Block, HashableBlockData}, - merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, + merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, + nullifier::UTXONullifier, }; use rand::{rngs::OsRng, RngCore}; From 958e1dcb9c94b9a7a8c3f77a134c5b0a62fde037 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 23 May 2025 09:10:34 +0300 Subject: [PATCH 23/37] fix: tests fix --- sequencer_core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index ca07f6a..7a083f1 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -332,7 +332,7 @@ mod tests { common_setup(&mut sequencer); let roots = sequencer.get_tree_roots(); - assert_eq!(roots.len(), 3); // Should return three roots + assert_eq!(roots.len(), 2); // Should return two roots } #[test] From e94173aa1227da84c364d7dc936c9f9b7af51292 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:46:52 -0400 Subject: [PATCH 24/37] add new column family --- storage/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 753cac3..dd43016 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -41,6 +41,8 @@ pub const CF_BLOCK_NAME: &str = "cf_block"; pub const CF_META_NAME: &str = "cf_meta"; ///Name of smart contract column family pub const CF_SC_NAME: &str = "cf_sc"; +///Name of snapshot column family +pub const CF_SNAPSHOT_NAME: &str = "cf_snapshot"; ///Suffix, used to mark field, which contain length of smart contract pub const SC_LEN_SUFFIX: &str = "sc_len"; From b89dcb7fca41d8e0dfc60512b1147ea63d10daae Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:47:20 -0400 Subject: [PATCH 25/37] add new db keys --- storage/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index dd43016..2c73380 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -35,6 +35,17 @@ pub const DB_META_FIRST_BLOCK_SET_KEY: &str = "first_block_set"; ///Key to list of all known smart contract addresses pub const DB_META_SC_LIST: &str = "sc_list"; +///Key base for storing snapshot which describe block id +pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id"; +///Key base for storing snapshot which describe commitment +pub const DB_SNAPSHOT_COMMITMENT_KEY: &str = "commitment"; +///Key base for storing snapshot which describe transaction +pub const DB_SNAPSHOT_TRANSACTION_KEY: &str = "transaction"; +///Key base for storing snapshot which describe nullifier +pub const DB_SNAPSHOT_NULLIFIER_KEY: &str = "nullifier"; +///Key base for storing snapshot which describe account +pub const DB_SNAPSHOT_ACCOUNT_KEY: &str = "account"; + ///Name of block column family pub const CF_BLOCK_NAME: &str = "cf_block"; ///Name of meta column family From d9e82f4ffc185e660f32be67d7f1b69f7a5d6d67 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:47:39 -0400 Subject: [PATCH 26/37] fix new fn --- storage/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 2c73380..89a4dc5 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -72,6 +72,7 @@ impl RocksDBIO { let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); let cfsc = ColumnFamilyDescriptor::new(CF_SC_NAME, cf_opts.clone()); + let cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); let mut db_opts = Options::default(); db_opts.create_missing_column_families(true); @@ -79,7 +80,7 @@ impl RocksDBIO { let db = DBWithThreadMode::::open_cf_descriptors( &db_opts, path, - vec![cfb, cfmeta, cfsc], + vec![cfb, cfmeta, cfsc, cfsnapshot], ); let dbio = Self { From a53e8f708c34af637d40eaf80ebc02fbe55d0979 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:47:51 -0400 Subject: [PATCH 27/37] fix destroy fn --- storage/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 89a4dc5..8224b14 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -115,6 +115,7 @@ impl RocksDBIO { //ToDo: Add more column families for different data let _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); + let _cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); let mut db_opts = Options::default(); db_opts.create_missing_column_families(true); From caaa6108d8e729ada3380e52f41540c04a16d44a Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:48:09 -0400 Subject: [PATCH 28/37] add handle for snapshot --- storage/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 8224b14..422365e 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -136,6 +136,10 @@ impl RocksDBIO { self.db.cf_handle(CF_SC_NAME).unwrap() } + pub fn snapshot_column(&self) -> Arc { + self.db.cf_handle(CF_SNAPSHOT_NAME).unwrap() + } + pub fn get_meta_first_block_in_db(&self) -> DbResult { let cf_meta = self.meta_column(); let res = self From 4350b69a18b32d7bb13337f12285ffe40380af33 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:49:27 -0400 Subject: [PATCH 29/37] add getters for block_id and commitment --- storage/src/lib.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 422365e..287edb9 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -403,6 +403,41 @@ impl RocksDBIO { Ok(data_blob_list) } + + pub fn get_snapshot_block_id(&self) -> DbResult { + let cf_snapshot = self.snapshot_column(); + let res = self + .db + .get_cf(&cf_snapshot, DB_SNAPSHOT_BLOCK_ID_KEY) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + + if let Some(data) = res { + Ok(u64::from_be_bytes(data.try_into().unwrap())) + } else { + Err(DbError::db_interaction_error( + "Snapshot block ID not found".to_string(), + )) + } + } + + pub fn get_snapshot_commitment(&self) -> DbResult> { + let cf_snapshot = self.snapshot_column(); + let res = self + .db + .get_cf(&cf_snapshot, DB_SNAPSHOT_COMMITMENT_KEY) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + + if let Some(data) = res { + Ok(data) + } else { + Err(DbError::db_interaction_error( + "Snapshot commitment not found".to_string(), + )) + } + } + + + } ///Creates address for sc data blob at corresponding id From ee26147dde1e0e384ce066adac86ff7a6afbeeb1 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:49:59 -0400 Subject: [PATCH 30/37] add getters for transaction and nullifier --- storage/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 287edb9..625f19f 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -436,7 +436,37 @@ impl RocksDBIO { } } + pub fn get_snapshot_transaction(&self) -> DbResult> { + let cf_snapshot = self.snapshot_column(); + let res = self + .db + .get_cf(&cf_snapshot, DB_SNAPSHOT_TRANSACTION_KEY) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + if let Some(data) = res { + Ok(data) + } else { + Err(DbError::db_interaction_error( + "Snapshot transaction not found".to_string(), + )) + } + } + + pub fn get_snapshot_nullifier(&self) -> DbResult> { + let cf_snapshot = self.snapshot_column(); + let res = self + .db + .get_cf(&cf_snapshot, DB_SNAPSHOT_NULLIFIER_KEY) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + + if let Some(data) = res { + Ok(data) + } else { + Err(DbError::db_interaction_error( + "Snapshot nullifier not found".to_string(), + )) + } + } } From 611436a9431b4fdc7860cb6ef996672455b47054 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:50:16 -0400 Subject: [PATCH 31/37] add getters for account --- storage/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 625f19f..0df1515 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -468,6 +468,22 @@ impl RocksDBIO { } } + pub fn get_snapshot_account(&self) -> DbResult> { + let cf_snapshot = self.snapshot_column(); + let res = self + .db + .get_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + + if let Some(data) = res { + Ok(data) + } else { + Err(DbError::db_interaction_error( + "Snapshot account not found".to_string(), + )) + } + } + } ///Creates address for sc data blob at corresponding id From c71e1b9f8bcdf0cae01efd9c66b53205d078168b Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:50:51 -0400 Subject: [PATCH 32/37] add out fn for block_id and commitment --- storage/src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 0df1515..059d646 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -484,6 +484,31 @@ impl RocksDBIO { } } + pub fn put_snapshot_block_id_db(&self, block_id: u64) -> DbResult<()> { + let cf_snapshot = self.snapshot_column(); + self.db + .put_cf( + &cf_snapshot, + DB_SNAPSHOT_BLOCK_ID_KEY.as_bytes(), + block_id.to_be_bytes(), + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } + + pub fn put_snapshot_commitement_db(&self, commitment: Vec) -> DbResult<()> { + let cf_snapshot = self.snapshot_column(); + self.db + .put_cf( + &cf_snapshot, + DB_SNAPSHOT_COMMITMENT_KEY.as_bytes(), + commitment, + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } + + } ///Creates address for sc data blob at corresponding id From b69969942acfdc3b5b62fb32744cf040ee3eaaca Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:51:21 -0400 Subject: [PATCH 33/37] add out fn for transaction, nullifier and account --- storage/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 059d646..0839e05 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -508,7 +508,41 @@ impl RocksDBIO { Ok(()) } + pub fn put_snapshot_transaction_db(&self, transaction: Vec) -> DbResult<()> { + let cf_snapshot = self.snapshot_column(); + self.db + .put_cf( + &cf_snapshot, + DB_SNAPSHOT_TRANSACTION_KEY.as_bytes(), + transaction, + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } + pub fn put_snapshot_nullifier_db(&self, nullifier: Vec) -> DbResult<()> { + let cf_snapshot = self.snapshot_column(); + self.db + .put_cf( + &cf_snapshot, + DB_SNAPSHOT_NULLIFIER_KEY.as_bytes(), + nullifier, + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } + + pub fn put_snapshot_account_db(&self, account: Vec) -> DbResult<()> { + let cf_snapshot = self.snapshot_column(); + self.db + .put_cf( + &cf_snapshot, + DB_SNAPSHOT_ACCOUNT_KEY.as_bytes(), + account, + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } } ///Creates address for sc data blob at corresponding id From 0b1a1c03dc73722ec89aa3a4f75e2845c25fee24 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Fri, 23 May 2025 15:51:31 -0400 Subject: [PATCH 34/37] fmt --- storage/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 0839e05..e7f7f44 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -535,11 +535,7 @@ impl RocksDBIO { pub fn put_snapshot_account_db(&self, account: Vec) -> DbResult<()> { let cf_snapshot = self.snapshot_column(); self.db - .put_cf( - &cf_snapshot, - DB_SNAPSHOT_ACCOUNT_KEY.as_bytes(), - account, - ) + .put_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY.as_bytes(), account) .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; Ok(()) } From a6429466657bfc996ff5338bcab5a441dd629bd2 Mon Sep 17 00:00:00 2001 From: Rostyslav Tyshko Date: Wed, 28 May 2025 01:05:44 -0400 Subject: [PATCH 35/37] add asserts to test --- common/src/merkle_tree_public/merkle_tree.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index 64a6343..3540b06 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -221,6 +221,8 @@ mod tests { let obj: HashStorageMerkleTree = serde_json::from_slice(&binding).unwrap(); assert_eq!(tree.leaves, obj.leaves); + assert_eq!(tree.hash_to_id_map, obj.hash_to_id_map); + assert_eq!(tree.tree.root(), obj.tree.root()); } #[test] From 8d3ee363929db827dd89dbf7384718e13fa31e15 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 28 May 2025 08:23:54 +0300 Subject: [PATCH 36/37] fix: suggersion added 1 --- Cargo.lock | 68 ---------------------------------- Cargo.toml | 1 - common/Cargo.toml | 1 - node_core/Cargo.toml | 1 - sc_core/Cargo.toml | 1 - sc_core/src/proofs_circuits.rs | 2 - utxo/Cargo.toml | 1 - 7 files changed, 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b294ce1..6f663dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,17 +764,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bls12_381" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "bonsai-sdk" version = "1.4.0" @@ -1007,7 +996,6 @@ dependencies = [ "anyhow", "elliptic-curve", "hex", - "indexed-merkle-tree", "log", "reqwest 0.11.27", "risc0-zkvm", @@ -2366,23 +2354,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784" -[[package]] -name = "indexed-merkle-tree" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86e7e0a70243eb602dba292003d26682c23cff528c5b3c06c002d242a26d865" -dependencies = [ - "anyhow", - "bls12_381", - "borsh", - "hex", - "num", - "num-bigint 0.4.6", - "num-traits", - "serde", - "sha2", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -2956,7 +2927,6 @@ dependencies = [ "elliptic-curve", "env_logger", "hex", - "indexed-merkle-tree", "k256", "log", "rand 0.8.5", @@ -3037,20 +3007,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint 0.4.6", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.3.3" @@ -3107,28 +3063,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -4293,7 +4227,6 @@ dependencies = [ "elliptic-curve", "env_logger", "hex", - "indexed-merkle-tree", "k256", "light-poseidon", "log", @@ -5229,7 +5162,6 @@ dependencies = [ "common", "env_logger", "hex", - "indexed-merkle-tree", "log", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index edad918..7af2e24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,6 @@ tempfile = "3.14.0" light-poseidon = "0.3.0" ark-bn254 = "0.5.0" ark-ff = "0.5.0" -indexed-merkle-tree = "0.6.2" rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/common/Cargo.toml b/common/Cargo.toml index 4d2f52b..b692f5f 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -9,7 +9,6 @@ thiserror.workspace = true serde_json.workspace = true serde.workspace = true reqwest.workspace = true -indexed-merkle-tree.workspace = true risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.0" } rs_merkle.workspace = true diff --git a/node_core/Cargo.toml b/node_core/Cargo.toml index 2b59783..18120b2 100644 --- a/node_core/Cargo.toml +++ b/node_core/Cargo.toml @@ -12,7 +12,6 @@ serde.workspace = true rand.workspace = true k256.workspace = true sha2.workspace = true -indexed-merkle-tree.workspace = true bincode.workspace = true elliptic-curve.workspace = true reqwest.workspace = true diff --git a/sc_core/Cargo.toml b/sc_core/Cargo.toml index 4401ddb..e93c955 100644 --- a/sc_core/Cargo.toml +++ b/sc_core/Cargo.toml @@ -12,7 +12,6 @@ serde.workspace = true rand.workspace = true k256.workspace = true sha2.workspace = true -indexed-merkle-tree.workspace = true bincode.workspace = true elliptic-curve.workspace = true hex.workspace = true diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index d7c27d6..55e1e21 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -43,8 +43,6 @@ pub fn validate_in_commitments_proof( in_commitments_proof: &[Vec], ) -> bool { // Placeholder implementation. - // Replace with Merkle proof verification logic. - // hash(&[pedersen_commitment.serialize().to_vec(), in_commitments_proof.concat()].concat()) == root_commitment in_commitments_proof.contains(in_commitment) } diff --git a/utxo/Cargo.toml b/utxo/Cargo.toml index e7b35ef..0d97789 100644 --- a/utxo/Cargo.toml +++ b/utxo/Cargo.toml @@ -9,7 +9,6 @@ serde_json.workspace = true env_logger.workspace = true log.workspace = true serde.workspace = true -indexed-merkle-tree.workspace = true sha2.workspace = true hex.workspace = true From 9ad013253ab53c567e0ca6d264d1e3146f0fe98e Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 28 May 2025 20:32:43 +0300 Subject: [PATCH 37/37] fix: suggestions added 2 --- sc_core/src/proofs_circuits.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 55e1e21..cbebe3e 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -38,25 +38,21 @@ pub fn generate_commitments(input_utxos: &[UTXO]) -> Vec> { // takes the in_commitments[i] as a leaf, the root hash root_commitment and the path in_commitments_proofs[i][], // returns True if the in_commitments[i] is in the tree with root hash root_commitment otherwise returns False, as membership proof. pub fn validate_in_commitments_proof( - in_commitment: &Vec, + _in_commitment: &Vec, _root_commitment: Vec, - in_commitments_proof: &[Vec], + _in_commitments_proof: &[Vec], ) -> bool { - // Placeholder implementation. + // ToDo: Implement correct check - in_commitments_proof.contains(in_commitment) + todo!() } -// Validate non-membership proof for nullifiers - -// takes the nullifiers[i], path nullifiers_proof[i][] and the root hash root_nullifier, -// returns True if the nullifiers[i] is not in the tree with root hash root_nullifier otherwise returns False, as non-membership proof. -pub fn validate_nullifiers_proof( +// Validate that `nullifier` has not been present in set items before +pub fn validate_nullifier_not_present_in_set_items( nullifier: [u8; 32], - _root_nullifier: [u8; 32], - nullifiers_proof: &[[u8; 32]], + nullifiers_items: &[[u8; 32]], ) -> bool { - !nullifiers_proof.contains(&nullifier) + !nullifiers_items.contains(&nullifier) } #[allow(unused)] @@ -84,9 +80,8 @@ fn private_kernel( } for nullifier in nullifiers.iter() { - validate_nullifiers_proof( + validate_nullifier_not_present_in_set_items( nullifier[0..32].try_into().unwrap(), - root_nullifier, nullifiers_proof, ); } @@ -203,9 +198,8 @@ fn de_kernel( } for nullifier in nullifiers.iter() { - validate_nullifiers_proof( + validate_nullifier_not_present_in_set_items( nullifier[0..32].try_into().unwrap(), - root_nullifier, nullifiers_proof, ); } @@ -220,11 +214,13 @@ fn de_kernel( // otherwise // returns False, as membership proof. pub fn validate_in_commitments_proof_se( - pedersen_commitment: &PedersenCommitment, + _pedersen_commitment: &PedersenCommitment, _root_commitment: Vec, - in_commitments_proof: &[Vec], + _in_commitments_proof: &[Vec], ) -> bool { - in_commitments_proof.contains(&pedersen_commitment.serialize().to_vec()) + // ToDo: Implement correct check + + todo!() } // Generate nullifiers SE