From ae4777423486caf2027d008a0e7f8ef0587f9691 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Tue, 14 Mar 2023 17:49:41 +0100 Subject: [PATCH 01/34] checkpoint --- manta-accounting/src/wallet/signer/mod.rs | 39 +++++++++++++++++++++++ manta-pay/src/signer/base.rs | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index ed1055eb0..35515fe9d 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -108,6 +108,45 @@ where TransferPost: Clone; } +/// Signer Initial Synchronization Data +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde( + bound( + deserialize = r" + Utxo: Deserialize<'de>, + UtxoMembershipProof: Deserialize<'de> + ", + serialize = r" + Utxo: Serialize, + UtxoMembershipProof: Serialize + ", + ), + crate = "manta_util::serde", + deny_unknown_fields + ) +)] +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "Utxo: Clone, UtxoMembershipProof: Clone"), + Debug(bound = "Utxo: Debug, UtxoMembershipProof: Debug"), + Default(bound = ""), + Eq(bound = "Utxo: Eq, UtxoMembershipProof: Eq"), + Hash(bound = "Utxo: Hash, UtxoMembershipProof: Hash"), + PartialEq(bound = "Utxo: PartialEq, UtxoMembershipProof: PartialEq") +)] +pub struct InitialSyncData +where + C: transfer::Configuration + ?Sized, +{ + /// UTXO Data + pub utxo_data: Vec>, + + /// Membership Proof Data + pub membership_proof_data: manta_util::Array, NUMBER_OF_PROOFS>, +} + /// Signer Synchronization Data #[cfg_attr( feature = "serde", diff --git a/manta-pay/src/signer/base.rs b/manta-pay/src/signer/base.rs index b4c3c8ef2..ab0635a22 100644 --- a/manta-pay/src/signer/base.rs +++ b/manta-pay/src/signer/base.rs @@ -79,7 +79,7 @@ pub type UtxoAccumulator = merkle_tree::forest::TreeArrayMerkleForest< MerkleTreeConfiguration, merkle_tree::fork::ForkedTree< MerkleTreeConfiguration, - merkle_tree::full::Full, + merkle_tree::partial::Partial, >, { MerkleTreeConfiguration::FOREST_WIDTH }, >; From df6edd41ccb728121228982b0c88aa95f807fc3a Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 11:48:08 +0100 Subject: [PATCH 02/34] checkpoint --- .../src/wallet/signer/functions.rs | 65 ++++++++++++++++++- manta-accounting/src/wallet/signer/mod.rs | 22 ++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index bbc474f53..f2bfb0f6b 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -35,9 +35,9 @@ use crate::{ UtxoAccumulatorItem, UtxoAccumulatorModel, }, wallet::signer::{ - AccountTable, BalanceUpdate, Checkpoint, Configuration, SignError, SignResponse, - SignWithTransactionDataResponse, SignWithTransactionDataResult, SignerParameters, SyncData, - SyncError, SyncRequest, SyncResponse, + AccountTable, BalanceUpdate, Checkpoint, Configuration, InitialSyncData, SignError, + SignResponse, SignWithTransactionDataResponse, SignWithTransactionDataResult, + SignerParameters, SyncData, SyncError, SyncRequest, SyncResponse, }, }; use alloc::{vec, vec::Vec}; @@ -933,3 +933,62 @@ where .collect(), )) } + +/// Updates `assets`, `checkpoint` and `utxo_accumulator`, returning the new asset distribution. +#[inline] +pub fn intial_sync( + parameters: &SignerParameters, + authorization_context: &mut AuthorizationContext, + assets: &mut C::AssetMap, + checkpoint: &mut C::Checkpoint, + utxo_accumulator: &mut C::UtxoAccumulator, + request: InitialSyncData, + rng: &mut C::Rng, +) -> Result, SyncError> +where + C: Configuration, +{ + let InitialSyncData { + utxo_data, + membership_proof_data, + nullifier_data, + } = request; + let response = initial_sync_with::( + authorization_context, + assets, + checkpoint, + utxo_accumulator, + ¶meters.parameters, + utxo_data, + nullifier_data, + rng, + ); + utxo_accumulator.commit(); + Ok(response) +} + +/// Updates the internal ledger state, returning the new asset distribution. +#[allow(clippy::too_many_arguments)] +#[inline] +fn initial_sync_with( + authorization_context: &mut AuthorizationContext, + assets: &mut C::AssetMap, + checkpoint: &mut C::Checkpoint, + utxo_accumulator: &mut C::UtxoAccumulator, + parameters: &Parameters, + utxos: Vec>, + nullifiers: Vec>, + rng: &mut C::Rng, +) -> SyncResponse +where + C: Configuration, +{ + checkpoint.update_from_nullifiers(nullifiers.len()); + checkpoint.update_from_utxo_accumulator(utxo_accumulator); + SyncResponse { + checkpoint: checkpoint.clone(), + balance_update: BalanceUpdate::Full { + assets: assets.assets().into(), + }, + } +} diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 35515fe9d..466158470 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -116,11 +116,13 @@ where bound( deserialize = r" Utxo: Deserialize<'de>, - UtxoMembershipProof: Deserialize<'de> + UtxoMembershipProof: Deserialize<'de>, + Nullifier: Deserialize<'de>, ", serialize = r" Utxo: Serialize, - UtxoMembershipProof: Serialize + UtxoMembershipProof: Serialize, + Nullifier: Serialize, ", ), crate = "manta_util::serde", @@ -129,12 +131,13 @@ where )] #[derive(derivative::Derivative)] #[derivative( - Clone(bound = "Utxo: Clone, UtxoMembershipProof: Clone"), - Debug(bound = "Utxo: Debug, UtxoMembershipProof: Debug"), - Default(bound = ""), - Eq(bound = "Utxo: Eq, UtxoMembershipProof: Eq"), - Hash(bound = "Utxo: Hash, UtxoMembershipProof: Hash"), - PartialEq(bound = "Utxo: PartialEq, UtxoMembershipProof: PartialEq") + Clone(bound = "Utxo: Clone, UtxoMembershipProof: Clone, Nullifier: Clone"), + Debug(bound = "Utxo: Debug, UtxoMembershipProof: Debug, Nullifier: Debug"), + Eq(bound = "Utxo: Eq, UtxoMembershipProof: Eq, Nullifier: Eq"), + Hash(bound = "Utxo: Hash, UtxoMembershipProof: Hash, Nullifier: Hash"), + PartialEq( + bound = "Utxo: PartialEq, UtxoMembershipProof: PartialEq, Nullifier: PartialEq" + ) )] pub struct InitialSyncData where @@ -143,6 +146,9 @@ where /// UTXO Data pub utxo_data: Vec>, + /// Nullifier Data + pub nullifier_data: Vec>, + /// Membership Proof Data pub membership_proof_data: manta_util::Array, NUMBER_OF_PROOFS>, } From 164057a33be83fcf158cd7917cf576e767e99b88 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 13:32:04 +0100 Subject: [PATCH 03/34] checkpoint --- manta-accounting/src/wallet/signer/functions.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index f2bfb0f6b..fd909aea0 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -32,7 +32,7 @@ use crate::{ Address, Asset, AssociatedData, Authorization, AuthorizationContext, FullParametersRef, IdentifiedAsset, Identifier, IdentityProof, Note, Nullifier, Parameters, PreSender, ProvingContext, Receiver, Sender, Shape, SpendingKey, Transfer, TransferPost, Utxo, - UtxoAccumulatorItem, UtxoAccumulatorModel, + UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoMembershipProof, }, wallet::signer::{ AccountTable, BalanceUpdate, Checkpoint, Configuration, InitialSyncData, SignError, @@ -46,6 +46,7 @@ use manta_crypto::{ rand::Rand, }; use manta_util::{ + Array, array_map, cmp::Independence, into_array_unchecked, iter::IteratorExt, persistence::Rollback, vec::VecExt, }; @@ -953,13 +954,14 @@ where membership_proof_data, nullifier_data, } = request; - let response = initial_sync_with::( + let response = initial_sync_with::( authorization_context, assets, checkpoint, utxo_accumulator, ¶meters.parameters, utxo_data, + membership_proof_data, nullifier_data, rng, ); @@ -970,13 +972,14 @@ where /// Updates the internal ledger state, returning the new asset distribution. #[allow(clippy::too_many_arguments)] #[inline] -fn initial_sync_with( +fn initial_sync_with( authorization_context: &mut AuthorizationContext, assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, parameters: &Parameters, utxos: Vec>, + membership_proof_data: Array, NUMBER_OF_PROOFS>, nullifiers: Vec>, rng: &mut C::Rng, ) -> SyncResponse From 60c5eb8c4018275c9246ef13798f691c253335d4 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 17:27:50 +0100 Subject: [PATCH 04/34] merkle tree functions --- .../src/wallet/signer/functions.rs | 3 +- manta-crypto/src/merkle_tree/forest.rs | 65 +++++++++++++++++++ manta-crypto/src/merkle_tree/fork.rs | 21 ++++++ manta-crypto/src/merkle_tree/partial.rs | 32 +++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index fd909aea0..8d30ebc93 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -46,9 +46,8 @@ use manta_crypto::{ rand::Rand, }; use manta_util::{ - Array, array_map, cmp::Independence, into_array_unchecked, iter::IteratorExt, persistence::Rollback, - vec::VecExt, + vec::VecExt, Array, }; /// Returns the default account for `accounts`. diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 959278dd8..2f2a6a166 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -30,6 +30,7 @@ use crate::{ merkle_tree::{ fork::ForkedTree, inner_tree::InnerMap, + partial::Partial, path::Path, tree::{self, Leaf, Parameters, Root, Tree}, InnerDigest, LeafDigest, WithProofs, @@ -525,6 +526,70 @@ where } } +impl TreeArray, N> +where + C: Configuration + ?Sized, + C::Index: FixedIndex, + LeafDigest: Clone + Default, + InnerDigest: Clone + Default + PartialEq, +{ + /// Builds a new [`TreeArray`] from `leaves` and `paths` without checking that + /// the `paths` are consistent with the leaves and that they are + /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. + #[inline] + pub fn from_leaves_and_current_paths_unchecked( + parameters: &Parameters, + leaves: Vec>, + paths: BoxArray, N>, + ) -> Self { + TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( + |(tree_index, path)| { + Partial::from_leaves_and_path_unchecked( + parameters, + leaves + .iter() + .filter(|leaf| C::tree_index(leaf).into() == tree_index) + .map(|leaf| parameters.digest(leaf)) + .collect(), + path, + ) + }, + ))) + } +} + +impl TreeArray>, N> +where + C: Configuration + ?Sized, + C::Index: FixedIndex, + LeafDigest: Clone + Default, + InnerDigest: Clone + Default + PartialEq, +{ + /// Builds a new [`TreeArray`] from `leaves` and `paths` without checking that + /// the `paths` are consistent with the leaves and that they are + /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. + #[inline] + pub fn from_leaves_and_current_paths_unchecked( + parameters: &Parameters, + leaves: Vec>, + paths: BoxArray, N>, + ) -> Self { + TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( + |(tree_index, path)| { + ForkedTree::from_leaves_and_path_unchecked( + parameters, + leaves + .iter() + .filter(|leaf| C::tree_index(leaf).into() == tree_index) + .map(|leaf| parameters.digest(leaf)) + .collect(), + path, + ) + }, + ))) + } +} + impl AsRef<[T; N]> for TreeArray where C: Configuration + ?Sized, diff --git a/manta-crypto/src/merkle_tree/fork.rs b/manta-crypto/src/merkle_tree/fork.rs index 8e6865e2e..b4a44b957 100644 --- a/manta-crypto/src/merkle_tree/fork.rs +++ b/manta-crypto/src/merkle_tree/fork.rs @@ -930,6 +930,27 @@ where } } +impl ForkedTree> +where + C: Configuration + ?Sized, + LeafDigest: Clone + Default, + InnerDigest: Clone + Default + PartialEq, +{ + /// Builds a new [`ForkedTree`] from `leaf_digests` and `path` without checking that + /// `path` is consistent with the leaves and that it is a [`CurrentPath`]. + #[inline] + pub fn from_leaves_and_path_unchecked( + parameters: &Parameters, + leaf_digests: Vec>, + path: Path, + ) -> Self { + Self::new( + Partial::from_leaves_and_path_unchecked(parameters, leaf_digests, path), + parameters, + ) + } +} + impl Tree for ForkedTree where C: Configuration + ?Sized, diff --git a/manta-crypto/src/merkle_tree/partial.rs b/manta-crypto/src/merkle_tree/partial.rs index f9cc34aae..cdf276af2 100644 --- a/manta-crypto/src/merkle_tree/partial.rs +++ b/manta-crypto/src/merkle_tree/partial.rs @@ -21,6 +21,7 @@ use crate::merkle_tree::{ capacity, inner_tree::{BTreeMap, InnerMap, PartialInnerTree}, + node::Parity, Configuration, CurrentPath, InnerDigest, Leaf, LeafDigest, MerkleTree, Node, Parameters, Path, PathError, Root, Tree, WithProofs, }; @@ -85,6 +86,37 @@ where } } + /// Builds a new [`Partial`] from `leaf_digests` and `path` without checking that + /// `path` is consistent with the leaves and that it is a [`CurrentPath`]. + #[inline] + pub fn from_leaves_and_path_unchecked( + parameters: &Parameters, + leaf_digests: Vec>, + path: Path, + ) -> Self + where + M: Default, + InnerDigest: Default + PartialEq, + { + let n = leaf_digests.len(); + if n == 0 { + Self::new_unchecked(leaf_digests, Default::default()) + } else { + let base = match Parity::from_index(n - 1) { + Parity::Left => parameters.join_leaves(&leaf_digests[n - 1], &path.sibling_digest), + Parity::Right => parameters.join_leaves(&path.sibling_digest, &leaf_digests[n - 1]), + }; + Self::new_unchecked( + leaf_digests, + PartialInnerTree::from_current( + parameters, + base, + CurrentPath::from_path_unchecked(path).inner_path, + ), + ) + } + } + /// Returns the leaf digests currently stored in the merkle tree. /// /// # Note From 6496e486481942667ec9b72e20f03b11abaf8f11 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 17:58:47 +0100 Subject: [PATCH 05/34] accumulator trait --- manta-crypto/src/accumulator.rs | 12 ++++++ manta-crypto/src/merkle_tree/forest.rs | 51 +++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 0b09f235c..979fafc87 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -17,10 +17,12 @@ //! Dynamic Cryptographic Accumulators use crate::eclair::alloc::{mode::Derived, Allocate, Allocator, Constant, Variable}; +use alloc::vec::Vec; use core::{fmt::Debug, hash::Hash}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; +use manta_util::BoxArray; /// Accumulator Membership Model Types pub trait Types { @@ -202,6 +204,16 @@ pub trait OptimizedAccumulator: Accumulator { } } +/// From Proofs and Witnesses +pub trait FromItemsAndWitnesses: Accumulator { + /// Builds a new [`Self`] from `items` and `proofs`. + fn from_items_and_witnesses( + model: &Self::Model, + items: Vec, + witnesses: BoxArray, + ) -> Self; +} + /// Accumulator Membership Proof #[cfg_attr( feature = "serde", diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 2f2a6a166..7110680a8 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -24,8 +24,8 @@ use crate::{ accumulator::{ - self, Accumulator, ConstantCapacityAccumulator, ExactSizeAccumulator, MembershipProof, - OptimizedAccumulator, + self, Accumulator, ConstantCapacityAccumulator, ExactSizeAccumulator, + FromItemsAndWitnesses, MembershipProof, OptimizedAccumulator, }, merkle_tree::{ fork::ForkedTree, @@ -590,6 +590,53 @@ where } } +impl FromItemsAndWitnesses for TreeArrayMerkleForest, N> +where + C: Configuration + ?Sized, + C::Index: FixedIndex, + Parameters: Clone, + LeafDigest: Clone + Default + PartialEq, + InnerDigest: Clone + Default + PartialEq, +{ + #[inline] + fn from_items_and_witnesses( + model: &Self::Model, + items: Vec, + witnesses: BoxArray, + ) -> Self { + Self::from_forest( + TreeArray::, N>::from_leaves_and_current_paths_unchecked( + model, items, witnesses, + ), + model.clone(), + ) + } +} + +impl FromItemsAndWitnesses + for TreeArrayMerkleForest>, N> +where + C: Configuration + ?Sized, + C::Index: FixedIndex, + Parameters: Clone, + LeafDigest: Clone + Default + PartialEq, + InnerDigest: Clone + Default + PartialEq, +{ + #[inline] + fn from_items_and_witnesses( + model: &Self::Model, + items: Vec, + witnesses: BoxArray, + ) -> Self { + Self::from_forest( + TreeArray::>, N>::from_leaves_and_current_paths_unchecked( + model, items, witnesses, + ), + model.clone(), + ) + } +} + impl AsRef<[T; N]> for TreeArray where C: Configuration + ?Sized, From e6d73f96a800d98ef664cd0b6a7a44a44c15ba92 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 18:24:13 +0100 Subject: [PATCH 06/34] signer functions --- .../src/wallet/signer/functions.rs | 28 ++++++++++++------- manta-accounting/src/wallet/signer/mod.rs | 25 +++++++++-------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index 8d30ebc93..b30c49fba 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -32,7 +32,7 @@ use crate::{ Address, Asset, AssociatedData, Authorization, AuthorizationContext, FullParametersRef, IdentifiedAsset, Identifier, IdentityProof, Note, Nullifier, Parameters, PreSender, ProvingContext, Receiver, Sender, Shape, SpendingKey, Transfer, TransferPost, Utxo, - UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoMembershipProof, + UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoAccumulatorWitness, }, wallet::signer::{ AccountTable, BalanceUpdate, Checkpoint, Configuration, InitialSyncData, SignError, @@ -42,12 +42,12 @@ use crate::{ }; use alloc::{vec, vec::Vec}; use manta_crypto::{ - accumulator::{Accumulator, ItemHashFunction, OptimizedAccumulator}, + accumulator::{Accumulator, FromItemsAndWitnesses, ItemHashFunction, OptimizedAccumulator}, rand::Rand, }; use manta_util::{ array_map, cmp::Independence, into_array_unchecked, iter::IteratorExt, persistence::Rollback, - vec::VecExt, Array, + vec::VecExt, BoxArray, }; /// Returns the default account for `accounts`. @@ -938,15 +938,15 @@ where #[inline] pub fn intial_sync( parameters: &SignerParameters, - authorization_context: &mut AuthorizationContext, assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, + utxo_accumulator_model: &UtxoAccumulatorModel, request: InitialSyncData, - rng: &mut C::Rng, ) -> Result, SyncError> where C: Configuration, + C::UtxoAccumulator: FromItemsAndWitnesses, { let InitialSyncData { utxo_data, @@ -954,15 +954,14 @@ where nullifier_data, } = request; let response = initial_sync_with::( - authorization_context, assets, checkpoint, utxo_accumulator, + utxo_accumulator_model, ¶meters.parameters, utxo_data, membership_proof_data, nullifier_data, - rng, ); utxo_accumulator.commit(); Ok(response) @@ -972,19 +971,28 @@ where #[allow(clippy::too_many_arguments)] #[inline] fn initial_sync_with( - authorization_context: &mut AuthorizationContext, assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, + utxo_accumulator_model: &UtxoAccumulatorModel, parameters: &Parameters, utxos: Vec>, - membership_proof_data: Array, NUMBER_OF_PROOFS>, + membership_proof_data: BoxArray, NUMBER_OF_PROOFS>, nullifiers: Vec>, - rng: &mut C::Rng, ) -> SyncResponse where C: Configuration, + C::UtxoAccumulator: FromItemsAndWitnesses, { + let accumulator = C::UtxoAccumulator::from_items_and_witnesses( + utxo_accumulator_model, + utxos + .iter() + .map(|utxo| item_hash::(parameters, utxo)) + .collect(), + membership_proof_data, + ); + *utxo_accumulator = accumulator; checkpoint.update_from_nullifiers(nullifiers.len()); checkpoint.update_from_utxo_accumulator(utxo_accumulator); SyncResponse { diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 4fe36855f..6a661c602 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -33,7 +33,7 @@ use crate::{ canonical::{MultiProvingContext, Transaction, TransactionData}, Address, Asset, AuthorizationContext, IdentifiedAsset, Identifier, IdentityProof, Note, Nullifier, Parameters, ProofSystemError, SpendingKey, TransferPost, Utxo, - UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoMembershipProof, + UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoAccumulatorWitness, UtxoMembershipProof, }, wallet::ledger::{self, Data}, }; @@ -116,12 +116,12 @@ where bound( deserialize = r" Utxo: Deserialize<'de>, - UtxoMembershipProof: Deserialize<'de>, + UtxoAccumulatorWitness: Deserialize<'de>, Nullifier: Deserialize<'de>, ", serialize = r" Utxo: Serialize, - UtxoMembershipProof: Serialize, + UtxoAccumulatorWitness: Serialize, Nullifier: Serialize, ", ), @@ -131,12 +131,12 @@ where )] #[derive(derivative::Derivative)] #[derivative( - Clone(bound = "Utxo: Clone, UtxoMembershipProof: Clone, Nullifier: Clone"), - Debug(bound = "Utxo: Debug, UtxoMembershipProof: Debug, Nullifier: Debug"), - Eq(bound = "Utxo: Eq, UtxoMembershipProof: Eq, Nullifier: Eq"), - Hash(bound = "Utxo: Hash, UtxoMembershipProof: Hash, Nullifier: Hash"), + Clone(bound = "Utxo: Clone, UtxoAccumulatorWitness: Clone, Nullifier: Clone"), + Debug(bound = "Utxo: Debug, UtxoAccumulatorWitness: Debug, Nullifier: Debug"), + Eq(bound = "Utxo: Eq, UtxoAccumulatorWitness: Eq, Nullifier: Eq"), + Hash(bound = "Utxo: Hash, UtxoAccumulatorWitness: Hash, Nullifier: Hash"), PartialEq( - bound = "Utxo: PartialEq, UtxoMembershipProof: PartialEq, Nullifier: PartialEq" + bound = "Utxo: PartialEq, UtxoAccumulatorWitness: PartialEq, Nullifier: PartialEq" ) )] pub struct InitialSyncData @@ -150,7 +150,7 @@ where pub nullifier_data: Vec>, /// Membership Proof Data - pub membership_proof_data: manta_util::Array, NUMBER_OF_PROOFS>, + pub membership_proof_data: manta_util::BoxArray, NUMBER_OF_PROOFS>, } /// Signer Synchronization Data @@ -708,8 +708,11 @@ pub trait Configuration: transfer::Configuration { + DeriveAddresses; /// [`Utxo`] Accumulator Type - type UtxoAccumulator: Accumulator, Model = UtxoAccumulatorModel> - + ExactSizeAccumulator + type UtxoAccumulator: Accumulator< + Item = UtxoAccumulatorItem, + Model = UtxoAccumulatorModel, + Witness = UtxoAccumulatorWitness, + > + ExactSizeAccumulator + OptimizedAccumulator + Rollback; From 8444d0127830324e0d24d4da549eec3587e3eded Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 18:47:01 +0100 Subject: [PATCH 07/34] signer initial sync --- .../src/wallet/signer/functions.rs | 26 +++++++++---------- manta-accounting/src/wallet/signer/mod.rs | 23 +++++++++++++++- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index b30c49fba..adb762cfc 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -941,7 +941,6 @@ pub fn intial_sync( assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, - utxo_accumulator_model: &UtxoAccumulatorModel, request: InitialSyncData, ) -> Result, SyncError> where @@ -953,16 +952,16 @@ where membership_proof_data, nullifier_data, } = request; - let response = initial_sync_with::( + let (accumulator, response) = initial_sync_with::( assets, checkpoint, - utxo_accumulator, - utxo_accumulator_model, + utxo_accumulator.model(), ¶meters.parameters, utxo_data, membership_proof_data, nullifier_data, ); + *utxo_accumulator = accumulator; utxo_accumulator.commit(); Ok(response) } @@ -973,13 +972,12 @@ where fn initial_sync_with( assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, - utxo_accumulator: &mut C::UtxoAccumulator, utxo_accumulator_model: &UtxoAccumulatorModel, parameters: &Parameters, utxos: Vec>, membership_proof_data: BoxArray, NUMBER_OF_PROOFS>, nullifiers: Vec>, -) -> SyncResponse +) -> (C::UtxoAccumulator, SyncResponse) where C: Configuration, C::UtxoAccumulator: FromItemsAndWitnesses, @@ -992,13 +990,15 @@ where .collect(), membership_proof_data, ); - *utxo_accumulator = accumulator; checkpoint.update_from_nullifiers(nullifiers.len()); - checkpoint.update_from_utxo_accumulator(utxo_accumulator); - SyncResponse { - checkpoint: checkpoint.clone(), - balance_update: BalanceUpdate::Full { - assets: assets.assets().into(), + checkpoint.update_from_utxo_accumulator(&accumulator); + ( + accumulator, + SyncResponse { + checkpoint: checkpoint.clone(), + balance_update: BalanceUpdate::Full { + assets: assets.assets().into(), + }, }, - } + ) } diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 6a661c602..fe79bc683 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -40,7 +40,10 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use core::{convert::Infallible, fmt::Debug, hash::Hash}; use manta_crypto::{ - accumulator::{Accumulator, ExactSizeAccumulator, ItemHashFunction, OptimizedAccumulator}, + accumulator::{ + Accumulator, ExactSizeAccumulator, FromItemsAndWitnesses, ItemHashFunction, + OptimizedAccumulator, + }, rand::{CryptoRng, FromEntropy, RngCore}, }; use manta_util::{future::LocalBoxFutureResult, persistence::Rollback}; @@ -1250,6 +1253,24 @@ where } false } + + /// + #[inline] + pub fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> Result, SyncError> + where + C::UtxoAccumulator: FromItemsAndWitnesses, + { + functions::intial_sync( + &self.parameters, + &mut self.state.assets, + &mut self.state.checkpoint, + &mut self.state.utxo_accumulator, + request, + ) + } } impl Connection for Signer From 1c18f589e3ab94316f541499c966ef749b934e8a Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 15 Mar 2023 19:19:36 +0100 Subject: [PATCH 08/34] wallet has method as well --- manta-accounting/src/wallet/mod.rs | 69 ++++++++++++++++++- .../src/wallet/signer/functions.rs | 14 ++-- manta-accounting/src/wallet/signer/mod.rs | 52 ++++++++------ manta-crypto/src/accumulator.rs | 10 +-- manta-crypto/src/merkle_tree/forest.rs | 18 +++-- manta-pay/src/signer/client/http.rs | 14 +++- manta-pay/src/signer/client/websocket.rs | 14 +++- manta-pay/src/signer/mod.rs | 3 + 8 files changed, 147 insertions(+), 47 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index f880b34f8..8b4138ed4 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -37,9 +37,9 @@ use crate::{ balance::{BTreeMapBalanceState, BalanceState}, ledger::ReadResponse, signer::{ - BalanceUpdate, IdentityRequest, IdentityResponse, SignError, SignRequest, SignResponse, - SignWithTransactionDataResponse, SyncData, SyncError, SyncRequest, SyncResponse, - TransactionDataRequest, TransactionDataResponse, + BalanceUpdate, IdentityRequest, IdentityResponse, InitialSyncData, SignError, + SignRequest, SignResponse, SignWithTransactionDataResponse, SyncData, SyncError, + SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }, }; @@ -265,6 +265,24 @@ where Ok(()) } + /// + #[inline] + pub async fn initial_sync(&mut self) -> Result<(), Error> + where + L: ledger::Read, Checkpoint = S::Checkpoint>, + { + let ReadResponse { + should_continue: _, + data, + } = self + .ledger + .read(&self.checkpoint) + .await + .map_err(Error::LedgerConnectionError)?; + self.signer_initial_sync(data).await?; + Ok(()) + } + /// Pulls data from the ledger, synchronizing the wallet and balance state. This method returns /// a [`ControlFlow`] for matching against to determine if the wallet requires more /// synchronization. @@ -350,6 +368,51 @@ where } } + /// + #[inline] + async fn signer_initial_sync( + &mut self, + request: InitialSyncData, + ) -> Result<(), Error> { + match self + .signer + .initial_sync(request) + .await + .map_err(Error::SignerConnectionError)? + { + Ok(SyncResponse { + checkpoint, + balance_update, + }) => { + match balance_update { + BalanceUpdate::Partial { deposit, withdraw } => { + self.assets.deposit_all(deposit); + if !self.assets.withdraw_all(withdraw) { + return Err(Error::Inconsistency(InconsistencyError::WalletBalance)); + } + } + BalanceUpdate::Full { assets } => { + self.assets.clear(); + self.assets.deposit_all(assets); + } + } + self.checkpoint = checkpoint; + Ok(()) + } + Err(SyncError::InconsistentSynchronization { checkpoint }) => { + if checkpoint < self.checkpoint { + self.checkpoint = checkpoint; + } + Err(Error::Inconsistency( + InconsistencyError::SignerSynchronization, + )) + } + Err(SyncError::MissingProofAuthorizationKey) => { + Err(Error::MissingProofAuthorizationKey) + } + } + } + /// Checks if `transaction` can be executed on the balance state of `self`, returning the /// kind of update that should be performed on the balance state if the transaction is /// successfully posted to the ledger. diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index adb762cfc..3f5d3663b 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -47,7 +47,7 @@ use manta_crypto::{ }; use manta_util::{ array_map, cmp::Independence, into_array_unchecked, iter::IteratorExt, persistence::Rollback, - vec::VecExt, BoxArray, + vec::VecExt, }; /// Returns the default account for `accounts`. @@ -936,23 +936,22 @@ where /// Updates `assets`, `checkpoint` and `utxo_accumulator`, returning the new asset distribution. #[inline] -pub fn intial_sync( +pub fn intial_sync( parameters: &SignerParameters, assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, - request: InitialSyncData, + request: InitialSyncData, ) -> Result, SyncError> where C: Configuration, - C::UtxoAccumulator: FromItemsAndWitnesses, { let InitialSyncData { utxo_data, membership_proof_data, nullifier_data, } = request; - let (accumulator, response) = initial_sync_with::( + let (accumulator, response) = initial_sync_with::( assets, checkpoint, utxo_accumulator.model(), @@ -969,18 +968,17 @@ where /// Updates the internal ledger state, returning the new asset distribution. #[allow(clippy::too_many_arguments)] #[inline] -fn initial_sync_with( +fn initial_sync_with( assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator_model: &UtxoAccumulatorModel, parameters: &Parameters, utxos: Vec>, - membership_proof_data: BoxArray, NUMBER_OF_PROOFS>, + membership_proof_data: Vec>, nullifiers: Vec>, ) -> (C::UtxoAccumulator, SyncResponse) where C: Configuration, - C::UtxoAccumulator: FromItemsAndWitnesses, { let accumulator = C::UtxoAccumulator::from_items_and_witnesses( utxo_accumulator_model, diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index fe79bc683..fc15209bb 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -79,6 +79,12 @@ where request: SyncRequest, ) -> LocalBoxFutureResult, Self::Error>; + /// + fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> LocalBoxFutureResult, Self::Error>; + /// Signs a transaction and returns the ledger transfer posts if successful. fn sign( &mut self, @@ -142,7 +148,7 @@ where bound = "Utxo: PartialEq, UtxoAccumulatorWitness: PartialEq, Nullifier: PartialEq" ) )] -pub struct InitialSyncData +pub struct InitialSyncData where C: transfer::Configuration + ?Sized, { @@ -153,7 +159,7 @@ where pub nullifier_data: Vec>, /// Membership Proof Data - pub membership_proof_data: manta_util::BoxArray, NUMBER_OF_PROOFS>, + pub membership_proof_data: Vec>, } /// Signer Synchronization Data @@ -716,6 +722,7 @@ pub trait Configuration: transfer::Configuration { Model = UtxoAccumulatorModel, Witness = UtxoAccumulatorWitness, > + ExactSizeAccumulator + + FromItemsAndWitnesses + OptimizedAccumulator + Rollback; @@ -1126,6 +1133,21 @@ where ) } + /// + #[inline] + pub fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> Result, SyncError> { + functions::intial_sync( + &self.parameters, + &mut self.state.assets, + &mut self.state.checkpoint, + &mut self.state.utxo_accumulator, + request, + ) + } + /// Generates an [`IdentityProof`] for `identified_asset` by /// signing a virtual [`ToPublic`](transfer::canonical::ToPublic) transaction. #[inline] @@ -1253,24 +1275,6 @@ where } false } - - /// - #[inline] - pub fn initial_sync( - &mut self, - request: InitialSyncData, - ) -> Result, SyncError> - where - C::UtxoAccumulator: FromItemsAndWitnesses, - { - functions::intial_sync( - &self.parameters, - &mut self.state.assets, - &mut self.state.checkpoint, - &mut self.state.utxo_accumulator, - request, - ) - } } impl Connection for Signer @@ -1289,6 +1293,14 @@ where Box::pin(async move { Ok(self.sync(request)) }) } + #[inline] + fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> LocalBoxFutureResult, Self::Error> { + Box::pin(async move { Ok(self.initial_sync(request)) }) + } + #[inline] fn sign( &mut self, diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 979fafc87..d08348392 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -22,7 +22,6 @@ use core::{fmt::Debug, hash::Hash}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; -use manta_util::BoxArray; /// Accumulator Membership Model Types pub trait Types { @@ -204,13 +203,16 @@ pub trait OptimizedAccumulator: Accumulator { } } -/// From Proofs and Witnesses -pub trait FromItemsAndWitnesses: Accumulator { +/// From Items and Witnesses +pub trait FromItemsAndWitnesses: Accumulator { + /// Number of Proofs + const NUMBER_OF_PROOFS: usize; + /// Builds a new [`Self`] from `items` and `proofs`. fn from_items_and_witnesses( model: &Self::Model, items: Vec, - witnesses: BoxArray, + witnesses: Vec, ) -> Self; } diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 7110680a8..7cc09c4ff 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -540,7 +540,7 @@ where pub fn from_leaves_and_current_paths_unchecked( parameters: &Parameters, leaves: Vec>, - paths: BoxArray, N>, + paths: Vec>, ) -> Self { TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( |(tree_index, path)| { @@ -572,7 +572,7 @@ where pub fn from_leaves_and_current_paths_unchecked( parameters: &Parameters, leaves: Vec>, - paths: BoxArray, N>, + paths: Vec>, ) -> Self { TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( |(tree_index, path)| { @@ -590,7 +590,7 @@ where } } -impl FromItemsAndWitnesses for TreeArrayMerkleForest, N> +impl FromItemsAndWitnesses for TreeArrayMerkleForest, N> where C: Configuration + ?Sized, C::Index: FixedIndex, @@ -598,12 +598,15 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { + const NUMBER_OF_PROOFS: usize = N; + #[inline] fn from_items_and_witnesses( model: &Self::Model, items: Vec, - witnesses: BoxArray, + witnesses: Vec, ) -> Self { + assert_eq!(witnesses.len(), N); Self::from_forest( TreeArray::, N>::from_leaves_and_current_paths_unchecked( model, items, witnesses, @@ -613,7 +616,7 @@ where } } -impl FromItemsAndWitnesses +impl FromItemsAndWitnesses for TreeArrayMerkleForest>, N> where C: Configuration + ?Sized, @@ -622,12 +625,15 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { + const NUMBER_OF_PROOFS: usize = N; + #[inline] fn from_items_and_witnesses( model: &Self::Model, items: Vec, - witnesses: BoxArray, + witnesses: Vec, ) -> Self { + assert_eq!(witnesses.len(), N); Self::from_forest( TreeArray::>, N>::from_leaves_and_current_paths_unchecked( model, items, witnesses, diff --git a/manta-pay/src/signer/client/http.rs b/manta-pay/src/signer/client/http.rs index dc3690228..20448ed48 100644 --- a/manta-pay/src/signer/client/http.rs +++ b/manta-pay/src/signer/client/http.rs @@ -20,9 +20,9 @@ use crate::{ config::{utxo::Address, Config}, signer::{ client::network::{Message, Network}, - AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, SignError, - SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, SyncRequest, - SyncResponse, TransactionDataRequest, TransactionDataResponse, + AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, InitialSyncData, + SignError, SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, + SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }; use alloc::boxed::Box; @@ -102,6 +102,14 @@ impl signer::Connection for Client { Box::pin(self.post_request("sync", request)) } + #[inline] + fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> LocalBoxFutureResult, Self::Error> { + Box::pin(self.post_request("initial_sync", request)) + } + #[inline] fn sign( &mut self, diff --git a/manta-pay/src/signer/client/websocket.rs b/manta-pay/src/signer/client/websocket.rs index 2ff6e70be..376869a5f 100644 --- a/manta-pay/src/signer/client/websocket.rs +++ b/manta-pay/src/signer/client/websocket.rs @@ -21,9 +21,9 @@ use crate::{ config::{utxo::Address, Config}, signer::{ - AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, SignError, - SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, SyncRequest, - SyncResponse, TransactionDataRequest, TransactionDataResponse, + AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, InitialSyncData, + SignError, SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, + SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }; use alloc::boxed::Box; @@ -140,6 +140,14 @@ impl signer::Connection for Client { Box::pin(self.send("sync", request)) } + #[inline] + fn initial_sync( + &mut self, + request: InitialSyncData, + ) -> LocalBoxFutureResult, Self::Error> { + Box::pin(self.send("initial_sync", request)) + } + #[inline] fn sign( &mut self, diff --git a/manta-pay/src/signer/mod.rs b/manta-pay/src/signer/mod.rs index 819a2ab34..71808ebde 100644 --- a/manta-pay/src/signer/mod.rs +++ b/manta-pay/src/signer/mod.rs @@ -40,6 +40,9 @@ pub mod functions; /// Synchronization Request pub type SyncRequest = signer::SyncRequest; +/// Initial Synchronization Data +pub type InitialSyncData = signer::InitialSyncData; + /// Synchronization Response pub type SyncResponse = signer::SyncResponse; From 091eb31034662e2764017638c6fe40c74e1ee436 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Thu, 16 Mar 2023 19:32:24 +0100 Subject: [PATCH 09/34] tests --- manta-accounting/src/wallet/test/mod.rs | 17 +- manta-crypto/src/merkle_tree/forest.rs | 10 +- manta-crypto/src/merkle_tree/inner_tree.rs | 8 +- manta-crypto/src/merkle_tree/partial.rs | 8 +- manta-crypto/src/merkle_tree/test.rs | 190 ++++++++++++++++++++- manta-pay/src/bin/simulation.rs | 2 + manta-pay/src/simulation/ledger/mod.rs | 68 +++++++- manta-pay/src/simulation/mod.rs | 28 ++- 8 files changed, 306 insertions(+), 25 deletions(-) diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index 7b29cd6e5..bf92913c4 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -24,7 +24,7 @@ use crate::{ transfer::{canonical::Transaction, Address, Asset, Configuration, TransferPost}, wallet::{ ledger, - signer::{self, SyncData}, + signer::{self, InitialSyncData, SyncData}, BalanceState, Error, Wallet, }, }; @@ -993,8 +993,14 @@ impl Config { C: Configuration, C::AssetValue: AddAssign + SampleUniform, for<'v> &'v C::AssetValue: CheckedSub, - L: Ledger + PublicBalanceOracle, - S: signer::Connection, + L: Ledger + + PublicBalanceOracle + + ledger::Read< + InitialSyncData, + Checkpoint = >>::Checkpoint, + >, + Error: Debug, + S: signer::Connection>>::Checkpoint>, S::Error: Debug, B: BalanceState, R: CryptoRng + RngCore, @@ -1027,6 +1033,11 @@ impl Config { .expect("Wallet should have address") .expect("Missing spending key"); simulation.addresses.lock().insert(address); + actor + .wallet + .initial_sync() + .await + .expect("Error during initial sync"); } let mut simulator = sim::Simulator::new(sim::ActionSim(simulation), actors); let initial_balances = diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 7cc09c4ff..1927ea48a 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -537,7 +537,7 @@ where /// the `paths` are consistent with the leaves and that they are /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. #[inline] - pub fn from_leaves_and_current_paths_unchecked( + pub fn from_leaves_and_paths_unchecked( parameters: &Parameters, leaves: Vec>, paths: Vec>, @@ -569,7 +569,7 @@ where /// the `paths` are consistent with the leaves and that they are /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. #[inline] - pub fn from_leaves_and_current_paths_unchecked( + pub fn from_leaves_and_paths_unchecked( parameters: &Parameters, leaves: Vec>, paths: Vec>, @@ -608,9 +608,7 @@ where ) -> Self { assert_eq!(witnesses.len(), N); Self::from_forest( - TreeArray::, N>::from_leaves_and_current_paths_unchecked( - model, items, witnesses, - ), + TreeArray::, N>::from_leaves_and_paths_unchecked(model, items, witnesses), model.clone(), ) } @@ -635,7 +633,7 @@ where ) -> Self { assert_eq!(witnesses.len(), N); Self::from_forest( - TreeArray::>, N>::from_leaves_and_current_paths_unchecked( + TreeArray::>, N>::from_leaves_and_paths_unchecked( model, items, witnesses, ), model.clone(), diff --git a/manta-crypto/src/merkle_tree/inner_tree.rs b/manta-crypto/src/merkle_tree/inner_tree.rs index 35b7004d9..7ab7dddd0 100644 --- a/manta-crypto/src/merkle_tree/inner_tree.rs +++ b/manta-crypto/src/merkle_tree/inner_tree.rs @@ -25,7 +25,7 @@ use crate::merkle_tree::{ path_length, Configuration, InnerDigest, Node, Parameters, Parity, }; use alloc::collections::btree_map; -use core::{fmt::Debug, hash::Hash, iter::FusedIterator, marker::PhantomData, ops::Index}; +use core::{default, fmt::Debug, hash::Hash, iter::FusedIterator, marker::PhantomData, ops::Index}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; @@ -774,6 +774,12 @@ where { self.inner_tree.path(leaf_index) } + + /// + #[inline] + pub fn reset_starting_leaf_index(&mut self, default: Node) { + self.starting_leaf_index = default; + } } impl PartialInnerTree> diff --git a/manta-crypto/src/merkle_tree/partial.rs b/manta-crypto/src/merkle_tree/partial.rs index cdf276af2..806bb7ed2 100644 --- a/manta-crypto/src/merkle_tree/partial.rs +++ b/manta-crypto/src/merkle_tree/partial.rs @@ -106,14 +106,18 @@ where Parity::Left => parameters.join_leaves(&leaf_digests[n - 1], &path.sibling_digest), Parity::Right => parameters.join_leaves(&path.sibling_digest, &leaf_digests[n - 1]), }; - Self::new_unchecked( + let mut partial_tree = Self::new_unchecked( leaf_digests, PartialInnerTree::from_current( parameters, base, CurrentPath::from_path_unchecked(path).inner_path, ), - ) + ); + partial_tree + .inner_digests + .reset_starting_leaf_index(Default::default()); + partial_tree } } diff --git a/manta-crypto/src/merkle_tree/test.rs b/manta-crypto/src/merkle_tree/test.rs index 0ef3a42e7..f80e9ec27 100644 --- a/manta-crypto/src/merkle_tree/test.rs +++ b/manta-crypto/src/merkle_tree/test.rs @@ -17,16 +17,23 @@ //! Testing Framework use crate::{ + accumulator::{Accumulator, FromItemsAndWitnesses}, merkle_tree::{ + forest::{self, Forest, MerkleForest, TreeArrayMerkleForest}, + fork::ForkedTree, + full::{Full, FullMerkleTree}, + partial::{Partial, PartialMerkleTree}, Configuration, HashConfiguration, IdentityLeafHash, InnerDigest, InnerHash, InnerHashParameters, Leaf, LeafHashParameters, MerkleTree, Parameters, Path, Tree, WithProofs, }, - rand::{RngCore, Sample}, + rand::{OsRng, Rand, RngCore, Sample}, }; use alloc::string::String; use core::{fmt::Debug, hash::Hash, marker::PhantomData}; +use super::forest::FixedIndex; + /// Hash Parameter Sampling pub trait HashParameterSampling: HashConfiguration { /// Leaf Hash Parameter Distribution @@ -279,3 +286,184 @@ where let _ = (distribution, rng); } } + +/// +#[test] +fn test_from_leaves_and_path() { + let mut rng = OsRng; + const HEIGHT: usize = 7; + type Config = Test; + let parameters = Parameters::::sample(Default::default(), &mut rng); + let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); + let inner_element_index = rng.gen_range(0..number_of_insertions - 3); // make sure this one isn't the last nor its sibling + println!("{number_of_insertions}, {inner_element_index}"); + let mut tree = FullMerkleTree::::new(parameters); + let mut insertions = Vec::::with_capacity(number_of_insertions); + for _ in 0..number_of_insertions { + insertions.push(rng.gen()); + } + for leaf in &insertions { + tree.insert(leaf); + } + let forked_tree = ForkedTree::>::new(tree.tree.clone(), ¶meters); + let path = tree.current_path(); + let partial_tree = PartialMerkleTree::> { + parameters, + tree: Partial::from_leaves_and_path_unchecked( + ¶meters, + insertions.clone(), + path.clone().into(), + ), + }; + let forked_partial_tree = ForkedTree::>::from_leaves_and_path_unchecked( + ¶meters, + insertions.clone(), + path.clone().into(), + ); + let root = tree.root().clone(); + let partial_root = partial_tree.root().clone(); + let forked_root = forked_tree.root().clone(); + let forked_partial_root = forked_partial_tree.root().clone(); + assert_eq!(root, partial_root, "Roots must be equal"); + assert_eq!(root, forked_root, "Roots must be equal"); + assert_eq!(root, forked_partial_root, "Roots must be equal"); + let proof_full_inner = tree + .prove(&insertions[inner_element_index]) + .expect("Failed to generate proof"); + let proof_partial_inner = partial_tree + .prove(&insertions[inner_element_index]) + .expect("Failed to generate proof"); + assert!( + proof_full_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), + "Inner proof in the full tree must be valid" + ); + assert!( + !proof_partial_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), + "Inner proof in the partial tree must be invalid" + ); + let proof_full = tree + .prove(&insertions[number_of_insertions - 1]) + .expect("Failed to generate proof"); + let proof_partial = partial_tree + .prove(&insertions[number_of_insertions - 1]) + .expect("Failed to generate proof"); + assert!( + proof_full.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), + "Final proof in the full tree must be valid" + ); + assert!( + proof_partial.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), + "Final proof in the partial tree must be valid" + ); +} + +/// +#[derive(PartialEq)] +pub enum Index { + /// + Zero, + + /// + One, +} + +impl From for usize { + fn from(value: Index) -> Self { + match value { + Index::Zero => 0, + Index::One => 1, + } + } +} + +impl FixedIndex<2> for Index { + fn from_index(index: usize) -> Self { + if index % 2 == 0 { + Index::Zero + } else { + Index::One + } + } +} + +impl forest::Configuration for Test { + type Index = Index; + fn tree_index(leaf: &Leaf) -> Self::Index { + let parity = leaf % 2; + if parity == 0 { + Index::Zero + } else { + Index::One + } + } +} +/// +#[test] +fn test_from_leaves_and_path_forest() { + let mut rng = OsRng; + const HEIGHT: usize = 7; + type Config = Test; + let parameters = Parameters::::sample(Default::default(), &mut rng); + let mut forest = + TreeArrayMerkleForest::>, 2>::new(parameters); + let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); + let mut insertions = Vec::::with_capacity(number_of_insertions); + for _ in 0..number_of_insertions { + insertions.push(rng.gen()); + } + for leaf in &insertions { + forest.insert(leaf); + } + let path_1 = Path::from(forest.forest.get(Index::Zero).current_path()); + let path_2 = Path::from(forest.forest.get(Index::One).current_path()); + let paths = vec![path_1, path_2]; + let partial_forest = + TreeArrayMerkleForest::<_, ForkedTree<_, Partial>, 2>::from_items_and_witnesses( + ¶meters, + insertions.clone(), + paths, + ); + for leaf in &insertions { + assert_eq!(forest.output_from(leaf), partial_forest.output_from(leaf)); + } +} + +/// +#[test] +fn visual_test_with_strings() { + const HEIGHT: usize = 5; + let mut rng = OsRng; + let parameters = Parameters::>::sample(Default::default(), &mut rng); + let mut tree = FullMerkleTree::>::new(parameters); + let insertions = vec![ + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", + ] + .into_iter() + .map(String::from) + .collect::>(); + for leaf in &insertions { + tree.insert(leaf); + } + let root = tree.root().clone(); + let path = tree.current_path(); + println!("{path:?}"); + let partial_tree = PartialMerkleTree::> { + parameters, + tree: Partial::from_leaves_and_path_unchecked(¶meters, insertions.clone(), path.into()), + }; + let second_root = partial_tree.root().clone(); + assert_eq!(root, second_root); + const INNER_ELEMENT_INDEX: usize = 10; // k + let proof = tree.prove(&insertions[INNER_ELEMENT_INDEX]).unwrap(); + println!("{proof:?}"); + let proof_2 = partial_tree + .prove(&insertions[INNER_ELEMENT_INDEX]) + .unwrap(); + println!("{proof_2:?}"); + let proof_3 = tree.prove(&insertions[insertions.len() - 1]).unwrap(); + let proof_4 = partial_tree + .prove(&insertions[insertions.len() - 1]) + .unwrap(); + println!("{proof_3:?}"); + println!("{proof_4:?}"); +} diff --git a/manta-pay/src/bin/simulation.rs b/manta-pay/src/bin/simulation.rs index 1d43790a9..afdb3f916 100644 --- a/manta-pay/src/bin/simulation.rs +++ b/manta-pay/src/bin/simulation.rs @@ -46,3 +46,5 @@ pub fn main() { .exit(), } } + +// cargo run --release --package manta-pay --all-features --bin simulation 3 10 2 1000 diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index e109d4cb5..d84395c80 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -19,12 +19,15 @@ // TODO: How to model existential deposits and fee payments? // TODO: Add in some concurrency (and measure how much we need it). -use crate::config::{ - utxo::{ - AssetId, AssetValue, Checkpoint, FullIncomingNote, MerkleTreeConfiguration, Parameters, +use crate::{ + config::{ + utxo::{ + AssetId, AssetValue, Checkpoint, FullIncomingNote, MerkleTreeConfiguration, Parameters, + }, + AccountId, Config, MultiVerifyingContext, Nullifier, ProofSystem, TransferPost, Utxo, + UtxoAccumulatorModel, }, - AccountId, Config, MultiVerifyingContext, Nullifier, ProofSystem, TransferPost, Utxo, - UtxoAccumulatorModel, + signer::InitialSyncData, }; use alloc::{sync::Arc, vec::Vec}; use core::convert::Infallible; @@ -50,7 +53,7 @@ use manta_crypto::{ constraint::ProofSystem as _, merkle_tree::{ self, - forest::{Configuration, FixedIndex}, + forest::{Configuration, FixedIndex, Forest}, }, }; use manta_util::future::{LocalBoxFuture, LocalBoxFutureResult}; @@ -214,6 +217,46 @@ impl Ledger { } true } + + /// + #[inline] + pub fn initial_read(&self) -> ReadResponse { + let mut utxos = Vec::new(); + for (i, mut index) in (0..MerkleTreeConfiguration::FOREST_WIDTH).enumerate() { + let shard = &self.shards[&MerkleForestIndex::from_index(i)]; + while let Some(entry) = shard.get_index(index) { + utxos.push(entry.0.clone()); + index += 1; + } + } + let senders = self.nullifiers.iter().cloned().collect::>(); + let utxo_merkle_forest = self.utxo_forest.clone(); + let mut membership_proof_data = Vec::new(); + for index in (0..MerkleTreeConfiguration::FOREST_WIDTH) { + membership_proof_data.push( + utxo_merkle_forest + .forest + .get(index as u8) + .current_path() + .clone() + .into(), + ) + } + ReadResponse { + should_continue: false, + data: InitialSyncData { + utxo_data: utxos, + nullifier_data: senders, + membership_proof_data, + }, + } + } + + /// + #[inline] + pub fn utxos(&self) -> &HashSet { + &self.utxos + } } /// Sender Ledger Error @@ -637,6 +680,19 @@ impl ledger::Read> for LedgerConnection { } } +impl ledger::Read for LedgerConnection { + type Checkpoint = Checkpoint; + + #[inline] + fn read<'s>( + &'s mut self, + checkpoint: &'s Self::Checkpoint, + ) -> LocalBoxFutureResult<'s, ReadResponse, Self::Error> { + let _ = checkpoint; + Box::pin(async move { Ok(self.ledger.read().await.initial_read()) }) + } +} + impl ledger::Write> for LedgerConnection { type Response = bool; diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index fb3b222e4..5f4523b0c 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -23,17 +23,18 @@ use crate::{ UtxoAccumulatorModel, }, key::KeySecret, - signer::{base::Signer, functions}, + signer::{base::Signer, functions, InitialSyncData}, simulation::ledger::{Ledger, LedgerConnection}, }; use alloc::{format, sync::Arc}; -use core::fmt::Debug; +use core::{fmt::Debug, ops::Deref}; use manta_accounting::{ self, asset::AssetList, key::AccountTable, wallet::{ self, + signer::SyncData, test::{self, PublicBalanceOracle}, Error, }, @@ -139,11 +140,18 @@ impl Simulation { self.setup(&mut ledger); let ledger = Arc::new(RwLock::new(ledger)); self.run_with( - move |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), + |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), + |_| sample_signer(proving_context, parameters, utxo_accumulator_model, rng), + move |i| account_id_from_u64(i as u64), + ) + .await; + println!("{:?}", ledger.read().await.utxos()); + self.run_with( + |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), move |_| sample_signer(proving_context, parameters, utxo_accumulator_model, rng), move |i| account_id_from_u64(i as u64), ) - .await + .await; } /// Runs the simulation with the given ledger connections and signer connections. @@ -155,8 +163,16 @@ impl Simulation { #[inline] pub async fn run_with(&self, ledger: GL, signer: GS, public_account: GP) where - L: wallet::test::Ledger + PublicBalanceOracle, - S: wallet::signer::Connection, + L: wallet::test::Ledger + + PublicBalanceOracle + + wallet::ledger::Read< + InitialSyncData, + Checkpoint = >>::Checkpoint, + >, + S: wallet::signer::Connection< + Config, + Checkpoint = >>::Checkpoint, + >, S::Error: Debug, GL: FnMut(usize) -> L, GS: FnMut(usize) -> S, From 0c78f264e4ec46e9060f9cb0413bf463b371bb90 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Thu, 16 Mar 2023 20:05:40 +0100 Subject: [PATCH 10/34] change dep --- manta-accounting/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/manta-accounting/Cargo.toml b/manta-accounting/Cargo.toml index 0150fc67a..d2c4a000b 100644 --- a/manta-accounting/Cargo.toml +++ b/manta-accounting/Cargo.toml @@ -48,6 +48,7 @@ test = [ "futures", "indexmap", "manta-crypto/arkworks", + "manta_crypto/getrandom", "manta-crypto/rand", "manta-crypto/test", "parking_lot", From be369ad40668f7259cd039c4355a3fc79680a883 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Thu, 16 Mar 2023 20:10:21 +0100 Subject: [PATCH 11/34] fixed dep --- manta-accounting/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manta-accounting/Cargo.toml b/manta-accounting/Cargo.toml index d2c4a000b..285e85010 100644 --- a/manta-accounting/Cargo.toml +++ b/manta-accounting/Cargo.toml @@ -48,7 +48,7 @@ test = [ "futures", "indexmap", "manta-crypto/arkworks", - "manta_crypto/getrandom", + "manta-crypto/getrandom", "manta-crypto/rand", "manta-crypto/test", "parking_lot", From 805325869976db28487fb9ef248d329e794b7390 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Thu, 16 Mar 2023 20:15:56 +0100 Subject: [PATCH 12/34] dep --- manta-crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manta-crypto/Cargo.toml b/manta-crypto/Cargo.toml index d8ad63cec..29b45adc3 100644 --- a/manta-crypto/Cargo.toml +++ b/manta-crypto/Cargo.toml @@ -70,7 +70,7 @@ std = [ ] # Testing Frameworks -test = [] +test = ["getrandom"] [dependencies] ark-bls12-381 = { version = "0.3.0", optional = true, default-features = false, features = ["curve"] } From ca0ad1d922f479885539a189254572b7e20f8a9d Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Fri, 17 Mar 2023 13:49:49 +0100 Subject: [PATCH 13/34] rearranged tests --- manta-crypto/src/merkle_tree/inner_tree.rs | 2 +- manta-crypto/src/merkle_tree/test.rs | 469 --------------------- manta-pay/src/simulation/ledger/mod.rs | 4 +- manta-trusted-setup/src/groth16/mpc.rs | 1 + 4 files changed, 4 insertions(+), 472 deletions(-) delete mode 100644 manta-crypto/src/merkle_tree/test.rs diff --git a/manta-crypto/src/merkle_tree/inner_tree.rs b/manta-crypto/src/merkle_tree/inner_tree.rs index 7ab7dddd0..42eca5012 100644 --- a/manta-crypto/src/merkle_tree/inner_tree.rs +++ b/manta-crypto/src/merkle_tree/inner_tree.rs @@ -25,7 +25,7 @@ use crate::merkle_tree::{ path_length, Configuration, InnerDigest, Node, Parameters, Parity, }; use alloc::collections::btree_map; -use core::{default, fmt::Debug, hash::Hash, iter::FusedIterator, marker::PhantomData, ops::Index}; +use core::{fmt::Debug, hash::Hash, iter::FusedIterator, marker::PhantomData, ops::Index}; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; diff --git a/manta-crypto/src/merkle_tree/test.rs b/manta-crypto/src/merkle_tree/test.rs deleted file mode 100644 index f80e9ec27..000000000 --- a/manta-crypto/src/merkle_tree/test.rs +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright 2019-2022 Manta Network. -// This file is part of manta-rs. -// -// manta-rs is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// manta-rs is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with manta-rs. If not, see . - -//! Testing Framework - -use crate::{ - accumulator::{Accumulator, FromItemsAndWitnesses}, - merkle_tree::{ - forest::{self, Forest, MerkleForest, TreeArrayMerkleForest}, - fork::ForkedTree, - full::{Full, FullMerkleTree}, - partial::{Partial, PartialMerkleTree}, - Configuration, HashConfiguration, IdentityLeafHash, InnerDigest, InnerHash, - InnerHashParameters, Leaf, LeafHashParameters, MerkleTree, Parameters, Path, Tree, - WithProofs, - }, - rand::{OsRng, Rand, RngCore, Sample}, -}; -use alloc::string::String; -use core::{fmt::Debug, hash::Hash, marker::PhantomData}; - -use super::forest::FixedIndex; - -/// Hash Parameter Sampling -pub trait HashParameterSampling: HashConfiguration { - /// Leaf Hash Parameter Distribution - type LeafHashParameterDistribution; - - /// Inner Hash Parameter Distribution - type InnerHashParameterDistribution; - - /// Sample leaf hash parameters from `distribution` using the given `rng`. - fn sample_leaf_hash_parameters( - distribution: Self::LeafHashParameterDistribution, - rng: &mut R, - ) -> LeafHashParameters - where - R: RngCore + ?Sized; - - /// Sample inner hash parameters from `distribution` using the given `rng`. - fn sample_inner_hash_parameters( - distribution: Self::InnerHashParameterDistribution, - rng: &mut R, - ) -> InnerHashParameters - where - R: RngCore + ?Sized; -} - -/// Hash Parameter Distribution -#[derive(derivative::Derivative)] -#[derivative( - Clone( - bound = "C::LeafHashParameterDistribution: Clone, C::InnerHashParameterDistribution: Clone" - ), - Copy( - bound = "C::LeafHashParameterDistribution: Copy, C::InnerHashParameterDistribution: Copy" - ), - Debug( - bound = "C::LeafHashParameterDistribution: Debug, C::InnerHashParameterDistribution: Debug" - ), - Default( - bound = "C::LeafHashParameterDistribution: Default, C::InnerHashParameterDistribution: Default" - ), - Eq(bound = "C::LeafHashParameterDistribution: Eq, C::InnerHashParameterDistribution: Eq"), - Hash( - bound = "C::LeafHashParameterDistribution: Hash, C::InnerHashParameterDistribution: Hash" - ), - PartialEq(bound = "C::LeafHashParameterDistribution: PartialEq, - C::InnerHashParameterDistribution: PartialEq") -)] -pub struct HashParameterDistribution -where - C: HashParameterSampling + ?Sized, -{ - /// Leaf Hash Parameter Distribution - pub leaf: C::LeafHashParameterDistribution, - - /// Inner Hash Parameter Distribution - pub inner: C::InnerHashParameterDistribution, -} - -impl Sample> for Parameters -where - C: HashParameterSampling + ?Sized, -{ - #[inline] - fn sample(distribution: HashParameterDistribution, rng: &mut R) -> Self - where - R: RngCore + ?Sized, - { - Self::new( - C::sample_leaf_hash_parameters(distribution.leaf, rng), - C::sample_inner_hash_parameters(distribution.inner, rng), - ) - } -} - -/// Tests that a tree constructed with `parameters` can accept at least two leaves without -/// failing. -#[inline] -pub fn push_twice_to_empty_tree_succeeds( - parameters: Parameters, - lhs: &Leaf, - rhs: &Leaf, -) -> Parameters -where - C: Configuration + ?Sized, - T: Tree, -{ - let mut tree = MerkleTree::::new(parameters); - assert!( - tree.push(lhs), - "Trees always have a capacity of at least two." - ); - assert!( - tree.push(rhs), - "Trees always have a capacity of at least two." - ); - tree.into_parameters() -} - -/// Tests path construction by checking that the path at the given `index` on `tree` is a valid -/// [`Path`](super::Path) for `leaf`. -#[inline] -pub fn assert_valid_path(tree: &MerkleTree, index: usize, leaf: &Leaf) -where - C: Configuration + ?Sized, - T: Tree + WithProofs, - InnerDigest: Debug + PartialEq, - Path: Debug, -{ - let path = tree.path(index).expect("Only valid queries are accepted."); - let root = tree.root(); - assert!( - path.verify(tree.parameters(), root, leaf), - "Path returned from tree was not valid: {:?}. Expected {:?} but got {:?}.", - path, - root, - path.root(&tree.parameters, &tree.parameters.digest(leaf)), - ); -} - -/// Tests path construction for multiple insertions. This is an extension of the -/// [`assert_valid_path`] test. -#[inline] -pub fn assert_valid_paths(tree: &mut MerkleTree, leaves: &[Leaf]) -where - C: Configuration + ?Sized, - T: Tree + WithProofs, - InnerDigest: Debug + PartialEq, - Path: Debug, - Leaf: Sized, -{ - let starting_index = tree.len(); - for (i, leaf) in leaves.iter().enumerate() { - tree.push(leaf); - for (j, previous_leaf) in leaves.iter().enumerate().take(i + 1) { - assert_valid_path(tree, starting_index + j, previous_leaf); - } - } -} - -/// Test Inner Hash -/// -/// # Warning -/// -/// This is only meant for testing purposes, and should not be used in any production or -/// cryptographically secure environments. -pub trait TestHash { - /// Joins `lhs` and `rhs` into an output hash value. - fn join(lhs: &Self, rhs: &Self) -> Self; -} - -impl TestHash for u64 { - #[inline] - fn join(lhs: &Self, rhs: &Self) -> Self { - *lhs ^ *rhs - } -} - -impl TestHash for String { - #[inline] - fn join(lhs: &Self, rhs: &Self) -> Self { - let mut lhs = lhs.clone(); - lhs.push_str(rhs); - lhs - } -} - -/// Test Merkle Tree Configuration -/// -/// # Warning -/// -/// This is only meant for testing purposes, and should not be used in production or -/// cryptographically secure environments. -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct Test(PhantomData) -where - T: Clone + Default + PartialEq + TestHash; - -impl InnerHash for Test -where - T: Clone + Default + PartialEq + TestHash, -{ - type LeafDigest = T; - type Parameters = (); - type Output = T; - - #[inline] - fn join( - parameters: &Self::Parameters, - lhs: &Self::Output, - rhs: &Self::Output, - _: &mut (), - ) -> Self::Output { - let _ = parameters; - TestHash::join(lhs, rhs) - } - - #[inline] - fn join_leaves( - parameters: &Self::Parameters, - lhs: &Self::LeafDigest, - rhs: &Self::LeafDigest, - _: &mut (), - ) -> Self::Output { - let _ = parameters; - TestHash::join(lhs, rhs) - } -} - -impl HashConfiguration for Test -where - T: Clone + Default + PartialEq + TestHash, -{ - type LeafHash = IdentityLeafHash; - type InnerHash = Test; -} - -impl Configuration for Test -where - T: Clone + Default + PartialEq + TestHash, -{ - const HEIGHT: usize = HEIGHT; -} - -impl HashParameterSampling for Test -where - T: Clone + Default + PartialEq + TestHash, -{ - type LeafHashParameterDistribution = (); - type InnerHashParameterDistribution = (); - - #[inline] - fn sample_leaf_hash_parameters( - distribution: Self::LeafHashParameterDistribution, - rng: &mut R, - ) -> LeafHashParameters - where - R: RngCore + ?Sized, - { - let _ = (distribution, rng); - } - - #[inline] - fn sample_inner_hash_parameters( - distribution: Self::InnerHashParameterDistribution, - rng: &mut R, - ) -> InnerHashParameters - where - R: RngCore + ?Sized, - { - let _ = (distribution, rng); - } -} - -/// -#[test] -fn test_from_leaves_and_path() { - let mut rng = OsRng; - const HEIGHT: usize = 7; - type Config = Test; - let parameters = Parameters::::sample(Default::default(), &mut rng); - let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); - let inner_element_index = rng.gen_range(0..number_of_insertions - 3); // make sure this one isn't the last nor its sibling - println!("{number_of_insertions}, {inner_element_index}"); - let mut tree = FullMerkleTree::::new(parameters); - let mut insertions = Vec::::with_capacity(number_of_insertions); - for _ in 0..number_of_insertions { - insertions.push(rng.gen()); - } - for leaf in &insertions { - tree.insert(leaf); - } - let forked_tree = ForkedTree::>::new(tree.tree.clone(), ¶meters); - let path = tree.current_path(); - let partial_tree = PartialMerkleTree::> { - parameters, - tree: Partial::from_leaves_and_path_unchecked( - ¶meters, - insertions.clone(), - path.clone().into(), - ), - }; - let forked_partial_tree = ForkedTree::>::from_leaves_and_path_unchecked( - ¶meters, - insertions.clone(), - path.clone().into(), - ); - let root = tree.root().clone(); - let partial_root = partial_tree.root().clone(); - let forked_root = forked_tree.root().clone(); - let forked_partial_root = forked_partial_tree.root().clone(); - assert_eq!(root, partial_root, "Roots must be equal"); - assert_eq!(root, forked_root, "Roots must be equal"); - assert_eq!(root, forked_partial_root, "Roots must be equal"); - let proof_full_inner = tree - .prove(&insertions[inner_element_index]) - .expect("Failed to generate proof"); - let proof_partial_inner = partial_tree - .prove(&insertions[inner_element_index]) - .expect("Failed to generate proof"); - assert!( - proof_full_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), - "Inner proof in the full tree must be valid" - ); - assert!( - !proof_partial_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), - "Inner proof in the partial tree must be invalid" - ); - let proof_full = tree - .prove(&insertions[number_of_insertions - 1]) - .expect("Failed to generate proof"); - let proof_partial = partial_tree - .prove(&insertions[number_of_insertions - 1]) - .expect("Failed to generate proof"); - assert!( - proof_full.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), - "Final proof in the full tree must be valid" - ); - assert!( - proof_partial.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), - "Final proof in the partial tree must be valid" - ); -} - -/// -#[derive(PartialEq)] -pub enum Index { - /// - Zero, - - /// - One, -} - -impl From for usize { - fn from(value: Index) -> Self { - match value { - Index::Zero => 0, - Index::One => 1, - } - } -} - -impl FixedIndex<2> for Index { - fn from_index(index: usize) -> Self { - if index % 2 == 0 { - Index::Zero - } else { - Index::One - } - } -} - -impl forest::Configuration for Test { - type Index = Index; - fn tree_index(leaf: &Leaf) -> Self::Index { - let parity = leaf % 2; - if parity == 0 { - Index::Zero - } else { - Index::One - } - } -} -/// -#[test] -fn test_from_leaves_and_path_forest() { - let mut rng = OsRng; - const HEIGHT: usize = 7; - type Config = Test; - let parameters = Parameters::::sample(Default::default(), &mut rng); - let mut forest = - TreeArrayMerkleForest::>, 2>::new(parameters); - let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); - let mut insertions = Vec::::with_capacity(number_of_insertions); - for _ in 0..number_of_insertions { - insertions.push(rng.gen()); - } - for leaf in &insertions { - forest.insert(leaf); - } - let path_1 = Path::from(forest.forest.get(Index::Zero).current_path()); - let path_2 = Path::from(forest.forest.get(Index::One).current_path()); - let paths = vec![path_1, path_2]; - let partial_forest = - TreeArrayMerkleForest::<_, ForkedTree<_, Partial>, 2>::from_items_and_witnesses( - ¶meters, - insertions.clone(), - paths, - ); - for leaf in &insertions { - assert_eq!(forest.output_from(leaf), partial_forest.output_from(leaf)); - } -} - -/// -#[test] -fn visual_test_with_strings() { - const HEIGHT: usize = 5; - let mut rng = OsRng; - let parameters = Parameters::>::sample(Default::default(), &mut rng); - let mut tree = FullMerkleTree::>::new(parameters); - let insertions = vec![ - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", - ] - .into_iter() - .map(String::from) - .collect::>(); - for leaf in &insertions { - tree.insert(leaf); - } - let root = tree.root().clone(); - let path = tree.current_path(); - println!("{path:?}"); - let partial_tree = PartialMerkleTree::> { - parameters, - tree: Partial::from_leaves_and_path_unchecked(¶meters, insertions.clone(), path.into()), - }; - let second_root = partial_tree.root().clone(); - assert_eq!(root, second_root); - const INNER_ELEMENT_INDEX: usize = 10; // k - let proof = tree.prove(&insertions[INNER_ELEMENT_INDEX]).unwrap(); - println!("{proof:?}"); - let proof_2 = partial_tree - .prove(&insertions[INNER_ELEMENT_INDEX]) - .unwrap(); - println!("{proof_2:?}"); - let proof_3 = tree.prove(&insertions[insertions.len() - 1]).unwrap(); - let proof_4 = partial_tree - .prove(&insertions[insertions.len() - 1]) - .unwrap(); - println!("{proof_3:?}"); - println!("{proof_4:?}"); -} diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index d84395c80..a6a19942c 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -225,14 +225,14 @@ impl Ledger { for (i, mut index) in (0..MerkleTreeConfiguration::FOREST_WIDTH).enumerate() { let shard = &self.shards[&MerkleForestIndex::from_index(i)]; while let Some(entry) = shard.get_index(index) { - utxos.push(entry.0.clone()); + utxos.push(entry.0); index += 1; } } let senders = self.nullifiers.iter().cloned().collect::>(); let utxo_merkle_forest = self.utxo_forest.clone(); let mut membership_proof_data = Vec::new(); - for index in (0..MerkleTreeConfiguration::FOREST_WIDTH) { + for index in 0..MerkleTreeConfiguration::FOREST_WIDTH { membership_proof_data.push( utxo_merkle_forest .forest diff --git a/manta-trusted-setup/src/groth16/mpc.rs b/manta-trusted-setup/src/groth16/mpc.rs index abe445825..29c5aab15 100644 --- a/manta-trusted-setup/src/groth16/mpc.rs +++ b/manta-trusted-setup/src/groth16/mpc.rs @@ -513,6 +513,7 @@ where /// transitions. /// /// [`Challenge`]: mpc::ChallengeType::Challenge +#[allow(clippy::redundant_clone)] // The state clone is actually necessary here. #[inline] pub fn verify_transform_all( mut challenge: C::Challenge, From 9cc2e1fa2b348ce0be151250e8e6bda1714761e9 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Fri, 17 Mar 2023 13:52:54 +0100 Subject: [PATCH 14/34] restored cargo.toml --- manta-accounting/Cargo.toml | 1 - manta-crypto/Cargo.toml | 2 +- manta-crypto/src/merkle_tree/test/mod.rs | 327 +++++++++++++++++++ manta-crypto/src/merkle_tree/test/partial.rs | 134 ++++++++ 4 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 manta-crypto/src/merkle_tree/test/mod.rs create mode 100644 manta-crypto/src/merkle_tree/test/partial.rs diff --git a/manta-accounting/Cargo.toml b/manta-accounting/Cargo.toml index 285e85010..0150fc67a 100644 --- a/manta-accounting/Cargo.toml +++ b/manta-accounting/Cargo.toml @@ -48,7 +48,6 @@ test = [ "futures", "indexmap", "manta-crypto/arkworks", - "manta-crypto/getrandom", "manta-crypto/rand", "manta-crypto/test", "parking_lot", diff --git a/manta-crypto/Cargo.toml b/manta-crypto/Cargo.toml index 29b45adc3..d8ad63cec 100644 --- a/manta-crypto/Cargo.toml +++ b/manta-crypto/Cargo.toml @@ -70,7 +70,7 @@ std = [ ] # Testing Frameworks -test = ["getrandom"] +test = [] [dependencies] ark-bls12-381 = { version = "0.3.0", optional = true, default-features = false, features = ["curve"] } diff --git a/manta-crypto/src/merkle_tree/test/mod.rs b/manta-crypto/src/merkle_tree/test/mod.rs new file mode 100644 index 000000000..e01c4d75b --- /dev/null +++ b/manta-crypto/src/merkle_tree/test/mod.rs @@ -0,0 +1,327 @@ +// Copyright 2019-2022 Manta Network. +// This file is part of manta-rs. +// +// manta-rs is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// manta-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with manta-rs. If not, see . + +//! Testing Framework + +use crate::{ + merkle_tree::{ + forest, Configuration, HashConfiguration, IdentityLeafHash, InnerDigest, InnerHash, + InnerHashParameters, Leaf, LeafHashParameters, MerkleTree, Parameters, Path, Tree, + WithProofs, + }, + rand::{RngCore, Sample}, +}; +use alloc::string::String; +use core::{fmt::Debug, hash::Hash, marker::PhantomData}; + +#[cfg(test)] +pub mod partial; + +/// Hash Parameter Sampling +pub trait HashParameterSampling: HashConfiguration { + /// Leaf Hash Parameter Distribution + type LeafHashParameterDistribution; + + /// Inner Hash Parameter Distribution + type InnerHashParameterDistribution; + + /// Sample leaf hash parameters from `distribution` using the given `rng`. + fn sample_leaf_hash_parameters( + distribution: Self::LeafHashParameterDistribution, + rng: &mut R, + ) -> LeafHashParameters + where + R: RngCore + ?Sized; + + /// Sample inner hash parameters from `distribution` using the given `rng`. + fn sample_inner_hash_parameters( + distribution: Self::InnerHashParameterDistribution, + rng: &mut R, + ) -> InnerHashParameters + where + R: RngCore + ?Sized; +} + +/// Hash Parameter Distribution +#[derive(derivative::Derivative)] +#[derivative( + Clone( + bound = "C::LeafHashParameterDistribution: Clone, C::InnerHashParameterDistribution: Clone" + ), + Copy( + bound = "C::LeafHashParameterDistribution: Copy, C::InnerHashParameterDistribution: Copy" + ), + Debug( + bound = "C::LeafHashParameterDistribution: Debug, C::InnerHashParameterDistribution: Debug" + ), + Default( + bound = "C::LeafHashParameterDistribution: Default, C::InnerHashParameterDistribution: Default" + ), + Eq(bound = "C::LeafHashParameterDistribution: Eq, C::InnerHashParameterDistribution: Eq"), + Hash( + bound = "C::LeafHashParameterDistribution: Hash, C::InnerHashParameterDistribution: Hash" + ), + PartialEq(bound = "C::LeafHashParameterDistribution: PartialEq, + C::InnerHashParameterDistribution: PartialEq") +)] +pub struct HashParameterDistribution +where + C: HashParameterSampling + ?Sized, +{ + /// Leaf Hash Parameter Distribution + pub leaf: C::LeafHashParameterDistribution, + + /// Inner Hash Parameter Distribution + pub inner: C::InnerHashParameterDistribution, +} + +impl Sample> for Parameters +where + C: HashParameterSampling + ?Sized, +{ + #[inline] + fn sample(distribution: HashParameterDistribution, rng: &mut R) -> Self + where + R: RngCore + ?Sized, + { + Self::new( + C::sample_leaf_hash_parameters(distribution.leaf, rng), + C::sample_inner_hash_parameters(distribution.inner, rng), + ) + } +} + +/// Tests that a tree constructed with `parameters` can accept at least two leaves without +/// failing. +#[inline] +pub fn push_twice_to_empty_tree_succeeds( + parameters: Parameters, + lhs: &Leaf, + rhs: &Leaf, +) -> Parameters +where + C: Configuration + ?Sized, + T: Tree, +{ + let mut tree = MerkleTree::::new(parameters); + assert!( + tree.push(lhs), + "Trees always have a capacity of at least two." + ); + assert!( + tree.push(rhs), + "Trees always have a capacity of at least two." + ); + tree.into_parameters() +} + +/// Tests path construction by checking that the path at the given `index` on `tree` is a valid +/// [`Path`](super::Path) for `leaf`. +#[inline] +pub fn assert_valid_path(tree: &MerkleTree, index: usize, leaf: &Leaf) +where + C: Configuration + ?Sized, + T: Tree + WithProofs, + InnerDigest: Debug + PartialEq, + Path: Debug, +{ + let path = tree.path(index).expect("Only valid queries are accepted."); + let root = tree.root(); + assert!( + path.verify(tree.parameters(), root, leaf), + "Path returned from tree was not valid: {:?}. Expected {:?} but got {:?}.", + path, + root, + path.root(&tree.parameters, &tree.parameters.digest(leaf)), + ); +} + +/// Tests path construction for multiple insertions. This is an extension of the +/// [`assert_valid_path`] test. +#[inline] +pub fn assert_valid_paths(tree: &mut MerkleTree, leaves: &[Leaf]) +where + C: Configuration + ?Sized, + T: Tree + WithProofs, + InnerDigest: Debug + PartialEq, + Path: Debug, + Leaf: Sized, +{ + let starting_index = tree.len(); + for (i, leaf) in leaves.iter().enumerate() { + tree.push(leaf); + for (j, previous_leaf) in leaves.iter().enumerate().take(i + 1) { + assert_valid_path(tree, starting_index + j, previous_leaf); + } + } +} + +/// Test Inner Hash +/// +/// # Warning +/// +/// This is only meant for testing purposes, and should not be used in any production or +/// cryptographically secure environments. +pub trait TestHash { + /// Joins `lhs` and `rhs` into an output hash value. + fn join(lhs: &Self, rhs: &Self) -> Self; +} + +impl TestHash for u64 { + #[inline] + fn join(lhs: &Self, rhs: &Self) -> Self { + *lhs ^ *rhs + } +} + +impl TestHash for String { + #[inline] + fn join(lhs: &Self, rhs: &Self) -> Self { + let mut lhs = lhs.clone(); + lhs.push_str(rhs); + lhs + } +} + +/// Test Merkle Tree Configuration +/// +/// # Warning +/// +/// This is only meant for testing purposes, and should not be used in production or +/// cryptographically secure environments. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Test(PhantomData) +where + T: Clone + Default + PartialEq + TestHash; + +impl InnerHash for Test +where + T: Clone + Default + PartialEq + TestHash, +{ + type LeafDigest = T; + type Parameters = (); + type Output = T; + + #[inline] + fn join( + parameters: &Self::Parameters, + lhs: &Self::Output, + rhs: &Self::Output, + _: &mut (), + ) -> Self::Output { + let _ = parameters; + TestHash::join(lhs, rhs) + } + + #[inline] + fn join_leaves( + parameters: &Self::Parameters, + lhs: &Self::LeafDigest, + rhs: &Self::LeafDigest, + _: &mut (), + ) -> Self::Output { + let _ = parameters; + TestHash::join(lhs, rhs) + } +} + +impl HashConfiguration for Test +where + T: Clone + Default + PartialEq + TestHash, +{ + type LeafHash = IdentityLeafHash; + type InnerHash = Test; +} + +impl Configuration for Test +where + T: Clone + Default + PartialEq + TestHash, +{ + const HEIGHT: usize = HEIGHT; +} + +impl HashParameterSampling for Test +where + T: Clone + Default + PartialEq + TestHash, +{ + type LeafHashParameterDistribution = (); + type InnerHashParameterDistribution = (); + + #[inline] + fn sample_leaf_hash_parameters( + distribution: Self::LeafHashParameterDistribution, + rng: &mut R, + ) -> LeafHashParameters + where + R: RngCore + ?Sized, + { + let _ = (distribution, rng); + } + + #[inline] + fn sample_inner_hash_parameters( + distribution: Self::InnerHashParameterDistribution, + rng: &mut R, + ) -> InnerHashParameters + where + R: RngCore + ?Sized, + { + let _ = (distribution, rng); + } +} + +/// Binary Index +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum BinaryIndex { + /// Zero + Zero, + + /// One + One, +} + +impl From for usize { + fn from(value: BinaryIndex) -> Self { + match value { + BinaryIndex::Zero => 0, + BinaryIndex::One => 1, + } + } +} + +impl forest::FixedIndex<2> for BinaryIndex { + fn from_index(index: usize) -> Self { + if index % 2 == 0 { + BinaryIndex::Zero + } else { + BinaryIndex::One + } + } +} + +impl forest::Configuration for Test { + type Index = BinaryIndex; + + #[inline] + fn tree_index(leaf: &Leaf) -> Self::Index { + let parity = leaf % 2; + if parity == 0 { + BinaryIndex::Zero + } else { + BinaryIndex::One + } + } +} diff --git a/manta-crypto/src/merkle_tree/test/partial.rs b/manta-crypto/src/merkle_tree/test/partial.rs new file mode 100644 index 000000000..cf04639ee --- /dev/null +++ b/manta-crypto/src/merkle_tree/test/partial.rs @@ -0,0 +1,134 @@ +// Copyright 2019-2022 Manta Network. +// This file is part of manta-rs. +// +// manta-rs is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// manta-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with manta-rs. If not, see . + +//! Partial Merkle Tree + +use crate::{ + accumulator::{Accumulator, FromItemsAndWitnesses}, + merkle_tree::{ + forest::{Forest, TreeArrayMerkleForest}, + fork::ForkedTree, + full::{Full, FullMerkleTree}, + partial::{Partial, PartialMerkleTree}, + path::Path, + test::{BinaryIndex, Test}, + tree::Parameters, + }, + rand::{OsRng, Rand, Sample}, +}; + +/// Tests the [`Partial`] tree generated from a set of leaves and a [`Path`] behaves +/// as expected. +#[test] +fn test_from_leaves_and_path() { + let mut rng = OsRng; + const HEIGHT: usize = 7; + type Config = Test; + let parameters = Parameters::::sample(Default::default(), &mut rng); + let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); + let inner_element_index = rng.gen_range(0..number_of_insertions - 3); + println!("{number_of_insertions}, {inner_element_index}"); + let mut tree = FullMerkleTree::::new(parameters); + let mut insertions = Vec::::with_capacity(number_of_insertions); + for _ in 0..number_of_insertions { + insertions.push(rng.gen()); + } + for leaf in &insertions { + tree.insert(leaf); + } + let forked_tree = ForkedTree::>::new(tree.tree.clone(), ¶meters); + let path = tree.current_path(); + let partial_tree = PartialMerkleTree::> { + parameters, + tree: Partial::from_leaves_and_path_unchecked( + ¶meters, + insertions.clone(), + path.clone().into(), + ), + }; + let forked_partial_tree = ForkedTree::>::from_leaves_and_path_unchecked( + ¶meters, + insertions.clone(), + path.into(), + ); + let root = tree.root(); + let partial_root = partial_tree.root(); + let forked_root = forked_tree.root(); + let forked_partial_root = forked_partial_tree.root(); + assert_eq!(root, partial_root, "Roots must be equal"); + assert_eq!(root, forked_root, "Roots must be equal"); + assert_eq!(root, forked_partial_root, "Roots must be equal"); + let proof_full_inner = tree + .prove(&insertions[inner_element_index]) + .expect("Failed to generate proof"); + let proof_partial_inner = partial_tree + .prove(&insertions[inner_element_index]) + .expect("Failed to generate proof"); + assert!( + proof_full_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), + "Inner proof in the full tree must be valid" + ); + assert!( + !proof_partial_inner.verify(¶meters, &insertions[inner_element_index], &mut ()), + "Inner proof in the partial tree must be invalid" + ); + let proof_full = tree + .prove(&insertions[number_of_insertions - 1]) + .expect("Failed to generate proof"); + let proof_partial = partial_tree + .prove(&insertions[number_of_insertions - 1]) + .expect("Failed to generate proof"); + assert!( + proof_full.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), + "Final proof in the full tree must be valid" + ); + assert!( + proof_partial.verify(¶meters, &insertions[number_of_insertions - 1], &mut ()), + "Final proof in the partial tree must be valid" + ); +} + +/// Tests the forest consisting of [`Partial`] trees generated from a set of leaves +/// and a [`Path`]s behaves as expected. +#[test] +fn test_from_leaves_and_path_forest() { + let mut rng = OsRng; + const HEIGHT: usize = 7; + type Config = Test; + let parameters = Parameters::::sample(Default::default(), &mut rng); + let mut forest = + TreeArrayMerkleForest::>, 2>::new(parameters); + let number_of_insertions = rng.gen_range(5..(1 << (HEIGHT - 1))); + let mut insertions = Vec::::with_capacity(number_of_insertions); + for _ in 0..number_of_insertions { + insertions.push(rng.gen()); + } + for leaf in &insertions { + forest.insert(leaf); + } + let path_1 = Path::from(forest.forest.get(BinaryIndex::Zero).current_path()); + let path_2 = Path::from(forest.forest.get(BinaryIndex::One).current_path()); + let paths = vec![path_1, path_2]; + let partial_forest = + TreeArrayMerkleForest::<_, ForkedTree<_, Partial>, 2>::from_items_and_witnesses( + ¶meters, + insertions.clone(), + paths, + ); + for leaf in &insertions { + assert_eq!(forest.output_from(leaf), partial_forest.output_from(leaf)); + } +} From 68ce7ac8a48fce8098e1bc7aeed73c26a6d8ddb4 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Fri, 17 Mar 2023 13:54:07 +0100 Subject: [PATCH 15/34] clippy --- manta-pay/src/simulation/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index 5f4523b0c..e11dc845b 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -27,7 +27,7 @@ use crate::{ simulation::ledger::{Ledger, LedgerConnection}, }; use alloc::{format, sync::Arc}; -use core::{fmt::Debug, ops::Deref}; +use core::{fmt::Debug}; use manta_accounting::{ self, asset::AssetList, From d9c2a77801038f3ad39f009e75a79359ffb8717b Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Fri, 17 Mar 2023 14:29:52 +0100 Subject: [PATCH 16/34] changed nullifier data and batched the initial sync --- manta-accounting/src/wallet/mod.rs | 23 ++++++++++++------- .../src/wallet/signer/functions.rs | 8 +++---- manta-accounting/src/wallet/signer/mod.rs | 6 ++--- manta-pay/src/simulation/ledger/mod.rs | 2 +- manta-pay/src/simulation/mod.rs | 2 +- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 8b4138ed4..88cab5b03 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -268,11 +268,21 @@ where /// #[inline] pub async fn initial_sync(&mut self) -> Result<(), Error> + where + L: ledger::Read, Checkpoint = S::Checkpoint>, + { + while self.initial_sync_partial().await?.is_continue() {} + Ok(()) + } + + /// + #[inline] + pub async fn initial_sync_partial(&mut self) -> Result> where L: ledger::Read, Checkpoint = S::Checkpoint>, { let ReadResponse { - should_continue: _, + should_continue, data, } = self .ledger @@ -280,7 +290,7 @@ where .await .map_err(Error::LedgerConnectionError)?; self.signer_initial_sync(data).await?; - Ok(()) + Ok(ControlFlow::should_continue(should_continue)) } /// Pulls data from the ledger, synchronizing the wallet and balance state. This method returns @@ -385,16 +395,13 @@ where balance_update, }) => { match balance_update { - BalanceUpdate::Partial { deposit, withdraw } => { - self.assets.deposit_all(deposit); - if !self.assets.withdraw_all(withdraw) { - return Err(Error::Inconsistency(InconsistencyError::WalletBalance)); - } - } BalanceUpdate::Full { assets } => { self.assets.clear(); self.assets.deposit_all(assets); } + _ => { + unreachable!("No transactions could have happened on a new account."); + } } self.checkpoint = checkpoint; Ok(()) diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index 3f5d3663b..018369d12 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -949,7 +949,7 @@ where let InitialSyncData { utxo_data, membership_proof_data, - nullifier_data, + nullifier_count, } = request; let (accumulator, response) = initial_sync_with::( assets, @@ -958,7 +958,7 @@ where ¶meters.parameters, utxo_data, membership_proof_data, - nullifier_data, + nullifier_count, ); *utxo_accumulator = accumulator; utxo_accumulator.commit(); @@ -975,7 +975,7 @@ fn initial_sync_with( parameters: &Parameters, utxos: Vec>, membership_proof_data: Vec>, - nullifiers: Vec>, + nullifier_count: u128, ) -> (C::UtxoAccumulator, SyncResponse) where C: Configuration, @@ -988,7 +988,7 @@ where .collect(), membership_proof_data, ); - checkpoint.update_from_nullifiers(nullifiers.len()); + checkpoint.update_from_nullifiers(nullifier_count as usize); checkpoint.update_from_utxo_accumulator(&accumulator); ( accumulator, diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index fc15209bb..0d90785f6 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -155,11 +155,11 @@ where /// UTXO Data pub utxo_data: Vec>, - /// Nullifier Data - pub nullifier_data: Vec>, - /// Membership Proof Data pub membership_proof_data: Vec>, + + /// Nullifier Count + pub nullifier_count: u128, } /// Signer Synchronization Data diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index a6a19942c..fd30b3c14 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -246,8 +246,8 @@ impl Ledger { should_continue: false, data: InitialSyncData { utxo_data: utxos, - nullifier_data: senders, membership_proof_data, + nullifier_count: senders.len() as u128, }, } } diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index e11dc845b..fffe65bc9 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -27,7 +27,7 @@ use crate::{ simulation::ledger::{Ledger, LedgerConnection}, }; use alloc::{format, sync::Arc}; -use core::{fmt::Debug}; +use core::fmt::Debug; use manta_accounting::{ self, asset::AssetList, From e57d2b6b4296d59d0415b4ad4472de6c69a9d91b Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Mon, 20 Mar 2023 15:22:19 +0100 Subject: [PATCH 17/34] final design --- manta-accounting/src/transfer/mod.rs | 1 + manta-accounting/src/wallet/mod.rs | 56 ++++---- .../src/wallet/signer/functions.rs | 24 ++-- manta-accounting/src/wallet/signer/mod.rs | 124 +++++++++++++++++- manta-accounting/src/wallet/test/mod.rs | 3 +- manta-crypto/src/accumulator.rs | 9 +- manta-crypto/src/merkle_tree/forest.rs | 89 ++++++++----- manta-pay/src/signer/base.rs | 5 + manta-pay/src/signer/client/http.rs | 15 ++- manta-pay/src/signer/client/websocket.rs | 15 ++- manta-pay/src/signer/mod.rs | 3 + manta-pay/src/simulation/mod.rs | 3 +- 12 files changed, 256 insertions(+), 91 deletions(-) diff --git a/manta-accounting/src/transfer/mod.rs b/manta-accounting/src/transfer/mod.rs index 0ccc7b6ba..5e6d89da1 100644 --- a/manta-accounting/src/transfer/mod.rs +++ b/manta-accounting/src/transfer/mod.rs @@ -152,6 +152,7 @@ pub trait Configuration { + auth::ProveAuthorization + auth::VerifyAuthorization + auth::DeriveSigningKey + + Clone + for<'a> auth::Sign> + for<'a> auth::VerifySignature> + utxo::AssetType> diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 88cab5b03..97e7a37e4 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -37,9 +37,9 @@ use crate::{ balance::{BTreeMapBalanceState, BalanceState}, ledger::ReadResponse, signer::{ - BalanceUpdate, IdentityRequest, IdentityResponse, InitialSyncData, SignError, - SignRequest, SignResponse, SignWithTransactionDataResponse, SyncData, SyncError, - SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, + BalanceUpdate, Checkpoint, IdentityRequest, IdentityResponse, InitialSyncData, + SignError, SignRequest, SignResponse, SignWithTransactionDataResponse, SyncData, + SyncError, SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }, }; @@ -50,6 +50,8 @@ use manta_util::ops::ControlFlow; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; +use self::signer::InitialSyncRequest; + pub mod balance; pub mod ledger; pub mod signer; @@ -270,29 +272,37 @@ where pub async fn initial_sync(&mut self) -> Result<(), Error> where L: ledger::Read, Checkpoint = S::Checkpoint>, + C: signer::Configuration, + S::Checkpoint: signer::Checkpoint, { - while self.initial_sync_partial().await?.is_continue() {} + let mut is_continue = true; + let mut checkpoint = self.checkpoint.clone(); + let mut request = InitialSyncRequest::::default(); + while is_continue { + let ReadResponse { + should_continue, + data, + } = self + .ledger + .read(&checkpoint) + .await + .map_err(Error::LedgerConnectionError)?; + is_continue = should_continue; + request.extend_with_data( + &self + .signer + .transfer_parameters() + .await + .map_err(Error::SignerConnectionError)?, + data, + ); + checkpoint + .update_from_utxo_count(request.utxo_data.iter().map(|utxos| utxos.len()).collect()) + } + self.signer_initial_sync(request).await?; Ok(()) } - /// - #[inline] - pub async fn initial_sync_partial(&mut self) -> Result> - where - L: ledger::Read, Checkpoint = S::Checkpoint>, - { - let ReadResponse { - should_continue, - data, - } = self - .ledger - .read(&self.checkpoint) - .await - .map_err(Error::LedgerConnectionError)?; - self.signer_initial_sync(data).await?; - Ok(ControlFlow::should_continue(should_continue)) - } - /// Pulls data from the ledger, synchronizing the wallet and balance state. This method returns /// a [`ControlFlow`] for matching against to determine if the wallet requires more /// synchronization. @@ -382,7 +392,7 @@ where #[inline] async fn signer_initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> Result<(), Error> { match self .signer diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index 018369d12..3c60b8765 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -35,9 +35,9 @@ use crate::{ UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoAccumulatorWitness, }, wallet::signer::{ - AccountTable, BalanceUpdate, Checkpoint, Configuration, InitialSyncData, SignError, - SignResponse, SignWithTransactionDataResponse, SignWithTransactionDataResult, - SignerParameters, SyncData, SyncError, SyncRequest, SyncResponse, + AccountTable, BalanceUpdate, Checkpoint, Configuration, SignError, SignResponse, + SignWithTransactionDataResponse, SignWithTransactionDataResult, SignerParameters, SyncData, + SyncError, SyncRequest, SyncResponse, }, }; use alloc::{vec, vec::Vec}; @@ -50,6 +50,8 @@ use manta_util::{ vec::VecExt, }; +use super::InitialSyncRequest; + /// Returns the default account for `accounts`. #[inline] pub fn default_account(accounts: &AccountTable) -> Account @@ -110,7 +112,7 @@ where /// Hashes `utxo` using the [`UtxoAccumulatorItemHash`](transfer::Configuration::UtxoAccumulatorItemHash) /// in the transfer [`Configuration`](transfer::Configuration). #[inline] -fn item_hash(parameters: &C::Parameters, utxo: &Utxo) -> UtxoAccumulatorItem +pub fn item_hash(parameters: &C::Parameters, utxo: &Utxo) -> UtxoAccumulatorItem where C: Configuration, { @@ -937,16 +939,15 @@ where /// Updates `assets`, `checkpoint` and `utxo_accumulator`, returning the new asset distribution. #[inline] pub fn intial_sync( - parameters: &SignerParameters, assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator: &mut C::UtxoAccumulator, - request: InitialSyncData, + request: InitialSyncRequest, ) -> Result, SyncError> where C: Configuration, { - let InitialSyncData { + let InitialSyncRequest { utxo_data, membership_proof_data, nullifier_count, @@ -955,7 +956,6 @@ where assets, checkpoint, utxo_accumulator.model(), - ¶meters.parameters, utxo_data, membership_proof_data, nullifier_count, @@ -972,8 +972,7 @@ fn initial_sync_with( assets: &mut C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator_model: &UtxoAccumulatorModel, - parameters: &Parameters, - utxos: Vec>, + utxos: Vec>>, membership_proof_data: Vec>, nullifier_count: u128, ) -> (C::UtxoAccumulator, SyncResponse) @@ -982,10 +981,7 @@ where { let accumulator = C::UtxoAccumulator::from_items_and_witnesses( utxo_accumulator_model, - utxos - .iter() - .map(|utxo| item_hash::(parameters, utxo)) - .collect(), + utxos, membership_proof_data, ); checkpoint.update_from_nullifiers(nullifier_count as usize); diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 0d90785f6..1d5c8325b 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -82,7 +82,7 @@ where /// fn initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> LocalBoxFutureResult, Self::Error>; /// Signs a transaction and returns the ledger transfer posts if successful. @@ -115,6 +115,9 @@ where ) -> LocalBoxFutureResult, Self::Error> where TransferPost: Clone; + + /// + fn transfer_parameters(&mut self) -> LocalBoxFutureResult, Self::Error>; } /// Signer Initial Synchronization Data @@ -162,6 +165,106 @@ where pub nullifier_count: u128, } +/// Signer Initial Synchronization Request +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde( + bound( + deserialize = r" + UtxoAccumulatorItem: Deserialize<'de>, + UtxoAccumulatorWitness: Deserialize<'de>, + Nullifier: Deserialize<'de>, + ", + serialize = r" + UtxoAccumulatorItem: Serialize, + UtxoAccumulatorWitness: Serialize, + Nullifier: Serialize, + ", + ), + crate = "manta_util::serde", + deny_unknown_fields + ) +)] +#[derive(derivative::Derivative)] +#[derivative( + Clone( + bound = "UtxoAccumulatorItem: Clone, UtxoAccumulatorWitness: Clone, Nullifier: Clone" + ), + Debug( + bound = "UtxoAccumulatorItem: Debug, UtxoAccumulatorWitness: Debug, Nullifier: Debug" + ), + Default(bound = ""), + Eq(bound = "UtxoAccumulatorItem: Eq, UtxoAccumulatorWitness: Eq, Nullifier: Eq"), + Hash( + bound = "UtxoAccumulatorItem: Hash, UtxoAccumulatorWitness: Hash, Nullifier: Hash" + ), + PartialEq( + bound = "UtxoAccumulatorItem: PartialEq, UtxoAccumulatorWitness: PartialEq, Nullifier: PartialEq" + ) +)] +pub struct InitialSyncRequest +where + C: transfer::Configuration + ?Sized, +{ + /// UTXO Data + pub utxo_data: Vec>>, + + /// Membership Proof Data + pub membership_proof_data: Vec>, + + /// Nullifier Count + pub nullifier_count: u128, +} + +impl InitialSyncRequest +where + C: transfer::Configuration, +{ + /// + #[inline] + pub fn from_initial_sync_data(parameters: &Parameters, data: InitialSyncData) -> Self + where + C: Configuration, + { + Self { + utxo_data: C::UtxoAccumulator::sort_items( + data.utxo_data + .iter() + .map(|utxo| functions::item_hash::(parameters, utxo)) + .collect(), + ), + membership_proof_data: data.membership_proof_data, + nullifier_count: data.nullifier_count, + } + } + + /// + #[inline] + pub fn extend_with_data(&mut self, parameters: &Parameters, data: InitialSyncData) + where + C: Configuration, + { + let InitialSyncData { + utxo_data, + membership_proof_data, + nullifier_count, + } = data; + let sorted_utxo_data = C::UtxoAccumulator::sort_items( + utxo_data + .iter() + .map(|utxo| functions::item_hash::(parameters, utxo)) + .collect(), + ); + for (old_vector, new_vector) in self.utxo_data.iter_mut().zip(sorted_utxo_data.into_iter()) + { + old_vector.extend(new_vector) + } + self.membership_proof_data = membership_proof_data; + self.nullifier_count = nullifier_count; + } +} + /// Signer Synchronization Data #[cfg_attr( feature = "serde", @@ -684,6 +787,9 @@ where /// Updates `self` by viewing a new `accumulator`. fn update_from_utxo_accumulator(&mut self, accumulator: &Self::UtxoAccumulator); + /// + fn update_from_utxo_count(&mut self, utxo_count: Vec); + /// Computes a best-effort [`Checkpoint`] from the current `accumulator` state. #[inline] fn from_utxo_accumulator(accumulator: &Self::UtxoAccumulator) -> Self { @@ -1137,10 +1243,9 @@ where #[inline] pub fn initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> Result, SyncError> { functions::intial_sync( - &self.parameters, &mut self.state.assets, &mut self.state.checkpoint, &mut self.state.utxo_accumulator, @@ -1275,6 +1380,12 @@ where } false } + + /// + #[inline] + pub fn transfer_parameters(&self) -> Parameters { + self.parameters.parameters.clone() + } } impl Connection for Signer @@ -1296,7 +1407,7 @@ where #[inline] fn initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> LocalBoxFutureResult, Self::Error> { Box::pin(async move { Ok(self.initial_sync(request)) }) } @@ -1340,6 +1451,11 @@ where { Box::pin(async move { Ok(self.sign_with_transaction_data(request.transaction)) }) } + + #[inline] + fn transfer_parameters(&mut self) -> LocalBoxFutureResult, Self::Error> { + Box::pin(async move { Ok(Signer::transfer_parameters(self)) }) + } } /// Storage State diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index bf92913c4..10409fd2d 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -990,7 +990,7 @@ impl Config { mut event_subscriber: ES, ) -> Result> where - C: Configuration, + C: signer::Configuration, C::AssetValue: AddAssign + SampleUniform, for<'v> &'v C::AssetValue: CheckedSub, L: Ledger @@ -1001,6 +1001,7 @@ impl Config { >, Error: Debug, S: signer::Connection>>::Checkpoint>, + S::Checkpoint: signer::Checkpoint, S::Error: Debug, B: BalanceState, R: CryptoRng + RngCore, diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index d08348392..3f883fc43 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -205,15 +205,16 @@ pub trait OptimizedAccumulator: Accumulator { /// From Items and Witnesses pub trait FromItemsAndWitnesses: Accumulator { - /// Number of Proofs - const NUMBER_OF_PROOFS: usize; - /// Builds a new [`Self`] from `items` and `proofs`. fn from_items_and_witnesses( model: &Self::Model, - items: Vec, + items: Vec>, witnesses: Vec, ) -> Self; + + /// Sorts `items`. + // TODO: move this to the model. + fn sort_items(items: Vec) -> Vec>; } /// Accumulator Membership Proof diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 1927ea48a..c69f5e8e3 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -539,22 +539,21 @@ where #[inline] pub fn from_leaves_and_paths_unchecked( parameters: &Parameters, - leaves: Vec>, + leaves: Vec>>, paths: Vec>, ) -> Self { - TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( - |(tree_index, path)| { - Partial::from_leaves_and_path_unchecked( - parameters, - leaves - .iter() - .filter(|leaf| C::tree_index(leaf).into() == tree_index) - .map(|leaf| parameters.digest(leaf)) - .collect(), - path, - ) - }, - ))) + TreeArray::new(BoxArray::from_iter( + leaves + .into_iter() + .zip(paths.into_iter()) + .map(|(leaves, path)| { + Partial::from_leaves_and_path_unchecked( + parameters, + leaves.iter().map(|leaf| parameters.digest(leaf)).collect(), + path, + ) + }), + )) } } @@ -571,22 +570,21 @@ where #[inline] pub fn from_leaves_and_paths_unchecked( parameters: &Parameters, - leaves: Vec>, + leaves: Vec>>, paths: Vec>, ) -> Self { - TreeArray::new(BoxArray::from_iter(paths.into_iter().enumerate().map( - |(tree_index, path)| { - ForkedTree::from_leaves_and_path_unchecked( - parameters, - leaves - .iter() - .filter(|leaf| C::tree_index(leaf).into() == tree_index) - .map(|leaf| parameters.digest(leaf)) - .collect(), - path, - ) - }, - ))) + TreeArray::new(BoxArray::from_iter( + leaves + .into_iter() + .zip(paths.into_iter()) + .map(|(leaves, path)| { + ForkedTree::from_leaves_and_path_unchecked( + parameters, + leaves.iter().map(|leaf| parameters.digest(leaf)).collect(), + path, + ) + }), + )) } } @@ -598,20 +596,32 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { - const NUMBER_OF_PROOFS: usize = N; - #[inline] fn from_items_and_witnesses( model: &Self::Model, - items: Vec, + items: Vec>, witnesses: Vec, ) -> Self { assert_eq!(witnesses.len(), N); + assert_eq!(items.len(), N); Self::from_forest( TreeArray::, N>::from_leaves_and_paths_unchecked(model, items, witnesses), model.clone(), ) } + + #[inline] + fn sort_items(items: Vec) -> Vec> { + let mut result = Vec::>::default(); + result.resize_with(N, Default::default); + + for item in items { + let tree_index = C::tree_index(&item).into(); + result[tree_index].push(item); + } + + result + } } impl FromItemsAndWitnesses @@ -623,12 +633,10 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { - const NUMBER_OF_PROOFS: usize = N; - #[inline] fn from_items_and_witnesses( model: &Self::Model, - items: Vec, + items: Vec>, witnesses: Vec, ) -> Self { assert_eq!(witnesses.len(), N); @@ -639,6 +647,19 @@ where model.clone(), ) } + + #[inline] + fn sort_items(items: Vec) -> Vec> { + let mut result = Vec::>::default(); + result.resize_with(N, Default::default); + + for item in items { + let tree_index = C::tree_index(&item).into(); + result[tree_index].push(item); + } + + result + } } impl AsRef<[T; N]> for TreeArray diff --git a/manta-pay/src/signer/base.rs b/manta-pay/src/signer/base.rs index ab0635a22..50668c90c 100644 --- a/manta-pay/src/signer/base.rs +++ b/manta-pay/src/signer/base.rs @@ -112,6 +112,11 @@ impl signer::Checkpoint for Checkpoint { .collect(); } + #[inline] + fn update_from_utxo_count(&mut self, utxo_count: Vec) { + self.receiver_index = manta_util::Array(utxo_count.try_into().expect("Wrong size")); + } + /// Prunes the `data` by comparing `origin` and `signer_checkpoint` and checks if updating the /// `origin` checkpoint by viewing `data` would exceed the current `signer_checkpoint`. If not, /// then we can prune all the data. Otherwise, we take each entry in `data` and remove by shard diff --git a/manta-pay/src/signer/client/http.rs b/manta-pay/src/signer/client/http.rs index 20448ed48..fa5d0668c 100644 --- a/manta-pay/src/signer/client/http.rs +++ b/manta-pay/src/signer/client/http.rs @@ -17,12 +17,12 @@ //! Signer HTTP Client Implementation use crate::{ - config::{utxo::Address, Config}, + config::{utxo::Address, Config, Parameters}, signer::{ client::network::{Message, Network}, - AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, InitialSyncData, - SignError, SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, - SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, + AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, + InitialSyncRequest, SignError, SignRequest, SignResponse, SignWithTransactionDataResult, + SyncError, SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }; use alloc::boxed::Box; @@ -105,7 +105,7 @@ impl signer::Connection for Client { #[inline] fn initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> LocalBoxFutureResult, Self::Error> { Box::pin(self.post_request("initial_sync", request)) } @@ -146,4 +146,9 @@ impl signer::Connection for Client { ) -> LocalBoxFutureResult { Box::pin(self.post_request("sign_with_transaction_data", request)) } + + #[inline] + fn transfer_parameters(&mut self) -> LocalBoxFutureResult { + Box::pin(self.post_request("transfer_parameters", GetRequest::Get)) + } } diff --git a/manta-pay/src/signer/client/websocket.rs b/manta-pay/src/signer/client/websocket.rs index 376869a5f..6c7811f59 100644 --- a/manta-pay/src/signer/client/websocket.rs +++ b/manta-pay/src/signer/client/websocket.rs @@ -19,11 +19,11 @@ // TODO: Make this code work on WASM and non-WASM by choosing the correct dependency library. use crate::{ - config::{utxo::Address, Config}, + config::{utxo::Address, Config, Parameters}, signer::{ - AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, InitialSyncData, - SignError, SignRequest, SignResponse, SignWithTransactionDataResult, SyncError, - SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, + AssetMetadata, Checkpoint, GetRequest, IdentityRequest, IdentityResponse, + InitialSyncRequest, SignError, SignRequest, SignResponse, SignWithTransactionDataResult, + SyncError, SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, }, }; use alloc::boxed::Box; @@ -143,7 +143,7 @@ impl signer::Connection for Client { #[inline] fn initial_sync( &mut self, - request: InitialSyncData, + request: InitialSyncRequest, ) -> LocalBoxFutureResult, Self::Error> { Box::pin(self.send("initial_sync", request)) } @@ -184,4 +184,9 @@ impl signer::Connection for Client { ) -> LocalBoxFutureResult { Box::pin(self.send("sign_with_transaction_data", request)) } + + #[inline] + fn transfer_parameters(&mut self) -> LocalBoxFutureResult { + Box::pin(self.send("transfer_parameters", GetRequest::Get)) + } } diff --git a/manta-pay/src/signer/mod.rs b/manta-pay/src/signer/mod.rs index 71808ebde..2575e30a7 100644 --- a/manta-pay/src/signer/mod.rs +++ b/manta-pay/src/signer/mod.rs @@ -43,6 +43,9 @@ pub type SyncRequest = signer::SyncRequest; /// Initial Synchronization Data pub type InitialSyncData = signer::InitialSyncData; +/// Initial Synchronization Request +pub type InitialSyncRequest = signer::InitialSyncRequest; + /// Synchronization Response pub type SyncResponse = signer::SyncResponse; diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index fffe65bc9..47dd5d6dd 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -33,7 +33,7 @@ use manta_accounting::{ asset::AssetList, key::AccountTable, wallet::{ - self, + self, signer, signer::SyncData, test::{self, PublicBalanceOracle}, Error, @@ -173,6 +173,7 @@ impl Simulation { Config, Checkpoint = >>::Checkpoint, >, + S::Checkpoint: signer::Checkpoint, S::Error: Debug, GL: FnMut(usize) -> L, GS: FnMut(usize) -> S, From 1d83f3c35a1781d0e93b6addc63c1f591dc0d01a Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Mon, 20 Mar 2023 19:31:29 +0100 Subject: [PATCH 18/34] export type CurrentPath --- manta-pay/src/config/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manta-pay/src/config/mod.rs b/manta-pay/src/config/mod.rs index ae6866c9e..790a7cd98 100644 --- a/manta-pay/src/config/mod.rs +++ b/manta-pay/src/config/mod.rs @@ -25,6 +25,7 @@ use manta_crypto::arkworks::{ self, constraints::EdwardsVar as Bn254_EdwardsVar, EdwardsProjective as Bn254_Edwards, }, groth16, + merkle_tree::path::CurrentPath, }; #[cfg(feature = "bs58")] @@ -149,6 +150,9 @@ pub type AssetValue = transfer::AssetValue; /// Asset Type pub type Asset = transfer::Asset; +/// Current Path Type +pub type CurrentPath = CurrentPath; + /// Unspent Transaction Output Type pub type Utxo = transfer::Utxo; From 976ae741bafd143baa520bcc930221383ba9dcbf Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Mon, 20 Mar 2023 19:43:52 +0100 Subject: [PATCH 19/34] small error --- manta-pay/src/config/mod.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/manta-pay/src/config/mod.rs b/manta-pay/src/config/mod.rs index 790a7cd98..d61f7a51e 100644 --- a/manta-pay/src/config/mod.rs +++ b/manta-pay/src/config/mod.rs @@ -17,15 +17,17 @@ //! Manta-Pay Configuration use manta_accounting::transfer; -use manta_crypto::arkworks::{ - algebra::{self, ScalarVar}, - bn254::{self, Bn254}, - constraint::{FpVar, R1CS}, - ed_on_bn254::{ - self, constraints::EdwardsVar as Bn254_EdwardsVar, EdwardsProjective as Bn254_Edwards, +use manta_crypto::{ + arkworks::{ + algebra::{self, ScalarVar}, + bn254::{self, Bn254}, + constraint::{FpVar, R1CS}, + ed_on_bn254::{ + self, constraints::EdwardsVar as Bn254_EdwardsVar, EdwardsProjective as Bn254_Edwards, + }, + groth16, }, - groth16, - merkle_tree::path::CurrentPath, + merkle_tree::path, }; #[cfg(feature = "bs58")] @@ -151,7 +153,7 @@ pub type AssetValue = transfer::AssetValue; pub type Asset = transfer::Asset; /// Current Path Type -pub type CurrentPath = CurrentPath; +pub type CurrentPath = path::CurrentPath; /// Unspent Transaction Output Type pub type Utxo = transfer::Utxo; From e16c651596470e8c0a4ae4df8d586bfc784e5ace Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Tue, 21 Mar 2023 20:34:42 +0100 Subject: [PATCH 20/34] debugging --- manta-accounting/src/wallet/mod.rs | 4 +++- manta-accounting/src/wallet/test/mod.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 97e7a37e4..bf0d9e7d6 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -31,7 +31,7 @@ use crate::{ asset::AssetList, transfer::{ canonical::{Transaction, TransactionKind}, - Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorModel, + Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorModel, UtxoAccumulatorItem, }, wallet::{ balance::{BTreeMapBalanceState, BalanceState}, @@ -274,6 +274,7 @@ where L: ledger::Read, Checkpoint = S::Checkpoint>, C: signer::Configuration, S::Checkpoint: signer::Checkpoint, + UtxoAccumulatorItem: Debug, { let mut is_continue = true; let mut checkpoint = self.checkpoint.clone(); @@ -296,6 +297,7 @@ where .map_err(Error::SignerConnectionError)?, data, ); + panic!("Utxo data: {:?}", request.utxo_data); checkpoint .update_from_utxo_count(request.utxo_data.iter().map(|utxos| utxos.len()).collect()) } diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index 10409fd2d..be4aaec3f 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -21,7 +21,7 @@ use crate::{ asset::AssetList, - transfer::{canonical::Transaction, Address, Asset, Configuration, TransferPost}, + transfer::{canonical::Transaction, Address, Asset, Configuration, TransferPost, UtxoAccumulatorItem}, wallet::{ ledger, signer::{self, InitialSyncData, SyncData}, @@ -1012,6 +1012,7 @@ impl Config { ES: Copy + FnMut(&sim::Event>>) -> ESFut, ESFut: Future, Address: Clone + Eq + Hash, + UtxoAccumulatorItem: Debug, { let action_distribution = ActionDistribution::try_from(self.action_distribution) .expect("Unable to sample from action distribution."); From 0c1506dc32c1d35ff587a33eeab0670828fb6b03 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Tue, 21 Mar 2023 20:43:07 +0100 Subject: [PATCH 21/34] debug --- manta-accounting/src/wallet/mod.rs | 1 - manta-accounting/src/wallet/signer/mod.rs | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index bf0d9e7d6..2dd87d72d 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -297,7 +297,6 @@ where .map_err(Error::SignerConnectionError)?, data, ); - panic!("Utxo data: {:?}", request.utxo_data); checkpoint .update_from_utxo_count(request.utxo_data.iter().map(|utxos| utxos.len()).collect()) } diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 1d5c8325b..ecf75fa65 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -244,6 +244,7 @@ where pub fn extend_with_data(&mut self, parameters: &Parameters, data: InitialSyncData) where C: Configuration, + UtxoAccumulatorItem: Debug, { let InitialSyncData { utxo_data, @@ -256,6 +257,7 @@ where .map(|utxo| functions::item_hash::(parameters, utxo)) .collect(), ); + panic!("Sorted utxo data: {:?}", sorted_utxo_data); for (old_vector, new_vector) in self.utxo_data.iter_mut().zip(sorted_utxo_data.into_iter()) { old_vector.extend(new_vector) From bcd0aff73d174cb811d42d93c818349e14d092b3 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Tue, 21 Mar 2023 21:22:02 +0100 Subject: [PATCH 22/34] debugging --- manta-accounting/src/wallet/signer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index ecf75fa65..5f3d924ec 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -257,11 +257,11 @@ where .map(|utxo| functions::item_hash::(parameters, utxo)) .collect(), ); - panic!("Sorted utxo data: {:?}", sorted_utxo_data); for (old_vector, new_vector) in self.utxo_data.iter_mut().zip(sorted_utxo_data.into_iter()) { old_vector.extend(new_vector) } + panic!("Utxo data: {:?}", self.utxo_data); self.membership_proof_data = membership_proof_data; self.nullifier_count = nullifier_count; } From 69a088bb12af27ba07de373fb0655d033252ab36 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Tue, 21 Mar 2023 21:32:49 +0100 Subject: [PATCH 23/34] changed default impl --- manta-accounting/src/wallet/mod.rs | 3 ++- manta-accounting/src/wallet/signer/mod.rs | 20 ++++++++++++++++++-- manta-accounting/src/wallet/test/mod.rs | 4 +++- manta-crypto/src/accumulator.rs | 3 +++ manta-crypto/src/merkle_tree/forest.rs | 4 ++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 2dd87d72d..a313d4391 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -31,7 +31,8 @@ use crate::{ asset::AssetList, transfer::{ canonical::{Transaction, TransactionKind}, - Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorModel, UtxoAccumulatorItem, + Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorItem, + UtxoAccumulatorModel, }, wallet::{ balance::{BTreeMapBalanceState, BalanceState}, diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index 5f3d924ec..e9a9e25a2 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -194,7 +194,6 @@ where Debug( bound = "UtxoAccumulatorItem: Debug, UtxoAccumulatorWitness: Debug, Nullifier: Debug" ), - Default(bound = ""), Eq(bound = "UtxoAccumulatorItem: Eq, UtxoAccumulatorWitness: Eq, Nullifier: Eq"), Hash( bound = "UtxoAccumulatorItem: Hash, UtxoAccumulatorWitness: Hash, Nullifier: Hash" @@ -261,12 +260,29 @@ where { old_vector.extend(new_vector) } - panic!("Utxo data: {:?}", self.utxo_data); self.membership_proof_data = membership_proof_data; self.nullifier_count = nullifier_count; } } +impl Default for InitialSyncRequest +where + C: Configuration, +{ + #[inline] + fn default() -> Self { + let mut utxo_data = Vec::>::default(); + let mut membership_proof_data = Vec::new(); + utxo_data.resize_with(C::UtxoAccumulator::NUMBER_OF_PROOFS, Default::default); + membership_proof_data.resize_with(C::UtxoAccumulator::NUMBER_OF_PROOFS, Default::default); + Self { + utxo_data, + membership_proof_data, + nullifier_count: Default::default(), + } + } +} + /// Signer Synchronization Data #[cfg_attr( feature = "serde", diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index be4aaec3f..a8cfa97ab 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -21,7 +21,9 @@ use crate::{ asset::AssetList, - transfer::{canonical::Transaction, Address, Asset, Configuration, TransferPost, UtxoAccumulatorItem}, + transfer::{ + canonical::Transaction, Address, Asset, Configuration, TransferPost, UtxoAccumulatorItem, + }, wallet::{ ledger, signer::{self, InitialSyncData, SyncData}, diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 3f883fc43..5d2f3feda 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -205,6 +205,9 @@ pub trait OptimizedAccumulator: Accumulator { /// From Items and Witnesses pub trait FromItemsAndWitnesses: Accumulator { + /// + const NUMBER_OF_PROOFS: usize; + /// Builds a new [`Self`] from `items` and `proofs`. fn from_items_and_witnesses( model: &Self::Model, diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index c69f5e8e3..4e8df6eff 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -596,6 +596,8 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { + const NUMBER_OF_PROOFS: usize = N; + #[inline] fn from_items_and_witnesses( model: &Self::Model, @@ -633,6 +635,8 @@ where LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { + const NUMBER_OF_PROOFS: usize = N; + #[inline] fn from_items_and_witnesses( model: &Self::Model, From 087e7b65ca35bd21f4ba584c313c9bd091acc478 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 14:32:27 +0100 Subject: [PATCH 24/34] first round of corrections --- manta-accounting/src/transfer/mod.rs | 4 +- manta-accounting/src/wallet/mod.rs | 26 ++- .../src/wallet/signer/functions.rs | 12 +- manta-accounting/src/wallet/signer/mod.rs | 30 ++- manta-crypto/src/accumulator.rs | 2 +- manta-crypto/src/merkle_tree/forest.rs | 212 +++++++----------- manta-crypto/src/merkle_tree/inner_tree.rs | 2 +- manta-pay/src/signer/base.rs | 7 +- 8 files changed, 136 insertions(+), 159 deletions(-) diff --git a/manta-accounting/src/transfer/mod.rs b/manta-accounting/src/transfer/mod.rs index 5e6d89da1..ccd9980d4 100644 --- a/manta-accounting/src/transfer/mod.rs +++ b/manta-accounting/src/transfer/mod.rs @@ -148,11 +148,11 @@ pub trait Configuration { type UtxoAccumulatorItemHash: ItemHashFunction, Item = UtxoAccumulatorItem>; /// Parameters Type - type Parameters: auth::DeriveContext + type Parameters: Clone + + auth::DeriveContext + auth::ProveAuthorization + auth::VerifyAuthorization + auth::DeriveSigningKey - + Clone + for<'a> auth::Sign> + for<'a> auth::VerifySignature> + utxo::AssetType> diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index a313d4391..b1cf14c2f 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -39,8 +39,9 @@ use crate::{ ledger::ReadResponse, signer::{ BalanceUpdate, Checkpoint, IdentityRequest, IdentityResponse, InitialSyncData, - SignError, SignRequest, SignResponse, SignWithTransactionDataResponse, SyncData, - SyncError, SyncRequest, SyncResponse, TransactionDataRequest, TransactionDataResponse, + InitialSyncRequest, SignError, SignRequest, SignResponse, + SignWithTransactionDataResponse, SyncData, SyncError, SyncRequest, SyncResponse, + TransactionDataRequest, TransactionDataResponse, }, }, }; @@ -51,8 +52,6 @@ use manta_util::ops::ControlFlow; #[cfg(feature = "serde")] use manta_util::serde::{Deserialize, Serialize}; -use self::signer::InitialSyncRequest; - pub mod balance; pub mod ledger; pub mod signer; @@ -268,7 +267,24 @@ where Ok(()) } + /// Pulls data from the ledger, synchronizing the wallet and balance state. This method + /// builds a [`InitialSyncRequest`] by continuously calling [`read`](ledger::Read::read) + /// until all the ledger data has arrived. Once the request is built, it executes + /// synchronizes the signer against it. + /// + /// # Implementation Note + /// + /// Using this method to synchronize a signer will make it impossibile to spend any + /// [`Utxo`](crate::transfer::Utxo)s already on the ledger at the time of synchronization. + /// Therefore, this method should only be used for the initial synchronization of a + /// new signer. + /// + /// # Failure Conditions /// + /// This method returns an element of type [`Error`] on failure, which can result from any + /// number of synchronization issues between the wallet, the ledger, and the signer. See the + /// [`InconsistencyError`] type for more information on the kinds of errors that can occur and + /// how to resolve them. #[inline] pub async fn initial_sync(&mut self) -> Result<(), Error> where @@ -390,7 +406,7 @@ where } } - /// + /// Performs an initial synchronization with the signer against the given `request`. #[inline] async fn signer_initial_sync( &mut self, diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index 3c60b8765..9959612cf 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -35,9 +35,9 @@ use crate::{ UtxoAccumulatorItem, UtxoAccumulatorModel, UtxoAccumulatorWitness, }, wallet::signer::{ - AccountTable, BalanceUpdate, Checkpoint, Configuration, SignError, SignResponse, - SignWithTransactionDataResponse, SignWithTransactionDataResult, SignerParameters, SyncData, - SyncError, SyncRequest, SyncResponse, + AccountTable, BalanceUpdate, Checkpoint, Configuration, InitialSyncRequest, SignError, + SignResponse, SignWithTransactionDataResponse, SignWithTransactionDataResult, + SignerParameters, SyncData, SyncError, SyncRequest, SyncResponse, }, }; use alloc::{vec, vec::Vec}; @@ -50,8 +50,6 @@ use manta_util::{ vec::VecExt, }; -use super::InitialSyncRequest; - /// Returns the default account for `accounts`. #[inline] pub fn default_account(accounts: &AccountTable) -> Account @@ -965,8 +963,8 @@ where Ok(response) } -/// Updates the internal ledger state, returning the new asset distribution. -#[allow(clippy::too_many_arguments)] +/// Updates the internal ledger state from `utxos`, `membership_proof_data` +/// and `nullifier_count`. #[inline] fn initial_sync_with( assets: &mut C::AssetMap, diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index e9a9e25a2..dcc0da1ca 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -79,7 +79,14 @@ where request: SyncRequest, ) -> LocalBoxFutureResult, Self::Error>; + /// Performs the initial synchronization of a new signer with the ledger data. /// + /// # Implementation Note + /// + /// Using this method to synchronize a signer will make it impossibile to spend any + /// [`Utxo`](crate::transfer::Utxo)s already on the ledger at the time of synchronization. + /// Therefore, this method should only be used for the initial synchronization of a + /// new signer. fn initial_sync( &mut self, request: InitialSyncRequest, @@ -116,7 +123,7 @@ where where TransferPost: Clone; - /// + /// Returns the transfer [`Parameters`] corresponding to `self`. fn transfer_parameters(&mut self) -> LocalBoxFutureResult, Self::Error>; } @@ -220,7 +227,7 @@ impl InitialSyncRequest where C: transfer::Configuration, { - /// + /// Builds a new [`InitialSyncRequest`] from `parameters` and `data`. #[inline] pub fn from_initial_sync_data(parameters: &Parameters, data: InitialSyncData) -> Self where @@ -238,7 +245,7 @@ where } } - /// + /// Extends `self` with `parameters` and `data`. #[inline] pub fn extend_with_data(&mut self, parameters: &Parameters, data: InitialSyncData) where @@ -805,7 +812,7 @@ where /// Updates `self` by viewing a new `accumulator`. fn update_from_utxo_accumulator(&mut self, accumulator: &Self::UtxoAccumulator); - /// + /// Updates `self` by viewing `utxo_count`-many [`Utxo`]s. fn update_from_utxo_count(&mut self, utxo_count: Vec); /// Computes a best-effort [`Checkpoint`] from the current `accumulator` state. @@ -1257,7 +1264,14 @@ where ) } + /// Performs the initial synchronization of a new signer with the ledger data. + /// + /// # Implementation Note /// + /// Using this method to synchronize a signer will make it impossibile to spend any + /// [`Utxo`](crate::transfer::Utxo)s already on the ledger at the time of synchronization. + /// Therefore, this method should only be used for the initial synchronization of a + /// new signer. #[inline] pub fn initial_sync( &mut self, @@ -1399,10 +1413,10 @@ where false } - /// + /// Returns the transfer [`Parameters`] corresponding to `self`. #[inline] - pub fn transfer_parameters(&self) -> Parameters { - self.parameters.parameters.clone() + pub fn transfer_parameters(&self) -> &Parameters { + &self.parameters.parameters } } @@ -1472,7 +1486,7 @@ where #[inline] fn transfer_parameters(&mut self) -> LocalBoxFutureResult, Self::Error> { - Box::pin(async move { Ok(Signer::transfer_parameters(self)) }) + Box::pin(async move { Ok(Signer::transfer_parameters(self).clone()) }) } } diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 5d2f3feda..1f0bd9bec 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -205,7 +205,7 @@ pub trait OptimizedAccumulator: Accumulator { /// From Items and Witnesses pub trait FromItemsAndWitnesses: Accumulator { - /// + /// Number of Proofs const NUMBER_OF_PROOFS: usize; /// Builds a new [`Self`] from `items` and `proofs`. diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 4e8df6eff..e8675b4d4 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -526,145 +526,89 @@ where } } -impl TreeArray, N> -where - C: Configuration + ?Sized, - C::Index: FixedIndex, - LeafDigest: Clone + Default, - InnerDigest: Clone + Default + PartialEq, -{ - /// Builds a new [`TreeArray`] from `leaves` and `paths` without checking that - /// the `paths` are consistent with the leaves and that they are - /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. - #[inline] - pub fn from_leaves_and_paths_unchecked( - parameters: &Parameters, - leaves: Vec>>, - paths: Vec>, - ) -> Self { - TreeArray::new(BoxArray::from_iter( - leaves - .into_iter() - .zip(paths.into_iter()) - .map(|(leaves, path)| { - Partial::from_leaves_and_path_unchecked( - parameters, - leaves.iter().map(|leaf| parameters.digest(leaf)).collect(), - path, - ) - }), - )) - } -} - -impl TreeArray>, N> -where - C: Configuration + ?Sized, - C::Index: FixedIndex, - LeafDigest: Clone + Default, - InnerDigest: Clone + Default + PartialEq, -{ - /// Builds a new [`TreeArray`] from `leaves` and `paths` without checking that - /// the `paths` are consistent with the leaves and that they are - /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. - #[inline] - pub fn from_leaves_and_paths_unchecked( - parameters: &Parameters, - leaves: Vec>>, - paths: Vec>, - ) -> Self { - TreeArray::new(BoxArray::from_iter( - leaves - .into_iter() - .zip(paths.into_iter()) - .map(|(leaves, path)| { - ForkedTree::from_leaves_and_path_unchecked( - parameters, - leaves.iter().map(|leaf| parameters.digest(leaf)).collect(), - path, - ) - }), - )) - } -} - -impl FromItemsAndWitnesses for TreeArrayMerkleForest, N> -where - C: Configuration + ?Sized, - C::Index: FixedIndex, - Parameters: Clone, - LeafDigest: Clone + Default + PartialEq, - InnerDigest: Clone + Default + PartialEq, -{ - const NUMBER_OF_PROOFS: usize = N; - - #[inline] - fn from_items_and_witnesses( - model: &Self::Model, - items: Vec>, - witnesses: Vec, - ) -> Self { - assert_eq!(witnesses.len(), N); - assert_eq!(items.len(), N); - Self::from_forest( - TreeArray::, N>::from_leaves_and_paths_unchecked(model, items, witnesses), - model.clone(), - ) - } - - #[inline] - fn sort_items(items: Vec) -> Vec> { - let mut result = Vec::>::default(); - result.resize_with(N, Default::default); - - for item in items { - let tree_index = C::tree_index(&item).into(); - result[tree_index].push(item); +macro_rules! impl_from_items_and_witnesses { + ($forest:ty, $tree_array:ty, $tree_variant:ty) => { + impl $tree_array + where + C: Configuration + ?Sized, + C::Index: FixedIndex, + LeafDigest: Clone + Default, + InnerDigest: Clone + Default + PartialEq, + { + /// Builds a new [`TreeArray`] from `leaves` and `paths` without checking that + /// the `paths` are consistent with the leaves and that they are + /// [`CurrentPath`](crate::merkle_tree::path::CurrentPath)s. + #[inline] + pub fn from_leaves_and_paths_unchecked( + parameters: &Parameters, + leaves: Vec>>, + paths: Vec>, + ) -> Self { + <$tree_array>::new(BoxArray::from_iter( + leaves + .into_iter() + .zip(paths.into_iter()) + .map(|(leaves, path)| { + <$tree_variant>::from_leaves_and_path_unchecked( + parameters, + leaves.iter().map(|leaf| parameters.digest(leaf)).collect(), + path, + ) + }), + )) + } } - result - } + impl FromItemsAndWitnesses for $forest + where + C: Configuration + ?Sized, + C::Index: FixedIndex, + Parameters: Clone, + LeafDigest: Clone + Default + PartialEq, + InnerDigest: Clone + Default + PartialEq, + { + const NUMBER_OF_PROOFS: usize = N; + + #[inline] + fn from_items_and_witnesses( + model: &Self::Model, + items: Vec>, + witnesses: Vec, + ) -> Self { + assert_eq!(witnesses.len(), N); + Self::from_forest( + <$tree_array>::from_leaves_and_paths_unchecked(model, items, witnesses), + model.clone(), + ) + } + + #[inline] + fn sort_items(items: Vec) -> Vec> { + let mut result = Vec::>::default(); + result.resize_with(N, Default::default); + + for item in items { + let tree_index = C::tree_index(&item).into(); + result[tree_index].push(item); + } + + result + } + } + }; } -impl FromItemsAndWitnesses - for TreeArrayMerkleForest>, N> -where - C: Configuration + ?Sized, - C::Index: FixedIndex, - Parameters: Clone, - LeafDigest: Clone + Default + PartialEq, - InnerDigest: Clone + Default + PartialEq, -{ - const NUMBER_OF_PROOFS: usize = N; - - #[inline] - fn from_items_and_witnesses( - model: &Self::Model, - items: Vec>, - witnesses: Vec, - ) -> Self { - assert_eq!(witnesses.len(), N); - Self::from_forest( - TreeArray::>, N>::from_leaves_and_paths_unchecked( - model, items, witnesses, - ), - model.clone(), - ) - } - - #[inline] - fn sort_items(items: Vec) -> Vec> { - let mut result = Vec::>::default(); - result.resize_with(N, Default::default); - - for item in items { - let tree_index = C::tree_index(&item).into(); - result[tree_index].push(item); - } +impl_from_items_and_witnesses!( + TreeArrayMerkleForest, N>, + TreeArray, N>, + Partial +); - result - } -} +impl_from_items_and_witnesses!( + TreeArrayMerkleForest>, N>, + TreeArray>, N>, + ForkedTree> +); impl AsRef<[T; N]> for TreeArray where diff --git a/manta-crypto/src/merkle_tree/inner_tree.rs b/manta-crypto/src/merkle_tree/inner_tree.rs index 42eca5012..7e769dcaf 100644 --- a/manta-crypto/src/merkle_tree/inner_tree.rs +++ b/manta-crypto/src/merkle_tree/inner_tree.rs @@ -775,7 +775,7 @@ where self.inner_tree.path(leaf_index) } - /// + /// Sets the starting leaf index in `self` to `default`. #[inline] pub fn reset_starting_leaf_index(&mut self, default: Node) { self.starting_leaf_index = default; diff --git a/manta-pay/src/signer/base.rs b/manta-pay/src/signer/base.rs index 50668c90c..bcba9b7e9 100644 --- a/manta-pay/src/signer/base.rs +++ b/manta-pay/src/signer/base.rs @@ -114,7 +114,12 @@ impl signer::Checkpoint for Checkpoint { #[inline] fn update_from_utxo_count(&mut self, utxo_count: Vec) { - self.receiver_index = manta_util::Array(utxo_count.try_into().expect("Wrong size")); + self.receiver_index = manta_util::Array(utxo_count.try_into().unwrap_or_else(|_| { + panic!( + "Utxo count must have {} elements", + MerkleTreeConfiguration::FOREST_WIDTH + ) + })) } /// Prunes the `data` by comparing `origin` and `signer_checkpoint` and checks if updating the From 09b5969e255a6a18ccb735e7255b9afb4d4720f1 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 14:38:48 +0100 Subject: [PATCH 25/34] debug removed --- manta-accounting/src/wallet/mod.rs | 1 - manta-accounting/src/wallet/signer/mod.rs | 1 - manta-accounting/src/wallet/test/mod.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index b1cf14c2f..64e1d05d2 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -291,7 +291,6 @@ where L: ledger::Read, Checkpoint = S::Checkpoint>, C: signer::Configuration, S::Checkpoint: signer::Checkpoint, - UtxoAccumulatorItem: Debug, { let mut is_continue = true; let mut checkpoint = self.checkpoint.clone(); diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index dcc0da1ca..c54f00e95 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -250,7 +250,6 @@ where pub fn extend_with_data(&mut self, parameters: &Parameters, data: InitialSyncData) where C: Configuration, - UtxoAccumulatorItem: Debug, { let InitialSyncData { utxo_data, diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index a8cfa97ab..6caf05bd7 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -1014,7 +1014,6 @@ impl Config { ES: Copy + FnMut(&sim::Event>>) -> ESFut, ESFut: Future, Address: Clone + Eq + Hash, - UtxoAccumulatorItem: Debug, { let action_distribution = ActionDistribution::try_from(self.action_distribution) .expect("Unable to sample from action distribution."); From aa4b43be934c7f50fa3fb1d54631eec65b9cc511 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 14:39:26 +0100 Subject: [PATCH 26/34] unused imports --- manta-accounting/src/wallet/mod.rs | 2 +- manta-accounting/src/wallet/test/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 64e1d05d2..5f40f8b16 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -31,7 +31,7 @@ use crate::{ asset::AssetList, transfer::{ canonical::{Transaction, TransactionKind}, - Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorItem, + Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorModel, }, wallet::{ diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index 6caf05bd7..68fec709e 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -22,7 +22,7 @@ use crate::{ asset::AssetList, transfer::{ - canonical::Transaction, Address, Asset, Configuration, TransferPost, UtxoAccumulatorItem, + canonical::Transaction, Address, Asset, Configuration, TransferPost, }, wallet::{ ledger, From 30fe0d8dd2a9f7900499b5e1a56d40073b60c313 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 14:58:30 +0100 Subject: [PATCH 27/34] simplified initial sync. added reset to initial sync --- manta-accounting/src/wallet/mod.rs | 20 ++++++++----------- .../src/wallet/signer/functions.rs | 6 +++++- manta-accounting/src/wallet/test/mod.rs | 4 +--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 5f40f8b16..8cc79b558 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -31,8 +31,7 @@ use crate::{ asset::AssetList, transfer::{ canonical::{Transaction, TransactionKind}, - Address, Asset, Configuration, IdentifiedAsset, TransferPost, - UtxoAccumulatorModel, + Address, Asset, Configuration, IdentifiedAsset, TransferPost, UtxoAccumulatorModel, }, wallet::{ balance::{BTreeMapBalanceState, BalanceState}, @@ -293,7 +292,7 @@ where S::Checkpoint: signer::Checkpoint, { let mut is_continue = true; - let mut checkpoint = self.checkpoint.clone(); + let mut checkpoint = Default::default(); let mut request = InitialSyncRequest::::default(); while is_continue { let ReadResponse { @@ -433,16 +432,13 @@ where self.checkpoint = checkpoint; Ok(()) } - Err(SyncError::InconsistentSynchronization { checkpoint }) => { - if checkpoint < self.checkpoint { - self.checkpoint = checkpoint; - } - Err(Error::Inconsistency( - InconsistencyError::SignerSynchronization, - )) + Err(SyncError::InconsistentSynchronization { checkpoint: _ }) => { + unreachable!("Initial synchronization always starts at the default checkpoint.") } - Err(SyncError::MissingProofAuthorizationKey) => { - Err(Error::MissingProofAuthorizationKey) + _ => { + unreachable!( + "Proof authorization key is not required for the initial synchronization." + ); } } } diff --git a/manta-accounting/src/wallet/signer/functions.rs b/manta-accounting/src/wallet/signer/functions.rs index 9959612cf..431e17ec0 100644 --- a/manta-accounting/src/wallet/signer/functions.rs +++ b/manta-accounting/src/wallet/signer/functions.rs @@ -944,12 +944,16 @@ pub fn intial_sync( ) -> Result, SyncError> where C: Configuration, + C::AssetMap: Default, + C::Checkpoint: Default, { let InitialSyncRequest { utxo_data, membership_proof_data, nullifier_count, } = request; + *checkpoint = Default::default(); + *assets = Default::default(); let (accumulator, response) = initial_sync_with::( assets, checkpoint, @@ -967,7 +971,7 @@ where /// and `nullifier_count`. #[inline] fn initial_sync_with( - assets: &mut C::AssetMap, + assets: &C::AssetMap, checkpoint: &mut C::Checkpoint, utxo_accumulator_model: &UtxoAccumulatorModel, utxos: Vec>>, diff --git a/manta-accounting/src/wallet/test/mod.rs b/manta-accounting/src/wallet/test/mod.rs index 68fec709e..10409fd2d 100644 --- a/manta-accounting/src/wallet/test/mod.rs +++ b/manta-accounting/src/wallet/test/mod.rs @@ -21,9 +21,7 @@ use crate::{ asset::AssetList, - transfer::{ - canonical::Transaction, Address, Asset, Configuration, TransferPost, - }, + transfer::{canonical::Transaction, Address, Asset, Configuration, TransferPost}, wallet::{ ledger, signer::{self, InitialSyncData, SyncData}, From c2a461043c92f8c139bc91e4dc2d4a18486c6d6c Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 15:30:31 +0100 Subject: [PATCH 28/34] simulation restored --- manta-pay/src/bin/simulation.rs | 2 -- manta-pay/src/simulation/mod.rs | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/manta-pay/src/bin/simulation.rs b/manta-pay/src/bin/simulation.rs index afdb3f916..1d43790a9 100644 --- a/manta-pay/src/bin/simulation.rs +++ b/manta-pay/src/bin/simulation.rs @@ -46,5 +46,3 @@ pub fn main() { .exit(), } } - -// cargo run --release --package manta-pay --all-features --bin simulation 3 10 2 1000 diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index 47dd5d6dd..dd9d023bf 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -140,14 +140,7 @@ impl Simulation { self.setup(&mut ledger); let ledger = Arc::new(RwLock::new(ledger)); self.run_with( - |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), - |_| sample_signer(proving_context, parameters, utxo_accumulator_model, rng), - move |i| account_id_from_u64(i as u64), - ) - .await; - println!("{:?}", ledger.read().await.utxos()); - self.run_with( - |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), + move |i| LedgerConnection::new(account_id_from_u64(i as u64), ledger.clone()), move |_| sample_signer(proving_context, parameters, utxo_accumulator_model, rng), move |i| account_id_from_u64(i as u64), ) From c3bd7549900302feb0a5be58b6e574c7d1a106f6 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 17:21:42 +0100 Subject: [PATCH 29/34] testing fixed --- manta-crypto/src/merkle_tree/test/mod.rs | 17 ++++++++--------- manta-crypto/src/merkle_tree/test/partial.rs | 2 +- manta-pay/src/simulation/ledger/mod.rs | 6 ++++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/manta-crypto/src/merkle_tree/test/mod.rs b/manta-crypto/src/merkle_tree/test/mod.rs index e01c4d75b..d13720a15 100644 --- a/manta-crypto/src/merkle_tree/test/mod.rs +++ b/manta-crypto/src/merkle_tree/test/mod.rs @@ -294,6 +294,7 @@ pub enum BinaryIndex { } impl From for usize { + #[inline] fn from(value: BinaryIndex) -> Self { match value { BinaryIndex::Zero => 0, @@ -303,11 +304,11 @@ impl From for usize { } impl forest::FixedIndex<2> for BinaryIndex { + #[inline] fn from_index(index: usize) -> Self { - if index % 2 == 0 { - BinaryIndex::Zero - } else { - BinaryIndex::One + match index % 2 { + 0 => BinaryIndex::Zero, + _ => BinaryIndex::One, } } } @@ -317,11 +318,9 @@ impl forest::Configuration for Test { #[inline] fn tree_index(leaf: &Leaf) -> Self::Index { - let parity = leaf % 2; - if parity == 0 { - BinaryIndex::Zero - } else { - BinaryIndex::One + match leaf % 2 { + 0 => BinaryIndex::Zero, + _ => BinaryIndex::One, } } } diff --git a/manta-crypto/src/merkle_tree/test/partial.rs b/manta-crypto/src/merkle_tree/test/partial.rs index cf04639ee..f59f61f2e 100644 --- a/manta-crypto/src/merkle_tree/test/partial.rs +++ b/manta-crypto/src/merkle_tree/test/partial.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with manta-rs. If not, see . -//! Partial Merkle Tree +//! Partial Merkle Tree Tests use crate::{ accumulator::{Accumulator, FromItemsAndWitnesses}, diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index fd30b3c14..b26220f2d 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -218,7 +218,9 @@ impl Ledger { true } - /// + /// Pulls the data from the ledger necessary to perform an [`initial_sync`]. + /// + /// [`initial_sync`]: manta_accounting::wallet::signer::Connection::initial_sync #[inline] pub fn initial_read(&self) -> ReadResponse { let mut utxos = Vec::new(); @@ -252,7 +254,7 @@ impl Ledger { } } - /// + /// Returns the [`Utxo`]s in `self`. #[inline] pub fn utxos(&self) -> &HashSet { &self.utxos From c99cf89464da242a22f6ccd0394b521a7fe9d0ff Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 17:24:42 +0100 Subject: [PATCH 30/34] test fixed --- manta-crypto/src/merkle_tree/test/partial.rs | 5 ++++- manta-pay/src/simulation/ledger/mod.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/manta-crypto/src/merkle_tree/test/partial.rs b/manta-crypto/src/merkle_tree/test/partial.rs index f59f61f2e..332d8cc69 100644 --- a/manta-crypto/src/merkle_tree/test/partial.rs +++ b/manta-crypto/src/merkle_tree/test/partial.rs @@ -122,10 +122,13 @@ fn test_from_leaves_and_path_forest() { let path_1 = Path::from(forest.forest.get(BinaryIndex::Zero).current_path()); let path_2 = Path::from(forest.forest.get(BinaryIndex::One).current_path()); let paths = vec![path_1, path_2]; + let items = TreeArrayMerkleForest::<_, ForkedTree<_, Partial>, 2>::sort_items( + insertions.clone(), + ); let partial_forest = TreeArrayMerkleForest::<_, ForkedTree<_, Partial>, 2>::from_items_and_witnesses( ¶meters, - insertions.clone(), + items, paths, ); for leaf in &insertions { diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index b26220f2d..48e4c242c 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -219,7 +219,7 @@ impl Ledger { } /// Pulls the data from the ledger necessary to perform an [`initial_sync`]. - /// + /// /// [`initial_sync`]: manta_accounting::wallet::signer::Connection::initial_sync #[inline] pub fn initial_read(&self) -> ReadResponse { From 8bd829ca942a4864fb88fb2c09114a6716cd40a5 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 17:45:31 +0100 Subject: [PATCH 31/34] fixed feature issue --- manta-crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manta-crypto/Cargo.toml b/manta-crypto/Cargo.toml index d8ad63cec..9d523c499 100644 --- a/manta-crypto/Cargo.toml +++ b/manta-crypto/Cargo.toml @@ -94,4 +94,4 @@ rand_chacha = { version = "0.3.1", optional = true, default-features = false } rand_core = { version = "0.6.4", default-features = false } [dev-dependencies] -manta-crypto = { path = ".", default-features = false, features = ["ark-bn254", "ark-ed-on-bn254", "getrandom", "std", "test"] } +manta-crypto = { path = ".", default-features = false, features = ["ark-bn254", "ark-ed-on-bn254", "getrandom", "rand", "std", "test"] } From c87f67b6ed21ec8ce51e229f3de6be232aced0e8 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 17:49:44 +0100 Subject: [PATCH 32/34] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fed7d5ef..af0135153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] ### Added +- [\#329](https://github.com/Manta-Network/manta-rs/pull/329) Signer initial synchronization method. - [\#328](https://github.com/Manta-Network/manta-rs/pull/328) Expose reset wallet method. ### Changed From 91901dec1c131582d84c9ae12a9d5959567e80ac Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Wed, 22 Mar 2023 17:58:41 +0100 Subject: [PATCH 33/34] signer method in wallet --- manta-accounting/src/wallet/mod.rs | 6 ++++++ manta-pay/src/simulation/mod.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 8cc79b558..9c8909f04 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -145,6 +145,12 @@ where Self::new_unchecked(ledger, Default::default(), signer, Default::default()) } + /// Returns the [`Connection`](signer::Connection). + #[inline] + pub fn signer(&self) -> &S { + &self.signer + } + /// Returns a mutable reference to the [`Connection`](signer::Connection). /// /// # Crypto Safety diff --git a/manta-pay/src/simulation/mod.rs b/manta-pay/src/simulation/mod.rs index dd9d023bf..e4f65a9f7 100644 --- a/manta-pay/src/simulation/mod.rs +++ b/manta-pay/src/simulation/mod.rs @@ -144,7 +144,7 @@ impl Simulation { move |_| sample_signer(proving_context, parameters, utxo_accumulator_model, rng), move |i| account_id_from_u64(i as u64), ) - .await; + .await } /// Runs the simulation with the given ledger connections and signer connections. From 090b67ef5e0aef2a05d47d870af640fe7e4ad721 Mon Sep 17 00:00:00 2001 From: SupremoUGH Date: Fri, 24 Mar 2023 12:41:20 +0100 Subject: [PATCH 34/34] comments addressed --- manta-accounting/src/wallet/mod.rs | 74 +++++++++-------------- manta-accounting/src/wallet/signer/mod.rs | 20 +++++- manta-crypto/src/accumulator.rs | 6 +- manta-crypto/src/merkle_tree/forest.rs | 4 +- 4 files changed, 50 insertions(+), 54 deletions(-) diff --git a/manta-accounting/src/wallet/mod.rs b/manta-accounting/src/wallet/mod.rs index 9c8909f04..a1bd650c2 100644 --- a/manta-accounting/src/wallet/mod.rs +++ b/manta-accounting/src/wallet/mod.rs @@ -40,7 +40,7 @@ use crate::{ BalanceUpdate, Checkpoint, IdentityRequest, IdentityResponse, InitialSyncData, InitialSyncRequest, SignError, SignRequest, SignResponse, SignWithTransactionDataResponse, SyncData, SyncError, SyncRequest, SyncResponse, - TransactionDataRequest, TransactionDataResponse, + SyncResult, TransactionDataRequest, TransactionDataResponse, }, }, }; @@ -300,6 +300,11 @@ where let mut is_continue = true; let mut checkpoint = Default::default(); let mut request = InitialSyncRequest::::default(); + let parameters = self + .signer + .transfer_parameters() + .await + .map_err(Error::SignerConnectionError)?; while is_continue { let ReadResponse { should_continue, @@ -310,14 +315,7 @@ where .await .map_err(Error::LedgerConnectionError)?; is_continue = should_continue; - request.extend_with_data( - &self - .signer - .transfer_parameters() - .await - .map_err(Error::SignerConnectionError)?, - data, - ); + request.extend_with_data(¶meters, data); checkpoint .update_from_utxo_count(request.utxo_data.iter().map(|utxos| utxos.len()).collect()) } @@ -365,18 +363,13 @@ where Ok(ControlFlow::should_continue(should_continue)) } - /// Performs a synchronization with the signer against the given `request`. + /// Updates `self` from `response`. #[inline] - async fn signer_sync( + fn process_sync_response( &mut self, - request: SyncRequest, + response: SyncResult, ) -> Result<(), Error> { - match self - .signer - .sync(request) - .await - .map_err(Error::SignerConnectionError)? - { + match response { Ok(SyncResponse { checkpoint, balance_update, @@ -410,43 +403,32 @@ where } } + /// Performs a synchronization with the signer against the given `request`. + #[inline] + async fn signer_sync( + &mut self, + request: SyncRequest, + ) -> Result<(), Error> { + let response = self + .signer + .sync(request) + .await + .map_err(Error::SignerConnectionError)?; + self.process_sync_response(response) + } + /// Performs an initial synchronization with the signer against the given `request`. #[inline] async fn signer_initial_sync( &mut self, request: InitialSyncRequest, ) -> Result<(), Error> { - match self + let response = self .signer .initial_sync(request) .await - .map_err(Error::SignerConnectionError)? - { - Ok(SyncResponse { - checkpoint, - balance_update, - }) => { - match balance_update { - BalanceUpdate::Full { assets } => { - self.assets.clear(); - self.assets.deposit_all(assets); - } - _ => { - unreachable!("No transactions could have happened on a new account."); - } - } - self.checkpoint = checkpoint; - Ok(()) - } - Err(SyncError::InconsistentSynchronization { checkpoint: _ }) => { - unreachable!("Initial synchronization always starts at the default checkpoint.") - } - _ => { - unreachable!( - "Proof authorization key is not required for the initial synchronization." - ); - } - } + .map_err(Error::SignerConnectionError)?; + self.process_sync_response(response) } /// Checks if `transaction` can be executed on the balance state of `self`, returning the diff --git a/manta-accounting/src/wallet/signer/mod.rs b/manta-accounting/src/wallet/signer/mod.rs index c54f00e95..13fd6259f 100644 --- a/manta-accounting/src/wallet/signer/mod.rs +++ b/manta-accounting/src/wallet/signer/mod.rs @@ -166,6 +166,11 @@ where pub utxo_data: Vec>, /// Membership Proof Data + /// + /// # Note + /// + /// Each [`UtxoAccumulatorWitness`] here is the membership proof of the last item + /// of each subaccumulator in the [`UtxoAccumulator`](Configuration::UtxoAccumulator). pub membership_proof_data: Vec>, /// Nullifier Count @@ -217,6 +222,11 @@ where pub utxo_data: Vec>>, /// Membership Proof Data + /// + /// # Note + /// + /// Each [`UtxoAccumulatorWitness`] here is the membership proof of the last item + /// of each subaccumulator in the [`UtxoAccumulator`](Configuration::UtxoAccumulator). pub membership_proof_data: Vec>, /// Nullifier Count @@ -279,8 +289,14 @@ where fn default() -> Self { let mut utxo_data = Vec::>::default(); let mut membership_proof_data = Vec::new(); - utxo_data.resize_with(C::UtxoAccumulator::NUMBER_OF_PROOFS, Default::default); - membership_proof_data.resize_with(C::UtxoAccumulator::NUMBER_OF_PROOFS, Default::default); + utxo_data.resize_with( + C::UtxoAccumulator::NUMBER_OF_SUBACCUMULATORS, + Default::default, + ); + membership_proof_data.resize_with( + C::UtxoAccumulator::NUMBER_OF_SUBACCUMULATORS, + Default::default, + ); Self { utxo_data, membership_proof_data, diff --git a/manta-crypto/src/accumulator.rs b/manta-crypto/src/accumulator.rs index 1f0bd9bec..9b081c42f 100644 --- a/manta-crypto/src/accumulator.rs +++ b/manta-crypto/src/accumulator.rs @@ -205,8 +205,8 @@ pub trait OptimizedAccumulator: Accumulator { /// From Items and Witnesses pub trait FromItemsAndWitnesses: Accumulator { - /// Number of Proofs - const NUMBER_OF_PROOFS: usize; + /// Number of Subaccumulators + const NUMBER_OF_SUBACCUMULATORS: usize; /// Builds a new [`Self`] from `items` and `proofs`. fn from_items_and_witnesses( @@ -215,7 +215,7 @@ pub trait FromItemsAndWitnesses: Accumulator { witnesses: Vec, ) -> Self; - /// Sorts `items`. + /// Groups `items` by the subaccumulator they belong to. // TODO: move this to the model. fn sort_items(items: Vec) -> Vec>; } diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index e8675b4d4..e0596067f 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -567,7 +567,7 @@ macro_rules! impl_from_items_and_witnesses { LeafDigest: Clone + Default + PartialEq, InnerDigest: Clone + Default + PartialEq, { - const NUMBER_OF_PROOFS: usize = N; + const NUMBER_OF_SUBACCUMULATORS: usize = N; #[inline] fn from_items_and_witnesses( @@ -586,12 +586,10 @@ macro_rules! impl_from_items_and_witnesses { fn sort_items(items: Vec) -> Vec> { let mut result = Vec::>::default(); result.resize_with(N, Default::default); - for item in items { let tree_index = C::tree_index(&item).into(); result[tree_index].push(item); } - result } }