From ee3089a245a0eea99edcafde6a8134a9eb77394b Mon Sep 17 00:00:00 2001 From: Andrew Kirillov <20803092+akirillo@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:28:45 -0700 Subject: [PATCH] renegade_contracts: verifier, darkpool: consolidate into multiverifier contract --- src/darkpool.cairo | 270 +++++++++------------ src/darkpool/types.cairo | 13 + src/testing/tests/darkpool_tests.cairo | 314 ++++--------------------- src/testing/tests/merkle_tests.cairo | 4 +- src/utils/crypto.cairo | 20 +- src/verifier.cairo | 233 +++++++++++------- src/verifier/types.cairo | 5 +- 7 files changed, 328 insertions(+), 531 deletions(-) diff --git a/src/darkpool.cairo b/src/darkpool.cairo index 630a0781..6bc2b5db 100644 --- a/src/darkpool.cairo +++ b/src/darkpool.cairo @@ -30,21 +30,17 @@ trait IDarkpool { ref self: TContractState, merkle_class_hash: ClassHash, nullifier_set_class_hash: ClassHash, + verifier_class_hash: ClassHash, height: u8, ); - fn initialize_verifier( - ref self: TContractState, - circuit: Circuit, - verifier_contract_address: ContractAddress, - circuit_params: CircuitParams, + fn parameterize_verifier( + ref self: TContractState, circuit: Circuit, circuit_params: CircuitParams, ); // OZ fn upgrade(ref self: TContractState, darkpool_class_hash: ClassHash); fn upgrade_merkle(ref self: TContractState, merkle_class_hash: ClassHash); fn upgrade_nullifier_set(ref self: TContractState, nullifier_set_class_hash: ClassHash); - fn upgrade_verifier( - ref self: TContractState, circuit: Circuit, verifier_contract_address: ContractAddress - ); + fn upgrade_verifier(ref self: TContractState, verifier_class_hash: ClassHash); // GETTERS fn get_wallet_blinder_transaction( self: @TContractState, wallet_blinder_share: Scalar @@ -53,7 +49,7 @@ trait IDarkpool { fn root_in_history(self: @TContractState, root: Scalar) -> bool; fn is_nullifier_available(self: @TContractState, nullifier: Scalar) -> bool; fn check_verification_job_status( - self: @TContractState, circuit: Circuit, verification_job_id: felt252 + self: @TContractState, verification_job_id: felt252 ) -> Option; // SETTERS fn new_wallet( @@ -113,8 +109,8 @@ mod Darkpool { use renegade_contracts::{ verifier::{ - scalar::Scalar, types::{Proof, CircuitParams}, IVerifierDispatcher, - IVerifierDispatcherTrait + scalar::Scalar, types::{Proof, CircuitParams}, IMultiVerifierLibraryDispatcher, + IMultiVerifierDispatcherTrait }, merkle::{poseidon::poseidon_hash, IMerkleLibraryDispatcher, IMerkleDispatcherTrait}, nullifier_set::{INullifierSetLibraryDispatcher, INullifierSetDispatcherTrait}, @@ -150,18 +146,8 @@ mod Darkpool { merkle_class_hash: ClassHash, /// Stores the implementation class hash for the nullifier set interface nullifier_set_class_hash: ClassHash, - /// Stores the contract address of the deployed verifier for the VALID WALLET CREATE circuit - valid_wallet_create_verifier_address: ContractAddress, - /// Stores the contract address of the deployed verifier for the VALID WALLET UPDATE circuit - valid_wallet_update_verifier_address: ContractAddress, - /// Stores the contract address of the deployed verifier for the VALID COMMITMENTS circuit - valid_commitments_verifier_address: ContractAddress, - /// Stores the contract address of the deployed verifier for the VALID REBLIND circuit - valid_reblind_verifier_address: ContractAddress, - /// Stores the contract address of the deployed verifier for the VALID MATCH MPC circuit - valid_match_mpc_verifier_address: ContractAddress, - /// Stores the contract address of the deployed verifier for the VALID SETTLE circuit - valid_settle_verifier_address: ContractAddress, + /// Stores the implementation class hash for the verifier interface + verifier_class_hash: ClassHash, /// Mapping of elements to be used in the post-polling merkle & nullifier set /// callback logic for in-progress `new_wallet` verification jobs new_wallet_callback_elems: LegacyMap>, @@ -211,12 +197,11 @@ mod Darkpool { new_class: ClassHash, } - /// Emitted when there's a change to the verifier contract address + /// Emitted when there's a change to the verifier implementation class #[derive(Drop, PartialEq, starknet::Event)] struct VerifierUpgrade { - circuit: Circuit, - old_address: ContractAddress, - new_address: ContractAddress, + old_class: ClassHash, + new_class: ClassHash, } /// Emitted when there's an update to the encrypted wallet identified by `wallet_blinder_share` @@ -298,36 +283,55 @@ mod Darkpool { ref self: ContractState, merkle_class_hash: ClassHash, nullifier_set_class_hash: ClassHash, + verifier_class_hash: ClassHash, height: u8, ) { ownable__assert_only_owner(@self); initializable__initialize(ref self); - // Save Merkle tree & nullifier set class hashes to storage + // Save Merkle tree, nullifier set, & verifier class hashes to storage self.merkle_class_hash.write(merkle_class_hash); self.nullifier_set_class_hash.write(nullifier_set_class_hash); + self.verifier_class_hash.write(verifier_class_hash); + + // Add all of the circuits to the multi-verifier + + let verifier = _get_verifier(@self); + let mut circuits = array![ + Circuit::ValidWalletCreate(()), + Circuit::ValidWalletUpdate(()), + Circuit::ValidCommitments(()), + Circuit::ValidReblind(()), + Circuit::ValidMatchMpc(()), + Circuit::ValidSettle(()), + ]; + + loop { + match circuits.pop_front() { + Option::Some(circuit) => { + verifier.add_circuit(circuit.into()); + }, + Option::None(()) => { + break; + } + }; + }; // Initialize the Merkle tree & verifier _get_merkle_tree(@self).initialize(height); } - /// Initializes a verifier contract + /// Parameterizes the verifier for a given circuit /// Parameters: - /// - `verifier_contract_address`: The address of the deployed verifier contract /// - `circuit`: The circuit for which to initialize the verifier contract /// - `circuit_params`: The parameters of the circuit - fn initialize_verifier( - ref self: ContractState, - circuit: Circuit, - verifier_contract_address: ContractAddress, - circuit_params: CircuitParams + fn parameterize_verifier( + ref self: ContractState, circuit: Circuit, circuit_params: CircuitParams ) { ownable__assert_only_owner(@self); - // Save verifier contract address to storage - _write_verifier_address(ref self, circuit, verifier_contract_address); // Initialize the verifier - _get_verifier(@self, circuit).initialize(circuit_params); + _get_verifier(@self).parameterize_circuit(circuit.into(), circuit_params); } // ----------- @@ -380,25 +384,23 @@ mod Darkpool { ); } - /// Upgrades the verifier contract address + /// Upgrades the verifier implementation class /// Parameters: - /// - `verifier_contract_address`: The address of the deployed verifier contract + /// - `verifier_class_hash`: The hash of the implementation class used for verifier operations /// - `circuit`: The circuit for which to upgrade the verifier - fn upgrade_verifier( - ref self: ContractState, circuit: Circuit, verifier_contract_address: ContractAddress - ) { + fn upgrade_verifier(ref self: ContractState, verifier_class_hash: ClassHash) { ownable__assert_only_owner(@self); - // Get existing contract_address to emit event - let old_address = _read_verifier_address(@self, circuit); - _write_verifier_address(ref self, circuit, verifier_contract_address); + // Get existing class hash to emit event + let old_class_hash = self.verifier_class_hash.read(); + self.verifier_class_hash.write(verifier_class_hash); // Emit event self .emit( Event::VerifierUpgrade( VerifierUpgrade { - circuit, old_address, new_address: verifier_contract_address + old_class: old_class_hash, new_class: verifier_class_hash } ) ); @@ -454,9 +456,9 @@ mod Darkpool { /// - An optional boolean, which, if is `None`, means the job is still in progress, /// and otherwise indicates whether or not the verification succeeded fn check_verification_job_status( - self: @ContractState, circuit: Circuit, verification_job_id: felt252 + self: @ContractState, verification_job_id: felt252 ) -> Option { - _get_verifier(self, circuit).check_verification_job_status(verification_job_id) + _get_verifier(self).check_verification_job_status(verification_job_id) } // ----------- @@ -478,14 +480,19 @@ mod Darkpool { proof: Proof, verification_job_id: felt252, ) { - let verifier = _get_verifier(@self, Circuit::ValidWalletCreate(())); + let verifier = _get_verifier(@self); // Inject witness - let (B, B_blind) = verifier.get_pc_gens(); - append_statement_commitments(B, B_blind, @statement, ref witness_commitments); + append_statement_commitments(@statement, ref witness_commitments); // Queue verification - verifier.queue_verification_job(proof, witness_commitments, verification_job_id); + verifier + .queue_verification_job( + Circuit::ValidWalletCreate(()).into(), + proof, + witness_commitments, + verification_job_id + ); // Store callback elements let callback_elems = NewWalletCallbackElems { @@ -508,14 +515,15 @@ mod Darkpool { fn poll_new_wallet( ref self: ContractState, verification_job_id: felt252, ) -> Option> { - let verifier = _get_verifier(@self, Circuit::ValidWalletCreate(())); + let verifier = _get_verifier(@self); assert( verifier.check_verification_job_status(verification_job_id).is_none(), 'polling already complete' ); - let verified = verifier.step_verification(verification_job_id); + let verified = verifier + .step_verification(Circuit::ValidWalletCreate(()).into(), verification_job_id); match verified { Option::Some(success) => { @@ -593,14 +601,19 @@ mod Darkpool { // Mark the `old_shares_nullifier` as in use _get_nullifier_set(@self).mark_nullifier_in_use(statement.old_shares_nullifier); - let verifier = _get_verifier(@self, Circuit::ValidWalletUpdate(())); + let verifier = _get_verifier(@self); // Inject witness - let (B, B_blind) = verifier.get_pc_gens(); - append_statement_commitments(B, B_blind, @statement, ref witness_commitments); + append_statement_commitments(@statement, ref witness_commitments); // Queue verification - verifier.queue_verification_job(proof, witness_commitments, verification_job_id); + verifier + .queue_verification_job( + Circuit::ValidWalletUpdate(()).into(), + proof, + witness_commitments, + verification_job_id + ); // Store callback elements let external_transfer = if statement.external_transfer == Default::default() { @@ -631,14 +644,15 @@ mod Darkpool { fn poll_update_wallet( ref self: ContractState, verification_job_id: felt252, ) -> Option> { - let verifier = _get_verifier(@self, Circuit::ValidWalletUpdate(())); + let verifier = _get_verifier(@self); assert( verifier.check_verification_job_status(verification_job_id).is_none(), 'polling already complete' ); - let verified = verifier.step_verification(verification_job_id); + let verified = verifier + .step_verification(Circuit::ValidWalletUpdate(()).into(), verification_job_id); match verified { Option::Some(success) => { @@ -734,34 +748,29 @@ mod Darkpool { // Inject witnesses & queue verifications // TODO: This probably won't fit in a transaction... think about how to handle this + let verifier = _get_verifier(@self); + // Party 0 VALID COMMITMENTS - let valid_commitments_verifier = _get_verifier(@self, Circuit::ValidCommitments(())); - let (valid_commitments_B, valid_commitments_B_blind) = valid_commitments_verifier - .get_pc_gens(); append_statement_commitments( - valid_commitments_B, - valid_commitments_B_blind, @party_0_payload.valid_commitments_statement, ref party_0_payload.valid_commitments_witness_commitments ); - valid_commitments_verifier + verifier .queue_verification_job( + Circuit::ValidCommitments(()).into(), party_0_payload.valid_commitments_proof, party_0_payload.valid_commitments_witness_commitments, *verification_job_ids[0] ); // Party 0 VALID REBLIND - let valid_reblind_verifier = _get_verifier(@self, Circuit::ValidReblind(())); - let (valid_reblind_B, valid_reblind_B_blind) = valid_reblind_verifier.get_pc_gens(); append_statement_commitments( - valid_reblind_B, - valid_reblind_B_blind, @party_0_payload.valid_reblind_statement, ref party_0_payload.valid_reblind_witness_commitments ); - valid_reblind_verifier + verifier .queue_verification_job( + Circuit::ValidReblind(()).into(), party_0_payload.valid_reblind_proof, party_0_payload.valid_reblind_witness_commitments, *verification_job_ids[1] @@ -769,13 +778,12 @@ mod Darkpool { // Party 1 VALID COMMITMENTS append_statement_commitments( - valid_commitments_B, - valid_commitments_B_blind, @party_1_payload.valid_commitments_statement, ref party_1_payload.valid_commitments_witness_commitments ); - valid_commitments_verifier + verifier .queue_verification_job( + Circuit::ValidCommitments(()).into(), party_1_payload.valid_commitments_proof, party_1_payload.valid_commitments_witness_commitments, *verification_job_ids[2] @@ -783,13 +791,12 @@ mod Darkpool { // Party 1 VALID REBLIND append_statement_commitments( - valid_reblind_B, - valid_reblind_B_blind, @party_1_payload.valid_reblind_statement, ref party_1_payload.valid_reblind_witness_commitments ); - valid_reblind_verifier + verifier .queue_verification_job( + Circuit::ValidReblind(()).into(), party_1_payload.valid_reblind_proof, party_1_payload.valid_reblind_witness_commitments, *verification_job_ids[3] @@ -797,26 +804,24 @@ mod Darkpool { // VALID MATCH MPC // No statement to inject into witness - let valid_match_mpc_verifier = _get_verifier(@self, Circuit::ValidMatchMpc(())); - valid_match_mpc_verifier + verifier .queue_verification_job( + Circuit::ValidMatchMpc(()).into(), valid_match_mpc_proof, valid_match_mpc_witness_commitments, *verification_job_ids[4] ); // VALID SETTLE - let valid_settle_verifier = _get_verifier(@self, Circuit::ValidSettle(())); - let (valid_settle_B, valid_settle_B_blind) = valid_settle_verifier.get_pc_gens(); append_statement_commitments( - valid_settle_B, - valid_settle_B_blind, - @valid_settle_statement, - ref valid_settle_witness_commitments + @valid_settle_statement, ref valid_settle_witness_commitments ); - valid_settle_verifier + verifier .queue_verification_job( - valid_settle_proof, valid_settle_witness_commitments, *verification_job_ids[5] + Circuit::ValidSettle(()).into(), + valid_settle_proof, + valid_settle_witness_commitments, + *verification_job_ids[5] ); // Store callback elements @@ -855,25 +860,21 @@ mod Darkpool { fn poll_process_match( ref self: ContractState, verification_job_ids: Array, ) -> Option> { - let valid_commitments_verifier = _get_verifier(@self, Circuit::ValidCommitments(())); - let valid_reblind_verifier = _get_verifier(@self, Circuit::ValidReblind(())); - let valid_match_mpc_verifier = _get_verifier(@self, Circuit::ValidMatchMpc(())); - let valid_settle_verifier = _get_verifier(@self, Circuit::ValidSettle(())); - - let verifiers = array![ - valid_commitments_verifier, - valid_reblind_verifier, - valid_commitments_verifier, - valid_reblind_verifier, - valid_match_mpc_verifier, - valid_settle_verifier, + let verifier = _get_verifier(@self); + + let circuits = array![ + Circuit::ValidCommitments(()), + Circuit::ValidReblind(()), + Circuit::ValidCommitments(()), + Circuit::ValidReblind(()), + Circuit::ValidMatchMpc(()), + Circuit::ValidSettle(()) ] .span(); + let verification_job_ids = verification_job_ids.span(); - assert( - verifiers.len() == verification_job_ids.len(), 'wrong # of verification job ids' - ); + assert(circuits.len() == verification_job_ids.len(), 'wrong # of verification job ids'); // Assert that no verification jobs have failed, and that not all are complete let mut i = 0; @@ -883,8 +884,7 @@ mod Darkpool { break; } - let verified = (*verifiers[i]) - .check_verification_job_status(*verification_job_ids[i]); + let verified = verifier.check_verification_job_status(*verification_job_ids[i]); match verified { Option::Some(success) => { @@ -909,7 +909,8 @@ mod Darkpool { break; }; - let verified = (*verifiers[i]).step_verification(*verification_job_ids[i]); + let verified = verifier + .step_verification((*circuits[i]).into(), *verification_job_ids[i]); match verified { Option::Some(success) => { @@ -1018,16 +1019,12 @@ mod Darkpool { INullifierSetLibraryDispatcher { class_hash: self.nullifier_set_class_hash.read() } } - /// Returns the contract dispatcher struct for the verifier interface, - /// using the currently stored verifier contract address for the given circuit - /// Parameters: - /// - `circuit`: The circuit for which to get the verifier contract + /// Returns the library dispatcher struct for the verifier interface, + /// using the currently stored verifier class hash /// Returns: - /// - Contract dispatcher instance - fn _get_verifier(self: @ContractState, circuit: Circuit) -> IVerifierDispatcher { - let contract_address = _read_verifier_address(self, circuit); - - IVerifierDispatcher { contract_address } + /// - Library dispatcher instance + fn _get_verifier(self: @ContractState) -> IMultiVerifierLibraryDispatcher { + IMultiVerifierLibraryDispatcher { class_hash: self.verifier_class_hash.read() } } /// Returns the contract dispatcher struct for the ERC20 interface, @@ -1040,53 +1037,10 @@ mod Darkpool { IERC20Dispatcher { contract_address } } - /// Returns the currently stored contract address of the verifier contract for the given circuit - /// Parameters: - /// - `circuit`: The circuit for which to get the verifier contract address - fn _read_verifier_address(self: @ContractState, circuit: Circuit) -> ContractAddress { - match circuit { - Circuit::ValidWalletCreate(()) => self.valid_wallet_create_verifier_address.read(), - Circuit::ValidWalletUpdate(()) => self.valid_wallet_update_verifier_address.read(), - Circuit::ValidCommitments(()) => self.valid_commitments_verifier_address.read(), - Circuit::ValidReblind(()) => self.valid_reblind_verifier_address.read(), - Circuit::ValidMatchMpc(()) => self.valid_match_mpc_verifier_address.read(), - Circuit::ValidSettle(()) => self.valid_settle_verifier_address.read(), - } - } - // ----------- // | SETTERS | // ----------- - /// Stores a new verifier contract address for the given circuit - /// Parameters: - /// - `circuit`: The circuit for which to store the verifier contract address - /// - `verifier_contract_address`: The address of the deployed verifier contract - fn _write_verifier_address( - ref self: ContractState, circuit: Circuit, verifier_contract_address: ContractAddress - ) { - match circuit { - Circuit::ValidWalletCreate(()) => self - .valid_wallet_create_verifier_address - .write(verifier_contract_address), - Circuit::ValidWalletUpdate(()) => self - .valid_wallet_update_verifier_address - .write(verifier_contract_address), - Circuit::ValidCommitments(()) => self - .valid_commitments_verifier_address - .write(verifier_contract_address), - Circuit::ValidReblind(()) => self - .valid_reblind_verifier_address - .write(verifier_contract_address), - Circuit::ValidMatchMpc(()) => self - .valid_match_mpc_verifier_address - .write(verifier_contract_address), - Circuit::ValidSettle(()) => self - .valid_settle_verifier_address - .write(verifier_contract_address), - } - } - /// Sets the wallet update storage variable to the current transaction hash, /// indicating that the wallet has been modified at this transaction /// Parameters: diff --git a/src/darkpool/types.cairo b/src/darkpool/types.cairo index 467c6a5b..23e18f91 100644 --- a/src/darkpool/types.cairo +++ b/src/darkpool/types.cairo @@ -141,3 +141,16 @@ enum Circuit { ValidMatchMpc: (), ValidSettle: (), } + +impl CircuitIntoFelt of Into { + fn into(self: Circuit) -> felt252 { + match self { + Circuit::ValidWalletCreate(()) => 0, + Circuit::ValidWalletUpdate(()) => 1, + Circuit::ValidCommitments(()) => 2, + Circuit::ValidReblind(()) => 3, + Circuit::ValidMatchMpc(()) => 4, + Circuit::ValidSettle(()) => 5, + } + } +} diff --git a/src/testing/tests/darkpool_tests.cairo b/src/testing/tests/darkpool_tests.cairo index 10667f7d..3d4d21a2 100644 --- a/src/testing/tests/darkpool_tests.cairo +++ b/src/testing/tests/darkpool_tests.cairo @@ -10,7 +10,7 @@ use starknet::{ use renegade_contracts::{ darkpool::{Darkpool, IDarkpoolDispatcher, IDarkpoolDispatcherTrait, types::Circuit}, merkle::Merkle, nullifier_set::NullifierSet, - verifier::{Verifier, IVerifierDispatcher, IVerifierDispatcherTrait}, + verifier::{MultiVerifier, IMultiVerifierDispatcher, IMultiVerifierDispatcherTrait}, utils::eq::OptionTPartialEq, }; @@ -42,7 +42,7 @@ const DUMMY_CALLER: felt252 = 'DUMMY_CALLER'; fn test_upgrade_darkpool() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); darkpool.upgrade(DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap()); // The dummy upgrade target has a hardcoded response for the `get_wallet_blinder_transaction` @@ -61,7 +61,7 @@ fn test_upgrade_darkpool() { fn test_upgrade_merkle() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let original_root = darkpool.get_root(); @@ -77,7 +77,7 @@ fn test_upgrade_merkle() { fn test_upgrade_nullifier_set() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); darkpool.upgrade_nullifier_set(DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap()); assert(!darkpool.is_nullifier_available(0.into()), 'upgrade target wrong result'); @@ -87,72 +87,25 @@ fn test_upgrade_nullifier_set() { } #[test] +#[should_panic( + expected: ('failed to read from storage', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED', ) +)] #[available_gas(10000000000)] // 100x fn test_upgrade_verifier() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let ( - mut darkpool, - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ) = - setup_darkpool(); - - let (upgrade_target_address, _) = deploy_syscall( - DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap(), 0, ArrayTrait::new().span(), false, - ) - .unwrap(); + let mut darkpool = setup_darkpool(); - // For each circuit, queue a dummy verification job, check that the verifier has not verified it, - // upgrade the verifier, check that it (and it alone) has verified the dummy job, - // and then upgrade it back to the original verifier contract. - - queue_job_direct(valid_wallet_create_verifier_address, 0); - queue_job_direct(valid_wallet_update_verifier_address, 0); - queue_job_direct(valid_commitments_verifier_address, 0); - queue_job_direct(valid_reblind_verifier_address, 0); - queue_job_direct(valid_match_mpc_verifier_address, 0); - queue_job_direct(valid_settle_verifier_address, 0); - - // VALID WALLET CREATE - assert_not_verified(ref darkpool, Circuit::ValidWalletCreate(()), 0); - darkpool.upgrade_verifier(Circuit::ValidWalletCreate(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidWalletCreate(()), 0); - darkpool.upgrade_verifier(Circuit::ValidWalletCreate(()), valid_wallet_create_verifier_address); - - // VALID WALLET UPDATE - assert_not_verified(ref darkpool, Circuit::ValidWalletUpdate(()), 0); - darkpool.upgrade_verifier(Circuit::ValidWalletUpdate(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidWalletUpdate(()), 0); - darkpool.upgrade_verifier(Circuit::ValidWalletUpdate(()), valid_wallet_update_verifier_address); - - // VALID COMMITMENTS - assert_not_verified(ref darkpool, Circuit::ValidCommitments(()), 0); - darkpool.upgrade_verifier(Circuit::ValidCommitments(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidCommitments(()), 0); - darkpool.upgrade_verifier(Circuit::ValidCommitments(()), valid_commitments_verifier_address); - - // VALID REBLIND - assert_not_verified(ref darkpool, Circuit::ValidReblind(()), 0); - darkpool.upgrade_verifier(Circuit::ValidReblind(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidReblind(()), 0); - darkpool.upgrade_verifier(Circuit::ValidReblind(()), valid_reblind_verifier_address); - - // VALID MATCH MPC - assert_not_verified(ref darkpool, Circuit::ValidMatchMpc(()), 0); - darkpool.upgrade_verifier(Circuit::ValidMatchMpc(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidMatchMpc(()), 0); - darkpool.upgrade_verifier(Circuit::ValidMatchMpc(()), valid_match_mpc_verifier_address); - - // VALID SETTLE - assert_not_verified(ref darkpool, Circuit::ValidSettle(()), 0); - darkpool.upgrade_verifier(Circuit::ValidSettle(()), upgrade_target_address); - assert_only_upgraded_circuit_verified(ref darkpool, Circuit::ValidSettle(()), 0); - darkpool.upgrade_verifier(Circuit::ValidSettle(()), valid_settle_verifier_address); + darkpool.upgrade_verifier(DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap()); + assert( + darkpool.check_verification_job_status(0) == Option::Some(true), + 'upgrade target wrong result' + ); + + darkpool.upgrade_verifier(MultiVerifier::TEST_CLASS_HASH.try_into().unwrap()); + assert( + darkpool.check_verification_job_status(0) == Option::None(()), 'upgrade target wrong result' + ); } // ---------------------------- @@ -164,7 +117,7 @@ fn test_upgrade_verifier() { fn test_transfer_ownership() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); darkpool.transfer_ownership(dummy_caller); @@ -182,7 +135,7 @@ fn test_transfer_ownership() { fn test_initialize_access() { let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); - let (_, _, _, _, _, _, _) = setup_darkpool(); + setup_darkpool(); } #[test] @@ -191,7 +144,7 @@ fn test_initialize_access() { fn test_upgrade_darkpool_access() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); @@ -205,7 +158,7 @@ fn test_upgrade_darkpool_access() { fn test_upgrade_merkle_access() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); @@ -219,7 +172,7 @@ fn test_upgrade_merkle_access() { fn test_upgrade_nullifier_set_access() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); @@ -233,17 +186,12 @@ fn test_upgrade_nullifier_set_access() { fn test_upgrade_verifier_access() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); - // Testing w/ multiple `Circuit` enum variants is irrelevant as the access control is - // checked before ever referencing the `Circuit` argument - darkpool - .upgrade_verifier( - Circuit::ValidWalletCreate(()), DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap() - ); + darkpool.upgrade_verifier(DummyUpgradeTarget::TEST_CLASS_HASH.try_into().unwrap()); } #[test] @@ -252,7 +200,7 @@ fn test_upgrade_verifier_access() { fn test_transfer_ownership_access() { let test_caller = contract_address_try_from_felt252(TEST_CALLER).unwrap(); set_contract_address(test_caller); - let (mut darkpool, _, _, _, _, _, _) = setup_darkpool(); + let mut darkpool = setup_darkpool(); let dummy_caller = contract_address_try_from_felt252(DUMMY_CALLER).unwrap(); set_contract_address(dummy_caller); @@ -278,51 +226,17 @@ fn test_initialize_twice() { ) .unwrap(); - let ( - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ) = - deploy_all_verifier_contracts(); - let mut darkpool = IDarkpoolDispatcher { contract_address: darkpool_address }; - initialize_darkpool( - ref darkpool, - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ); - initialize_darkpool( - ref darkpool, - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ); + initialize_darkpool(ref darkpool); + initialize_darkpool(ref darkpool); } // ----------- // | HELPERS | // ----------- -fn setup_darkpool() -> ( - IDarkpoolDispatcher, - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, -) { +fn setup_darkpool() -> IDarkpoolDispatcher { let mut calldata = ArrayTrait::new(); calldata.append(TEST_CALLER); @@ -331,178 +245,32 @@ fn setup_darkpool() -> ( ) .unwrap(); - let ( - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ) = - deploy_all_verifier_contracts(); - let mut darkpool = IDarkpoolDispatcher { contract_address: darkpool_address }; - initialize_darkpool( - ref darkpool, - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ); + initialize_darkpool(ref darkpool); - ( - darkpool, - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ) + darkpool } -fn initialize_darkpool( - ref darkpool: IDarkpoolDispatcher, - valid_wallet_create_verifier_address: ContractAddress, - valid_wallet_update_verifier_address: ContractAddress, - valid_commitments_verifier_address: ContractAddress, - valid_reblind_verifier_address: ContractAddress, - valid_match_mpc_verifier_address: ContractAddress, - valid_settle_verifier_address: ContractAddress, -) { +fn initialize_darkpool(ref darkpool: IDarkpoolDispatcher, ) { darkpool .initialize( Merkle::TEST_CLASS_HASH.try_into().unwrap(), NullifierSet::TEST_CLASS_HASH.try_into().unwrap(), + MultiVerifier::TEST_CLASS_HASH.try_into().unwrap(), TEST_MERKLE_HEIGHT, ); - darkpool - .initialize_verifier( - Circuit::ValidWalletCreate(()), - valid_wallet_create_verifier_address, - get_dummy_circuit_params(), - ); - darkpool - .initialize_verifier( - Circuit::ValidWalletUpdate(()), - valid_wallet_update_verifier_address, - get_dummy_circuit_params(), - ); - darkpool - .initialize_verifier( - Circuit::ValidCommitments(()), - valid_commitments_verifier_address, - get_dummy_circuit_params(), - ); - darkpool - .initialize_verifier( - Circuit::ValidReblind(()), valid_reblind_verifier_address, get_dummy_circuit_params(), - ); - darkpool - .initialize_verifier( - Circuit::ValidMatchMpc(()), - valid_match_mpc_verifier_address, - get_dummy_circuit_params(), - ); - darkpool - .initialize_verifier( - Circuit::ValidSettle(()), valid_settle_verifier_address, get_dummy_circuit_params(), - ); -} - -fn deploy_all_verifier_contracts() -> ( - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, - ContractAddress, -) { - let verifier_class_hash = Verifier::TEST_CLASS_HASH.try_into().unwrap(); - - let (valid_wallet_create_verifier_address, _) = deploy_syscall( - verifier_class_hash, 0, ArrayTrait::new().span(), false, - ) - .unwrap(); - let (valid_wallet_update_verifier_address, _) = deploy_syscall( - verifier_class_hash, 1, ArrayTrait::new().span(), false, - ) - .unwrap(); - let (valid_commitments_verifier_address, _) = deploy_syscall( - verifier_class_hash, 2, ArrayTrait::new().span(), false, - ) - .unwrap(); - let (valid_reblind_verifier_address, _) = deploy_syscall( - verifier_class_hash, 3, ArrayTrait::new().span(), false, - ) - .unwrap(); - let (valid_match_mpc_verifier_address, _) = deploy_syscall( - verifier_class_hash, 4, ArrayTrait::new().span(), false, - ) - .unwrap(); - let (valid_settle_verifier_address, _) = deploy_syscall( - verifier_class_hash, 5, ArrayTrait::new().span(), false, - ) - .unwrap(); - - ( - valid_wallet_create_verifier_address, - valid_wallet_update_verifier_address, - valid_commitments_verifier_address, - valid_reblind_verifier_address, - valid_match_mpc_verifier_address, - valid_settle_verifier_address, - ) -} - -fn assert_only_upgraded_circuit_verified( - ref darkpool: IDarkpoolDispatcher, upgraded_circuit: Circuit, verification_job_id: felt252 -) { - let mut circuits = ArrayTrait::new(); - circuits.append(Circuit::ValidWalletCreate(())); - circuits.append(Circuit::ValidWalletUpdate(())); - circuits.append(Circuit::ValidCommitments(())); - circuits.append(Circuit::ValidReblind(())); - circuits.append(Circuit::ValidMatchMpc(())); - circuits.append(Circuit::ValidSettle(())); - - loop { - match circuits.pop_front() { - Option::Some(circuit) => { - if circuit == upgraded_circuit { - assert( - darkpool - .check_verification_job_status( - circuit, verification_job_id - ) == Option::Some(true), - 'upgraded circuit not verified' - ); - } else { - assert_not_verified(ref darkpool, circuit, verification_job_id); - } - }, - Option::None(()) => { - break; - } - }; - }; + darkpool.parameterize_verifier(Circuit::ValidWalletCreate(()), get_dummy_circuit_params()); + darkpool.parameterize_verifier(Circuit::ValidWalletUpdate(()), get_dummy_circuit_params()); + darkpool.parameterize_verifier(Circuit::ValidCommitments(()), get_dummy_circuit_params()); + darkpool.parameterize_verifier(Circuit::ValidReblind(()), get_dummy_circuit_params()); + darkpool.parameterize_verifier(Circuit::ValidMatchMpc(()), get_dummy_circuit_params()); + darkpool.parameterize_verifier(Circuit::ValidSettle(()), get_dummy_circuit_params()); } -fn assert_not_verified( - ref darkpool: IDarkpoolDispatcher, circuit: Circuit, verification_job_id: felt252 -) { +fn assert_not_verified(ref darkpool: IDarkpoolDispatcher, verification_job_id: felt252) { assert( - darkpool.check_verification_job_status(circuit, verification_job_id) == Option::None(()), + darkpool.check_verification_job_status(verification_job_id) == Option::None(()), 'circuit verified' ); } - -fn queue_job_direct(verifier_address: ContractAddress, verification_job_id: felt252) { - let mut verifier = IVerifierDispatcher { contract_address: verifier_address }; - let proof = get_dummy_proof(); - let witness_commitments = get_dummy_witness_commitments(); - verifier.queue_verification_job(proof, witness_commitments, verification_job_id); -} diff --git a/src/testing/tests/merkle_tests.cairo b/src/testing/tests/merkle_tests.cairo index c6cb9025..e401955d 100644 --- a/src/testing/tests/merkle_tests.cairo +++ b/src/testing/tests/merkle_tests.cairo @@ -4,8 +4,8 @@ use traits::Into; use renegade_contracts::merkle::{Merkle, Merkle::ContractState, IMerkle}; -const TEST_MERKLE_HEIGHT: u8 = 5; -const TEST_MERKLE_CAPACITY: u8 = 32; +const TEST_MERKLE_HEIGHT: u8 = 3; +const TEST_MERKLE_CAPACITY: u8 = 8; #[test] #[available_gas(1000000000)] // 10x diff --git a/src/utils/crypto.cairo b/src/utils/crypto.cairo index 402cd7d3..af79ec5d 100644 --- a/src/utils/crypto.cairo +++ b/src/utils/crypto.cairo @@ -2,7 +2,7 @@ use traits::{TryInto, Into}; use option::OptionTrait; use array::{ArrayTrait, SpanTrait}; use keccak::{keccak_u256s_le_inputs, keccak_add_u256_le, add_padding}; -use ec::ec_mul; +use ec::{ec_mul, ec_point_new, stark_curve}; use alexandria_data_structures::array_ext::ArrayTraitExt; use starknet::{syscalls::keccak_syscall, SyscallResultTrait}; use renegade_contracts::verifier::scalar::{Scalar, ScalarSerializable}; @@ -48,16 +48,18 @@ fn hash_to_felt(hash: u256) -> felt252 { } -/// Computes Pedersen commitments of the given public inputs using the given generators. +/// Computes Pedersen commitments of the given public inputs. /// We use 1 as the scalar blinding factor for public inputs. -fn commit_public(B: EcPoint, B_blind: EcPoint, mut inputs: Span) -> Array { +fn commit_public(mut inputs: Span) -> Array { + let pedersen_generator = ec_point_new(stark_curve::GEN_X, stark_curve::GEN_Y); let mut commitments = ArrayTrait::new(); loop { match inputs.pop_front() { Option::Some(input) => { - // Using 1 as scalar blinding factor => simply add B_blind - commitments.append(ec_mul(B, (*input).into()) + B_blind); + // Using 1 as scalar blinding factor => simply add generator + commitments + .append(ec_mul(pedersen_generator, (*input).into()) + pedersen_generator); }, Option::None(()) => { break; @@ -68,13 +70,13 @@ fn commit_public(B: EcPoint, B_blind: EcPoint, mut inputs: Span) -> Arra commitments } -/// Computes Pedersen commitments of the given statement using the given generators, -/// and appends the commitments to the existing array of witness commitments +/// Computes Pedersen commitments of the given statement and appends +/// the commitments to the existing array of witness commitments fn append_statement_commitments>( - B: EcPoint, B_blind: EcPoint, statement: @T, ref witness_commitments: Array + statement: @T, ref witness_commitments: Array ) { let statement_scalars = statement.to_scalars(); - let mut statement_commitments = commit_public(B, B_blind, statement_scalars.span()); + let mut statement_commitments = commit_public(statement_scalars.span()); witness_commitments.append_all(ref statement_commitments); } diff --git a/src/verifier.cairo b/src/verifier.cairo index 34e4fd81..e0534ad1 100644 --- a/src/verifier.cairo +++ b/src/verifier.cairo @@ -12,28 +12,36 @@ use renegade_contracts::utils::serde::EcPointSerde; use types::{CircuitParams, Proof, VerificationJob}; #[starknet::interface] -trait IVerifier { - fn initialize(ref self: TContractState, circuit_params: CircuitParams); +trait IMultiVerifier { + fn add_circuit(ref self: TContractState, circuit_id: felt252); + fn parameterize_circuit( + ref self: TContractState, circuit_id: felt252, circuit_params: CircuitParams + ); fn queue_verification_job( ref self: TContractState, + circuit_id: felt252, proof: Proof, witness_commitments: Array, verification_job_id: felt252 ); - fn step_verification(ref self: TContractState, verification_job_id: felt252) -> Option; - fn get_pc_gens(self: @TContractState) -> (EcPoint, EcPoint); + fn step_verification( + ref self: TContractState, circuit_id: felt252, verification_job_id: felt252 + ) -> Option; fn check_verification_job_status( self: @TContractState, verification_job_id: felt252 ) -> Option; } #[starknet::contract] -mod Verifier { +mod MultiVerifier { use option::OptionTrait; use clone::Clone; use traits::{Into, TryInto}; use array::{ArrayTrait, SpanTrait}; - use ec::{EcPoint, ec_point_zero, ec_mul, ec_point_unwrap, ec_point_non_zero}; + use ec::{ + EcPoint, ec_point_zero, ec_mul, ec_point_unwrap, ec_point_non_zero, ec_point_new, + stark_curve + }; use alexandria_data_structures::array_ext::ArrayTraitExt; use alexandria_math::fast_power::fast_power; @@ -67,36 +75,33 @@ mod Verifier { #[storage] struct Storage { - /// Queue of in-progress verification jobs + /// Map of in-use circuit IDs + circuit_id_in_use: LegacyMap, + /// Mapping from verification job ID -> verification job verification_queue: LegacyMap>, /// Map of in-use verification job IDs job_id_in_use: LegacyMap, - /// Generator used for Pedersen commitments - B: StoreSerdeWrapper, - /// Generator used for blinding in Pedersen commitments - B_blind: StoreSerdeWrapper, - /// Number of multiplication gates in the circuit - n: usize, - /// Number of multiplication gates in the circuit, + /// Mapping from circuit ID -> number of multiplication gates in the circuit + n: LegacyMap, + /// Mapping from circuit ID -> number of multiplication gates in the circuit, /// padded to the next power of 2 - n_plus: usize, - /// log_2(n_plus), cached for efficiency - k: usize, - /// The number of linear constraints in the circuit - q: usize, - /// The witness size - m: usize, - // TODO: These may just have to be lists of pointers (StorageBaseAddress) to the matrices - /// Sparse-reduced matrix of left input weights for the circuit - W_L: StoreSerdeWrapper, - /// Sparse-reduced matrix of right input weights for the circuit - W_R: StoreSerdeWrapper, - /// Sparse-reduced matrix of output weights for the circuit - W_O: StoreSerdeWrapper, - /// Sparse-reduced matrix of witness weights for the circuit - W_V: StoreSerdeWrapper, - /// Sparse-reduced vector of constants for the circuit - c: StoreSerdeWrapper, + n_plus: LegacyMap, + /// Mapping from circuit ID -> log_2(n_plus), cached for efficiency + k: LegacyMap, + /// Mapping from circuit ID -> the number of linear constraints in the circuit + q: LegacyMap, + /// Mapping from circuit ID -> the witness size for the circuit + m: LegacyMap, + /// Mapping from circuit ID -> sparse-reduced matrix of left input weights for the circuit + W_L: LegacyMap>, + /// Mapping from circuit ID -> sparse-reduced matrix of right input weights for the circuit + W_R: LegacyMap>, + /// Mapping from circuit ID -> sparse-reduced matrix of output weights for the circuit + W_O: LegacyMap>, + /// Mapping from circuit ID -> sparse-reduced matrix of witness weights for the circuit + W_V: LegacyMap>, + /// Mapping from circuit ID -> sparse-reduced vector of constants for the circuit + c: LegacyMap>, } // ---------- @@ -106,7 +111,14 @@ mod Verifier { // TODO: Access / management controls events #[derive(Drop, PartialEq, starknet::Event)] - struct Initialized {} + struct CircuitAdded { + circuit_id: felt252, + } + + #[derive(Drop, PartialEq, starknet::Event)] + struct CircuitParameterized { + circuit_id: felt252, + } #[derive(Drop, PartialEq, starknet::Event)] struct VerificationJobQueued { @@ -122,7 +134,8 @@ mod Verifier { #[event] #[derive(Drop, PartialEq, starknet::Event)] enum Event { - Initialized: Initialized, + CircuitAdded: CircuitAdded, + CircuitParameterized: CircuitParameterized, VerificationJobQueued: VerificationJobQueued, VerificationJobCompleted: VerificationJobCompleted, } @@ -132,11 +145,28 @@ mod Verifier { // ---------------------------- #[external(v0)] - impl IVerifierImpl of super::IVerifier { + impl IMultiVerifierImpl of super::IMultiVerifier { + /// Adds a new circuit to the contract + /// Parameters: + /// - `circuit_id`: The ID of the circuit + fn add_circuit(ref self: ContractState, circuit_id: felt252) { + // Assert that the circuit ID is not already in use + assert(!self.circuit_id_in_use.read(circuit_id), 'circuit ID already in use'); + self.circuit_id_in_use.write(circuit_id, true); + + self.emit(Event::CircuitAdded(CircuitAdded { circuit_id })); + } + /// Initializes the verifier for the given public parameters /// Parameters: + /// - `circuit_id`: The ID of the circuit /// - `circuit_params`: The public parameters of the circuit - fn initialize(ref self: ContractState, circuit_params: CircuitParams) { + fn parameterize_circuit( + ref self: ContractState, circuit_id: felt252, circuit_params: CircuitParams + ) { + // Assert that the circuit ID is in use + assert(self.circuit_id_in_use.read(circuit_id), 'circuit ID not in use'); + // Assert that n_plus = 2^k assert( fast_power(2, circuit_params.k.into(), MAX_USIZE.into() + 1) == circuit_params @@ -160,52 +190,53 @@ mod Verifier { // Assert that `c` vector is not too wide assert(circuit_params.c.len() <= circuit_params.q, 'c too wide'); - self.n.write(circuit_params.n); - self.n_plus.write(circuit_params.n_plus); - self.k.write(circuit_params.k); - self.q.write(circuit_params.q); - self.m.write(circuit_params.m); - self.B.write(StoreSerdeWrapper { inner: circuit_params.B }); - self.B_blind.write(StoreSerdeWrapper { inner: circuit_params.B_blind }); - self.W_L.write(StoreSerdeWrapper { inner: circuit_params.W_L }); - self.W_R.write(StoreSerdeWrapper { inner: circuit_params.W_R }); - self.W_O.write(StoreSerdeWrapper { inner: circuit_params.W_O }); - self.W_V.write(StoreSerdeWrapper { inner: circuit_params.W_V }); - self.c.write(StoreSerdeWrapper { inner: circuit_params.c }); - - self.emit(Event::Initialized(Initialized {})); + self.n.write(circuit_id, circuit_params.n); + self.n_plus.write(circuit_id, circuit_params.n_plus); + self.k.write(circuit_id, circuit_params.k); + self.q.write(circuit_id, circuit_params.q); + self.m.write(circuit_id, circuit_params.m); + self.W_L.write(circuit_id, StoreSerdeWrapper { inner: circuit_params.W_L }); + self.W_R.write(circuit_id, StoreSerdeWrapper { inner: circuit_params.W_R }); + self.W_O.write(circuit_id, StoreSerdeWrapper { inner: circuit_params.W_O }); + self.W_V.write(circuit_id, StoreSerdeWrapper { inner: circuit_params.W_V }); + self.c.write(circuit_id, StoreSerdeWrapper { inner: circuit_params.c }); + + self.emit(Event::CircuitParameterized(CircuitParameterized { circuit_id })); } /// Enqueues a verification job for the given proof, squeezing out challenge scalars /// as necessary. /// Parameters: + /// - `circuit_id`: The ID of the circuit /// - `proof`: The proof to verify /// - `verification_job_id`: The ID of the verification job fn queue_verification_job( ref self: ContractState, + circuit_id: felt252, mut proof: Proof, mut witness_commitments: Array, verification_job_id: felt252 ) { + // Assert that the circuit ID is in use + assert(self.circuit_id_in_use.read(circuit_id), 'circuit ID not in use'); + // Assert that the verification job ID is not already in use assert(!self.job_id_in_use.read(verification_job_id), 'job ID already in use'); self.job_id_in_use.write(verification_job_id, true); // Assert that there is the right number of witness commitments - let m = self.m.read(); + let m = self.m.read(circuit_id); assert(witness_commitments.len() == m, 'wrong # of witness commitments'); - let n = self.n.read(); - let n_plus = self.n_plus.read(); - let k = self.k.read(); - let q = self.q.read(); - let B = self.B.read().inner; - let B_blind = self.B_blind.read().inner; - let W_L = self.W_L.read().inner; - let W_R = self.W_R.read().inner; - let W_O = self.W_O.read().inner; - let W_V = self.W_V.read().inner; - let c = self.c.read().inner; + let n = self.n.read(circuit_id); + let n_plus = self.n_plus.read(circuit_id); + let k = self.k.read(circuit_id); + let q = self.q.read(circuit_id); + let W_L = self.W_L.read(circuit_id).inner; + let W_R = self.W_R.read(circuit_id).inner; + let W_O = self.W_O.read(circuit_id).inner; + let W_V = self.W_V.read(circuit_id).inner; + let c = self.c.read(circuit_id).inner; // Prep `RemainingGenerators` structs for G and H generators let (G_rem, H_rem) = prep_rem_gens(n_plus); @@ -232,8 +263,9 @@ mod Verifier { ); // 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, B, B_blind + ref proof, ref witness_commitments, pedersen_generator, pedersen_generator, ); // Pack `VerificationJob` struct @@ -249,7 +281,15 @@ mod Verifier { }; let verification_job = VerificationJobTrait::new( - rem_scalar_polys, y_inv_power, z, u_vec, vec_indices, G_rem, H_rem, rem_commitments, + circuit_id, + rem_scalar_polys, + y_inv_power, + z, + u_vec, + vec_indices, + G_rem, + H_rem, + rem_commitments, ); // Enqueue verification job @@ -261,7 +301,7 @@ mod Verifier { } fn step_verification( - ref self: ContractState, verification_job_id: felt252 + ref self: ContractState, circuit_id: felt252, verification_job_id: felt252 ) -> Option { let mut verification_job = self.verification_queue.read(verification_job_id).inner; step_verification_inner(ref self, ref verification_job); @@ -291,10 +331,6 @@ mod Verifier { // | GETTERS | // ----------- - fn get_pc_gens(self: @ContractState) -> (EcPoint, EcPoint) { - (self.B.read().inner, self.B_blind.read().inner) - } - fn check_verification_job_status( self: @ContractState, verification_job_id: felt252 ) -> Option { @@ -550,7 +586,8 @@ mod Verifier { return Option::None(()); } - let VerificationJob{rem_scalar_polys: mut rem_scalar_polys, + let VerificationJob{circuit_id, + rem_scalar_polys: mut rem_scalar_polys, y_inv_power: mut y_inv_power, z, u_vec, @@ -564,7 +601,8 @@ mod Verifier { self; let poly = rem_scalar_polys.at(0); - let scalar = poly.evaluate(contract, y_inv_power, z, u_vec.span(), @vec_indices); + let scalar = poly + .evaluate(contract, circuit_id, y_inv_power, z, u_vec.span(), @vec_indices); if poly.uses_y() { // Last scalar used a power of y, so we now increase it to the next power @@ -584,7 +622,7 @@ mod Verifier { // Last scalar used an element from this vector, so we now // increase the index of the next element to be used from this vector let index = vec_indices.bump_index(@vec_subterm); - let max_index = vec_subterm.len(contract); + let max_index = vec_subterm.len(contract, circuit_id); // If the index is now equal to the max index for the vector, we pop the // current polynomial from `rem_scalar_polys`. @@ -611,6 +649,7 @@ mod Verifier { }; self = VerificationJob { + circuit_id, rem_scalar_polys, y_inv_power, z, @@ -633,6 +672,7 @@ mod Verifier { fn evaluate( self: @VecPoly3, contract: @ContractState, + circuit_id: felt252, y_inv_power: (Scalar, Scalar), z: Scalar, u: Span, @@ -660,7 +700,7 @@ mod Verifier { term_eval *= match term.vec { Option::Some(vec_subterm) => { - vec_subterm.evaluate(z, u, vec_indices, contract) + vec_subterm.evaluate(z, u, vec_indices, contract, circuit_id) }, Option::None(()) => 1.into(), }; @@ -676,16 +716,16 @@ mod Verifier { #[generate_trait] impl VecSubtermImpl of ContractAwareVecSubtermTrait { /// Returns the expected length of the given vector - fn len(self: @VecSubterm, contract: @ContractState) -> usize { + fn len(self: @VecSubterm, contract: @ContractState, circuit_id: felt252) -> usize { match self { - VecSubterm::W_L_flat(()) => contract.n.read(), - VecSubterm::W_R_flat(()) => contract.n.read(), - VecSubterm::W_O_flat(()) => contract.n.read(), - VecSubterm::W_V_flat(()) => contract.m.read(), - VecSubterm::S(()) => contract.n_plus.read(), - VecSubterm::S_inv(()) => contract.n_plus.read(), - VecSubterm::U_sq(()) => contract.k.read(), - VecSubterm::U_sq_inv(()) => contract.k.read(), + VecSubterm::W_L_flat(()) => contract.n.read(circuit_id), + VecSubterm::W_R_flat(()) => contract.n.read(circuit_id), + VecSubterm::W_O_flat(()) => contract.n.read(circuit_id), + VecSubterm::W_V_flat(()) => contract.m.read(circuit_id), + VecSubterm::S(()) => contract.n_plus.read(circuit_id), + VecSubterm::S_inv(()) => contract.n_plus.read(circuit_id), + VecSubterm::U_sq(()) => contract.k.read(circuit_id), + VecSubterm::U_sq_inv(()) => contract.k.read(circuit_id), } } @@ -695,27 +735,44 @@ mod Verifier { z: Scalar, u: Span, vec_indices: @VecIndices, - contract: @ContractState + contract: @ContractState, + circuit_id: felt252, ) -> Scalar { match self { VecSubterm::W_L_flat(()) => { - contract.W_L.read().inner.get_flattened_elem(*vec_indices.w_L_flat_index, z) + contract + .W_L + .read(circuit_id) + .inner + .get_flattened_elem(*vec_indices.w_L_flat_index, z) }, VecSubterm::W_R_flat(()) => { - contract.W_R.read().inner.get_flattened_elem(*vec_indices.w_R_flat_index, z) + contract + .W_R + .read(circuit_id) + .inner + .get_flattened_elem(*vec_indices.w_R_flat_index, z) }, VecSubterm::W_O_flat(()) => { - contract.W_O.read().inner.get_flattened_elem(*vec_indices.w_O_flat_index, z) + contract + .W_O + .read(circuit_id) + .inner + .get_flattened_elem(*vec_indices.w_O_flat_index, z) }, VecSubterm::W_V_flat(()) => { - contract.W_V.read().inner.get_flattened_elem(*vec_indices.w_V_flat_index, z) + contract + .W_V + .read(circuit_id) + .inner + .get_flattened_elem(*vec_indices.w_V_flat_index, z) }, VecSubterm::S(()) => { get_s_elem(u, *vec_indices.s_index) }, VecSubterm::S_inv(()) => { // s_inv = rev(s) - get_s_elem(u, contract.n_plus.read() - *vec_indices.s_inv_index - 1) + get_s_elem(u, contract.n_plus.read(circuit_id) - *vec_indices.s_inv_index - 1) }, VecSubterm::U_sq(()) => { let u_i = *u.at(*vec_indices.u_sq_index); diff --git a/src/verifier/types.cairo b/src/verifier/types.cairo index ad78dd5f..7dcaa636 100644 --- a/src/verifier/types.cairo +++ b/src/verifier/types.cairo @@ -18,8 +18,9 @@ use super::scalar::{Scalar, ScalarTrait}; /// Tracks the verification of a single proof #[derive(Drop, Serde, PartialEq)] struct VerificationJob { + /// The ID of the circuit being verified + circuit_id: felt252, /// The challenge scalars remaining to be used for verification - // TODO: This may just have to be a pointer (StorageBaseAddress) to the array rem_scalar_polys: Array, /// Represents the base y^-1 challenge scalar & the last computed power of y^-1 y_inv_power: (Scalar, Scalar), @@ -45,6 +46,7 @@ struct VerificationJob { #[generate_trait] impl VerificationJobImpl of VerificationJobTrait { fn new( + circuit_id: felt252, rem_scalar_polys: Array, y_inv_power: (Scalar, Scalar), z: Scalar, @@ -55,6 +57,7 @@ impl VerificationJobImpl of VerificationJobTrait { rem_commitments: Array, ) -> VerificationJob { VerificationJob { + circuit_id, rem_scalar_polys, y_inv_power, z,