From 52a3ff9cbf2c68c61e58dc7937246dfd382e925a Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Sun, 22 Dec 2024 16:14:52 +0200 Subject: [PATCH] fix: update 1 --- Cargo.lock | 4 + accounts/src/key_management/mod.rs | 2 +- node_core/Cargo.toml | 5 + node_core/src/executions/mod.rs | 5 +- node_core/src/executions/private_exec.rs | 141 ++++++++++ node_core/src/lib.rs | 344 ++++++++++++++++++++++- node_rpc/src/process.rs | 41 ++- node_runner/src/lib.rs | 8 +- storage/Cargo.toml | 1 + storage/src/transaction.rs | 58 ++++ zkvm/src/lib.rs | 128 +++++++-- 11 files changed, 689 insertions(+), 48 deletions(-) create mode 100644 node_core/src/executions/private_exec.rs diff --git a/Cargo.lock b/Cargo.lock index 3785539..624baee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2674,11 +2674,13 @@ dependencies = [ "bincode", "elliptic-curve", "env_logger", + "hex", "k256", "log", "monotree", "rand 0.8.5", "reqwest 0.11.27", + "risc0-zkvm", "secp256k1-zkp", "serde", "serde_json", @@ -2688,6 +2690,7 @@ dependencies = [ "thiserror", "tokio", "utxo", + "zkvm", ] [[package]] @@ -4339,6 +4342,7 @@ name = "storage" version = "0.1.0" dependencies = [ "anyhow", + "elliptic-curve", "env_logger", "log", "lru", diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 817906f..df8e6b3 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -18,7 +18,7 @@ pub struct AddressKeyHolder { //Will be useful in future #[allow(dead_code)] top_secret_key_holder: TopSecretKeyHolder, - utxo_secret_key_holder: UTXOSecretKeyHolder, + pub utxo_secret_key_holder: UTXOSecretKeyHolder, pub address: TreeHashType, pub nullifer_public_key: PublicKey, pub viewing_public_key: PublicKey, diff --git a/node_core/Cargo.toml b/node_core/Cargo.toml index 2d22c22..e26c723 100644 --- a/node_core/Cargo.toml +++ b/node_core/Cargo.toml @@ -19,6 +19,8 @@ reqwest.workspace = true thiserror.workspace = true tokio.workspace = true tempfile.workspace = true +risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-1.2" } +hex.workspace = true [dependencies.accounts] path = "../accounts" @@ -29,6 +31,9 @@ path = "../storage" [dependencies.utxo] path = "../utxo" +[dependencies.zkvm] +path = "../zkvm" + [dependencies.secp256k1-zkp] workspace = true features = ["std", "rand-std", "rand", "serde", "global-context"] diff --git a/node_core/src/executions/mod.rs b/node_core/src/executions/mod.rs index 712e3e2..7c9d33e 100644 --- a/node_core/src/executions/mod.rs +++ b/node_core/src/executions/mod.rs @@ -1,2 +1,3 @@ -mod de; -mod se; +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 new file mode 100644 index 0000000..2661458 --- /dev/null +++ b/node_core/src/executions/private_exec.rs @@ -0,0 +1,141 @@ +use bincode; +use k256::Scalar; +use monotree::hasher::Blake3; +use monotree::{Hasher, Monotree, Proof}; +use rand::thread_rng; +use secp256k1_zkp::{ + compute_adaptive_blinding_factor, verify_commitments_sum_to_equal, CommitmentSecrets, + Generator, PedersenCommitment, Tag, Tweak, SECP256K1, +}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use storage::{ + commitment::Commitment, commitments_sparse_merkle_tree::CommitmentsSparseMerkleTree, + nullifier::UTXONullifier, nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, +}; +use utxo::{ + utxo_core::{UTXOPayload, UTXO}, + utxo_tree::UTXOSparseMerkleTree, +}; + +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 = CommitmentsSparseMerkleTree { + curr_root: Option::Some(root_commitment), + tree: Monotree::default(), + hasher: Blake3::new(), + }; + + let commitments: Vec<_> = in_commitments_proof + .into_iter() + .map(|n_p| Commitment { + commitment_hash: n_p.clone(), + }) + .collect(); + nsmt.insert_items(commitments).unwrap(); + + nsmt.get_non_membership_proof(in_commitment.clone()) + .unwrap() + .1 + .is_some() +} + +// 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 = NullifierSparseMerkleTree { + curr_root: Option::Some(root_nullifier), + tree: Monotree::default(), + hasher: Blake3::new(), + }; + + let nullifiers: Vec<_> = nullifiers_proof + .into_iter() + .map(|n_p| UTXONullifier { utxo_hash: *n_p }) + .collect(); + nsmt.insert_items(nullifiers).unwrap(); + + nsmt.get_non_membership_proof(nullifier) + .unwrap() + .1 + .is_none() +} + +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/lib.rs b/node_core/src/lib.rs index 290e539..48b32da 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1,24 +1,63 @@ -use std::sync::{ - atomic::{AtomicU64, Ordering}, - Arc, +use std::{ + collections::HashMap, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, }; -use accounts::account_core::Account; +use ::storage::transaction::{Transaction, TransactionPayload, TxKind}; +use accounts::account_core::{Account, AccountAddress}; use anyhow::Result; use config::NodeConfig; -use sequencer_client::SequencerClient; +use executions::{ + private_exec::{generate_commitments, generate_nullifiers}, + se::{commit, tag_random}, +}; +use rand::thread_rng; +use secp256k1_zkp::{CommitmentSecrets, Tweak}; +use sequencer_client::{json::SendTxResponse, SequencerClient}; +use serde::{Deserialize, Serialize}; use storage::NodeChainStore; use tokio::{sync::Mutex, task::JoinHandle}; +use utxo::utxo_core::UTXO; +use zkvm::{ + prove_mint_utxo, prove_send_utxo, prove_send_utxo_deshielded, prove_send_utxo_shielded, +}; pub mod config; pub mod executions; pub mod sequencer_client; pub mod storage; +#[derive(Debug, Serialize, Deserialize)] +pub struct MintMoneyPublicTx { + pub acc: AccountAddress, + pub amount: u128, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SendMoneyShieldedTx { + pub acc_sender: AccountAddress, + pub amount: u128, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SendMoneyDeshieldedTx { + pub receiver_data: Vec<(u128, AccountAddress)>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ActionData { + MintMoneyPublicTx(MintMoneyPublicTx), + SendMoneyShieldedTx(SendMoneyShieldedTx), + SendMoneyDeshieldedTx(SendMoneyDeshieldedTx), +} + pub struct NodeCore { pub storage: Arc>, pub curr_height: Arc, - pub main_acc: Account, + pub acc_map: HashMap, pub node_config: NodeConfig, pub db_updater_handle: JoinHandle>, pub sequencer_client: Arc, @@ -33,7 +72,7 @@ impl NodeCore { let mut storage = NodeChainStore::new_with_genesis(&config.home, genesis_block); - let account = Account::new(); + let account_map = HashMap::new(); let mut chain_height = genesis_id.genesis_id; @@ -81,10 +120,299 @@ impl NodeCore { Ok(Self { storage: wrapped_storage, curr_height: chain_height_wrapped, - main_acc: account, + acc_map: account_map, node_config: config.clone(), db_updater_handle: updater_handle, sequencer_client: client.clone(), }) } + + pub fn mint_utxo_private(&self, acc: AccountAddress, amount: u128) -> Transaction { + let (utxo, receipt) = prove_mint_utxo(amount, acc); + + let accout = self.acc_map.get(&acc).unwrap(); + + let encoded_data = Account::encrypt_data( + &accout.produce_ephemeral_key_holder(), + accout.key_holder.viewing_public_key, + &serde_json::to_vec(&utxo).unwrap(), + ); + + let comm = generate_commitments(&vec![utxo]); + + TransactionPayload { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: comm + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![], + execution_proof_private: serde_json::to_string(&receipt).unwrap(), + encoded_data: vec![(encoded_data.0, encoded_data.1.to_vec())], + } + .into() + } + + pub fn deposit_money_public(&self, acc: AccountAddress, amount: u128) -> Transaction { + TransactionPayload { + tx_kind: TxKind::Public, + execution_input: serde_json::to_vec(&ActionData::MintMoneyPublicTx( + MintMoneyPublicTx { acc, amount }, + )) + .unwrap(), + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: vec![], + nullifier_created_hashes: vec![], + execution_proof_private: "".to_string(), + encoded_data: vec![], + } + .into() + } + + pub async fn transfer_utxo_private( + &self, + utxo: UTXO, + receivers: Vec<(u128, AccountAddress)>, + ) -> Transaction { + let accout = self.acc_map.get(&utxo.owner).unwrap(); + + let commitment_in = { + let guard = self.storage.lock().await; + + guard.utxo_commitments_store.get_tx(utxo.hash).unwrap().hash + }; + + let nullifier = generate_nullifiers( + &utxo, + &accout + .key_holder + .utxo_secret_key_holder + .nullifier_secret_key + .to_bytes() + .to_vec(), + ); + + let (resulting_utxos, receipt) = prove_send_utxo(utxo, receivers); + + let utxos: Vec = resulting_utxos + .iter() + .map(|(utxo, _)| utxo.clone()) + .collect(); + + let encoded_data: Vec<(Vec, Vec)> = utxos + .iter() + .map(|utxo_enc| { + let accout_enc = self.acc_map.get(&utxo_enc.owner).unwrap(); + + let (ciphertext, nonce) = Account::encrypt_data( + &accout.produce_ephemeral_key_holder(), + accout_enc.key_holder.viewing_public_key, + &serde_json::to_vec(&utxo_enc).unwrap(), + ); + + (ciphertext, nonce.to_vec()) + }) + .collect(); + + let commitments = generate_commitments(&utxos); + + TransactionPayload { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: vec![commitment_in], + utxo_commitments_created_hashes: commitments + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: serde_json::to_string(&receipt).unwrap(), + encoded_data, + } + .into() + } + + pub async fn transfer_balance_shielded( + &self, + acc: AccountAddress, + balance: u64, + receivers: Vec<(u128, AccountAddress)>, + ) -> Transaction { + let accout = self.acc_map.get(&acc).unwrap(); + + let commitment_secrets = CommitmentSecrets { + value: balance, + value_blinding_factor: Tweak::from_slice( + &accout + .key_holder + .utxo_secret_key_holder + .viewing_secret_key + .to_bytes() + .to_vec(), + ) + .unwrap(), + generator_blinding_factor: Tweak::new(&mut thread_rng()), + }; + + let tag = tag_random(); + let commitment = commit(&commitment_secrets, tag); + + let nullifier = executions::se::generate_nullifiers( + &commitment, + &accout + .key_holder + .utxo_secret_key_holder + .nullifier_secret_key + .to_bytes() + .to_vec(), + ); + + let (resulting_utxos, receipt) = prove_send_utxo_shielded(acc, balance as u128, receivers); + + let utxos: Vec = resulting_utxos + .iter() + .map(|(utxo, _)| utxo.clone()) + .collect(); + + let encoded_data: Vec<(Vec, Vec)> = utxos + .iter() + .map(|utxo_enc| { + let accout_enc = self.acc_map.get(&utxo_enc.owner).unwrap(); + + let (ciphertext, nonce) = Account::encrypt_data( + &accout.produce_ephemeral_key_holder(), + accout_enc.key_holder.viewing_public_key, + &serde_json::to_vec(&utxo_enc).unwrap(), + ); + + (ciphertext, nonce.to_vec()) + }) + .collect(); + + let commitments = generate_commitments(&utxos); + + TransactionPayload { + tx_kind: TxKind::Private, + execution_input: serde_json::to_vec(&ActionData::SendMoneyShieldedTx( + SendMoneyShieldedTx { + acc_sender: acc, + amount: balance as u128, + }, + )) + .unwrap(), + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: commitments + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: serde_json::to_string(&receipt).unwrap(), + encoded_data, + } + .into() + } + + pub async fn transfer_utxo_deshielded( + &self, + utxo: UTXO, + receivers: Vec<(u128, AccountAddress)>, + ) -> Transaction { + let accout = self.acc_map.get(&utxo.owner).unwrap(); + + let commitment_in = { + let guard = self.storage.lock().await; + + guard.utxo_commitments_store.get_tx(utxo.hash).unwrap().hash + }; + + let nullifier = generate_nullifiers( + &utxo, + &accout + .key_holder + .utxo_secret_key_holder + .nullifier_secret_key + .to_bytes() + .to_vec(), + ); + + let (resulting_utxos, receipt) = prove_send_utxo_deshielded(utxo, receivers); + + TransactionPayload { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx( + SendMoneyDeshieldedTx { + receiver_data: resulting_utxos, + }, + )) + .unwrap(), + utxo_commitments_spent_hashes: vec![commitment_in], + utxo_commitments_created_hashes: vec![], + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: serde_json::to_string(&receipt).unwrap(), + encoded_data: vec![], + } + .into() + } + + pub async fn send_private_mint_tx( + &self, + acc: AccountAddress, + amount: u128, + ) -> Result { + Ok(self + .sequencer_client + .send_tx(self.mint_utxo_private(acc, amount)) + .await?) + } + + pub async fn send_public_deposit( + &self, + acc: AccountAddress, + amount: u128, + ) -> Result { + Ok(self + .sequencer_client + .send_tx(self.deposit_money_public(acc, amount)) + .await?) + } + + pub async fn send_private_send_tx( + &self, + utxo: UTXO, + receivers: Vec<(u128, AccountAddress)>, + ) -> Result { + Ok(self + .sequencer_client + .send_tx(self.transfer_utxo_private(utxo, receivers).await) + .await?) + } + + pub async fn send_shielded_send_tx( + &self, + acc: AccountAddress, + amount: u64, + receivers: Vec<(u128, AccountAddress)>, + ) -> Result { + Ok(self + .sequencer_client + .send_tx(self.transfer_balance_shielded(acc, amount, receivers).await) + .await?) + } + + pub async fn send_deshielded_send_tx( + &self, + utxo: UTXO, + receivers: Vec<(u128, AccountAddress)>, + ) -> Result { + Ok(self + .sequencer_client + .send_tx(self.transfer_utxo_deshielded(utxo, receivers).await) + .await?) + } } diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index 9dbcc93..384fd06 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -9,7 +9,10 @@ use rpc_primitives::{ use crate::{ rpc_error_responce_inverter, - types::{err_rpc::cast_seq_client_error_into_rpc_error, rpc_structs::{RegisterAccountRequest, RegisterAccountResponse, SendTxRequest}}, + types::{ + err_rpc::cast_seq_client_error_into_rpc_error, + rpc_structs::{RegisterAccountRequest, RegisterAccountResponse, SendTxRequest}, + }, }; use super::{respond, types::err_rpc::RpcErr, JsonHandler}; @@ -31,21 +34,25 @@ impl JsonHandler { } } - async fn process_register_account(&self, request: Request) -> Result { - let req = RegisterAccountRequest::parse(Some(request.params))?; + // async fn process_register_account(&self, request: Request) -> Result { + // let req = RegisterAccountRequest::parse(Some(request.params))?; - { - let guard = self.node_chain_store.lock().await; + // { + // let guard = self.node_chain_store.lock().await; - guard.sequencer_client.register_account(&guard.main_acc).await.map_err(cast_seq_client_error_into_rpc_error)?; - } + // guard + // .sequencer_client + // .register_account(&guard.main_acc) + // .await + // .map_err(cast_seq_client_error_into_rpc_error)?; + // } - let helperstruct = RegisterAccountResponse { - status: "success".to_string() - }; + // let helperstruct = RegisterAccountResponse { + // status: "success".to_string(), + // }; - respond(helperstruct) - } + // respond(helperstruct) + // } async fn process_send_tx(&self, request: Request) -> Result { let req = SendTxRequest::parse(Some(request.params))?; @@ -53,11 +60,15 @@ impl JsonHandler { { let guard = self.node_chain_store.lock().await; - guard.sequencer_client.send_tx(req.transaction).await.map_err(cast_seq_client_error_into_rpc_error)?; + guard + .sequencer_client + .send_tx(req.transaction) + .await + .map_err(cast_seq_client_error_into_rpc_error)?; } let helperstruct = RegisterAccountResponse { - status: "success".to_string() + status: "success".to_string(), }; respond(helperstruct) @@ -66,7 +77,7 @@ impl JsonHandler { pub async fn process_request_internal(&self, request: Request) -> Result { match request.method.as_ref() { //Todo : Add handling of more JSON RPC methods - "register_account" => self.process_register_account(request).await, + //"register_account" => self.process_register_account(request).await, "send_tx" => self.process_send_tx(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } diff --git a/node_runner/src/lib.rs b/node_runner/src/lib.rs index f86573f..8641da5 100644 --- a/node_runner/src/lib.rs +++ b/node_runner/src/lib.rs @@ -17,13 +17,17 @@ pub async fn main_runner() -> Result<()> { home: PathBuf::new(), override_rust_log: None, sequencer_addr: "addr".to_string(), - seq_poll_timeout_secs: 1 + seq_poll_timeout_secs: 1, }; let node_core = NodeCore::start_from_config_update_chain(node_config.clone()).await?; let wrapped_node_core = Arc::new(Mutex::new(node_core)); - let http_server = new_http_server(RpcConfig::default(), node_config.clone(), wrapped_node_core.clone())?; + let http_server = new_http_server( + RpcConfig::default(), + node_config.clone(), + wrapped_node_core.clone(), + )?; info!("HTTP server started"); let _http_server_handle = http_server.handle(); tokio::spawn(http_server); diff --git a/storage/Cargo.toml b/storage/Cargo.toml index 17e4271..cce6d2c 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -11,6 +11,7 @@ log.workspace = true serde.workspace = true lru.workspace = true thiserror.workspace = true +elliptic-curve.workspace = true rocksdb.workspace = true rs_merkle.workspace = true diff --git a/storage/src/transaction.rs b/storage/src/transaction.rs index 3c1cf37..ffafe9e 100644 --- a/storage/src/transaction.rs +++ b/storage/src/transaction.rs @@ -1,7 +1,17 @@ use serde::{Deserialize, Serialize}; +use sha2::{digest::FixedOutput, Digest}; use crate::merkle_tree_public::TreeHashType; +use elliptic_curve::{ + consts::{B0, B1}, + generic_array::GenericArray, +}; +use sha2::digest::typenum::{UInt, UTerm}; + +pub type CipherText = Vec; +pub type Nonce = GenericArray, B1>, B0>, B0>>; + #[derive(Debug, Serialize, Deserialize, Clone, Copy)] pub enum TxKind { Public, @@ -19,10 +29,58 @@ pub struct Transaction { pub execution_input: Vec, ///Tx output data (public_part) pub execution_output: Vec, + ///Tx input utxo commitments + pub utxo_commitments_spent_hashes: Vec, ///Tx output utxo commitments pub utxo_commitments_created_hashes: Vec, ///Tx output nullifiers pub nullifier_created_hashes: Vec, ///Execution proof (private part) pub execution_proof_private: String, + ///Encoded blobs of data + pub encoded_data: Vec<(CipherText, Vec)>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +///General transaction object +pub struct TransactionPayload { + pub tx_kind: TxKind, + ///Tx input data (public part) + pub execution_input: Vec, + ///Tx output data (public_part) + pub execution_output: Vec, + ///Tx input utxo commitments + pub utxo_commitments_spent_hashes: Vec, + ///Tx output utxo commitments + pub utxo_commitments_created_hashes: Vec, + ///Tx output nullifiers + pub nullifier_created_hashes: Vec, + ///Execution proof (private part) + pub execution_proof_private: String, + ///Encoded blobs of data + pub encoded_data: Vec<(CipherText, Vec)>, +} + +impl From for Transaction { + fn from(value: TransactionPayload) -> Self { + let raw_data = serde_json::to_vec(&value).unwrap(); + + let mut hasher = sha2::Sha256::new(); + + hasher.update(&raw_data); + + let hash = ::from(hasher.finalize_fixed()); + + Self { + hash, + tx_kind: value.tx_kind, + execution_input: value.execution_input, + execution_output: value.execution_output, + utxo_commitments_spent_hashes: value.utxo_commitments_spent_hashes, + utxo_commitments_created_hashes: value.utxo_commitments_created_hashes, + nullifier_created_hashes: value.nullifier_created_hashes, + execution_proof_private: value.execution_proof_private, + encoded_data: value.encoded_data, + } + } } diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 90e855e..72dfa0b 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -1,8 +1,8 @@ -use accounts::account_core::{Account, AccountAddress}; +use accounts::account_core::AccountAddress; use risc0_zkvm::{default_executor, default_prover, sha::Digest, ExecutorEnv, Receipt}; use utxo::utxo_core::{UTXOPayload, UTXO}; -pub fn prove_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> UTXO { +pub fn prove_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> (UTXO, Receipt) { let mut builder = ExecutorEnv::builder(); builder.write(&amount_to_mint).unwrap(); @@ -12,14 +12,20 @@ pub fn prove_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> UTXO { let prover = default_prover(); - let receipt = prover.prove(env, test_methods::MINT_UTXO_ELF).unwrap().receipt; + let receipt = prover + .prove(env, test_methods::MINT_UTXO_ELF) + .unwrap() + .receipt; let digest: UTXOPayload = receipt.journal.decode().unwrap(); - - UTXO::create_utxo_from_payload(digest) + + (UTXO::create_utxo_from_payload(digest), receipt) } -pub fn prove_send_utxo(spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddress)>) -> (UTXO, Vec<(UTXO, AccountAddress)>) { +pub fn prove_send_utxo( + spent_utxo: UTXO, + owners_parts: Vec<(u128, AccountAddress)>, +) -> (Vec<(UTXO, AccountAddress)>, Receipt) { let mut builder = ExecutorEnv::builder(); builder.write(&spent_utxo).unwrap(); @@ -29,13 +35,86 @@ pub fn prove_send_utxo(spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddress let prover = default_prover(); - let receipt = prover.prove(env, test_methods::SEND_UTXO_ELF).unwrap().receipt; + let receipt = prover + .prove(env, test_methods::SEND_UTXO_ELF) + .unwrap() + .receipt; - let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = receipt.journal.decode().unwrap(); - - (UTXO::create_utxo_from_payload(digest.0), digest.1.into_iter().map(|(payload, addr)| ( - UTXO::create_utxo_from_payload(payload), addr - )).collect()) + let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode().unwrap(); + + ( + digest + .into_iter() + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), + receipt, + ) +} + +pub fn prove_send_utxo_shielded( + owner: AccountAddress, + amount: u128, + owners_parts: Vec<(u128, AccountAddress)>, +) -> (Vec<(UTXO, AccountAddress)>, Receipt) { + let temp_utxo_to_spend = UTXO::create_utxo_from_payload(UTXOPayload { + owner, + asset: vec![], + amount, + privacy_flag: true, + }); + + let mut builder = ExecutorEnv::builder(); + + builder.write(&temp_utxo_to_spend).unwrap(); + builder.write(&owners_parts).unwrap(); + + let env = builder.build().unwrap(); + + let prover = default_prover(); + + let receipt = prover + .prove(env, test_methods::SEND_UTXO_ELF) + .unwrap() + .receipt; + + let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode().unwrap(); + + ( + digest + .into_iter() + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), + receipt, + ) +} + +pub fn prove_send_utxo_deshielded( + spent_utxo: UTXO, + owners_parts: Vec<(u128, AccountAddress)>, +) -> (Vec<(u128, AccountAddress)>, Receipt) { + let mut builder = ExecutorEnv::builder(); + + builder.write(&spent_utxo).unwrap(); + builder.write(&owners_parts).unwrap(); + + let env = builder.build().unwrap(); + + let prover = default_prover(); + + let receipt = prover + .prove(env, test_methods::SEND_UTXO_ELF) + .unwrap() + .receipt; + + let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode().unwrap(); + + ( + digest + .into_iter() + .map(|(payload, addr)| (payload.amount, addr)) + .collect(), + receipt, + ) } pub fn execute_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> UTXO { @@ -51,11 +130,14 @@ pub fn execute_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> UTXO { let receipt = executor.execute(env, test_methods::MINT_UTXO_ELF).unwrap(); let digest: UTXOPayload = receipt.journal.decode().unwrap(); - + UTXO::create_utxo_from_payload(digest) } -pub fn execute_send_utxo(spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddress)>) -> (UTXO, Vec<(UTXO, AccountAddress)>) { +pub fn execute_send_utxo( + spent_utxo: UTXO, + owners_parts: Vec<(u128, AccountAddress)>, +) -> (UTXO, Vec<(UTXO, AccountAddress)>) { let mut builder = ExecutorEnv::builder(); builder.write(&spent_utxo).unwrap(); @@ -67,11 +149,17 @@ pub fn execute_send_utxo(spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddre let receipt = executor.execute(env, test_methods::SEND_UTXO_ELF).unwrap(); - let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = receipt.journal.decode().unwrap(); - - (UTXO::create_utxo_from_payload(digest.0), digest.1.into_iter().map(|(payload, addr)| ( - UTXO::create_utxo_from_payload(payload), addr - )).collect()) + let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = + receipt.journal.decode().unwrap(); + + ( + UTXO::create_utxo_from_payload(digest.0), + digest + .1 + .into_iter() + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), + ) } pub fn prove(input_vec: Vec, elf: &[u8]) -> (u64, Receipt) { @@ -122,7 +210,7 @@ pub fn verify(receipt: Receipt, image_id: impl Into) { #[cfg(test)] mod tests { use super::*; - use test_methods::{BIG_CALCULATION_ELF, BIG_CALCULATION_ID}; + use test_methods::BIG_CALCULATION_ELF; use test_methods::{MULTIPLICATION_ELF, MULTIPLICATION_ID}; use test_methods::{SUMMATION_ELF, SUMMATION_ID};