initialize branch

This commit is contained in:
jonesmarvin8 2026-04-27 20:16:39 -04:00
parent e5eae57a5f
commit b12222641b
10 changed files with 288 additions and 73 deletions

View File

@ -24,21 +24,15 @@ pub enum AuthTransferSubcommand {
#[arg(
long,
conflicts_with = "account_label",
conflicts_with = "pin",
required_unless_present_any = ["account_label", "pin"]
// required_unless_present = "account_label"
)]
account_id: Option<String>,
/// Account label (alternative to --account-id).
#[arg(long, conflicts_with = "account_id", conflicts_with = "pin")]
#[arg(long, conflicts_with = "account_id")]
account_label: Option<String>,
#[arg(
long,
conflicts_with = "account_id",
conflicts_with = "account_label",
requires = "key_path"
)]
pin: Option<String>,
#[arg(long)]
pin: Option<String>,
#[arg(long, conflicts_with = "account_id", conflicts_with = "account_label")]
key_path: Option<String>,
},
/// Send native tokens from one account to another with variable privacy.
@ -49,10 +43,10 @@ pub enum AuthTransferSubcommand {
/// First is used for owned accounts, second otherwise.
Send {
/// from - valid 32 byte base58 string with privacy prefix.
#[arg(long, conflicts_with = "from_label", conflicts_with = "pin", required_unless_present_any = ["from_label", "pin"])]
#[arg(long, conflicts_with = "from_label")]
from: Option<String>,
/// From account label (alternative to --from).
#[arg(long, conflicts_with = "from", conflicts_with = "pin")]
#[arg(long, conflicts_with = "from")]
from_label: Option<String>,
/// to - valid 32 byte base58 string with privacy prefix.
#[arg(long, conflicts_with = "to_label")]
@ -69,11 +63,11 @@ pub enum AuthTransferSubcommand {
/// amount - amount of balance to move.
#[arg(long)]
amount: u128,
#[arg(long)]
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
pin: Option<String>,
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
from_key_path: Option<String>,
#[arg(long, conflicts_with = "to", conflicts_with = "to_label")]
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
to_key_path: Option<String>,
},
}
@ -173,7 +167,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
)?),
(None, None, Some(to_key_path)) => {
Some(KeycardWallet::get_account_id_for_path_with_connect(
pin.as_ref().expect("Expect a pin as a String."),
&pin.as_ref().expect("Expect a pin as a String."),
&to_key_path,
))
}
@ -232,6 +226,8 @@ impl WalletSubcommand for AuthTransferSubcommand {
from,
to,
amount,
pin,
key_path: from_key_path,
},
)
}
@ -258,6 +254,8 @@ impl WalletSubcommand for AuthTransferSubcommand {
to_npk,
to_vpk,
amount,
pin,
key_path: from_key_path,
},
)
}
@ -287,14 +285,9 @@ pub enum NativeTokenTransferProgramSubcommand {
/// amount - amount of balance to move.
#[arg(long)]
amount: u128,
#[arg(
long,
conflicts_with = "from",
conflicts_with = "from_label",
requires = "key_path"
)]
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
pin: Option<String>,
#[arg(long)]
#[arg(long, conflicts_with = "from", conflicts_with = "from_label")]
key_path: Option<String>,
},
/// Private execution.
@ -336,6 +329,10 @@ pub enum NativeTokenTransferProgramSubcommandShielded {
/// amount - amount of balance to move.
#[arg(long)]
amount: u128,
#[arg(long)]
pin: Option<String>,
#[arg(long)]
key_path: Option<String>,
},
/// Send native token transfer from `from` to `to` for `amount`.
///
@ -353,6 +350,10 @@ pub enum NativeTokenTransferProgramSubcommandShielded {
/// amount - amount of balance to move.
#[arg(long)]
amount: u128,
#[arg(long)]
pin: Option<String>,
#[arg(long)]
key_path: Option<String>,
},
}
@ -473,12 +474,18 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> {
match self {
Self::ShieldedOwned { from, to, amount } => {
Self::ShieldedOwned {
from,
to,
amount,
pin,
key_path,
} => {
let from: AccountId = from.parse().unwrap();
let to: AccountId = to.parse().unwrap();
let (tx_hash, secret) = NativeTokenTransfer(wallet_core)
.send_shielded_transfer(from, to, amount)
.send_shielded_transfer(from, to, amount, &pin, &key_path)
.await?;
println!("Transaction hash is {tx_hash}");
@ -503,6 +510,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
to_npk,
to_vpk,
amount,
pin,
key_path,
} => {
let from: AccountId = from.parse().unwrap();
@ -518,7 +527,9 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec());
let (tx_hash, _) = NativeTokenTransfer(wallet_core)
.send_shielded_transfer_to_outer_account(from, to_npk, to_vpk, amount)
.send_shielded_transfer_to_outer_account(
from, to_npk, to_vpk, amount, &pin, &key_path,
)
.await?;
println!("Transaction hash is {tx_hash}");

View File

@ -288,6 +288,8 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
sender_account_id: from,
recipient_account_id: to,
balance_to_move: amount,
pin,
sender_key_path: from_key_path,
},
)
}
@ -564,6 +566,10 @@ pub enum TokenProgramSubcommandPublic {
recipient_account_id: String,
#[arg(short, long)]
balance_to_move: u128,
#[arg(long)]
pin: Option<String>,
#[arg(long)]
sender_key_path: Option<String>,
},
// Burn tokens using the token program
BurnToken {
@ -796,12 +802,16 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
sender_account_id,
recipient_account_id,
balance_to_move,
pin,
sender_key_path,
} => {
Token(wallet_core)
.send_transfer_transaction(
sender_account_id.parse().unwrap(),
recipient_account_id.parse().unwrap(),
balance_to_move,
pin,
sender_key_path,
)
.await?;
Ok(SubcommandReturnValue::Empty)

View File

@ -70,7 +70,8 @@ pub fn resolve_id_or_label(
(None, None, Some(pin)) => Ok(KeycardWallet::get_account_id_for_path_with_connect(
pin,
key_path.as_ref().expect("Expect a key path String."),
)),
)
.to_string()),
_ => anyhow::bail!("provide exactly one of account id, account label or keycard path"),
}
}

View File

@ -16,16 +16,19 @@ use chain_storage::WalletChainStore;
use common::{HashType, transaction::NSSATransaction};
use config::WalletConfig;
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode as _};
use keycard_wallet::KeycardWallet;
use log::info;
use nssa::{
Account, AccountId, PrivacyPreservingTransaction,
Account, AccountId, PrivacyPreservingTransaction, PublicKey, Signature,
privacy_preserving_transaction::{
circuit::{ProgramWithDependencies, Proof},
message::EncryptedAccountData,
},
};
use nssa_core::{
Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData,
Commitment, MembershipProof, SharedSecretKey,
account::{AccountWithMetadata, Nonce},
program::InstructionData,
};
pub use privacy_preserving_tx::PrivacyPreservingAccount;
use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder};
@ -33,7 +36,7 @@ use tokio::io::AsyncWriteExt as _;
use crate::{
config::{PersistentStorage, WalletConfigOverrides},
helperfunctions::produce_data_for_storage,
helperfunctions::{parse_addr_with_privacy_prefix, produce_data_for_storage},
poller::TxPoller,
};
@ -363,10 +366,17 @@ impl WalletCore {
accounts: Vec<PrivacyPreservingAccount>,
instruction_data: InstructionData,
program: &ProgramWithDependencies,
pin: &Option<String>,
key_path: &Option<String>,
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
Ok(())
})
self.send_privacy_preserving_tx_with_pre_check(
accounts,
instruction_data,
program,
|_| Ok(()),
pin,
key_path,
)
.await
}
@ -376,10 +386,53 @@ impl WalletCore {
instruction_data: InstructionData,
program: &ProgramWithDependencies,
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
pin: &Option<String>,
key_path: &Option<String>,
) -> Result<(HashType, Vec<SharedSecretKey>), ExecutionFailureKind> {
let acc_manager = privacy_preserving_tx::AccountManager::new(self, accounts).await?;
let pre_states = acc_manager.pre_states();
let keycard_account = if let Some(pin) = pin.as_ref() {
let account_id = KeycardWallet::get_account_id_for_path_with_connect(
pin,
key_path.as_ref().expect("Expect a key path String."),
);
let (acc_id, _) =
parse_addr_with_privacy_prefix(&account_id).expect("Valid parsing of account id");
let account_id = acc_id.parse().expect("Expect a valid Account Id");
let account = self
.get_account_public(account_id)
.await
.expect("Expect valid account");
Some(AccountWithMetadata {
account,
is_authorized: true,
account_id,
})
} else {
None
};
let nonces: Vec<Nonce> = acc_manager.public_account_nonces().into_iter().collect();
let account_ids: Vec<AccountId> = acc_manager.public_account_ids();
let visibility_mask = acc_manager.visibility_mask().to_vec();
if let Some(acc) = keycard_account.as_ref() {
nonces.push(acc.account.nonce);
account_ids.push(acc.account_id);
visibility_mask.push(0);
pre_states.push(acc.clone());
}
tx_pre_check(
&pre_states
.iter()
@ -391,7 +444,7 @@ impl WalletCore {
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
pre_states,
instruction_data,
acc_manager.visibility_mask().to_vec(),
visibility_mask,
private_account_keys
.iter()
.map(|keys| (keys.npk, keys.ssk))
@ -404,8 +457,8 @@ impl WalletCore {
let message =
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
acc_manager.public_account_ids(),
Vec::from_iter(acc_manager.public_account_nonces()),
account_ids,
nonces,
private_account_keys
.iter()
.map(|keys| (keys.npk, keys.vpk.clone(), keys.epk.clone()))
@ -414,7 +467,7 @@ impl WalletCore {
)
.unwrap();
let witness_set = Self::sign_privacy_message(&message, &proof, &acc_manager)
let witness_set = Self::sign_privacy_message(&message, &proof, &acc_manager, pin, key_path)
.expect("Expect a valid witness set");
let tx = PrivacyPreservingTransaction::new(message, witness_set);
@ -574,13 +627,68 @@ impl WalletCore {
message: &nssa::privacy_preserving_transaction::Message,
proof: &Proof,
acc_manager: &privacy_preserving_tx::AccountManager,
_pin: &Option<String>,
_key_path: &Option<String>,
) -> Result<nssa::privacy_preserving_transaction::witness_set::WitnessSet, ExecutionFailureKind>
{
//if pin.is_none() {
Ok(
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
message,
proof.clone(),
&acc_manager.public_account_auth(),
),
)
/*} else {
let public_key = KeycardWallet::get_public_key_for_path_with_connect(
&pin.as_ref().expect("Expect a pin as a String."),
&key_path.as_ref().expect("Expect a key path String."),
);
let signature = KeycardWallet::sign_message_for_path_with_connect(
&pin.as_ref().expect("Expect a pin as a String."),
&key_path.as_ref().expect("Expect a key path String."),
&message.hash_message(),
)
.expect("Expect a valid signature");
let mut signatures = Vec::<Signature>::new();
signatures.push(signature);
let mut public_keys = Vec::<PublicKey>::new();
public_keys.push(public_key);
Ok(
nssa::privacy_preserving_transaction::witness_set::WitnessSet::from_list(
proof.clone(),
&signatures,
&public_keys,
),
)
}*/
}
pub fn sign_privacy_message_with_keycard(
message: &nssa::privacy_preserving_transaction::Message,
proof: Proof,
pin: &String,
key_paths: &[String],
) -> Result<nssa::privacy_preserving_transaction::witness_set::WitnessSet, ExecutionFailureKind>
{
let mut signatures = Vec::<Signature>::new();
let mut public_keys = Vec::<PublicKey>::new();
for path in key_paths.iter() {
public_keys.push(KeycardWallet::get_public_key_for_path_with_connect(
&pin, &path,
));
signatures.push(
KeycardWallet::sign_message_for_path_with_connect(&pin, &path, &message.hash_message())
.expect("Expect a valid signature"),
);
}
Ok(
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
message,
proof.clone(),
&acc_manager.public_account_auth(),
nssa::privacy_preserving_transaction::witness_set::WitnessSet::from_list(
proof,
&signatures,
&public_keys,
),
)
}

View File

@ -194,7 +194,13 @@ impl Ata<'_> {
];
self.0
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
.send_privacy_preserving_tx(
accounts,
instruction_data,
&ata_with_token_dependency(),
&None,
&None,
)
.await
.map(|(hash, mut secrets)| {
let secret = secrets.pop().expect("expected owner's secret");
@ -229,7 +235,13 @@ impl Ata<'_> {
];
self.0
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
.send_privacy_preserving_tx(
accounts,
instruction_data,
&ata_with_token_dependency(),
&None,
&None,
)
.await
.map(|(hash, mut secrets)| {
let secret = secrets.pop().expect("expected owner's secret");
@ -263,7 +275,13 @@ impl Ata<'_> {
];
self.0
.send_privacy_preserving_tx(accounts, instruction_data, &ata_with_token_dependency())
.send_privacy_preserving_tx(
accounts,
instruction_data,
&ata_with_token_dependency(),
&None,
&None,
)
.await
.map(|(hash, mut secrets)| {
let secret = secrets.pop().expect("expected owner's secret");

View File

@ -22,6 +22,8 @@ impl NativeTokenTransfer<'_> {
instruction_data,
&program.into(),
tx_pre_check,
&None,
&None,
)
.await
.map(|(resp, secrets)| {

View File

@ -19,6 +19,8 @@ impl NativeTokenTransfer<'_> {
vec![PrivacyPreservingAccount::PrivateOwned(from)],
Program::serialize_instruction(instruction).unwrap(),
&Program::authenticated_transfer_program().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -49,6 +51,8 @@ impl NativeTokenTransfer<'_> {
instruction_data,
&program.into(),
tx_pre_check,
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -76,6 +80,8 @@ impl NativeTokenTransfer<'_> {
instruction_data,
&program.into(),
tx_pre_check,
&None,
&None,
)
.await
.map(|(resp, secrets)| {

View File

@ -11,6 +11,8 @@ impl NativeTokenTransfer<'_> {
from: AccountId,
to: AccountId,
balance_to_move: u128,
pin: &Option<String>,
from_key_path: &Option<String>,
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
@ -23,6 +25,8 @@ impl NativeTokenTransfer<'_> {
instruction_data,
&program.into(),
tx_pre_check,
pin,
from_key_path,
)
.await
.map(|(resp, secrets)| {
@ -40,6 +44,8 @@ impl NativeTokenTransfer<'_> {
to_npk: NullifierPublicKey,
to_vpk: ViewingPublicKey,
balance_to_move: u128,
pin: &Option<String>,
from_key_path: &Option<String>,
) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
@ -55,6 +61,8 @@ impl NativeTokenTransfer<'_> {
instruction_data,
&program.into(),
tx_pre_check,
pin,
from_key_path,
)
.await
.map(|(resp, secrets)| {

View File

@ -60,6 +60,8 @@ impl Pinata<'_> {
],
nssa::program::Program::serialize_instruction(solution).unwrap(),
&nssa::program::Program::pinata().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {

View File

@ -1,5 +1,6 @@
use common::{HashType, transaction::NSSATransaction};
use nssa::{AccountId, program::Program};
use keycard_wallet::KeycardWallet;
use nssa::{AccountId, program::Program, public_transaction::WitnessSet};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
use sequencer_service_rpc::RpcClient as _;
use token_core::Instruction;
@ -78,6 +79,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -108,6 +111,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -138,6 +143,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -153,6 +160,8 @@ impl Token<'_> {
sender_account_id: AccountId,
recipient_account_id: AccountId,
amount: u128,
pin: Option<String>,
sender_key_path: Option<String>,
) -> Result<HashType, ExecutionFailureKind> {
let account_ids = vec![sender_account_id, recipient_account_id];
let program_id = nssa::program::Program::token().id();
@ -164,34 +173,12 @@ impl Token<'_> {
.get_accounts_nonces(vec![sender_account_id])
.await
.map_err(ExecutionFailureKind::SequencerError)?;
let mut private_keys = Vec::new();
let sender_sk = self
let recipient_nonces = self
.0
.storage
.user_data
.get_pub_account_signing_key(sender_account_id)
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
private_keys.push(sender_sk);
if let Some(recipient_sk) = self
.0
.storage
.user_data
.get_pub_account_signing_key(recipient_account_id)
{
private_keys.push(recipient_sk);
let recipient_nonces = self
.0
.get_accounts_nonces(vec![recipient_account_id])
.await
.map_err(ExecutionFailureKind::SequencerError)?;
nonces.extend(recipient_nonces);
} else {
println!(
"Receiver's account ({recipient_account_id}) private key not found in wallet. Proceeding with only sender's key."
);
}
.get_accounts_nonces(vec![recipient_account_id])
.await
.map_err(ExecutionFailureKind::SequencerError)?;
nonces.extend(recipient_nonces);
let message = nssa::public_transaction::Message::try_new(
program_id,
@ -200,8 +187,44 @@ impl Token<'_> {
instruction,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys);
let witness_set = if pin.is_none() {
let mut private_keys = Vec::new();
let sender_sk = self
.0
.storage
.user_data
.get_pub_account_signing_key(sender_account_id)
.ok_or(ExecutionFailureKind::KeyNotFoundError)?;
private_keys.push(sender_sk);
if let Some(recipient_sk) = self
.0
.storage
.user_data
.get_pub_account_signing_key(recipient_account_id)
{
private_keys.push(recipient_sk);
} else {
println!(
"Receiver's account ({recipient_account_id}) private key not found in wallet. Proceeding with only sender's key."
);
}
nssa::public_transaction::WitnessSet::for_message(&message, &private_keys)
} else {
let sender_public_key = KeycardWallet::get_public_key_for_path_with_connect(
&pin.as_ref().expect("Expect a pin as a String."),
&sender_key_path.as_ref().expect("Expect a key path String."),
);
let signature = KeycardWallet::sign_message_for_path_with_connect(
&pin.expect("Expect a pin as a String."),
&sender_key_path.expect("Expect a key path String."),
&message.hash_message(),
)
.expect("Expect a valid signature");
WitnessSet::from_list(&[signature], &[sender_public_key])
};
let tx = nssa::PublicTransaction::new(message, witness_set);
@ -232,6 +255,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -266,6 +291,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -296,6 +323,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -327,6 +356,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -362,6 +393,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -435,6 +468,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -465,6 +500,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -496,6 +533,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -591,6 +630,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -625,6 +666,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -655,6 +698,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -686,6 +731,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {
@ -721,6 +768,8 @@ impl Token<'_> {
],
instruction_data,
&Program::token().into(),
&None,
&None,
)
.await
.map(|(resp, secrets)| {