diff --git a/src/darkpool.cairo b/src/darkpool.cairo index 4c34e856..75cf7045 100644 --- a/src/darkpool.cairo +++ b/src/darkpool.cairo @@ -10,7 +10,8 @@ mod statements; use starknet::{ClassHash, ContractAddress}; use renegade_contracts::{ - verifier::{scalar::Scalar, types::{Proof, CircuitParams}}, utils::serde::EcPointSerde, + verifier::{scalar::Scalar, types::{Proof, CircuitParams}}, + utils::{serde::EcPointSerde, profiling::Breakpoint}, }; use types::{ @@ -32,6 +33,7 @@ trait IDarkpool { nullifier_set_class_hash: ClassHash, verifier_class_hash: ClassHash, height: u8, + breakpoint: Breakpoint, ); fn add_circuit(ref self: TContractState, circuit: Circuit); fn parameterize_circuit( @@ -60,9 +62,10 @@ trait IDarkpool { witness_commitments: Array, proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ); fn poll_new_wallet( - ref self: TContractState, verification_job_id: felt252, + ref self: TContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option>; fn update_wallet( ref self: TContractState, @@ -72,9 +75,10 @@ trait IDarkpool { witness_commitments: Array, proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ); fn poll_update_wallet( - ref self: TContractState, verification_job_id: felt252, + ref self: TContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option>; fn process_match( ref self: TContractState, @@ -86,9 +90,10 @@ trait IDarkpool { valid_settle_witness_commitments: Array, valid_settle_proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ); fn poll_process_match( - ref self: TContractState, verification_job_id: felt252, + ref self: TContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option>; } @@ -117,7 +122,8 @@ mod Darkpool { nullifier_set::{INullifierSetLibraryDispatcher, INullifierSetDispatcherTrait}, utils::{ serde::EcPointSerde, storage::StoreSerdeWrapper, - crypto::{append_statement_commitments, hash_statement, compute_poseidon_with_flag} + crypto::{append_statement_commitments, hash_statement, compute_poseidon_with_flag}, + profiling::Breakpoint, }, oz::erc20::{IERC20DispatcherTrait, IERC20Dispatcher}, }; @@ -289,6 +295,7 @@ mod Darkpool { nullifier_set_class_hash: ClassHash, verifier_class_hash: ClassHash, height: u8, + breakpoint: Breakpoint, ) { ownable__assert_only_owner(@self); initializable__initialize(ref self); @@ -323,9 +330,17 @@ mod Darkpool { let feature_flags = self.feature_flags.read(); + if breakpoint == Breakpoint::PreMerkleInitialize { + return; + } + // Initialize the Merkle tree _get_merkle_tree(@self).initialize(height, feature_flags); + if breakpoint == Breakpoint::MerkleInitialize { + return; + } + // Set verification disabled flag in the verifier _get_verifier(@self).set_feature_flags(feature_flags); } @@ -495,21 +510,31 @@ mod Darkpool { mut witness_commitments: Array, proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ) { let verifier = _get_verifier(@self); // Inject witness append_statement_commitments(@statement, ref witness_commitments); + if breakpoint == Breakpoint::AppendStatementCommitments { + return; + } + // Queue verification verifier .queue_verification_job( Circuit::ValidWalletCreate(()).into(), proof, witness_commitments, - verification_job_id + verification_job_id, + breakpoint, ); + if breakpoint == Breakpoint::QueueVerification { + return; + } + // Store callback elements let callback_elems = NewWalletCallbackElems { wallet_blinder_share, @@ -529,7 +554,7 @@ mod Darkpool { /// Returns: /// - The new root after the wallet is inserted into the tree, if the proof verifies fn poll_new_wallet( - ref self: ContractState, verification_job_id: felt252, + ref self: ContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option> { let verifier = _get_verifier(@self); @@ -541,6 +566,10 @@ mod Darkpool { let verified = verifier .step_verification(Circuit::ValidWalletCreate(()).into(), verification_job_id); + if breakpoint == Breakpoint::StepVerification { + return Option::Some(Result::Err('breakpoint reached')); + } + match verified { Option::Some(success) => { if success { @@ -559,9 +588,17 @@ mod Darkpool { hash_input.span(), self.feature_flags.read().use_base_field_poseidon ); + if breakpoint == Breakpoint::SharesCommitment { + return Option::Some(Result::Err('breakpoint reached')); + } + let merkle_tree = _get_merkle_tree(@self); let new_root = merkle_tree.insert(total_shares_commitment); + if breakpoint == Breakpoint::MerkleInsert { + return Option::Some(Result::Err('breakpoint reached')); + } + // Mark wallet as updated _mark_wallet_updated( ref self, callback_elems.wallet_blinder_share, callback_elems.tx_hash @@ -592,6 +629,7 @@ mod Darkpool { mut witness_commitments: Array, proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ) { // Assert that the merkle root for which inclusion is proven in `VALID WALLET UPDATE` // is a valid historical root @@ -605,6 +643,11 @@ mod Darkpool { // as the `old_pk_root` in the statement is the root key of the pre-update wallet // now signing a new wallet with a new root key. let statement_hash = hash_statement(@statement); + + if breakpoint == Breakpoint::HashStatement { + return; + } + assert( check_ecdsa_signature( statement_hash.into(), @@ -615,21 +658,34 @@ mod Darkpool { 'invalid statement signature' ); + if breakpoint == Breakpoint::CheckECDSA { + return; + } + // Mark the `old_shares_nullifier` as in use _get_nullifier_set(@self).mark_nullifier_in_use(statement.old_shares_nullifier); // Inject witness append_statement_commitments(@statement, ref witness_commitments); + if breakpoint == Breakpoint::AppendStatementCommitments { + return; + } + // Queue verification _get_verifier(@self) .queue_verification_job( Circuit::ValidWalletUpdate(()).into(), proof, witness_commitments, - verification_job_id + verification_job_id, + breakpoint, ); + if breakpoint == Breakpoint::QueueVerification { + return; + } + // Store callback elements let external_transfer = if statement.external_transfer == Default::default() { Option::None(()) @@ -657,7 +713,7 @@ mod Darkpool { /// Returns: /// - The root of the tree after the new commitment is inserted, if the proof verifies fn poll_update_wallet( - ref self: ContractState, verification_job_id: felt252, + ref self: ContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option> { let verifier = _get_verifier(@self); @@ -669,6 +725,10 @@ mod Darkpool { let verified = verifier .step_verification(Circuit::ValidWalletUpdate(()).into(), verification_job_id); + if breakpoint == Breakpoint::StepVerification { + return Option::Some(Result::Err('breakpoint reached')); + } + match verified { Option::Some(success) => { let nullifier_set = _get_nullifier_set(@self); @@ -689,9 +749,17 @@ mod Darkpool { hash_input.span(), self.feature_flags.read().use_base_field_poseidon ); + if breakpoint == Breakpoint::SharesCommitment { + return Option::Some(Result::Err('breakpoint reached')); + } + let merkle_tree = _get_merkle_tree(@self); let new_root = merkle_tree.insert(total_shares_commitment); + if breakpoint == Breakpoint::MerkleInsert { + return Option::Some(Result::Err('breakpoint reached')); + } + // Add the old shares nullifier to the spent nullifier set nullifier_set.mark_nullifier_spent(callback_elems.old_shares_nullifier); @@ -739,6 +807,7 @@ mod Darkpool { mut valid_settle_witness_commitments: Array, valid_settle_proof: Proof, verification_job_id: felt252, + breakpoint: Breakpoint, ) { // Assert that the merkle roots for which inclusion is proven in `VALID REBLIND` // are valid historical roots @@ -768,6 +837,10 @@ mod Darkpool { let verifier = _get_verifier(@self); + if breakpoint == Breakpoint::PreInjectAndQueue { + return; + } + // Party 0 VALID COMMITMENTS append_statement_commitments( @party_0_payload.valid_commitments_statement, @@ -778,9 +851,14 @@ mod Darkpool { Circuit::ValidCommitments(()).into(), party_0_payload.valid_commitments_proof, party_0_payload.valid_commitments_witness_commitments, - verification_job_id + verification_job_id, + breakpoint, ); + if breakpoint == Breakpoint::Party0ValidCommitments { + return; + } + // Party 0 VALID REBLIND append_statement_commitments( @party_0_payload.valid_reblind_statement, @@ -791,9 +869,14 @@ mod Darkpool { Circuit::ValidReblind(()).into(), party_0_payload.valid_reblind_proof, party_0_payload.valid_reblind_witness_commitments, - verification_job_id + 1 + verification_job_id + 1, + breakpoint, ); + if breakpoint == Breakpoint::Party0ValidReblind { + return; + } + // Party 1 VALID COMMITMENTS append_statement_commitments( @party_1_payload.valid_commitments_statement, @@ -804,9 +887,14 @@ mod Darkpool { Circuit::ValidCommitments(()).into(), party_1_payload.valid_commitments_proof, party_1_payload.valid_commitments_witness_commitments, - verification_job_id + 2 + verification_job_id + 2, + breakpoint, ); + if breakpoint == Breakpoint::Party1ValidCommitments { + return; + } + // Party 1 VALID REBLIND append_statement_commitments( @party_1_payload.valid_reblind_statement, @@ -817,9 +905,14 @@ mod Darkpool { Circuit::ValidReblind(()).into(), party_1_payload.valid_reblind_proof, party_1_payload.valid_reblind_witness_commitments, - verification_job_id + 3 + verification_job_id + 3, + breakpoint, ); + if breakpoint == Breakpoint::Party1ValidReblind { + return; + } + // VALID MATCH MPC // No statement to inject into witness verifier @@ -827,9 +920,14 @@ mod Darkpool { Circuit::ValidMatchMpc(()).into(), valid_match_mpc_proof, valid_match_mpc_witness_commitments, - verification_job_id + 4 + verification_job_id + 4, + breakpoint, ); + if breakpoint == Breakpoint::ValidMatchMpc { + return; + } + // VALID SETTLE append_statement_commitments( @valid_settle_statement, ref valid_settle_witness_commitments @@ -839,9 +937,14 @@ mod Darkpool { Circuit::ValidSettle(()).into(), valid_settle_proof, valid_settle_witness_commitments, - verification_job_id + 5 + verification_job_id + 5, + breakpoint, ); + if breakpoint == Breakpoint::ValidSettle { + return; + } + // Store callback elements let callback_elems = ProcessMatchCallbackElems { party_0_wallet_blinder_share: party_0_payload.wallet_blinder_share, @@ -874,11 +977,17 @@ mod Darkpool { /// Returns: /// - The root of the tree after the new commitment is inserted, if the proof verifies fn poll_process_match( - ref self: ContractState, verification_job_id: felt252, + ref self: ContractState, verification_job_id: felt252, breakpoint: Breakpoint, ) -> Option> { let poll_result = _check_and_poll_process_match(@self, verification_job_id); - _handle_process_match_poll_result(ref self, verification_job_id, poll_result) + if breakpoint == Breakpoint::CheckAndPoll { + return Option::Some(Result::Err('breakpoint reached')); + } + + _handle_process_match_poll_result( + ref self, verification_job_id, poll_result, breakpoint + ) } } @@ -1056,7 +1165,10 @@ mod Darkpool { } fn _handle_process_match_poll_result( - ref self: ContractState, verification_job_id: felt252, poll_result: Option + ref self: ContractState, + verification_job_id: felt252, + poll_result: Option, + breakpoint: Breakpoint, ) -> Option> { match poll_result { Option::Some(success) => { @@ -1094,10 +1206,18 @@ mod Darkpool { party_1_hash_input.span(), use_base_field_poseidon ); + if breakpoint == Breakpoint::SharesCommitment { + return Option::Some(Result::Err('breakpoint reached')); + } + let merkle_tree = _get_merkle_tree(@self); merkle_tree.insert(party_0_total_shares_commitment); let new_root = merkle_tree.insert(party_1_total_shares_commitment); + if breakpoint == Breakpoint::MerkleInsert { + return Option::Some(Result::Err('breakpoint reached')); + } + // Mark wallet as updated _mark_wallet_updated( ref self, diff --git a/src/testing/tests/darkpool_tests.cairo b/src/testing/tests/darkpool_tests.cairo index e7c02acc..8e28d5a9 100644 --- a/src/testing/tests/darkpool_tests.cairo +++ b/src/testing/tests/darkpool_tests.cairo @@ -13,7 +13,7 @@ use renegade_contracts::{ }, merkle::Merkle, nullifier_set::NullifierSet, verifier::{MultiVerifier, IMultiVerifierDispatcher, IMultiVerifierDispatcherTrait}, - utils::eq::OptionTPartialEq, + utils::{eq::OptionTPartialEq, profiling::Breakpoint}, }; use super::{ @@ -276,6 +276,7 @@ fn initialize_darkpool(ref darkpool: IDarkpoolDispatcher) { NullifierSet::TEST_CLASS_HASH.try_into().unwrap(), MultiVerifier::TEST_CLASS_HASH.try_into().unwrap(), TEST_MERKLE_HEIGHT, + Breakpoint::None, ); darkpool.parameterize_circuit(Circuit::ValidWalletCreate(()), get_dummy_circuit_params()); diff --git a/src/utils.cairo b/src/utils.cairo index e8b1fa11..20c276fb 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -7,4 +7,5 @@ mod collections; mod eq; mod constants; mod crypto; +mod profiling; diff --git a/src/utils/profiling.cairo b/src/utils/profiling.cairo new file mode 100644 index 00000000..bc7d8108 --- /dev/null +++ b/src/utils/profiling.cairo @@ -0,0 +1,26 @@ +#[derive(Drop, Serde, Copy, PartialEq)] +enum Breakpoint { + None, + ReadCircuitParams, + PrepRemGens, + SqueezeChallengeScalars, + PrepRemScalarPolys, + PrepRemCommitments, + PreMerkleInitialize, + MerkleInitialize, + AppendStatementCommitments, + QueueVerification, + StepVerification, + SharesCommitment, + MerkleInsert, + HashStatement, + CheckECDSA, + PreInjectAndQueue, + Party0ValidCommitments, + Party0ValidReblind, + Party1ValidCommitments, + Party1ValidReblind, + ValidMatchMpc, + ValidSettle, + CheckAndPoll, +} diff --git a/src/verifier.cairo b/src/verifier.cairo index 699adf37..f2bab067 100644 --- a/src/verifier.cairo +++ b/src/verifier.cairo @@ -7,7 +7,9 @@ mod utils; // ------------- // TODO: Move to separate file / module when extensibility pattern is stabilized -use renegade_contracts::{utils::serde::EcPointSerde, darkpool::types::FeatureFlags}; +use renegade_contracts::{ + utils::{serde::EcPointSerde, profiling::Breakpoint}, darkpool::types::FeatureFlags +}; use types::{CircuitParams, Proof, VerificationJob}; @@ -23,7 +25,8 @@ trait IMultiVerifier { circuit_id: felt252, proof: Proof, witness_commitments: Array, - verification_job_id: felt252 + verification_job_id: felt252, + breakpoint: Breakpoint, ); fn step_verification( ref self: TContractState, circuit_id: felt252, verification_job_id: felt252 @@ -49,7 +52,7 @@ mod MultiVerifier { use renegade_contracts::{ utils::{ math::get_consecutive_powers, storage::StoreSerdeWrapper, eq::EcPointPartialEq, - serde::EcPointSerde, constants::{MAX_USIZE, G_LABEL, H_LABEL} + serde::EcPointSerde, constants::{MAX_USIZE, G_LABEL, H_LABEL}, profiling::Breakpoint, }, darkpool::types::FeatureFlags }; @@ -69,9 +72,9 @@ mod MultiVerifier { /// Determines how many MSM points are processed in each invocation /// of `step_verification`. - // TODO: The current value (50) was chosen arbitrarily, we should benchmark + // TODO: The current value (1) was chosen to aid in profiling, we should benchmark // the optimal amount given Starknet parameters. - const MSM_CHUNK_SIZE: usize = 50; + const MSM_CHUNK_SIZE: usize = 1; // ----------- // | STORAGE | @@ -230,7 +233,8 @@ mod MultiVerifier { circuit_id: felt252, mut proof: Proof, mut witness_commitments: Array, - verification_job_id: felt252 + verification_job_id: felt252, + breakpoint: Breakpoint, ) { // Assert that the circuit ID is in use assert(self.circuit_id_in_use.read(circuit_id), 'circuit ID not in use'); @@ -253,13 +257,26 @@ mod MultiVerifier { let W_V = self.W_V.read(circuit_id).inner; let c = self.c.read(circuit_id).inner; + if breakpoint == Breakpoint::ReadCircuitParams { + return; + } + // Prep `RemainingGenerators` structs for G and H generators let (G_rem, H_rem) = prep_rem_gens(n_plus); + if breakpoint == Breakpoint::PrepRemGens { + return; + } + // Squeeze out challenge scalars from proof let (mut challenge_scalars, u_vec) = squeeze_challenge_scalars( @proof, witness_commitments.span(), m, n_plus ); + + if breakpoint == Breakpoint::SqueezeChallengeScalars { + return; + } + let y = challenge_scalars.pop_front().unwrap(); let z = challenge_scalars.pop_front().unwrap(); let u = challenge_scalars.pop_front().unwrap(); @@ -277,12 +294,20 @@ mod MultiVerifier { y_inv, z, u, x, w, r, @proof, n, n_plus, @W_L, @W_R, @c, ); + if breakpoint == Breakpoint::PrepRemScalarPolys { + return; + } + // Prep commitments let pedersen_generator = ec_point_new(stark_curve::GEN_X, stark_curve::GEN_Y); let rem_commitments = prep_rem_commitments( ref proof, ref witness_commitments, pedersen_generator, pedersen_generator, ); + if breakpoint == Breakpoint::PrepRemCommitments { + return; + } + // Pack `VerificationJob` struct let vec_indices = VecIndices { w_L_flat_index: 0,