diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e4b84..5c2f56d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add support for phoenix_core methods - Add support for stake contract functions - Add support for transfer contract functions +- Update dependencies for new phoenix_core ### Changed - Change the whole api to support `wasm32-unkonwn-unknown` @@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix the input selecting algorithm from custom new one to old wallet-core to fix wrong picking of notes - Fix the execute to work with only one public spend key and one `Transaction` - Fix double rkyv serialization bug #113 +- Fix memory allocation bug with `mem::forget` ## [Old Changelog below] @@ -133,6 +135,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Expose `NodeClient` and `Store` through FFI - Define FFI and compile it only for WASM +[#113]: https://github.com/dusk-network/wallet-core/issues/113 [#58]: https://github.com/dusk-network/wallet-core/issues/58 [#55]: https://github.com/dusk-network/wallet-core/issues/55 [#53]: https://github.com/dusk-network/wallet-core/issues/53 @@ -141,7 +144,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#44]: https://github.com/dusk-network/wallet-core/issues/44 [#41]: https://github.com/dusk-network/wallet-core/issues/41 [#40]: https://github.com/dusk-network/wallet-core/issues/40 -[#113]: https://github.com/dusk-network/wallet-core/issues/113 [#34]: https://github.com/dusk-network/wallet-core/issues/34 [#31]: https://github.com/dusk-network/wallet-core/issues/31 [#25]: https://github.com/dusk-network/wallet-core/issues/25 diff --git a/src/compat/allow.rs b/src/compat/allow.rs deleted file mode 100644 index b3cc3bf..0000000 --- a/src/compat/allow.rs +++ /dev/null @@ -1,108 +0,0 @@ -// 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 crate::{key::*, types, utils, MAX_LEN}; - -use alloc::string::String; - -use bls12_381_bls::PublicKey as StakePublicKey; -use dusk_jubjub::JubJubScalar; -use ff::Field; -use phoenix_core::{ - transaction::{allow_signature_message, Allow}, - Crossover, Fee, Note, PublicKey, -}; - -/// Get unstake call data -#[no_mangle] -pub fn get_allow_call_data(args: i32, len: i32) -> i64 { - let types::GetAllowCallDataArgs { - seed, - rng_seed, - sender_index, - refund, - owner_index, - counter, - gas_limit, - gas_price, - } = match utils::take_args(args, len) { - Some(a) => a, - None => return utils::fail(), - }; - - let rng_seed = match utils::sanitize_rng_seed(rng_seed) { - Some(s) => s, - None => return utils::fail(), - }; - - let seed = match utils::sanitize_seed(seed) { - Some(s) => s, - None => return utils::fail(), - }; - - let refund: PublicKey = match utils::bs58_to_pk(&refund) { - Some(a) => a, - None => return utils::fail(), - }; - - let stake_sk = derive_stake_sk(&seed, owner_index); - let staker_pk = StakePublicKey::from(&stake_sk); - - let owner_sk = derive_stake_sk(&seed, sender_index); - let owner_pk = StakePublicKey::from(&owner_sk); - - let rng = &mut utils::rng(rng_seed); - - let msg = allow_signature_message(counter, staker_pk); - let signature = owner_sk.sign(&owner_pk, &msg); - - let blinder = JubJubScalar::random(&mut *rng); - let note = Note::obfuscated(rng, &refund, 0, blinder); - let (mut fee, crossover) = note - .try_into() - .expect("Obfuscated notes should always yield crossovers"); - - fee.gas_limit = gas_limit; - fee.gas_price = gas_price; - - let allow = Allow { - public_key: staker_pk, - owner: owner_pk, - signature, - }; - - let contract = bs58::encode(rusk_abi::STAKE_CONTRACT).into_string(); - let method = String::from("allow"); - let payload = match rkyv::to_bytes::<_, MAX_LEN>(&allow).ok() { - Some(a) => a.to_vec(), - None => return utils::fail(), - }; - - let crossover = match rkyv::to_bytes::(&crossover) { - Ok(a) => a.to_vec(), - Err(_) => return utils::fail(), - }; - - let blinder = match rkyv::to_bytes::(&blinder) { - Ok(a) => a.to_vec(), - Err(_) => return utils::fail(), - }; - - let fee = match rkyv::to_bytes::(&fee) { - Ok(a) => a.to_vec(), - Err(_) => return utils::fail(), - }; - - // reusing this type - utils::into_ptr(types::GetAllowCallDataResponse { - contract, - method, - payload, - blinder, - crossover, - fee, - }) -} diff --git a/src/compat/crypto.rs b/src/compat/crypto.rs index 26f7f32..042d809 100644 --- a/src/compat/crypto.rs +++ b/src/compat/crypto.rs @@ -29,14 +29,16 @@ const TREE_LEAF_SIZE: usize = size_of::(); /// if its true then nullifier of that note if sent with it #[no_mangle] pub fn check_note_ownership(args: i32, len: i32) -> i64 { - let args = utils::take_args_raw(args, len); + // SAFETY: We assume the caller has passed a valid pointer and len as the + // function arguments else we might get undefined behavior + let args = unsafe { core::slice::from_raw_parts(args as _, len as _) }; let seed = &args[..64]; let leaves: &[u8] = &args[64..]; - let seed = match seed.try_into().ok() { - Some(s) => s, - None => return utils::fail(), + let seed = match seed.try_into() { + Ok(s) => s, + Err(_) => return utils::fail(), }; let mut leaf_chunk = leaves.chunks_exact(TREE_LEAF_SIZE); @@ -46,24 +48,31 @@ pub fn check_note_ownership(args: i32, len: i32) -> i64 { let mut nullifiers = Vec::new(); let mut block_heights = Vec::new(); let mut public_spend_keys = Vec::new(); + let mut view_keys = Vec::with_capacity(MAX_KEY); + let mut secret_keys = Vec::with_capacity(MAX_KEY); + + for idx in 0..MAX_KEY { + let idx = idx as u64; + let view_key = key::derive_vk(&seed, idx); + let sk = key::derive_sk(&seed, idx as _); + view_keys.push(view_key); + secret_keys.push(sk); + } for leaf_bytes in leaf_chunk.by_ref() { - let TreeLeaf { block_height, note } = - match rkyv::from_bytes(leaf_bytes).ok() { - Some(a) => a, - None => { - return utils::fail(); - } - }; + let TreeLeaf { block_height, note } = match rkyv::from_bytes(leaf_bytes) + { + Ok(a) => a, + Err(_) => { + return utils::fail(); + } + }; last_pos = core::cmp::max(last_pos, *note.pos()); for idx in 0..=MAX_KEY { - let idx = idx as u64; - let view_key = key::derive_vk(&seed, idx); - - if view_key.owns(¬e) { - let sk = key::derive_sk(&seed, idx); + if view_keys[idx].owns(¬e) { + let sk = secret_keys[idx]; let nullifier = note.gen_nullifier(&sk); let nullifier_found = @@ -77,9 +86,9 @@ pub fn check_note_ownership(args: i32, len: i32) -> i64 { bs58::encode(PublicKey::from(sk).to_bytes()).into_string(); let raw_note: Vec = - match rkyv::to_bytes::(¬e).ok() { - Some(n) => n.to_vec(), - None => return utils::fail(), + match rkyv::to_bytes::(¬e) { + Ok(n) => n.to_vec(), + Err(_) => return utils::fail(), }; notes.push(raw_note.to_owned()); diff --git a/src/ffi.rs b/src/ffi.rs index f22002e..e3e2846 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -92,7 +92,7 @@ pub fn balance(args: i32, len: i32) -> i64 { Err(_) => return utils::fail(), }; - let mut keys = unsafe { [mem::zeroed(); MAX_KEY + 1] }; + let mut keys = unsafe { [mem::zeroed(); MAX_KEY] }; let mut values = Vec::with_capacity(notes.len()); let mut keys_len = 0; let mut sum = 0u64; @@ -100,7 +100,7 @@ pub fn balance(args: i32, len: i32) -> i64 { 'outer: for note in notes { // we iterate all the available keys until one can successfully decrypt // the note. if all fails, returns false - for idx in 0..=MAX_KEY { + for idx in 0..MAX_KEY { if keys_len == idx { keys[idx] = key::derive_vk(&seed, idx as u64); keys_len += 1; @@ -355,7 +355,7 @@ pub fn public_keys(args: i32, len: i32) -> i64 { None => return utils::fail(), }; - let keys = (0..=MAX_KEY) + let keys = (0..MAX_KEY) .map(|idx| key::derive_pk(&seed, idx as u64)) .map(|pk| bs58::encode(pk.to_bytes()).into_string()) .collect(); @@ -382,7 +382,7 @@ pub fn view_keys(args: i32, len: i32) -> i64 { None => return utils::fail(), }; - let keys: Vec<_> = (0..=MAX_KEY) + let keys: Vec<_> = (0..MAX_KEY) .map(|idx| key::derive_vk(&seed, idx as u64)) .collect(); @@ -416,14 +416,14 @@ pub fn nullifiers(args: i32, len: i32) -> i64 { }; let mut nullifiers = Vec::with_capacity(notes.len()); - let mut sks = unsafe { [mem::zeroed(); MAX_KEY + 1] }; - let mut vks = unsafe { [mem::zeroed(); MAX_KEY + 1] }; + let mut sks = unsafe { [mem::zeroed(); MAX_KEY] }; + let mut vks = unsafe { [mem::zeroed(); MAX_KEY] }; let mut keys_len = 0; 'outer: for note in notes { // we iterate all the available view key until one can successfully // decrypt the note. if any fails, returns false - for idx in 0..=MAX_KEY { + for idx in 0..MAX_KEY { if keys_len == idx { sks[idx] = key::derive_sk(&seed, idx as u64); vks[idx] = ViewKey::from(&sks[idx]); diff --git a/src/utils.rs b/src/utils.rs index 77405c1..bbccded 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -63,14 +63,6 @@ where serde_json::from_str(&args).ok() } -/// reads the raw bytes at the pointer for the length and returns what it reason -pub fn take_args_raw<'a>(args: i32, len: i32) -> &'a [u8] { - let args = args as *mut u8; - let len = len as usize; - - unsafe { core::slice::from_raw_parts(args, len) } -} - /// Sanitizes arbitrary bytes into well-formed seed. pub fn sanitize_seed(bytes: Vec) -> Option<[u8; RNG_SEED]> { (bytes.len() == RNG_SEED).then(|| { diff --git a/tests/wallet.rs b/tests/wallet.rs index 0b5d077..bd898ca 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -200,7 +200,7 @@ fn public_keys_works() { PublicKey::from_bytes(&key_array).unwrap(); } - assert_eq!(keys.len(), MAX_KEY + 1); + assert_eq!(keys.len(), MAX_KEY); } #[test] @@ -336,8 +336,7 @@ mod node { .into_iter() .map(|value| { let obfuscated = (rng.next_u32() & 1) == 1; - let idx = rng.next_u64() - % (if MAX_KEY == 0 { 1 } else { MAX_KEY }) as u64; + let idx = rng.next_u64() % (MAX_KEY) as u64; let sk = key::derive_sk(seed, idx); let pk = PublicKey::from(&sk);