diff --git a/wallet-core/Cargo.toml b/wallet-core/Cargo.toml index f4e3630552..74b5a46a9c 100644 --- a/wallet-core/Cargo.toml +++ b/wallet-core/Cargo.toml @@ -12,5 +12,7 @@ rand_chacha = { version = "0.3", default-features = false } sha2 = { version = "0.10", default-features = false } [dev-dependencies] +rand = "0.8" +ff = { version = "0.13", default-features = false } [features] diff --git a/wallet-core/src/lib.rs b/wallet-core/src/lib.rs index 85f0d38093..87860d4b9f 100644 --- a/wallet-core/src/lib.rs +++ b/wallet-core/src/lib.rs @@ -4,14 +4,54 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -//! Types used for interacting with Dusk's transfer and stake contracts. +//! Implementations of basic wallet functionalities. #![cfg_attr(target_family = "wasm", no_std)] #![deny(missing_docs)] #![deny(rustdoc::broken_intra_doc_links)] #![deny(clippy::pedantic)] +extern crate alloc; + pub mod keys; /// Length of the seed of the generated rng. pub const RNG_SEED: usize = 64; + +// The maximum amount of input notes that can be spend in one +// phoenix-transaction +const MAX_INPUT_NOTES: usize = 4; + +use alloc::vec::Vec; + +use execution_core::transfer::phoenix::{Note, ViewKey as PhoenixViewKey}; + +/// Calculate the sum for all the given [`Note`]s that belong to the given +/// [`PhoenixViewKey`]. +pub fn phoenix_balance( + phoenix_vk: &PhoenixViewKey, + notes: impl AsRef<[Note]>, +) -> BalanceInfo { + let mut values: Vec = Vec::new(); + notes.as_ref().iter().for_each(|note| { + values.push(note.value(Some(phoenix_vk)).unwrap_or_default()) + }); + + values.sort_by(|a, b| b.cmp(a)); + + BalanceInfo { + value: values.iter().sum(), + spendable: values[..MAX_INPUT_NOTES].iter().sum(), + } +} + +/// Information about the balance of a particular key. +#[derive(Debug, Default, Hash, Clone, Copy, PartialEq, Eq)] +pub struct BalanceInfo { + /// The total value of the balance. + pub value: u64, + /// The maximum _spendable_ value in a single transaction. This is + /// different from `value` since there is a maximum number of notes one can + /// spend. + pub spendable: u64, +} diff --git a/wallet-core/tests/balance.rs b/wallet-core/tests/balance.rs new file mode 100644 index 0000000000..7bbf6a560a --- /dev/null +++ b/wallet-core/tests/balance.rs @@ -0,0 +1,72 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use ff::Field; +use rand::rngs::StdRng; +use rand::SeedableRng; + +use execution_core::{ + transfer::phoenix::{ + Note, PublicKey as PhoenixPublicKey, SecretKey as PhoenixSecretKey, + }, + JubJubScalar, +}; + +use wallet_core::{phoenix_balance, BalanceInfo}; + +#[test] +fn test_balance() { + let mut rng = StdRng::seed_from_u64(0xdab); + + let owner_sk = PhoenixSecretKey::random(&mut rng); + let owner_pk = PhoenixPublicKey::from(&owner_sk); + let sender_pk = PhoenixPublicKey::from(&PhoenixSecretKey::random(&mut rng)); + + let mut notes = Vec::new(); + + // create the notes + for value in 0..=10 { + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + // we want to test with a mix of transparent and obfuscated notes so we + // make every 10th note transparent + let note = if value % 10 == 0 { + Note::transparent( + &mut rng, + &sender_pk, + &owner_pk, + value, + sender_blinder, + ) + } else { + Note::obfuscated( + &mut rng, + &sender_pk, + &owner_pk, + value, + value_blinder, + sender_blinder, + ) + }; + notes.push(note); + } + + // the sum of these notes should be 5 * 11 = 55 + // and the spendable notes are 7 + 8 + 9 + 10 = 34 + let expected_balance = BalanceInfo { + value: 55, + spendable: 34, + }; + + assert_eq!( + phoenix_balance(&(&owner_sk).into(), notes), + expected_balance + ); +} diff --git a/wallet-core/tests/keys_derive.rs b/wallet-core/tests/keys.rs similarity index 99% rename from wallet-core/tests/keys_derive.rs rename to wallet-core/tests/keys.rs index cf0e1fbcc5..5eaf1b2442 100644 --- a/wallet-core/tests/keys_derive.rs +++ b/wallet-core/tests/keys.rs @@ -5,6 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use dusk_bytes::Serializable; + use wallet_core::keys::{ derive_bls_sk, derive_phoenix_pk, derive_phoenix_sk, derive_phoenix_vk, };