diff --git a/cli/testScript.sh b/cli/testScript.sh index 100c57be87..d8bfc6b372 100755 --- a/cli/testScript.sh +++ b/cli/testScript.sh @@ -8,8 +8,8 @@ node build/ts/index.js setVerifyingKeys \ --msg-tree-depth 2 \ --vote-option-tree-depth 2 \ --msg-batch-depth 1 \ - --process-messages-zkey ./zkeys/ProcessMessages_10-2-1-2_test/ProcessMessages_10-2-1-2_test.0.zkey \ - --tally-votes-zkey ./zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test.0.zkey + --process-messages-zkey-qv ./zkeys/ProcessMessages_10-2-1-2_test/ProcessMessages_10-2-1-2_test.0.zkey \ + --tally-votes-zkey-qv ./zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test.0.zkey node build/ts/index.js create -s 10 node build/ts/index.js deployPoll \ --pubkey macipk.281830024fb6d21a4c73a89a7139aff61fbbddad731ef2dc2db9516171fd390e \ diff --git a/cli/tests/ceremony-params/ceremonyParams.test.ts b/cli/tests/ceremony-params/ceremonyParams.test.ts index 4bfe9cf910..17f08d10a8 100644 --- a/cli/tests/ceremony-params/ceremonyParams.test.ts +++ b/cli/tests/ceremony-params/ceremonyParams.test.ts @@ -70,8 +70,8 @@ describe("Stress tests with ceremony params (6,9,2,3)", function test() { messageTreeDepth, voteOptionTreeDepth, messageBatchDepth, - processMessagesZkeyPath: ceremonyProcessMessagesZkeyPath, - tallyVotesZkeyPath: ceremonyTallyVotesZkeyPath, + processMessagesZkeyPathQv: ceremonyProcessMessagesZkeyPath, + tallyVotesZkeyPathQv: ceremonyTallyVotesZkeyPath, }; const verifyingKeysNonQvArgs: Omit = { @@ -81,8 +81,8 @@ describe("Stress tests with ceremony params (6,9,2,3)", function test() { messageTreeDepth, voteOptionTreeDepth, messageBatchDepth, - processMessagesZkeyPath: ceremonyProcessMessagesNonQvZkeyPath, - tallyVotesZkeyPath: ceremonyTallyVotesNonQvZkeyPath, + processMessagesZkeyPathNonQv: ceremonyProcessMessagesNonQvZkeyPath, + tallyVotesZkeyPathNonQv: ceremonyTallyVotesNonQvZkeyPath, }; const ceremonyDeployArgs: Omit = { diff --git a/cli/tests/constants.ts b/cli/tests/constants.ts index 53a4eb7dac..eade24f114 100644 --- a/cli/tests/constants.ts +++ b/cli/tests/constants.ts @@ -94,8 +94,8 @@ export const setVerifyingKeysArgs: Omit = { messageTreeDepth: MSG_TREE_DEPTH, voteOptionTreeDepth: VOTE_OPTION_TREE_DEPTH, messageBatchDepth: MSG_BATCH_DEPTH, - processMessagesZkeyPath: processMessageTestZkeyPath, - tallyVotesZkeyPath: tallyVotesTestZkeyPath, + processMessagesZkeyPathQv: processMessageTestZkeyPath, + tallyVotesZkeyPathQv: tallyVotesTestZkeyPath, }; export const setVerifyingKeysNonQvArgs: Omit = { @@ -105,8 +105,8 @@ export const setVerifyingKeysNonQvArgs: Omit = { messageTreeDepth: MSG_TREE_DEPTH, voteOptionTreeDepth: VOTE_OPTION_TREE_DEPTH, messageBatchDepth: MSG_BATCH_DEPTH, - processMessagesZkeyPath: processMessageTestNonQvZkeyPath, - tallyVotesZkeyPath: tallyVotesTestNonQvZkeyPath, + processMessagesZkeyPathNonQv: processMessageTestNonQvZkeyPath, + tallyVotesZkeyPathNonQv: tallyVotesTestNonQvZkeyPath, }; export const checkVerifyingKeysArgs: Omit = { diff --git a/cli/ts/commands/setVerifyingKeys.ts b/cli/ts/commands/setVerifyingKeys.ts index 1eb1b9179b..57ec9b89b7 100644 --- a/cli/ts/commands/setVerifyingKeys.ts +++ b/cli/ts/commands/setVerifyingKeys.ts @@ -29,8 +29,10 @@ export const setVerifyingKeys = async ({ messageTreeDepth, voteOptionTreeDepth, messageBatchDepth, - processMessagesZkeyPath, - tallyVotesZkeyPath, + processMessagesZkeyPathQv, + tallyVotesZkeyPathQv, + processMessagesZkeyPathNonQv, + tallyVotesZkeyPathNonQv, vkRegistry, signer, useQuadraticVoting = true, @@ -48,17 +50,28 @@ export const setVerifyingKeys = async ({ const vkRegistryAddress = vkRegistry || readContractAddress("VkRegistry", network?.name); // check if zKey files exist - if (!fs.existsSync(processMessagesZkeyPath)) { - logError(`${processMessagesZkeyPath} does not exist.`); + if (useQuadraticVoting && processMessagesZkeyPathQv && !fs.existsSync(processMessagesZkeyPathQv)) { + logError(`${processMessagesZkeyPathQv} does not exist.`); + } + + if (useQuadraticVoting && tallyVotesZkeyPathQv && !fs.existsSync(tallyVotesZkeyPathQv)) { + logError(`${tallyVotesZkeyPathQv} does not exist.`); } - if (!fs.existsSync(tallyVotesZkeyPath)) { - logError(`${tallyVotesZkeyPath} does not exist.`); + if (!useQuadraticVoting && processMessagesZkeyPathNonQv && !fs.existsSync(processMessagesZkeyPathNonQv)) { + logError(`${processMessagesZkeyPathNonQv} does not exist.`); + } + + if (!useQuadraticVoting && tallyVotesZkeyPathNonQv && !fs.existsSync(tallyVotesZkeyPathNonQv)) { + logError(`${tallyVotesZkeyPathNonQv} does not exist.`); } // extract the vks - const processVk = VerifyingKey.fromObj(await extractVk(processMessagesZkeyPath)); - const tallyVk = VerifyingKey.fromObj(await extractVk(tallyVotesZkeyPath)); + const processVkQv = processMessagesZkeyPathQv && VerifyingKey.fromObj(await extractVk(processMessagesZkeyPathQv)); + const tallyVkQv = tallyVotesZkeyPathQv && VerifyingKey.fromObj(await extractVk(tallyVotesZkeyPathQv)); + const processVkNonQv = + processMessagesZkeyPathNonQv && VerifyingKey.fromObj(await extractVk(processMessagesZkeyPathNonQv)); + const tallyVkNonQv = tallyVotesZkeyPathNonQv && VerifyingKey.fromObj(await extractVk(tallyVotesZkeyPathNonQv)); // validate args if ( @@ -75,41 +88,25 @@ export const setVerifyingKeys = async ({ logError("Invalid state tree depth or intermediate state tree depth"); } - // Check the pm zkey filename against specified params - const pmMatch = processMessagesZkeyPath.match(/.+_(\d+)-(\d+)-(\d+)-(\d+)/); - - if (!pmMatch) { - logError(`${processMessagesZkeyPath} has an invalid filename`); - return; - } - - const pmStateTreeDepth = Number(pmMatch[1]); - const pmMsgTreeDepth = Number(pmMatch[2]); - const pmMsgBatchDepth = Number(pmMatch[3]); - const pmVoteOptionTreeDepth = Number(pmMatch[4]); - - const tvMatch = tallyVotesZkeyPath.match(/.+_(\d+)-(\d+)-(\d+)/); - - if (!tvMatch) { - logError(`${tallyVotesZkeyPath} has an invalid filename`); - return; - } - - const tvStateTreeDepth = Number(tvMatch[1]); - const tvIntStateTreeDepth = Number(tvMatch[2]); - const tvVoteOptionTreeDepth = Number(tvMatch[3]); - - if ( - stateTreeDepth !== pmStateTreeDepth || - messageTreeDepth !== pmMsgTreeDepth || - messageBatchDepth !== pmMsgBatchDepth || - voteOptionTreeDepth !== pmVoteOptionTreeDepth || - stateTreeDepth !== tvStateTreeDepth || - intStateTreeDepth !== tvIntStateTreeDepth || - voteOptionTreeDepth !== tvVoteOptionTreeDepth - ) { - logError("Incorrect .zkey file; please check the circuit params"); - } + checkZkeyFilepaths({ + processMessagesZkeyPath: processMessagesZkeyPathQv!, + tallyVotesZkeyPath: tallyVotesZkeyPathQv!, + stateTreeDepth, + messageTreeDepth, + messageBatchDepth, + voteOptionTreeDepth, + intStateTreeDepth, + }); + + checkZkeyFilepaths({ + processMessagesZkeyPath: processMessagesZkeyPathNonQv!, + tallyVotesZkeyPath: tallyVotesZkeyPathNonQv!, + stateTreeDepth, + messageTreeDepth, + messageBatchDepth, + voteOptionTreeDepth, + intStateTreeDepth, + }); // ensure we have a contract deployed at the provided address if (!(await contractExists(signer.provider!, vkRegistryAddress))) { @@ -122,33 +119,57 @@ export const setVerifyingKeys = async ({ const messageBatchSize = 5 ** messageBatchDepth; // check if the process messages vk was already set - const mode = useQuadraticVoting ? EMode.QV : EMode.NON_QV; const processVkSig = genProcessVkSig(stateTreeDepth, messageTreeDepth, voteOptionTreeDepth, messageBatchSize); - if (await vkRegistryContract.isProcessVkSet(processVkSig, mode)) { + if (useQuadraticVoting && (await vkRegistryContract.isProcessVkSet(processVkSig, EMode.QV))) { + logError("This process verifying key is already set in the contract"); + } + + if (!useQuadraticVoting && (await vkRegistryContract.isProcessVkSet(processVkSig, EMode.NON_QV))) { logError("This process verifying key is already set in the contract"); } // do the same for the tally votes vk const tallyVkSig = genTallyVkSig(stateTreeDepth, intStateTreeDepth, voteOptionTreeDepth); - if (await vkRegistryContract.isTallyVkSet(tallyVkSig, mode)) { + if (useQuadraticVoting && (await vkRegistryContract.isTallyVkSet(tallyVkSig, EMode.QV))) { + logError("This tally verifying key is already set in the contract"); + } + + if (!useQuadraticVoting && (await vkRegistryContract.isTallyVkSet(tallyVkSig, EMode.NON_QV))) { logError("This tally verifying key is already set in the contract"); } // actually set those values try { logYellow(quiet, info("Setting verifying keys...")); + + const processZkeys = [processVkQv, processVkNonQv] + .filter(Boolean) + .map((vk) => (vk as VerifyingKey).asContractParam() as IVerifyingKeyStruct); + const tallyZkeys = [tallyVkQv, tallyVkNonQv] + .filter(Boolean) + .map((vk) => (vk as VerifyingKey).asContractParam() as IVerifyingKeyStruct); + const modes: EMode[] = []; + + if (processVkQv && tallyVkQv) { + modes.push(EMode.QV); + } + + if (processVkNonQv && tallyVkNonQv) { + modes.push(EMode.NON_QV); + } + // set them onchain - const tx = await vkRegistryContract.setVerifyingKeys( + const tx = await vkRegistryContract.setVerifyingKeysBatch( stateTreeDepth, intStateTreeDepth, messageTreeDepth, voteOptionTreeDepth, messageBatchSize, - mode, - processVk.asContractParam() as IVerifyingKeyStruct, - tallyVk.asContractParam() as IVerifyingKeyStruct, + modes, + processZkeys, + tallyZkeys, ); const receipt = await tx.wait(); @@ -160,27 +181,52 @@ export const setVerifyingKeys = async ({ logYellow(quiet, info(`Transaction hash: ${receipt!.hash}`)); // confirm that they were actually set correctly - const processVkOnChain = await vkRegistryContract.getProcessVk( - stateTreeDepth, - messageTreeDepth, - voteOptionTreeDepth, - messageBatchSize, - mode, - ); - - const tallyVkOnChain = await vkRegistryContract.getTallyVk( - stateTreeDepth, - intStateTreeDepth, - voteOptionTreeDepth, - mode, - ); - - if (!compareVks(processVk, processVkOnChain)) { - logError("processVk mismatch"); - } - - if (!compareVks(tallyVk, tallyVkOnChain)) { - logError("tallyVk mismatch"); + if (useQuadraticVoting) { + const processVkOnChain = await vkRegistryContract.getProcessVk( + stateTreeDepth, + messageTreeDepth, + voteOptionTreeDepth, + messageBatchSize, + EMode.QV, + ); + + const tallyVkOnChain = await vkRegistryContract.getTallyVk( + stateTreeDepth, + intStateTreeDepth, + voteOptionTreeDepth, + EMode.QV, + ); + + if (!compareVks(processVkQv as VerifyingKey, processVkOnChain)) { + logError("processVk mismatch"); + } + + if (!compareVks(tallyVkQv as VerifyingKey, tallyVkOnChain)) { + logError("tallyVk mismatch"); + } + } else { + const processVkOnChain = await vkRegistryContract.getProcessVk( + stateTreeDepth, + messageTreeDepth, + voteOptionTreeDepth, + messageBatchSize, + EMode.NON_QV, + ); + + const tallyVkOnChain = await vkRegistryContract.getTallyVk( + stateTreeDepth, + intStateTreeDepth, + voteOptionTreeDepth, + EMode.NON_QV, + ); + + if (!compareVks(processVkNonQv as VerifyingKey, processVkOnChain)) { + logError("processVk mismatch"); + } + + if (!compareVks(tallyVkNonQv as VerifyingKey, tallyVkOnChain)) { + logError("tallyVk mismatch"); + } } } catch (error) { logError((error as Error).message); @@ -188,3 +234,63 @@ export const setVerifyingKeys = async ({ logGreen(quiet, success("Verifying keys set successfully")); }; + +interface ICheckZkeyFilepathsArgs { + stateTreeDepth: number; + messageTreeDepth: number; + messageBatchDepth: number; + voteOptionTreeDepth: number; + intStateTreeDepth: number; + processMessagesZkeyPath?: string; + tallyVotesZkeyPath?: string; +} + +function checkZkeyFilepaths({ + processMessagesZkeyPath, + tallyVotesZkeyPath, + stateTreeDepth, + messageTreeDepth, + messageBatchDepth, + voteOptionTreeDepth, + intStateTreeDepth, +}: ICheckZkeyFilepathsArgs): void { + if (!processMessagesZkeyPath || !tallyVotesZkeyPath) { + return; + } + + // Check the pm zkey filename against specified params + const pmMatch = processMessagesZkeyPath.match(/.+_(\d+)-(\d+)-(\d+)-(\d+)/); + + if (!pmMatch) { + logError(`${processMessagesZkeyPath} has an invalid filename`); + return; + } + + const pmStateTreeDepth = Number(pmMatch[1]); + const pmMsgTreeDepth = Number(pmMatch[2]); + const pmMsgBatchDepth = Number(pmMatch[3]); + const pmVoteOptionTreeDepth = Number(pmMatch[4]); + + const tvMatch = tallyVotesZkeyPath.match(/.+_(\d+)-(\d+)-(\d+)/); + + if (!tvMatch) { + logError(`${tallyVotesZkeyPath} has an invalid filename`); + return; + } + + const tvStateTreeDepth = Number(tvMatch[1]); + const tvIntStateTreeDepth = Number(tvMatch[2]); + const tvVoteOptionTreeDepth = Number(tvMatch[3]); + + if ( + stateTreeDepth !== pmStateTreeDepth || + messageTreeDepth !== pmMsgTreeDepth || + messageBatchDepth !== pmMsgBatchDepth || + voteOptionTreeDepth !== pmVoteOptionTreeDepth || + stateTreeDepth !== tvStateTreeDepth || + intStateTreeDepth !== tvIntStateTreeDepth || + voteOptionTreeDepth !== tvVoteOptionTreeDepth + ) { + logError("Incorrect .zkey file; please check the circuit params"); + } +} diff --git a/cli/ts/index.ts b/cli/ts/index.ts index dca98849fe..ff03f39670 100644 --- a/cli/ts/index.ts +++ b/cli/ts/index.ts @@ -233,13 +233,21 @@ program .requiredOption("-m, --msg-tree-depth ", "the message tree depth", parseInt) .requiredOption("-v, --vote-option-tree-depth ", "the vote option tree depth", parseInt) .requiredOption("-b, --msg-batch-depth ", "the message batch depth", parseInt) - .requiredOption( - "-p, --process-messages-zkey ", - "the process messages zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", + .option( + "-pqv, --process-messages-zkey-qv ", + "the process messages qv zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", ) - .requiredOption( - "-t, --tally-votes-zkey ", - "the tally votes zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", + .option( + "-tqv, --tally-votes-zkey-qv ", + "the tally votes qv zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", + ) + .option( + "-pnqv, --process-messages-zkey-non-qv ", + "the process messages non-qv zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", + ) + .option( + "-tnqv, --tally-votes-zkey-non-qv ", + "the tally votes non-qv zkey path (see different options for zkey files to use specific circuits https://maci.pse.dev/docs/trusted-setup, https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing)", ) .option("-uq, --use-quadratic-voting", "whether to use quadratic voting", (value) => value === "true", true) .option("-k, --vk-registry ", "the vk registry contract address") @@ -255,8 +263,10 @@ program messageTreeDepth: cmdObj.msgTreeDepth, voteOptionTreeDepth: cmdObj.voteOptionTreeDepth, messageBatchDepth: cmdObj.msgBatchDepth, - processMessagesZkeyPath: cmdObj.processMessagesZkey, - tallyVotesZkeyPath: cmdObj.tallyVotesZkey, + processMessagesZkeyPathQv: cmdObj.processMessagesZkeyQv, + tallyVotesZkeyPathQv: cmdObj.tallyVotesZkeyQv, + processMessagesZkeyPathNonQv: cmdObj.processMessagesZkeyNonQv, + tallyVotesZkeyPathNonQv: cmdObj.tallyVotesZkeyNonQv, vkRegistry: cmdObj.vkRegistry, quiet: cmdObj.quiet, useQuadraticVoting: cmdObj.useQuadraticVoting, diff --git a/cli/ts/utils/interfaces.ts b/cli/ts/utils/interfaces.ts index 9da095f3e0..04ecc1036d 100644 --- a/cli/ts/utils/interfaces.ts +++ b/cli/ts/utils/interfaces.ts @@ -805,14 +805,24 @@ export interface SetVerifyingKeysArgs { messageBatchDepth: number; /** - * The path to the process messages zkey + * The path to the process messages qv zkey */ - processMessagesZkeyPath: string; + processMessagesZkeyPathQv?: string; /** - * The path to the tally votes zkey + * The path to the tally votes qv zkey */ - tallyVotesZkeyPath: string; + tallyVotesZkeyPathQv?: string; + + /** + * The path to the process messages non-qv zkey + */ + processMessagesZkeyPathNonQv?: string; + + /** + * The path to the tally votes non-qv zkey + */ + tallyVotesZkeyPathNonQv?: string; /** * A signer object diff --git a/contracts/contracts/Tally.sol b/contracts/contracts/Tally.sol index bc98405d94..5a0d7c80a1 100644 --- a/contracts/contracts/Tally.sol +++ b/contracts/contracts/Tally.sol @@ -242,7 +242,7 @@ contract Tally is Ownable, SnarkCommon, CommonUtilities, Hasher { /// @param _totalSpent spent field retrieved in the totalSpentVoiceCredits object /// @param _totalSpentSalt the corresponding salt in the totalSpentVoiceCredit object /// @param _resultCommitment hashLeftRight(merkle root of the results.tally, results.salt) in tally.json file - /// @param _perVOSpentVoiceCreditsHash only for QV - hashLeftRight(merkle root of the no spent voice credits per vote option, salt) + /// @param _perVOSpentVoiceCreditsHash only for QV - hashLeftRight(merkle root of the no spent voice credits, salt) /// @return isValid Whether the provided values are valid function verifySpentVoiceCredits( uint256 _totalSpent, diff --git a/contracts/contracts/VkRegistry.sol b/contracts/contracts/VkRegistry.sol index e66bd83ebf..bec949a0d4 100644 --- a/contracts/contracts/VkRegistry.sol +++ b/contracts/contracts/VkRegistry.sol @@ -24,6 +24,7 @@ contract VkRegistry is Ownable, SnarkCommon, IVkRegistry { error ProcessVkNotSet(); error TallyVkNotSet(); error SubsidyVkNotSet(); + error InvalidKeysParams(); /// @notice Create a new instance of the VkRegistry contract // solhint-disable-next-line no-empty-blocks @@ -72,6 +73,50 @@ contract VkRegistry is Ownable, SnarkCommon, IVkRegistry { sig = (_stateTreeDepth << 128) + (_intStateTreeDepth << 64) + _voteOptionTreeDepth; } + /// @notice Set the process and tally verifying keys for a certain combination + /// of parameters and modes + /// @param _stateTreeDepth The state tree depth + /// @param _intStateTreeDepth The intermediate state tree depth + /// @param _messageTreeDepth The message tree depth + /// @param _voteOptionTreeDepth The vote option tree depth + /// @param _messageBatchSize The message batch size + /// @param _modes Array of QV or Non-QV modes (must have the same length as process and tally keys) + /// @param _processVks The process verifying keys (must have the same length as modes) + /// @param _tallyVks The tally verifying keys (must have the same length as modes) + function setVerifyingKeysBatch( + uint256 _stateTreeDepth, + uint256 _intStateTreeDepth, + uint256 _messageTreeDepth, + uint256 _voteOptionTreeDepth, + uint256 _messageBatchSize, + Mode[] calldata _modes, + VerifyingKey[] calldata _processVks, + VerifyingKey[] calldata _tallyVks + ) public onlyOwner { + if (_modes.length != _processVks.length || _modes.length != _tallyVks.length) { + revert InvalidKeysParams(); + } + + uint256 length = _modes.length; + + for (uint256 index = 0; index < length; ) { + setVerifyingKeys( + _stateTreeDepth, + _intStateTreeDepth, + _messageTreeDepth, + _voteOptionTreeDepth, + _messageBatchSize, + _modes[index], + _processVks[index], + _tallyVks[index] + ); + + unchecked { + index++; + } + } + } + /// @notice Set the process and tally verifying keys for a certain combination /// of parameters /// @param _stateTreeDepth The state tree depth diff --git a/contracts/deploy-config-example.json b/contracts/deploy-config-example.json index 169b7c5fc4..a087b2e994 100644 --- a/contracts/deploy-config-example.json +++ b/contracts/deploy-config-example.json @@ -23,8 +23,16 @@ "messageTreeDepth": 2, "voteOptionTreeDepth": 2, "messageBatchDepth": 1, - "processMessagesZkey": "../cli/zkeys/ProcessMessages_10-2-1-2_test/ProcessMessages_10-2-1-2_test.0.zkey", - "tallyVotesZkey": "../cli/zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test.0.zkey" + "zkeys": { + "qv": { + "processMessagesZkey": "../cli/zkeys/ProcessMessages_10-2-1-2_test/ProcessMessages_10-2-1-2_test.0.zkey", + "tallyVotesZkey": "../cli/zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test.0.zkey" + }, + "nonQv": { + "processMessagesZkey": "../cli/zkeys/ProcessMessagesNonQv_10-2-1-2_test/ProcessMessagesNonQv_10-2-1-2_test.0.zkey", + "tallyVotesZkey": "../cli/zkeys/TallyVotesNonQv_10-1-2_test/TallyVotesNonQv_10-1-2_test.0.zkey" + } + } }, "Poll": { "pollDuration": 30, diff --git a/contracts/tasks/deploy/maci/10-vkRegistry.ts b/contracts/tasks/deploy/maci/10-vkRegistry.ts index 85704ebcd0..97d6408f03 100644 --- a/contracts/tasks/deploy/maci/10-vkRegistry.ts +++ b/contracts/tasks/deploy/maci/10-vkRegistry.ts @@ -32,31 +32,64 @@ deployment const messageTreeDepth = deployment.getDeployConfigField(EContracts.VkRegistry, "messageTreeDepth"); const messageBatchDepth = deployment.getDeployConfigField(EContracts.VkRegistry, "messageBatchDepth"); const voteOptionTreeDepth = deployment.getDeployConfigField(EContracts.VkRegistry, "voteOptionTreeDepth"); - const processMessagesZkeyPath = deployment.getDeployConfigField( + const processMessagesZkeyPathQv = deployment.getDeployConfigField( EContracts.VkRegistry, - "processMessagesZkey", + "zkeys.qv.processMessagesZkey", + ); + const processMessagesZkeyPathNonQv = deployment.getDeployConfigField( + EContracts.VkRegistry, + "zkeys.nonQv.processMessagesZkey", + ); + const tallyVotesZkeyPathQv = deployment.getDeployConfigField( + EContracts.VkRegistry, + "zkeys.qv.tallyVotesZkey", + ); + const tallyVotesZkeyPathNonQv = deployment.getDeployConfigField( + EContracts.VkRegistry, + "zkeys.nonQv.tallyVotesZkey", ); - const tallyVotesZkeyPath = deployment.getDeployConfigField(EContracts.VkRegistry, "tallyVotesZkey"); const useQuadraticVoting = deployment.getDeployConfigField(EContracts.Poll, "useQuadraticVoting") ?? false; - const [processVk, tallyVk] = await Promise.all([ - extractVk(processMessagesZkeyPath), - extractVk(tallyVotesZkeyPath), - ]).then((vks) => vks.map((vk) => VerifyingKey.fromObj(vk))); + if (useQuadraticVoting && (!tallyVotesZkeyPathQv || !processMessagesZkeyPathQv)) { + throw new Error("QV zkeys are not set"); + } + + if (!useQuadraticVoting && (!tallyVotesZkeyPathNonQv || !processMessagesZkeyPathNonQv)) { + throw new Error("Non-QV zkeys are not set"); + } + + const [qvProcessVk, qvTallyVk, nonQvProcessVk, nonQvTallyQv] = await Promise.all([ + processMessagesZkeyPathQv && extractVk(processMessagesZkeyPathQv), + tallyVotesZkeyPathQv && extractVk(tallyVotesZkeyPathQv), + processMessagesZkeyPathNonQv && extractVk(processMessagesZkeyPathNonQv), + tallyVotesZkeyPathNonQv && extractVk(tallyVotesZkeyPathNonQv), + ]).then((vks) => vks.map((vk) => vk && (VerifyingKey.fromObj(vk).asContractParam() as IVerifyingKeyStruct))); const vkRegistryContract = await deployment.deployContract(EContracts.VkRegistry, deployer); + const processZkeys = [qvProcessVk, nonQvProcessVk].filter(Boolean) as IVerifyingKeyStruct[]; + const tallyZkeys = [qvTallyVk, nonQvTallyQv].filter(Boolean) as IVerifyingKeyStruct[]; + const modes: EMode[] = []; + + if (qvProcessVk && qvTallyVk) { + modes.push(EMode.QV); + } + + if (nonQvProcessVk && nonQvTallyQv) { + modes.push(EMode.NON_QV); + } + await vkRegistryContract - .setVerifyingKeys( + .setVerifyingKeysBatch( stateTreeDepth, intStateTreeDepth, messageTreeDepth, voteOptionTreeDepth, 5 ** messageBatchDepth, - useQuadraticVoting ? EMode.QV : EMode.NON_QV, - processVk.asContractParam() as IVerifyingKeyStruct, - tallyVk.asContractParam() as IVerifyingKeyStruct, + modes, + processZkeys, + tallyZkeys, ) .then((tx) => tx.wait()); diff --git a/contracts/tests/VkRegistry.test.ts b/contracts/tests/VkRegistry.test.ts index 67b1a218b5..ddb95923dc 100644 --- a/contracts/tests/VkRegistry.test.ts +++ b/contracts/tests/VkRegistry.test.ts @@ -4,7 +4,14 @@ import { Signer } from "ethers"; import { IVerifyingKeyStruct, VkRegistry, deployVkRegistry, getDefaultSigner } from "../ts"; import { EMode } from "../ts/constants"; -import { messageBatchSize, testProcessVk, testTallyVk, treeDepths } from "./constants"; +import { + messageBatchSize, + testProcessVk, + testProcessVkNonQv, + testTallyVk, + testTallyVkNonQv, + treeDepths, +} from "./constants"; import { compareVks } from "./utils"; describe("VkRegistry", () => { @@ -18,6 +25,7 @@ describe("VkRegistry", () => { signer = await getDefaultSigner(); vkRegistryContract = await deployVkRegistry(signer, true); }); + it("should have set the correct owner", async () => { expect(await vkRegistryContract.owner()).to.eq(await signer.getAddress()); }); @@ -89,6 +97,44 @@ describe("VkRegistry", () => { }); }); + describe("setVerifyingKeysBatch", () => { + it("should set the process and tally vks", async () => { + const tx = await vkRegistryContract.setVerifyingKeysBatch( + stateTreeDepth, + treeDepths.intStateTreeDepth, + treeDepths.messageTreeDepth, + treeDepths.voteOptionTreeDepth, + messageBatchSize, + [EMode.NON_QV], + [testProcessVkNonQv.asContractParam() as IVerifyingKeyStruct], + [testTallyVkNonQv.asContractParam() as IVerifyingKeyStruct], + { gasLimit: 1000000 }, + ); + + const receipt = await tx.wait(); + expect(receipt?.status).to.eq(1); + }); + + it("should throw when zkeys doesn't have the same length", async () => { + await expect( + vkRegistryContract.setVerifyingKeysBatch( + stateTreeDepth, + treeDepths.intStateTreeDepth, + treeDepths.messageTreeDepth, + treeDepths.voteOptionTreeDepth, + messageBatchSize, + [EMode.QV], + [ + testProcessVk.asContractParam() as IVerifyingKeyStruct, + testProcessVkNonQv.asContractParam() as IVerifyingKeyStruct, + ], + [testTallyVk.asContractParam() as IVerifyingKeyStruct], + { gasLimit: 1000000 }, + ), + ).to.be.revertedWithCustomError(vkRegistryContract, "InvalidKeysParams"); + }); + }); + describe("hasVks", () => { describe("hasProcessVk", () => { it("should return true for the process vk", async () => { diff --git a/contracts/tests/constants.ts b/contracts/tests/constants.ts index f2464db2a6..a7c6957e9b 100644 --- a/contracts/tests/constants.ts +++ b/contracts/tests/constants.ts @@ -26,6 +26,22 @@ export const testTallyVk = new VerifyingKey( [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], ); +export const testProcessVkNonQv = new VerifyingKey( + new G1Point(BigInt(1), BigInt(1)), + new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), + new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), + new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), + [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], +); + +export const testTallyVkNonQv = new VerifyingKey( + new G1Point(BigInt(1), BigInt(1)), + new G2Point([BigInt(2), BigInt(3)], [BigInt(4), BigInt(5)]), + new G2Point([BigInt(6), BigInt(7)], [BigInt(8), BigInt(9)]), + new G2Point([BigInt(10), BigInt(11)], [BigInt(12), BigInt(13)]), + [new G1Point(BigInt(14), BigInt(15)), new G1Point(BigInt(16), BigInt(17))], +); + export const initialVoiceCreditBalance = 100; export const maxValues: MaxValues = { maxMessages: STATE_TREE_ARITY ** MESSAGE_TREE_DEPTH, diff --git a/integrationTests/ts/__tests__/integration.test.ts b/integrationTests/ts/__tests__/integration.test.ts index f90752901d..a792b82ba9 100644 --- a/integrationTests/ts/__tests__/integration.test.ts +++ b/integrationTests/ts/__tests__/integration.test.ts @@ -78,14 +78,22 @@ describe("Integration tests", function test() { messageTreeDepth: MSG_TREE_DEPTH, voteOptionTreeDepth: VOTE_OPTION_TREE_DEPTH, messageBatchDepth: MSG_BATCH_DEPTH, - processMessagesZkeyPath: path.resolve( + processMessagesZkeyPathQv: path.resolve( __dirname, "../../../cli/zkeys/ProcessMessages_10-2-1-2_test/ProcessMessages_10-2-1-2_test.0.zkey", ), - tallyVotesZkeyPath: path.resolve( + tallyVotesZkeyPathQv: path.resolve( __dirname, "../../../cli/zkeys/TallyVotes_10-1-2_test/TallyVotes_10-1-2_test.0.zkey", ), + processMessagesZkeyPathNonQv: path.resolve( + __dirname, + "../../../cli/zkeys/ProcessMessagesNonQv_10-2-1-2_test/ProcessMessagesNonQv_10-2-1-2_test.0.zkey", + ), + tallyVotesZkeyPathNonQv: path.resolve( + __dirname, + "../../../cli/zkeys/TallyVotesNonQv_10-1-2_test/TallyVotesNonQv_10-1-2_test.0.zkey", + ), vkRegistry: vkRegistryAddress, signer, }); diff --git a/website/versioned_docs/version-v1.3_alpha/cli.md b/website/versioned_docs/version-v1.3_alpha/cli.md index 41f75b97e0..11692acc3c 100644 --- a/website/versioned_docs/version-v1.3_alpha/cli.md +++ b/website/versioned_docs/version-v1.3_alpha/cli.md @@ -37,7 +37,7 @@ pnpm run hardhat | `deployVkRegistry` | Deploy a new verification key registry contract | `-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | | `show` | Show the deployed contract addresses | `-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | | `deployPoll` | Deploy a new poll | `-vk, --vkRegistryAddress `: The vk registry contract address
`-t, --duration `: The poll duration
`-i, --int-state-tree-depth `: The int state tree depth
`-b, --msg-batch-depth `: The message tree sub depth
`-m, --msg-tree-depth `: The message tree depth
`-v, --vote-option-tree-depth `: The vote option tree depth
`-pk, --pubkey `: The coordinator public key
`-uq, --use-quadratic-voting"`: Whether to use quadratic voting
`-x, --maci-address `: The MACI contract address
`-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | -| `setVerifyingKeys` | Set the verifying keys | `-s, --state-tree-depth `: The state tree depth
`-i, --int-state-tree-depth `: The intermediate state tree depth
`-m, --msg-tree-depth `: The message tree depth
`-v, --vote-option-tree-depth `: The vote option tree depth
`-b, --msg-batch-depth `: The message batch depth
`-p, --process-messages-zkey `: The process messages zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-t, --tally-votes-zkey `: The tally votes zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-uq, --use-quadratic-voting"`: Whether to use quadratic voting
`-k, --vk-registry `: The vk registry contract address
`-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | +| `setVerifyingKeys` | Set the verifying keys | `-s, --state-tree-depth `: The state tree depth
`-i, --int-state-tree-depth `: The intermediate state tree depth
`-m, --msg-tree-depth `: The message tree depth
`-v, --vote-option-tree-depth `: The vote option tree depth
`-b, --msg-batch-depth `: The message batch depth
`-pqv, --process-messages-zkey-qv `: The process messages qv zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-tqv, --tally-votes-zkey-qv `: The tally votes qv zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-pnqv, --process-messages-zkey-non-qv `: The process messages non-qv zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-tnqv, --tally-votes-zkey-non-qv `: The tally votes qv zkey path (see different options to use specific circuits [Trusted setup](https://maci.pse.dev/docs/trusted-setup) or [Testing](https://maci.pse.dev/docs/testing/#pre-compiled-artifacts-for-testing))
`-uq, --use-quadratic-voting"`: Whether to use quadratic voting
`-k, --vk-registry `: The vk registry contract address
`-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | | `publish` | Publish a new message to a MACI Poll contract | `-p, --pubkey `: The MACI public key which should replace the user's public key in the state tree
`-x, --maci-address `: The MACI contract address
`-sk, --privkey `: Your serialized MACI private key
`-i, --state-index `: The user's state index
`-v, --vote-option-index `: The vote option index
`-n, --nonce `: The message nonce
`-s, --salt `: The message salt
`-o, --poll-id `: The poll id
`-w, --new-vote-weight `: The new vote weight
`-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL | | `mergeMessages` | Merge the message accumulator queue | `-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL
`-x, --maci-address `: The MACI contract address
`-o, --poll-id `: The poll id
`-n, --num-queue-ops `: The number of queue operations | | `mergeSignups` | Merge the signups accumulator queue | `-q, --quiet`: Whether to print values to the console
`-r, --rpc-provider `: The rpc provider URL
`-x, --maci-address `: The MACI contract address
`-o, --poll-id `: The poll id
`-n, --num-queue-ops `: The number of queue operations |