Merge branch 'main' into Pravdyvy/indexer-state-management

This commit is contained in:
Pravdyvy 2026-02-17 08:06:16 +02:00
commit f11d374ae7
69 changed files with 2760 additions and 1760 deletions

View File

@ -12,6 +12,7 @@ ignore = [
{ id = "RUSTSEC-2024-0436", reason = "`paste` has a security vulnerability; consider using an alternative. Use `cargo tree -p paste -i > tmp.txt` to check the dependency tree." },
{ id = "RUSTSEC-2025-0055", reason = "`tracing-subscriber` v0.2.25 pulled in by ark-relations v0.4.0 - will be addressed before mainnet" },
{ id = "RUSTSEC-2025-0141", reason = "`bincode` is unmaintained but continuing to use it." },
{ id = "RUSTSEC-2023-0089", reason = "atomic-polyfill is pulled transitively via risc0-zkvm; waiting on upstream fix (see https://github.com/risc0/risc0/issues/3453)" },
]
yanked = "deny"
unused-ignored-advisory = "deny"
@ -35,6 +36,16 @@ allow = [
"Unicode-3.0",
"Zlib",
]
exceptions = [
# TEMP: Pending legal review. Pulled transitively via `risc0-zkvm`
{ name = "downloader", version = "0.2.8", allow = ["LGPL-3.0-or-later"] },
{ name = "malachite", version = "0.4.22", allow = ["LGPL-3.0-only"] },
{ name = "malachite-base", version = "0.4.22", allow = ["LGPL-3.0-only"] },
{ name = "malachite-float", version = "0.4.22", allow = ["LGPL-3.0-only"] },
{ name = "malachite-nz", version = "0.4.22", allow = ["LGPL-3.0-only"] },
{ name = "malachite-q", version = "0.4.22", allow = ["LGPL-3.0-only"] },
{ name = "managed", version = "0.8.0", allow = ["0BSD"] },
]
private = { ignore = false }
unused-allowed-license = "deny"

1428
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -67,8 +67,8 @@ tokio = { version = "1.28.2", features = [
"fs",
] }
tokio-util = "0.7.18"
risc0-zkvm = { version = "3.0.3", features = ['std'] }
risc0-build = "3.0.3"
risc0-zkvm = { version = "3.0.5", features = ['std'] }
risc0-build = "3.0.5"
anyhow = "1.0.98"
num_cpus = "1.13.1"
openssl = { version = "0.10", features = ["vendored"] }

View File

@ -92,7 +92,7 @@ wallet account new private
# Output:
Generated new account with account_id Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF
With npk 6a2dfe433cf28e525aa0196d719be3c16146f7ee358ca39595323f94fde38f93
With ipk 03d59abf4bee974cc12ddb44641c19f0b5441fef39191f047c988c29a77252a577
With vpk 03d59abf4bee974cc12ddb44641c19f0b5441fef39191f047c988c29a77252a577
```
2. Create the token (Token B):

View File

@ -154,11 +154,11 @@ wallet account new private
# Output:
Generated new account with account_id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL
With npk e6366f79d026c8bd64ae6b3d601f0506832ec682ab54897f205fffe64ec0d951
With ipk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17
With vpk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17
```
> [!Tip]
> Focus on the account ID for now. The `npk` and `ipk` values are stored locally and used to build privacy-preserving transactions. The private account ID is derived from `npk`.
> Focus on the account ID for now. The `npk` and `vpk` values are stored locally and used to build privacy-preserving transactions. The private account ID is derived from `npk`.
Just like public accounts, new private accounts start out uninitialized:
@ -228,17 +228,17 @@ wallet account new private
# Output:
Generated new account with account_id Private/AukXPRBmrYVqoqEW2HTs7N3hvTn3qdNFDcxDHVr5hMm5
With npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e
With ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72
With vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72
```
> [!Tip]
> Ignore the private account ID here and use the `npk` and `ipk` values to send to a foreign private account.
> Ignore the private account ID here and use the `npk` and `vpk` values to send to a foreign private account.
```bash
wallet auth-transfer send \
--from Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \
--to-npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e \
--to-ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \
--to-vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \
--amount 3
```

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -97,7 +97,7 @@ _wallet_auth_transfer() {
'--from[Source account ID]:from_account:_wallet_account_ids' \
'--to[Destination account ID (for owned accounts)]:to_account:_wallet_account_ids' \
'--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
'--to-ipk[Destination viewing public key (for foreign private accounts)]:ipk:' \
'--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of native tokens to send]:amount:'
;;
esac
@ -164,7 +164,7 @@ _wallet_account() {
get)
_arguments \
'(-r --raw)'{-r,--raw}'[Get raw account data]' \
'(-k --keys)'{-k,--keys}'[Display keys (pk for public accounts, npk/ipk for private accounts)]' \
'(-k --keys)'{-k,--keys}'[Display keys (pk for public accounts, npk/vpk for private accounts)]' \
'(-a --account-id)'{-a,--account-id}'[Account ID to query]:account_id:_wallet_account_ids'
;;
list|ls)
@ -255,7 +255,7 @@ _wallet_token() {
'--from[Source holding account ID]:from_account:_wallet_account_ids' \
'--to[Destination holding account ID (for owned accounts)]:to_account:_wallet_account_ids' \
'--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
'--to-ipk[Destination viewing public key (for foreign private accounts)]:ipk:' \
'--to-vpk[Destination viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of tokens to send]:amount:'
;;
burn)
@ -269,7 +269,7 @@ _wallet_token() {
'--definition[Definition account ID]:definition_account:_wallet_account_ids' \
'--holder[Holder account ID (for owned accounts)]:holder_account:_wallet_account_ids' \
'--holder-npk[Holder nullifier public key (for foreign private accounts)]:npk:' \
'--holder-ipk[Holder viewing public key (for foreign private accounts)]:ipk:' \
'--holder-vpk[Holder viewing public key (for foreign private accounts)]:vpk:' \
'--amount[Amount of tokens to mint]:amount:'
;;
esac

View File

@ -29,40 +29,7 @@
],
"initial_commitments": [
{
"npk": [
63,
202,
178,
231,
183,
82,
237,
212,
216,
221,
215,
255,
153,
101,
177,
161,
254,
210,
128,
122,
54,
190,
230,
151,
183,
64,
225,
229,
113,
1,
228,
97
],
"npk": [13, 25, 40, 5, 198, 248, 210, 248, 237, 121, 124, 145, 186, 142, 253, 216, 236, 69, 193, 32, 166, 167, 49, 133, 172, 111, 159, 46, 84, 17, 157, 23],
"account": {
"program_owner": [
0,
@ -80,40 +47,7 @@
}
},
{
"npk": [
192,
251,
166,
243,
167,
236,
84,
249,
35,
136,
130,
172,
219,
225,
161,
139,
229,
89,
243,
125,
194,
213,
209,
30,
23,
174,
100,
244,
124,
74,
140,
47
],
"npk": [32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210, 143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165],
"account": {
"program_owner": [
0,

View File

@ -263,7 +263,7 @@ impl indexer_service_rpc::RpcServer for MockIndexerService {
.collect();
// Sort by block ID descending (most recent first)
account_txs.sort_by(|a, b| b.1.cmp(&a.1));
account_txs.sort_by_key(|b| std::cmp::Reverse(b.1));
let start = offset as usize;
if start >= account_txs.len() {

View File

@ -102,7 +102,7 @@ async fn amm_public() -> Result<()> {
from: format_public_account_id(supply_account_id_1),
to: Some(format_public_account_id(recipient_account_id_1)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 7,
};
@ -126,7 +126,7 @@ async fn amm_public() -> Result<()> {
from: format_public_account_id(supply_account_id_2),
to: Some(format_public_account_id(recipient_account_id_2)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 7,
};

View File

@ -26,7 +26,7 @@ async fn private_transfer_to_owned_account() -> Result<()> {
from: format_private_account_id(from),
to: Some(format_private_account_id(to)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -59,13 +59,13 @@ async fn private_transfer_to_foreign_account() -> Result<()> {
let from: AccountId = ctx.existing_private_accounts()[0];
let to_npk = NullifierPublicKey([42; 32]);
let to_npk_string = hex::encode(to_npk.0);
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let to_vpk = Secp256k1Point::from_scalar(to_npk.0);
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: format_private_account_id(from),
to: None,
to_npk: Some(to_npk_string),
to_ipk: Some(hex::encode(to_ipk.0)),
to_vpk: Some(hex::encode(to_vpk.0)),
amount: 100,
});
@ -113,7 +113,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> {
from: format_private_account_id(from),
to: Some(format_public_account_id(to)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -168,12 +168,12 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> {
.cloned()
.context("Failed to get private account")?;
// Send to this account using claiming path (using npk and ipk instead of account ID)
// Send to this account using claiming path (using npk and vpk instead of account ID)
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: format_private_account_id(from),
to: None,
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
});
@ -221,7 +221,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> {
from: format_public_account_id(from),
to: Some(format_private_account_id(to)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -256,14 +256,14 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> {
let to_npk = NullifierPublicKey([42; 32]);
let to_npk_string = hex::encode(to_npk.0);
let to_ipk = Secp256k1Point::from_scalar(to_npk.0);
let to_vpk = Secp256k1Point::from_scalar(to_npk.0);
let from: AccountId = ctx.existing_public_accounts()[0];
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: format_public_account_id(from),
to: None,
to_npk: Some(to_npk_string),
to_ipk: Some(hex::encode(to_ipk.0)),
to_vpk: Some(hex::encode(to_vpk.0)),
amount: 100,
});
@ -325,12 +325,12 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> {
.cloned()
.context("Failed to get private account")?;
// Send transfer using nullifier and incoming viewing public keys
// Send transfer using nullifier and viewing public keys
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
from: format_private_account_id(from),
to: None,
to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)),
to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)),
to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)),
amount: 100,
});

View File

@ -19,7 +19,7 @@ async fn successful_transfer_to_existing_account() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -72,7 +72,7 @@ pub async fn successful_transfer_to_new_account() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(new_persistent_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -108,7 +108,7 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 1000000,
});
@ -146,7 +146,7 @@ async fn two_consecutive_successful_transfers() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -178,7 +178,7 @@ async fn two_consecutive_successful_transfers() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});

View File

@ -12,7 +12,7 @@ use tokio::test;
use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand};
/// Timeout in milliseconds to reliably await for block finalization
const L2_TO_L1_TIMEOUT_MILLIS: u64 = 220000;
const L2_TO_L1_TIMEOUT_MILLIS: u64 = 300000;
#[test]
async fn indexer_test_run() -> Result<()> {
@ -45,6 +45,7 @@ async fn indexer_test_run() -> Result<()> {
}
#[test]
#[ignore = "Not reliable with current bedrock node"]
async fn indexer_block_batching() -> Result<()> {
let ctx = TestContext::new().await?;
@ -80,6 +81,7 @@ async fn indexer_block_batching() -> Result<()> {
}
#[test]
#[ignore = "Not reliable with current bedrock node"]
async fn indexer_state_consistency() -> Result<()> {
let mut ctx = TestContext::new().await?;
@ -87,7 +89,7 @@ async fn indexer_state_consistency() -> Result<()> {
from: format_public_account_id(ctx.existing_public_accounts()[0]),
to: Some(format_public_account_id(ctx.existing_public_accounts()[1])),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
@ -119,7 +121,7 @@ async fn indexer_state_consistency() -> Result<()> {
from: format_private_account_id(from),
to: Some(format_private_account_id(to)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});

View File

@ -50,7 +50,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_private_account_id(from),
to: Some(format_private_account_id(to_account_id1)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 100,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -60,7 +60,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_private_account_id(from),
to: Some(format_private_account_id(to_account_id2)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 101,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -96,7 +96,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_public_account_id(from),
to: Some(format_public_account_id(to_account_id3)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 102,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -106,7 +106,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_public_account_id(from),
to: Some(format_public_account_id(to_account_id4)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 103,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -169,7 +169,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_private_account_id(to_account_id1),
to: Some(format_private_account_id(to_account_id2)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 10,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
@ -178,7 +178,7 @@ async fn restore_keys_from_seed() -> Result<()> {
from: format_public_account_id(to_account_id3),
to: Some(format_public_account_id(to_account_id4)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: 11,
});
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;

View File

@ -115,7 +115,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
from: format_public_account_id(supply_account_id),
to: Some(format_public_account_id(recipient_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: transfer_amount,
};
@ -208,7 +208,7 @@ async fn create_and_transfer_public_token() -> Result<()> {
definition: format_public_account_id(definition_account_id),
holder: Some(format_public_account_id(recipient_account_id)),
holder_npk: None,
holder_ipk: None,
holder_vpk: None,
amount: mint_amount,
};
@ -343,7 +343,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> {
from: format_private_account_id(supply_account_id),
to: Some(format_private_account_id(recipient_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: transfer_amount,
};
@ -525,7 +525,7 @@ async fn create_token_with_private_definition() -> Result<()> {
definition: format_private_account_id(definition_account_id),
holder: Some(format_public_account_id(recipient_account_id_public)),
holder_npk: None,
holder_ipk: None,
holder_vpk: None,
amount: mint_amount_public,
};
@ -572,7 +572,7 @@ async fn create_token_with_private_definition() -> Result<()> {
definition: format_private_account_id(definition_account_id),
holder: Some(format_private_account_id(recipient_account_id_private)),
holder_npk: None,
holder_ipk: None,
holder_vpk: None,
amount: mint_amount_private,
};
@ -701,7 +701,7 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> {
from: format_private_account_id(supply_account_id),
to: Some(format_private_account_id(recipient_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: transfer_amount,
};
@ -819,7 +819,7 @@ async fn shielded_token_transfer() -> Result<()> {
from: format_public_account_id(supply_account_id),
to: Some(format_private_account_id(recipient_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: transfer_amount,
};
@ -933,7 +933,7 @@ async fn deshielded_token_transfer() -> Result<()> {
from: format_private_account_id(supply_account_id),
to: Some(format_public_account_id(recipient_account_id)),
to_npk: None,
to_ipk: None,
to_vpk: None,
amount: transfer_amount,
};
@ -1056,7 +1056,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> {
definition: format_private_account_id(definition_account_id),
holder: None,
holder_npk: Some(hex::encode(holder_keys.nullifer_public_key.0)),
holder_ipk: Some(hex::encode(holder_keys.incoming_viewing_public_key.0)),
holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)),
amount: mint_amount,
};

View File

@ -16,7 +16,7 @@ use nssa::{
use nssa_core::{
MembershipProof, NullifierPublicKey,
account::{AccountWithMetadata, data::Data},
encryption::IncomingViewingPublicKey,
encryption::ViewingPublicKey,
};
use tokio::test;
@ -192,8 +192,8 @@ impl TpsTestManager {
fn build_privacy_transaction() -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program();
let sender_nsk = [1; 32];
let sender_isk = [99; 32];
let sender_ipk = IncomingViewingPublicKey::from_scalar(sender_isk);
let sender_vsk = [99; 32];
let sender_vpk = ViewingPublicKey::from_scalar(sender_vsk);
let sender_npk = NullifierPublicKey::from(&sender_nsk);
let sender_pre = AccountWithMetadata::new(
Account {
@ -206,18 +206,18 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
AccountId::from(&sender_npk),
);
let recipient_nsk = [2; 32];
let recipient_isk = [99; 32];
let recipient_ipk = IncomingViewingPublicKey::from_scalar(recipient_isk);
let recipient_vsk = [99; 32];
let recipient_vpk = ViewingPublicKey::from_scalar(recipient_vsk);
let recipient_npk = NullifierPublicKey::from(&recipient_nsk);
let recipient_pre =
AccountWithMetadata::new(Account::default(), false, AccountId::from(&recipient_npk));
let eph_holder_from = EphemeralKeyHolder::new(&sender_npk);
let sender_ss = eph_holder_from.calculate_shared_secret_sender(&sender_ipk);
let sender_ss = eph_holder_from.calculate_shared_secret_sender(&sender_vpk);
let sender_epk = eph_holder_from.generate_ephemeral_public_key();
let eph_holder_to = EphemeralKeyHolder::new(&recipient_npk);
let recipient_ss = eph_holder_to.calculate_shared_secret_sender(&recipient_ipk);
let recipient_ss = eph_holder_to.calculate_shared_secret_sender(&recipient_vpk);
let recipient_epk = eph_holder_from.generate_ephemeral_public_key();
let balance_to_move: u128 = 1;
@ -246,8 +246,8 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
vec![],
vec![],
vec![
(sender_npk, sender_ipk, sender_epk),
(recipient_npk, recipient_ipk, recipient_epk),
(sender_npk, sender_vpk, sender_epk),
(recipient_npk, recipient_vpk, recipient_epk),
],
output,
)

View File

@ -2,6 +2,7 @@ use std::{
collections::HashSet,
ffi::{CStr, CString, c_char},
io::Write,
path::Path,
time::Duration,
};
@ -24,6 +25,11 @@ unsafe extern "C" {
password: *const c_char,
) -> *mut WalletHandle;
fn wallet_ffi_open(
config_path: *const c_char,
storage_path: *const c_char,
) -> *mut WalletHandle;
fn wallet_ffi_destroy(handle: *mut WalletHandle);
fn wallet_ffi_create_account_public(
@ -56,6 +62,12 @@ unsafe extern "C" {
out_account: *mut FfiAccount,
) -> error::WalletFfiError;
fn wallet_ffi_get_account_private(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_account: *mut FfiAccount,
) -> error::WalletFfiError;
fn wallet_ffi_free_account_data(account: *mut FfiAccount);
fn wallet_ffi_get_public_account_key(
@ -89,6 +101,30 @@ unsafe extern "C" {
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_transfer_shielded(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to_keys: *const FfiPrivateAccountKeys,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_transfer_deshielded(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to: *const FfiBytes32,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_transfer_private(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to_keys: *const FfiPrivateAccountKeys,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_free_transfer_result(result: *mut FfiTransferResult);
fn wallet_ffi_register_public_account(
@ -96,12 +132,29 @@ unsafe extern "C" {
account_id: *const FfiBytes32,
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_register_private_account(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_result: *mut FfiTransferResult,
) -> error::WalletFfiError;
fn wallet_ffi_save(handle: *mut WalletHandle) -> error::WalletFfiError;
fn wallet_ffi_sync_to_block(handle: *mut WalletHandle, block_id: u64) -> error::WalletFfiError;
fn wallet_ffi_get_current_block_height(
handle: *mut WalletHandle,
out_block_height: *mut u64,
) -> error::WalletFfiError;
}
fn new_wallet_ffi_with_test_context_config(ctx: &BlockingTestContext) -> *mut WalletHandle {
let tempdir = tempfile::tempdir().unwrap();
let config_path = tempdir.path().join("wallet_config.json");
let storage_path = tempdir.path().join("storage.json");
fn new_wallet_ffi_with_test_context_config(
ctx: &BlockingTestContext,
home: &Path,
) -> *mut WalletHandle {
let config_path = home.join("wallet_config.json");
let storage_path = home.join("storage.json");
let mut config = ctx.ctx().wallet().config().to_owned();
if let Some(config_overrides) = ctx.ctx().wallet().config_overrides().clone() {
config.apply_overrides(config_overrides);
@ -161,6 +214,15 @@ fn new_wallet_rust_with_default_config(password: &str) -> WalletCore {
.unwrap()
}
fn load_existing_ffi_wallet(home: &Path) -> *mut WalletHandle {
let config_path = home.join("wallet_config.json");
let storage_path = home.join("storage.json");
let config_path = CString::new(config_path.to_str().unwrap()).unwrap();
let storage_path = CString::new(storage_path.to_str().unwrap()).unwrap();
unsafe { wallet_ffi_open(config_path.as_ptr(), storage_path.as_ptr()) }
}
#[test]
fn test_wallet_ffi_create_public_accounts() {
let password = "password_for_tests";
@ -232,6 +294,56 @@ fn test_wallet_ffi_create_private_accounts() {
assert_eq!(new_private_account_ids_ffi, new_private_account_ids_rust)
}
#[test]
fn test_wallet_ffi_save_and_load_persistent_storage() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let mut out_private_account_id = FfiBytes32::from_bytes([0; 32]);
let home = tempfile::tempdir().unwrap();
// Create a private account with the wallet FFI and save it
unsafe {
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_private_account_id) as *mut FfiBytes32,
);
wallet_ffi_save(wallet_ffi_handle);
wallet_ffi_destroy(wallet_ffi_handle);
}
let private_account_keys = unsafe {
let wallet_ffi_handle = load_existing_ffi_wallet(home.path());
let mut private_account = FfiAccount::default();
let result = wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_private_account_id) as *const FfiBytes32,
(&mut private_account) as *mut FfiAccount,
);
assert_eq!(result, error::WalletFfiError::Success);
let mut out_keys = FfiPrivateAccountKeys::default();
let result = wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_private_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
);
assert_eq!(result, error::WalletFfiError::Success);
wallet_ffi_destroy(wallet_ffi_handle);
out_keys
};
assert_eq!(
nssa::AccountId::from(&private_account_keys.npk()),
out_private_account_id.into()
);
Ok(())
}
#[test]
fn test_wallet_ffi_list_accounts() {
@ -326,7 +438,8 @@ fn test_wallet_ffi_list_accounts() {
fn test_wallet_ffi_get_balance_public() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
@ -354,7 +467,8 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> {
fn test_wallet_ffi_get_account_public() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let mut out_account = FfiAccount::default();
let account: Account = unsafe {
@ -385,11 +499,48 @@ fn test_wallet_ffi_get_account_public() -> Result<()> {
Ok(())
}
#[test]
fn test_wallet_ffi_get_account_private() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let mut out_account = FfiAccount::default();
let account: Account = unsafe {
let ffi_account_id = FfiBytes32::from(&account_id);
let _result = wallet_ffi_get_account_private(
wallet_ffi_handle,
(&ffi_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
(&out_account).try_into().unwrap()
};
assert_eq!(
account.program_owner,
Program::authenticated_transfer_program().id()
);
assert_eq!(account.balance, 10000);
assert!(account.data.is_empty());
assert_eq!(account.nonce, 0);
unsafe {
wallet_ffi_free_account_data((&mut out_account) as *mut FfiAccount);
wallet_ffi_destroy(wallet_ffi_handle);
}
info!("Successfully retrieved account with correct details");
Ok(())
}
#[test]
fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_public_accounts()[0];
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let mut out_key = FfiPublicAccountKey::default();
let key: PublicKey = unsafe {
@ -426,7 +577,8 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> {
fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
let ctx = BlockingTestContext::new()?;
let account_id: AccountId = ctx.ctx().existing_private_accounts()[0];
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let mut keys = FfiPrivateAccountKeys::default();
unsafe {
@ -448,10 +600,10 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> {
.0;
let expected_npk = &key_chain.nullifer_public_key;
let expected_ivk = &key_chain.incoming_viewing_public_key;
let expected_vpk = &key_chain.viewing_public_key;
assert_eq!(&keys.npk(), expected_npk);
assert_eq!(&keys.ivk().unwrap(), expected_ivk);
assert_eq!(&keys.vpk().unwrap(), expected_vpk);
unsafe {
wallet_ffi_free_private_account_keys((&mut keys) as *mut FfiPrivateAccountKeys);
@ -504,7 +656,8 @@ fn test_wallet_ffi_base58_to_account_id() {
#[test]
fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
// Create a new uninitialized public account
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
@ -563,10 +716,81 @@ fn test_wallet_ffi_init_public_account_auth_transfer() -> Result<()> {
Ok(())
}
#[test]
fn test_wallet_ffi_init_private_account_auth_transfer() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
// Create a new uninitialized public account
let mut out_account_id = FfiBytes32::from_bytes([0; 32]);
unsafe {
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
}
// Check its program owner is the default program id
let account: Account = unsafe {
let mut out_account = FfiAccount::default();
wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
(&out_account).try_into().unwrap()
};
assert_eq!(account.program_owner, DEFAULT_PROGRAM_ID);
// Call the init funciton
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_register_private_account(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut transfer_result) as *mut FfiTransferResult,
);
}
info!("Waiting for next block creation");
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
// Check that the program owner is now the authenticated transfer program
let account: Account = unsafe {
let mut out_account = FfiAccount::default();
let _result = wallet_ffi_get_account_private(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_account) as *mut FfiAccount,
);
(&out_account).try_into().unwrap()
};
assert_eq!(
account.program_owner,
Program::authenticated_transfer_program().id()
);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_destroy(wallet_ffi_handle);
}
Ok(())
}
#[test]
fn test_wallet_ffi_transfer_public() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx);
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let from: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[0]).into();
let to: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[1]).into();
let amount: [u8; 16] = 100u128.to_le_bytes();
@ -617,3 +841,220 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
Ok(())
}
#[test]
fn test_wallet_ffi_transfer_shielded() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let from: FfiBytes32 = (&ctx.ctx().existing_public_accounts()[0]).into();
let (to, to_keys) = unsafe {
let mut out_account_id = FfiBytes32::default();
let mut out_keys = FfiPrivateAccountKeys::default();
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
);
(out_account_id, out_keys)
};
let amount: [u8; 16] = 100u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_shielded(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to_keys) as *const FfiPrivateAccountKeys,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
);
}
info!("Waiting for next block creation");
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
true,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
let to_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
false,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
assert_eq!(from_balance, 9900);
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_destroy(wallet_ffi_handle);
}
Ok(())
}
#[test]
fn test_wallet_ffi_transfer_deshielded() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let from: FfiBytes32 = (&ctx.ctx().existing_private_accounts()[0]).into();
let to = FfiBytes32::from_bytes([37; 32]);
let amount: [u8; 16] = 100u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_deshielded(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to) as *const FfiBytes32,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
);
}
info!("Waiting for next block creation");
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
false,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
let to_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
true,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
assert_eq!(from_balance, 9900);
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_destroy(wallet_ffi_handle);
}
Ok(())
}
#[test]
fn test_wallet_ffi_transfer_private() -> Result<()> {
let ctx = BlockingTestContext::new().unwrap();
let home = tempfile::tempdir().unwrap();
let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path());
let from: FfiBytes32 = (&ctx.ctx().existing_private_accounts()[0]).into();
let (to, to_keys) = unsafe {
let mut out_account_id = FfiBytes32::default();
let mut out_keys = FfiPrivateAccountKeys::default();
wallet_ffi_create_account_private(
wallet_ffi_handle,
(&mut out_account_id) as *mut FfiBytes32,
);
wallet_ffi_get_private_account_keys(
wallet_ffi_handle,
(&out_account_id) as *const FfiBytes32,
(&mut out_keys) as *mut FfiPrivateAccountKeys,
);
(out_account_id, out_keys)
};
let amount: [u8; 16] = 100u128.to_le_bytes();
let mut transfer_result = FfiTransferResult::default();
unsafe {
wallet_ffi_transfer_private(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
(&to_keys) as *const FfiPrivateAccountKeys,
(&amount) as *const [u8; 16],
(&mut transfer_result) as *mut FfiTransferResult,
);
}
info!("Waiting for next block creation");
std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS));
// Sync private account local storage with onchain encrypted state
unsafe {
let mut current_height = 0;
wallet_ffi_get_current_block_height(wallet_ffi_handle, (&mut current_height) as *mut u64);
wallet_ffi_sync_to_block(wallet_ffi_handle, current_height);
};
let from_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&from) as *const FfiBytes32,
false,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
let to_balance = unsafe {
let mut out_balance: [u8; 16] = [0; 16];
let _result = wallet_ffi_get_balance(
wallet_ffi_handle,
(&to) as *const FfiBytes32,
false,
(&mut out_balance) as *mut [u8; 16],
);
u128::from_le_bytes(out_balance)
};
assert_eq!(from_balance, 9900);
assert_eq!(to_balance, 100);
unsafe {
wallet_ffi_free_transfer_result((&mut transfer_result) as *mut FfiTransferResult);
wallet_ffi_destroy(wallet_ffi_handle);
}
Ok(())
}

View File

@ -1,6 +1,6 @@
use nssa_core::{
NullifierPublicKey, SharedSecretKey,
encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey},
encryption::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey},
};
use rand::{RngCore, rngs::OsRng};
use sha2::Digest;
@ -13,12 +13,12 @@ pub struct EphemeralKeyHolder {
}
pub fn produce_one_sided_shared_secret_receiver(
ipk: &IncomingViewingPublicKey,
vpk: &ViewingPublicKey,
) -> (SharedSecretKey, EphemeralPublicKey) {
let mut esk = [0; 32];
OsRng.fill_bytes(&mut esk);
(
SharedSecretKey::new(&esk, ipk),
SharedSecretKey::new(&esk, vpk),
EphemeralPublicKey::from_scalar(esk),
)
}
@ -42,11 +42,8 @@ impl EphemeralKeyHolder {
pub fn calculate_shared_secret_sender(
&self,
receiver_incoming_viewing_public_key: &IncomingViewingPublicKey,
receiver_viewing_public_key: &ViewingPublicKey,
) -> SharedSecretKey {
SharedSecretKey::new(
&self.ephemeral_secret_key,
receiver_incoming_viewing_public_key,
)
SharedSecretKey::new(&self.ephemeral_secret_key, receiver_viewing_public_key)
}
}

View File

@ -1,5 +1,5 @@
use k256::{Scalar, elliptic_curve::PrimeField};
use nssa_core::encryption::IncomingViewingPublicKey;
use nssa_core::{NullifierPublicKey, encryption::ViewingPublicKey};
use serde::{Deserialize, Serialize};
use crate::key_management::{
@ -18,7 +18,7 @@ pub struct ChildKeysPrivate {
impl KeyNode for ChildKeysPrivate {
fn root(seed: [u8; 64]) -> Self {
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_priv");
let hash_value = hmac_sha512::HMAC::mac(seed, b"LEE_master_priv");
let ssk = SecretSpendingKey(
*hash_value
@ -29,23 +29,21 @@ impl KeyNode for ChildKeysPrivate {
.last_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get last 32");
let nsk = ssk.generate_nullifier_secret_key();
let isk = ssk.generate_incoming_viewing_secret_key();
let ovk = ssk.generate_outgoing_viewing_secret_key();
let nsk = ssk.generate_nullifier_secret_key(None);
let vsk = ssk.generate_viewing_secret_key(None);
let npk = (&nsk).into();
let ipk = IncomingViewingPublicKey::from_scalar(isk);
let npk = NullifierPublicKey::from(&nsk);
let vpk = ViewingPublicKey::from_scalar(vsk);
Self {
value: (
KeyChain {
secret_spending_key: ssk,
nullifer_public_key: npk,
incoming_viewing_public_key: ipk,
viewing_public_key: vpk,
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: nsk,
incoming_viewing_secret_key: isk,
outgoing_viewing_secret_key: ovk,
viewing_secret_key: vsk,
},
},
nssa::Account::default(),
@ -56,27 +54,14 @@ impl KeyNode for ChildKeysPrivate {
}
fn nth_child(&self, cci: u32) -> Self {
let parent_pt = Scalar::from_repr(
self.value
.0
.private_key_holder
.outgoing_viewing_secret_key
.into(),
)
.expect("Key generated as scalar, must be valid representation")
+ Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into())
let parent_pt =
Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into())
.expect("Key generated as scalar, must be valid representation")
* Scalar::from_repr(
self.value
.0
.private_key_holder
.incoming_viewing_secret_key
.into(),
)
.expect("Key generated as scalar, must be valid representation");
* Scalar::from_repr(self.value.0.private_key_holder.viewing_secret_key.into())
.expect("Key generated as scalar, must be valid representation");
let mut input = vec![];
input.extend_from_slice(b"NSSA_seed_priv");
input.extend_from_slice(b"LEE_seed_priv");
input.extend_from_slice(&parent_pt.to_bytes());
input.extend_from_slice(&cci.to_le_bytes());
@ -91,23 +76,21 @@ impl KeyNode for ChildKeysPrivate {
.last_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get last 32");
let nsk = ssk.generate_nullifier_secret_key();
let isk = ssk.generate_incoming_viewing_secret_key();
let ovk = ssk.generate_outgoing_viewing_secret_key();
let nsk = ssk.generate_nullifier_secret_key(Some(cci));
let vsk = ssk.generate_viewing_secret_key(Some(cci));
let npk = (&nsk).into();
let ipk = IncomingViewingPublicKey::from_scalar(isk);
let npk = NullifierPublicKey::from(&nsk);
let vpk = ViewingPublicKey::from_scalar(vsk);
Self {
value: (
KeyChain {
secret_spending_key: ssk,
nullifer_public_key: npk,
incoming_viewing_public_key: ipk,
viewing_public_key: vpk,
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: nsk,
incoming_viewing_secret_key: isk,
outgoing_viewing_secret_key: ovk,
viewing_secret_key: vsk,
},
},
nssa::Account::default(),
@ -144,120 +127,98 @@ impl<'a> From<&'a mut ChildKeysPrivate> for &'a mut (KeyChain, nssa::Account) {
#[cfg(test)]
mod tests {
use nssa_core::{NullifierPublicKey, NullifierSecretKey};
use super::*;
use crate::key_management::{self, secret_holders::ViewingSecretKey};
#[test]
fn test_keys_deterministic_generation() {
let root_keys = ChildKeysPrivate::root([42; 64]);
let child_keys = root_keys.nth_child(5);
fn test_master_key_generation() {
let seed: [u8; 64] = [
252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255,
49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18,
129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56,
114, 39, 38, 118, 197, 205, 225,
];
assert_eq!(root_keys.cci, None);
assert_eq!(child_keys.cci, Some(5));
let keys = ChildKeysPrivate::root(seed);
assert_eq!(
root_keys.value.0.secret_spending_key.0,
[
249, 83, 253, 32, 174, 204, 185, 44, 253, 167, 61, 92, 128, 5, 152, 4, 220, 21, 88,
84, 167, 180, 154, 249, 44, 77, 33, 136, 59, 131, 203, 152
]
);
assert_eq!(
child_keys.value.0.secret_spending_key.0,
[
16, 242, 229, 242, 252, 158, 153, 210, 234, 120, 70, 85, 83, 196, 5, 53, 28, 26,
187, 230, 22, 193, 146, 232, 237, 3, 166, 184, 122, 1, 233, 93
]
);
let expected_ssk: SecretSpendingKey = key_management::secret_holders::SecretSpendingKey([
246, 79, 26, 124, 135, 95, 52, 51, 201, 27, 48, 194, 2, 144, 51, 219, 245, 128, 139,
222, 42, 195, 105, 33, 115, 97, 186, 0, 97, 14, 218, 191,
]);
assert_eq!(
root_keys.value.0.private_key_holder.nullifier_secret_key,
[
38, 195, 52, 182, 16, 66, 167, 156, 9, 14, 65, 100, 17, 93, 166, 71, 27, 148, 93,
85, 116, 109, 130, 8, 195, 222, 159, 214, 141, 41, 124, 57
]
);
assert_eq!(
child_keys.value.0.private_key_holder.nullifier_secret_key,
[
215, 46, 2, 151, 174, 60, 86, 154, 5, 3, 175, 245, 12, 176, 220, 58, 250, 118, 236,
49, 254, 221, 229, 58, 40, 1, 170, 145, 175, 108, 23, 170
]
);
let expected_ccc = [
56, 114, 70, 249, 67, 169, 206, 9, 192, 11, 180, 168, 149, 129, 42, 95, 43, 157, 130,
111, 13, 5, 195, 75, 20, 255, 162, 85, 40, 251, 8, 168,
];
assert_eq!(
root_keys
.value
.0
.private_key_holder
.incoming_viewing_secret_key,
[
153, 161, 15, 34, 96, 184, 165, 165, 27, 244, 155, 40, 70, 5, 241, 133, 78, 40, 61,
118, 48, 148, 226, 5, 97, 18, 201, 128, 82, 248, 163, 72
]
);
assert_eq!(
child_keys
.value
.0
.private_key_holder
.incoming_viewing_secret_key,
[
192, 155, 55, 43, 164, 115, 71, 145, 227, 225, 21, 57, 55, 12, 226, 44, 10, 103,
39, 73, 230, 173, 60, 69, 69, 122, 110, 241, 164, 3, 192, 57
]
);
let expected_nsk: NullifierSecretKey = [
154, 102, 103, 5, 34, 235, 227, 13, 22, 182, 226, 11, 7, 67, 110, 162, 99, 193, 174,
34, 234, 19, 222, 2, 22, 12, 163, 252, 88, 11, 0, 163,
];
assert_eq!(
root_keys
.value
.0
.private_key_holder
.outgoing_viewing_secret_key,
[
205, 87, 71, 129, 90, 242, 217, 200, 140, 252, 124, 46, 207, 7, 33, 156, 83, 166,
150, 81, 98, 131, 182, 156, 110, 92, 78, 140, 125, 218, 152, 154
]
);
assert_eq!(
child_keys
.value
.0
.private_key_holder
.outgoing_viewing_secret_key,
[
131, 202, 219, 172, 219, 29, 48, 120, 226, 209, 209, 10, 216, 173, 48, 167, 233,
17, 35, 155, 30, 217, 176, 120, 72, 146, 250, 226, 165, 178, 255, 90
]
);
let expected_npk: NullifierPublicKey = nssa_core::NullifierPublicKey([
7, 123, 125, 191, 233, 183, 201, 4, 20, 214, 155, 210, 45, 234, 27, 240, 194, 111, 97,
247, 155, 113, 122, 246, 192, 0, 70, 61, 76, 71, 70, 2,
]);
let expected_vsk: ViewingSecretKey = [
155, 90, 54, 75, 228, 130, 68, 201, 129, 251, 180, 195, 250, 64, 34, 230, 241, 204,
216, 50, 149, 156, 10, 67, 208, 74, 9, 10, 47, 59, 50, 202,
];
assert_eq!(
root_keys.value.0.nullifer_public_key.0,
[
65, 176, 149, 243, 192, 45, 216, 177, 169, 56, 229, 7, 28, 66, 204, 87, 109, 83,
152, 64, 14, 188, 179, 210, 147, 60, 22, 251, 203, 70, 89, 215
]
);
assert_eq!(
child_keys.value.0.nullifer_public_key.0,
[
69, 104, 130, 115, 48, 134, 19, 188, 67, 148, 163, 54, 155, 237, 57, 27, 136, 228,
111, 233, 205, 158, 149, 31, 84, 11, 241, 176, 243, 12, 138, 249
]
);
let expected_vpk_as_bytes: [u8; 33] = [
2, 191, 99, 102, 114, 40, 131, 109, 166, 8, 222, 186, 107, 29, 156, 106, 206, 96, 127,
80, 170, 66, 217, 79, 38, 80, 11, 74, 147, 123, 221, 159, 166,
];
assert_eq!(
root_keys.value.0.incoming_viewing_public_key.0,
&[
3, 174, 56, 136, 244, 179, 18, 122, 38, 220, 36, 50, 200, 41, 104, 167, 70, 18, 60,
202, 93, 193, 29, 16, 125, 252, 96, 51, 199, 152, 47, 233, 178
]
);
assert_eq!(
child_keys.value.0.incoming_viewing_public_key.0,
&[
3, 18, 202, 246, 79, 141, 169, 51, 55, 202, 120, 169, 244, 201, 156, 162, 216, 115,
126, 53, 46, 94, 235, 125, 114, 178, 215, 81, 171, 93, 93, 88, 117
]
);
assert!(expected_ssk == keys.value.0.secret_spending_key);
assert!(expected_ccc == keys.ccc);
assert!(expected_nsk == keys.value.0.private_key_holder.nullifier_secret_key);
assert!(expected_npk == keys.value.0.nullifer_public_key);
assert!(expected_vsk == keys.value.0.private_key_holder.viewing_secret_key);
assert!(expected_vpk_as_bytes == keys.value.0.viewing_public_key.to_bytes());
}
#[test]
fn test_child_keys_generation() {
let seed: [u8; 64] = [
252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255,
49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18,
129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56,
114, 39, 38, 118, 197, 205, 225,
];
let root_node = ChildKeysPrivate::root(seed);
let child_node = ChildKeysPrivate::nth_child(&root_node, 42u32);
let expected_ccc: [u8; 32] = [
145, 59, 225, 32, 54, 168, 14, 45, 60, 253, 57, 202, 31, 86, 142, 234, 51, 57, 154, 88,
132, 200, 92, 191, 220, 144, 42, 184, 108, 35, 226, 146,
];
let expected_nsk: NullifierSecretKey = [
19, 100, 119, 73, 191, 225, 234, 219, 129, 88, 40, 229, 63, 225, 189, 136, 69, 172,
221, 186, 147, 83, 150, 207, 70, 17, 228, 70, 113, 87, 227, 31,
];
let expected_npk: NullifierPublicKey = nssa_core::NullifierPublicKey([
133, 235, 223, 151, 12, 69, 26, 222, 60, 125, 235, 125, 167, 212, 201, 168, 101, 242,
111, 239, 1, 228, 12, 252, 146, 53, 75, 17, 187, 255, 122, 181,
]);
let expected_vsk: ViewingSecretKey = [
218, 219, 193, 132, 160, 6, 178, 194, 139, 248, 199, 81, 17, 133, 37, 201, 58, 104, 49,
222, 187, 46, 156, 93, 14, 118, 209, 243, 38, 101, 77, 45,
];
let expected_vpk_as_bytes: [u8; 33] = [
3, 164, 65, 167, 88, 167, 179, 51, 159, 27, 241, 174, 77, 174, 142, 106, 128, 96, 69,
74, 117, 231, 42, 193, 235, 153, 206, 116, 102, 7, 101, 192, 45,
];
assert!(expected_ccc == child_node.ccc);
assert!(expected_nsk == child_node.value.0.private_key_holder.nullifier_secret_key);
assert!(expected_npk == child_node.value.0.nullifer_public_key);
assert!(expected_vsk == child_node.value.0.private_key_holder.viewing_secret_key);
assert!(expected_vpk_as_bytes == child_node.value.0.viewing_public_key.to_bytes());
}
}

View File

@ -1,6 +1,6 @@
use nssa_core::{
NullifierPublicKey, SharedSecretKey,
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
encryption::{EphemeralPublicKey, ViewingPublicKey},
};
use secret_holders::{PrivateKeyHolder, SecretSpendingKey, SeedHolder};
use serde::{Deserialize, Serialize};
@ -17,7 +17,7 @@ pub struct KeyChain {
pub secret_spending_key: SecretSpendingKey,
pub private_key_holder: PrivateKeyHolder,
pub nullifer_public_key: NullifierPublicKey,
pub incoming_viewing_public_key: IncomingViewingPublicKey,
pub viewing_public_key: ViewingPublicKey,
}
impl KeyChain {
@ -27,16 +27,16 @@ impl KeyChain {
let seed_holder = SeedHolder::new_os_random();
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder(None);
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
let incoming_viewing_public_key = private_key_holder.generate_incoming_viewing_public_key();
let viewing_public_key = private_key_holder.generate_viewing_public_key();
Self {
secret_spending_key,
private_key_holder,
nullifer_public_key,
incoming_viewing_public_key,
viewing_public_key,
}
}
@ -46,16 +46,16 @@ impl KeyChain {
let seed_holder = SeedHolder::new_mnemonic(passphrase);
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder(None);
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
let incoming_viewing_public_key = private_key_holder.generate_incoming_viewing_public_key();
let viewing_public_key = private_key_holder.generate_viewing_public_key();
Self {
secret_spending_key,
private_key_holder,
nullifer_public_key,
incoming_viewing_public_key,
viewing_public_key,
}
}
@ -64,9 +64,7 @@ impl KeyChain {
ephemeral_public_key_sender: EphemeralPublicKey,
) -> SharedSecretKey {
SharedSecretKey::new(
&self
.secret_spending_key
.generate_incoming_viewing_secret_key(),
&self.secret_spending_key.generate_viewing_secret_key(None),
&ephemeral_public_key_sender,
)
}
@ -112,10 +110,10 @@ mod tests {
let seed_holder = SeedHolder::new_os_random();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_private_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_private_key_holder(None);
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_incoming_viewing_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
let pub_account_signing_key = nssa::PrivateKey::new_os_random();

View File

@ -2,7 +2,7 @@ use bip39::Mnemonic;
use common::HashType;
use nssa_core::{
NullifierPublicKey, NullifierSecretKey,
encryption::{IncomingViewingPublicKey, Scalar},
encryption::{Scalar, ViewingPublicKey},
};
use rand::{RngCore, rngs::OsRng};
use serde::{Deserialize, Serialize};
@ -18,20 +18,18 @@ pub struct SeedHolder {
pub(crate) seed: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
/// Secret spending key object. Can produce `PrivateKeyHolder` objects.
pub struct SecretSpendingKey(pub(crate) [u8; 32]);
pub type IncomingViewingSecretKey = Scalar;
pub type OutgoingViewingSecretKey = Scalar;
pub type ViewingSecretKey = Scalar;
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Private key holder. Produces public keys. Can produce account_id. Can produce shared secret for
/// recepient.
pub struct PrivateKeyHolder {
pub nullifier_secret_key: NullifierSecretKey,
pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey,
pub outgoing_viewing_secret_key: OutgoingViewingSecretKey,
pub(crate) viewing_secret_key: ViewingSecretKey,
}
impl SeedHolder {
@ -75,44 +73,49 @@ impl SeedHolder {
}
impl SecretSpendingKey {
pub fn generate_nullifier_secret_key(&self) -> NullifierSecretKey {
let mut hasher = sha2::Sha256::new();
pub fn generate_nullifier_secret_key(&self, index: Option<u32>) -> NullifierSecretKey {
let index = match index {
None => 0u32,
_ => index.expect("Expect a valid u32"),
};
hasher.update("NSSA_keys");
const PREFIX: &[u8; 8] = b"LEE/keys";
const SUFFIX_1: &[u8; 1] = &[1];
const SUFFIX_2: &[u8; 19] = &[0; 19];
let mut hasher = sha2::Sha256::new();
hasher.update(PREFIX);
hasher.update(self.0);
hasher.update([1u8]);
hasher.update([0u8; 22]);
hasher.update(SUFFIX_1);
hasher.update(index.to_le_bytes());
hasher.update(SUFFIX_2);
<NullifierSecretKey>::from(hasher.finalize_fixed())
}
pub fn generate_incoming_viewing_secret_key(&self) -> IncomingViewingSecretKey {
let mut hasher = sha2::Sha256::new();
pub fn generate_viewing_secret_key(&self, index: Option<u32>) -> ViewingSecretKey {
let index = match index {
None => 0u32,
_ => index.expect("Expect a valid u32"),
};
const PREFIX: &[u8; 8] = b"LEE/keys";
const SUFFIX_1: &[u8; 1] = &[2];
const SUFFIX_2: &[u8; 19] = &[0; 19];
hasher.update("NSSA_keys");
let mut hasher = sha2::Sha256::new();
hasher.update(PREFIX);
hasher.update(self.0);
hasher.update([2u8]);
hasher.update([0u8; 22]);
hasher.update(SUFFIX_1);
hasher.update(index.to_le_bytes());
hasher.update(SUFFIX_2);
hasher.finalize_fixed().into()
}
pub fn generate_outgoing_viewing_secret_key(&self) -> OutgoingViewingSecretKey {
let mut hasher = sha2::Sha256::new();
hasher.update("NSSA_keys");
hasher.update(self.0);
hasher.update([3u8]);
hasher.update([0u8; 22]);
hasher.finalize_fixed().into()
}
pub fn produce_private_key_holder(&self) -> PrivateKeyHolder {
pub fn produce_private_key_holder(&self, index: Option<u32>) -> PrivateKeyHolder {
PrivateKeyHolder {
nullifier_secret_key: self.generate_nullifier_secret_key(),
incoming_viewing_secret_key: self.generate_incoming_viewing_secret_key(),
outgoing_viewing_secret_key: self.generate_outgoing_viewing_secret_key(),
nullifier_secret_key: self.generate_nullifier_secret_key(index),
viewing_secret_key: self.generate_viewing_secret_key(index),
}
}
}
@ -122,8 +125,8 @@ impl PrivateKeyHolder {
(&self.nullifier_secret_key).into()
}
pub fn generate_incoming_viewing_public_key(&self) -> IncomingViewingPublicKey {
IncomingViewingPublicKey::from_scalar(self.incoming_viewing_secret_key)
pub fn generate_viewing_public_key(&self) -> ViewingPublicKey {
ViewingPublicKey::from_scalar(self.viewing_secret_key)
}
}
@ -131,6 +134,7 @@ impl PrivateKeyHolder {
mod tests {
use super::*;
// TODO? are these necessary?
#[test]
fn seed_generation_test() {
let seed_holder = SeedHolder::new_os_random();
@ -155,18 +159,7 @@ mod tests {
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let _ = top_secret_key_holder.generate_incoming_viewing_secret_key();
}
#[test]
fn ovs_generation_test() {
let seed_holder = SeedHolder::new_os_random();
assert_eq!(seed_holder.seed.len(), 64);
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let _ = top_secret_key_holder.generate_outgoing_viewing_secret_key();
let _ = top_secret_key_holder.generate_viewing_secret_key(None);
}
#[test]

View File

@ -33,3 +33,4 @@ test-case = "3.3.1"
[features]
default = []
prove = ["risc0-zkvm/prove"]

View File

@ -159,6 +159,7 @@ mod tests {
assert_eq!(new_acc_with_metadata.account_id, fingerprint);
}
#[cfg(feature = "host")]
#[test]
fn parse_valid_account_id() {
let base58_str = "11111111111111111111111111111111";
@ -166,6 +167,7 @@ mod tests {
assert_eq!(account_id.value, [0u8; 32]);
}
#[cfg(feature = "host")]
#[test]
fn parse_invalid_base58() {
let base58_str = "00".repeat(32); // invalid base58 chars
@ -173,6 +175,7 @@ mod tests {
assert!(matches!(result, AccountIdError::InvalidBase58(_)));
}
#[cfg(feature = "host")]
#[test]
fn parse_wrong_length_short() {
let base58_str = "11".repeat(31); // 62 chars = 31 bytes
@ -180,6 +183,7 @@ mod tests {
assert!(matches!(result, AccountIdError::InvalidLength(_)));
}
#[cfg(feature = "host")]
#[test]
fn parse_wrong_length_long() {
let base58_str = "11".repeat(33); // 66 chars = 33 bytes

View File

@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
pub mod shared_key_derivation;
#[cfg(feature = "host")]
pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey};
pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey};
use crate::{Commitment, account::Account};

View File

@ -28,7 +28,7 @@ impl Secp256k1Point {
pub type EphemeralSecretKey = Scalar;
pub type EphemeralPublicKey = Secp256k1Point;
pub type IncomingViewingPublicKey = Secp256k1Point;
pub type ViewingPublicKey = Secp256k1Point;
impl From<&EphemeralSecretKey> for EphemeralPublicKey {
fn from(value: &EphemeralSecretKey) -> Self {
Secp256k1Point::from_scalar(*value)

View File

@ -10,7 +10,8 @@ pub struct NullifierPublicKey(pub [u8; 32]);
impl From<&NullifierPublicKey> for AccountId {
fn from(value: &NullifierPublicKey) -> Self {
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Private/\x00\x00\x00";
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] =
b"/LEE/v0.3/AccountId/Private/\x00\x00\x00\x00";
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
@ -28,9 +29,9 @@ impl AsRef<[u8]> for NullifierPublicKey {
impl From<&NullifierSecretKey> for NullifierPublicKey {
fn from(value: &NullifierSecretKey) -> Self {
let mut bytes = Vec::new();
const PREFIX: &[u8; 9] = b"NSSA_keys";
const PREFIX: &[u8; 8] = b"LEE/keys";
const SUFFIX_1: &[u8; 1] = &[7];
const SUFFIX_2: &[u8; 22] = &[0; 22];
const SUFFIX_2: &[u8; 23] = &[0; 23];
bytes.extend_from_slice(PREFIX);
bytes.extend_from_slice(value);
bytes.extend_from_slice(SUFFIX_1);
@ -102,8 +103,8 @@ mod tests {
196, 134, 22, 224, 211, 237, 120, 136, 225, 188, 220, 249, 28,
];
let expected_npk = NullifierPublicKey([
202, 120, 42, 189, 194, 218, 78, 244, 31, 6, 108, 169, 29, 61, 22, 221, 69, 138, 197,
161, 241, 39, 142, 242, 242, 50, 188, 201, 99, 28, 176, 238,
78, 20, 20, 5, 177, 198, 233, 100, 175, 134, 174, 200, 24, 205, 68, 215, 130, 74, 35,
54, 154, 184, 219, 42, 168, 106, 126, 147, 133, 244, 18, 218,
]);
let npk = NullifierPublicKey::from(&nsk);
assert_eq!(npk, expected_npk);
@ -117,8 +118,8 @@ mod tests {
];
let npk = NullifierPublicKey::from(&nsk);
let expected_account_id = AccountId::new([
18, 153, 225, 78, 35, 214, 212, 205, 152, 83, 18, 246, 69, 41, 20, 217, 85, 1, 108, 7,
87, 133, 181, 53, 247, 221, 174, 12, 112, 194, 34, 121,
139, 72, 194, 222, 215, 187, 147, 56, 55, 35, 222, 205, 156, 12, 204, 227, 166, 44, 30,
81, 186, 14, 167, 234, 28, 236, 32, 213, 125, 251, 193, 233,
]);
let account_id = AccountId::from(&npk);

View File

@ -223,7 +223,7 @@ mod tests {
let expected_sender_pre = sender.clone();
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk());
let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.vpk());
let (output, proof) = execute_and_prove(
vec![sender, recipient],
@ -316,10 +316,10 @@ mod tests {
];
let esk_1 = [3; 32];
let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk());
let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.vpk());
let esk_2 = [5; 32];
let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk());
let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.vpk());
let (output, proof) = execute_and_prove(
vec![sender_pre.clone(), recipient],

View File

@ -2,7 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use nssa_core::{
Commitment, CommitmentSetDigest, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitOutput,
account::{Account, Nonce},
encryption::{Ciphertext, EphemeralPublicKey, IncomingViewingPublicKey},
encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey},
};
use sha2::{Digest, Sha256};
@ -21,10 +21,10 @@ impl EncryptedAccountData {
fn new(
ciphertext: Ciphertext,
npk: NullifierPublicKey,
ivk: IncomingViewingPublicKey,
vpk: ViewingPublicKey,
epk: EphemeralPublicKey,
) -> Self {
let view_tag = Self::compute_view_tag(npk, ivk);
let view_tag = Self::compute_view_tag(npk, vpk);
Self {
ciphertext,
epk,
@ -32,12 +32,12 @@ impl EncryptedAccountData {
}
}
/// Computes the tag as the first byte of SHA256("/NSSA/v0.2/ViewTag/" || Npk || Ivk)
pub fn compute_view_tag(npk: NullifierPublicKey, ivk: IncomingViewingPublicKey) -> ViewTag {
/// Computes the tag as the first byte of SHA256("/NSSA/v0.2/ViewTag/" || Npk || vpk)
pub fn compute_view_tag(npk: NullifierPublicKey, vpk: ViewingPublicKey) -> ViewTag {
let mut hasher = Sha256::new();
hasher.update(b"/NSSA/v0.2/ViewTag/");
hasher.update(npk.to_byte_array());
hasher.update(ivk.to_bytes());
hasher.update(vpk.to_bytes());
let digest: [u8; 32] = hasher.finalize().into();
digest[0]
}
@ -57,11 +57,7 @@ impl Message {
pub fn try_from_circuit_output(
public_account_ids: Vec<AccountId>,
nonces: Vec<Nonce>,
public_keys: Vec<(
NullifierPublicKey,
IncomingViewingPublicKey,
EphemeralPublicKey,
)>,
public_keys: Vec<(NullifierPublicKey, ViewingPublicKey, EphemeralPublicKey)>,
output: PrivacyPreservingCircuitOutput,
) -> Result<Self, NssaError> {
if public_keys.len() != output.ciphertexts.len() {
@ -74,8 +70,8 @@ impl Message {
.ciphertexts
.into_iter()
.zip(public_keys)
.map(|(ciphertext, (npk, ivk, epk))| {
EncryptedAccountData::new(ciphertext, npk, ivk, epk)
.map(|(ciphertext, (npk, vpk, epk))| {
EncryptedAccountData::new(ciphertext, npk, vpk, epk)
})
.collect();
Ok(Self {
@ -94,7 +90,7 @@ pub mod tests {
use nssa_core::{
Commitment, EncryptionScheme, Nullifier, NullifierPublicKey, SharedSecretKey,
account::Account,
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
encryption::{EphemeralPublicKey, ViewingPublicKey},
};
use sha2::{Digest, Sha256};
@ -142,21 +138,21 @@ pub mod tests {
#[test]
fn test_encrypted_account_data_constructor() {
let npk = NullifierPublicKey::from(&[1; 32]);
let ivk = IncomingViewingPublicKey::from_scalar([2; 32]);
let vpk = ViewingPublicKey::from_scalar([2; 32]);
let account = Account::default();
let commitment = Commitment::new(&npk, &account);
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &ivk);
let shared_secret = SharedSecretKey::new(&esk, &vpk);
let epk = EphemeralPublicKey::from_scalar(esk);
let ciphertext = EncryptionScheme::encrypt(&account, &shared_secret, &commitment, 2);
let encrypted_account_data =
EncryptedAccountData::new(ciphertext.clone(), npk.clone(), ivk.clone(), epk.clone());
EncryptedAccountData::new(ciphertext.clone(), npk.clone(), vpk.clone(), epk.clone());
let expected_view_tag = {
let mut hasher = Sha256::new();
hasher.update(b"/NSSA/v0.2/ViewTag/");
hasher.update(npk.to_byte_array());
hasher.update(ivk.to_bytes());
hasher.update(vpk.to_bytes());
let digest: [u8; 32] = hasher.finalize().into();
digest[0]
};
@ -165,7 +161,7 @@ pub mod tests {
assert_eq!(encrypted_account_data.epk, epk);
assert_eq!(
encrypted_account_data.view_tag,
EncryptedAccountData::compute_view_tag(npk, ivk)
EncryptedAccountData::compute_view_tag(npk, vpk)
);
assert_eq!(encrypted_account_data.view_tag, expected_view_tag);
}

View File

@ -315,7 +315,7 @@ pub mod tests {
use nssa_core::{
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar},
encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey},
program::{PdaSeed, ProgramId},
};
use token_core::{TokenDefinition, TokenHolding};
@ -864,7 +864,7 @@ pub mod tests {
pub struct TestPrivateKeys {
pub nsk: NullifierSecretKey,
pub isk: Scalar,
pub vsk: Scalar,
}
impl TestPrivateKeys {
@ -872,22 +872,22 @@ pub mod tests {
NullifierPublicKey::from(&self.nsk)
}
pub fn ivk(&self) -> IncomingViewingPublicKey {
IncomingViewingPublicKey::from_scalar(self.isk)
pub fn vpk(&self) -> ViewingPublicKey {
ViewingPublicKey::from_scalar(self.vsk)
}
}
pub fn test_private_account_keys_1() -> TestPrivateKeys {
TestPrivateKeys {
nsk: [13; 32],
isk: [31; 32],
vsk: [31; 32],
}
}
pub fn test_private_account_keys_2() -> TestPrivateKeys {
TestPrivateKeys {
nsk: [38; 32],
isk: [83; 32],
vsk: [83; 32],
}
}
@ -908,7 +908,7 @@ pub mod tests {
let recipient = AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk());
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk());
let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.vpk());
let epk = EphemeralPublicKey::from_scalar(esk);
let (output, proof) = circuit::execute_and_prove(
@ -926,7 +926,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![sender_keys.account_id()],
vec![sender_nonce],
vec![(recipient_keys.npk(), recipient_keys.ivk(), epk)],
vec![(recipient_keys.npk(), recipient_keys.vpk(), epk)],
output,
)
.unwrap();
@ -951,11 +951,11 @@ pub mod tests {
AccountWithMetadata::new(Account::default(), false, &recipient_keys.npk());
let esk_1 = [3; 32];
let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.ivk());
let shared_secret_1 = SharedSecretKey::new(&esk_1, &sender_keys.vpk());
let epk_1 = EphemeralPublicKey::from_scalar(esk_1);
let esk_2 = [3; 32];
let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk());
let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.vpk());
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
let (output, proof) = circuit::execute_and_prove(
@ -977,8 +977,8 @@ pub mod tests {
vec![],
vec![],
vec![
(sender_keys.npk(), sender_keys.ivk(), epk_1),
(recipient_keys.npk(), recipient_keys.ivk(), epk_2),
(sender_keys.npk(), sender_keys.vpk(), epk_1),
(recipient_keys.npk(), recipient_keys.vpk(), epk_2),
],
output,
)
@ -1008,7 +1008,7 @@ pub mod tests {
);
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &sender_keys.ivk());
let shared_secret = SharedSecretKey::new(&esk, &sender_keys.vpk());
let epk = EphemeralPublicKey::from_scalar(esk);
let (output, proof) = circuit::execute_and_prove(
@ -1026,7 +1026,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![*recipient_account_id],
vec![],
vec![(sender_keys.npk(), sender_keys.ivk(), epk)],
vec![(sender_keys.npk(), sender_keys.vpk(), epk)],
output,
)
.unwrap();
@ -1538,11 +1538,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1572,7 +1572,7 @@ pub mod tests {
// Setting only one key for an execution with two private accounts.
let private_account_keys = [(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
)];
let result = execute_and_prove(
vec![private_account_1, private_account_2],
@ -1615,11 +1615,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1657,11 +1657,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
private_account_nsks.to_vec(),
@ -1693,12 +1693,12 @@ pub mod tests {
// First private account is the sender
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
// Second private account is the recipient
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
];
@ -1753,11 +1753,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1801,11 +1801,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1848,11 +1848,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1895,11 +1895,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -1940,11 +1940,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -2013,11 +2013,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
vec![sender_keys.nsk],
@ -2050,15 +2050,15 @@ pub mod tests {
let private_account_keys = [
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
(
sender_keys.npk(),
SharedSecretKey::new(&[57; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[57; 32], &sender_keys.vpk()),
),
];
let result = execute_and_prove(
@ -2105,11 +2105,11 @@ pub mod tests {
vec![
(
sender_keys.npk(),
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[55; 32], &sender_keys.vpk()),
),
(
recipient_keys.npk(),
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
SharedSecretKey::new(&[56; 32], &recipient_keys.vpk()),
),
],
private_account_nsks.to_vec(),
@ -2192,7 +2192,7 @@ pub mod tests {
let visibility_mask = [1, 1];
let private_account_nsks = [sender_keys.nsk, sender_keys.nsk];
let private_account_membership_proofs = [Some((1, vec![])), Some((1, vec![]))];
let shared_secret = SharedSecretKey::new(&[55; 32], &sender_keys.ivk());
let shared_secret = SharedSecretKey::new(&[55; 32], &sender_keys.vpk());
let result = execute_and_prove(
vec![private_account_1.clone(), private_account_1],
Program::serialize_instruction(100u128).unwrap(),
@ -3809,11 +3809,11 @@ pub mod tests {
);
let from_esk = [3; 32];
let from_ss = SharedSecretKey::new(&from_esk, &from_keys.ivk());
let from_ss = SharedSecretKey::new(&from_esk, &from_keys.vpk());
let from_epk = EphemeralPublicKey::from_scalar(from_esk);
let to_esk = [3; 32];
let to_ss = SharedSecretKey::new(&to_esk, &to_keys.ivk());
let to_ss = SharedSecretKey::new(&to_esk, &to_keys.vpk());
let to_epk = EphemeralPublicKey::from_scalar(to_esk);
let mut dependencies = HashMap::new();
@ -3858,8 +3858,8 @@ pub mod tests {
vec![],
vec![],
vec![
(to_keys.npk(), to_keys.ivk(), to_epk),
(from_keys.npk(), from_keys.ivk(), from_epk),
(to_keys.npk(), to_keys.vpk(), to_epk),
(from_keys.npk(), from_keys.vpk(), from_epk),
],
output,
)
@ -4069,7 +4069,7 @@ pub mod tests {
// Set up parameters for the new account
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &private_keys.ivk());
let shared_secret = SharedSecretKey::new(&esk, &private_keys.vpk());
let epk = EphemeralPublicKey::from_scalar(esk);
// Balance to initialize the account with (0 for a new account)
@ -4094,7 +4094,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![],
vec![],
vec![(private_keys.npk(), private_keys.ivk(), epk)],
vec![(private_keys.npk(), private_keys.vpk(), epk)],
output,
)
.unwrap();
@ -4124,7 +4124,7 @@ pub mod tests {
// Set up parameters for claiming the new account
let esk = [3; 32];
let shared_secret = SharedSecretKey::new(&esk, &private_keys.ivk());
let shared_secret = SharedSecretKey::new(&esk, &private_keys.vpk());
let epk = EphemeralPublicKey::from_scalar(esk);
let balance: u128 = 0;
@ -4146,7 +4146,7 @@ pub mod tests {
let message = Message::try_from_circuit_output(
vec![],
vec![],
vec![(private_keys.npk(), private_keys.ivk(), epk)],
vec![(private_keys.npk(), private_keys.vpk(), epk)],
output,
)
.unwrap();
@ -4174,7 +4174,7 @@ pub mod tests {
let noop_program = Program::noop();
let esk2 = [4; 32];
let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.ivk());
let shared_secret2 = SharedSecretKey::new(&esk2, &private_keys.vpk());
let nonce2 = 0xdeadbeef2;
@ -4256,7 +4256,7 @@ pub mod tests {
vec![2],
vec![(
sender_keys.npk(),
SharedSecretKey::new(&[3; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[3; 32], &sender_keys.vpk()),
)],
vec![sender_keys.nsk],
vec![Some((0, vec![]))],
@ -4284,7 +4284,7 @@ pub mod tests {
vec![2],
vec![(
sender_keys.npk(),
SharedSecretKey::new(&[3; 32], &sender_keys.ivk()),
SharedSecretKey::new(&[3; 32], &sender_keys.vpk()),
)],
vec![sender_keys.nsk],
vec![Some((0, vec![]))],
@ -4327,7 +4327,7 @@ pub mod tests {
let instruction = (balance_to_transfer, auth_transfers.id());
let recipient_esk = [3; 32];
let recipient = SharedSecretKey::new(&recipient_esk, &recipient_keys.ivk());
let recipient = SharedSecretKey::new(&recipient_esk, &recipient_keys.vpk());
let mut dependencies = HashMap::new();
dependencies.insert(auth_transfers.id(), auth_transfers);

View File

@ -118,7 +118,7 @@ pub fn add_liquidity(
assert!(delta_lp != 0, "Payable LP must be nonzero");
assert!(
delta_lp >= min_amount_liquidity.into(),
delta_lp >= min_amount_liquidity.get(),
"Payable LP is less than provided minimum LP amount"
);

View File

@ -870,15 +870,15 @@ mod tests {
fn acc1() -> AccountId {
AccountId::new([
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
148, 179, 206, 253, 199, 51, 82, 86, 232, 2, 152, 122, 80, 243, 54, 207, 237, 112, 83,
153, 44, 59, 204, 49, 128, 84, 160, 227, 216, 149, 97, 102,
])
}
fn acc2() -> AccountId {
AccountId::new([
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
30, 145, 107, 3, 207, 73, 192, 230, 160, 63, 238, 207, 18, 69, 54, 216, 103, 244, 92,
94, 124, 248, 42, 16, 141, 19, 119, 18, 14, 226, 140, 204,
])
}

View File

@ -19,3 +19,7 @@ cbindgen = "0.29"
[dev-dependencies]
tempfile = "3"
[features]
default = []
prove = ["nssa/prove"]

View File

@ -354,6 +354,61 @@ pub unsafe extern "C" fn wallet_ffi_get_account_public(
WalletFfiError::Success
}
/// Get full private account data from the local storage.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `account_id`: The account ID (32 bytes)
/// - `out_account`: Output pointer for account data
///
/// # Returns
/// - `Success` on successful query
/// - Error code on failure
///
/// # Memory
/// The account data must be freed with `wallet_ffi_free_account_data()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_account` must be a valid pointer to a `FfiAccount` struct
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_get_account_private(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_account: *mut FfiAccount,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
if account_id.is_null() || out_account.is_null() {
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
let account_id = AccountId::new(unsafe { (*account_id).data });
let Some(account) = wallet.get_account_private(account_id) else {
return WalletFfiError::AccountNotFound;
};
unsafe {
*out_account = account.into();
}
WalletFfiError::Success
}
/// Free account data returned by `wallet_ffi_get_account_public`.
///
/// # Safety

View File

@ -73,7 +73,7 @@ pub unsafe extern "C" fn wallet_ffi_get_public_account_key(
/// Get keys for a private account.
///
/// Returns the nullifier public key (NPK) and incoming viewing public key (IPK)
/// Returns the nullifier public key (NPK) and viewing public key (VPK)
/// for the specified private account. These keys are safe to share publicly.
///
/// # Parameters
@ -130,17 +130,17 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys(
// NPK is a 32-byte array
let npk_bytes = key_chain.nullifer_public_key.0;
// IPK is a compressed secp256k1 point (33 bytes)
let ipk_bytes = key_chain.incoming_viewing_public_key.to_bytes();
let ipk_len = ipk_bytes.len();
let ipk_vec = ipk_bytes.to_vec();
let ipk_boxed = ipk_vec.into_boxed_slice();
let ipk_ptr = Box::into_raw(ipk_boxed) as *const u8;
// VPK is a compressed secp256k1 point (33 bytes)
let vpk_bytes = key_chain.viewing_public_key.to_bytes();
let vpk_len = vpk_bytes.len();
let vpk_vec = vpk_bytes.to_vec();
let vpk_boxed = vpk_vec.into_boxed_slice();
let vpk_ptr = Box::into_raw(vpk_boxed) as *const u8;
unsafe {
(*out_keys).nullifier_public_key.data = npk_bytes;
(*out_keys).incoming_viewing_public_key = ipk_ptr;
(*out_keys).incoming_viewing_public_key_len = ipk_len;
(*out_keys).viewing_public_key = vpk_ptr;
(*out_keys).viewing_public_key_len = vpk_len;
}
WalletFfiError::Success
@ -159,10 +159,10 @@ pub unsafe extern "C" fn wallet_ffi_free_private_account_keys(keys: *mut FfiPriv
unsafe {
let keys = &*keys;
if !keys.incoming_viewing_public_key.is_null() && keys.incoming_viewing_public_key_len > 0 {
if !keys.viewing_public_key.is_null() && keys.viewing_public_key_len > 0 {
let slice = std::slice::from_raw_parts_mut(
keys.incoming_viewing_public_key as *mut u8,
keys.incoming_viewing_public_key_len,
keys.viewing_public_key as *mut u8,
keys.viewing_public_key_len,
);
drop(Box::from_raw(slice as *mut [u8]));
}

View File

@ -11,6 +11,7 @@ use crate::{
error::{print_error, WalletFfiError},
types::{FfiBytes32, FfiTransferResult, WalletHandle},
wallet::get_wallet,
FfiPrivateAccountKeys,
};
/// Send a public token transfer.
@ -89,13 +90,270 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public(
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
match e {
ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds,
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
_ => WalletFfiError::InternalError,
map_execution_error(e)
}
Err(e) => e,
}
}
/// Send a shielded token transfer.
///
/// Transfers tokens from a public account to a private account.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `from`: Source account ID (must be owned by this wallet)
/// - `to_keys`: Destination account keys
/// - `amount`: Amount to transfer as little-endian [u8; 16]
/// - `out_result`: Output pointer for transfer result
///
/// # Returns
/// - `Success` if the transfer was submitted successfully
/// - `InsufficientFunds` if the source account doesn't have enough balance
/// - `KeyNotFound` if the source account's signing key is not in this wallet
/// - Error code on other failures
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `from` must be a valid pointer to a `FfiBytes32` struct
/// - `to_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
/// - `amount` must be a valid pointer to a `[u8; 16]` array
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_transfer_shielded(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to_keys: *const FfiPrivateAccountKeys,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
if from.is_null() || to_keys.is_null() || amount.is_null() || out_result.is_null() {
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
let from_id = AccountId::new(unsafe { (*from).data });
let to_npk = (*to_keys).npk();
let to_vpk = match (*to_keys).vpk() {
Ok(vpk) => vpk,
Err(e) => {
print_error("Invalid viewing key");
return e;
}
};
let amount = u128::from_le_bytes(unsafe { *amount });
let transfer = NativeTokenTransfer(&wallet);
match block_on(
transfer.send_shielded_transfer_to_outer_account(from_id, to_npk, to_vpk, amount),
) {
Ok(Ok((response, _shared_key))) => {
let tx_hash = CString::new(response.tx_hash)
.map(|s| s.into_raw())
.unwrap_or(ptr::null_mut());
unsafe {
(*out_result).tx_hash = tx_hash;
(*out_result).success = true;
}
WalletFfiError::Success
}
Ok(Err(e)) => {
print_error(format!("Transfer failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
map_execution_error(e)
}
Err(e) => e,
}
}
/// Send a deshielded token transfer.
///
/// Transfers tokens from a private account to a public account.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `from`: Source account ID (must be owned by this wallet)
/// - `to`: Destination account ID
/// - `amount`: Amount to transfer as little-endian [u8; 16]
/// - `out_result`: Output pointer for transfer result
///
/// # Returns
/// - `Success` if the transfer was submitted successfully
/// - `InsufficientFunds` if the source account doesn't have enough balance
/// - `KeyNotFound` if the source account's signing key is not in this wallet
/// - Error code on other failures
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `from` must be a valid pointer to a `FfiBytes32` struct
/// - `to` must be a valid pointer to a `FfiBytes32` struct
/// - `amount` must be a valid pointer to a `[u8; 16]` array
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_transfer_deshielded(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to: *const FfiBytes32,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() {
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
let from_id = AccountId::new(unsafe { (*from).data });
let to_id = AccountId::new(unsafe { (*to).data });
let amount = u128::from_le_bytes(unsafe { *amount });
let transfer = NativeTokenTransfer(&wallet);
match block_on(transfer.send_deshielded_transfer(from_id, to_id, amount)) {
Ok(Ok((response, _shared_key))) => {
let tx_hash = CString::new(response.tx_hash)
.map(|s| s.into_raw())
.unwrap_or(ptr::null_mut());
unsafe {
(*out_result).tx_hash = tx_hash;
(*out_result).success = true;
}
WalletFfiError::Success
}
Ok(Err(e)) => {
print_error(format!("Transfer failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
map_execution_error(e)
}
Err(e) => e,
}
}
/// Send a private token transfer.
///
/// Transfers tokens from a private account to another private account.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `from`: Source account ID (must be owned by this wallet)
/// - `to_keys`: Destination account keys
/// - `amount`: Amount to transfer as little-endian [u8; 16]
/// - `out_result`: Output pointer for transfer result
///
/// # Returns
/// - `Success` if the transfer was submitted successfully
/// - `InsufficientFunds` if the source account doesn't have enough balance
/// - `KeyNotFound` if the source account's signing key is not in this wallet
/// - Error code on other failures
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `from` must be a valid pointer to a `FfiBytes32` struct
/// - `to_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
/// - `amount` must be a valid pointer to a `[u8; 16]` array
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_transfer_private(
handle: *mut WalletHandle,
from: *const FfiBytes32,
to_keys: *const FfiPrivateAccountKeys,
amount: *const [u8; 16],
out_result: *mut FfiTransferResult,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
if from.is_null() || to_keys.is_null() || amount.is_null() || out_result.is_null() {
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
let from_id = AccountId::new(unsafe { (*from).data });
let to_npk = (*to_keys).npk();
let to_vpk = match (*to_keys).vpk() {
Ok(vpk) => vpk,
Err(e) => {
print_error("Invalid viewing key");
return e;
}
};
let amount = u128::from_le_bytes(unsafe { *amount });
let transfer = NativeTokenTransfer(&wallet);
match block_on(transfer.send_private_transfer_to_outer_account(from_id, to_npk, to_vpk, amount))
{
Ok(Ok((response, _shared_key))) => {
let tx_hash = CString::new(response.tx_hash)
.map(|s| s.into_raw())
.unwrap_or(ptr::null_mut());
unsafe {
(*out_result).tx_hash = tx_hash;
(*out_result).success = true;
}
WalletFfiError::Success
}
Ok(Err(e)) => {
print_error(format!("Transfer failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
map_execution_error(e)
}
Err(e) => e,
}
@ -168,12 +426,80 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account(
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
match e {
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
_ => WalletFfiError::InternalError,
map_execution_error(e)
}
Err(e) => e,
}
}
/// Register a private account on the network.
///
/// This initializes a private account. The account must be
/// owned by this wallet.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `account_id`: Account ID to register
/// - `out_result`: Output pointer for registration result
///
/// # Returns
/// - `Success` if the registration was submitted successfully
/// - Error code on failure
///
/// # Memory
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `account_id` must be a valid pointer to a `FfiBytes32` struct
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_register_private_account(
handle: *mut WalletHandle,
account_id: *const FfiBytes32,
out_result: *mut FfiTransferResult,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
if account_id.is_null() || out_result.is_null() {
print_error("Null pointer argument");
return WalletFfiError::NullPointer;
}
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {}", e));
return WalletFfiError::InternalError;
}
};
let account_id = AccountId::new(unsafe { (*account_id).data });
let transfer = NativeTokenTransfer(&wallet);
match block_on(transfer.register_account_private(account_id)) {
Ok(Ok((res, _secret))) => {
let tx_hash = CString::new(res.tx_hash)
.map(|s| s.into_raw())
.unwrap_or(ptr::null_mut());
unsafe {
(*out_result).tx_hash = tx_hash;
(*out_result).success = true;
}
WalletFfiError::Success
}
Ok(Err(e)) => {
print_error(format!("Registration failed: {:?}", e));
unsafe {
(*out_result).tx_hash = ptr::null_mut();
(*out_result).success = false;
}
map_execution_error(e)
}
Err(e) => e,
}
@ -197,3 +523,13 @@ pub unsafe extern "C" fn wallet_ffi_free_transfer_result(result: *mut FfiTransfe
}
}
}
fn map_execution_error(e: ExecutionFailureKind) -> WalletFfiError {
match e {
ExecutionFailureKind::InsufficientFundsError => WalletFfiError::InsufficientFunds,
ExecutionFailureKind::KeyNotFoundError => WalletFfiError::KeyNotFound,
ExecutionFailureKind::SequencerError => WalletFfiError::NetworkError,
ExecutionFailureKind::SequencerClientError(_) => WalletFfiError::NetworkError,
_ => WalletFfiError::InternalError,
}
}

View File

@ -72,18 +72,18 @@ impl Default for FfiAccount {
pub struct FfiPrivateAccountKeys {
/// Nullifier public key (32 bytes)
pub nullifier_public_key: FfiBytes32,
/// Incoming viewing public key (compressed secp256k1 point)
pub incoming_viewing_public_key: *const u8,
/// Length of incoming viewing public key (typically 33 bytes)
pub incoming_viewing_public_key_len: usize,
/// viewing public key (compressed secp256k1 point)
pub viewing_public_key: *const u8,
/// Length of viewing public key (typically 33 bytes)
pub viewing_public_key_len: usize,
}
impl Default for FfiPrivateAccountKeys {
fn default() -> Self {
Self {
nullifier_public_key: FfiBytes32::default(),
incoming_viewing_public_key: std::ptr::null(),
incoming_viewing_public_key_len: 0,
viewing_public_key: std::ptr::null(),
viewing_public_key_len: 0,
}
}
}
@ -157,13 +157,10 @@ impl FfiPrivateAccountKeys {
nssa_core::NullifierPublicKey(self.nullifier_public_key.data)
}
pub fn ivk(&self) -> Result<nssa_core::encryption::IncomingViewingPublicKey, WalletFfiError> {
if self.incoming_viewing_public_key_len == 33 {
pub fn vpk(&self) -> Result<nssa_core::encryption::ViewingPublicKey, WalletFfiError> {
if self.viewing_public_key_len == 33 {
let slice = unsafe {
slice::from_raw_parts(
self.incoming_viewing_public_key,
self.incoming_viewing_public_key_len,
)
slice::from_raw_parts(self.viewing_public_key, self.viewing_public_key_len)
};
Ok(Secp256k1Point(slice.to_vec()))
} else {

View File

@ -198,13 +198,13 @@ typedef struct FfiPrivateAccountKeys {
*/
struct FfiBytes32 nullifier_public_key;
/**
* Incoming viewing public key (compressed secp256k1 point)
* viewing public key (compressed secp256k1 point)
*/
const uint8_t *incoming_viewing_public_key;
const uint8_t *viewing_public_key;
/**
* Length of incoming viewing public key (typically 33 bytes)
* Length of viewing public key (typically 33 bytes)
*/
uintptr_t incoming_viewing_public_key_len;
uintptr_t viewing_public_key_len;
} FfiPrivateAccountKeys;
/**
@ -344,6 +344,30 @@ enum WalletFfiError wallet_ffi_get_account_public(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
struct FfiAccount *out_account);
/**
* Get full private account data from the local storage.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `account_id`: The account ID (32 bytes)
* - `out_account`: Output pointer for account data
*
* # Returns
* - `Success` on successful query
* - Error code on failure
*
* # Memory
* The account data must be freed with `wallet_ffi_free_account_data()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_account` must be a valid pointer to a `FfiAccount` struct
*/
enum WalletFfiError wallet_ffi_get_account_private(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
struct FfiAccount *out_account);
/**
* Free account data returned by `wallet_ffi_get_account_public`.
*
@ -380,7 +404,7 @@ enum WalletFfiError wallet_ffi_get_public_account_key(struct WalletHandle *handl
/**
* Get keys for a private account.
*
* Returns the nullifier public key (NPK) and incoming viewing public key (IPK)
* Returns the nullifier public key (NPK) and viewing public key (VPK)
* for the specified private account. These keys are safe to share publicly.
*
* # Parameters
@ -546,6 +570,108 @@ enum WalletFfiError wallet_ffi_transfer_public(struct WalletHandle *handle,
const uint8_t (*amount)[16],
struct FfiTransferResult *out_result);
/**
* Send a shielded token transfer.
*
* Transfers tokens from a public account to a private account.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `from`: Source account ID (must be owned by this wallet)
* - `to_keys`: Destination account keys
* - `amount`: Amount to transfer as little-endian [u8; 16]
* - `out_result`: Output pointer for transfer result
*
* # Returns
* - `Success` if the transfer was submitted successfully
* - `InsufficientFunds` if the source account doesn't have enough balance
* - `KeyNotFound` if the source account's signing key is not in this wallet
* - Error code on other failures
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `from` must be a valid pointer to a `FfiBytes32` struct
* - `to_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
* - `amount` must be a valid pointer to a `[u8; 16]` array
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_transfer_shielded(struct WalletHandle *handle,
const struct FfiBytes32 *from,
const struct FfiPrivateAccountKeys *to_keys,
const uint8_t (*amount)[16],
struct FfiTransferResult *out_result);
/**
* Send a deshielded token transfer.
*
* Transfers tokens from a private account to a public account.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `from`: Source account ID (must be owned by this wallet)
* - `to`: Destination account ID
* - `amount`: Amount to transfer as little-endian [u8; 16]
* - `out_result`: Output pointer for transfer result
*
* # Returns
* - `Success` if the transfer was submitted successfully
* - `InsufficientFunds` if the source account doesn't have enough balance
* - `KeyNotFound` if the source account's signing key is not in this wallet
* - Error code on other failures
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `from` must be a valid pointer to a `FfiBytes32` struct
* - `to` must be a valid pointer to a `FfiBytes32` struct
* - `amount` must be a valid pointer to a `[u8; 16]` array
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_transfer_deshielded(struct WalletHandle *handle,
const struct FfiBytes32 *from,
const struct FfiBytes32 *to,
const uint8_t (*amount)[16],
struct FfiTransferResult *out_result);
/**
* Send a private token transfer.
*
* Transfers tokens from a private account to another private account.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `from`: Source account ID (must be owned by this wallet)
* - `to_keys`: Destination account keys
* - `amount`: Amount to transfer as little-endian [u8; 16]
* - `out_result`: Output pointer for transfer result
*
* # Returns
* - `Success` if the transfer was submitted successfully
* - `InsufficientFunds` if the source account doesn't have enough balance
* - `KeyNotFound` if the source account's signing key is not in this wallet
* - Error code on other failures
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `from` must be a valid pointer to a `FfiBytes32` struct
* - `to_keys` must be a valid pointer to a `FfiPrivateAccountKeys` struct
* - `amount` must be a valid pointer to a `[u8; 16]` array
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_transfer_private(struct WalletHandle *handle,
const struct FfiBytes32 *from,
const struct FfiPrivateAccountKeys *to_keys,
const uint8_t (*amount)[16],
struct FfiTransferResult *out_result);
/**
* Register a public account on the network.
*
@ -573,6 +699,33 @@ enum WalletFfiError wallet_ffi_register_public_account(struct WalletHandle *hand
const struct FfiBytes32 *account_id,
struct FfiTransferResult *out_result);
/**
* Register a private account on the network.
*
* This initializes a private account. The account must be
* owned by this wallet.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `account_id`: Account ID to register
* - `out_result`: Output pointer for registration result
*
* # Returns
* - `Success` if the registration was submitted successfully
* - Error code on failure
*
* # Memory
* The result must be freed with `wallet_ffi_free_transfer_result()`.
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `account_id` must be a valid pointer to a `FfiBytes32` struct
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
*/
enum WalletFfiError wallet_ffi_register_private_account(struct WalletHandle *handle,
const struct FfiBytes32 *account_id,
struct FfiTransferResult *out_result);
/**
* Free a transfer result returned by `wallet_ffi_transfer_public` or
* `wallet_ffi_register_public_account`.

View File

@ -84,9 +84,9 @@
]
}
},
{
{
"Private": {
"account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
"account_id": "2ECgkFTaXzwjJBXR7ZKmXYQtpHbvTTHK9Auma4NL9AUo",
"account": {
"program_owner": [
0,
@ -103,219 +103,19 @@
"nonce": 0
},
"key_chain": {
"secret_spending_key": [
251,
82,
235,
1,
146,
96,
30,
81,
162,
234,
33,
15,
123,
129,
116,
0,
84,
136,
176,
70,
190,
224,
161,
54,
134,
142,
154,
1,
18,
251,
242,
189
],
"secret_spending_key": [112, 17, 152, 192, 217, 201, 142, 92, 111, 68, 85, 222, 107, 73, 78, 196, 118, 226, 37, 17, 185, 177, 149, 182, 9, 85, 187, 152, 163, 144, 68, 121],
"private_key_holder": {
"nullifier_secret_key": [
29,
250,
10,
187,
35,
123,
180,
250,
246,
97,
216,
153,
44,
156,
16,
93,
241,
26,
174,
219,
72,
84,
34,
247,
112,
101,
217,
243,
189,
173,
75,
20
],
"incoming_viewing_secret_key": [
251,
201,
22,
154,
100,
165,
218,
108,
163,
190,
135,
91,
145,
84,
69,
241,
46,
117,
217,
110,
197,
248,
91,
193,
14,
104,
88,
103,
67,
153,
182,
158
],
"outgoing_viewing_secret_key": [
25,
67,
121,
76,
175,
100,
30,
198,
105,
123,
49,
169,
75,
178,
75,
210,
100,
143,
210,
243,
228,
243,
21,
18,
36,
84,
164,
186,
139,
113,
214,
12
]
"nullifier_secret_key": [52, 33, 235, 245, 42, 132, 163, 182, 114, 56, 144, 187, 147, 23, 184, 227, 128, 12, 180, 142, 217, 110, 188, 177, 155, 141, 23, 127, 216, 185, 33, 126],
"viewing_secret_key": [44, 81, 165, 166, 34, 188, 192, 240, 40, 9, 83, 189, 215, 184, 246, 154, 247, 227, 155, 16, 121, 238, 4, 245, 63, 135, 192, 213, 222, 247, 120, 86]
},
"nullifer_public_key": [
63,
202,
178,
231,
183,
82,
237,
212,
216,
221,
215,
255,
153,
101,
177,
161,
254,
210,
128,
122,
54,
190,
230,
151,
183,
64,
225,
229,
113,
1,
228,
97
],
"incoming_viewing_public_key": [
3,
235,
139,
131,
237,
177,
122,
189,
6,
177,
167,
178,
202,
117,
246,
58,
28,
65,
132,
79,
220,
139,
119,
243,
187,
160,
212,
121,
61,
247,
116,
72,
205
]
"nullifer_public_key": [13, 25, 40, 5, 198, 248, 210, 248, 237, 121, 124, 145, 186, 142, 253, 216, 236, 69, 193, 32, 166, 167, 49, 133, 172, 111, 159, 46, 84, 17, 157, 23],
"viewing_public_key": [3, 43, 116, 165, 161, 27, 150, 158, 175, 198, 215, 27, 121, 126, 158, 224, 249, 92, 168, 163, 173, 115, 120, 122, 89, 173, 133, 94, 39, 238, 62, 52, 193]
}
}
},
{
"Private": {
"account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
"account_id": "E8HwiTyQe4H9HK7icTvn95HQMnzx49mP9A2ddtMLpNaN",
"account": {
"program_owner": [
0,
@ -332,213 +132,13 @@
"nonce": 0
},
"key_chain": {
"secret_spending_key": [
238,
171,
241,
69,
111,
217,
85,
64,
19,
82,
18,
189,
32,
91,
78,
175,
107,
7,
109,
60,
52,
44,
243,
230,
72,
244,
192,
92,
137,
33,
118,
254
],
"secret_spending_key": [48, 175, 124, 10, 230, 240, 166, 14, 249, 254, 157, 226, 208, 124, 122, 177, 203, 139, 192, 180, 43, 120, 55, 151, 50, 21, 113, 22, 254, 83, 148, 56],
"private_key_holder": {
"nullifier_secret_key": [
25,
211,
215,
119,
57,
223,
247,
37,
245,
144,
122,
29,
118,
245,
83,
228,
23,
9,
101,
120,
88,
33,
238,
207,
128,
61,
110,
2,
89,
62,
164,
13
],
"incoming_viewing_secret_key": [
193,
181,
14,
196,
142,
84,
15,
65,
128,
101,
70,
196,
241,
47,
130,
221,
23,
146,
161,
237,
221,
40,
19,
126,
59,
15,
169,
236,
25,
105,
104,
231
],
"outgoing_viewing_secret_key": [
20,
170,
220,
108,
41,
23,
155,
217,
247,
190,
175,
168,
247,
34,
105,
134,
114,
74,
104,
91,
211,
62,
126,
13,
130,
100,
241,
214,
250,
236,
38,
150
]
"nullifier_secret_key": [99, 82, 190, 140, 234, 10, 61, 163, 15, 211, 179, 54, 70, 166, 87, 5, 182, 68, 117, 244, 217, 23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30],
"viewing_secret_key": [205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21, 154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128]
},
"nullifer_public_key": [
192,
251,
166,
243,
167,
236,
84,
249,
35,
136,
130,
172,
219,
225,
161,
139,
229,
89,
243,
125,
194,
213,
209,
30,
23,
174,
100,
244,
124,
74,
140,
47
],
"incoming_viewing_public_key": [
2,
181,
98,
93,
216,
241,
241,
110,
58,
198,
119,
174,
250,
184,
1,
204,
200,
173,
44,
238,
37,
247,
170,
156,
100,
254,
116,
242,
28,
183,
187,
77,
255
]
"nullifer_public_key": [32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210, 143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165],
"viewing_public_key": [2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11, 171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238]
}
}
}

View File

@ -20,7 +20,7 @@ pub enum AccountSubcommand {
/// Flag to get raw account data
#[arg(short, long)]
raw: bool,
/// Display keys (pk for public accounts, npk/ipk for private accounts)
/// Display keys (pk for public accounts, npk/vpk for private accounts)
#[arg(short, long)]
keys: bool,
/// Valid 32 byte base58 string with privacy prefix
@ -107,8 +107,8 @@ impl WalletSubcommand for NewSubcommand {
);
println!("With npk {}", hex::encode(key.nullifer_public_key.0));
println!(
"With ipk {}",
hex::encode(key.incoming_viewing_public_key.to_bytes())
"With vpk {}",
hex::encode(key.viewing_public_key.to_bytes())
);
wallet_core.store_persistent_data().await?;
@ -207,10 +207,7 @@ impl WalletSubcommand for AccountSubcommand {
.ok_or(anyhow::anyhow!("Private account not found in storage"))?;
println!("npk {}", hex::encode(key.nullifer_public_key.0));
println!(
"ipk {}",
hex::encode(key.incoming_viewing_public_key.to_bytes())
);
println!("vpk {}", hex::encode(key.viewing_public_key.to_bytes()));
}
}
Ok(())

View File

@ -22,7 +22,7 @@ pub enum AuthTransferSubcommand {
},
/// Send native tokens from one account to another with variable privacy
///
/// If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive
/// If receiver is private, then `to` and (`to_npk` , `to_vpk`) is a mutually exclusive
/// patterns.
///
/// First is used for owned accounts, second otherwise.
@ -36,9 +36,9 @@ pub enum AuthTransferSubcommand {
/// to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: Option<String>,
/// to_ipk - valid 33 byte hex string
/// to_vpk - valid 33 byte hex string
#[arg(long)]
to_ipk: Option<String>,
to_vpk: Option<String>,
/// amount - amount of balance to move
#[arg(long)]
amount: u128,
@ -102,10 +102,10 @@ impl WalletSubcommand for AuthTransferSubcommand {
from,
to,
to_npk,
to_ipk,
to_vpk,
amount,
} => {
let underlying_subcommand = match (to, to_npk, to_ipk) {
let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => {
anyhow::bail!(
"Provide either account account_id of receiver or their public keys"
@ -154,7 +154,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
}
}
}
(None, Some(to_npk), Some(to_ipk)) => {
(None, Some(to_npk), Some(to_vpk)) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy {
@ -163,7 +163,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from,
to_npk,
to_ipk,
to_vpk,
amount,
},
)
@ -173,7 +173,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from,
to_npk,
to_ipk,
to_vpk,
amount,
},
)
@ -255,9 +255,9 @@ pub enum NativeTokenTransferProgramSubcommandShielded {
/// to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
/// to_ipk - valid 33 byte hex string
/// to_vpk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
to_vpk: String,
/// amount - amount of balance to move
#[arg(long)]
amount: u128,
@ -292,9 +292,9 @@ pub enum NativeTokenTransferProgramSubcommandPrivate {
/// to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: String,
/// to_ipk - valid 33 byte hex string
/// to_vpk - valid 33 byte hex string
#[arg(long)]
to_ipk: String,
to_vpk: String,
/// amount - amount of balance to move
#[arg(long)]
amount: u128,
@ -336,7 +336,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from,
to_npk,
to_ipk,
to_vpk,
amount,
} => {
let from: AccountId = from.parse().unwrap();
@ -345,14 +345,14 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let to_vpk_res = hex::decode(to_vpk)?;
let mut to_vpk = [0u8; 33];
to_vpk.copy_from_slice(&to_vpk_res);
let to_vpk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec());
let (res, [secret_from, _]) = NativeTokenTransfer(wallet_core)
.send_private_transfer_to_outer_account(from, to_npk, to_ipk, amount)
.send_private_transfer_to_outer_account(from, to_npk, to_vpk, amount)
.await?;
println!("Results of tx send are {res:#?}");
@ -412,7 +412,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from,
to_npk,
to_ipk,
to_vpk,
amount,
} => {
let from: AccountId = from.parse().unwrap();
@ -422,14 +422,14 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
to_npk.copy_from_slice(&to_npk_res);
let to_npk = nssa_core::NullifierPublicKey(to_npk);
let to_ipk_res = hex::decode(to_ipk)?;
let mut to_ipk = [0u8; 33];
to_ipk.copy_from_slice(&to_ipk_res);
let to_ipk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
let to_vpk_res = hex::decode(to_vpk)?;
let mut to_vpk = [0u8; 33];
to_vpk.copy_from_slice(&to_vpk_res);
let to_vpk =
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec());
let (res, _) = NativeTokenTransfer(wallet_core)
.send_shielded_transfer_to_outer_account(from, to_npk, to_ipk, amount)
.send_shielded_transfer_to_outer_account(from, to_npk, to_vpk, amount)
.await?;
println!("Results of tx send are {res:#?}");

View File

@ -29,7 +29,7 @@ pub enum TokenProgramAgnosticSubcommand {
},
/// Send tokens from one account to another with variable privacy
///
/// If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive
/// If receiver is private, then `to` and (`to_npk` , `to_vpk`) is a mutually exclusive
/// patterns.
///
/// First is used for owned accounts, second otherwise.
@ -43,9 +43,9 @@ pub enum TokenProgramAgnosticSubcommand {
/// to_npk - valid 32 byte hex string
#[arg(long)]
to_npk: Option<String>,
/// to_ipk - valid 33 byte hex string
/// to_vpk - valid 33 byte hex string
#[arg(long)]
to_ipk: Option<String>,
to_vpk: Option<String>,
/// amount - amount of balance to move
#[arg(long)]
amount: u128,
@ -71,7 +71,7 @@ pub enum TokenProgramAgnosticSubcommand {
///
/// `definition` is owned
///
/// If `holder` is private, then `holder` and (`holder_npk` , `holder_ipk`) is a mutually
/// If `holder` is private, then `holder` and (`holder_npk` , `holder_vpk`) is a mutually
/// exclusive patterns.
///
/// First is used for owned accounts, second otherwise.
@ -85,9 +85,9 @@ pub enum TokenProgramAgnosticSubcommand {
/// holder_npk - valid 32 byte hex string
#[arg(long)]
holder_npk: Option<String>,
/// to_ipk - valid 33 byte hex string
/// to_vpk - valid 33 byte hex string
#[arg(long)]
holder_ipk: Option<String>,
holder_vpk: Option<String>,
/// amount - amount of balance to mint
#[arg(long)]
amount: u128,
@ -160,10 +160,10 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
from,
to,
to_npk,
to_ipk,
to_vpk,
amount,
} => {
let underlying_subcommand = match (to, to_npk, to_ipk) {
let underlying_subcommand = match (to, to_npk, to_vpk) {
(None, None, None) => {
anyhow::bail!(
"Provide either account account_id of receiver or their public keys"
@ -220,7 +220,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
}
}
}
(None, Some(to_npk), Some(to_ipk)) => {
(None, Some(to_npk), Some(to_vpk)) => {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy {
@ -228,7 +228,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_account_id: from,
recipient_npk: to_npk,
recipient_ipk: to_ipk,
recipient_vpk: to_vpk,
balance_to_move: amount,
},
),
@ -236,7 +236,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_account_id: from,
recipient_npk: to_npk,
recipient_ipk: to_ipk,
recipient_vpk: to_vpk,
balance_to_move: amount,
},
),
@ -302,10 +302,10 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
definition,
holder,
holder_npk,
holder_ipk,
holder_vpk,
amount,
} => {
let underlying_subcommand = match (holder, holder_npk, holder_ipk) {
let underlying_subcommand = match (holder, holder_npk, holder_vpk) {
(None, None, None) => {
anyhow::bail!(
"Provide either account account_id of holder or their public keys"
@ -363,7 +363,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
}
}
}
(None, Some(holder_npk), Some(holder_ipk)) => {
(None, Some(holder_npk), Some(holder_vpk)) => {
let (definition, definition_privacy) =
parse_addr_with_privacy_prefix(&definition)?;
@ -372,7 +372,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
TokenProgramSubcommandPrivate::MintTokenPrivateForeign {
definition_account_id: definition,
holder_npk,
holder_ipk,
holder_vpk,
amount,
},
),
@ -380,7 +380,7 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
TokenProgramSubcommandShielded::MintTokenShieldedForeign {
definition_account_id: definition,
holder_npk,
holder_ipk,
holder_vpk,
amount,
},
),
@ -465,9 +465,9 @@ pub enum TokenProgramSubcommandPrivate {
/// recipient_npk - valid 32 byte hex string
#[arg(long)]
recipient_npk: String,
/// recipient_ipk - valid 33 byte hex string
/// recipient_vpk - valid 33 byte hex string
#[arg(long)]
recipient_ipk: String,
recipient_vpk: String,
#[arg(short, long)]
balance_to_move: u128,
},
@ -496,7 +496,7 @@ pub enum TokenProgramSubcommandPrivate {
#[arg(short, long)]
holder_npk: String,
#[arg(short, long)]
holder_ipk: String,
holder_vpk: String,
#[arg(short, long)]
amount: u128,
},
@ -553,9 +553,9 @@ pub enum TokenProgramSubcommandShielded {
/// recipient_npk - valid 32 byte hex string
#[arg(long)]
recipient_npk: String,
/// recipient_ipk - valid 33 byte hex string
/// recipient_vpk - valid 33 byte hex string
#[arg(long)]
recipient_ipk: String,
recipient_vpk: String,
#[arg(short, long)]
balance_to_move: u128,
},
@ -584,7 +584,7 @@ pub enum TokenProgramSubcommandShielded {
#[arg(short, long)]
holder_npk: String,
#[arg(short, long)]
holder_ipk: String,
holder_vpk: String,
#[arg(short, long)]
amount: u128,
},
@ -745,7 +745,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_account_id,
recipient_npk,
recipient_ipk,
recipient_vpk,
balance_to_move,
} => {
let sender_account_id: AccountId = sender_account_id.parse().unwrap();
@ -754,18 +754,18 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
recipient_npk.copy_from_slice(&recipient_npk_res);
let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk);
let recipient_ipk_res = hex::decode(recipient_ipk)?;
let mut recipient_ipk = [0u8; 33];
recipient_ipk.copy_from_slice(&recipient_ipk_res);
let recipient_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
recipient_ipk.to_vec(),
let recipient_vpk_res = hex::decode(recipient_vpk)?;
let mut recipient_vpk = [0u8; 33];
recipient_vpk.copy_from_slice(&recipient_vpk_res);
let recipient_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
recipient_vpk.to_vec(),
);
let (res, [secret_sender, _]) = Token(wallet_core)
.send_transfer_transaction_private_foreign_account(
sender_account_id,
recipient_npk,
recipient_ipk,
recipient_vpk,
balance_to_move,
)
.await?;
@ -865,7 +865,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
TokenProgramSubcommandPrivate::MintTokenPrivateForeign {
definition_account_id,
holder_npk,
holder_ipk,
holder_vpk,
amount,
} => {
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
@ -875,18 +875,18 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
holder_npk.copy_from_slice(&holder_npk_res);
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
let holder_ipk_res = hex::decode(holder_ipk)?;
let mut holder_ipk = [0u8; 33];
holder_ipk.copy_from_slice(&holder_ipk_res);
let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
holder_ipk.to_vec(),
let holder_vpk_res = hex::decode(holder_vpk)?;
let mut holder_vpk = [0u8; 33];
holder_vpk.copy_from_slice(&holder_vpk_res);
let holder_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
holder_vpk.to_vec(),
);
let (res, [secret_definition, _]) = Token(wallet_core)
.send_mint_transaction_private_foreign_account(
definition_account_id,
holder_npk,
holder_ipk,
holder_vpk,
amount,
)
.await?;
@ -1034,7 +1034,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_account_id,
recipient_npk,
recipient_ipk,
recipient_vpk,
balance_to_move,
} => {
let sender_account_id: AccountId = sender_account_id.parse().unwrap();
@ -1043,18 +1043,18 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
recipient_npk.copy_from_slice(&recipient_npk_res);
let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk);
let recipient_ipk_res = hex::decode(recipient_ipk)?;
let mut recipient_ipk = [0u8; 33];
recipient_ipk.copy_from_slice(&recipient_ipk_res);
let recipient_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
recipient_ipk.to_vec(),
let recipient_vpk_res = hex::decode(recipient_vpk)?;
let mut recipient_vpk = [0u8; 33];
recipient_vpk.copy_from_slice(&recipient_vpk_res);
let recipient_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
recipient_vpk.to_vec(),
);
let (res, _) = Token(wallet_core)
.send_transfer_transaction_shielded_foreign_account(
sender_account_id,
recipient_npk,
recipient_ipk,
recipient_vpk,
balance_to_move,
)
.await?;
@ -1177,7 +1177,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
TokenProgramSubcommandShielded::MintTokenShieldedForeign {
definition_account_id,
holder_npk,
holder_ipk,
holder_vpk,
amount,
} => {
let definition_account_id: AccountId = definition_account_id.parse().unwrap();
@ -1187,18 +1187,18 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
holder_npk.copy_from_slice(&holder_npk_res);
let holder_npk = nssa_core::NullifierPublicKey(holder_npk);
let holder_ipk_res = hex::decode(holder_ipk)?;
let mut holder_ipk = [0u8; 33];
holder_ipk.copy_from_slice(&holder_ipk_res);
let holder_ipk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
holder_ipk.to_vec(),
let holder_vpk_res = hex::decode(holder_vpk)?;
let mut holder_vpk = [0u8; 33];
holder_vpk.copy_from_slice(&holder_vpk_res);
let holder_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point(
holder_vpk.to_vec(),
);
let (res, _) = Token(wallet_core)
.send_mint_transaction_shielded_foreign_account(
definition_account_id,
holder_npk,
holder_ipk,
holder_vpk,
amount,
)
.await?;

View File

@ -292,7 +292,7 @@ impl Default for WalletConfig {
},
{
"Private": {
"account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
"account_id": "FpdcxBrMkHWqXCBQ6FG98eYfWGY6jWZRsKNSi1FwDMxy",
"account": {
"program_owner": [
0,
@ -310,218 +310,151 @@ impl Default for WalletConfig {
},
"key_chain": {
"secret_spending_key": [
251,
82,
235,
1,
146,
96,
30,
81,
162,
234,
239,
27,
159,
83,
199,
194,
132,
33,
15,
123,
129,
116,
0,
20,
28,
217,
103,
101,
57,
27,
125,
84,
136,
176,
70,
190,
224,
57,
19,
86,
98,
135,
161,
54,
134,
142,
154,
1,
18,
251,
242,
189
221,
108,
125,
152,
174,
161,
64,
16,
200
],
"private_key_holder": {
"nullifier_secret_key": [
29,
250,
10,
187,
35,
123,
180,
250,
246,
97,
216,
153,
44,
156,
71,
195,
16,
93,
241,
26,
174,
219,
72,
84,
34,
247,
112,
101,
217,
243,
189,
173,
75,
20
],
"incoming_viewing_secret_key": [
251,
201,
22,
154,
100,
165,
218,
108,
163,
190,
135,
91,
145,
84,
69,
241,
46,
117,
217,
110,
197,
248,
91,
193,
14,
104,
88,
103,
67,
153,
182,
158
],
"outgoing_viewing_secret_key": [
25,
67,
121,
76,
175,
100,
30,
198,
105,
123,
49,
169,
75,
178,
75,
210,
100,
143,
210,
243,
228,
243,
21,
18,
36,
84,
164,
186,
119,
0,
98,
35,
106,
139,
113,
214,
12
82,
145,
50,
27,
140,
206,
19,
53,
122,
166,
76,
195,
0,
16,
19,
21,
143,
155,
119,
9,
200,
81,
105
],
"viewing_secret_key": [
5,
117,
221,
27,
236,
199,
53,
22,
249,
231,
98,
147,
213,
116,
191,
82,
188,
148,
175,
98,
139,
52,
232,
249,
220,
217,
83,
58,
112,
155,
197,
196
]
},
"nullifer_public_key": [
63,
202,
178,
231,
183,
82,
237,
212,
216,
221,
215,
255,
153,
101,
177,
161,
254,
210,
128,
122,
54,
190,
230,
151,
183,
64,
225,
229,
113,
1,
228,
97
],
"incoming_viewing_public_key": [
3,
235,
139,
131,
237,
177,
122,
189,
6,
177,
167,
178,
202,
117,
246,
58,
28,
65,
132,
79,
220,
139,
119,
11,
87,
38,
254,
159,
231,
165,
1,
94,
64,
137,
243,
187,
160,
212,
121,
61,
247,
116,
72,
205
]
76,
249,
101,
251,
129,
33,
101,
189,
30,
42,
11,
191,
34,
103,
186,
227,
230
],
"viewing_public_key": [
2, 69, 126, 43, 158, 209, 172, 144, 23, 185, 208, 25, 163, 166, 176, 200, 225, 251, 106, 211, 4, 199, 112, 243, 207, 144, 135, 56, 157, 167, 32, 219, 38]
}
}
},
{
"Private": {
"account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
"account_id": "E8HwiTyQe4H9HK7icTvn95HQMnzx49mP9A2ddtMLpNaN",
"account": {
"program_owner": [
0,
@ -539,211 +472,20 @@ impl Default for WalletConfig {
},
"key_chain": {
"secret_spending_key": [
238,
171,
241,
69,
111,
217,
85,
64,
19,
82,
18,
189,
32,
91,
78,
175,
107,
7,
109,
60,
52,
44,
243,
230,
72,
244,
192,
92,
137,
33,
118,
254
],
48, 175, 124, 10, 230, 240, 166, 14, 249, 254, 157, 226, 208, 124, 122, 177, 203, 139, 192, 180, 43, 120, 55, 151, 50, 21, 113, 22, 254, 83, 148, 56],
"private_key_holder": {
"nullifier_secret_key": [
25,
211,
215,
119,
57,
223,
247,
37,
245,
144,
122,
29,
118,
245,
83,
228,
23,
9,
101,
120,
88,
33,
238,
207,
128,
61,
110,
2,
89,
62,
164,
13
99, 82, 190, 140, 234, 10, 61, 163, 15, 211, 179, 54, 70, 166, 87, 5, 182, 68, 117, 244, 217, 23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30
],
"incoming_viewing_secret_key": [
193,
181,
14,
196,
142,
84,
15,
65,
128,
101,
70,
196,
241,
47,
130,
221,
23,
146,
161,
237,
221,
40,
19,
126,
59,
15,
169,
236,
25,
105,
104,
231
],
"outgoing_viewing_secret_key": [
20,
170,
220,
108,
41,
23,
155,
217,
247,
190,
175,
168,
247,
34,
105,
134,
114,
74,
104,
91,
211,
62,
126,
13,
130,
100,
241,
214,
250,
236,
38,
150
"viewing_secret_key": [
205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21, 154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128
]
},
"nullifer_public_key": [
192,
251,
166,
243,
167,
236,
84,
249,
35,
136,
130,
172,
219,
225,
161,
139,
229,
89,
243,
125,
194,
213,
209,
30,
23,
174,
100,
244,
124,
74,
140,
47
32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210, 143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165
],
"incoming_viewing_public_key": [
2,
181,
98,
93,
216,
241,
241,
110,
58,
198,
119,
174,
250,
184,
1,
204,
200,
173,
44,
238,
37,
247,
170,
156,
100,
254,
116,
242,
28,
183,
187,
77,
255
"viewing_public_key": [
2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11, 171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238
]
}
}

View File

@ -298,6 +298,8 @@ impl WalletCore {
instruction_data: InstructionData,
program: &ProgramWithDependencies,
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
// TODO: handle large Err-variant properly
#[allow(clippy::result_large_err)]
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
Ok(())
})
@ -343,7 +345,7 @@ impl WalletCore {
Vec::from_iter(acc_manager.public_account_nonces()),
private_account_keys
.iter()
.map(|keys| (keys.npk.clone(), keys.ipk.clone(), keys.epk.clone()))
.map(|keys| (keys.npk.clone(), keys.vpk.clone(), keys.epk.clone()))
.collect(),
output,
)
@ -427,7 +429,7 @@ impl WalletCore {
.flat_map(|(acc_account_id, key_chain)| {
let view_tag = EncryptedAccountData::compute_view_tag(
key_chain.nullifer_public_key.clone(),
key_chain.incoming_viewing_public_key.clone(),
key_chain.viewing_public_key.clone(),
);
tx.message()

View File

@ -36,7 +36,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: winner_nsk,
npk: winner_npk,
ipk: winner_ipk,
vpk: winner_vpk,
auth_acc: winner_pre,
proof: _,
} = self
@ -50,7 +50,7 @@ impl WalletCore {
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id);
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_vpk);
let (output, proof) = circuit::execute_and_prove(
&[pinata_pre, winner_pre],
@ -70,7 +70,7 @@ impl WalletCore {
vec![],
vec![(
winner_npk.clone(),
winner_ipk.clone(),
winner_vpk.clone(),
eph_holder_winner.generate_ephemeral_public_key(),
)],
output,
@ -103,7 +103,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: _,
npk: winner_npk,
ipk: winner_ipk,
vpk: winner_vpk,
auth_acc: winner_pre,
proof: _,
} = self
@ -117,7 +117,7 @@ impl WalletCore {
let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id);
let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_vpk);
let (output, proof) = circuit::execute_and_prove(
&[pinata_pre, winner_pre],
@ -137,7 +137,7 @@ impl WalletCore {
vec![],
vec![(
winner_npk.clone(),
winner_ipk.clone(),
winner_vpk.clone(),
eph_holder_winner.generate_ephemeral_public_key(),
)],
output,

View File

@ -5,7 +5,7 @@ use nssa::{AccountId, PrivateKey};
use nssa_core::{
MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
account::{AccountWithMetadata, Nonce},
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
encryption::{EphemeralPublicKey, ViewingPublicKey},
};
use crate::WalletCore;
@ -16,7 +16,7 @@ pub enum PrivacyPreservingAccount {
PrivateOwned(AccountId),
PrivateForeign {
npk: NullifierPublicKey,
ipk: IncomingViewingPublicKey,
vpk: ViewingPublicKey,
},
}
@ -28,7 +28,7 @@ impl PrivacyPreservingAccount {
pub fn is_private(&self) -> bool {
matches!(
&self,
Self::PrivateOwned(_) | Self::PrivateForeign { npk: _, ipk: _ }
Self::PrivateOwned(_) | Self::PrivateForeign { npk: _, vpk: _ }
)
}
}
@ -36,7 +36,7 @@ impl PrivacyPreservingAccount {
pub struct PrivateAccountKeys {
pub npk: NullifierPublicKey,
pub ssk: SharedSecretKey,
pub ipk: IncomingViewingPublicKey,
pub vpk: ViewingPublicKey,
pub epk: EphemeralPublicKey,
}
@ -80,13 +80,13 @@ impl AccountManager {
(State::Private(pre), mask)
}
PrivacyPreservingAccount::PrivateForeign { npk, ipk } => {
PrivacyPreservingAccount::PrivateForeign { npk, vpk } => {
let acc = nssa_core::account::Account::default();
let auth_acc = AccountWithMetadata::new(acc, false, &npk);
let pre = AccountPreparedData {
nsk: None,
npk,
ipk,
vpk,
pre_state: auth_acc,
proof: None,
};
@ -138,8 +138,8 @@ impl AccountManager {
Some(PrivateAccountKeys {
npk: pre.npk.clone(),
ssk: eph_holder.calculate_shared_secret_sender(&pre.ipk),
ipk: pre.ipk.clone(),
ssk: eph_holder.calculate_shared_secret_sender(&pre.vpk),
vpk: pre.vpk.clone(),
epk: eph_holder.generate_ephemeral_public_key(),
})
}
@ -192,7 +192,7 @@ impl AccountManager {
struct AccountPreparedData {
nsk: Option<NullifierSecretKey>,
npk: NullifierPublicKey,
ipk: IncomingViewingPublicKey,
vpk: ViewingPublicKey,
pre_state: AccountWithMetadata,
proof: Option<MembershipProof>,
}
@ -213,7 +213,7 @@ async fn private_acc_preparation(
let nsk = from_keys.private_key_holder.nullifier_secret_key;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let from_vpk = from_keys.viewing_public_key;
// TODO: Remove this unwrap, error types must be compatible
let proof = wallet
@ -228,7 +228,7 @@ async fn private_acc_preparation(
Ok(AccountPreparedData {
nsk: Some(nsk),
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
pre_state: sender_pre,
proof,
})

View File

@ -20,6 +20,9 @@ fn auth_transfer_preparation(
) {
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
let program = Program::authenticated_transfer_program();
// TODO: handle large Err-variant properly
#[allow(clippy::result_large_err)]
let tx_pre_check = move |accounts: &[&Account]| {
let from = accounts[0];
if from.balance >= balance_to_move {

View File

@ -2,7 +2,7 @@ use std::vec;
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
use nssa::{AccountId, program::Program};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
use super::{NativeTokenTransfer, auth_transfer_preparation};
use crate::PrivacyPreservingAccount;
@ -32,7 +32,7 @@ impl NativeTokenTransfer<'_> {
&self,
from: AccountId,
to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey,
to_vpk: ViewingPublicKey,
balance_to_move: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
@ -43,7 +43,7 @@ impl NativeTokenTransfer<'_> {
PrivacyPreservingAccount::PrivateOwned(from),
PrivacyPreservingAccount::PrivateForeign {
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
},
],
instruction_data,

View File

@ -1,6 +1,6 @@
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
use nssa::AccountId;
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
use super::{NativeTokenTransfer, auth_transfer_preparation};
use crate::PrivacyPreservingAccount;
@ -38,7 +38,7 @@ impl NativeTokenTransfer<'_> {
&self,
from: AccountId,
to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey,
to_vpk: ViewingPublicKey,
balance_to_move: u128,
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move);
@ -49,7 +49,7 @@ impl NativeTokenTransfer<'_> {
PrivacyPreservingAccount::Public(from),
PrivacyPreservingAccount::PrivateForeign {
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
},
],
instruction_data,

View File

@ -1,6 +1,6 @@
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
use nssa::{AccountId, program::Program};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey};
use nssa_core::{NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey};
use token_core::Instruction;
use crate::{PrivacyPreservingAccount, WalletCore};
@ -194,7 +194,7 @@ impl Token<'_> {
&self,
sender_account_id: AccountId,
recipient_npk: NullifierPublicKey,
recipient_ipk: IncomingViewingPublicKey,
recipient_vpk: ViewingPublicKey,
amount: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let instruction = Instruction::Transfer {
@ -209,7 +209,7 @@ impl Token<'_> {
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
PrivacyPreservingAccount::PrivateForeign {
npk: recipient_npk,
ipk: recipient_ipk,
vpk: recipient_vpk,
},
],
instruction_data,
@ -290,7 +290,7 @@ impl Token<'_> {
&self,
sender_account_id: AccountId,
recipient_npk: NullifierPublicKey,
recipient_ipk: IncomingViewingPublicKey,
recipient_vpk: ViewingPublicKey,
amount: u128,
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
let instruction = Instruction::Transfer {
@ -305,7 +305,7 @@ impl Token<'_> {
PrivacyPreservingAccount::Public(sender_account_id),
PrivacyPreservingAccount::PrivateForeign {
npk: recipient_npk,
ipk: recipient_ipk,
vpk: recipient_vpk,
},
],
instruction_data,
@ -525,7 +525,7 @@ impl Token<'_> {
&self,
definition_account_id: AccountId,
holder_npk: NullifierPublicKey,
holder_ipk: IncomingViewingPublicKey,
holder_vpk: ViewingPublicKey,
amount: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let instruction = Instruction::Mint {
@ -540,7 +540,7 @@ impl Token<'_> {
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
PrivacyPreservingAccount::PrivateForeign {
npk: holder_npk,
ipk: holder_ipk,
vpk: holder_vpk,
},
],
instruction_data,
@ -621,7 +621,7 @@ impl Token<'_> {
&self,
definition_account_id: AccountId,
holder_npk: NullifierPublicKey,
holder_ipk: IncomingViewingPublicKey,
holder_vpk: ViewingPublicKey,
amount: u128,
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
let instruction = Instruction::Mint {
@ -636,7 +636,7 @@ impl Token<'_> {
PrivacyPreservingAccount::Public(definition_account_id),
PrivacyPreservingAccount::PrivateForeign {
npk: holder_npk,
ipk: holder_ipk,
vpk: holder_vpk,
},
],
instruction_data,

View File

@ -7,7 +7,7 @@ use nssa::{
};
use nssa_core::{
Commitment, MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
account::AccountWithMetadata, encryption::IncomingViewingPublicKey, program::InstructionData,
account::AccountWithMetadata, encryption::ViewingPublicKey, program::InstructionData,
};
use crate::{WalletCore, helperfunctions::produce_random_nonces};
@ -15,7 +15,7 @@ use crate::{WalletCore, helperfunctions::produce_random_nonces};
pub(crate) struct AccountPreparedData {
pub nsk: Option<NullifierSecretKey>,
pub npk: NullifierPublicKey,
pub ipk: IncomingViewingPublicKey,
pub vpk: ViewingPublicKey,
pub auth_acc: AccountWithMetadata,
pub proof: Option<MembershipProof>,
}
@ -40,7 +40,7 @@ impl WalletCore {
let mut proof = None;
let from_npk = from_keys.nullifer_public_key;
let from_ipk = from_keys.incoming_viewing_public_key;
let from_vpk = from_keys.viewing_public_key;
let sender_commitment = Commitment::new(&from_npk, &from_acc);
@ -61,7 +61,7 @@ impl WalletCore {
Ok(AccountPreparedData {
nsk,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof,
})
@ -79,7 +79,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: from_nsk,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
@ -87,7 +87,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: to_nsk,
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, true, false).await?;
@ -95,10 +95,10 @@ impl WalletCore {
tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_vpk);
let eph_holder_to = EphemeralKeyHolder::new(&to_npk);
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk);
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -123,12 +123,12 @@ impl WalletCore {
vec![
(
from_npk.clone(),
from_ipk.clone(),
from_vpk.clone(),
eph_holder_from.generate_ephemeral_public_key(),
),
(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder_to.generate_ephemeral_public_key(),
),
],
@ -156,7 +156,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: from_nsk,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
@ -164,7 +164,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: _,
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, false, false).await?;
@ -172,10 +172,10 @@ impl WalletCore {
tx_pre_check(&sender_pre.account, &recipient_pre.account)?;
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_vpk);
let eph_holder_to = EphemeralKeyHolder::new(&to_npk);
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk);
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -197,12 +197,12 @@ impl WalletCore {
vec![
(
from_npk.clone(),
from_ipk.clone(),
from_vpk.clone(),
eph_holder_from.generate_ephemeral_public_key(),
),
(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder_to.generate_ephemeral_public_key(),
),
],
@ -223,7 +223,7 @@ impl WalletCore {
&self,
from: AccountId,
to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey,
to_vpk: ViewingPublicKey,
instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program,
@ -231,7 +231,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: from_nsk,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
@ -244,8 +244,8 @@ impl WalletCore {
let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_ipk);
let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_ipk);
let shared_secret_from = eph_holder.calculate_shared_secret_sender(&from_vpk);
let shared_secret_to = eph_holder.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -267,12 +267,12 @@ impl WalletCore {
vec![
(
from_npk.clone(),
from_ipk.clone(),
from_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
),
(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
),
],
@ -301,7 +301,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: from_nsk,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof: from_proof,
} = self.private_acc_preparation(from, true, true).await?;
@ -315,7 +315,7 @@ impl WalletCore {
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, to);
let eph_holder = EphemeralKeyHolder::new(&from_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&from_ipk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&from_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -333,7 +333,7 @@ impl WalletCore {
vec![],
vec![(
from_npk.clone(),
from_ipk.clone(),
from_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
)],
output,
@ -366,7 +366,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: to_nsk,
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, true, false).await?;
@ -376,7 +376,7 @@ impl WalletCore {
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -394,7 +394,7 @@ impl WalletCore {
vec![from_acc.nonce],
vec![(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
)],
output,
@ -432,7 +432,7 @@ impl WalletCore {
let AccountPreparedData {
nsk: _,
npk: to_npk,
ipk: to_ipk,
vpk: to_vpk,
auth_acc: recipient_pre,
proof: _,
} = self.private_acc_preparation(to, false, false).await?;
@ -442,7 +442,7 @@ impl WalletCore {
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -460,7 +460,7 @@ impl WalletCore {
vec![from_acc.nonce],
vec![(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
)],
output,
@ -487,7 +487,7 @@ impl WalletCore {
&self,
from: AccountId,
to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey,
to_vpk: ViewingPublicKey,
instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program,
@ -504,7 +504,7 @@ impl WalletCore {
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
let eph_holder = EphemeralKeyHolder::new(&to_npk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_vpk);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
@ -522,7 +522,7 @@ impl WalletCore {
vec![from_acc.nonce],
vec![(
to_npk.clone(),
to_ipk.clone(),
to_vpk.clone(),
eph_holder.generate_ephemeral_public_key(),
)],
output,
@ -548,13 +548,13 @@ impl WalletCore {
let AccountPreparedData {
nsk: _,
npk: from_npk,
ipk: from_ipk,
vpk: from_vpk,
auth_acc: sender_pre,
proof: _,
} = self.private_acc_preparation(from, false, false).await?;
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_vpk);
let instruction: u128 = 0;
@ -574,7 +574,7 @@ impl WalletCore {
vec![],
vec![(
from_npk.clone(),
from_ipk.clone(),
from_vpk.clone(),
eph_holder_from.generate_ephemeral_public_key(),
)],
output,