Merge pull request #57 from vacp2p/provability

Implementation of Public State Provability
This commit is contained in:
tyshko-rostyslav 2025-04-16 12:27:31 -04:00 committed by GitHub
commit 373e3b953d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 526 additions and 21 deletions

3
Cargo.lock generated
View File

@ -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",

View File

@ -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,

View File

@ -40,6 +40,8 @@ impl From<SequencerRpcError> 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)
}
}

View File

@ -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"

View File

@ -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<u8>;
@ -40,6 +41,8 @@ pub struct Transaction {
pub encoded_data: Vec<(CipherText, Vec<u8>)>,
///Transaction senders ephemeral pub key
pub ephemeral_pub_key: Vec<u8>,
///Public (Pedersen) commitment
pub commitment: PedersenCommitment,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -62,4 +65,6 @@ pub struct TransactionPayload {
pub encoded_data: Vec<(CipherText, Vec<u8>)>,
///Transaction senders ephemeral pub key
pub ephemeral_pub_key: Vec<u8>,
///Public (Pedersen) commitment
pub commitment: PedersenCommitment,
}

View File

@ -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<u64>,
secret_r: &[u8],
) -> (Tweak, &[u8], Vec<PedersenCommitment>) {
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],

View File

@ -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<u8>) -> Vec<u64> {
// 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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<Vec<u64>> = 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<u64> = context.produce_u64_list_from_context().unwrap();
vec_values_u64.push(context_public_info);
let vec_public_info: Vec<u64> = 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,

View File

@ -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<Vec<DataBlob>> {
Ok(self.dbio.get_sc_sc_state(sc_addr)?)
}
}
#[cfg(test)]

View File

@ -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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<AccountPublicMask> =
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<u8>) -> 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<Vec<u64>, 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<u8>;
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());
}
}

View File

@ -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 => {

View File

@ -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<u64>,
) -> (Tweak, [u8; 32], Vec<PedersenCommitment>) {
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

View File

@ -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<u8>) -> TransactionPayload {
pub fn create_public_transaction_payload(
execution_input: Vec<u8>,
commitment: Vec<PedersenCommitment>,
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<u8>) -> Transactio
execution_proof_private: "".to_string(),
encoded_data: vec![],
ephemeral_pub_key: vec![],
commitment,
tweak,
secret_r,
}
}

View File

@ -21,3 +21,7 @@ path = "../mempool"
[dependencies.accounts]
path = "../accounts"
[dependencies.secp256k1-zkp]
workspace = true
features = ["std", "rand-std", "rand", "serde", "global-context"]

View File

@ -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],
}
}

View File

@ -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"]

View File

@ -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<u8>, Tag)>,
///Transaction senders ephemeral pub key
pub ephemeral_pub_key: Vec<u8>,
///Public (Pedersen) commitment
pub commitment: Vec<PedersenCommitment>,
///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<u8>, Tag)>,
///Transaction senders ephemeral pub key
pub ephemeral_pub_key: Vec<u8>,
///Public (Pedersen) commitment
pub commitment: Vec<PedersenCommitment>,
///tweak
pub tweak: Tweak,
///secret_r
pub secret_r: [u8; 32],
}
impl From<TransactionPayload> for Transaction {
@ -88,6 +101,9 @@ impl From<TransactionPayload> 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,
}
}
}