mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-08 00:03:09 +00:00
fix; privacy preserving tx gen 1
This commit is contained in:
parent
65dfbd8bbb
commit
854d96af72
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2333,6 +2333,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nssa",
|
||||
"nssa-core",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@ -147,6 +147,26 @@ impl SequencerClient {
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
///Send transaction to sequencer
|
||||
pub async fn send_tx_private(
|
||||
&self,
|
||||
transaction: nssa::PrivacyPreservingTransaction,
|
||||
) -> Result<SendTxResponse, SequencerClientError> {
|
||||
let transaction = EncodedTransaction::from(NSSATransaction::PrivacyPreserving(transaction));
|
||||
|
||||
let tx_req = SendTxRequest {
|
||||
transaction: transaction.to_bytes(),
|
||||
};
|
||||
|
||||
let req = serde_json::to_value(tx_req)?;
|
||||
|
||||
let resp = self.call_method_with_payload("send_tx", req).await?;
|
||||
|
||||
let resp_deser = serde_json::from_value(resp)?;
|
||||
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
///Get genesis id from sequencer
|
||||
pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> {
|
||||
let genesis_req = GetGenesisIdRequest {};
|
||||
|
||||
@ -117,7 +117,7 @@ pub async fn test_success() {
|
||||
}
|
||||
|
||||
pub async fn test_success_move_to_another_account() {
|
||||
let command = Command::RegisterAccount {};
|
||||
let command = Command::RegisterAccountPublic {};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
@ -130,10 +130,10 @@ pub async fn test_success_move_to_another_account() {
|
||||
let mut new_persistent_account_addr = String::new();
|
||||
|
||||
for per_acc in persistent_accounts {
|
||||
if (per_acc.address.to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address.to_string() != ACC_SENDER)
|
||||
if (per_acc.address().to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address().to_string() != ACC_SENDER)
|
||||
{
|
||||
new_persistent_account_addr = per_acc.address.to_string();
|
||||
new_persistent_account_addr = per_acc.address().to_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ aes-gcm.workspace = true
|
||||
lazy_static.workspace = true
|
||||
bip39.workspace = true
|
||||
hmac-sha512.workspace = true
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
|
||||
[dependencies.common]
|
||||
path = "../common"
|
||||
|
||||
@ -23,9 +23,9 @@ pub struct TopSecretKeyHolder {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
///Private key holder. Produces public keys. Can produce address. Can produce shared secret for recepient.
|
||||
pub struct PrivateKeyHolder {
|
||||
pub(crate) nullifier_secret_key: [u8; 32],
|
||||
pub nullifier_secret_key: [u8; 32],
|
||||
pub(crate) incoming_viewing_secret_key: Scalar,
|
||||
pub(crate) outgoing_viewing_secret_key: Scalar,
|
||||
pub outgoing_viewing_secret_key: Scalar,
|
||||
}
|
||||
|
||||
impl SeedHolder {
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct NSSAUserData {
|
||||
///Map for all user public accounts
|
||||
pub pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
///Map for all user private accounts
|
||||
user_private_accounts: HashMap<nssa::Address, KeyChain>,
|
||||
pub user_private_accounts: HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
}
|
||||
|
||||
impl NSSAUserData {
|
||||
@ -30,10 +30,10 @@ impl NSSAUserData {
|
||||
}
|
||||
|
||||
fn valid_private_key_transaction_pairing_check(
|
||||
accounts_keys_map: &HashMap<nssa::Address, KeyChain>,
|
||||
accounts_keys_map: &HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
) -> bool {
|
||||
let mut check_res = true;
|
||||
for (addr, key) in accounts_keys_map {
|
||||
for (addr, (key, _)) in accounts_keys_map {
|
||||
if nssa::Address::new(key.produce_user_address()) != *addr {
|
||||
check_res = false;
|
||||
}
|
||||
@ -43,7 +43,7 @@ impl NSSAUserData {
|
||||
|
||||
pub fn new_with_accounts(
|
||||
accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
accounts_key_chains: HashMap<nssa::Address, KeyChain>,
|
||||
accounts_key_chains: HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
) -> Result<Self> {
|
||||
if !Self::valid_public_key_transaction_pairing_check(&accounts_keys) {
|
||||
anyhow::bail!(
|
||||
@ -90,15 +90,27 @@ impl NSSAUserData {
|
||||
let key_chain = KeyChain::new_os_random();
|
||||
let address = nssa::Address::new(key_chain.produce_user_address());
|
||||
|
||||
self.user_private_accounts.insert(address, key_chain);
|
||||
self.user_private_accounts
|
||||
.insert(address, (key_chain, nssa_core::account::Account::default()));
|
||||
|
||||
address
|
||||
}
|
||||
|
||||
/// Returns the signing key for public transaction signatures
|
||||
pub fn get_private_account_key_chain(&self, address: &nssa::Address) -> Option<&KeyChain> {
|
||||
pub fn get_private_account(
|
||||
&self,
|
||||
address: &nssa::Address,
|
||||
) -> Option<&(KeyChain, nssa_core::account::Account)> {
|
||||
self.user_private_accounts.get(address)
|
||||
}
|
||||
|
||||
/// Returns the signing key for public transaction signatures
|
||||
pub fn get_private_account_mut(
|
||||
&mut self,
|
||||
address: &nssa::Address,
|
||||
) -> Option<&mut (KeyChain, nssa_core::account::Account)> {
|
||||
self.user_private_accounts.get_mut(address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NSSAUserData {
|
||||
@ -123,9 +135,7 @@ mod tests {
|
||||
|
||||
assert!(is_private_key_generated);
|
||||
|
||||
let is_key_chain_generated = user_data
|
||||
.get_private_account_key_chain(&addr_private)
|
||||
.is_some();
|
||||
let is_key_chain_generated = user_data.get_private_account(&addr_private).is_some();
|
||||
|
||||
assert!(is_key_chain_generated);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ pub mod address;
|
||||
pub mod encoding;
|
||||
pub mod error;
|
||||
mod merkle_tree;
|
||||
mod privacy_preserving_transaction;
|
||||
pub mod privacy_preserving_transaction;
|
||||
pub mod program;
|
||||
pub mod public_transaction;
|
||||
mod signature;
|
||||
|
||||
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use anyhow::Result;
|
||||
use key_protocol::key_protocol_core::NSSAUserData;
|
||||
|
||||
use crate::config::{PersistentAccountData, WalletConfig};
|
||||
use crate::config::{InitialAccountData, PersistentAccountData, WalletConfig};
|
||||
|
||||
pub struct WalletChainStore {
|
||||
pub user_data: NSSAUserData,
|
||||
@ -12,24 +12,40 @@ pub struct WalletChainStore {
|
||||
|
||||
impl WalletChainStore {
|
||||
pub fn new(config: WalletConfig) -> Result<Self> {
|
||||
let accounts_keys: HashMap<nssa::Address, nssa::PrivateKey> = config
|
||||
.initial_accounts
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|init_acc_data| (init_acc_data.address, init_acc_data.pub_sign_key))
|
||||
.collect();
|
||||
let mut public_init_acc_map = HashMap::new();
|
||||
let mut private_init_acc_map = HashMap::new();
|
||||
|
||||
for init_acc_data in config.initial_accounts.clone() {
|
||||
match init_acc_data {
|
||||
InitialAccountData::Public(data) => {
|
||||
public_init_acc_map.insert(data.address, data.pub_sign_key);
|
||||
}
|
||||
InitialAccountData::Private(data) => {
|
||||
private_init_acc_map.insert(data.address, (data.key_chain, data.account));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
user_data: NSSAUserData::new_with_accounts(accounts_keys, HashMap::new())?,
|
||||
user_data: NSSAUserData::new_with_accounts(public_init_acc_map, private_init_acc_map)?,
|
||||
wallet_config: config,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn insert_account_data(&mut self, acc_data: PersistentAccountData) {
|
||||
match acc_data {
|
||||
PersistentAccountData::Public(acc_data) => {
|
||||
self.user_data
|
||||
.pub_account_signing_keys
|
||||
.insert(acc_data.address, acc_data.pub_sign_key);
|
||||
}
|
||||
PersistentAccountData::Private(acc_data) => {
|
||||
self.user_data
|
||||
.user_private_accounts
|
||||
.insert(acc_data.address, (acc_data.key_chain, acc_data.account));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -1,19 +1,87 @@
|
||||
use key_protocol::key_management::KeyChain;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InitialAccountData {
|
||||
pub struct InitialAccountDataPublic {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub pub_sign_key: nssa::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentAccountData {
|
||||
pub struct PersistentAccountDataPublic {
|
||||
pub address: nssa::Address,
|
||||
pub pub_sign_key: nssa::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InitialAccountDataPrivate {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub key_chain: KeyChain,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentAccountDataPrivate {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub key_chain: KeyChain,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InitialAccountData {
|
||||
Public(InitialAccountDataPublic),
|
||||
Private(InitialAccountDataPrivate),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PersistentAccountData {
|
||||
Public(PersistentAccountDataPublic),
|
||||
Private(PersistentAccountDataPrivate),
|
||||
}
|
||||
|
||||
impl InitialAccountData {
|
||||
pub fn address(&self) -> nssa::Address {
|
||||
match &self {
|
||||
Self::Public(acc) => acc.address,
|
||||
Self::Private(acc) => acc.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PersistentAccountData {
|
||||
pub fn address(&self) -> nssa::Address {
|
||||
match &self {
|
||||
Self::Public(acc) => acc.address,
|
||||
Self::Private(acc) => acc.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitialAccountDataPublic> for InitialAccountData {
|
||||
fn from(value: InitialAccountDataPublic) -> Self {
|
||||
Self::Public(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitialAccountDataPrivate> for InitialAccountData {
|
||||
fn from(value: InitialAccountDataPrivate) -> Self {
|
||||
Self::Private(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PersistentAccountDataPublic> for PersistentAccountData {
|
||||
fn from(value: PersistentAccountDataPublic) -> Self {
|
||||
Self::Public(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PersistentAccountDataPrivate> for PersistentAccountData {
|
||||
fn from(value: PersistentAccountDataPrivate) -> Self {
|
||||
Self::Private(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GasConfig {
|
||||
/// Gas spent per deploying one byte of data
|
||||
|
||||
@ -6,7 +6,10 @@ use nssa::Address;
|
||||
|
||||
use crate::{
|
||||
HOME_DIR_ENV_VAR,
|
||||
config::{PersistentAccountData, WalletConfig},
|
||||
config::{
|
||||
PersistentAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic,
|
||||
WalletConfig,
|
||||
},
|
||||
};
|
||||
|
||||
///Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed.
|
||||
@ -54,10 +57,24 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
|
||||
let mut vec_for_storage = vec![];
|
||||
|
||||
for (addr, key) in &user_data.pub_account_signing_keys {
|
||||
vec_for_storage.push(PersistentAccountData {
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPublic {
|
||||
address: *addr,
|
||||
pub_sign_key: key.clone(),
|
||||
});
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
for (addr, (key, acc)) in &user_data.user_private_accounts {
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPrivate {
|
||||
address: *addr,
|
||||
account: acc.clone(),
|
||||
key_chain: key.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
vec_for_storage
|
||||
|
||||
@ -10,11 +10,11 @@ use common::{
|
||||
use anyhow::Result;
|
||||
use chain_storage::WalletChainStore;
|
||||
use config::WalletConfig;
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use log::info;
|
||||
use nssa::Address;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use nssa_core::account::Account;
|
||||
|
||||
use crate::{
|
||||
helperfunctions::{
|
||||
@ -31,8 +31,6 @@ pub mod config;
|
||||
pub mod helperfunctions;
|
||||
pub mod poller;
|
||||
|
||||
//
|
||||
|
||||
pub struct WalletCore {
|
||||
pub storage: WalletChainStore,
|
||||
pub poller: TxPoller,
|
||||
@ -74,19 +72,16 @@ impl WalletCore {
|
||||
Ok(accs_path)
|
||||
}
|
||||
|
||||
pub fn create_new_account(&mut self) -> Address {
|
||||
pub fn create_new_account_public(&mut self) -> Address {
|
||||
self.storage
|
||||
.user_data
|
||||
.generate_new_public_transaction_private_key()
|
||||
}
|
||||
|
||||
pub fn search_for_initial_account(&self, acc_addr: Address) -> Option<Account> {
|
||||
for initial_acc in &self.storage.wallet_config.initial_accounts {
|
||||
if initial_acc.address == acc_addr {
|
||||
return Some(initial_acc.account.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn create_new_account_private(&mut self) -> Address {
|
||||
self.storage
|
||||
.user_data
|
||||
.generate_new_privacy_preserving_transaction_key_chain()
|
||||
}
|
||||
|
||||
pub async fn send_public_native_token_transfer(
|
||||
@ -131,6 +126,92 @@ impl WalletCore {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_private_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let from_data = self.storage.user_data.get_private_account(&from);
|
||||
let to_data = self.storage.user_data.get_private_account(&to);
|
||||
|
||||
let Some((from_keys, from_acc)) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let Some((to_keys, to_acc)) = to_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
let sender_commitment = nssa_core::Commitment::new(
|
||||
&nssa_core::NullifierPublicKey(from_keys.nullifer_public_key),
|
||||
from_acc,
|
||||
);
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
};
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: false,
|
||||
};
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(
|
||||
to_keys.nullifer_public_key,
|
||||
from_keys.private_key_holder.outgoing_viewing_secret_key,
|
||||
from_acc.nonce.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let shared_secret =
|
||||
eph_holder.calculate_shared_secret_sender(to_keys.incoming_viewing_public_key);
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 2],
|
||||
&[from_acc.nonce + 1, to_acc.nonce + 1],
|
||||
&[
|
||||
(
|
||||
nssa_core::NullifierPublicKey(from_keys.nullifer_public_key),
|
||||
shared_secret,
|
||||
),
|
||||
(
|
||||
nssa_core::NullifierPublicKey(to_keys.nullifer_public_key),
|
||||
shared_secret,
|
||||
),
|
||||
],
|
||||
&[(
|
||||
from_keys.private_key_holder.nullifier_secret_key,
|
||||
state.get_proof_for_commitment(&sender_commitment).unwrap(),
|
||||
)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![],
|
||||
vec![],
|
||||
vec![
|
||||
(sender_keys.npk(), sender_keys.ivk(), epk_1),
|
||||
(recipient_keys.npk(), recipient_keys.ivk(), epk_2),
|
||||
],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
|
||||
///Get account balance
|
||||
pub async fn get_account_balance(&self, acc: Address) -> Result<u128> {
|
||||
Ok(self
|
||||
@ -176,8 +257,10 @@ pub enum Command {
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Register new account
|
||||
RegisterAccount {},
|
||||
///Register new public account
|
||||
RegisterAccountPublic {},
|
||||
///Register new private account
|
||||
RegisterAccountPrivate {},
|
||||
///Fetch transaction by `hash`
|
||||
FetchTx {
|
||||
#[arg(short, long)]
|
||||
@ -225,8 +308,8 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
|
||||
info!("Transaction data is {transfer_tx:?}");
|
||||
}
|
||||
Command::RegisterAccount {} => {
|
||||
let addr = wallet_core.create_new_account();
|
||||
Command::RegisterAccountPublic {} => {
|
||||
let addr = wallet_core.create_new_account_public();
|
||||
|
||||
let key = wallet_core
|
||||
.storage
|
||||
@ -236,6 +319,19 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
info!("Generated new account with addr {addr:#?}");
|
||||
info!("With key {key:#?}");
|
||||
}
|
||||
Command::RegisterAccountPrivate {} => {
|
||||
let addr = wallet_core.create_new_account_private();
|
||||
|
||||
let (key, account) = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&addr)
|
||||
.unwrap();
|
||||
|
||||
info!("Generated new account with addr {addr:#?}");
|
||||
info!("With key {key:#?}");
|
||||
info!("With account {account:#?}");
|
||||
}
|
||||
Command::FetchTx { tx_hash } => {
|
||||
let tx_obj = wallet_core
|
||||
.sequencer_client
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user