diff --git a/Cargo.lock b/Cargo.lock index babf1b82..d4522c0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1154,6 +1154,7 @@ dependencies = [ "env_logger", "log", "monotree", + "secp256k1-zkp", "sequencer_core", "serde", "serde_json", @@ -4685,6 +4686,7 @@ dependencies = [ "log", "mempool", "rand 0.8.5", + "secp256k1-zkp", "serde", "serde_json", "storage", @@ -4975,6 +4977,7 @@ dependencies = [ "monotree", "rocksdb", "rs_merkle", + "secp256k1-zkp", "serde", "serde_json", "sha2 0.10.8", diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 647ca24c..1bedd55e 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -29,6 +29,7 @@ pub struct Account { ///A strucure, which represents all the visible(public) information /// /// known to each node about account `address` +#[derive(Serialize, Clone)] pub struct AccountPublicMask { pub nullifier_public_key: AffinePoint, pub viewing_public_key: AffinePoint, diff --git a/common/src/lib.rs b/common/src/lib.rs index 2049ae65..16ff6388 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -40,6 +40,8 @@ impl From for SequencerClientError { pub enum ExecutionFailureKind { #[error("Failed to write into builder err: {0:?}")] WriteError(anyhow::Error), + #[error("Failed to interact with a db err: {0:?}")] + DBError(anyhow::Error), #[error("Failed to build builder err: {0:?}")] BuilderError(anyhow::Error), #[error("Failed prove execution err: {0:?}")] @@ -70,4 +72,8 @@ impl ExecutionFailureKind { pub fn prove_error(err: anyhow::Error) -> Self { Self::ProveError(err) } + + pub fn db_error(err: anyhow::Error) -> Self { + Self::DBError(err) + } } diff --git a/core_primitives/Cargo.toml b/core_primitives/Cargo.toml index c3a6f728..39885b27 100644 --- a/core_primitives/Cargo.toml +++ b/core_primitives/Cargo.toml @@ -13,6 +13,10 @@ sha2.workspace = true elliptic-curve.workspace = true monotree.workspace = true +[dependencies.secp256k1-zkp] +workspace = true +features = ["std", "rand-std", "rand", "serde", "global-context"] + [dependencies.storage] path = "../storage" diff --git a/core_primitives/src/transaction.rs b/core_primitives/src/transaction.rs index be0fb8ea..5dbf226c 100644 --- a/core_primitives/src/transaction.rs +++ b/core_primitives/src/transaction.rs @@ -6,6 +6,7 @@ use elliptic_curve::{ consts::{B0, B1}, generic_array::GenericArray, }; +use secp256k1_zkp::PedersenCommitment; use sha2::digest::typenum::{UInt, UTerm}; pub type CipherText = Vec; @@ -40,6 +41,8 @@ pub struct Transaction { pub encoded_data: Vec<(CipherText, Vec)>, ///Transaction senders ephemeral pub key pub ephemeral_pub_key: Vec, + ///Public (Pedersen) commitment + pub commitment: PedersenCommitment, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -62,4 +65,6 @@ pub struct TransactionPayload { pub encoded_data: Vec<(CipherText, Vec)>, ///Transaction senders ephemeral pub key pub ephemeral_pub_key: Vec, + ///Public (Pedersen) commitment + pub commitment: PedersenCommitment, } diff --git a/node_core/src/executions/de.rs b/node_core/src/executions/de.rs index c2ddd592..a4ee490d 100644 --- a/node_core/src/executions/de.rs +++ b/node_core/src/executions/de.rs @@ -154,6 +154,45 @@ pub fn verify_commitment( 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], diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 33bc2283..c0084698 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -11,6 +11,7 @@ use anyhow::Result; use config::NodeConfig; use executions::private_exec::{generate_commitments, generate_nullifiers}; use log::info; +use sc_core::proofs_circuits::pedersen_commitment_vec; use sequencer_client::{json::SendTxResponse, SequencerClient}; use serde::{Deserialize, Serialize}; use storage::NodeChainStore; @@ -29,6 +30,23 @@ pub mod executions; pub mod sequencer_client; pub mod storage; +fn vec_u8_to_vec_u64(bytes: Vec) -> Vec { + // Pad with zeros to make sure it's a multiple of 8 + let mut padded = bytes.clone(); + while padded.len() % 8 != 0 { + padded.push(0); + } + + padded + .chunks(8) + .map(|chunk| { + let mut array = [0u8; 8]; + array.copy_from_slice(chunk); + u64::from_le_bytes(array) + }) + .collect() +} + #[derive(Debug, Serialize, Deserialize)] pub struct MintMoneyPublicTx { pub acc: AccountAddress, @@ -175,9 +193,9 @@ impl NodeCore { let acc_map_read_guard = self.storage.read().await; - let accout = acc_map_read_guard.acc_map.get(&acc).unwrap(); + let account = acc_map_read_guard.acc_map.get(&acc).unwrap(); - let ephm_key_holder = &accout.produce_ephemeral_key_holder(); + let ephm_key_holder = &account.produce_ephemeral_key_holder(); ephm_key_holder.log(); let eph_pub_key = @@ -185,14 +203,37 @@ impl NodeCore { let encoded_data = Account::encrypt_data( &ephm_key_holder, - accout.key_holder.viewing_public_key, + account.key_holder.viewing_public_key, &serde_json::to_vec(&utxo).unwrap(), ); - let tag = accout.make_tag(); + let tag = account.make_tag(); let comm = generate_commitments(&vec![utxo]); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Private, @@ -210,6 +251,9 @@ impl NodeCore { .unwrap(), encoded_data: vec![(encoded_data.0, encoded_data.1.to_vec(), tag)], ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), result_hash, @@ -227,9 +271,9 @@ impl NodeCore { let acc_map_read_guard = self.storage.read().await; - let accout = acc_map_read_guard.acc_map.get(&acc).unwrap(); + let account = acc_map_read_guard.acc_map.get(&acc).unwrap(); - let ephm_key_holder = &accout.produce_ephemeral_key_holder(); + let ephm_key_holder = &account.produce_ephemeral_key_holder(); ephm_key_holder.log(); let eph_pub_key = @@ -241,10 +285,10 @@ impl NodeCore { ( Account::encrypt_data( &ephm_key_holder, - accout.key_holder.viewing_public_key, + account.key_holder.viewing_public_key, &serde_json::to_vec(&utxo).unwrap(), ), - accout.make_tag(), + account.make_tag(), ) }) .map(|((ciphertext, nonce), tag)| (ciphertext, nonce.to_vec(), tag)) @@ -252,6 +296,29 @@ impl NodeCore { let comm = generate_commitments(&utxos); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Private, @@ -269,6 +336,9 @@ impl NodeCore { .unwrap(), encoded_data, ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), result_hashes, @@ -283,11 +353,11 @@ impl NodeCore { ) -> Result<(Transaction, Vec<(AccountAddress, [u8; 32])>), ExecutionFailureKind> { let acc_map_read_guard = self.storage.read().await; - let accout = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); + let account = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); let nullifier = generate_nullifiers( &utxo, - &accout + &account .key_holder .utxo_secret_key_holder .nullifier_secret_key @@ -306,7 +376,7 @@ impl NodeCore { .map(|(utxo, _)| utxo.clone()) .collect(); - let ephm_key_holder = &accout.produce_ephemeral_key_holder(); + let ephm_key_holder = &account.produce_ephemeral_key_holder(); ephm_key_holder.log(); let eph_pub_key = @@ -331,6 +401,29 @@ impl NodeCore { let commitments = generate_commitments(&utxos); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Private, @@ -348,6 +441,9 @@ impl NodeCore { .unwrap(), encoded_data, ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), utxo_hashes, @@ -363,9 +459,9 @@ impl NodeCore { ) -> Result<(Transaction, Vec<[u8; 32]>, Vec<[u8; 32]>), ExecutionFailureKind> { let acc_map_read_guard = self.storage.read().await; - let accout = acc_map_read_guard.acc_map.get(&utxos[0].owner).unwrap(); + let account = acc_map_read_guard.acc_map.get(&utxos[0].owner).unwrap(); - let nsk = accout + let nsk = account .key_holder .utxo_secret_key_holder .nullifier_secret_key @@ -391,7 +487,7 @@ impl NodeCore { .map(|utxo| utxo.hash) .collect(); - let ephm_key_holder = &accout.produce_ephemeral_key_holder(); + let ephm_key_holder = &account.produce_ephemeral_key_holder(); ephm_key_holder.log(); let eph_pub_key = @@ -438,6 +534,29 @@ impl NodeCore { commitments.extend(commitments_1); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Private, @@ -455,6 +574,9 @@ impl NodeCore { .unwrap(), encoded_data, ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), utxo_hashes_receiver, @@ -472,6 +594,7 @@ impl NodeCore { let account = acc_map_read_guard.acc_map.get(&acc).unwrap(); + // TODO: add to transaction structure and do the check. Research has to update the scheme as well. let commitment = sc_core::transaction_payloads_tools::generate_secret_random_commitment( balance, account, ) @@ -523,6 +646,29 @@ impl NodeCore { let commitments = generate_commitments(&utxos); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Shielded, @@ -546,6 +692,9 @@ impl NodeCore { .unwrap(), encoded_data, ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), utxo_hashes, @@ -566,11 +715,11 @@ impl NodeCore { .unwrap() .hash; - let accout = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); + let account = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); let nullifier = generate_nullifiers( &utxo, - &accout + &account .key_holder .utxo_secret_key_holder .nullifier_secret_key @@ -580,6 +729,29 @@ impl NodeCore { let (resulting_balances, receipt) = prove_send_utxo_deshielded(utxo, receivers)?; + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(TransactionPayload { tx_kind: TxKind::Deshielded, execution_input: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx( @@ -596,6 +768,9 @@ impl NodeCore { .unwrap(), encoded_data: vec![], ephemeral_pub_key: vec![], + commitment, + tweak, + secret_r, } .into()) } @@ -661,6 +836,17 @@ impl NodeCore { //Considering proof time, needs to be done before proof let tx_roots = self.get_roots().await; + let public_context = { + let read_guard = self.storage.read().await; + + read_guard.produce_context(acc) + }; + + let (tweak, secret_r, commitment) = pedersen_commitment_vec( + //Will not panic, as public context is serializable + public_context.produce_u64_list_from_context().unwrap(), + ); + let tx: Transaction = sc_core::transaction_payloads_tools::create_public_transaction_payload( serde_json::to_vec(&ActionData::MintMoneyPublicTx(MintMoneyPublicTx { @@ -668,6 +854,9 @@ impl NodeCore { amount, })) .unwrap(), + commitment, + tweak, + secret_r, ) .into(); tx.log(); @@ -1102,11 +1291,11 @@ impl NodeCore { ) -> Result<(Transaction, Vec<(AccountAddress, [u8; 32])>), ExecutionFailureKind> { let acc_map_read_guard = self.storage.read().await; - let accout = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); + let account = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); let nullifier = generate_nullifiers( &utxo, - &accout + &account .key_holder .utxo_secret_key_holder .nullifier_secret_key @@ -1125,7 +1314,7 @@ impl NodeCore { .map(|(utxo, _)| utxo.clone()) .collect(); - let ephm_key_holder = &accout.produce_ephemeral_key_holder(); + let ephm_key_holder = &account.produce_ephemeral_key_holder(); ephm_key_holder.log(); let eph_pub_key = @@ -1164,6 +1353,29 @@ impl NodeCore { .collect(), }); + // TODO: fix address when correspoding method will be added + let sc_addr = ""; + + let sc_state = acc_map_read_guard + .block_store + .get_sc_sc_state(sc_addr) + .map_err(ExecutionFailureKind::db_error)?; + + let mut vec_values_u64: Vec> = sc_state + .into_iter() + .map(|slice| vec_u8_to_vec_u64(slice.to_vec())) + .collect(); + + let context = acc_map_read_guard.produce_context(account.address); + + //Will not panic, as PublicScContext is serializable + let context_public_info: Vec = context.produce_u64_list_from_context().unwrap(); + vec_values_u64.push(context_public_info); + + let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); + + let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + Ok(( TransactionPayload { tx_kind: TxKind::Shielded, @@ -1182,6 +1394,9 @@ impl NodeCore { .unwrap(), encoded_data, ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, } .into(), utxo_hashes, diff --git a/node_core/src/storage/block_store.rs b/node_core/src/storage/block_store.rs index 6991ee5a..33aa8ab0 100644 --- a/node_core/src/storage/block_store.rs +++ b/node_core/src/storage/block_store.rs @@ -1,6 +1,7 @@ use std::path::Path; use anyhow::{anyhow, Result}; +use storage::sc_db_utils::DataBlob; use storage::{block::Block, RocksDBIO}; pub struct NodeBlockStore { @@ -41,6 +42,10 @@ impl NodeBlockStore { pub fn put_block_at_id(&self, block: Block) -> Result<()> { Ok(self.dbio.put_block(block, false)?) } + + pub fn get_sc_sc_state(&self, sc_addr: &str) -> Result> { + Ok(self.dbio.get_sc_sc_state(sc_addr)?) + } } #[cfg(test)] diff --git a/node_core/src/storage/public_context.rs b/node_core/src/storage/public_context.rs index db0503fb..957241f1 100644 --- a/node_core/src/storage/public_context.rs +++ b/node_core/src/storage/public_context.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use accounts::account_core::{AccountAddress, AccountPublicMask}; +use serde::{ser::SerializeStruct, Serialize}; use storage::merkle_tree_public::TreeHashType; ///Strucutre, representing context, given to a smart contract on a call @@ -12,3 +13,164 @@ pub struct PublicSCContext { pub comitment_store_root: TreeHashType, pub pub_tx_store_root: TreeHashType, } + +impl Serialize for PublicSCContext { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut account_masks_keys: Vec<[u8; 32]> = self.account_masks.keys().cloned().collect(); + account_masks_keys.sort(); + + let mut account_mask_values: Vec = + self.account_masks.values().cloned().collect(); + account_mask_values.sort_by(|left, right| left.address.cmp(&right.address)); + + let mut s = serializer.serialize_struct("PublicSCContext", 7)?; + + s.serialize_field("caller_address", &self.caller_address)?; + 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)?; + + s.end() + } +} + +impl PublicSCContext { + ///Produces `u64` from bytes in a vector + /// + /// Assumes, that vector of le_bytes + pub fn produce_u64_from_fit_vec(data: Vec) -> u64 { + let data_len = data.len(); + + assert!(data_len <= 8); + let mut le_bytes: [u8; 8] = [0; 8]; + + for (idx, item) in data.into_iter().enumerate() { + le_bytes[idx] = item + } + + u64::from_le_bytes(le_bytes) + } + + ///Produces vector of `u64` from context + pub fn produce_u64_list_from_context(&self) -> Result, serde_json::Error> { + let mut u64_list = vec![]; + + let ser_data = serde_json::to_vec(self)?; + + //`ToDo` Replace with `next_chunk` usage, when feature stabilizes in Rust + for i in 0..=(ser_data.len() / 8) { + let next_chunk: Vec; + + if (i + 1) * 8 < ser_data.len() { + next_chunk = ser_data[(i * 8)..((i + 1) * 8)].iter().cloned().collect(); + } else { + next_chunk = ser_data[(i * 8)..(ser_data.len())] + .iter() + .cloned() + .collect(); + } + + u64_list.push(PublicSCContext::produce_u64_from_fit_vec(next_chunk)); + } + + Ok(u64_list) + } +} + +#[cfg(test)] +mod tests { + use accounts::account_core::Account; + + use super::*; + + 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]; + + let mut account_masks = BTreeMap::new(); + + let acc_1 = Account::new(); + let acc_2 = Account::new(); + let acc_3 = Account::new(); + + account_masks.insert(acc_1.address, acc_1.make_account_public_mask()); + account_masks.insert(acc_2.address, acc_2.make_account_public_mask()); + account_masks.insert(acc_3.address, acc_3.make_account_public_mask()); + + PublicSCContext { + caller_address, + caller_balance: 100, + account_masks, + nullifier_store_root, + comitment_store_root, + pub_tx_store_root, + } + } + + #[test] + fn bin_ser_stability_test() { + let test_context = create_test_context(); + + let serialization_1 = serde_json::to_vec(&test_context).unwrap(); + let serialization_2 = serde_json::to_vec(&test_context).unwrap(); + + assert_eq!(serialization_1, serialization_2); + } + + #[test] + fn correct_u64_production_from_fit_vec() { + let le_vec = vec![1, 1, 1, 1, 2, 1, 1, 1]; + + let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); + + assert_eq!(num, 72340177133043969); + } + + #[test] + fn correct_u64_production_from_small_vec() { + //7 items instead of 8 + let le_vec = vec![1, 1, 1, 1, 2, 1, 1]; + + let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); + + assert_eq!(num, 282583095116033); + } + + #[test] + fn correct_u64_production_from_small_vec_le_bytes() { + //7 items instead of 8 + let le_vec = vec![1, 1, 1, 1, 2, 1, 1]; + let le_vec_res = [1, 1, 1, 1, 2, 1, 1, 0]; + + let num = PublicSCContext::produce_u64_from_fit_vec(le_vec); + + assert_eq!(num.to_le_bytes(), le_vec_res); + } + + #[test] + #[should_panic] + fn correct_u64_production_from_unfit_vec_should_panic() { + //9 items instead of 8 + let le_vec = vec![1, 1, 1, 1, 2, 1, 1, 1, 1]; + + PublicSCContext::produce_u64_from_fit_vec(le_vec); + } + + #[test] + fn consistent_len_of_context_commitments() { + let test_context = create_test_context(); + + let context_num_vec1 = test_context.produce_u64_list_from_context().unwrap(); + let context_num_vec2 = test_context.produce_u64_list_from_context().unwrap(); + + assert_eq!(context_num_vec1.len(), context_num_vec2.len()); + } +} diff --git a/node_rpc/src/types/err_rpc.rs b/node_rpc/src/types/err_rpc.rs index df80de93..22e9d299 100644 --- a/node_rpc/src/types/err_rpc.rs +++ b/node_rpc/src/types/err_rpc.rs @@ -66,6 +66,7 @@ pub fn cast_common_execution_error_into_rpc_error(comm_exec_err: ExecutionFailur match comm_exec_err { ExecutionFailureKind::BuilderError(_) => RpcError::new_internal_error(None, &error_string), ExecutionFailureKind::WriteError(_) => RpcError::new_internal_error(None, &error_string), + ExecutionFailureKind::DBError(_) => RpcError::new_internal_error(None, &error_string), ExecutionFailureKind::DecodeError(_) => RpcError::new_internal_error(None, &error_string), ExecutionFailureKind::ProveError(_) => RpcError::new_internal_error(None, &error_string), ExecutionFailureKind::AmountMismatchError => { diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 7c646c22..6b2b3675 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -2,7 +2,7 @@ use bincode; use k256::Scalar; use monotree::hasher::Blake3; use monotree::{Hasher, Monotree}; -use rand::thread_rng; +use rand::{thread_rng, RngCore}; use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1}; use sha2::{Digest, Sha256}; use storage::{ @@ -168,6 +168,32 @@ pub fn check_balances(public_info: u128, output_utxos: &[UTXO]) -> bool { public_info == total_output } +// new_commitment for a Vec of values +pub fn pedersen_commitment_vec( + public_info_vec: Vec, +) -> (Tweak, [u8; 32], Vec) { + let mut random_val: [u8; 32] = [0; 32]; + thread_rng().fill_bytes(&mut random_val); + + 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(&random_val).unwrap(), + generator_blinding_factor, + }; + + commit(&commitment_secrets, tag) + }) + .collect(); + + (generator_blinding_factor, random_val, vec_commitments) +} + // Verify Pedersen commitment // takes the public_info, secret_r and pedersen_commitment and diff --git a/sc_core/src/transaction_payloads_tools.rs b/sc_core/src/transaction_payloads_tools.rs index f1a99e0f..c84cc6fe 100644 --- a/sc_core/src/transaction_payloads_tools.rs +++ b/sc_core/src/transaction_payloads_tools.rs @@ -8,7 +8,12 @@ use utxo::utxo_core::UTXO; use crate::proofs_circuits::{commit, generate_nullifiers, tag_random}; -pub fn create_public_transaction_payload(execution_input: Vec) -> TransactionPayload { +pub fn create_public_transaction_payload( + execution_input: Vec, + commitment: Vec, + tweak: Tweak, + secret_r: [u8; 32], +) -> TransactionPayload { TransactionPayload { tx_kind: TxKind::Public, execution_input, @@ -19,6 +24,9 @@ pub fn create_public_transaction_payload(execution_input: Vec) -> Transactio execution_proof_private: "".to_string(), encoded_data: vec![], ephemeral_pub_key: vec![], + commitment, + tweak, + secret_r, } } diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 634337e0..730684ab 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -21,3 +21,7 @@ path = "../mempool" [dependencies.accounts] path = "../accounts" + +[dependencies.secp256k1-zkp] +workspace = true +features = ["std", "rand-std", "rand", "serde", "global-context"] diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index e07f49e0..01b0dd9f 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -263,6 +263,7 @@ mod tests { use std::{fmt::format, path::PathBuf}; use rand::Rng; + use secp256k1_zkp::Tweak; use storage::transaction::{Transaction, TxKind}; use transaction_mempool::TransactionMempool; @@ -289,6 +290,8 @@ mod tests { utxo_commitments_spent_hashes: Vec<[u8; 32]>, utxo_commitments_created_hashes: Vec<[u8; 32]>, ) -> Transaction { + let mut rng = rand::thread_rng(); + Transaction { hash, tx_kind: TxKind::Private, @@ -300,6 +303,9 @@ mod tests { execution_proof_private: "dummy_proof".to_string(), encoded_data: vec![], ephemeral_pub_key: vec![10, 11, 12], + commitment: vec![], + tweak: Tweak::new(&mut rng), + secret_r: [0; 32], } } diff --git a/storage/Cargo.toml b/storage/Cargo.toml index 0da0fc36..4455cbf1 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -18,3 +18,7 @@ rocksdb.workspace = true rs_merkle.workspace = true sha2.workspace = true monotree.workspace = true + +[dependencies.secp256k1-zkp] +workspace = true +features = ["std", "rand-std", "rand", "serde", "global-context"] diff --git a/storage/src/transaction.rs b/storage/src/transaction.rs index 2a7f23c6..149ddc0d 100644 --- a/storage/src/transaction.rs +++ b/storage/src/transaction.rs @@ -1,4 +1,5 @@ use log::info; +use secp256k1_zkp::{PedersenCommitment, Tweak}; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; @@ -43,6 +44,12 @@ pub struct Transaction { pub encoded_data: Vec<(CipherText, Vec, Tag)>, ///Transaction senders ephemeral pub key pub ephemeral_pub_key: Vec, + ///Public (Pedersen) commitment + pub commitment: Vec, + ///tweak + pub tweak: Tweak, + ///secret_r + pub secret_r: [u8; 32], } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -65,6 +72,12 @@ pub struct TransactionPayload { pub encoded_data: Vec<(CipherText, Vec, Tag)>, ///Transaction senders ephemeral pub key pub ephemeral_pub_key: Vec, + ///Public (Pedersen) commitment + pub commitment: Vec, + ///tweak + pub tweak: Tweak, + ///secret_r + pub secret_r: [u8; 32], } impl From for Transaction { @@ -88,6 +101,9 @@ impl From for Transaction { execution_proof_private: value.execution_proof_private, encoded_data: value.encoded_data, ephemeral_pub_key: value.ephemeral_pub_key, + commitment: value.commitment, + tweak: value.tweak, + secret_r: value.secret_r, } } }