From db1b369f5c64765de04e3b0ee50915f56532ea00 Mon Sep 17 00:00:00 2001 From: drewstone Date: Thu, 8 Dec 2022 20:31:37 -0700 Subject: [PATCH] Updates to extension architecture (#211) Co-authored-by: semaraugusto --- .prettierrc.json | 2 +- package.json | 1 + packages/anchors/src/ChainalysisVAnchor.ts | 5 + packages/anchors/src/IdentityVAnchor.ts | 235 +---- packages/anchors/src/OpenVAnchor.ts | 15 +- packages/anchors/src/VAnchor.ts | 248 +++-- packages/anchors/src/VAnchorForest.ts | 283 +++--- packages/bridges/src/SignatureBridgeSide.ts | 22 +- .../contracts/contracts/SignatureBridge.sol | 184 ++-- packages/contracts/contracts/Treasury.sol | 97 +- .../contracts/anchors/AnchorBase.sol | 116 --- .../contracts/anchors/AnchorForest.sol | 101 -- .../contracts/anchors/LinkableAnchor.sol | 342 +++---- .../anchors/LinkableAnchorForest.sol | 243 ----- .../contracts/handlers/AnchorHandler.sol | 108 ++- .../contracts/handlers/HandlerHelpers.sol | 54 +- .../contracts/handlers/RegistryHandler.sol | 152 +-- .../handlers/TokenWrapperHandler.sol | 96 +- .../contracts/handlers/TreasuryHandler.sol | 83 +- .../contracts/contracts/hashers/IHasher.sol | 12 +- .../contracts/hashers/KeccakHasher.sol | 122 ++- .../contracts/contracts/hashers/Poseidon.sol | 7 +- .../contracts/hashers/PoseidonHasher.sol | 176 ++-- .../contracts/hashers/SnarkConstants.sol | 7 +- .../contracts/interfaces/IExecutor.sol | 15 +- .../contracts/interfaces/IMerkleSystem.sol | 78 ++ .../contracts/interfaces/ITreasury.sol | 13 +- .../interfaces/anchors/ILinkableAnchor.sol | 33 +- .../interfaces/anchors/ISemaphoreGroups.sol | 106 +-- .../anchors/LinkableIncrementalBinaryTree.sol | 16 - .../external/aave/IAaveLendingPool.sol | 18 +- .../external/chainalysis/ISanctionsList.sol | 4 +- .../interfaces/tokens/IAaveTokenWrapper.sol | 8 +- .../tokens/IFungibleTokenWrapper.sol | 18 +- .../interfaces/tokens/IMintableERC20.sol | 56 +- .../interfaces/tokens/IMultiTokenManager.sol | 41 +- .../interfaces/tokens/IMultiTokenWrapper.sol | 64 +- .../contracts/interfaces/tokens/IRegistry.sol | 48 +- .../interfaces/tokens/ITokenWrapper.sol | 42 +- .../interfaces/verifiers/IAnchorVerifier.sol | 18 +- .../verifiers/IMASPVAnchorVerifier.sol | 48 +- .../interfaces/verifiers/ISetVerifier.sol | 6 +- .../interfaces/verifiers/IVAnchorVerifier.sol | 48 +- .../interfaces/verifiers/IVerifier.sol | 60 +- .../libs/IdentityVAnchorEncodeInputs.sol | 424 +-------- .../libs/MASPVAnchorEncodeInputs.sol | 213 +++++ .../contracts/libs/VAnchorEncodeInputs.sol | 660 ++++--------- .../contracts/contracts/mocks/ERC1155Mock.sol | 13 +- .../contracts/contracts/mocks/ERC20Mock.sol | 8 +- .../contracts/contracts/mocks/ERC721Mock.sol | 16 +- .../contracts/mocks/LinkableAnchorMock.sol | 94 +- .../contracts/mocks/MerkleForestMock.sol | 32 +- .../mocks/MerkleTreePoseidonMock.sol | 10 +- packages/contracts/contracts/structs/Edge.sol | 16 +- .../contracts/structs/MultiAssetExtData.sol | 4 +- .../contracts/structs/PublicInputs.sol | 49 + .../contracts/structs/SingleAssetExtData.sol | 2 +- .../contracts/tokens/AaveTokenWrapper.sol | 75 +- .../contracts/tokens/FungibleTokenWrapper.sol | 272 +++--- .../tokens/MultiFungibleTokenManager.sol | 69 +- .../contracts/tokens/MultiNftTokenManager.sol | 60 +- .../tokens/MultiTokenManagerBase.sol | 72 +- .../contracts/tokens/NftTokenWrapper.sol | 372 ++++---- .../contracts/contracts/tokens/Registry.sol | 194 ++-- .../contracts/tokens/TokenWrapper.sol | 360 +++---- .../trees/LinkableIncrementalBinaryTree.sol | 720 ++++++-------- .../contracts/trees/MerkleForest.sol | 195 ++-- .../contracts/contracts/trees/MerkleTree.sol | 31 +- .../contracts/trees/MerkleTreeWithHistory.sol | 209 ++--- .../contracts/utils/ChainIdWithType.sol | 54 +- .../contracts/contracts/utils/Governable.sol | 397 ++++---- .../contracts/contracts/utils/Initialized.sol | 18 +- .../contracts/contracts/utils/Pausable.sol | 144 +-- .../contracts/utils/ProposalNonceTracker.sol | 38 +- .../contracts/utils/SanctionFilter.sol | 12 +- .../contracts/vanchors/ChainalysisVAnchor.sol | 348 ------- .../contracts/vanchors/IdentityVAnchor.sol | 357 ------- .../contracts/vanchors/MultiAssetVAnchor.sol | 429 --------- .../contracts/vanchors/OpenVAnchor.sol | 301 ------ .../contracts/contracts/vanchors/VAnchor.sol | 376 -------- .../contracts/vanchors/VAnchorBase.sol | 110 --- .../contracts/vanchors/VAnchorForest.sol | 406 -------- .../contracts/vanchors/VAnchorForestBase.sol | 112 --- .../vanchors/base/MultiAssetVAnchor.sol | 150 +++ .../contracts/vanchors/base/VAnchor.sol | 115 +++ .../contracts/vanchors/base/VAnchorBase.sol | 290 ++++++ .../contracts/vanchors/base/ZKVAnchorBase.sol | 236 +++++ .../extensions/ChainalysisVAnchor.sol | 65 ++ .../vanchors/extensions/IdentityVAnchor.sol | 113 +++ .../vanchors/extensions/OpenVAnchor.sol | 182 ++++ .../vanchors/instances/VAnchorForest.sol | 78 ++ .../vanchors/instances/VAnchorTree.sol | 67 ++ .../contracts/verifiers/AnchorVerifier.sol | 3 +- .../verifiers/IdentityVAnchorVerifier.sol | 3 +- .../verifiers/MASPVAnchorVerifier.sol | 3 +- .../contracts/verifiers/TxProofVerifier.sol | 70 +- .../contracts/verifiers/VAnchorVerifier.sol | 3 +- .../contracts/verifiers/anchor/Verifier2.sol | 559 ++++++----- .../contracts/verifiers/anchor/Verifier3.sol | 569 +++++++----- .../contracts/verifiers/anchor/Verifier4.sol | 579 +++++++----- .../contracts/verifiers/anchor/Verifier5.sol | 589 ++++++------ .../contracts/verifiers/anchor/Verifier6.sol | 599 ++++++------ .../identity_vanchor_16/VerifierID2_16.sol | 759 ++++++++------- .../identity_vanchor_16/VerifierID8_16.sol | 879 ++++++++++-------- .../identity_vanchor_2/VerifierID2_2.sol | 619 ++++++------ .../identity_vanchor_2/VerifierID8_2.sol | 739 ++++++++------- .../masp_vanchor_16/VerifierMASP2_16.sol | 749 ++++++++------- .../masp_vanchor_16/VerifierMASP8_16.sol | 809 ++++++++-------- .../masp_vanchor_2/VerifierMASP2_2.sol | 609 ++++++------ .../masp_vanchor_2/VerifierMASP8_2.sol | 669 +++++++------ .../verifiers/vanchor_16/Verifier2_16.sol | 739 ++++++++------- .../verifiers/vanchor_16/Verifier8_16.sol | 799 ++++++++-------- .../verifiers/vanchor_2/Verifier2_2.sol | 599 ++++++------ .../verifiers/vanchor_2/Verifier8_2.sol | 659 +++++++------ .../vanchor_forest_16/VerifierF2_16.sol | 739 ++++++++------- .../vanchor_forest_16/VerifierF8_16.sol | 799 ++++++++-------- .../vanchor_forest_2/VerifierF2_2.sol | 599 ++++++------ .../vanchor_forest_2/VerifierF8_2.sol | 659 +++++++------ packages/contracts/hardhat.config.ts | 2 +- .../contracts/test/anchor/addEdges.test.ts | 23 +- .../contracts/test/anchor/updateEdges.test.ts | 31 +- .../identityVAnchor/identityVAnchor.test.ts | 329 ++++++- .../test/open-vanchor/openVAnchor.test.ts | 4 +- .../contracts/test/trees/MerkleForest.test.ts | 12 +- .../test/trees/MerkleTreePoseidon.test.ts | 11 +- .../test/vanchor/ChainalysisVAnchor.test.ts | 1 + .../test/vanchor/mocks/SetupTxVAnchorMock.ts | 15 +- .../contracts/test/vanchor/vanchor.test.ts | 343 +++---- .../test/vanchor/vanchorForest.test.ts | 367 ++++---- .../test/vbridge/signatureVBridge.test.ts | 163 ++-- .../test/vbridge/signatureVBridgeSide.test.ts | 54 +- .../src/{IAnchor.ts => IVAnchor.ts} | 6 +- packages/interfaces/src/anchor/index.ts | 28 - packages/interfaces/src/bridge/index.ts | 4 +- packages/interfaces/src/index.ts | 3 +- packages/interfaces/src/vanchor/index.ts | 7 +- packages/tokens/src/MintableToken.ts | 8 +- packages/utils/src/utils.ts | 3 + packages/vbridge/src/VBridge.ts | 120 +-- yarn.lock | 26 +- 140 files changed, 13825 insertions(+), 14155 deletions(-) delete mode 100644 packages/contracts/contracts/anchors/AnchorBase.sol delete mode 100644 packages/contracts/contracts/anchors/AnchorForest.sol delete mode 100644 packages/contracts/contracts/anchors/LinkableAnchorForest.sol create mode 100644 packages/contracts/contracts/interfaces/IMerkleSystem.sol delete mode 100644 packages/contracts/contracts/interfaces/anchors/LinkableIncrementalBinaryTree.sol create mode 100644 packages/contracts/contracts/libs/MASPVAnchorEncodeInputs.sol create mode 100644 packages/contracts/contracts/structs/PublicInputs.sol delete mode 100644 packages/contracts/contracts/vanchors/ChainalysisVAnchor.sol delete mode 100644 packages/contracts/contracts/vanchors/IdentityVAnchor.sol delete mode 100644 packages/contracts/contracts/vanchors/MultiAssetVAnchor.sol delete mode 100644 packages/contracts/contracts/vanchors/OpenVAnchor.sol delete mode 100644 packages/contracts/contracts/vanchors/VAnchor.sol delete mode 100644 packages/contracts/contracts/vanchors/VAnchorBase.sol delete mode 100644 packages/contracts/contracts/vanchors/VAnchorForest.sol delete mode 100644 packages/contracts/contracts/vanchors/VAnchorForestBase.sol create mode 100644 packages/contracts/contracts/vanchors/base/MultiAssetVAnchor.sol create mode 100644 packages/contracts/contracts/vanchors/base/VAnchor.sol create mode 100644 packages/contracts/contracts/vanchors/base/VAnchorBase.sol create mode 100644 packages/contracts/contracts/vanchors/base/ZKVAnchorBase.sol create mode 100644 packages/contracts/contracts/vanchors/extensions/ChainalysisVAnchor.sol create mode 100644 packages/contracts/contracts/vanchors/extensions/IdentityVAnchor.sol create mode 100644 packages/contracts/contracts/vanchors/extensions/OpenVAnchor.sol create mode 100644 packages/contracts/contracts/vanchors/instances/VAnchorForest.sol create mode 100644 packages/contracts/contracts/vanchors/instances/VAnchorTree.sol rename packages/interfaces/src/{IAnchor.ts => IVAnchor.ts} (89%) delete mode 100644 packages/interfaces/src/anchor/index.ts diff --git a/.prettierrc.json b/.prettierrc.json index 78d37ae9a..b2452df00 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -5,7 +5,7 @@ "options": { "printWidth": 100, "tabWidth": 4, - "useTabs": false, + "useTabs": true, "singleQuote": false, "bracketSpacing": true } diff --git a/package.json b/package.json index 0e66c5a1e..01a4e973d 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "hardhat-gas-reporter": "^1.0.8", "lerna": "^5.4.3", "nx": "^14.5.10", + "prettier-plugin-solidity": "^1.0.0", "truffle-assertions": "^0.9.2", "web3": "^1.3.6", "web3-utils": "^1.2.11" diff --git a/packages/anchors/src/ChainalysisVAnchor.ts b/packages/anchors/src/ChainalysisVAnchor.ts index 704a6f910..a27a65483 100644 --- a/packages/anchors/src/ChainalysisVAnchor.ts +++ b/packages/anchors/src/ChainalysisVAnchor.ts @@ -34,6 +34,11 @@ export class ChainalysisVAnchor extends VAnchor { ); createdVAnchor.latestSyncedBlock = vAnchor.deployTransaction.blockNumber!; createdVAnchor.token = token; + const tx = await createdVAnchor.contract.initialize( + BigNumber.from('1'), + BigNumber.from(2).pow(256).sub(1) + ); + await tx.wait(); return createdVAnchor; } } diff --git a/packages/anchors/src/IdentityVAnchor.ts b/packages/anchors/src/IdentityVAnchor.ts index 54e995d9d..7fa702792 100644 --- a/packages/anchors/src/IdentityVAnchor.ts +++ b/packages/anchors/src/IdentityVAnchor.ts @@ -26,13 +26,18 @@ import { CircomUtxo, } from '@webb-tools/sdk-core'; import { - IAnchorDeposit, - IAnchor, + IVAnchor, IIdentityVariableAnchorExtData, IIdentityVariableAnchorPublicInputs, - IAnchorDepositInfo, } from '@webb-tools/interfaces'; -import { hexToU8a, u8aToHex, getChainIdType, UTXOInputs, ZkComponents } from '@webb-tools/utils'; +import { + hexToU8a, + u8aToHex, + getChainIdType, + UTXOInputs, + ZkComponents, + ZERO_BYTES32, +} from '@webb-tools/utils'; import { Semaphore } from '@webb-tools/semaphore'; import { LinkedGroup } from '@webb-tools/semaphore-group'; @@ -77,7 +82,7 @@ export var proofTimeBenchmark = []; // It represents a deployed contract throughout its life (e.g. maintains merkle tree state) // Functionality relevant to anchors in general (proving, verifying) is implemented in static methods // Functionality relevant to a particular anchor deployment (deposit, withdraw) is implemented in instance methods -export class IdentityVAnchor implements IAnchor { +export class IdentityVAnchor implements IVAnchor { signer: ethers.Signer; contract: IdentityVAnchorContract; semaphore: Semaphore; @@ -117,59 +122,7 @@ export class IdentityVAnchor implements IAnchor { this.smallCircuitZkComponents = smallCircuitZkComponents; this.largeCircuitZkComponents = largeCircuitZkComponents; } - deposit(destinationChainId: number): Promise { - throw new Error('Method not implemented.'); - } - setupWithdraw( - deposit: IAnchorDepositInfo, - index: number, - recipient: string, - relayer: string, - fee: bigint, - refreshCommitment: string | number - ) { - throw new Error('Method not implemented.'); - } - withdraw( - deposit: IAnchorDepositInfo, - index: number, - recipient: string, - relayer: string, - fee: bigint, - refreshCommitment: string | number - ): Promise { - throw new Error('Method not implemented.'); - } - wrapAndDeposit( - tokenAddress: string, - wrappingFee: number, - destinationChainId?: number - ): Promise { - throw new Error('Method not implemented.'); - } - bridgedWithdrawAndUnwrap( - deposit: IAnchorDeposit, - merkleProof: any, - recipient: string, - relayer: string, - fee: string, - refund: string, - refreshCommitment: string, - tokenAddress: string - ): Promise { - throw new Error('Method not implemented.'); - } - bridgedWithdraw( - deposit: IAnchorDeposit, - merkleProof: any, - recipient: string, - relayer: string, - fee: string, - refund: string, - refreshCommitment: string - ): Promise { - throw new Error('Method not implemented.'); - } + getAddress(): string { return this.contract.address; } @@ -201,8 +154,8 @@ export class IdentityVAnchor implements IAnchor { const vAnchor = await factory.deploy( semaphore.contract.address, verifier, - levels, hasher, + levels, handler, token, maxEdges, @@ -221,6 +174,11 @@ export class IdentityVAnchor implements IAnchor { ); createdIdentityVAnchor.latestSyncedBlock = vAnchor.deployTransaction.blockNumber!; createdIdentityVAnchor.token = token; + const tx = await createdIdentityVAnchor.contract.initialize( + BigNumber.from('1'), + BigNumber.from(2).pow(256).sub(1) + ); + await tx.wait(); return createdIdentityVAnchor; } @@ -235,7 +193,7 @@ export class IdentityVAnchor implements IAnchor { ) { const anchor = IdentityVAnchor__factory.connect(address, signer); const maxEdges = await anchor.maxEdges(); - const treeHeight = await anchor.levels(); + const treeHeight = await anchor.outerLevels(); const groupId = await anchor.groupId(); const createdAnchor = new IdentityVAnchor( anchor, @@ -466,7 +424,7 @@ export class IdentityVAnchor implements IAnchor { return rootData.root; }); let thisRoot = await this.contract.getLastRoot(); - return [thisRoot, ...neighborRootInfos]; + return [thisRoot.toString(), ...neighborRootInfos.map((bignum) => bignum.toString())]; } public async getClassAndContractRoots() { @@ -709,6 +667,7 @@ export class IdentityVAnchor implements IAnchor { relayer: string, fee: BigNumber, refund: BigNumber, + wrapUnwrapToken: string, encryptedOutput1: string, encryptedOutput2: string ): Promise<{ extData: ExtData; extDataHash: BigNumber }> { @@ -718,7 +677,7 @@ export class IdentityVAnchor implements IAnchor { relayer: toFixedHex(relayer, 20), fee: toFixedHex(fee), refund: toFixedHex(refund.toString()), - token: toFixedHex(this.token, 20), + token: toFixedHex(wrapUnwrapToken, 20), encryptedOutput1, encryptedOutput2, }; @@ -731,7 +690,7 @@ export class IdentityVAnchor implements IAnchor { recipient, relayer, refund.toString(), - this.token + wrapUnwrapToken ); return { extData, extDataHash }; } @@ -789,7 +748,8 @@ export class IdentityVAnchor implements IAnchor { fee: BigNumberish, refund: BigNumberish, recipient: string, - relayer: string + relayer: string, + wrapUnwrapToken: string ): Promise { const chainId = getChainIdType(await this.signer.getChainId()); const randomKeypair = new Keypair(); @@ -832,104 +792,17 @@ export class IdentityVAnchor implements IAnchor { .add(outputs.reduce((sum, x) => sum.add(BigNumber.from(BigInt(x.amount))), BigNumber.from(0))) .sub(inputs.reduce((sum, x) => sum.add(BigNumber.from(BigInt(x.amount))), BigNumber.from(0))); - const { extData, extDataHash } = await this.generateExtData( - recipient, - extAmount, - relayer, - BigNumber.from(fee), - BigNumber.from(refund), - outputs[0].encrypt(), - outputs[1].encrypt() - ); - - const vanchorInput: UTXOInputs = await this.generateUTXOInputs( - inputs, - outputs, - chainId, - extAmount, - BigNumber.from(fee), - extDataHash - ); - - const outSemaphoreProofs = this.generateOutputSemaphoreProof(outputs); - - const publicInputs = await this.setupTransaction( - keypair, - identityRootInputs, - identityMerkleProof, - outSemaphoreProofs, - vanchorInput, - extDataHash.toString() - ); - - let tx = await this.contract.transact({ ...publicInputs }, extData, { gasLimit: '0x5B8D80' }); - - // Add the leaves to the tree - outputs.forEach((x) => { - this.tree.insert(u8aToHex(x.commitment)); - let numOfElements = this.tree.number_of_elements(); - this.depositHistory[numOfElements - 1] = toFixedHex(this.tree.root().toString()); - }); - - return tx; - } - - public async transactWrap( - tokenAddress: string, - keypair: Keypair, - inputs: Utxo[], - outputs: Utxo[], - fee: BigNumberish, - refund: BigNumberish, - recipient: string, - relayer: string - ): Promise { - // Default UTXO chain ID will match with the configured signer's chain ID - const evmId = await this.signer.getChainId(); - const chainId = getChainIdType(evmId); - const randomKeypair = new Keypair(); - - const identityRootInputs = this.populateIdentityRootsForProof(); - const identityMerkleProof: MerkleProof = this.generateIdentityMerkleProof(keypair.getPubKey()); - - while (inputs.length !== 2 && inputs.length < 16) { - inputs.push( - await CircomUtxo.generateUtxo({ - curve: 'Bn254', - backend: 'Circom', - chainId: chainId.toString(), - originChainId: chainId.toString(), - amount: '0', - blinding: hexToU8a(randomBN(31).toHexString()), - keypair: randomKeypair, - }) - ); + if (wrapUnwrapToken.length === 0) { + wrapUnwrapToken = this.token; } - if (outputs.length < 2) { - while (outputs.length < 2) { - outputs.push( - await CircomUtxo.generateUtxo({ - curve: 'Bn254', - backend: 'Circom', - chainId: chainId.toString(), - originChainId: chainId.toString(), - amount: '0', - keypair: randomKeypair, - }) - ); - } - } - let extAmount = BigNumber.from(fee) - .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) - .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))); - const { extData, extDataHash } = await this.generateExtData( recipient, extAmount, relayer, BigNumber.from(fee), BigNumber.from(refund), + wrapUnwrapToken, outputs[0].encrypt(), outputs[1].encrypt() ); @@ -954,46 +827,38 @@ export class IdentityVAnchor implements IAnchor { extDataHash.toString() ); - let tx: ContractTransaction; - if (extAmount.gt(0) && checkNativeAddress(tokenAddress)) { - let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); - let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); - - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { - value: valueToSend.toHexString(), - gasLimit: '0x5B8D80', - } - ); - } else { - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { gasLimit: '0x5B8D80' } - ); - } - // const receipt = await tx.wait(); + let tx = await this.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + extData, + { gasLimit: '0x5B8D80' } + ); + const receipt = await tx.wait(); // Add the leaves to the tree outputs.forEach((x) => { - // Maintain tree state after insertions this.tree.insert(u8aToHex(x.commitment)); let numOfElements = this.tree.number_of_elements(); this.depositHistory[numOfElements - 1] = toFixedHex(this.tree.root().toString()); }); return tx; - // return receipt; } } diff --git a/packages/anchors/src/OpenVAnchor.ts b/packages/anchors/src/OpenVAnchor.ts index 8b200c9f2..7e0282497 100644 --- a/packages/anchors/src/OpenVAnchor.ts +++ b/packages/anchors/src/OpenVAnchor.ts @@ -14,7 +14,7 @@ import { MerkleProof, } from '@webb-tools/sdk-core'; import { u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils'; -import { IAnchor } from '@webb-tools/interfaces'; +import { IVAnchor } from '@webb-tools/interfaces'; const zeroAddress = '0x0000000000000000000000000000000000000000'; function checkNativeAddress(tokenAddress: string): boolean { @@ -34,7 +34,7 @@ export var proofTimeBenchmark = []; // It represents a deployed contract throughout its life (e.g. maintains merkle tree state) // Functionality relevant to anchors in general (proving, verifying) is implemented in static methods // Functionality relevant to a particular anchor deployment (deposit, withdraw) is implemented in instance methods -export class OpenVAnchor implements IAnchor { +export class OpenVAnchor implements IVAnchor { signer: ethers.Signer; contract: OpenVAnchorContract; tree: MerkleTree; @@ -65,10 +65,15 @@ export class OpenVAnchor implements IAnchor { signer: ethers.Signer ) { const factory = new OpenVAnchor__factory(signer); - const openVAnchor = await factory.deploy(levels, hasher, handler, token, {}); + const openVAnchor = await factory.deploy(hasher, levels, handler, token, {}); await openVAnchor.deployed(); const createdVAnchor = new OpenVAnchor(openVAnchor, signer, BigNumber.from(levels).toNumber()); createdVAnchor.token = token; + const tx = await createdVAnchor.contract.initialize( + BigNumber.from('1'), + BigNumber.from(2).pow(256).sub(1) + ); + await tx.wait(); return createdVAnchor; } @@ -79,7 +84,7 @@ export class OpenVAnchor implements IAnchor { signer: ethers.Signer ) { const anchor = OpenVAnchor__factory.connect(address, signer); - const treeHeight = await anchor.levels(); + const treeHeight = await anchor.outerLevels(); const createdAnchor = new OpenVAnchor(anchor, signer, treeHeight); createdAnchor.token = await anchor.token(); return createdAnchor; @@ -237,7 +242,7 @@ export class OpenVAnchor implements IAnchor { return rootData.root; }); let thisRoot = await this.contract.getLastRoot(); - return [thisRoot, ...neighborRootInfos]; + return [thisRoot.toString(), ...neighborRootInfos.map((bignum) => bignum.toString())]; } public async getClassAndContractRoots() { diff --git a/packages/anchors/src/VAnchor.ts b/packages/anchors/src/VAnchor.ts index 5b27006b3..5e5565a47 100644 --- a/packages/anchors/src/VAnchor.ts +++ b/packages/anchors/src/VAnchor.ts @@ -1,8 +1,7 @@ import { BigNumber, BigNumberish, ContractTransaction, ethers } from 'ethers'; import { - VAnchor as VAnchorContract, - VAnchor__factory, - ChainalysisVAnchor as ChainalysisVAnchorContract, + VAnchorTree as VAnchorTreeContract, + VAnchorTree__factory, VAnchorEncodeInputs__factory, TokenWrapper__factory, } from '@webb-tools/contracts'; @@ -26,11 +25,11 @@ import { LeafIdentifier, } from '@webb-tools/sdk-core'; import { - IAnchor, + IVAnchor, IVariableAnchorExtData, IVariableAnchorPublicInputs, } from '@webb-tools/interfaces'; -import { hexToU8a, u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils'; +import { hexToU8a, u8aToHex, getChainIdType, ZkComponents, ZERO_BYTES32 } from '@webb-tools/utils'; const zeroAddress = '0x0000000000000000000000000000000000000000'; function checkNativeAddress(tokenAddress: string): boolean { @@ -46,9 +45,9 @@ export var proofTimeBenchmark = []; // It represents a deployed contract throughout its life (e.g. maintains merkle tree state) // Functionality relevant to anchors in general (proving, verifying) is implemented in static methods // Functionality relevant to a particular anchor deployment (deposit, withdraw) is implemented in instance methods -export class VAnchor implements IAnchor { +export class VAnchor implements IVAnchor { signer: ethers.Signer; - contract: VAnchorContract | ChainalysisVAnchorContract; + contract: VAnchorTreeContract; tree: MerkleTree; // hex string of the connected root maxEdges: number; @@ -63,7 +62,7 @@ export class VAnchor implements IAnchor { provingManager: CircomProvingManager; constructor( - contract: VAnchorContract | ChainalysisVAnchorContract, + contract: VAnchorTreeContract, signer: ethers.Signer, treeHeight: number, maxEdges: number, @@ -98,7 +97,8 @@ export class VAnchor implements IAnchor { const encodeLibraryFactory = new VAnchorEncodeInputs__factory(signer); const encodeLibrary = await encodeLibraryFactory.deploy(); await encodeLibrary.deployed(); - const factory = new VAnchor__factory( + + const factory = new VAnchorTree__factory( { ['contracts/libs/VAnchorEncodeInputs.sol:VAnchorEncodeInputs']: encodeLibrary.address }, signer ); @@ -114,6 +114,11 @@ export class VAnchor implements IAnchor { ); createdVAnchor.latestSyncedBlock = vAnchor.deployTransaction.blockNumber!; createdVAnchor.token = token; + const tx = await createdVAnchor.contract.initialize( + BigNumber.from('1'), + BigNumber.from(2).pow(256).sub(1) + ); + await tx.wait(); return createdVAnchor; } @@ -125,7 +130,7 @@ export class VAnchor implements IAnchor { largeCircuitZkComponents: ZkComponents, signer: ethers.Signer ) { - const anchor = VAnchor__factory.connect(address, signer); + const anchor = VAnchorTree__factory.connect(address, signer); const maxEdges = await anchor.maxEdges(); const treeHeight = await anchor.levels(); const createdAnchor = new VAnchor( @@ -170,6 +175,7 @@ export class VAnchor implements IAnchor { return { proof: args[0], roots: args[1], + extensionRoots: '0x00', inputNullifiers: args[2], outputCommitments: args[3], publicAmount: args[4], @@ -322,7 +328,7 @@ export class VAnchor implements IAnchor { ); } - public async populateRootsForProof(): Promise { + public async populateRootsForProof(): Promise { const neighborEdges = await this.contract.getLatestNeighborEdges(); const neighborRootInfos = neighborEdges.map((rootData) => { return rootData.root; @@ -366,23 +372,24 @@ export class VAnchor implements IAnchor { public generatePublicInputs( proof: any, - roots: string[], + roots: BigNumber[], inputs: Utxo[], outputs: Utxo[], publicAmount: BigNumberish, - extDataHash: string + extDataHash: BigNumber ): IVariableAnchorPublicInputs { // public inputs to the contract const args: IVariableAnchorPublicInputs = { proof: `0x${proof}`, roots: `0x${roots.map((x) => toFixedHex(x).slice(2)).join('')}`, - inputNullifiers: inputs.map((x) => toFixedHex('0x' + x.nullifier)), + extensionRoots: '0x00', + inputNullifiers: inputs.map((x) => BigNumber.from(toFixedHex('0x' + x.nullifier))), outputCommitments: [ - toFixedHex(u8aToHex(outputs[0].commitment)), - toFixedHex(u8aToHex(outputs[1].commitment)), + BigNumber.from(toFixedHex(u8aToHex(outputs[0].commitment))), + BigNumber.from(toFixedHex(u8aToHex(outputs[1].commitment))), ], publicAmount: toFixedHex(publicAmount), - extDataHash: toFixedHex(extDataHash), + extDataHash, }; return args; @@ -458,9 +465,9 @@ export class VAnchor implements IAnchor { extAmount: BigNumberish, fee: BigNumberish, refund: BigNumberish, - token: string, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ) { // first, check if the merkle root is known on chain - if not, then update @@ -490,7 +497,7 @@ export class VAnchor implements IAnchor { inputUtxos: inputs, leavesMap, leafIds, - roots: roots.map((root) => hexToU8a(root)), + roots: roots.map((root) => hexToU8a(root.toHexString())), chainId: chainId.toString(), output: outputs, encryptedCommitments, @@ -502,7 +509,7 @@ export class VAnchor implements IAnchor { extAmount: toFixedHex(BigNumber.from(extAmount)), fee: BigNumber.from(fee).toString(), refund: BigNumber.from(refund).toString(), - token: hexToU8a(token), + token: hexToU8a(wrapUnwrapToken), }; inputs.length > 2 @@ -525,7 +532,7 @@ export class VAnchor implements IAnchor { inputs, outputs, proofInput.publicAmount, - u8aToHex(proof.extDataHash) + BigNumber.from(u8aToHex(proof.extDataHash)) ); const extData: IVariableAnchorExtData = { @@ -546,102 +553,13 @@ export class VAnchor implements IAnchor { } public async transact( - inputs: Utxo[], - outputs: Utxo[], - leavesMap: Record, - fee: BigNumberish, - refund: BigNumberish, - recipient: string, - relayer: string - ): Promise { - // Validate input utxos have a valid originChainId - inputs.map((utxo) => { - if (utxo.originChainId === undefined) { - throw new Error('Input Utxo does not have a configured originChainId'); - } - }); - - // Default UTXO chain ID will match with the configured signer's chain ID - const evmId = await this.signer.getChainId(); - const chainId = getChainIdType(evmId); - const randomKeypair = new Keypair(); - - while (inputs.length !== 2 && inputs.length < 16) { - inputs.push( - await CircomUtxo.generateUtxo({ - curve: 'Bn254', - backend: 'Circom', - chainId: chainId.toString(), - originChainId: chainId.toString(), - amount: '0', - blinding: hexToU8a(randomBN(31).toHexString()), - keypair: randomKeypair, - }) - ); - } - - if (outputs.length < 2) { - while (outputs.length < 2) { - outputs.push( - await CircomUtxo.generateUtxo({ - curve: 'Bn254', - backend: 'Circom', - chainId: chainId.toString(), - originChainId: chainId.toString(), - amount: '0', - keypair: randomKeypair, - }) - ); - } - } - - let extAmount = BigNumber.from(fee) - .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) - .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))); - - const token = this.token; - - const { extData, publicInputs } = await this.setupTransaction( - inputs, - [outputs[0], outputs[1]], - extAmount, - fee, - refund, - token, - recipient, - relayer, - leavesMap - ); - - let tx = await this.contract.transact( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - { gasLimit: '0x5B8D80' } - ); - const receipt = await tx.wait(); - gasBenchmark.push(receipt.gasUsed.toString()); - - // Add the leaves to the tree - outputs.forEach((x) => { - this.tree.insert(u8aToHex(x.commitment)); - let numOfElements = this.tree.number_of_elements(); - this.depositHistory[numOfElements - 1] = toFixedHex(this.tree.root().toString()); - }); - - return receipt; - } - - public async transactWrap( - tokenAddress: string, inputs: Utxo[], outputs: Utxo[], fee: BigNumberish, refund: BigNumberish, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ): Promise { // Default UTXO chain ID will match with the configured signer's chain ID @@ -682,46 +600,59 @@ export class VAnchor implements IAnchor { .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))); + if (wrapUnwrapToken.length === 0) { + wrapUnwrapToken = this.token; + } + const { extData, publicInputs } = await this.setupTransaction( inputs, [outputs[0], outputs[1]], extAmount, fee, refund, - tokenAddress, recipient, relayer, + wrapUnwrapToken, leavesMap ); - let tx: ContractTransaction; - if (extAmount.gt(0) && checkNativeAddress(tokenAddress)) { + let options = {}; + if (extAmount.gt(0) && checkNativeAddress(wrapUnwrapToken)) { let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { - value: valueToSend.toHexString(), - gasLimit: '0x5B8D80', - } - ); + options = { + value: valueToSend.toHexString(), + }; } else { - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { gasLimit: '0x5B8D80' } - ); + options = {}; } + + const tx = await this.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.roots, + extensionRoots: '0x', + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: extData.encryptedOutput1, + encryptedOutput2: extData.encryptedOutput2, + }, + options + ); const receipt = await tx.wait(); // Add the leaves to the tree @@ -744,6 +675,7 @@ export class VAnchor implements IAnchor { refund: BigNumberish, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ): Promise { const chainId = getChainIdType(await this.signer.getChainId()); @@ -783,7 +715,9 @@ export class VAnchor implements IAnchor { .add(outputs.reduce((sum, x) => sum.add(BigNumber.from(BigInt(x.amount))), BigNumber.from(0))) .sub(inputs.reduce((sum, x) => sum.add(BigNumber.from(BigInt(x.amount))), BigNumber.from(0))); - const token = this.token; + if (wrapUnwrapToken.length === 0) { + wrapUnwrapToken = this.token; + } const { extData, publicInputs } = await this.setupTransaction( inputs, @@ -791,20 +725,52 @@ export class VAnchor implements IAnchor { extAmount, fee, refund, - token, recipient, relayer, + wrapUnwrapToken, leavesMap ); + let options = {}; + if (extAmount.gt(0) && checkNativeAddress(wrapUnwrapToken)) { + let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); + let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); + + options = { + value: valueToSend.toHexString(), + }; + } else { + options = {}; + } + let tx = await this.contract.registerAndTransact( { owner, keyData: keyData }, + publicInputs.proof, + ZERO_BYTES32, { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, }, - extData, - { gasLimit: '0x5B8D80' } + { + roots: publicInputs.roots, + extensionRoots: [], + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + BigNumber.from(publicInputs.outputCommitments[0]), + BigNumber.from(publicInputs.outputCommitments[1]), + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: extData.encryptedOutput1, + encryptedOutput2: extData.encryptedOutput2, + }, + options ); const receipt = await tx.wait(); diff --git a/packages/anchors/src/VAnchorForest.ts b/packages/anchors/src/VAnchorForest.ts index 50d288751..d7415ea0a 100644 --- a/packages/anchors/src/VAnchorForest.ts +++ b/packages/anchors/src/VAnchorForest.ts @@ -34,11 +34,18 @@ import { // import { MerkleTree } from "." import { - IAnchor, + IVAnchor, IVariableAnchorExtData, IVariableAnchorPublicInputs, } from '@webb-tools/interfaces'; -import { hexToU8a, UTXOInputs, u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils'; +import { + hexToU8a, + UTXOInputs, + u8aToHex, + getChainIdType, + ZkComponents, + ZERO_BYTES32, +} from '@webb-tools/utils'; import { solidityPack } from 'ethers/lib/utils'; const zeroAddress = '0x0000000000000000000000000000000000000000'; @@ -167,6 +174,11 @@ export class VAnchorForest { ); createdVAnchor.latestSyncedBlock = vAnchor.deployTransaction.blockNumber!; createdVAnchor.token = token; + const tx = await createdVAnchor.contract.initialize( + BigNumber.from('1'), + BigNumber.from(2).pow(256).sub(1) + ); + await tx.wait(); return createdVAnchor; } @@ -185,8 +197,8 @@ export class VAnchorForest { const createdAnchor = new VAnchorForest( anchor, signer, - forestHeight.toNumber(), - subtreeHeight.toNumber(), + forestHeight, + subtreeHeight, maxEdges, smallCircuitZkComponents, largeCircuitZkComponents @@ -225,6 +237,7 @@ export class VAnchorForest { return { proof: args[0], roots: args[1], + extensionRoots: '0x', inputNullifiers: args[2], outputCommitments: args[3], publicAmount: args[4], @@ -377,13 +390,13 @@ export class VAnchorForest { ); } - public async populateRootsForProof(): Promise { + public async populateRootsForProof(): Promise { const neighborEdges = await this.contract.getLatestNeighborEdges(); const neighborRootInfos = neighborEdges.map((rootData) => { return rootData.root; }); let thisRoot = await this.contract.getLastRoot(); - return [thisRoot.toString(), ...neighborRootInfos.map((bignum) => bignum.toString())]; + return [thisRoot, ...neighborRootInfos]; } public async getClassAndContractRoots() { @@ -589,6 +602,7 @@ export class VAnchorForest { relayer: string, fee: BigNumber, refund: BigNumber, + wrapUnwrapToken: string, encryptedOutput1: string, encryptedOutput2: string ): Promise<{ extData: ExtData; extDataHash: BigNumber }> { @@ -598,7 +612,7 @@ export class VAnchorForest { relayer: toFixedHex(relayer, 20), fee: toFixedHex(fee), refund: toFixedHex(refund.toString()), - token: toFixedHex(this.token, 20), + token: toFixedHex(wrapUnwrapToken, 20), encryptedOutput1, encryptedOutput2, }; @@ -611,7 +625,7 @@ export class VAnchorForest { recipient, relayer, refund.toString(), - this.token + wrapUnwrapToken ); return { extData, extDataHash }; } @@ -625,7 +639,7 @@ export class VAnchorForest { }); const curIdx = await this.contract.currSubtreeIndex(); const lastSubtreeRoot = await this.contract.getLastSubtreeRoot(0); - this.forest.update(curIdx.toNumber(), this.tree.root().toHexString()); + this.forest.update(curIdx, this.tree.root().toHexString()); } /** @@ -639,14 +653,13 @@ export class VAnchorForest { extAmount: BigNumberish, fee: BigNumberish, refund: BigNumberish, - token: string, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ) { // first, check if the merkle root is known on chain - if not, then update const chainId = getChainIdType(await this.signer.getChainId()); - const roots = await this.populateRootsForProof(); // calculate the sum of input notes (for calculating the public amount) let sumInputUtxosAmount: BigNumberish = 0; @@ -672,6 +685,7 @@ export class VAnchorForest { relayer, BigNumber.from(fee), BigNumber.from(refund), + wrapUnwrapToken, outputs[0].encrypt(), outputs[1].encrypt() ); @@ -704,118 +718,6 @@ export class VAnchorForest { }; } - public async transact( - raw_inputs: Utxo[], - raw_outputs: Utxo[], - leavesMap: Record, - fee: BigNumberish, - refund: BigNumberish, - recipient: string, - relayer: string - ): Promise { - // Validate input utxos have a valid originChainId - raw_inputs.map((utxo) => { - if (utxo.originChainId === undefined) { - throw new Error('Input Utxo does not have a configured originChainId'); - } - }); - - // Default UTXO chain ID will match with the configured signer's chain ID - let { inputs, outputs } = await this.padInputsAndOutputs(raw_inputs, raw_outputs); - - let extAmount = await this.getExtAmount(inputs, outputs, fee); - - const { extData, publicInputs } = await this.setupTransaction( - inputs, - [outputs[0], outputs[1]], - extAmount, - fee, - refund, - this.token, - recipient, - relayer, - leavesMap - ); - // console.log("after setup transaction publicInputs", publicInputs) - - let tx = await this.contract.transact( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - { gasLimit: '0x5B8D80' } - ); - const receipt = await tx.wait(); - gasBenchmark.push(receipt.gasUsed.toString()); - - await this.updateForest(outputs); - - return receipt; - } - - public async transactWrap( - tokenAddress: string, - raw_inputs: Utxo[], - raw_outputs: Utxo[], - fee: BigNumberish, - refund: BigNumberish, - recipient: string, - relayer: string, - leavesMap: Record - ): Promise { - // Default UTXO chain ID will match with the configured signer's chain ID - let { inputs, outputs } = await this.padInputsAndOutputs(raw_inputs, raw_outputs); - - let extAmount = await this.getExtAmount(inputs, outputs, fee); - - const { extData, publicInputs } = await this.setupTransaction( - inputs, - [outputs[0], outputs[1]], - extAmount, - fee, - refund, - tokenAddress, - recipient, - relayer, - leavesMap - ); - - let tx: ContractTransaction; - if (extAmount.gt(0) && checkNativeAddress(tokenAddress)) { - let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); - let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); - - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { - value: valueToSend.toHexString(), - gasLimit: '0x5B8D80', - } - ); - } else { - tx = await this.contract.transactWrap( - { - ...publicInputs, - outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], - }, - extData, - tokenAddress, - { gasLimit: '0x5B8D80' } - ); - } - const receipt = await tx.wait(); - - // Add the leaves to the tree - await this.updateForest(outputs); - - return receipt; - } public async encodeSolidityProof(fullProof: any, calldata: any): Promise { const proof = JSON.parse('[' + calldata + ']'); const pi_a = proof[0]; @@ -880,34 +782,159 @@ export class VAnchorForest { refund: BigNumberish, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ): Promise { let { inputs, outputs } = await this.padInputsAndOutputs(raw_inputs, raw_outputs); let extAmount = await this.getExtAmount(inputs, outputs, fee); + if (wrapUnwrapToken.length === 0) { + wrapUnwrapToken = this.token; + } + const { extData, publicInputs } = await this.setupTransaction( inputs, [outputs[0], outputs[1]], extAmount, fee, refund, - this.token, recipient, relayer, + wrapUnwrapToken, leavesMap ); + + let options = {}; + if (extAmount.gt(0) && checkNativeAddress(wrapUnwrapToken)) { + let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); + let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); + + options = { + value: valueToSend.toHexString(), + gasLimit: '0x5B8D80', + }; + } else { + options = { + gasLimit: '0x5B8D80', + }; + } + let tx = await this.contract.registerAndTransact( { owner, keyData: keyData }, + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.roots, + extensionRoots: [], + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + BigNumber.from(publicInputs.outputCommitments[0]), + BigNumber.from(publicInputs.outputCommitments[1]), + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: extData.encryptedOutput1, + encryptedOutput2: extData.encryptedOutput2, + }, + options + ); + const receipt = await tx.wait(); + // Add the leaves to the tree + await this.updateForest(outputs); + + return receipt; + } + + public async transact( + raw_inputs: Utxo[], + raw_outputs: Utxo[], + fee: BigNumberish, + refund: BigNumberish, + recipient: string, + relayer: string, + wrapUnwrapToken: string, + leavesMap: Record + ): Promise { + // Validate input utxos have a valid originChainId + raw_inputs.map((utxo) => { + if (utxo.originChainId === undefined) { + throw new Error('Input Utxo does not have a configured originChainId'); + } + }); + + // Default UTXO chain ID will match with the configured signer's chain ID + let { inputs, outputs } = await this.padInputsAndOutputs(raw_inputs, raw_outputs); + + let extAmount = await this.getExtAmount(inputs, outputs, fee); + + if (wrapUnwrapToken.length === 0) { + wrapUnwrapToken = this.token; + } + + const { extData, publicInputs } = await this.setupTransaction( + inputs, + [outputs[0], outputs[1]], + extAmount, + fee, + refund, + recipient, + relayer, + wrapUnwrapToken, + leavesMap + ); + + let options = {}; + if (extAmount.gt(0) && checkNativeAddress(wrapUnwrapToken)) { + let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer); + let valueToSend = await tokenWrapper.getAmountToWrap(extAmount); + + options = { + value: valueToSend.toHexString(), + gasLimit: '0x5B8D80', + }; + } else { + options = { + gasLimit: '0x5B8D80', + }; + } + + const tx = await this.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, { - ...publicInputs, + roots: publicInputs.roots, + extensionRoots: [], + inputNullifiers: publicInputs.inputNullifiers, outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, }, - extData, - { gasLimit: '0x5B8D80' } + { + encryptedOutput1: extData.encryptedOutput1, + encryptedOutput2: extData.encryptedOutput2, + }, + options ); const receipt = await tx.wait(); - // Add the leaves to the tree await this.updateForest(outputs); return receipt; diff --git a/packages/bridges/src/SignatureBridgeSide.ts b/packages/bridges/src/SignatureBridgeSide.ts index 910b2a95f..840b1d13d 100644 --- a/packages/bridges/src/SignatureBridgeSide.ts +++ b/packages/bridges/src/SignatureBridgeSide.ts @@ -3,7 +3,7 @@ import { SignatureBridge, SignatureBridge__factory } from '@webb-tools/contracts import { FungibleTokenWrapper, Treasury } from '@webb-tools/tokens'; import { TokenWrapperHandler } from '@webb-tools/tokens'; import { AnchorHandler } from '@webb-tools/anchors'; -import { IAnchor, IBridgeSide, Proposal } from '@webb-tools/interfaces'; +import { IVAnchor, IBridgeSide, Proposal } from '@webb-tools/interfaces'; import { TreasuryHandler } from '@webb-tools/tokens'; import { getChainIdType } from '@webb-tools/utils'; import { signMessage, toHex } from '@webb-tools/sdk-core'; @@ -113,14 +113,14 @@ export class SignatureBridgeSide implements IBridgeSide { * @returns Promise */ public async createAnchorUpdateProposalData( - srcAnchor: IAnchor, + srcAnchor: IVAnchor, executionResourceID: string ): Promise { const proposalData = await srcAnchor.getProposalData(executionResourceID); return proposalData; } - public async createHandlerUpdateProposalData(anchor: IAnchor, newHandler: string) { + public async createHandlerUpdateProposalData(anchor: IVAnchor, newHandler: string) { const proposalData = await anchor.getHandlerProposalData(newHandler); return proposalData; } @@ -191,14 +191,14 @@ export class SignatureBridgeSide implements IBridgeSide { } public async createMinWithdrawalLimitProposalData( - vAnchor: IAnchor, + vAnchor: IVAnchor, _minimalWithdrawalAmount: string ) { const proposalData = await vAnchor.getMinWithdrawalLimitProposalData(_minimalWithdrawalAmount); return proposalData; } - public async createMaxDepositLimitProposalData(vAnchor: IAnchor, _maximumDepositAmount: string) { + public async createMaxDepositLimitProposalData(vAnchor: IVAnchor, _maximumDepositAmount: string) { const proposalData = await vAnchor.getMaxDepositLimitProposalData(_maximumDepositAmount); return proposalData; } @@ -218,7 +218,7 @@ export class SignatureBridgeSide implements IBridgeSide { // Connects the bridgeSide, anchor handler, and anchor. // Returns the resourceId of the anchor instance that connects // the anchor handler to the anchor (execution) contract. - public async connectAnchorWithSignature(anchor: IAnchor): Promise { + public async connectAnchorWithSignature(anchor: IVAnchor): Promise { const resourceId = await this.setAnchorResourceWithSignature(anchor); if (this.anchorHandler.contract.address !== (await anchor.getHandler())) { await this.executeHandlerProposalWithSig(anchor, this.anchorHandler.contract.address); @@ -271,7 +271,7 @@ export class SignatureBridgeSide implements IBridgeSide { return newResourceId; } - public async setAnchorResourceWithSignature(anchor: IAnchor): Promise { + public async setAnchorResourceWithSignature(anchor: IVAnchor): Promise { if (!this.anchorHandler) throw this.ANCHOR_HANDLER_MISSING_ERROR; const newResourceId = await anchor.createResourceId(); @@ -308,13 +308,13 @@ export class SignatureBridgeSide implements IBridgeSide { return receipt; } - public async executeHandlerProposalWithSig(anchor: IAnchor, newHandler: string) { + public async executeHandlerProposalWithSig(anchor: IVAnchor, newHandler: string) { const proposalData = await this.createHandlerUpdateProposalData(anchor, newHandler); return this.execute(proposalData); } // emit ProposalEvent(chainID, nonce, ProposalStatus.Executed, dataHash); - public async executeAnchorProposalWithSig(srcAnchor: IAnchor, executionResourceID: string) { + public async executeAnchorProposalWithSig(srcAnchor: IVAnchor, executionResourceID: string) { if (!this.anchorHandler) throw this.ANCHOR_HANDLER_MISSING_ERROR; const proposalData = await this.createAnchorUpdateProposalData(srcAnchor, executionResourceID); return this.execute(proposalData); @@ -383,7 +383,7 @@ export class SignatureBridgeSide implements IBridgeSide { } public async executeMinWithdrawalLimitProposalWithSig( - anchor: IAnchor, + anchor: IVAnchor, _minimalWithdrawalAmount: string ) { if (!this.anchorHandler) throw this.ANCHOR_HANDLER_MISSING_ERROR; @@ -395,7 +395,7 @@ export class SignatureBridgeSide implements IBridgeSide { } public async executeMaxDepositLimitProposalWithSig( - anchor: IAnchor, + anchor: IVAnchor, _maximumDepositAmount: string ) { if (!this.anchorHandler) throw this.ANCHOR_HANDLER_MISSING_ERROR; diff --git a/packages/contracts/contracts/SignatureBridge.sol b/packages/contracts/contracts/SignatureBridge.sol index 4fb039fe1..ee74043bc 100644 --- a/packages/contracts/contracts/SignatureBridge.sol +++ b/packages/contracts/contracts/SignatureBridge.sol @@ -17,35 +17,38 @@ import "./interfaces/IExecutor.sol"; @author ChainSafe Systems & Webb Technologies. */ contract SignatureBridge is Pausable, Governable, ChainIdWithType, ProposalNonceTracker { - // resourceID => handler address - mapping(bytes32 => address) public _resourceIDToHandlerAddress; + // resourceID => handler address + mapping(bytes32 => address) public _resourceIDToHandlerAddress; - /** + /** Verifying signature of governor over some datahash */ - modifier signedByGovernor(bytes memory data, bytes memory sig) { - require(isSignatureFromGovernor(data, sig), "SignatureBridge: Not valid sig from governor"); - _; - } + modifier signedByGovernor(bytes memory data, bytes memory sig) { + require(isSignatureFromGovernor(data, sig), "SignatureBridge: Not valid sig from governor"); + _; + } - /** + /** Verifying batch signatures from a governor over some datahash */ - modifier batchSignedByGovernor(bytes[] memory data, bytes[] memory sig) { - require(data.length == sig.length, "SignatureBridge: Data and sig lengths must match"); - for (uint256 i = 0; i < data.length; i++) { - require(isSignatureFromGovernor(data[i], sig[i]), "SignatureBridge: Not valid sig from governor"); - } - _; - } + modifier batchSignedByGovernor(bytes[] memory data, bytes[] memory sig) { + require(data.length == sig.length, "SignatureBridge: Data and sig lengths must match"); + for (uint256 i = 0; i < data.length; i++) { + require( + isSignatureFromGovernor(data[i], sig[i]), + "SignatureBridge: Not valid sig from governor" + ); + } + _; + } - /** + /** @notice Initializes SignatureBridge with a governor @param initialGovernor Addresses that should be initially granted the relayer role. */ - constructor (address initialGovernor, uint32 nonce) Governable(initialGovernor, nonce) {} + constructor(address initialGovernor, uint32 nonce) Governable(initialGovernor, nonce) {} - /** + /** @notice Sets a new resource for handler contracts that use the IExecutor interface, and maps the {handlerAddress} to {newResourceID} in {_resourceIDToHandlerAddress}. @notice Only callable by an address that currently has the admin role. @@ -56,78 +59,95 @@ contract SignatureBridge is Pausable, Governable, ChainIdWithType, ProposalNonce @param handlerAddress Address of handler resource will be set for. @param sig The signature from the governor of the encoded set resource proposal. */ - function adminSetResourceWithSignature( - bytes32 resourceID, - bytes4 functionSig, - uint32 nonce, - bytes32 newResourceID, - address handlerAddress, - bytes memory sig - ) external onlyIncrementingByOne(nonce) signedByGovernor( - abi.encodePacked( - resourceID, - functionSig, - nonce, - newResourceID, - handlerAddress - ), sig) - { - require(this.isCorrectExecutionChain(resourceID), "adminSetResourceWithSignature: Executing on wrong chain"); - require(this.isCorrectExecutionChain(newResourceID), "adminSetResourceWithSignature: Executing on wrong chain"); - require(this.isCorrectExecutionContext(resourceID), "adminSetResourceWithSignature: Invalid execution context"); - require( - functionSig == bytes4(keccak256( - "adminSetResourceWithSignature(bytes32,bytes4,uint32,bytes32,address,bytes)" - )), - "adminSetResourceWithSignature: Invalid function signature" - ); - _resourceIDToHandlerAddress[newResourceID] = handlerAddress; - IExecutor handler = IExecutor(handlerAddress); - address executionContext = address(bytes20(newResourceID << (6 * 8))); - handler.setResource(newResourceID, executionContext); - } + function adminSetResourceWithSignature( + bytes32 resourceID, + bytes4 functionSig, + uint32 nonce, + bytes32 newResourceID, + address handlerAddress, + bytes memory sig + ) + external + onlyIncrementingByOne(nonce) + signedByGovernor( + abi.encodePacked(resourceID, functionSig, nonce, newResourceID, handlerAddress), + sig + ) + { + require( + this.isCorrectExecutionChain(resourceID), + "adminSetResourceWithSignature: Executing on wrong chain" + ); + require( + this.isCorrectExecutionChain(newResourceID), + "adminSetResourceWithSignature: Executing on wrong chain" + ); + require( + this.isCorrectExecutionContext(resourceID), + "adminSetResourceWithSignature: Invalid execution context" + ); + require( + functionSig == + bytes4( + keccak256( + "adminSetResourceWithSignature(bytes32,bytes4,uint32,bytes32,address,bytes)" + ) + ), + "adminSetResourceWithSignature: Invalid function signature" + ); + _resourceIDToHandlerAddress[newResourceID] = handlerAddress; + IExecutor handler = IExecutor(handlerAddress); + address executionContext = address(bytes20(newResourceID << (6 * 8))); + handler.setResource(newResourceID, executionContext); + } - /** + /** @notice Executes a proposal signed by the governor. @param data Data meant for execution by execution handlers. */ - function executeProposalWithSignature( - bytes calldata data, - bytes memory sig - ) external signedByGovernor(data, sig) { - // Parse resourceID from the data - bytes32 resourceID = bytes32(data[0:32]); - require(this.isCorrectExecutionChain(resourceID), "SignatureBridge: Executing on wrong chain"); - address handler = _resourceIDToHandlerAddress[resourceID]; - IExecutor executionHandler = IExecutor(handler); - executionHandler.executeProposal(resourceID, data); - } + function executeProposalWithSignature( + bytes calldata data, + bytes memory sig + ) external signedByGovernor(data, sig) { + // Parse resourceID from the data + bytes32 resourceID = bytes32(data[0:32]); + require( + this.isCorrectExecutionChain(resourceID), + "SignatureBridge: Executing on wrong chain" + ); + address handler = _resourceIDToHandlerAddress[resourceID]; + IExecutor executionHandler = IExecutor(handler); + executionHandler.executeProposal(resourceID, data); + } - /** + /** @notice Executes a batch of proposals signed by the governor. @param data Data meant for execution by execution handlers. */ - function batchExecuteProposalWithSignature( - bytes[] calldata data, - bytes[] memory sig - ) external batchSignedByGovernor(data, sig) { - for (uint256 i = 0; i < data.length; i++) { - // Parse resourceID from the data - bytes32 resourceID = bytes32(data[i][0:32]); - require(this.isCorrectExecutionChain(resourceID), "SignatureBridge: Batch Executing on wrong chain"); - address handler = _resourceIDToHandlerAddress[resourceID]; - IExecutor executionHandler = IExecutor(handler); - executionHandler.executeProposal(resourceID, data[i]); - } - } + function batchExecuteProposalWithSignature( + bytes[] calldata data, + bytes[] memory sig + ) external batchSignedByGovernor(data, sig) { + for (uint256 i = 0; i < data.length; i++) { + // Parse resourceID from the data + bytes32 resourceID = bytes32(data[i][0:32]); + require( + this.isCorrectExecutionChain(resourceID), + "SignatureBridge: Batch Executing on wrong chain" + ); + address handler = _resourceIDToHandlerAddress[resourceID]; + IExecutor executionHandler = IExecutor(handler); + executionHandler.executeProposal(resourceID, data[i]); + } + } - function isCorrectExecutionChain(bytes32 resourceID) external view returns (bool) { - uint64 executionChainId = parseChainIdFromResourceId(resourceID); - // Verify current chain matches chain ID from resource ID - return uint256(getChainIdType()) == uint256(executionChainId); - } + function isCorrectExecutionChain(bytes32 resourceID) external view returns (bool) { + uint64 executionChainId = parseChainIdFromResourceId(resourceID); + // Verify current chain matches chain ID from resource ID + return uint256(getChainIdType()) == uint256(executionChainId); + } - function isCorrectExecutionContext(bytes32 resourceId) public view returns (bool) { - return address(bytes20(resourceId << (6 * 8))) == address(this); - } + function isCorrectExecutionContext(bytes32 resourceId) public view returns (bool) { + return address(bytes20(resourceId << (6 * 8))) == address(this); + } } diff --git a/packages/contracts/contracts/Treasury.sol b/packages/contracts/contracts/Treasury.sol index d7c17d06e..94cdd653b 100644 --- a/packages/contracts/contracts/Treasury.sol +++ b/packages/contracts/contracts/Treasury.sol @@ -11,53 +11,52 @@ import "./interfaces/ITreasury.sol"; import "./utils/ProposalNonceTracker.sol"; contract Treasury is ITreasury, ProposalNonceTracker { - address treasuryHandler; - - constructor (address _treasuryHandler) { - treasuryHandler = _treasuryHandler; - } - - modifier onlyHandler() { - require(msg.sender == treasuryHandler, "Function can only be called by treasury handler"); - _; - } - - function rescueTokens( - address tokenAddress, - address payable to, - uint256 amountToRescue, - uint32 nonce - ) external override onlyHandler onlyIncrementingByOne(nonce) { - require(to != address(0), "Cannot send liquidity to zero address"); - require(tokenAddress != address(this), "Cannot rescue wrapped asset"); - - if (tokenAddress == address(0)) { - // Native Ether - uint256 ethBalance = address(this).balance; - if(ethBalance >= amountToRescue) { - to.transfer(amountToRescue); - } else { - to.transfer(ethBalance); - } - - } else { - // ERC20 Token - uint256 erc20Balance = IERC20(tokenAddress).balanceOf(address(this)); - if(erc20Balance >= amountToRescue) { - IERC20(tokenAddress).transfer(to, amountToRescue); - } else { - IERC20(tokenAddress).transfer(to, erc20Balance); - } - } - } - - function setHandler( - address newHandler, - uint32 nonce - ) onlyHandler onlyIncrementingByOne(nonce) override external { - require(newHandler != address(0), "Handler cannot be 0"); - treasuryHandler = newHandler; - } - - receive() external payable {} + address treasuryHandler; + + constructor(address _treasuryHandler) { + treasuryHandler = _treasuryHandler; + } + + modifier onlyHandler() { + require(msg.sender == treasuryHandler, "Function can only be called by treasury handler"); + _; + } + + function rescueTokens( + address tokenAddress, + address payable to, + uint256 amountToRescue, + uint32 nonce + ) external override onlyHandler onlyIncrementingByOne(nonce) { + require(to != address(0), "Cannot send liquidity to zero address"); + require(tokenAddress != address(this), "Cannot rescue wrapped asset"); + + if (tokenAddress == address(0)) { + // Native Ether + uint256 ethBalance = address(this).balance; + if (ethBalance >= amountToRescue) { + to.transfer(amountToRescue); + } else { + to.transfer(ethBalance); + } + } else { + // ERC20 Token + uint256 erc20Balance = IERC20(tokenAddress).balanceOf(address(this)); + if (erc20Balance >= amountToRescue) { + IERC20(tokenAddress).transfer(to, amountToRescue); + } else { + IERC20(tokenAddress).transfer(to, erc20Balance); + } + } + } + + function setHandler( + address newHandler, + uint32 nonce + ) external override onlyHandler onlyIncrementingByOne(nonce) { + require(newHandler != address(0), "Handler cannot be 0"); + treasuryHandler = newHandler; + } + + receive() external payable {} } diff --git a/packages/contracts/contracts/anchors/AnchorBase.sol b/packages/contracts/contracts/anchors/AnchorBase.sol deleted file mode 100644 index c1ca53137..000000000 --- a/packages/contracts/contracts/anchors/AnchorBase.sol +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../trees/MerkleTree.sol"; -import "./LinkableAnchor.sol"; - -/** - @title AnchorBase contract - @notice Base contract for interoperable anchors. Each anchor base - is a LinkableAnchor which allows it to be connected to other LinkableAnchors. - */ -abstract contract AnchorBase is LinkableAnchor { - // map to store used nullifier hashes - mapping(bytes32 => bool) public nullifierHashes; - // map to store all commitments to prevent accidental deposits with the same commitment - mapping(bytes32 => bool) public commitments; - - event Insertion(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp); - - /** - @notice The constructor - @param _handler The address of AnchorHandler for this contract - @param _hasher The address of hash contract - @param _merkleTreeHeight The height of deposits' Merkle Tree - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - address _handler, - IHasher _hasher, - uint32 _merkleTreeHeight, - uint8 _maxEdges - ) LinkableAnchor(_handler, _hasher, _merkleTreeHeight, _maxEdges) {} - - /** - @notice Inserts a commitment into the tree - @notice This is an internal function and meant to be used by a child contract. - @param _commitment The note commitment = Poseidon(chainId, nullifier, secret) - @return uint32 The index of the inserted commitment - */ - function insert(bytes32 _commitment) internal returns(uint32) { - require(!commitments[_commitment], "The commitment has been submitted"); - - uint32 insertedIndex = _insert(_commitment); - commitments[_commitment] = true; - emit Insertion(_commitment, insertedIndex, block.timestamp); - - return insertedIndex; - } - - /** - @notice Inserts two commitments into the tree. Useful for contracts - that need to insert two commitments at once. - @notice This is an internal function and meant to be used by a child contract. - @param _firstCommitment The first note commitment - @param _secondCommitment The second note commitment - @return uint32 The index of the first inserted commitment - */ - function insertTwo(bytes32 _firstCommitment, bytes32 _secondCommitment) internal returns(uint32) { - require(!commitments[_firstCommitment], "The commitment has been submitted"); - require(!commitments[_secondCommitment], "The commitment has been submitted"); - - uint32 insertedIndex = _insertTwo(_firstCommitment, _secondCommitment); - commitments[_firstCommitment] = true; - commitments[_secondCommitment] = true; - emit Insertion(_firstCommitment, insertedIndex, block.timestamp); - emit Insertion(_secondCommitment, insertedIndex + 1, block.timestamp); - - return insertedIndex; - } - - /** - @notice Whether a note is already spent - @param _nullifierHash The nullifier hash of the deposit note - @return bool Whether the note is already spent - */ - function isSpent(bytes32 _nullifierHash) public view returns (bool) { - return nullifierHashes[_nullifierHash]; - } - - /** - @notice Whether an array of notes is already spent - @param _nullifierHashes The array of nullifier hashes of the deposit notes - @return bool[] An array indicated whether each note's nullifier hash is already spent - */ - function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns (bool[] memory) { - bool[] memory spent = new bool[](_nullifierHashes.length); - for (uint256 i = 0; i < _nullifierHashes.length; i++) { - if (isSpent(_nullifierHashes[i])) { - spent[i] = true; - } - } - - return spent; - } - - /** - @notice Set a new handler with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _handler The new handler address - @param _nonce The nonce for updating the new handler - */ - function setHandler( - address _handler, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_handler != address(0), "Handler cannot be 0"); - handler = _handler; - } -} diff --git a/packages/contracts/contracts/anchors/AnchorForest.sol b/packages/contracts/contracts/anchors/AnchorForest.sol deleted file mode 100644 index 1003f27fc..000000000 --- a/packages/contracts/contracts/anchors/AnchorForest.sol +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../trees/MerkleTree.sol"; -import "./LinkableAnchorForest.sol"; -import "hardhat/console.sol"; - -/** - @title AnchorBase contract - @notice Base contract for interoperable anchors. Each anchor base - is a LinkableAnchor which allows it to be connected to other LinkableAnchors. - */ -abstract contract AnchorForest is LinkableAnchorForest { - // map to store used nullifier hashes - mapping(bytes32 => bool) public nullifierHashes; - // map to store all commitments to prevent accidental deposits with the same commitment - mapping(bytes32 => bool) public commitments; - - event Insertion(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp); - - /** - @notice The constructor - @param _handler The address of AnchorHandler for this contract - @param _hasher The address of hash contract - @param _merkleTreeHeight The height of deposits' Merkle Tree - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - address _handler, - IHasher _hasher, - uint32 _forestHeight, - uint32 _merkleTreeHeight, - uint8 _maxEdges - ) LinkableAnchorForest(_handler, _hasher, _forestHeight, _merkleTreeHeight, _maxEdges) {} - - /** - @notice Inserts two commitments into the tree. Useful for contracts - that need to insert two commitments at once. - @notice This is an internal function and meant to be used by a child contract. - @param _firstCommitment The first note commitment - @param _secondCommitment The second note commitment - @return uint32 The index of the first inserted commitment - */ - function insertTwo(bytes32 _firstCommitment, bytes32 _secondCommitment) internal returns(uint32) { - require(!commitments[_firstCommitment], "The commitment has been submitted"); - require(!commitments[_secondCommitment], "The commitment has been submitted"); - uint32 insertedIndex = _insertTwo(_firstCommitment, _secondCommitment); - commitments[_firstCommitment] = true; - commitments[_secondCommitment] = true; - emit Insertion(_firstCommitment, insertedIndex, block.timestamp); - emit Insertion(_secondCommitment, insertedIndex + 1, block.timestamp); - - return insertedIndex; - } - - /** - @notice Whether a note is already spent - @param _nullifierHash The nullifier hash of the deposit note - @return bool Whether the note is already spent - */ - function isSpent(bytes32 _nullifierHash) public view returns (bool) { - return nullifierHashes[_nullifierHash]; - } - - /** - @notice Whether an array of notes is already spent - @param _nullifierHashes The array of nullifier hashes of the deposit notes - @return bool[] An array indicated whether each note's nullifier hash is already spent - */ - function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns (bool[] memory) { - bool[] memory spent = new bool[](_nullifierHashes.length); - for (uint256 i = 0; i < _nullifierHashes.length; i++) { - if (isSpent(_nullifierHashes[i])) { - spent[i] = true; - } - } - - return spent; - } - - /** - @notice Set a new handler with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _handler The new handler address - @param _nonce The nonce for updating the new handler - */ - function setHandler( - address _handler, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_handler != address(0), "Handler cannot be 0"); - handler = _handler; - } -} diff --git a/packages/contracts/contracts/anchors/LinkableAnchor.sol b/packages/contracts/contracts/anchors/LinkableAnchor.sol index ac6a19ac0..20b1a764b 100644 --- a/packages/contracts/contracts/anchors/LinkableAnchor.sol +++ b/packages/contracts/contracts/anchors/LinkableAnchor.sol @@ -6,12 +6,12 @@ pragma solidity ^0.8.0; import "../structs/Edge.sol"; -import "../trees/MerkleTree.sol"; +import "../hashers/IHasher.sol"; import "../utils/ChainIdWithType.sol"; import "../utils/ProposalNonceTracker.sol"; import "../interfaces/anchors/ILinkableAnchor.sol"; +import "../interfaces/IMerkleSystem.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import "hardhat/console.sol"; /** @title The LinkableAnchor contract @@ -39,201 +39,219 @@ import "hardhat/console.sol"; An example usage of this system is the: - VAnchor.sol - for variable sized private bridging of assets */ -abstract contract LinkableAnchor is ILinkableAnchor, MerkleTree, ReentrancyGuard, ChainIdWithType, ProposalNonceTracker { - address public handler; +abstract contract LinkableAnchor is + ILinkableAnchor, + MerkleSystem, + ReentrancyGuard, + ChainIdWithType, + ProposalNonceTracker +{ + address public handler; - // The maximum number of edges this tree can support for zero-knowledge linkability. - uint8 public immutable maxEdges; + // The maximum number of edges this tree can support for zero-knowledge linkability. + uint8 public immutable maxEdges; + uint32 public immutable outerLevels; - // Maps sourceChainID to the index in the edge list - mapping(uint256 => uint256) public edgeIndex; - mapping(uint256 => bool) public edgeExistsForChain; - Edge[] public edgeList; + // Maps sourceChainID to the index in the edge list + mapping(uint256 => uint256) public edgeIndex; + mapping(uint256 => bool) public edgeExistsForChain; + Edge[] public edgeList; - // Map to store chainID => (rootIndex => root) to track neighbor histories - mapping(uint256 => mapping(uint32 => bytes32)) public neighborRoots; - // Map to store the current historical root index for a chainID - mapping(uint256 => uint32) public currentNeighborRootIndex; + // Map to store chainID => (rootIndex => root) to track neighbor histories + mapping(uint256 => mapping(uint32 => uint256)) public neighborRoots; + // Map to store the current historical root index for a chainID + mapping(uint256 => uint32) public currentNeighborRootIndex; - // Edge linking events - event EdgeAddition(uint256 chainID, uint256 latestLeafIndex, bytes32 merkleRoot); - event EdgeUpdate(uint256 chainID, uint256 latestLeafIndex, bytes32 merkleRoot); + // Edge linking events + event EdgeAddition(uint256 chainID, uint256 latestLeafIndex, uint256 merkleRoot); + event EdgeUpdate(uint256 chainID, uint256 latestLeafIndex, uint256 merkleRoot); - /** + /** @notice The LinkableAnchor constructor @param _handler The address of the `AnchorHandler` contract - @param _hasher The address of hash contract - @param _merkleTreeHeight The height of deposits' Merkle Tree + @param _outerTreeHeight The height of outer-most merkle tree @param _maxEdges The maximum # of edges this linkable tree connects to */ - constructor( - address _handler, - IHasher _hasher, - uint32 _merkleTreeHeight, - uint8 _maxEdges - ) MerkleTree(_merkleTreeHeight, _hasher) { - handler = _handler; - maxEdges = _maxEdges; - } - - /** + constructor(address _handler, uint32 _outerTreeHeight, uint8 _maxEdges) { + handler = _handler; + outerLevels = _outerTreeHeight; + maxEdges = _maxEdges; + } + + /** @notice Add an edge to the tree or update an existing edge. @param _root The merkle root of the edge's merkle tree @param _leafIndex The latest leaf insertion index of the edge's merkle tree @param _srcResourceID The origin resource ID of the originating linked anchor update */ - function updateEdge( - bytes32 _root, - uint32 _leafIndex, - bytes32 _srcResourceID - ) override onlyHandler external payable nonReentrant { - uint64 _srcChainID = parseChainIdFromResourceId(_srcResourceID); - if (this.hasEdge(_srcChainID)) { - // Require increasing nonce - require(edgeList[edgeIndex[_srcChainID]].latestLeafIndex < _leafIndex, "New leaf index must be greater"); - // Require leaf index increase is bounded by 65,536 updates at once - require(_leafIndex < edgeList[edgeIndex[_srcChainID]].latestLeafIndex + (65_536), "New leaf index must within 2^16 updates"); - require(_srcResourceID == edgeList[edgeIndex[_srcChainID]].srcResourceID, "srcResourceID must be the same"); - uint index = edgeIndex[_srcChainID]; - // update the edge in the edge list - edgeList[index].latestLeafIndex = _leafIndex; - edgeList[index].root = _root; - // add to root histories - uint32 neighborRootIndex = (currentNeighborRootIndex[_srcChainID] + 1) % ROOT_HISTORY_SIZE; - currentNeighborRootIndex[_srcChainID] = neighborRootIndex; - neighborRoots[_srcChainID][neighborRootIndex] = _root; - emit EdgeUpdate(_srcChainID, _leafIndex, _root); - } else { - //Add Edge - require(edgeList.length < maxEdges, "This Anchor is at capacity"); - edgeExistsForChain[_srcChainID] = true; - uint index = edgeList.length; - Edge memory edge = Edge({ - chainID: _srcChainID, - root: _root, - latestLeafIndex: _leafIndex, - srcResourceID: _srcResourceID - }); - edgeList.push(edge); - edgeIndex[_srcChainID] = index; - // add to root histories - uint32 neighborRootIndex = 0; - neighborRoots[_srcChainID][neighborRootIndex] = _root; - emit EdgeAddition(_srcChainID, _leafIndex, _root); - } - } - - /** + function updateEdge( + uint256 _root, + uint32 _leafIndex, + bytes32 _srcResourceID + ) external payable override onlyHandler onlyInitialized nonReentrant { + uint64 _srcChainID = parseChainIdFromResourceId(_srcResourceID); + if (this.hasEdge(_srcChainID)) { + // Require increasing nonce + require( + edgeList[edgeIndex[_srcChainID]].latestLeafIndex < _leafIndex, + "New leaf index must be greater" + ); + // Require leaf index increase is bounded by 65,536 updates at once + require( + _leafIndex < edgeList[edgeIndex[_srcChainID]].latestLeafIndex + (65_536), + "New leaf index must within 2^16 updates" + ); + require( + _srcResourceID == edgeList[edgeIndex[_srcChainID]].srcResourceID, + "srcResourceID must be the same" + ); + uint index = edgeIndex[_srcChainID]; + // update the edge in the edge list + edgeList[index].latestLeafIndex = _leafIndex; + edgeList[index].root = uint256(_root); + // add to root histories + uint32 neighborRootIndex = (currentNeighborRootIndex[_srcChainID] + 1) % + ROOT_HISTORY_SIZE; + currentNeighborRootIndex[_srcChainID] = neighborRootIndex; + neighborRoots[_srcChainID][neighborRootIndex] = _root; + emit EdgeUpdate(_srcChainID, _leafIndex, _root); + } else { + //Add Edge + require(edgeList.length < maxEdges, "This Anchor is at capacity"); + edgeExistsForChain[_srcChainID] = true; + uint index = edgeList.length; + Edge memory edge = Edge({ + chainID: _srcChainID, + root: uint256(_root), + latestLeafIndex: _leafIndex, + srcResourceID: _srcResourceID + }); + edgeList.push(edge); + edgeIndex[_srcChainID] = index; + // add to root histories + uint32 neighborRootIndex = 0; + neighborRoots[_srcChainID][neighborRootIndex] = _root; + emit EdgeAddition(_srcChainID, _leafIndex, _root); + } + } + + /** @notice Get the latest state of all neighbor edges @return Edge[] An array of all neighboring and potentially empty edges */ - function getLatestNeighborEdges() public view returns (Edge[] memory) { - Edge[] memory edges = new Edge[](maxEdges); - for (uint256 i = 0; i < maxEdges; i++) { - if (edgeList.length >= i + 1) { - edges[i] = edgeList[i]; - } else { - edges[i] = Edge({ - // merkle tree height for zeros - root: hasher.zeros(levels - 1), - chainID: 0, - latestLeafIndex: 0, - srcResourceID: 0x0 - }); - } - } - - return edges; - } - - /** + function getLatestNeighborEdges() public view returns (Edge[] memory) { + Edge[] memory edges = new Edge[](maxEdges); + for (uint256 i = 0; i < maxEdges; i++) { + if (edgeList.length >= i + 1) { + edges[i] = edgeList[i]; + } else { + edges[i] = Edge({ + // merkle tree height for zeros + root: this.getZeroHash(outerLevels - 1), + chainID: 0, + latestLeafIndex: 0, + srcResourceID: 0x0 + }); + } + } + + return edges; + } + + /** @notice Get the latest merkle roots of all neighbor edges @return bytes32[] An array of merkle roots */ - function getLatestNeighborRoots() public view returns (bytes32[] memory) { - bytes32[] memory roots = new bytes32[](maxEdges); - for (uint256 i = 0; i < maxEdges; i++) { - if (edgeList.length >= i + 1) { - roots[i] = edgeList[i].root; - } else { - // merkle tree height for zeros - roots[i] = hasher.zeros(levels - 1); - } - } - - return roots; - } - - /** + function getLatestNeighborRoots() public view returns (uint256[] memory) { + uint256[] memory roots = new uint256[](maxEdges); + for (uint256 i = 0; i < maxEdges; i++) { + if (edgeList.length >= i + 1) { + roots[i] = edgeList[i].root; + } else { + // merkle tree height for zeros + roots[i] = this.getZeroHash(outerLevels - 1); + } + } + + return roots; + } + + /** @notice Checks to see whether a `_root` is known for a neighboring `neighborChainID` @param _neighborChainID The chainID of the neighbor's edge @param _root The root to check */ - function isKnownNeighborRoot(uint256 _neighborChainID, bytes32 _root) public view returns (bool) { - if (_root == 0) { - return false; - } - uint32 _currentRootIndex = currentNeighborRootIndex[_neighborChainID]; - uint32 i = _currentRootIndex; - do { - if (_root == neighborRoots[_neighborChainID][i]) { - return true; - } - if (i == 0) { - i = ROOT_HISTORY_SIZE; - } - i--; - } while (i != _currentRootIndex); - return false; - } - - /** + function isKnownNeighborRoot( + uint256 _neighborChainID, + uint256 _root + ) public view returns (bool) { + if (_root == 0) { + return false; + } + uint32 _currentRootIndex = currentNeighborRootIndex[_neighborChainID]; + uint32 i = _currentRootIndex; + do { + if (_root == neighborRoots[_neighborChainID][i]) { + return true; + } + if (i == 0) { + i = ROOT_HISTORY_SIZE; + } + i--; + } while (i != _currentRootIndex); + return false; + } + + /** @notice Checks validity of an array of merkle roots in the history. The first root should always be the root of `this` underlying merkle tree and the remaining roots are of the neighboring roots in `edges. - @param _roots An array of bytes32 merkle roots to be checked against the history. + @param _roots An array of uint256 merkle roots to be checked against the history. */ - function isValidRoots(bytes32[] memory _roots) public view returns (bool) { - require(isKnownRoot(_roots[0]), "Cannot find your merkle root"); - require(_roots.length == maxEdges + 1, "Incorrect root array length"); - uint rootIndex = 1; - for (uint i = 0; i < edgeList.length; i++) { - Edge memory _edge = edgeList[i]; - require(isKnownNeighborRoot(_edge.chainID, _roots[i+1]), "Neighbor root not found"); - rootIndex++; - } - while (rootIndex != maxEdges + 1) { - require(_roots[rootIndex] == hasher.zeros(levels - 1), "non-existent edge is not set to the default root"); - rootIndex++; - } - return true; - } - - /** + function isValidRoots(uint256[] memory _roots) public view returns (bool) { + require(this.isKnownRoot(_roots[0]), "Cannot find your merkle root"); + require(_roots.length == maxEdges + 1, "Incorrect root array length"); + uint rootIndex = 1; + for (uint i = 0; i < edgeList.length; i++) { + Edge memory _edge = edgeList[i]; + require(isKnownNeighborRoot(_edge.chainID, _roots[i + 1]), "Neighbor root not found"); + rootIndex++; + } + while (rootIndex != maxEdges + 1) { + require( + _roots[rootIndex] == this.getZeroHash(outerLevels - 1), + "non-existent edge is not set to the default root" + ); + rootIndex++; + } + return true; + } + + /** @notice Checks the sender is the AnchorHandler configured on this contract */ - modifier onlyHandler() { - require(msg.sender == handler, 'sender is not the handler'); - _; - } + modifier onlyHandler() { + require(msg.sender == handler, "sender is not the handler"); + _; + } - /** + /** @notice Checks the `_chainID` has an edge on this contract */ - function hasEdge(uint256 _chainID) external view returns (bool) { - return edgeExistsForChain[_chainID]; - } + function hasEdge(uint256 _chainID) external view returns (bool) { + return edgeExistsForChain[_chainID]; + } - /** + /** @notice Decodes a byte string of roots into its parts. @return bytes32[] An array of bytes32 merkle roots */ - function decodeRoots(bytes calldata roots) internal view returns (bytes32[] memory) { - bytes32[] memory decodedRoots = new bytes32[](maxEdges + 1); - for (uint i = 0; i <= maxEdges; i++) { - decodedRoots[i] = bytes32(roots[32*i : 32*(i+1)]); - } - - return decodedRoots; - } + function decodeRoots(bytes calldata roots) internal view returns (bytes32[] memory) { + bytes32[] memory decodedRoots = new bytes32[](maxEdges + 1); + for (uint i = 0; i <= maxEdges; i++) { + decodedRoots[i] = bytes32(roots[32 * i:32 * (i + 1)]); + } + + return decodedRoots; + } } diff --git a/packages/contracts/contracts/anchors/LinkableAnchorForest.sol b/packages/contracts/contracts/anchors/LinkableAnchorForest.sol deleted file mode 100644 index 0e61da46a..000000000 --- a/packages/contracts/contracts/anchors/LinkableAnchorForest.sol +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../trees/MerkleForest.sol"; -import "../utils/ChainIdWithType.sol"; -import "../utils/ProposalNonceTracker.sol"; -import "../interfaces/anchors/ILinkableAnchor.sol"; -import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; - -/** - @title The LinkableAnchor contract - @author Webb Technologies - @notice The LinkableAnchor contract extends the MerkleTreePoseidon contract - with a graph-like interface for linking to other LinkableAnchors. Links - between these trees are represented as directed edges (since updates occur - on one contract per transaction). The edge data is maintained as a record of the: - - Chain id that the edge points to - - Latest merkle root of the MerkleTreePoseidon contract being linked - - Latest leaf insertion index (used as a nonce) of the linked merkle tree. - - Updating the state of the LinkableAnchor's edges is done through the handler - architecture defined originally by ChainSafe's ChainBridge system. In our case, - we employ a handler to propagate updates to a LinkableAnchor contract. For example, - the handler can be connected to an oracle system, signature system, or any other - bridge system to provide the state of the neighboring LinkableAnchor's edge data. - - The LinkableAnchor contract is meant to be inherited by child contracts that - define their own architecture around: - 1. The structure of elements being inserted into the underlying Merkle Tree - 2. The type of zkSNARK necessary for proving membership of a specific element - in one-of-many LinkableAnchors connected in a bridge. - - An example usage of this system is the: - - VAnchor.sol - for variable sized private bridging of assets - */ -abstract contract LinkableAnchorForest is ILinkableAnchor, MerkleForest, ReentrancyGuard, ChainIdWithType, ProposalNonceTracker { - address public handler; - - // The maximum number of edges this tree can support for zero-knowledge linkability. - uint8 public immutable maxEdges; - uint32 public immutable forestDepth; - uint32 public immutable subtreeDepth; - uint32 internal constant ROOT_HISTORY_SIZE = 30; - - // Maps sourceChainID to the index in the edge list - mapping(uint256 => uint256) public edgeIndex; - mapping(uint256 => bool) public edgeExistsForChain; - Edge[] public edgeList; - - // Map to store chainID => (rootIndex => root) to track neighbor histories - mapping(uint256 => mapping(uint32 => bytes32)) public neighborRoots; - // Map to store the current historical root index for a chainID - mapping(uint256 => uint32) public currentNeighborRootIndex; - - // Edge linking events - event EdgeAddition(uint256 chainID, uint256 latestLeafIndex, bytes32 merkleRoot); - event EdgeUpdate(uint256 chainID, uint256 latestLeafIndex, bytes32 merkleRoot); - - /** - @notice The LinkableAnchor constructor - @param _handler The address of the `AnchorHandler` contract - @param _hasher The address of hash contract - @param _subtreeHeight The height of deposits' Merkle Tree - @param _maxEdges The maximum # of edges this linkable tree connects to - */ - constructor( - address _handler, - IHasher _hasher, - uint32 _forestHeight, - uint32 _subtreeHeight, - uint8 _maxEdges - ) MerkleForest(_forestHeight, _subtreeHeight, _hasher) { - handler = _handler; - maxEdges = _maxEdges; - forestDepth = _forestHeight; - subtreeDepth = _subtreeHeight; - } - - /** - @notice Add an edge to the tree or update an existing edge. - @param _root The merkle root of the edge's merkle tree - @param _leafIndex The latest leaf insertion index of the edge's merkle tree - @param _srcResourceID The origin resource ID of the originating linked anchor update - */ - function updateEdge( - bytes32 _root, - uint32 _leafIndex, - bytes32 _srcResourceID - ) override onlyHandler external payable nonReentrant { - uint64 _srcChainID = parseChainIdFromResourceId(_srcResourceID); - if (this.hasEdge(_srcChainID)) { - // Require increasing nonce - require(edgeList[edgeIndex[_srcChainID]].latestLeafIndex < _leafIndex, "New leaf index must be greater"); - // Require leaf index increase is bounded by 65,536 updates at once - require(_leafIndex < edgeList[edgeIndex[_srcChainID]].latestLeafIndex + (65_536), "New leaf index must within 2^16 updates"); - require(_srcResourceID == edgeList[edgeIndex[_srcChainID]].srcResourceID, "srcResourceID must be the same"); - uint index = edgeIndex[_srcChainID]; - // update the edge in the edge list - edgeList[index].latestLeafIndex = _leafIndex; - edgeList[index].root = uint(_root); - // add to root histories - uint32 neighborRootIndex = (currentNeighborRootIndex[_srcChainID] + 1) % ROOT_HISTORY_SIZE; - currentNeighborRootIndex[_srcChainID] = neighborRootIndex; - neighborRoots[_srcChainID][neighborRootIndex] = _root; - emit EdgeUpdate(_srcChainID, _leafIndex, _root); - } else { - //Add Edge - require(edgeList.length < maxEdges, "This Anchor is at capacity"); - edgeExistsForChain[_srcChainID] = true; - uint index = edgeList.length; - Edge memory edge = Edge({ - chainID: _srcChainID, - root: uint(_root), - latestLeafIndex: _leafIndex, - srcResourceID: _srcResourceID - }); - edgeList.push(edge); - edgeIndex[_srcChainID] = index; - // add to root histories - uint32 neighborRootIndex = 0; - neighborRoots[_srcChainID][neighborRootIndex] = _root; - emit EdgeAddition(_srcChainID, _leafIndex, _root); - } - } - - /** - @notice Get the latest state of all neighbor edges - @return Edge[] An array of all neighboring and potentially empty edges - */ - function getLatestNeighborEdges() public view returns (Edge[] memory) { - Edge[] memory edges = new Edge[](maxEdges); - for (uint256 i = 0; i < maxEdges; i++) { - if (edgeList.length >= i + 1) { - edges[i] = edgeList[i]; - } else { - edges[i] = Edge({ - // merkle tree height for zeros - root: uint(hasher.zeros(forestDepth - 1)), - chainID: 0, - latestLeafIndex: 0, - srcResourceID: 0x0 - }); - } - } - - return edges; - } - - /** - @notice Get the latest merkle roots of all neighbor edges - @return bytes32[] An array of merkle roots - */ - function getLatestNeighborRoots() public view returns (bytes32[] memory) { - bytes32[] memory roots = new bytes32[](maxEdges); - for (uint256 i = 0; i < maxEdges; i++) { - if (edgeList.length >= i + 1) { - roots[i] = bytes32(edgeList[i].root); - } else { - // merkle tree height for zeros - roots[i] = hasher.zeros(forestDepth - 1); - } - } - - return roots; - } - - /** - @notice Checks to see whether a `_root` is known for a neighboring `neighborChainID` - @param _neighborChainID The chainID of the neighbor's edge - @param _root The root to check - */ - function isKnownNeighborRoot(uint256 _neighborChainID, bytes32 _root) public view returns (bool) { - if (_root == 0) { - return false; - } - uint32 _currentRootIndex = currentNeighborRootIndex[_neighborChainID]; - uint32 i = _currentRootIndex; - do { - if (_root == neighborRoots[_neighborChainID][i]) { - return true; - } - if (i == 0) { - i = ROOT_HISTORY_SIZE; - } - i--; - } while (i != _currentRootIndex); - return false; - } - - /** - @notice Checks validity of an array of merkle roots in the history. - The first root should always be the root of `this` underlying merkle - tree and the remaining roots are of the neighboring roots in `edges. - @param _roots An array of bytes32 merkle roots to be checked against the history. - */ - function isValidRoots(bytes32[] memory _roots) public view returns (bool) { - require(isKnownRoot(uint(_roots[0])), "Cannot find your merkle root"); - require(_roots.length == maxEdges + 1, "Incorrect root array length"); - uint rootIndex = 1; - for (uint i = 0; i < edgeList.length; i++) { - Edge memory _edge = edgeList[i]; - require(isKnownNeighborRoot(_edge.chainID, _roots[i+1]), "Neighbor root not found"); - rootIndex++; - } - while (rootIndex != maxEdges + 1) { - require(_roots[rootIndex] == hasher.zeros(forestDepth - 1), "non-existent edge is not set to the default root"); - rootIndex++; - } - return true; - } - - /** - @notice Checks the sender is the AnchorHandler configured on this contract - */ - modifier onlyHandler() { - require(msg.sender == handler, 'sender is not the handler'); - _; - } - - /** - @notice Checks the `_chainID` has an edge on this contract - */ - function hasEdge(uint256 _chainID) external view returns (bool) { - return edgeExistsForChain[_chainID]; - } - - /** - @notice Decodes a byte string of roots into its parts. - @return bytes32[] An array of bytes32 merkle roots - */ - function decodeRoots(bytes calldata roots) internal view returns (bytes32[] memory) { - bytes32[] memory decodedRoots = new bytes32[](maxEdges + 1); - for (uint i = 0; i <= maxEdges; i++) { - decodedRoots[i] = bytes32(roots[32*i : 32*(i+1)]); - } - - return decodedRoots; - } -} diff --git a/packages/contracts/contracts/handlers/AnchorHandler.sol b/packages/contracts/contracts/handlers/AnchorHandler.sol index ebe94eb31..45ebef652 100644 --- a/packages/contracts/contracts/handlers/AnchorHandler.sol +++ b/packages/contracts/contracts/handlers/AnchorHandler.sol @@ -17,7 +17,7 @@ import "../interfaces/anchors/ILinkableAnchor.sol"; @notice This contract is intended to be used with the Bridge contract. */ contract AnchorHandler is IExecutor, HandlerHelpers { - /** + /** @param bridgeAddress Contract address of previously deployed Bridge. @param initialResourceIDs Resource IDs are used to identify a specific contract address. These are the Resource IDs this contract will initially support. @@ -26,62 +26,74 @@ contract AnchorHandler is IExecutor, HandlerHelpers { @dev {initialResourceIDs} and {initialContractAddresses} must have the same length (one resourceID for every address). Also, these arrays must be ordered in the way that {initialResourceIDs}[0] is the intended resourceID for {initialContractAddresses}[0]. */ - constructor( - address bridgeAddress, - bytes32[] memory initialResourceIDs, - address[] memory initialContractAddresses - ) { - require(initialResourceIDs.length == initialContractAddresses.length, - "initialResourceIDs and initialContractAddresses len mismatch"); + constructor( + address bridgeAddress, + bytes32[] memory initialResourceIDs, + address[] memory initialContractAddresses + ) { + require( + initialResourceIDs.length == initialContractAddresses.length, + "initialResourceIDs and initialContractAddresses len mismatch" + ); - _bridgeAddress = bridgeAddress; + _bridgeAddress = bridgeAddress; - for (uint256 i = 0; i < initialResourceIDs.length; i++) { - _setResource(initialResourceIDs[i], initialContractAddresses[i]); - } - } + for (uint256 i = 0; i < initialResourceIDs.length; i++) { + _setResource(initialResourceIDs[i], initialContractAddresses[i]); + } + } - /** + /** @notice Proposal execution should be initiated when a proposal is signed and executed by the `SignatureBridge` @param resourceID ResourceID corresponding to a particular executing anchor contract. @param data Consists of a specific proposal data structure for each finer-grained anchor proposal */ - function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { - bytes32 resourceId; - bytes4 functionSig; - bytes calldata arguments; + function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { + bytes32 resourceId; + bytes4 functionSig; + bytes calldata arguments; - resourceId = bytes32(data[0:32]); - functionSig = bytes4(data[32:36]); - arguments = data[36:]; + resourceId = bytes32(data[0:32]); + functionSig = bytes4(data[32:36]); + arguments = data[36:]; - address anchorAddress = _resourceIDToContractAddress[resourceID]; + address anchorAddress = _resourceIDToContractAddress[resourceID]; - require(_contractWhitelist[anchorAddress], "provided tokenAddress is not whitelisted"); + require(_contractWhitelist[anchorAddress], "provided tokenAddress is not whitelisted"); - if (functionSig == bytes4(keccak256("setHandler(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address newHandler = address(bytes20(arguments[4:24])); - ILinkableAnchor(anchorAddress).setHandler(newHandler, nonce); - } else if (functionSig == bytes4(keccak256("setVerifier(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address newVerifier = address(bytes20(arguments[4:24])); - ISetVerifier(anchorAddress).setVerifier(newVerifier, nonce); - } else if (functionSig == bytes4(keccak256("updateEdge(bytes32,uint32,bytes32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - bytes32 merkleRoot = bytes32(arguments[4:36]); - bytes32 target = bytes32(arguments[36:68]); - ILinkableAnchor(anchorAddress).updateEdge(merkleRoot, nonce, target); - } else if (functionSig == bytes4(keccak256("configureMinimalWithdrawalLimit(uint256,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - uint256 minimalWithdrawalAmount = uint256(bytes32(arguments[4:36])); - ILinkableAnchor(anchorAddress).configureMinimalWithdrawalLimit(minimalWithdrawalAmount, nonce); - } else if(functionSig == bytes4(keccak256("configureMaximumDepositLimit(uint256,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - uint256 maximumDepositAmount = uint256(bytes32(arguments[4:36])); - ILinkableAnchor(anchorAddress).configureMaximumDepositLimit(maximumDepositAmount, nonce); - } else { - revert("Invalid function sig"); - } - } + if (functionSig == bytes4(keccak256("setHandler(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address newHandler = address(bytes20(arguments[4:24])); + ILinkableAnchor(anchorAddress).setHandler(newHandler, nonce); + } else if (functionSig == bytes4(keccak256("setVerifier(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address newVerifier = address(bytes20(arguments[4:24])); + ISetVerifier(anchorAddress).setVerifier(newVerifier, nonce); + } else if (functionSig == bytes4(keccak256("updateEdge(bytes32,uint32,bytes32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + uint256 merkleRoot = uint256(bytes32(arguments[4:36])); + bytes32 target = bytes32(arguments[36:68]); + ILinkableAnchor(anchorAddress).updateEdge(merkleRoot, nonce, target); + } else if ( + functionSig == bytes4(keccak256("configureMinimalWithdrawalLimit(uint256,uint32)")) + ) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + uint256 minimalWithdrawalAmount = uint256(bytes32(arguments[4:36])); + ILinkableAnchor(anchorAddress).configureMinimalWithdrawalLimit( + minimalWithdrawalAmount, + nonce + ); + } else if ( + functionSig == bytes4(keccak256("configureMaximumDepositLimit(uint256,uint32)")) + ) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + uint256 maximumDepositAmount = uint256(bytes32(arguments[4:36])); + ILinkableAnchor(anchorAddress).configureMaximumDepositLimit( + maximumDepositAmount, + nonce + ); + } else { + revert("Invalid function sig"); + } + } } diff --git a/packages/contracts/contracts/handlers/HandlerHelpers.sol b/packages/contracts/contracts/handlers/HandlerHelpers.sol index 948b5b355..e205d3a0c 100644 --- a/packages/contracts/contracts/handlers/HandlerHelpers.sol +++ b/packages/contracts/contracts/handlers/HandlerHelpers.sol @@ -2,7 +2,7 @@ * Copyright 2021-2022 Webb Technologies * SPDX-License-Identifier: GPL-3.0-or-later-only */ - + pragma solidity ^0.8.0; import "../interfaces/IExecutor.sol"; @@ -13,27 +13,27 @@ import "../interfaces/IExecutor.sol"; @notice This contract is intended to be used with the Bridge contract. */ abstract contract HandlerHelpers is IExecutor { - address public _bridgeAddress; + address public _bridgeAddress; - // resourceID => token contract address - mapping (bytes32 => address) public _resourceIDToContractAddress; + // resourceID => token contract address + mapping(bytes32 => address) public _resourceIDToContractAddress; - // Execution contract address => resourceID - mapping (address => bytes32) public _contractAddressToResourceID; + // Execution contract address => resourceID + mapping(address => bytes32) public _contractAddressToResourceID; - // Execution contract address => is whitelisted - mapping (address => bool) public _contractWhitelist; + // Execution contract address => is whitelisted + mapping(address => bool) public _contractWhitelist; - modifier onlyBridge() { - _onlyBridge(); - _; - } + modifier onlyBridge() { + _onlyBridge(); + _; + } - function _onlyBridge() private view { - require(msg.sender == _bridgeAddress, "sender must be bridge contract"); - } + function _onlyBridge() private view { + require(msg.sender == _bridgeAddress, "sender must be bridge contract"); + } - /** + /** @notice First verifies {_resourceIDToContractAddress}[{resourceID}] and {_contractAddressToResourceID}[{contractAddress}] are not already set, then sets {_resourceIDToContractAddress} with {contractAddress}, @@ -42,18 +42,18 @@ abstract contract HandlerHelpers is IExecutor { @param resourceID ResourceID to be used when executing proposals. @param contractAddress Address of contract to be called when a proposal is signed and submitted for execution. */ - function setResource(bytes32 resourceID, address contractAddress) external override onlyBridge { - _setResource(resourceID, contractAddress); - } + function setResource(bytes32 resourceID, address contractAddress) external override onlyBridge { + _setResource(resourceID, contractAddress); + } - function _setResource(bytes32 resourceID, address contractAddress) internal { - _resourceIDToContractAddress[resourceID] = contractAddress; - _contractAddressToResourceID[contractAddress] = resourceID; + function _setResource(bytes32 resourceID, address contractAddress) internal { + _resourceIDToContractAddress[resourceID] = contractAddress; + _contractAddressToResourceID[contractAddress] = resourceID; - _contractWhitelist[contractAddress] = true; - } + _contractWhitelist[contractAddress] = true; + } - function migrateBridge(address newBridge) external override onlyBridge { - _bridgeAddress = newBridge; - } + function migrateBridge(address newBridge) external override onlyBridge { + _bridgeAddress = newBridge; + } } diff --git a/packages/contracts/contracts/handlers/RegistryHandler.sol b/packages/contracts/contracts/handlers/RegistryHandler.sol index 1e42568f1..87ff9c540 100644 --- a/packages/contracts/contracts/handlers/RegistryHandler.sol +++ b/packages/contracts/contracts/handlers/RegistryHandler.sol @@ -8,7 +8,7 @@ pragma experimental ABIEncoderV2; import "./HandlerHelpers.sol"; import "../interfaces/IExecutor.sol"; -import "../interfaces/tokens/IRegistry.sol"; +import "../interfaces/tokens/IRegistry.sol"; /** @title Handles Registry token registrations for ERC20 and NFT tokens @@ -16,7 +16,7 @@ import "../interfaces/tokens/IRegistry.sol"; @notice This contract is intended to be used with the Bridge and SignatureBridge contracts. */ contract RegistryHandler is IExecutor, HandlerHelpers { - /** + /** @param bridgeAddress Contract address of previously deployed Bridge. @param initialResourceIDs Resource IDs are used to identify a specific contract address. These are the Resource IDs this contract will initially support. @@ -25,81 +25,93 @@ contract RegistryHandler is IExecutor, HandlerHelpers { @dev {initialResourceIDs} and {initialContractAddresses} must have the same length (one resourceID for every address). Also, these arrays must be ordered in the way that {initialResourceIDs}[0] is the intended resourceID for {initialContractAddresses}[0]. */ - constructor( - address bridgeAddress, - bytes32[] memory initialResourceIDs, - address[] memory initialContractAddresses - ) { - require(initialResourceIDs.length == initialContractAddresses.length, - "initialResourceIDs and initialContractAddresses len mismatch"); + constructor( + address bridgeAddress, + bytes32[] memory initialResourceIDs, + address[] memory initialContractAddresses + ) { + require( + initialResourceIDs.length == initialContractAddresses.length, + "initialResourceIDs and initialContractAddresses len mismatch" + ); - _bridgeAddress = bridgeAddress; + _bridgeAddress = bridgeAddress; - for (uint256 i = 0; i < initialResourceIDs.length; i++) { - _setResource(initialResourceIDs[i], initialContractAddresses[i]); - } - } + for (uint256 i = 0; i < initialResourceIDs.length; i++) { + _setResource(initialResourceIDs[i], initialContractAddresses[i]); + } + } - /** + /** @notice Proposal execution should be initiated when a proposal is finalized in the Bridge contract. by a relayer on the deposit's destination chain. Or when a valid signature is produced by the DKG in the case of SignatureBridge. @param resourceID ResourceID corresponding to a particular set of FungibleTokenWrapper contracts @param data Consists of a specific proposal data structure for each finer-grained token wrapper proposal */ - function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { - bytes32 resourceId; - bytes4 functionSig; - bytes calldata arguments; - - resourceId = bytes32(data[0:32]); - functionSig = bytes4(data[32:36]); - arguments = data[36:]; - - address registryAddress = _resourceIDToContractAddress[resourceID]; - IRegistry registry = IRegistry(registryAddress); - - if (functionSig == bytes4(keccak256("registerToken(uint32,address,uint254,string,string,bytes32,uint256,uint16,bool)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address tokenHandler = address(bytes20(arguments[4:24])); - uint256 assetId = uint256(bytes32(arguments[24:56])); - bytes32 name = bytes32(arguments[56:88]); - bytes32 symbol = bytes32(arguments[88:120]); - bytes32 salt = bytes32(arguments[120:152]); - uint256 limit = uint256(bytes32(arguments[152:184])); - uint16 feePercentage = uint16(bytes2(arguments[184:186])); - bool isNativeAllowed = bytes1(arguments[186:187]) == 0x01; - registry.registerToken( - nonce, - tokenHandler, - assetId, - bytes32ToString(name), - bytes32ToString(symbol), - salt, - limit, - feePercentage, - isNativeAllowed - ); - } else if (functionSig == bytes4(keccak256("registerNftToken(uint32,address,uint254,string,bytes32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address tokenHandler = address(bytes20(arguments[4:24])); - uint256 assetId = uint256(bytes32(arguments[24:56])); - bytes32 salt = bytes32(arguments[56:88]); - bytes memory uri = bytes(arguments[88:]); - registry.registerNftToken(nonce, tokenHandler, assetId, string(uri), salt); - } else { - revert("Invalid function sig"); - } - } + function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { + bytes32 resourceId; + bytes4 functionSig; + bytes calldata arguments; - function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) { - uint8 i = 0; - while(i < 32 && _bytes32[i] != 0) { - i++; - } - bytes memory bytesArray = new bytes(i); - for (i = 0; i < 32 && _bytes32[i] != 0; i++) { - bytesArray[i] = _bytes32[i]; - } - return string(bytesArray); - } + resourceId = bytes32(data[0:32]); + functionSig = bytes4(data[32:36]); + arguments = data[36:]; + + address registryAddress = _resourceIDToContractAddress[resourceID]; + IRegistry registry = IRegistry(registryAddress); + + if ( + functionSig == + bytes4( + keccak256( + "registerToken(uint32,address,uint254,string,string,bytes32,uint256,uint16,bool)" + ) + ) + ) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address tokenHandler = address(bytes20(arguments[4:24])); + uint256 assetId = uint256(bytes32(arguments[24:56])); + bytes32 name = bytes32(arguments[56:88]); + bytes32 symbol = bytes32(arguments[88:120]); + bytes32 salt = bytes32(arguments[120:152]); + uint256 limit = uint256(bytes32(arguments[152:184])); + uint16 feePercentage = uint16(bytes2(arguments[184:186])); + bool isNativeAllowed = bytes1(arguments[186:187]) == 0x01; + registry.registerToken( + nonce, + tokenHandler, + assetId, + bytes32ToString(name), + bytes32ToString(symbol), + salt, + limit, + feePercentage, + isNativeAllowed + ); + } else if ( + functionSig == + bytes4(keccak256("registerNftToken(uint32,address,uint254,string,bytes32)")) + ) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address tokenHandler = address(bytes20(arguments[4:24])); + uint256 assetId = uint256(bytes32(arguments[24:56])); + bytes32 salt = bytes32(arguments[56:88]); + bytes memory uri = bytes(arguments[88:]); + registry.registerNftToken(nonce, tokenHandler, assetId, string(uri), salt); + } else { + revert("Invalid function sig"); + } + } + + function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) { + uint8 i = 0; + while (i < 32 && _bytes32[i] != 0) { + i++; + } + bytes memory bytesArray = new bytes(i); + for (i = 0; i < 32 && _bytes32[i] != 0; i++) { + bytesArray[i] = _bytes32[i]; + } + return string(bytesArray); + } } diff --git a/packages/contracts/contracts/handlers/TokenWrapperHandler.sol b/packages/contracts/contracts/handlers/TokenWrapperHandler.sol index 4da1a2408..ff13ded66 100644 --- a/packages/contracts/contracts/handlers/TokenWrapperHandler.sol +++ b/packages/contracts/contracts/handlers/TokenWrapperHandler.sol @@ -8,7 +8,7 @@ pragma experimental ABIEncoderV2; import "./HandlerHelpers.sol"; import "../interfaces/IExecutor.sol"; -import "../interfaces/tokens/IFungibleTokenWrapper.sol"; +import "../interfaces/tokens/IFungibleTokenWrapper.sol"; /** @title Handles FungibleTokenWrapper fee and token updates @@ -16,7 +16,7 @@ import "../interfaces/tokens/IFungibleTokenWrapper.sol"; @notice This contract is intended to be used with the Bridge and SignatureBridge contracts. */ contract TokenWrapperHandler is IExecutor, HandlerHelpers { - /** + /** @param bridgeAddress Contract address of previously deployed Bridge. @param initialResourceIDs Resource IDs are used to identify a specific contract address. These are the Resource IDs this contract will initially support. @@ -25,57 +25,59 @@ contract TokenWrapperHandler is IExecutor, HandlerHelpers { @dev {initialResourceIDs} and {initialContractAddresses} must have the same length (one resourceID for every address). Also, these arrays must be ordered in the way that {initialResourceIDs}[0] is the intended resourceID for {initialContractAddresses}[0]. */ - constructor( - address bridgeAddress, - bytes32[] memory initialResourceIDs, - address[] memory initialContractAddresses - ) { - require(initialResourceIDs.length == initialContractAddresses.length, - "initialResourceIDs and initialContractAddresses len mismatch"); + constructor( + address bridgeAddress, + bytes32[] memory initialResourceIDs, + address[] memory initialContractAddresses + ) { + require( + initialResourceIDs.length == initialContractAddresses.length, + "initialResourceIDs and initialContractAddresses len mismatch" + ); - _bridgeAddress = bridgeAddress; + _bridgeAddress = bridgeAddress; - for (uint256 i = 0; i < initialResourceIDs.length; i++) { - _setResource(initialResourceIDs[i], initialContractAddresses[i]); - } - } + for (uint256 i = 0; i < initialResourceIDs.length; i++) { + _setResource(initialResourceIDs[i], initialContractAddresses[i]); + } + } - /** + /** @notice Proposal execution should be initiated when a proposal is finalized in the Bridge contract. by a relayer on the deposit's destination chain. Or when a valid signature is produced by the DKG in the case of SignatureBridge. @param resourceID ResourceID corresponding to a particular set of FungibleTokenWrapper contracts @param data Consists of a specific proposal data structure for each finer-grained token wrapper proposal */ - function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { - bytes32 resourceId; - bytes4 functionSig; - bytes calldata arguments; - - resourceId = bytes32(data[0:32]); - functionSig = bytes4(data[32:36]); - arguments = data[36:]; - - address fungibleTokenAddress = _resourceIDToContractAddress[resourceID]; - IFungibleTokenWrapper fungibleToken = IFungibleTokenWrapper(fungibleTokenAddress); - - if (functionSig == bytes4(keccak256("setFee(uint16,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - uint16 newFee = uint16(bytes2(arguments[4:6])); - fungibleToken.setFee(newFee, nonce); - } else if (functionSig == bytes4(keccak256("add(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address tokenAddress = address(bytes20(arguments[4:24])); - fungibleToken.add(tokenAddress, nonce); - } else if (functionSig == bytes4(keccak256("remove(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address tokenAddress = address(bytes20(arguments[4:24])); - fungibleToken.remove(tokenAddress, nonce); - } else if (functionSig == bytes4(keccak256("setFeeRecipient(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address payable feeRecipient = payable(address(bytes20(arguments[4:24]))); - fungibleToken.setFeeRecipient(feeRecipient, nonce); - } else { - revert("Invalid function sig"); - } - } + function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { + bytes32 resourceId; + bytes4 functionSig; + bytes calldata arguments; + + resourceId = bytes32(data[0:32]); + functionSig = bytes4(data[32:36]); + arguments = data[36:]; + + address fungibleTokenAddress = _resourceIDToContractAddress[resourceID]; + IFungibleTokenWrapper fungibleToken = IFungibleTokenWrapper(fungibleTokenAddress); + + if (functionSig == bytes4(keccak256("setFee(uint16,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + uint16 newFee = uint16(bytes2(arguments[4:6])); + fungibleToken.setFee(newFee, nonce); + } else if (functionSig == bytes4(keccak256("add(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address tokenAddress = address(bytes20(arguments[4:24])); + fungibleToken.add(tokenAddress, nonce); + } else if (functionSig == bytes4(keccak256("remove(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address tokenAddress = address(bytes20(arguments[4:24])); + fungibleToken.remove(tokenAddress, nonce); + } else if (functionSig == bytes4(keccak256("setFeeRecipient(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address payable feeRecipient = payable(address(bytes20(arguments[4:24]))); + fungibleToken.setFeeRecipient(feeRecipient, nonce); + } else { + revert("Invalid function sig"); + } + } } diff --git a/packages/contracts/contracts/handlers/TreasuryHandler.sol b/packages/contracts/contracts/handlers/TreasuryHandler.sol index a1055ad2c..93dc05eb1 100644 --- a/packages/contracts/contracts/handlers/TreasuryHandler.sol +++ b/packages/contracts/contracts/handlers/TreasuryHandler.sol @@ -16,7 +16,7 @@ import "../interfaces/ITreasury.sol"; @notice This contract is intended to be used with the Bridge and SignatureBridge contracts. */ contract TreasuryHandler is IExecutor, HandlerHelpers { - /** + /** @param bridgeAddress Contract address of previously deployed Bridge. @param initialResourceIDs Resource IDs are used to identify a specific contract address. These are the Resource IDs this contract will initially support. @@ -25,22 +25,24 @@ contract TreasuryHandler is IExecutor, HandlerHelpers { @dev {initialResourceIDs} and {initialContractAddresses} must have the same length (one resourceID for every address). Also, these arrays must be ordered in the way that {initialResourceIDs}[0] is the intended resourceID for {initialContractAddresses}[0]. */ - constructor( - address bridgeAddress, - bytes32[] memory initialResourceIDs, - address[] memory initialContractAddresses - ) { - require(initialResourceIDs.length == initialContractAddresses.length, - "initialResourceIDs and initialContractAddresses len mismatch"); + constructor( + address bridgeAddress, + bytes32[] memory initialResourceIDs, + address[] memory initialContractAddresses + ) { + require( + initialResourceIDs.length == initialContractAddresses.length, + "initialResourceIDs and initialContractAddresses len mismatch" + ); - _bridgeAddress = bridgeAddress; + _bridgeAddress = bridgeAddress; - for (uint256 i = 0; i < initialResourceIDs.length; i++) { - _setResource(initialResourceIDs[i], initialContractAddresses[i]); - } - } + for (uint256 i = 0; i < initialResourceIDs.length; i++) { + _setResource(initialResourceIDs[i], initialContractAddresses[i]); + } + } - /** + /** @notice Proposal execution should be initiated when a proposal is finalized in the Bridge contract. by a relayer on the deposit's destination chain. Or when a valid signature is produced by the DKG in the case of SignatureBridge. @param resourceID ResourceID corresponding to a particular set of Treasury contracts @@ -50,31 +52,32 @@ contract TreasuryHandler is IExecutor, HandlerHelpers { arguments: bytes 36- First 4 bytes of argument is nonce. */ - function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { - bytes32 resourceId; - bytes4 functionSig; - bytes calldata arguments; - - resourceId = bytes32(data[0:32]); - functionSig = bytes4(data[32:36]); - arguments = data[36:]; - - address treasuryAddress = _resourceIDToContractAddress[resourceID]; - ITreasury treasury = ITreasury(treasuryAddress); - + function executeProposal(bytes32 resourceID, bytes calldata data) external override onlyBridge { + bytes32 resourceId; + bytes4 functionSig; + bytes calldata arguments; - if (functionSig == bytes4(keccak256("setHandler(address,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address newHandler = address(bytes20(arguments[4:24])); - treasury.setHandler(newHandler, nonce); - } else if (functionSig == bytes4(keccak256("rescueTokens(address,address,uint256,uint32)"))) { - uint32 nonce = uint32(bytes4(arguments[0:4])); - address tokenAddress = address(bytes20(arguments[4:24])); - address payable to = payable(address(bytes20(arguments[24:44]))); - uint256 amountToRescue = uint256(bytes32(arguments[44:76])); - treasury.rescueTokens(tokenAddress, to, amountToRescue, nonce); - } else { - revert("Invalid function sig"); - } - } + resourceId = bytes32(data[0:32]); + functionSig = bytes4(data[32:36]); + arguments = data[36:]; + + address treasuryAddress = _resourceIDToContractAddress[resourceID]; + ITreasury treasury = ITreasury(treasuryAddress); + + if (functionSig == bytes4(keccak256("setHandler(address,uint32)"))) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address newHandler = address(bytes20(arguments[4:24])); + treasury.setHandler(newHandler, nonce); + } else if ( + functionSig == bytes4(keccak256("rescueTokens(address,address,uint256,uint32)")) + ) { + uint32 nonce = uint32(bytes4(arguments[0:4])); + address tokenAddress = address(bytes20(arguments[4:24])); + address payable to = payable(address(bytes20(arguments[24:44]))); + uint256 amountToRescue = uint256(bytes32(arguments[44:76])); + treasury.rescueTokens(tokenAddress, to, amountToRescue, nonce); + } else { + revert("Invalid function sig"); + } + } } diff --git a/packages/contracts/contracts/hashers/IHasher.sol b/packages/contracts/contracts/hashers/IHasher.sol index 0a289371d..db254d8d1 100644 --- a/packages/contracts/contracts/hashers/IHasher.sol +++ b/packages/contracts/contracts/hashers/IHasher.sol @@ -9,9 +9,11 @@ pragma solidity ^0.8.0; * Hasher interface for hashing 2 uint256 elements. */ interface IHasher { - function hash3(uint256[3] memory array) external view returns (uint256); - /// @dev provides a 2 elemtns hash with left and right elements - function hashLeftRight(uint256 _left, uint256 _right) external view returns (uint256); - /// @dev provides Zero (Empty) elements for a IHasher based MerkleTree. Up to 32 levels - function zeros(uint256 i) external view returns (bytes32); + function hash3(uint256[3] memory array) external view returns (uint256); + + /// @dev provides a 2 elemtns hash with left and right elements + function hashLeftRight(uint256 _left, uint256 _right) external view returns (uint256); + + /// @dev provides Zero (Empty) elements for a IHasher based MerkleTree. Up to 32 levels + function zeros(uint256 i) external view returns (bytes32); } diff --git a/packages/contracts/contracts/hashers/KeccakHasher.sol b/packages/contracts/contracts/hashers/KeccakHasher.sol index 225fc3ad1..e959cc685 100644 --- a/packages/contracts/contracts/hashers/KeccakHasher.sol +++ b/packages/contracts/contracts/hashers/KeccakHasher.sol @@ -11,51 +11,83 @@ import "./IHasher.sol"; * Keccak hash functions for 2 inputs. */ contract KeccakHasher is IHasher { - function hash3(uint256[3] memory array) override public pure returns (uint256) { - return uint256(keccak256(abi.encodePacked(array))); - } + function hash3(uint256[3] memory array) public pure override returns (uint256) { + return uint256(keccak256(abi.encodePacked(array))); + } - function hashLeftRight(uint256 _left, uint256 _right) override public pure returns (uint256) { - uint256 output = uint256(_left); - uint256 right = uint256(_right); - output = uint256(keccak256(abi.encodePacked(output, right))); - return output; - } + function hashLeftRight(uint256 _left, uint256 _right) public pure override returns (uint256) { + uint256 output = uint256(_left); + uint256 right = uint256(_right); + output = uint256(keccak256(abi.encodePacked(output, right))); + return output; + } - /// @dev provides Zero (Empty) elements for a Poseidon MerkleTree. Up to 32 levels - function zeros(uint256 i) override public pure returns (bytes32) { - if (i == 0) return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c); - else if (i == 1) return bytes32(0x4fc2fe9184a25f44ce8ddb5f32671fcae6d9c85ed710c199acef16ad16b29911); - else if (i == 2) return bytes32(0x0d826a474f851c563052d929ef0daa70f658aba9ba084f51f6e3483c13c0e59a); - else if (i == 3) return bytes32(0xf7761a16b5e4c0120e4c5704b910dbe18ff6162a9668ed1c2c4efde7c4f15806); - else if (i == 4) return bytes32(0xce9ce09a0ab259d6d14ca3dcd74e6c6b9e7d9074bff66973d4c57ccdffdb2a82); - else if (i == 5) return bytes32(0x02efd44c63015ff1385344e0624867775486d05e6eb1290a24976964a598003b); - else if (i == 6) return bytes32(0xc4dec5845d407ce2ac2e6824bb7857c4b138f819e5789d5d11e812db10c846cd); - else if (i == 7) return bytes32(0x5fbe3f20c23f3bd6ac347917fb0903433e0b9a48373412348240a5f919bfde19); - else if (i == 8) return bytes32(0x92d1b07e56b3da96b7917778cb657f2c513eaeeb4d1579a73b5ea316f25b7289); - else if (i == 9) return bytes32(0xa08add5656d6d3d0827ef909f7647981eac42aa1f51970a752f130f718f6d76a); - else if (i == 10) return bytes32(0x1704c5f297590d8ec62776b0714f4f3f2234bae0524035342b0da8b8988ebd79); - else if (i == 11) return bytes32(0xc5ae2bd47379c2c6d1189cfc3d057948dc6054caf845fcacd8f7affe94b11944); - else if (i == 12) return bytes32(0x12a161d6d5561062f387d91ad9f0f8966c0956afdb9e8325458b9e5057b82bdb); - else if (i == 13) return bytes32(0x4ade524ba596de20bbe94507a761c45251ae7a27857ceb4287d9018525b99bc5); - else if (i == 14) return bytes32(0x38287ad69151fa833bf4bf8b8eb6ffb39400a38f1a7e53b473f639c8c60fd5e4); - else if (i == 15) return bytes32(0x57f2ade7d711707e785451f2aba6c95872c7fe03153a98b7327b4024e8068fa3); - else if (i == 16) return bytes32(0xb1982e0d1b0de46a88d8b17941472e41a86d3ff64571ed8e0ca72d58633547fc); - else if (i == 17) return bytes32(0xb7c60f8670af15eb32b4ee36727179bc085a3dde03d5f9a1486664ba576b30a6); - else if (i == 18) return bytes32(0x5ff905c5c659a926b132ef3665a3de5d5a859c1d479e68851085bfc0348c5331); - else if (i == 19) return bytes32(0xb4dfa78b912e98c9f7eb42d71eb537a02bf3173d44a2eb887a48b3972072dd8e); - else if (i == 20) return bytes32(0x60919a16a2eb8b91cfb8ba1e5b4c155a76a14c217b5403edbd563f34e508ecdc); - else if (i == 21) return bytes32(0x5fc8c1e9d260531cade53159072fe9f14921a9559e5222dca7e28d504ab3dd04); - else if (i == 22) return bytes32(0x7ef08ed4b30c17c851a892c539030a92e5319857aa0cd453330a31a0183ac975); - else if (i == 23) return bytes32(0x6420ebe493376e2596f8082f7902dd5c83af477fa9e5d52b74f0f7759e2a9068); - else if (i == 24) return bytes32(0x93766eb9a297fe6ca5c12f268f84999d275250c2408aaea8a0a66aa7aef520a9); - else if (i == 25) return bytes32(0x52b9d8e178f12c49cd409cffc0a54139816ad9de9261f49d75e0cca3c581fab8); - else if (i == 26) return bytes32(0x5191df2c0bd0f66075ef15f47daf661fab17bd7d9520e1b011c5f7cb17ac1c3c); - else if (i == 27) return bytes32(0xca95564bdcd199f493f50a366e5a1ba1d749f136e586c2e81127fa0bba6b3076); - else if (i == 28) return bytes32(0x6955b26d7325787f232d42480b9dce4241793c3fe249ea6fbe03c6a798b20512); - else if (i == 29) return bytes32(0x02fab0f86aba653fbd368bbee2baa6092199592c90397b8c4b414803910e2553); - else if (i == 30) return bytes32(0x3878a3ff0eda8bcd772059f6c38939e9b4888d7848b36e8645e3929e0ba2f974); - else if (i == 31) return bytes32(0x819bff9ae5cb51403b906d369e5a1bbd8b791c51f7c27d3be41f9271d9434af1); - else revert("Index out of bounds"); - } + /// @dev provides Zero (Empty) elements for a Poseidon MerkleTree. Up to 32 levels + function zeros(uint256 i) public pure override returns (bytes32) { + if (i == 0) + return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c); + else if (i == 1) + return bytes32(0x4fc2fe9184a25f44ce8ddb5f32671fcae6d9c85ed710c199acef16ad16b29911); + else if (i == 2) + return bytes32(0x0d826a474f851c563052d929ef0daa70f658aba9ba084f51f6e3483c13c0e59a); + else if (i == 3) + return bytes32(0xf7761a16b5e4c0120e4c5704b910dbe18ff6162a9668ed1c2c4efde7c4f15806); + else if (i == 4) + return bytes32(0xce9ce09a0ab259d6d14ca3dcd74e6c6b9e7d9074bff66973d4c57ccdffdb2a82); + else if (i == 5) + return bytes32(0x02efd44c63015ff1385344e0624867775486d05e6eb1290a24976964a598003b); + else if (i == 6) + return bytes32(0xc4dec5845d407ce2ac2e6824bb7857c4b138f819e5789d5d11e812db10c846cd); + else if (i == 7) + return bytes32(0x5fbe3f20c23f3bd6ac347917fb0903433e0b9a48373412348240a5f919bfde19); + else if (i == 8) + return bytes32(0x92d1b07e56b3da96b7917778cb657f2c513eaeeb4d1579a73b5ea316f25b7289); + else if (i == 9) + return bytes32(0xa08add5656d6d3d0827ef909f7647981eac42aa1f51970a752f130f718f6d76a); + else if (i == 10) + return bytes32(0x1704c5f297590d8ec62776b0714f4f3f2234bae0524035342b0da8b8988ebd79); + else if (i == 11) + return bytes32(0xc5ae2bd47379c2c6d1189cfc3d057948dc6054caf845fcacd8f7affe94b11944); + else if (i == 12) + return bytes32(0x12a161d6d5561062f387d91ad9f0f8966c0956afdb9e8325458b9e5057b82bdb); + else if (i == 13) + return bytes32(0x4ade524ba596de20bbe94507a761c45251ae7a27857ceb4287d9018525b99bc5); + else if (i == 14) + return bytes32(0x38287ad69151fa833bf4bf8b8eb6ffb39400a38f1a7e53b473f639c8c60fd5e4); + else if (i == 15) + return bytes32(0x57f2ade7d711707e785451f2aba6c95872c7fe03153a98b7327b4024e8068fa3); + else if (i == 16) + return bytes32(0xb1982e0d1b0de46a88d8b17941472e41a86d3ff64571ed8e0ca72d58633547fc); + else if (i == 17) + return bytes32(0xb7c60f8670af15eb32b4ee36727179bc085a3dde03d5f9a1486664ba576b30a6); + else if (i == 18) + return bytes32(0x5ff905c5c659a926b132ef3665a3de5d5a859c1d479e68851085bfc0348c5331); + else if (i == 19) + return bytes32(0xb4dfa78b912e98c9f7eb42d71eb537a02bf3173d44a2eb887a48b3972072dd8e); + else if (i == 20) + return bytes32(0x60919a16a2eb8b91cfb8ba1e5b4c155a76a14c217b5403edbd563f34e508ecdc); + else if (i == 21) + return bytes32(0x5fc8c1e9d260531cade53159072fe9f14921a9559e5222dca7e28d504ab3dd04); + else if (i == 22) + return bytes32(0x7ef08ed4b30c17c851a892c539030a92e5319857aa0cd453330a31a0183ac975); + else if (i == 23) + return bytes32(0x6420ebe493376e2596f8082f7902dd5c83af477fa9e5d52b74f0f7759e2a9068); + else if (i == 24) + return bytes32(0x93766eb9a297fe6ca5c12f268f84999d275250c2408aaea8a0a66aa7aef520a9); + else if (i == 25) + return bytes32(0x52b9d8e178f12c49cd409cffc0a54139816ad9de9261f49d75e0cca3c581fab8); + else if (i == 26) + return bytes32(0x5191df2c0bd0f66075ef15f47daf661fab17bd7d9520e1b011c5f7cb17ac1c3c); + else if (i == 27) + return bytes32(0xca95564bdcd199f493f50a366e5a1ba1d749f136e586c2e81127fa0bba6b3076); + else if (i == 28) + return bytes32(0x6955b26d7325787f232d42480b9dce4241793c3fe249ea6fbe03c6a798b20512); + else if (i == 29) + return bytes32(0x02fab0f86aba653fbd368bbee2baa6092199592c90397b8c4b414803910e2553); + else if (i == 30) + return bytes32(0x3878a3ff0eda8bcd772059f6c38939e9b4888d7848b36e8645e3929e0ba2f974); + else if (i == 31) + return bytes32(0x819bff9ae5cb51403b906d369e5a1bbd8b791c51f7c27d3be41f9271d9434af1); + else revert("Index out of bounds"); + } } diff --git a/packages/contracts/contracts/hashers/Poseidon.sol b/packages/contracts/contracts/hashers/Poseidon.sol index a7d221e47..edc4e808d 100644 --- a/packages/contracts/contracts/hashers/Poseidon.sol +++ b/packages/contracts/contracts/hashers/Poseidon.sol @@ -2,14 +2,13 @@ pragma solidity ^0.8.0; library PoseidonT3 { - function poseidon(uint256[2] memory input) public pure returns (uint256) {} + function poseidon(uint256[2] memory input) public pure returns (uint256) {} } library PoseidonT4 { - function poseidon(uint256[3] memory input) public pure returns (uint256) {} + function poseidon(uint256[3] memory input) public pure returns (uint256) {} } library PoseidonT6 { - function poseidon(uint256[5] memory input) public pure returns (uint256) {} + function poseidon(uint256[5] memory input) public pure returns (uint256) {} } - diff --git a/packages/contracts/contracts/hashers/PoseidonHasher.sol b/packages/contracts/contracts/hashers/PoseidonHasher.sol index 53b8fd1ec..42d7bd692 100644 --- a/packages/contracts/contracts/hashers/PoseidonHasher.sol +++ b/packages/contracts/contracts/hashers/PoseidonHasher.sol @@ -13,83 +13,115 @@ import { SnarkConstants } from "./SnarkConstants.sol"; * Poseidon hash functions for 2, 5, and 11 input elements. */ contract PoseidonHasher is SnarkConstants, IHasher { - function hash3(uint256[3] memory array) override public pure returns (uint256) { - return PoseidonT4.poseidon(array); - } + function hash3(uint256[3] memory array) public pure override returns (uint256) { + return PoseidonT4.poseidon(array); + } - function hash5(uint256[5] memory array) public pure returns (uint256) { - return PoseidonT6.poseidon(array); - } + function hash5(uint256[5] memory array) public pure returns (uint256) { + return PoseidonT6.poseidon(array); + } - function hash11(uint256[] memory array) public pure returns (uint256) { - uint256[] memory input11 = new uint256[](11); - uint256[5] memory first5; - uint256[5] memory second5; - for (uint256 i = 0; i < array.length; i++) { - input11[i] = array[i]; - } + function hash11(uint256[] memory array) public pure returns (uint256) { + uint256[] memory input11 = new uint256[](11); + uint256[5] memory first5; + uint256[5] memory second5; + for (uint256 i = 0; i < array.length; i++) { + input11[i] = array[i]; + } - for (uint256 i = array.length; i < 11; i++) { - input11[i] = 0; - } + for (uint256 i = array.length; i < 11; i++) { + input11[i] = 0; + } - for (uint256 i = 0; i < 5; i++) { - first5[i] = input11[i]; - second5[i] = input11[i + 5]; - } + for (uint256 i = 0; i < 5; i++) { + first5[i] = input11[i]; + second5[i] = input11[i + 5]; + } - uint256[2] memory first2; - first2[0] = PoseidonT6.poseidon(first5); - first2[1] = PoseidonT6.poseidon(second5); - uint256[2] memory second2; - second2[0] = PoseidonT3.poseidon(first2); - second2[1] = input11[10]; - return PoseidonT3.poseidon(second2); - } + uint256[2] memory first2; + first2[0] = PoseidonT6.poseidon(first5); + first2[1] = PoseidonT6.poseidon(second5); + uint256[2] memory second2; + second2[0] = PoseidonT3.poseidon(first2); + second2[1] = input11[10]; + return PoseidonT3.poseidon(second2); + } - function hashLeftRight(uint256 _left, uint256 _right) override public pure returns (uint256) { - require(uint256(_left) < SNARK_SCALAR_FIELD, "_left should be inside the field"); - require(uint256(_right) < SNARK_SCALAR_FIELD, "_right should be inside the field"); - uint256[2] memory input; - input[0] = _left; - input[1] = _right; - return PoseidonT3.poseidon(input); - } + function hashLeftRight(uint256 _left, uint256 _right) public pure override returns (uint256) { + require(uint256(_left) < SNARK_SCALAR_FIELD, "_left should be inside the field"); + require(uint256(_right) < SNARK_SCALAR_FIELD, "_right should be inside the field"); + uint256[2] memory input; + input[0] = _left; + input[1] = _right; + return PoseidonT3.poseidon(input); + } - /// @dev provides Zero (Empty) elements for a Poseidon MerkleTree. Up to 32 levels - function zeros(uint256 i) override public pure returns (bytes32) { - if (i == 0) return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c); - else if (i == 1) return bytes32(0x13e37f2d6cb86c78ccc1788607c2b199788c6bb0a615a21f2e7a8e88384222f8); - else if (i == 2) return bytes32(0x217126fa352c326896e8c2803eec8fd63ad50cf65edfef27a41a9e32dc622765); - else if (i == 3) return bytes32(0x0e28a61a9b3e91007d5a9e3ada18e1b24d6d230c618388ee5df34cacd7397eee); - else if (i == 4) return bytes32(0x27953447a6979839536badc5425ed15fadb0e292e9bc36f92f0aa5cfa5013587); - else if (i == 5) return bytes32(0x194191edbfb91d10f6a7afd315f33095410c7801c47175c2df6dc2cce0e3affc); - else if (i == 6) return bytes32(0x1733dece17d71190516dbaf1927936fa643dc7079fc0cc731de9d6845a47741f); - else if (i == 7) return bytes32(0x267855a7dc75db39d81d17f95d0a7aa572bf5ae19f4db0e84221d2b2ef999219); - else if (i == 8) return bytes32(0x1184e11836b4c36ad8238a340ecc0985eeba665327e33e9b0e3641027c27620d); - else if (i == 9) return bytes32(0x0702ab83a135d7f55350ab1bfaa90babd8fc1d2b3e6a7215381a7b2213d6c5ce); - else if (i == 10) return bytes32(0x2eecc0de814cfd8c57ce882babb2e30d1da56621aef7a47f3291cffeaec26ad7); - else if (i == 11) return bytes32(0x280bc02145c155d5833585b6c7b08501055157dd30ce005319621dc462d33b47); - else if (i == 12) return bytes32(0x045132221d1fa0a7f4aed8acd2cbec1e2189b7732ccb2ec272b9c60f0d5afc5b); - else if (i == 13) return bytes32(0x27f427ccbf58a44b1270abbe4eda6ba53bd6ac4d88cf1e00a13c4371ce71d366); - else if (i == 14) return bytes32(0x1617eaae5064f26e8f8a6493ae92bfded7fde71b65df1ca6d5dcec0df70b2cef); - else if (i == 15) return bytes32(0x20c6b400d0ea1b15435703c31c31ee63ad7ba5c8da66cec2796feacea575abca); - else if (i == 16) return bytes32(0x09589ddb438723f53a8e57bdada7c5f8ed67e8fece3889a73618732965645eec); - else if (i == 17) return bytes32(0x0064b6a738a5ff537db7b220f3394f0ecbd35bfd355c5425dc1166bf3236079b); - else if (i == 18) return bytes32(0x095de56281b1d5055e897c3574ff790d5ee81dbc5df784ad2d67795e557c9e9f); - else if (i == 19) return bytes32(0x11cf2e2887aa21963a6ec14289183efe4d4c60f14ecd3d6fe0beebdf855a9b63); - else if (i == 20) return bytes32(0x2b0f6fc0179fa65b6f73627c0e1e84c7374d2eaec44c9a48f2571393ea77bcbb); - else if (i == 21) return bytes32(0x16fdb637c2abf9c0f988dbf2fd64258c46fb6a273d537b2cf1603ea460b13279); - else if (i == 22) return bytes32(0x21bbd7e944f6124dad4c376df9cc12e7ca66e47dff703ff7cedb1a454edcf0ff); - else if (i == 23) return bytes32(0x2784f8220b1c963e468f590f137baaa1625b3b92a27ad9b6e84eb0d3454d9962); - else if (i == 24) return bytes32(0x16ace1a65b7534142f8cc1aad810b3d6a7a74ca905d9c275cb98ba57e509fc10); - else if (i == 25) return bytes32(0x2328068c6a8c24265124debd8fe10d3f29f0665ea725a65e3638f6192a96a013); - else if (i == 26) return bytes32(0x2ddb991be1f028022411b4c4d2c22043e5e751c120736f00adf54acab1c9ac14); - else if (i == 27) return bytes32(0x0113798410eaeb95056a464f70521eb58377c0155f2fe518a5594d38cc209cc0); - else if (i == 28) return bytes32(0x202d1ae61526f0d0d01ef80fb5d4055a7af45721024c2c24cffd6a3798f54d50); - else if (i == 29) return bytes32(0x23ab323453748129f2765f79615022f5bebd6f4096a796300aab049a60b0f187); - else if (i == 30) return bytes32(0x1f15585f8947e378bcf8bd918716799da909acdb944c57150b1eb4565fda8aa0); - else if (i == 31) return bytes32(0x1eb064b21055ac6a350cf41eb30e4ce2cb19680217df3a243617c2838185ad06); - else revert("Index out of bounds"); - } + /// @dev provides Zero (Empty) elements for a Poseidon MerkleTree. Up to 32 levels + function zeros(uint256 i) public pure override returns (bytes32) { + if (i == 0) + return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c); + else if (i == 1) + return bytes32(0x13e37f2d6cb86c78ccc1788607c2b199788c6bb0a615a21f2e7a8e88384222f8); + else if (i == 2) + return bytes32(0x217126fa352c326896e8c2803eec8fd63ad50cf65edfef27a41a9e32dc622765); + else if (i == 3) + return bytes32(0x0e28a61a9b3e91007d5a9e3ada18e1b24d6d230c618388ee5df34cacd7397eee); + else if (i == 4) + return bytes32(0x27953447a6979839536badc5425ed15fadb0e292e9bc36f92f0aa5cfa5013587); + else if (i == 5) + return bytes32(0x194191edbfb91d10f6a7afd315f33095410c7801c47175c2df6dc2cce0e3affc); + else if (i == 6) + return bytes32(0x1733dece17d71190516dbaf1927936fa643dc7079fc0cc731de9d6845a47741f); + else if (i == 7) + return bytes32(0x267855a7dc75db39d81d17f95d0a7aa572bf5ae19f4db0e84221d2b2ef999219); + else if (i == 8) + return bytes32(0x1184e11836b4c36ad8238a340ecc0985eeba665327e33e9b0e3641027c27620d); + else if (i == 9) + return bytes32(0x0702ab83a135d7f55350ab1bfaa90babd8fc1d2b3e6a7215381a7b2213d6c5ce); + else if (i == 10) + return bytes32(0x2eecc0de814cfd8c57ce882babb2e30d1da56621aef7a47f3291cffeaec26ad7); + else if (i == 11) + return bytes32(0x280bc02145c155d5833585b6c7b08501055157dd30ce005319621dc462d33b47); + else if (i == 12) + return bytes32(0x045132221d1fa0a7f4aed8acd2cbec1e2189b7732ccb2ec272b9c60f0d5afc5b); + else if (i == 13) + return bytes32(0x27f427ccbf58a44b1270abbe4eda6ba53bd6ac4d88cf1e00a13c4371ce71d366); + else if (i == 14) + return bytes32(0x1617eaae5064f26e8f8a6493ae92bfded7fde71b65df1ca6d5dcec0df70b2cef); + else if (i == 15) + return bytes32(0x20c6b400d0ea1b15435703c31c31ee63ad7ba5c8da66cec2796feacea575abca); + else if (i == 16) + return bytes32(0x09589ddb438723f53a8e57bdada7c5f8ed67e8fece3889a73618732965645eec); + else if (i == 17) + return bytes32(0x0064b6a738a5ff537db7b220f3394f0ecbd35bfd355c5425dc1166bf3236079b); + else if (i == 18) + return bytes32(0x095de56281b1d5055e897c3574ff790d5ee81dbc5df784ad2d67795e557c9e9f); + else if (i == 19) + return bytes32(0x11cf2e2887aa21963a6ec14289183efe4d4c60f14ecd3d6fe0beebdf855a9b63); + else if (i == 20) + return bytes32(0x2b0f6fc0179fa65b6f73627c0e1e84c7374d2eaec44c9a48f2571393ea77bcbb); + else if (i == 21) + return bytes32(0x16fdb637c2abf9c0f988dbf2fd64258c46fb6a273d537b2cf1603ea460b13279); + else if (i == 22) + return bytes32(0x21bbd7e944f6124dad4c376df9cc12e7ca66e47dff703ff7cedb1a454edcf0ff); + else if (i == 23) + return bytes32(0x2784f8220b1c963e468f590f137baaa1625b3b92a27ad9b6e84eb0d3454d9962); + else if (i == 24) + return bytes32(0x16ace1a65b7534142f8cc1aad810b3d6a7a74ca905d9c275cb98ba57e509fc10); + else if (i == 25) + return bytes32(0x2328068c6a8c24265124debd8fe10d3f29f0665ea725a65e3638f6192a96a013); + else if (i == 26) + return bytes32(0x2ddb991be1f028022411b4c4d2c22043e5e751c120736f00adf54acab1c9ac14); + else if (i == 27) + return bytes32(0x0113798410eaeb95056a464f70521eb58377c0155f2fe518a5594d38cc209cc0); + else if (i == 28) + return bytes32(0x202d1ae61526f0d0d01ef80fb5d4055a7af45721024c2c24cffd6a3798f54d50); + else if (i == 29) + return bytes32(0x23ab323453748129f2765f79615022f5bebd6f4096a796300aab049a60b0f187); + else if (i == 30) + return bytes32(0x1f15585f8947e378bcf8bd918716799da909acdb944c57150b1eb4565fda8aa0); + else if (i == 31) + return bytes32(0x1eb064b21055ac6a350cf41eb30e4ce2cb19680217df3a243617c2838185ad06); + else revert("Index out of bounds"); + } } diff --git a/packages/contracts/contracts/hashers/SnarkConstants.sol b/packages/contracts/contracts/hashers/SnarkConstants.sol index 65d189085..cc28fefb4 100644 --- a/packages/contracts/contracts/hashers/SnarkConstants.sol +++ b/packages/contracts/contracts/hashers/SnarkConstants.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; contract SnarkConstants { - // The scalar field - uint256 internal constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; -} \ No newline at end of file + // The scalar field + uint256 internal constant SNARK_SCALAR_FIELD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; +} diff --git a/packages/contracts/contracts/interfaces/IExecutor.sol b/packages/contracts/contracts/interfaces/IExecutor.sol index a0c62ca51..710434cd5 100644 --- a/packages/contracts/contracts/interfaces/IExecutor.sol +++ b/packages/contracts/contracts/interfaces/IExecutor.sol @@ -2,7 +2,7 @@ * Copyright 2021-2022 Webb Technologies * SPDX-License-Identifier: GPL-3.0-or-later-only */ - + pragma solidity ^0.8.0; /** @@ -10,21 +10,22 @@ pragma solidity ^0.8.0; @author Webb Technologies, adapted from ChainSafe Systems. */ interface IExecutor { - /** + /** @notice It is intended that proposals are executed by the Bridge contract. @param data Consists of additional data needed for a specific deposit execution. */ - function executeProposal(bytes32 resourceID, bytes calldata data) external; - /** + function executeProposal(bytes32 resourceID, bytes calldata data) external; + + /** @notice Correlates {resourceID} with {contractAddress}. @param resourceID ResourceID to be used when making deposits. @param contractAddress Address of contract to be called when a deposit is made and a deposited is executed. */ - function setResource(bytes32 resourceID, address contractAddress) external; + function setResource(bytes32 resourceID, address contractAddress) external; - /** + /** @notice Migrates the bridge to a new bridge address @param newBridge New bridge address */ - function migrateBridge(address newBridge) external; + function migrateBridge(address newBridge) external; } diff --git a/packages/contracts/contracts/interfaces/IMerkleSystem.sol b/packages/contracts/contracts/interfaces/IMerkleSystem.sol new file mode 100644 index 000000000..e10b26ea5 --- /dev/null +++ b/packages/contracts/contracts/interfaces/IMerkleSystem.sol @@ -0,0 +1,78 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../utils/Initialized.sol"; +import "../hashers/IHasher.sol"; + +/** + @title IMerkleSystem contract for merkle tree like data structures. + @author Webb Technologies + */ +interface IMerkleSystem { + /** @dev Whether the root is present in the root history of the system */ + function isKnownRoot(uint256 root) external view returns (bool); + + /** @dev Gets the zero hash for a specific index */ + function getZeroHash(uint32 index) external view returns (uint256); + + /** @dev Gets the levels of the outer-most merkle tree in the system */ + function getLevels() external view returns (uint32); + + /** @dev Gets the last merkle root of the merkle system */ + function getLastRoot() external view returns (uint256); + + /** @dev Gets the next index of a subtree */ + function getNextIndex() external view returns (uint32); + + /** @dev Gets the hasher for this merkle system */ + function getHasher() external view returns (IHasher); +} + +abstract contract MerkleSystem is IMerkleSystem, Initialized { + uint256 public constant FIELD_SIZE = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 public constant ZERO_VALUE = + 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE + uint32 public constant ROOT_HISTORY_SIZE = 30; + + // The `Root` struct is used to store the root and the index of + // the leaf triggering this root update. + struct Root { + uint256 root; + uint32 latestLeafindex; + } + + // The mapping of root indices to roots for storing a history of ROOT_HISTORY_SIZE updates + mapping(uint256 => Root) public roots; + // The mapping of filled subtree indices to filled subtree roots + mapping(uint256 => uint256) public filledSubtrees; + // The mapping to store used nullifier hashes / spent commitments + mapping(uint256 => bool) public nullifierHashes; + // The mapping to store all commitments to prevent accidental deposits with the same commitment + mapping(uint256 => bool) public commitments; + + event Insertion(uint256 indexed commitment, uint32 leafIndex, uint256 timestamp); + + // Internal functions + function _initialize() internal { + initialized = true; + } + + /** @dev this function is defined in a child contract */ + function hashLeftRight(uint256 _left, uint256 _right) public view virtual returns (uint256) { + IHasher hasher = this.getHasher(); + return hasher.hashLeftRight(_left, _right); + } + + function _insert(uint256 element) internal virtual returns (uint32 index); + + function _insertTwo(uint256 left, uint256 right) internal virtual returns (uint32 index); + + function _insertTwo(uint256[2] memory elements) internal returns (uint32 index) { + return _insertTwo(elements[0], elements[1]); + } +} diff --git a/packages/contracts/contracts/interfaces/ITreasury.sol b/packages/contracts/contracts/interfaces/ITreasury.sol index a6b96eefa..3178b1251 100644 --- a/packages/contracts/contracts/interfaces/ITreasury.sol +++ b/packages/contracts/contracts/interfaces/ITreasury.sol @@ -10,19 +10,24 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface ITreasury { - /** + /** @notice Sends an `_amountToRescue` of tokens at `_tokenAddress` from the treasury contract to `_to` @param _tokenAddress Address of the token to rescue. @param _to Address of the recipient. @param _amountToRescue Amount of tokens to rescue. @param _nonce Nonce of the rescue transaction. */ - function rescueTokens(address _tokenAddress, address payable _to, uint256 _amountToRescue, uint32 _nonce) external; + function rescueTokens( + address _tokenAddress, + address payable _to, + uint256 _amountToRescue, + uint32 _nonce + ) external; - /** + /** @notice Sets the handler responsible with relaying rescue transactions. @param _newHandler Address of the handler. @param _nonce Nonce of the update. */ - function setHandler(address _newHandler, uint32 _nonce) external; + function setHandler(address _newHandler, uint32 _nonce) external; } diff --git a/packages/contracts/contracts/interfaces/anchors/ILinkableAnchor.sol b/packages/contracts/contracts/interfaces/anchors/ILinkableAnchor.sol index 5166075be..7e8338519 100644 --- a/packages/contracts/contracts/interfaces/anchors/ILinkableAnchor.sol +++ b/packages/contracts/contracts/interfaces/anchors/ILinkableAnchor.sol @@ -16,34 +16,37 @@ pragma solidity ^0.8.0; to control the minimal and maximum withdrawal and deposit limits respectively. */ interface ILinkableAnchor { - /** + /** @notice Sets the handler for updating edges and other contract state @param handler The new handler address @param nonce The nonce for tracking update counts */ - function setHandler(address handler, uint32 nonce) external; + function setHandler(address handler, uint32 nonce) external; - /** + /** @notice Sets the minimal withdrawal limit for the anchor @param minimalWithdrawalAmount The new minimal withdrawal limit */ - function configureMinimalWithdrawalLimit(uint256 minimalWithdrawalAmount, uint32 nonce) external; + function configureMinimalWithdrawalLimit( + uint256 minimalWithdrawalAmount, + uint32 nonce + ) external; - /** + /** @notice Sets the maximal deposit limit for the anchor @param maximumDepositAmount The new maximal deposit limit */ - function configureMaximumDepositLimit(uint256 maximumDepositAmount, uint32 nonce) external; - - /** + function configureMaximumDepositLimit(uint256 maximumDepositAmount, uint32 nonce) external; + + /** @notice The function is used to update the edge data of a LinkableAnchor @param root The merkle root of the linked anchor on the `sourceChainID`'s chain @param latestLeafIndex The index of the leaf updating the merkle tree with root `root` - @param target The target resource ID of the linked anchor + @param srcResourceID The source resource ID of the linked anchor where the update originates from */ - function updateEdge( - bytes32 root, - uint32 latestLeafIndex, - bytes32 target - ) external payable; -} \ No newline at end of file + function updateEdge( + uint256 root, + uint32 latestLeafIndex, + bytes32 srcResourceID + ) external payable; +} diff --git a/packages/contracts/contracts/interfaces/anchors/ISemaphoreGroups.sol b/packages/contracts/contracts/interfaces/anchors/ISemaphoreGroups.sol index 507158925..e08f91b3d 100644 --- a/packages/contracts/contracts/interfaces/anchors/ISemaphoreGroups.sol +++ b/packages/contracts/contracts/interfaces/anchors/ISemaphoreGroups.sol @@ -6,61 +6,53 @@ import "../../structs/Edge.sol"; /// @title SemaphoreGroups interface. /// @dev Interface of a SemaphoreGroups contract. interface ISemaphoreGroups { - error Semaphore__GroupDoesNotExist(); - error Semaphore__GroupAlreadyExists(); - error Semaphore__GroupIdIsNotLessThanSnarkScalarField(); - error Semaphore__InvalidCurrentChainRoot(); - error Semaphore__InvalidEdgeChainRoot(); - - /// @dev Emitted when a new group is created. - /// @param groupId: Id of the group. - /// @param depth: Depth of the tree. - event GroupCreated(uint256 indexed groupId, uint8 depth); - - /// @dev Emitted when a new identity commitment is added. - /// @param groupId: Group id of the group. - /// @param identityCommitment: New identity commitment. - /// @param root: New root hash of the tree. - event MemberAdded(uint256 indexed groupId, uint256 identityCommitment, uint256 root); - - /// @dev Emitted when a new identity commitment is removed. - /// @param groupId: Group id of the group. - /// @param identityCommitment: New identity commitment. - /// @param root: New root hash of the tree. - event MemberRemoved(uint256 indexed groupId, uint256 identityCommitment, uint256 root); - - function verifyRoots(uint256 groupId, bytes calldata roots) external view returns (bool); - - // function _updateEdge( - // uint256 groupId, - // uint256 sourceChainID, - // bytes32 root, - // uint256 leafIndex, - // bytes32 target - // ) external; - - /// @dev Returns the last root hash of a group. - /// @param groupId: Id of the group. - /// @return Latests roots from each edge connected - function getLatestNeighborEdges(uint256 groupId) external view returns (Edge[] memory); - - /// @dev Returns the last root hash of a group. - /// @param groupId: Id of the group. - /// @return Root hash of the group. - function getRoot(uint256 groupId) external view returns (uint256); - - /// @dev Returns the depth of the tree of a group. - /// @param groupId: Id of the group. - /// @return Depth of the group tree. - function getDepth(uint256 groupId) external view returns (uint8); - - /// @dev Returns the max edges of the linkable tree of a group. - /// @param groupId: Id of the group. - /// @return Maximum # of edges this group supports - function getMaxEdges(uint256 groupId) external view returns (uint8); - - /// @dev Returns the number of tree leaves of a group. - /// @param groupId: Id of the group. - /// @return Number of tree leaves. - function getNumberOfLeaves(uint256 groupId) external view returns (uint256); + error Semaphore__GroupDoesNotExist(); + error Semaphore__GroupAlreadyExists(); + error Semaphore__GroupIdIsNotLessThanSnarkScalarField(); + error Semaphore__InvalidCurrentChainRoot(); + error Semaphore__InvalidEdgeChainRoot(); + + /// @dev Emitted when a new group is created. + /// @param groupId: Id of the group. + /// @param depth: Depth of the tree. + event GroupCreated(uint256 indexed groupId, uint8 depth); + + /// @dev Emitted when a new identity commitment is added. + /// @param groupId: Group id of the group. + /// @param identityCommitment: New identity commitment. + /// @param root: New root hash of the tree. + event MemberAdded(uint256 indexed groupId, uint256 identityCommitment, uint256 root); + + /// @dev Emitted when a new identity commitment is removed. + /// @param groupId: Group id of the group. + /// @param identityCommitment: New identity commitment. + /// @param root: New root hash of the tree. + event MemberRemoved(uint256 indexed groupId, uint256 identityCommitment, uint256 root); + + function verifyRoots(uint256 groupId, bytes calldata roots) external view returns (bool); + + /// @dev Returns the last root hash of a group. + /// @param groupId: Id of the group. + /// @return Latests roots from each edge connected + function getLatestNeighborEdges(uint256 groupId) external view returns (Edge[] memory); + + /// @dev Returns the last root hash of a group. + /// @param groupId: Id of the group. + /// @return Root hash of the group. + function getRoot(uint256 groupId) external view returns (uint256); + + /// @dev Returns the depth of the tree of a group. + /// @param groupId: Id of the group. + /// @return Depth of the group tree. + function getDepth(uint256 groupId) external view returns (uint8); + + /// @dev Returns the max edges of the linkable tree of a group. + /// @param groupId: Id of the group. + /// @return Maximum # of edges this group supports + function getMaxEdges(uint256 groupId) external view returns (uint8); + + /// @dev Returns the number of tree leaves of a group. + /// @param groupId: Id of the group. + /// @return Number of tree leaves. + function getNumberOfLeaves(uint256 groupId) external view returns (uint256); } diff --git a/packages/contracts/contracts/interfaces/anchors/LinkableIncrementalBinaryTree.sol b/packages/contracts/contracts/interfaces/anchors/LinkableIncrementalBinaryTree.sol deleted file mode 100644 index 3f85e66be..000000000 --- a/packages/contracts/contracts/interfaces/anchors/LinkableIncrementalBinaryTree.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -/** - @dev The Edge struct is used to store the edge data for linkable tree connections. - @param chainId The chain id where the LinkableTree contract being linked is located. - @param root The latest merkle root of the LinkableTree contract being linked. - @param nonce The latest leaf insertion index of the LinkableTree contract being linked. - @param target The contract address or tree identifier of the LinkableTree being linked. -*/ -struct Edge { - uint256 chainID; - bytes32 root; - uint256 latestLeafIndex; - bytes32 srcResourceID; -} diff --git a/packages/contracts/contracts/interfaces/external/aave/IAaveLendingPool.sol b/packages/contracts/contracts/interfaces/external/aave/IAaveLendingPool.sol index 661e31fae..8703704a3 100644 --- a/packages/contracts/contracts/interfaces/external/aave/IAaveLendingPool.sol +++ b/packages/contracts/contracts/interfaces/external/aave/IAaveLendingPool.sol @@ -6,16 +6,12 @@ pragma solidity ^0.8.0; interface IAaveLendingPool { - function deposit( - address asset, - uint256 amount, - address onBehalfOf, - uint16 referralCode - ) external; + function deposit( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; - function withdraw( - address asset, - uint256 amount, - address to - ) external returns (uint256); + function withdraw(address asset, uint256 amount, address to) external returns (uint256); } diff --git a/packages/contracts/contracts/interfaces/external/chainalysis/ISanctionsList.sol b/packages/contracts/contracts/interfaces/external/chainalysis/ISanctionsList.sol index f145b67ca..2f3f869b0 100644 --- a/packages/contracts/contracts/interfaces/external/chainalysis/ISanctionsList.sol +++ b/packages/contracts/contracts/interfaces/external/chainalysis/ISanctionsList.sol @@ -6,5 +6,5 @@ pragma solidity ^0.8.0; interface ISanctionsList { - function isSanctioned(address addr) external view returns (bool); -} \ No newline at end of file + function isSanctioned(address addr) external view returns (bool); +} diff --git a/packages/contracts/contracts/interfaces/tokens/IAaveTokenWrapper.sol b/packages/contracts/contracts/interfaces/tokens/IAaveTokenWrapper.sol index 34e630d1e..343d722f3 100644 --- a/packages/contracts/contracts/interfaces/tokens/IAaveTokenWrapper.sol +++ b/packages/contracts/contracts/interfaces/tokens/IAaveTokenWrapper.sol @@ -10,17 +10,17 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface IAaveTokenWrapper { - /** + /** @notice Deposits token at `_tokenAddress` into Aave Lending Pool @param _tokenAddress The address of the token to deposit @param _amount The amount to deposit */ - function deposit(address _tokenAddress, uint256 _amount) external; + function deposit(address _tokenAddress, uint256 _amount) external; - /** + /** @notice Withdraws token at `_tokenAddress` from Aave Lending Pool @param _tokenAddress The address of the token to withdraw @param _amount The amount to withdraw */ - function withdraw(address _tokenAddress, uint256 _amount) external; + function withdraw(address _tokenAddress, uint256 _amount) external; } diff --git a/packages/contracts/contracts/interfaces/tokens/IFungibleTokenWrapper.sol b/packages/contracts/contracts/interfaces/tokens/IFungibleTokenWrapper.sol index ebf023cab..2d56f1d4f 100644 --- a/packages/contracts/contracts/interfaces/tokens/IFungibleTokenWrapper.sol +++ b/packages/contracts/contracts/interfaces/tokens/IFungibleTokenWrapper.sol @@ -10,35 +10,35 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface IFungibleTokenWrapper { - /** + /** @notice Adds a token at `_tokenAddress` to the FungibleTokenWrapper's wrapping list @param _tokenAddress The address of the token to be added @param _nonce The nonce tracking updates to this contract @notice Only the governor can call this function */ - function add(address _tokenAddress, uint32 _nonce) external; + function add(address _tokenAddress, uint32 _nonce) external; - /** + /** @notice Removes a token at `_tokenAddress` from the FungibleTokenWrapper's wrapping list @param _tokenAddress The address of the token to be removed @param _nonce The nonce tracking updates to this contract @notice Only the governor can call this function */ - function remove(address _tokenAddress, uint32 _nonce) external; + function remove(address _tokenAddress, uint32 _nonce) external; - /** + /** @notice Sets a new `_feePercentage` for the FungibleTokenWrapper @param _feePercentage The new fee percentage @param _nonce The nonce tracking updates to this contract @notice Only the governor can call this function */ - function setFee(uint16 _feePercentage, uint32 _nonce) external; + function setFee(uint16 _feePercentage, uint32 _nonce) external; - /** + /** @notice Sets a new `_feeRecipient` for the FungibleTokenWrapper @param _feeRecipient The new fee recipient @param _nonce The nonce tracking updates to this contract @notice Only the governor can call this function */ - function setFeeRecipient(address payable _feeRecipient, uint32 _nonce) external; -} \ No newline at end of file + function setFeeRecipient(address payable _feeRecipient, uint32 _nonce) external; +} diff --git a/packages/contracts/contracts/interfaces/tokens/IMintableERC20.sol b/packages/contracts/contracts/interfaces/tokens/IMintableERC20.sol index 9a357d1e5..4ab2aa038 100644 --- a/packages/contracts/contracts/interfaces/tokens/IMintableERC20.sol +++ b/packages/contracts/contracts/interfaces/tokens/IMintableERC20.sol @@ -9,34 +9,34 @@ pragma solidity ^0.8.0; * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IMintableERC20 { - /** - * @dev Mints `amount` tokens to account `to`. - * - * Emits a {Transfer} event. - */ - function mint(address to, uint256 amount) external; + /** + * @dev Mints `amount` tokens to account `to`. + * + * Emits a {Transfer} event. + */ + function mint(address to, uint256 amount) external; - /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address sender, - address recipient, - uint256 amount - ) external returns (bool); + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); } diff --git a/packages/contracts/contracts/interfaces/tokens/IMultiTokenManager.sol b/packages/contracts/contracts/interfaces/tokens/IMultiTokenManager.sol index 1061cb370..0267843ba 100644 --- a/packages/contracts/contracts/interfaces/tokens/IMultiTokenManager.sol +++ b/packages/contracts/contracts/interfaces/tokens/IMultiTokenManager.sol @@ -10,18 +10,15 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface IMultiTokenManager { - /** + /** @notice Initialize the contract with the registry and fee recipient @param _registry The address of the registry @param _feeRecipient The address of the fee recipient */ - function initialize( - address _registry, - address _feeRecipient - ) external; + function initialize(address _registry, address _feeRecipient) external; - /** - @notice Registers a new token and deploys the FungibleTokenWrapperInitializable contract + /** + @notice Registers a new token and deploys the FungibleTokenWrapper contract @param _handler The address of the token handler contract @param _name The name of the ERC20 @param _symbol The symbol of the ERC20 @@ -30,25 +27,25 @@ interface IMultiTokenManager { @param _feePercentage The fee percentage for wrapping @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function registerToken( - address _handler, - string memory _name, - string memory _symbol, - bytes32 _salt, - uint256 _limit, - uint16 _feePercentage, - bool _isNativeAllowed - ) external returns (address); + function registerToken( + address _handler, + string memory _name, + string memory _symbol, + bytes32 _salt, + uint256 _limit, + uint16 _feePercentage, + bool _isNativeAllowed + ) external returns (address); - /** + /** @notice Registers a new NFT token and deploys the NftTokenWrapper contract @param _handler The address of the token handler contract @param _uri The uri for the wrapped ERC1155 @param _salt Salt used for matching addresses across chain using CREATE2 */ - function registerNftToken( - address _handler, - string memory _uri, - bytes32 _salt - ) external returns (address); + function registerNftToken( + address _handler, + string memory _uri, + bytes32 _salt + ) external returns (address); } diff --git a/packages/contracts/contracts/interfaces/tokens/IMultiTokenWrapper.sol b/packages/contracts/contracts/interfaces/tokens/IMultiTokenWrapper.sol index f10bcc4ae..86f61e416 100644 --- a/packages/contracts/contracts/interfaces/tokens/IMultiTokenWrapper.sol +++ b/packages/contracts/contracts/interfaces/tokens/IMultiTokenWrapper.sol @@ -10,23 +10,27 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface IMultiTokenWrapper { - /** + /** @notice Wraps an `amount` of tokens from `tokenAddress` @param _fromTokenAddress Address of the token to wrap @param _toTokenAddress Address of the token to wrap into @param _amount Amount of tokens to wrap */ - function wrap(address _fromTokenAddress, address _toTokenAddress, uint256 _amount) payable external; + function wrap( + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount + ) external payable; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` @param _fromTokenAddress Address of the token to unwrap from @param _toTokenAddress Address of the token to unwrap into @param _amount Amount of tokens to unwrap */ - function unwrap(address _fromTokenAddress, address _toTokenAddress, uint256 _amount) external; + function unwrap(address _fromTokenAddress, address _toTokenAddress, uint256 _amount) external; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` and sends to a `recipient` address @param _fromTokenAddress Address of the token to unwrap from @@ -34,18 +38,28 @@ interface IMultiTokenWrapper { @param _amount Amount of tokens to unwrap @param _recipient Address of the recipient */ - function unwrapAndSendTo(address _fromTokenAddress, address _toTokenAddress, uint256 _amount, address _recipient) external; + function unwrapAndSendTo( + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount, + address _recipient + ) external; - /** + /** @notice Wraps an `amount` of tokens from `tokenAddress` for the `sender` @param _sender The sender address the tokens are being wrapped for @param _fromTokenAddress Address of the token to wrap @param _toTokenAddress Address of the token to wrap into @param _amount Amount of tokens to wrap */ - function wrapFor(address _sender, address _fromTokenAddress, address _toTokenAddress, uint256 _amount) payable external; + function wrapFor( + address _sender, + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount + ) external payable; - /** + /** @notice Wraps an `amount of tokens from `tokenAddress` for the `sender` address and sends to a `_mintRecipient` @param _sender The sender address the tokens are being wrapped for @param _fromTokenAddress Address of the token to wrap @@ -53,39 +67,53 @@ interface IMultiTokenWrapper { @param _amount Amount of tokens to wrap @param _mintRecipient Address of the recipient of the wrapped tokens */ - function wrapForAndSendTo(address _sender, address _fromTokenAddress, address _toTokenAddress, uint256 _amount, address _mintRecipient) payable external; + function wrapForAndSendTo( + address _sender, + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount, + address _mintRecipient + ) external payable; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` for a `sender` @param _sender The sender address the tokens are being unwrapped for @param _fromTokenAddress Address of the token to unwrap from @param _toTokenAddress Address of the token to unwrap into @param _amount Amount of tokens to unwrap */ - function unwrapFor(address _sender, address _fromTokenAddress, address _toTokenAddress, uint256 _amount) external; + function unwrapFor( + address _sender, + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount + ) external; - /** + /** @notice Gets the fee for an `_amountToWrap` amount of tokens @param _toTokenAddress Address of the token to wrap into @param _amountToWrap Amount of tokens to wrap @return uint256 The fee amount for the `_amountToWrap` amount of tokens */ - function getFeeFromAmount(address _toTokenAddress, uint _amountToWrap) external view returns (uint); + function getFeeFromAmount( + address _toTokenAddress, + uint _amountToWrap + ) external view returns (uint); - /** + /** @notice Gets the amount to wrap for an exact `_deposit` amount of tokens. This function calculates the amount needed to wrap inclusive of the fee that will be charged from `getFeeFromAmount` to meet the `_deposit` amount @param _toTokenAddress Address of the token to wrap into @param _deposit Amount of tokens needed for the deposit to be valid */ - function getAmountToWrap(address _toTokenAddress, uint _deposit) external view returns (uint); + function getAmountToWrap(address _toTokenAddress, uint _deposit) external view returns (uint); - /** + /** @notice Sets the `_feePercentage` to be taken from wrappings with a `_nonce` @param _toTokenAddress Address of the token being wrapped into @param _feePercentage The percentage of the fee to be taken from the wrapping, a value between 0 - 10000 @param _nonce The nonce for tracking fee updates */ - function setFee(address _toTokenAddress, uint16 _feePercentage, uint32 _nonce) external; + function setFee(address _toTokenAddress, uint16 _feePercentage, uint32 _nonce) external; } diff --git a/packages/contracts/contracts/interfaces/tokens/IRegistry.sol b/packages/contracts/contracts/interfaces/tokens/IRegistry.sol index 35f9b1739..6c9f1b7fd 100644 --- a/packages/contracts/contracts/interfaces/tokens/IRegistry.sol +++ b/packages/contracts/contracts/interfaces/tokens/IRegistry.sol @@ -10,7 +10,7 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface IRegistry { - /** + /** @notice Registers a new token and deploys the FungibleTokenWrapper contract @param _nonce The nonce of the proposal @param _handler The address of the token handler contract @@ -22,19 +22,19 @@ interface IRegistry { @param _limit The maximum amount of tokens that can be wrapped @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function registerToken( - uint32 _nonce, - address _handler, - uint256 _assetIdentifier, - string memory _name, - string memory _symbol, - bytes32 _salt, - uint256 _limit, - uint16 _feePercentage, - bool _isNativeAllowed - ) external; + function registerToken( + uint32 _nonce, + address _handler, + uint256 _assetIdentifier, + string memory _name, + string memory _symbol, + bytes32 _salt, + uint256 _limit, + uint16 _feePercentage, + bool _isNativeAllowed + ) external; - /** + /** @notice Registers a new NFT token and deploys the NftTokenWrapper contract @param _nonce The nonce of the proposal @param _handler The address of the token handler contract @@ -42,23 +42,23 @@ interface IRegistry { @param _uri The uri for the wrapped NFT @param _salt Salt used for matching addresses across chain using CREATE2 */ - function registerNftToken( - uint32 _nonce, - address _handler, - uint256 _assetIdentifier, - string memory _uri, - bytes32 _salt - ) external; + function registerNftToken( + uint32 _nonce, + address _handler, + uint256 _assetIdentifier, + string memory _uri, + bytes32 _salt + ) external; - /** + /** @notice Fetches the address for an asset ID @param _assetId The asset ID */ - function getAssetAddress(uint256 _assetId) external view returns (address); + function getAssetAddress(uint256 _assetId) external view returns (address); - /** + /** @notice Fetches the asset ID for an address @param _address The address */ - function getAssetId(address _address) external view returns (uint256); + function getAssetId(address _address) external view returns (uint256); } diff --git a/packages/contracts/contracts/interfaces/tokens/ITokenWrapper.sol b/packages/contracts/contracts/interfaces/tokens/ITokenWrapper.sol index 6f047730d..58a709fbd 100644 --- a/packages/contracts/contracts/interfaces/tokens/ITokenWrapper.sol +++ b/packages/contracts/contracts/interfaces/tokens/ITokenWrapper.sol @@ -10,66 +10,76 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ interface ITokenWrapper { - /** + /** @notice Wraps an `amount` of tokens from `tokenAddress` @param _tokenAddress Address of the token to wrap @param _amount Amount of tokens to wrap */ - function wrap(address _tokenAddress, uint256 _amount) payable external; + function wrap(address _tokenAddress, uint256 _amount) external payable; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` @param _tokenAddress Address of the token to unwrap into @param _amount Amount of tokens to unwrap */ - function unwrap(address _tokenAddress, uint256 _amount) external; + function unwrap(address _tokenAddress, uint256 _amount) external; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` and sends to a `recipient` address @param _tokenAddress Address of the token to unwrap into @param _amount Amount of tokens to unwrap @param _recipient Address of the recipient */ - function unwrapAndSendTo(address _tokenAddress, uint256 _amount, address _recipient) external; + function unwrapAndSendTo(address _tokenAddress, uint256 _amount, address _recipient) external; - /** + /** @notice Wraps an `amount` of tokens from `tokenAddress` for the `sender` @param _sender The sender address the tokens are being wrapped for @param _tokenAddress Address of the token to wrap @param _amount Amount of tokens to wrap */ - function wrapFor(address _sender, address _tokenAddress, uint256 _amount) payable external; + function wrapFor(address _sender, address _tokenAddress, uint256 _amount) external payable; - /** + /** @notice Wraps an `amount of tokens from `tokenAddress` for the `sender` address and sends to a `_mintRecipient` @param _sender The sender address the tokens are being wrapped for @param _tokenAddress Address of the token to wrap @param _amount Amount of tokens to wrap @param _mintRecipient Address of the recipient of the wrapped tokens */ - function wrapForAndSendTo(address _sender, address _tokenAddress, uint256 _amount, address _mintRecipient) payable external; + function wrapForAndSendTo( + address _sender, + address _tokenAddress, + uint256 _amount, + address _mintRecipient + ) external payable; - /** + /** @notice Unwraps an `amount` of an underlying token into the token at `tokenAddress` for a `sender` @param _sender The sender address the tokens are being unwrapped for @param _tokenAddress Address of the token to unwrap into @param _amount Amount of tokens to unwrap */ - function unwrapFor(address _sender, address _tokenAddress, uint256 _amount) external; + function unwrapFor(address _sender, address _tokenAddress, uint256 _amount) external; - /** + /** @notice Gets the fee for an `_amountToWrap` amount of tokens @param _amountToWrap Amount of tokens to wrap @return uint256 The fee amount for the `_amountToWrap` amount of tokens */ - function getFeeFromAmount(uint _amountToWrap) external view returns (uint); + function getFeeFromAmount(uint _amountToWrap) external view returns (uint); - /** + /** @notice Gets the amount to wrap for an exact `_deposit` amount of tokens. This function calculates the amount needed to wrap inclusive of the fee that will be charged from `getFeeFromAmount` to meet the `_deposit` amount @param _deposit Amount of tokens needed for the deposit to be valid */ - function getAmountToWrap(uint _deposit) external view returns (uint); + function getAmountToWrap(uint _deposit) external view returns (uint); + + /** + @notice Checks if a token is wrappable / valid + */ + function isValidToken(address _tokenAddress) external view returns (bool); } diff --git a/packages/contracts/contracts/interfaces/verifiers/IAnchorVerifier.sol b/packages/contracts/contracts/interfaces/verifiers/IAnchorVerifier.sol index 4823bcd19..2e4baabb1 100644 --- a/packages/contracts/contracts/interfaces/verifiers/IAnchorVerifier.sol +++ b/packages/contracts/contracts/interfaces/verifiers/IAnchorVerifier.sol @@ -10,12 +10,12 @@ pragma solidity ^0.8.0; @notice A generic interface for verifying zero-knowledge proofs for anchors of different sizes. */ interface IAnchorVerifier { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - bytes memory input, - uint8 maxEdges, - bool smallInputs - ) external view returns (bool r); -} \ No newline at end of file + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + bytes memory input, + uint8 maxEdges, + bool smallInputs + ) external view returns (bool r); +} diff --git a/packages/contracts/contracts/interfaces/verifiers/IMASPVAnchorVerifier.sol b/packages/contracts/contracts/interfaces/verifiers/IMASPVAnchorVerifier.sol index ef10562be..528387c66 100644 --- a/packages/contracts/contracts/interfaces/verifiers/IMASPVAnchorVerifier.sol +++ b/packages/contracts/contracts/interfaces/verifiers/IMASPVAnchorVerifier.sol @@ -14,12 +14,12 @@ pragma solidity ^0.8.0; - Y is the # of inputs to the join/split transaction (i.e. 2) */ interface IMASPVAnchorVerifier2_2 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[10] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[10] memory input + ) external view returns (bool r); } /** @@ -31,12 +31,12 @@ interface IMASPVAnchorVerifier2_2 { - Y is the # of inputs to the join/split transaction (i.e. 16) */ interface IMASPVAnchorVerifier2_16 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[24] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[24] memory input + ) external view returns (bool r); } /** @@ -48,12 +48,12 @@ interface IMASPVAnchorVerifier2_16 { - Y is the # of inputs to the join/split transaction (i.e. 2) */ interface IMASPVAnchorVerifier8_2 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[16] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[16] memory input + ) external view returns (bool r); } /** @@ -65,10 +65,10 @@ interface IMASPVAnchorVerifier8_2 { - Y is the # of inputs to the join/split transaction (i.e. 16) */ interface IMASPVAnchorVerifier8_16 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[30] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[30] memory input + ) external view returns (bool r); } diff --git a/packages/contracts/contracts/interfaces/verifiers/ISetVerifier.sol b/packages/contracts/contracts/interfaces/verifiers/ISetVerifier.sol index ba03d4963..2647667c2 100644 --- a/packages/contracts/contracts/interfaces/verifiers/ISetVerifier.sol +++ b/packages/contracts/contracts/interfaces/verifiers/ISetVerifier.sol @@ -9,10 +9,10 @@ pragma solidity ^0.8.0; @title Interface for setting the verifier for a contract. */ interface ISetVerifier { - /** + /** @notice Sets the verifier for the contract @param verifier The new verifier address @param nonce The nonce for tracking update counts */ - function setVerifier(address verifier, uint32 nonce) external; -} \ No newline at end of file + function setVerifier(address verifier, uint32 nonce) external; +} diff --git a/packages/contracts/contracts/interfaces/verifiers/IVAnchorVerifier.sol b/packages/contracts/contracts/interfaces/verifiers/IVAnchorVerifier.sol index cd14aa5ee..a9200b834 100644 --- a/packages/contracts/contracts/interfaces/verifiers/IVAnchorVerifier.sol +++ b/packages/contracts/contracts/interfaces/verifiers/IVAnchorVerifier.sol @@ -14,12 +14,12 @@ pragma solidity ^0.8.0; - Y is the # of inputs to the join/split transaction (i.e. 2) */ interface IVAnchorVerifier2_2 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[9] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[9] memory input + ) external view returns (bool r); } /** @@ -31,12 +31,12 @@ interface IVAnchorVerifier2_2 { - Y is the # of inputs to the join/split transaction (i.e. 16) */ interface IVAnchorVerifier2_16 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[23] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[23] memory input + ) external view returns (bool r); } /** @@ -48,12 +48,12 @@ interface IVAnchorVerifier2_16 { - Y is the # of inputs to the join/split transaction (i.e. 2) */ interface IVAnchorVerifier8_2 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[15] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[15] memory input + ) external view returns (bool r); } /** @@ -65,10 +65,10 @@ interface IVAnchorVerifier8_2 { - Y is the # of inputs to the join/split transaction (i.e. 16) */ interface IVAnchorVerifier8_16 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[29] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[29] memory input + ) external view returns (bool r); } diff --git a/packages/contracts/contracts/interfaces/verifiers/IVerifier.sol b/packages/contracts/contracts/interfaces/verifiers/IVerifier.sol index 7a400af67..b65a106dc 100644 --- a/packages/contracts/contracts/interfaces/verifiers/IVerifier.sol +++ b/packages/contracts/contracts/interfaces/verifiers/IVerifier.sol @@ -9,58 +9,58 @@ pragma solidity ^0.8.0; @title IVerifier2 interface for an Anchor Verifier with 2 edges */ interface IVerifier2 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[5] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[5] memory input + ) external view returns (bool r); } /** @title IVerifier3 interface for an Anchor Verifier with 3 edges */ interface IVerifier3 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[6] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[6] memory input + ) external view returns (bool r); } /** @title IVerifier4 interface for an Anchor Verifier with 4 edges */ interface IVerifier4 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[7] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[7] memory input + ) external view returns (bool r); } /** @title IVerifier5 interface for an Anchor Verifier with 5 edges */ interface IVerifier5 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[8] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[8] memory input + ) external view returns (bool r); } /** @title IVerifier6 interface for an Anchor Verifier with 6 edges */ interface IVerifier6 { - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint256[9] memory input - ) external view returns (bool r); + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint256[9] memory input + ) external view returns (bool r); } diff --git a/packages/contracts/contracts/libs/IdentityVAnchorEncodeInputs.sol b/packages/contracts/contracts/libs/IdentityVAnchorEncodeInputs.sol index ec64c0fda..59a8cd15f 100644 --- a/packages/contracts/contracts/libs/IdentityVAnchorEncodeInputs.sol +++ b/packages/contracts/contracts/libs/IdentityVAnchorEncodeInputs.sol @@ -3,37 +3,22 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; +import "../structs/PublicInputs.sol"; + /** @title VAnchorEncodeInputs library for encoding inputs for VAnchor proofs */ library IdentityVAnchorEncodeInputs { bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; - /** - @notice Proof struct for VAnchor proofs - @param proof The zkSNARK proof data - @param roots The roots on the VAnchor bridge to verify the proof against - @param inputNullifiers The nullifiers of the UTXO - @param outputCommitments The 2 new commitments for the join/split UTXO transaction - @param publicAmount The public amount being deposited to this VAnchor - @param extDataHash The external data hash for the proof verification - */ - struct Proof { - bytes proof; - bytes identityRoots; - bytes vanchorRoots; - bytes32[] inputNullifiers; - bytes32[2] outputCommitments; - uint256 publicAmount; - bytes32 extDataHash; - } - /** @notice Gets the chain id using the chain id opcode */ function getChainId() public view returns (uint) { uint chainId; - assembly { chainId := chainid() } + assembly { + chainId := chainid() + } return chainId; } @@ -60,17 +45,18 @@ library IdentityVAnchorEncodeInputs { @return (bytes, bytes) The public inputs and roots array separated */ function _encodeInputs2( - Proof memory _args, + PublicInputs memory _args, + bytes memory, uint8 _maxEdges - ) public view returns (bytes memory, bytes32[] memory) { + ) public view returns (bytes memory, uint256[] memory) { uint256 _chainId = getChainIdType(); - bytes32[] memory result = new bytes32[](_maxEdges + 1); + uint256[] memory result = new uint256[](_maxEdges + 1); bytes memory encodedInput; if (_maxEdges == 1) { - uint256[11] memory inputs; - bytes32[2] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[2])); - bytes32[2] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[2])); + uint256[11] memory inputs; + uint256[2] memory identityRoots = abi.decode(_args.extensionRoots, (uint256[2])); + uint256[2] memory vanchorRoots = abi.decode(_args.roots, (uint256[2])); // assign roots result[0] = vanchorRoots[0]; result[1] = vanchorRoots[1]; @@ -87,155 +73,10 @@ library IdentityVAnchorEncodeInputs { inputs[9] = uint256(vanchorRoots[0]); inputs[10] = uint256(vanchorRoots[1]); encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 2) { - uint256[13] memory inputs; - bytes32[3] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[3])); - bytes32[3] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[3])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(_chainId); - inputs[4] = uint256(_args.publicAmount); - inputs[5] = uint256(_args.extDataHash); - inputs[6] = uint256(_args.inputNullifiers[0]); - inputs[7] = uint256(_args.inputNullifiers[1]); - inputs[8] = uint256(_args.outputCommitments[0]); - inputs[9] = uint256(_args.outputCommitments[1]); - inputs[10] = uint256(vanchorRoots[0]); - inputs[11] = uint256(vanchorRoots[1]); - inputs[12] = uint256(vanchorRoots[2]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 3) { - uint256[15] memory inputs; - bytes32[4] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[4])); - bytes32[4] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[4])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(_chainId); - inputs[5] = uint256(_args.publicAmount); - inputs[6] = uint256(_args.extDataHash); - inputs[7] = uint256(_args.inputNullifiers[0]); - inputs[8] = uint256(_args.inputNullifiers[1]); - inputs[9] = uint256(_args.outputCommitments[0]); - inputs[10] = uint256(_args.outputCommitments[1]); - inputs[11] = uint256(vanchorRoots[0]); - inputs[12] = uint256(vanchorRoots[1]); - inputs[13] = uint256(vanchorRoots[2]); - inputs[14] = uint256(vanchorRoots[3]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 4) { - uint256[17] memory inputs; - bytes32[5] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[5])); - bytes32[5] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[5])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[4] = uint256(_chainId); - inputs[6] = uint256(_args.publicAmount); - inputs[7] = uint256(_args.extDataHash); - inputs[7] = uint256(_args.inputNullifiers[0]); - inputs[9] = uint256(_args.inputNullifiers[1]); - inputs[10] = uint256(_args.outputCommitments[0]); - inputs[11] = uint256(_args.outputCommitments[1]); - inputs[12] = uint256(vanchorRoots[0]); - inputs[13] = uint256(vanchorRoots[1]); - inputs[14] = uint256(vanchorRoots[2]); - inputs[15] = uint256(vanchorRoots[3]); - inputs[16] = uint256(vanchorRoots[4]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 5) { - uint256[19] memory inputs; - bytes32[6] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[6])); - bytes32[6] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[6])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - result[5] = vanchorRoots[5]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[5] = uint256(identityRoots[5]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(_args.publicAmount); - inputs[8] = uint256(_args.extDataHash); - inputs[9] = uint256(_args.inputNullifiers[0]); - inputs[10] = uint256(_args.inputNullifiers[1]); - inputs[11] = uint256(_args.outputCommitments[0]); - inputs[12] = uint256(_args.outputCommitments[1]); - inputs[13] = uint256(vanchorRoots[0]); - inputs[14] = uint256(vanchorRoots[1]); - inputs[15] = uint256(vanchorRoots[2]); - inputs[16] = uint256(vanchorRoots[3]); - inputs[17] = uint256(vanchorRoots[4]); - inputs[18] = uint256(vanchorRoots[5]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 6) { - uint256[21] memory inputs; - bytes32[7] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[7])); - bytes32[7] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[7])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - result[5] = vanchorRoots[5]; - result[6] = vanchorRoots[6]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[5] = uint256(identityRoots[5]); - inputs[6] = uint256(identityRoots[6]); - inputs[7] = uint256(_chainId); - inputs[8] = uint256(_args.publicAmount); - inputs[9] = uint256(_args.extDataHash); - inputs[10] = uint256(_args.inputNullifiers[0]); - inputs[11] = uint256(_args.inputNullifiers[1]); - inputs[12] = uint256(_args.outputCommitments[0]); - inputs[13] = uint256(_args.outputCommitments[1]); - inputs[14] = uint256(vanchorRoots[0]); - inputs[15] = uint256(vanchorRoots[1]); - inputs[16] = uint256(vanchorRoots[2]); - inputs[17] = uint256(vanchorRoots[3]); - inputs[18] = uint256(vanchorRoots[4]); - inputs[19] = uint256(vanchorRoots[5]); - inputs[20] = uint256(vanchorRoots[6]); - encodedInput = abi.encodePacked(inputs); } else if (_maxEdges == 7) { uint256[23] memory inputs; - bytes32[8] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[8])); - bytes32[8] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[8])); + uint256[8] memory identityRoots = abi.decode(_args.extensionRoots, (uint256[8])); + uint256[8] memory vanchorRoots = abi.decode(_args.roots, (uint256[8])); // assign roots result[0] = vanchorRoots[0]; result[1] = vanchorRoots[1]; @@ -270,8 +111,7 @@ library IdentityVAnchorEncodeInputs { inputs[21] = uint256(vanchorRoots[6]); inputs[22] = uint256(vanchorRoots[7]); encodedInput = abi.encodePacked(inputs); - } - else { + } else { require(false, "Invalid edges"); } @@ -285,17 +125,18 @@ library IdentityVAnchorEncodeInputs { @return (bytes, bytes) The public inputs and roots array separated */ function _encodeInputs16( - Proof memory _args, + PublicInputs memory _args, + bytes memory, uint8 _maxEdges - ) public view returns (bytes memory, bytes32[] memory) { + ) public view returns (bytes memory, uint256[] memory) { uint256 _chainId = getChainIdType(); - bytes32[] memory result = new bytes32[](_maxEdges + 1); + uint256[] memory result = new uint256[](_maxEdges + 1); bytes memory encodedInput; if (_maxEdges == 1) { uint256[25] memory inputs; - bytes32[2] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[2])); - bytes32[2] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[2])); + uint256[2] memory identityRoots = abi.decode(_args.extensionRoots, (uint256[2])); + uint256[2] memory vanchorRoots = abi.decode(_args.roots, (uint256[2])); // assign roots result[0] = vanchorRoots[0]; result[1] = vanchorRoots[1]; @@ -327,228 +168,11 @@ library IdentityVAnchorEncodeInputs { inputs[23] = uint256(vanchorRoots[0]); inputs[24] = uint256(vanchorRoots[1]); encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 2) { - uint256[27] memory inputs; - bytes32[3] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[3])); - bytes32[3] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[3])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(_args.publicAmount); - inputs[4] = uint256(_args.extDataHash); - inputs[5] = uint256(_args.inputNullifiers[0]); - inputs[6] = uint256(_args.inputNullifiers[1]); - inputs[7] = uint256(_args.inputNullifiers[2]); - inputs[8] = uint256(_args.inputNullifiers[3]); - inputs[9] = uint256(_args.inputNullifiers[4]); - inputs[10] = uint256(_args.inputNullifiers[5]); - inputs[11] = uint256(_args.inputNullifiers[6]); - inputs[12] = uint256(_args.inputNullifiers[7]); - inputs[13] = uint256(_args.inputNullifiers[8]); - inputs[14] = uint256(_args.inputNullifiers[9]); - inputs[15] = uint256(_args.inputNullifiers[10]); - inputs[16] = uint256(_args.inputNullifiers[11]); - inputs[17] = uint256(_args.inputNullifiers[12]); - inputs[18] = uint256(_args.inputNullifiers[13]); - inputs[19] = uint256(_args.inputNullifiers[14]); - inputs[20] = uint256(_args.inputNullifiers[15]); - inputs[21] = uint256(_args.outputCommitments[0]); - inputs[22] = uint256(_args.outputCommitments[1]); - inputs[23] = uint256(_chainId); - inputs[24] = uint256(vanchorRoots[0]); - inputs[25] = uint256(vanchorRoots[1]); - inputs[26] = uint256(vanchorRoots[2]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 3) { - uint256[29] memory inputs; - bytes32[4] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[4])); - bytes32[4] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[4])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(_args.publicAmount); - inputs[5] = uint256(_args.extDataHash); - inputs[6] = uint256(_args.inputNullifiers[0]); - inputs[7] = uint256(_args.inputNullifiers[1]); - inputs[8] = uint256(_args.inputNullifiers[2]); - inputs[9] = uint256(_args.inputNullifiers[3]); - inputs[10] = uint256(_args.inputNullifiers[4]); - inputs[11] = uint256(_args.inputNullifiers[5]); - inputs[12] = uint256(_args.inputNullifiers[6]); - inputs[13] = uint256(_args.inputNullifiers[7]); - inputs[14] = uint256(_args.inputNullifiers[8]); - inputs[15] = uint256(_args.inputNullifiers[9]); - inputs[16] = uint256(_args.inputNullifiers[10]); - inputs[17] = uint256(_args.inputNullifiers[11]); - inputs[18] = uint256(_args.inputNullifiers[12]); - inputs[19] = uint256(_args.inputNullifiers[13]); - inputs[20] = uint256(_args.inputNullifiers[14]); - inputs[21] = uint256(_args.inputNullifiers[15]); - inputs[22] = uint256(_args.outputCommitments[0]); - inputs[23] = uint256(_args.outputCommitments[1]); - inputs[24] = uint256(_chainId); - inputs[25] = uint256(vanchorRoots[0]); - inputs[26] = uint256(vanchorRoots[1]); - inputs[27] = uint256(vanchorRoots[2]); - inputs[28] = uint256(vanchorRoots[3]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 4) { - uint256[31] memory inputs; - // assign roots - bytes32[5] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[5])); - bytes32[5] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[5])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[5] = uint256(_args.publicAmount); - inputs[6] = uint256(_args.extDataHash); - inputs[7] = uint256(_args.inputNullifiers[0]); - inputs[8] = uint256(_args.inputNullifiers[1]); - inputs[9] = uint256(_args.inputNullifiers[2]); - inputs[10] = uint256(_args.inputNullifiers[3]); - inputs[11] = uint256(_args.inputNullifiers[4]); - inputs[12] = uint256(_args.inputNullifiers[5]); - inputs[13] = uint256(_args.inputNullifiers[6]); - inputs[14] = uint256(_args.inputNullifiers[7]); - inputs[15] = uint256(_args.inputNullifiers[8]); - inputs[16] = uint256(_args.inputNullifiers[9]); - inputs[17] = uint256(_args.inputNullifiers[10]); - inputs[18] = uint256(_args.inputNullifiers[11]); - inputs[19] = uint256(_args.inputNullifiers[12]); - inputs[20] = uint256(_args.inputNullifiers[13]); - inputs[21] = uint256(_args.inputNullifiers[14]); - inputs[22] = uint256(_args.inputNullifiers[15]); - inputs[23] = uint256(_args.outputCommitments[0]); - inputs[24] = uint256(_args.outputCommitments[1]); - inputs[25] = uint256(_chainId); - inputs[26] = uint256(vanchorRoots[0]); - inputs[27] = uint256(vanchorRoots[1]); - inputs[28] = uint256(vanchorRoots[2]); - inputs[29] = uint256(vanchorRoots[3]); - inputs[30] = uint256(vanchorRoots[4]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 5) { - uint256[33] memory inputs; - // assign input - bytes32[6] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[6])); - bytes32[6] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[6])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - result[5] = vanchorRoots[5]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[5] = uint256(identityRoots[5]); - inputs[6] = uint256(_args.publicAmount); - inputs[7] = uint256(_args.extDataHash); - inputs[8] = uint256(_args.inputNullifiers[0]); - inputs[9] = uint256(_args.inputNullifiers[1]); - inputs[10] = uint256(_args.inputNullifiers[2]); - inputs[11] = uint256(_args.inputNullifiers[3]); - inputs[12] = uint256(_args.inputNullifiers[4]); - inputs[13] = uint256(_args.inputNullifiers[5]); - inputs[14] = uint256(_args.inputNullifiers[6]); - inputs[15] = uint256(_args.inputNullifiers[7]); - inputs[16] = uint256(_args.inputNullifiers[8]); - inputs[17] = uint256(_args.inputNullifiers[9]); - inputs[18] = uint256(_args.inputNullifiers[10]); - inputs[19] = uint256(_args.inputNullifiers[11]); - inputs[20] = uint256(_args.inputNullifiers[12]); - inputs[21] = uint256(_args.inputNullifiers[13]); - inputs[22] = uint256(_args.inputNullifiers[14]); - inputs[23] = uint256(_args.inputNullifiers[15]); - inputs[24] = uint256(_args.outputCommitments[0]); - inputs[25] = uint256(_args.outputCommitments[1]); - inputs[26] = uint256(_chainId); - inputs[27] = uint256(vanchorRoots[0]); - inputs[28] = uint256(vanchorRoots[1]); - inputs[29] = uint256(vanchorRoots[2]); - inputs[30] = uint256(vanchorRoots[3]); - inputs[31] = uint256(vanchorRoots[4]); - inputs[32] = uint256(vanchorRoots[5]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 6) { - uint256[35] memory inputs; - bytes32[7] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[7])); - bytes32[7] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[7])); - // assign roots - result[0] = vanchorRoots[0]; - result[1] = vanchorRoots[1]; - result[2] = vanchorRoots[2]; - result[3] = vanchorRoots[3]; - result[4] = vanchorRoots[4]; - result[5] = vanchorRoots[5]; - result[6] = vanchorRoots[6]; - // assign input - inputs[0] = uint256(identityRoots[0]); - inputs[1] = uint256(identityRoots[1]); - inputs[2] = uint256(identityRoots[2]); - inputs[3] = uint256(identityRoots[3]); - inputs[4] = uint256(identityRoots[4]); - inputs[5] = uint256(identityRoots[5]); - inputs[6] = uint256(identityRoots[6]); - inputs[7] = uint256(_args.publicAmount); - inputs[8] = uint256(_args.extDataHash); - inputs[9] = uint256(_args.inputNullifiers[0]); - inputs[10] = uint256(_args.inputNullifiers[1]); - inputs[11] = uint256(_args.inputNullifiers[2]); - inputs[12] = uint256(_args.inputNullifiers[3]); - inputs[13] = uint256(_args.inputNullifiers[4]); - inputs[14] = uint256(_args.inputNullifiers[5]); - inputs[15] = uint256(_args.inputNullifiers[6]); - inputs[16] = uint256(_args.inputNullifiers[7]); - inputs[17] = uint256(_args.inputNullifiers[8]); - inputs[18] = uint256(_args.inputNullifiers[9]); - inputs[19] = uint256(_args.inputNullifiers[10]); - inputs[20] = uint256(_args.inputNullifiers[11]); - inputs[21] = uint256(_args.inputNullifiers[12]); - inputs[22] = uint256(_args.inputNullifiers[13]); - inputs[23] = uint256(_args.inputNullifiers[14]); - inputs[24] = uint256(_args.inputNullifiers[15]); - inputs[25] = uint256(_args.outputCommitments[0]); - inputs[26] = uint256(_args.outputCommitments[1]); - inputs[27] = uint256(_chainId); - inputs[28] = uint256(vanchorRoots[0]); - inputs[29] = uint256(vanchorRoots[1]); - inputs[30] = uint256(vanchorRoots[2]); - inputs[31] = uint256(vanchorRoots[3]); - inputs[32] = uint256(vanchorRoots[4]); - inputs[33] = uint256(vanchorRoots[5]); - inputs[34] = uint256(vanchorRoots[6]); - encodedInput = abi.encodePacked(inputs); } else if (_maxEdges == 7) { uint256[37] memory inputs; // assign input - bytes32[8] memory identityRoots = abi.decode(_args.identityRoots, (bytes32[8])); - bytes32[8] memory vanchorRoots = abi.decode(_args.vanchorRoots, (bytes32[8])); + uint256[8] memory identityRoots = abi.decode(_args.extensionRoots, (uint256[8])); + uint256[8] memory vanchorRoots = abi.decode(_args.roots, (uint256[8])); // assign roots result[0] = vanchorRoots[0]; result[1] = vanchorRoots[1]; @@ -601,6 +225,6 @@ library IdentityVAnchorEncodeInputs { require(false, "Invalid edges"); } - return (encodedInput, result); + return (encodedInput, result); } } diff --git a/packages/contracts/contracts/libs/MASPVAnchorEncodeInputs.sol b/packages/contracts/contracts/libs/MASPVAnchorEncodeInputs.sol new file mode 100644 index 000000000..f1ea33621 --- /dev/null +++ b/packages/contracts/contracts/libs/MASPVAnchorEncodeInputs.sol @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +import "../structs/PublicInputs.sol"; + +/** + @title MASPVAnchorEncodeInputs library for encoding inputs for MASP VAnchor proofs + */ +library MASPVAnchorEncodeInputs { + bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; + + /** + @notice Gets the chain id using the chain id opcode + */ + function getChainId() public view returns (uint) { + uint chainId; + assembly { + chainId := chainid() + } + return chainId; + } + + /** + @notice Computes the modified chain id using the underlying chain type (EVM) + */ + function getChainIdType() public view returns (uint48) { + // The chain ID and type pair is 6 bytes in length + // The first 2 bytes are reserved for the chain type. + // The last 4 bytes are reserved for a u32 (uint32) chain ID. + bytes4 chainID = bytes4(uint32(getChainId())); + bytes2 chainType = EVM_CHAIN_ID_TYPE; + // We encode the chain ID and type pair into packed bytes which + // should be 6 bytes using the encode packed method. We will + // cast this as a bytes32 in order to encode as a uint256 for zkp verification. + bytes memory chainIdWithType = abi.encodePacked(chainType, chainID); + return uint48(bytes6(chainIdWithType)); + } + + /** + @notice Encodes the proof into its public inputs and roots array for 2 input / 2 output txes + @param _args The proof arguments + @param _maxEdges The maximum # of edges supported by the underlying VAnchor + @return (bytes, bytes) The public inputs and roots array separated + */ + function _encodeInputs2( + PublicInputs memory _args, + bytes memory _auxPublicInputs, + uint8 _maxEdges + ) public view returns (bytes memory, uint256[] memory) { + uint256 _chainId = getChainIdType(); + uint256[] memory result = new uint256[](_maxEdges + 1); + bytes memory encodedInput; + + AuxPublicInputs memory _aux = abi.decode(_auxPublicInputs, (AuxPublicInputs)); + + if (_maxEdges == 1) { + uint256[10] memory inputs; + uint256[2] memory roots = abi.decode(_args.roots, (uint256[2])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_aux.assetID); + inputs[3] = uint256(_args.inputNullifiers[0]); + inputs[4] = uint256(_args.inputNullifiers[1]); + inputs[5] = uint256(_args.outputCommitments[0]); + inputs[6] = uint256(_args.outputCommitments[1]); + inputs[7] = uint256(_chainId); + inputs[8] = uint256(roots[0]); + inputs[9] = uint256(roots[1]); + encodedInput = abi.encodePacked(inputs); + } else if (_maxEdges == 7) { + uint256[16] memory inputs; + uint256[8] memory roots = abi.decode(_args.roots, (uint256[8])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + result[2] = roots[2]; + result[3] = roots[3]; + result[4] = roots[4]; + result[5] = roots[5]; + result[6] = roots[6]; + result[7] = roots[7]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_aux.assetID); + inputs[3] = uint256(_args.inputNullifiers[0]); + inputs[4] = uint256(_args.inputNullifiers[1]); + inputs[5] = uint256(_args.outputCommitments[0]); + inputs[6] = uint256(_args.outputCommitments[1]); + inputs[7] = uint256(_chainId); + inputs[8] = uint256(roots[0]); + inputs[9] = uint256(roots[1]); + inputs[10] = uint256(roots[2]); + inputs[11] = uint256(roots[3]); + inputs[12] = uint256(roots[4]); + inputs[13] = uint256(roots[5]); + inputs[14] = uint256(roots[6]); + inputs[15] = uint256(roots[7]); + encodedInput = abi.encodePacked(inputs); + } else { + require(false, "Invalid edges"); + } + + return (encodedInput, result); + } + + /** + @notice Encodes the proof into its public inputs and roots array for 16 input / 2 output txes + @param _args The proof arguments + @param _maxEdges The maximum # of edges supported by the underlying VAnchor + @return (bytes, bytes) The public inputs and roots array separated + */ + function _encodeInputs16( + PublicInputs memory _args, + bytes memory _auxPublicInputs, + uint8 _maxEdges + ) public view returns (bytes memory, uint256[] memory) { + uint256 _chainId = getChainIdType(); + uint256[] memory result = new uint256[](_maxEdges + 1); + bytes memory encodedInput; + + AuxPublicInputs memory _aux = abi.decode(_auxPublicInputs, (AuxPublicInputs)); + + if (_maxEdges == 1) { + uint256[24] memory inputs; + uint256[2] memory roots = abi.decode(_args.roots, (uint256[2])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + // assign input + //encodedInput = abi.encodePacked(inputs); + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_aux.assetID); + inputs[3] = uint256(_args.inputNullifiers[0]); + inputs[4] = uint256(_args.inputNullifiers[1]); + inputs[5] = uint256(_args.inputNullifiers[2]); + inputs[6] = uint256(_args.inputNullifiers[3]); + inputs[7] = uint256(_args.inputNullifiers[4]); + inputs[8] = uint256(_args.inputNullifiers[5]); + inputs[9] = uint256(_args.inputNullifiers[6]); + inputs[10] = uint256(_args.inputNullifiers[7]); + inputs[11] = uint256(_args.inputNullifiers[8]); + inputs[12] = uint256(_args.inputNullifiers[9]); + inputs[13] = uint256(_args.inputNullifiers[10]); + inputs[14] = uint256(_args.inputNullifiers[11]); + inputs[15] = uint256(_args.inputNullifiers[12]); + inputs[16] = uint256(_args.inputNullifiers[13]); + inputs[17] = uint256(_args.inputNullifiers[14]); + inputs[18] = uint256(_args.inputNullifiers[15]); + inputs[19] = uint256(_args.outputCommitments[0]); + inputs[20] = uint256(_args.outputCommitments[1]); + inputs[21] = uint256(_chainId); + inputs[22] = uint256(roots[0]); + inputs[23] = uint256(roots[1]); + encodedInput = abi.encodePacked(inputs); + } else if (_maxEdges == 7) { + uint256[30] memory inputs; + uint256[8] memory roots = abi.decode(_args.roots, (uint256[8])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + result[2] = roots[2]; + result[3] = roots[3]; + result[4] = roots[4]; + result[5] = roots[5]; + result[6] = roots[6]; + result[7] = roots[7]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_aux.assetID); + inputs[3] = uint256(_args.inputNullifiers[0]); + inputs[4] = uint256(_args.inputNullifiers[1]); + inputs[5] = uint256(_args.inputNullifiers[2]); + inputs[6] = uint256(_args.inputNullifiers[3]); + inputs[7] = uint256(_args.inputNullifiers[4]); + inputs[8] = uint256(_args.inputNullifiers[5]); + inputs[9] = uint256(_args.inputNullifiers[6]); + inputs[10] = uint256(_args.inputNullifiers[7]); + inputs[11] = uint256(_args.inputNullifiers[8]); + inputs[12] = uint256(_args.inputNullifiers[9]); + inputs[13] = uint256(_args.inputNullifiers[10]); + inputs[14] = uint256(_args.inputNullifiers[11]); + inputs[15] = uint256(_args.inputNullifiers[12]); + inputs[16] = uint256(_args.inputNullifiers[13]); + inputs[17] = uint256(_args.inputNullifiers[14]); + inputs[18] = uint256(_args.inputNullifiers[15]); + inputs[19] = uint256(_args.outputCommitments[0]); + inputs[20] = uint256(_args.outputCommitments[1]); + inputs[21] = uint256(_chainId); + inputs[22] = uint256(roots[0]); + inputs[23] = uint256(roots[1]); + inputs[24] = uint256(roots[2]); + inputs[25] = uint256(roots[3]); + inputs[26] = uint256(roots[4]); + inputs[27] = uint256(roots[5]); + inputs[28] = uint256(roots[6]); + inputs[29] = uint256(roots[7]); + encodedInput = abi.encodePacked(inputs); + } else { + require(false, "Invalid edges"); + } + + return (encodedInput, result); + } +} diff --git a/packages/contracts/contracts/libs/VAnchorEncodeInputs.sol b/packages/contracts/contracts/libs/VAnchorEncodeInputs.sol index 995c33185..0df55a8ce 100644 --- a/packages/contracts/contracts/libs/VAnchorEncodeInputs.sol +++ b/packages/contracts/contracts/libs/VAnchorEncodeInputs.sol @@ -3,13 +3,15 @@ pragma solidity ^0.8.0; pragma experimental ABIEncoderV2; +import "../structs/PublicInputs.sol"; + /** @title VAnchorEncodeInputs library for encoding inputs for VAnchor proofs */ library VAnchorEncodeInputs { - bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; + bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; - /** + /** @notice Proof struct for VAnchor proofs @param proof The zkSNARK proof data @param roots The roots on the VAnchor bridge to verify the proof against @@ -18,500 +20,204 @@ library VAnchorEncodeInputs { @param publicAmount The public amount being deposited to this VAnchor @param extDataHash The external data hash for the proof verification */ - struct Proof { - bytes proof; - bytes roots; - bytes32[] inputNullifiers; - bytes32[2] outputCommitments; - uint256 publicAmount; - bytes32 extDataHash; - } + struct Proof { + bytes proof; + bytes roots; + bytes32[] inputNullifiers; + bytes32[2] outputCommitments; + uint256 publicAmount; + bytes32 extDataHash; + } - /** + /** @notice Gets the chain id using the chain id opcode */ - function getChainId() public view returns (uint) { - uint chainId; - assembly { chainId := chainid() } - return chainId; - } + function getChainId() public view returns (uint) { + uint chainId; + assembly { + chainId := chainid() + } + return chainId; + } - /** + /** @notice Computes the modified chain id using the underlying chain type (EVM) */ - function getChainIdType() public view returns (uint48) { - // The chain ID and type pair is 6 bytes in length - // The first 2 bytes are reserved for the chain type. - // The last 4 bytes are reserved for a u32 (uint32) chain ID. - bytes4 chainID = bytes4(uint32(getChainId())); - bytes2 chainType = EVM_CHAIN_ID_TYPE; - // We encode the chain ID and type pair into packed bytes which - // should be 6 bytes using the encode packed method. We will - // cast this as a bytes32 in order to encode as a uint256 for zkp verification. - bytes memory chainIdWithType = abi.encodePacked(chainType, chainID); - return uint48(bytes6(chainIdWithType)); - } + function getChainIdType() public view returns (uint48) { + // The chain ID and type pair is 6 bytes in length + // The first 2 bytes are reserved for the chain type. + // The last 4 bytes are reserved for a u32 (uint32) chain ID. + bytes4 chainID = bytes4(uint32(getChainId())); + bytes2 chainType = EVM_CHAIN_ID_TYPE; + // We encode the chain ID and type pair into packed bytes which + // should be 6 bytes using the encode packed method. We will + // cast this as a bytes32 in order to encode as a uint256 for zkp verification. + bytes memory chainIdWithType = abi.encodePacked(chainType, chainID); + return uint48(bytes6(chainIdWithType)); + } - /** + /** @notice Encodes the proof into its public inputs and roots array for 2 input / 2 output txes @param _args The proof arguments @param _maxEdges The maximum # of edges supported by the underlying VAnchor @return (bytes, bytes) The public inputs and roots array separated */ - function _encodeInputs2( - Proof memory _args, - uint8 _maxEdges - ) public view returns (bytes memory, bytes32[] memory) { - uint256 _chainId = getChainIdType(); - bytes32[] memory result = new bytes32[](_maxEdges + 1); - bytes memory encodedInput; + function _encodeInputs2( + PublicInputs memory _args, + bytes memory, + uint8 _maxEdges + ) public view returns (bytes memory, uint256[] memory) { + uint256 _chainId = getChainIdType(); + uint256[] memory result = new uint256[](_maxEdges + 1); + bytes memory encodedInput; - if (_maxEdges == 1) { - uint256[9] memory inputs; - bytes32[2] memory roots = abi.decode(_args.roots, (bytes32[2])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 2) { - uint256[10] memory inputs; - bytes32[3] memory roots = abi.decode(_args.roots, (bytes32[3])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 3) { - uint256[11] memory inputs; - bytes32[4] memory roots = abi.decode(_args.roots, (bytes32[4])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - inputs[10] = uint256(roots[3]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 4) { - uint256[12] memory inputs; - bytes32[5] memory roots = abi.decode(_args.roots, (bytes32[5])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - inputs[10] = uint256(roots[3]); - inputs[11] = uint256(roots[4]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 5) { - uint256[13] memory inputs; - bytes32[6] memory roots = abi.decode(_args.roots, (bytes32[6])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - inputs[10] = uint256(roots[3]); - inputs[11] = uint256(roots[4]); - inputs[12] = uint256(roots[5]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 6) { - uint256[14] memory inputs; - bytes32[7] memory roots = abi.decode(_args.roots, (bytes32[7])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - inputs[10] = uint256(roots[3]); - inputs[11] = uint256(roots[4]); - inputs[12] = uint256(roots[5]); - inputs[13] = uint256(roots[6]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 7) { - uint256[15] memory inputs; - bytes32[8] memory roots = abi.decode(_args.roots, (bytes32[8])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - result[6] = roots[6]; - result[7] = roots[7]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.outputCommitments[0]); - inputs[5] = uint256(_args.outputCommitments[1]); - inputs[6] = uint256(_chainId); - inputs[7] = uint256(roots[0]); - inputs[8] = uint256(roots[1]); - inputs[9] = uint256(roots[2]); - inputs[10] = uint256(roots[3]); - inputs[11] = uint256(roots[4]); - inputs[12] = uint256(roots[5]); - inputs[13] = uint256(roots[6]); - inputs[14] = uint256(roots[7]); - encodedInput = abi.encodePacked(inputs); - } - else { - require(false, "Invalid edges"); - } + if (_maxEdges == 1) { + uint256[9] memory inputs; + uint256[2] memory roots = abi.decode(_args.roots, (uint256[2])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_args.inputNullifiers[0]); + inputs[3] = uint256(_args.inputNullifiers[1]); + inputs[4] = uint256(_args.outputCommitments[0]); + inputs[5] = uint256(_args.outputCommitments[1]); + inputs[6] = uint256(_chainId); + inputs[7] = uint256(roots[0]); + inputs[8] = uint256(roots[1]); + encodedInput = abi.encodePacked(inputs); + } else if (_maxEdges == 7) { + uint256[15] memory inputs; + uint256[8] memory roots = abi.decode(_args.roots, (uint256[8])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + result[2] = roots[2]; + result[3] = roots[3]; + result[4] = roots[4]; + result[5] = roots[5]; + result[6] = roots[6]; + result[7] = roots[7]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_args.inputNullifiers[0]); + inputs[3] = uint256(_args.inputNullifiers[1]); + inputs[4] = uint256(_args.outputCommitments[0]); + inputs[5] = uint256(_args.outputCommitments[1]); + inputs[6] = uint256(_chainId); + inputs[7] = uint256(roots[0]); + inputs[8] = uint256(roots[1]); + inputs[9] = uint256(roots[2]); + inputs[10] = uint256(roots[3]); + inputs[11] = uint256(roots[4]); + inputs[12] = uint256(roots[5]); + inputs[13] = uint256(roots[6]); + inputs[14] = uint256(roots[7]); + encodedInput = abi.encodePacked(inputs); + } else { + require(false, "Invalid edges"); + } - return (encodedInput, result); - } + return (encodedInput, result); + } - /** + /** @notice Encodes the proof into its public inputs and roots array for 16 input / 2 output txes @param _args The proof arguments @param _maxEdges The maximum # of edges supported by the underlying VAnchor @return (bytes, bytes) The public inputs and roots array separated */ - function _encodeInputs16( - Proof memory _args, - uint8 _maxEdges - ) public view returns (bytes memory, bytes32[] memory) { - uint256 _chainId = getChainIdType(); - bytes32[] memory result = new bytes32[](_maxEdges + 1); - bytes memory encodedInput; + function _encodeInputs16( + PublicInputs memory _args, + bytes memory, + uint8 _maxEdges + ) public view returns (bytes memory, uint256[] memory) { + uint256 _chainId = getChainIdType(); + uint256[] memory result = new uint256[](_maxEdges + 1); + bytes memory encodedInput; - if (_maxEdges == 1) { - uint256[23] memory inputs; - bytes32[2] memory roots = abi.decode(_args.roots, (bytes32[2])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - // assign input - //encodedInput = abi.encodePacked(inputs); - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 2) { - uint256[24] memory inputs; - bytes32[3] memory roots = abi.decode(_args.roots, (bytes32[3])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 3) { - uint256[25] memory inputs; - bytes32[4] memory roots = abi.decode(_args.roots, (bytes32[4])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - inputs[24] = uint256(roots[3]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 4) { - uint256[26] memory inputs; - bytes32[5] memory roots = abi.decode(_args.roots, (bytes32[5])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - inputs[24] = uint256(roots[3]); - inputs[25] = uint256(roots[4]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 5) { - uint256[27] memory inputs; - bytes32[6] memory roots = abi.decode(_args.roots, (bytes32[6])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - inputs[24] = uint256(roots[3]); - inputs[25] = uint256(roots[4]); - inputs[26] = uint256(roots[5]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 6) { - uint256[28] memory inputs; - bytes32[7] memory roots = abi.decode(_args.roots, (bytes32[7])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - result[6] = roots[6]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - inputs[24] = uint256(roots[3]); - inputs[25] = uint256(roots[4]); - inputs[26] = uint256(roots[5]); - inputs[27] = uint256(roots[6]); - encodedInput = abi.encodePacked(inputs); - } else if (_maxEdges == 7) { - uint256[29] memory inputs; - bytes32[8] memory roots = abi.decode(_args.roots, (bytes32[8])); - // assign roots - result[0] = roots[0]; - result[1] = roots[1]; - result[2] = roots[2]; - result[3] = roots[3]; - result[4] = roots[4]; - result[5] = roots[5]; - result[6] = roots[6]; - result[7] = roots[7]; - // assign input - inputs[0] = uint256(_args.publicAmount); - inputs[1] = uint256(_args.extDataHash); - inputs[2] = uint256(_args.inputNullifiers[0]); - inputs[3] = uint256(_args.inputNullifiers[1]); - inputs[4] = uint256(_args.inputNullifiers[2]); - inputs[5] = uint256(_args.inputNullifiers[3]); - inputs[6] = uint256(_args.inputNullifiers[4]); - inputs[7] = uint256(_args.inputNullifiers[5]); - inputs[8] = uint256(_args.inputNullifiers[6]); - inputs[9] = uint256(_args.inputNullifiers[7]); - inputs[10] = uint256(_args.inputNullifiers[8]); - inputs[11] = uint256(_args.inputNullifiers[9]); - inputs[12] = uint256(_args.inputNullifiers[10]); - inputs[13] = uint256(_args.inputNullifiers[11]); - inputs[14] = uint256(_args.inputNullifiers[12]); - inputs[15] = uint256(_args.inputNullifiers[13]); - inputs[16] = uint256(_args.inputNullifiers[14]); - inputs[17] = uint256(_args.inputNullifiers[15]); - inputs[18] = uint256(_args.outputCommitments[0]); - inputs[19] = uint256(_args.outputCommitments[1]); - inputs[20] = uint256(_chainId); - inputs[21] = uint256(roots[0]); - inputs[22] = uint256(roots[1]); - inputs[23] = uint256(roots[2]); - inputs[24] = uint256(roots[3]); - inputs[25] = uint256(roots[4]); - inputs[26] = uint256(roots[5]); - inputs[27] = uint256(roots[6]); - inputs[28] = uint256(roots[7]); - encodedInput = abi.encodePacked(inputs); - } else { - require(false, "Invalid edges"); - } + if (_maxEdges == 1) { + uint256[23] memory inputs; + uint256[2] memory roots = abi.decode(_args.roots, (uint256[2])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + // assign input + //encodedInput = abi.encodePacked(inputs); + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_args.inputNullifiers[0]); + inputs[3] = uint256(_args.inputNullifiers[1]); + inputs[4] = uint256(_args.inputNullifiers[2]); + inputs[5] = uint256(_args.inputNullifiers[3]); + inputs[6] = uint256(_args.inputNullifiers[4]); + inputs[7] = uint256(_args.inputNullifiers[5]); + inputs[8] = uint256(_args.inputNullifiers[6]); + inputs[9] = uint256(_args.inputNullifiers[7]); + inputs[10] = uint256(_args.inputNullifiers[8]); + inputs[11] = uint256(_args.inputNullifiers[9]); + inputs[12] = uint256(_args.inputNullifiers[10]); + inputs[13] = uint256(_args.inputNullifiers[11]); + inputs[14] = uint256(_args.inputNullifiers[12]); + inputs[15] = uint256(_args.inputNullifiers[13]); + inputs[16] = uint256(_args.inputNullifiers[14]); + inputs[17] = uint256(_args.inputNullifiers[15]); + inputs[18] = uint256(_args.outputCommitments[0]); + inputs[19] = uint256(_args.outputCommitments[1]); + inputs[20] = uint256(_chainId); + inputs[21] = uint256(roots[0]); + inputs[22] = uint256(roots[1]); + encodedInput = abi.encodePacked(inputs); + } else if (_maxEdges == 7) { + uint256[29] memory inputs; + uint256[8] memory roots = abi.decode(_args.roots, (uint256[8])); + // assign roots + result[0] = roots[0]; + result[1] = roots[1]; + result[2] = roots[2]; + result[3] = roots[3]; + result[4] = roots[4]; + result[5] = roots[5]; + result[6] = roots[6]; + result[7] = roots[7]; + // assign input + inputs[0] = uint256(_args.publicAmount); + inputs[1] = uint256(_args.extDataHash); + inputs[2] = uint256(_args.inputNullifiers[0]); + inputs[3] = uint256(_args.inputNullifiers[1]); + inputs[4] = uint256(_args.inputNullifiers[2]); + inputs[5] = uint256(_args.inputNullifiers[3]); + inputs[6] = uint256(_args.inputNullifiers[4]); + inputs[7] = uint256(_args.inputNullifiers[5]); + inputs[8] = uint256(_args.inputNullifiers[6]); + inputs[9] = uint256(_args.inputNullifiers[7]); + inputs[10] = uint256(_args.inputNullifiers[8]); + inputs[11] = uint256(_args.inputNullifiers[9]); + inputs[12] = uint256(_args.inputNullifiers[10]); + inputs[13] = uint256(_args.inputNullifiers[11]); + inputs[14] = uint256(_args.inputNullifiers[12]); + inputs[15] = uint256(_args.inputNullifiers[13]); + inputs[16] = uint256(_args.inputNullifiers[14]); + inputs[17] = uint256(_args.inputNullifiers[15]); + inputs[18] = uint256(_args.outputCommitments[0]); + inputs[19] = uint256(_args.outputCommitments[1]); + inputs[20] = uint256(_chainId); + inputs[21] = uint256(roots[0]); + inputs[22] = uint256(roots[1]); + inputs[23] = uint256(roots[2]); + inputs[24] = uint256(roots[3]); + inputs[25] = uint256(roots[4]); + inputs[26] = uint256(roots[5]); + inputs[27] = uint256(roots[6]); + inputs[28] = uint256(roots[7]); + encodedInput = abi.encodePacked(inputs); + } else { + require(false, "Invalid edges"); + } - return (encodedInput, result); - } -} \ No newline at end of file + return (encodedInput, result); + } +} diff --git a/packages/contracts/contracts/mocks/ERC1155Mock.sol b/packages/contracts/contracts/mocks/ERC1155Mock.sol index 10dcc5466..5abd3013c 100644 --- a/packages/contracts/contracts/mocks/ERC1155Mock.sol +++ b/packages/contracts/contracts/mocks/ERC1155Mock.sol @@ -4,12 +4,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; contract ERC1155Mock is ERC1155("token/{id}.json") { - function mint( - address to, - uint256 id, - uint256 amount, - bytes memory data - ) public { - _mint(to, id, amount, data); - } -} \ No newline at end of file + function mint(address to, uint256 id, uint256 amount, bytes memory data) public { + _mint(to, id, amount, data); + } +} diff --git a/packages/contracts/contracts/mocks/ERC20Mock.sol b/packages/contracts/contracts/mocks/ERC20Mock.sol index fdb4a4b45..205202a05 100644 --- a/packages/contracts/contracts/mocks/ERC20Mock.sol +++ b/packages/contracts/contracts/mocks/ERC20Mock.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract ERC20Mock is ERC20("DAIMock", "DAIM") { - function mint(address account, uint256 amount) public { - _mint(account, amount); - } -} \ No newline at end of file + function mint(address account, uint256 amount) public { + _mint(account, amount); + } +} diff --git a/packages/contracts/contracts/mocks/ERC721Mock.sol b/packages/contracts/contracts/mocks/ERC721Mock.sol index bc209e421..b7da5fade 100644 --- a/packages/contracts/contracts/mocks/ERC721Mock.sol +++ b/packages/contracts/contracts/mocks/ERC721Mock.sol @@ -5,13 +5,13 @@ import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract ERC721Mintable is ERC721 { - using Counters for Counters.Counter; - Counters.Counter private _tokenId; + using Counters for Counters.Counter; + Counters.Counter private _tokenId; - constructor(string memory name, string memory symbol) ERC721(name, symbol) {} + constructor(string memory name, string memory symbol) ERC721(name, symbol) {} - function mint(address account) public { - _tokenId.increment(); - _mint(account, _tokenId.current()); - } -} \ No newline at end of file + function mint(address account) public { + _tokenId.increment(); + _mint(account, _tokenId.current()); + } +} diff --git a/packages/contracts/contracts/mocks/LinkableAnchorMock.sol b/packages/contracts/contracts/mocks/LinkableAnchorMock.sol index 92b70432d..26f2ddfb7 100644 --- a/packages/contracts/contracts/mocks/LinkableAnchorMock.sol +++ b/packages/contracts/contracts/mocks/LinkableAnchorMock.sol @@ -8,48 +8,56 @@ pragma solidity ^0.8.0; import "../anchors/LinkableAnchor.sol"; import "../interfaces/verifiers/IAnchorVerifier.sol"; import "../interfaces/verifiers/ISetVerifier.sol"; +import "../trees/MerkleTree.sol"; -contract LinkableAnchorMock is LinkableAnchor, ISetVerifier{ - constructor( - address _handler, - IAnchorVerifier _verifier, - IHasher _hasher, - uint32 _merkleTreeHeight, - uint8 _maxEdges - ) LinkableAnchor(_handler, _hasher, _merkleTreeHeight, _maxEdges) { - require(address(_verifier) != address(0), "Verifier address cannot be 0"); - return; - } - - function setHandler( - address _handler, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - handler = _handler; - return; - } - - function setVerifier( - address _verifier, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - _verifier = _verifier; - return; - } - - function configureMinimalWithdrawalLimit( - uint256 _minimalWithdrawalAmount, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - _minimalWithdrawalAmount + _minimalWithdrawalAmount; - return; - } - - function configureMaximumDepositLimit( - uint256 _maximumDepositAmount, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - _maximumDepositAmount + _maximumDepositAmount; - return; - } +contract LinkableAnchorMock is MerkleTree, LinkableAnchor, ISetVerifier { + constructor( + address _handler, + IAnchorVerifier _verifier, + IHasher _hasher, + uint32 _merkleTreeHeight, + uint8 _maxEdges + ) + LinkableAnchor(_handler, _merkleTreeHeight, _maxEdges) + MerkleTree(_merkleTreeHeight, _hasher) + { + require(address(_verifier) != address(0), "Verifier address cannot be 0"); + return; + } + + function initialize() external onlyUninitialized { + super._initialize(); + } + + function setHandler( + address _handler, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + handler = _handler; + return; + } + + function setVerifier( + address _verifier, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + _verifier = _verifier; + return; + } + + function configureMinimalWithdrawalLimit( + uint256 _minimalWithdrawalAmount, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + _minimalWithdrawalAmount + _minimalWithdrawalAmount; + return; + } + + function configureMaximumDepositLimit( + uint256 _maximumDepositAmount, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + _maximumDepositAmount + _maximumDepositAmount; + return; + } } diff --git a/packages/contracts/contracts/mocks/MerkleForestMock.sol b/packages/contracts/contracts/mocks/MerkleForestMock.sol index 2dd302ccd..c6be38c0f 100644 --- a/packages/contracts/contracts/mocks/MerkleForestMock.sol +++ b/packages/contracts/contracts/mocks/MerkleForestMock.sol @@ -5,19 +5,25 @@ import "../trees/MerkleForest.sol"; import "../hashers/IHasher.sol"; contract MerkleForestMock is MerkleForest { - constructor(uint32 _forestLevels, uint32 _subtreeLevels, IHasher _hasher) MerkleForest(_forestLevels, _subtreeLevels, _hasher) {} + constructor( + uint32 _forestLevels, + uint32 _subtreeLevels, + IHasher _hasher + ) MerkleForest(_forestLevels, _subtreeLevels, _hasher) {} - function insert(bytes32 _leaf) public { - _insert(_leaf); - } - function insertTwoTest(bytes32 _leaf1, bytes32 _leaf2) public { - _insertTwo(_leaf1, _leaf2); - } - function insertTest(bytes32 _leaf) public { - _insert(_leaf); - } - function insertSubtreeTest(uint32 _subtreeId, bytes32 _leaf) public { - _insertSubtree(_subtreeId, _leaf); - } + function insert(uint256 _leaf) public { + _insert(_leaf); + } + function insertTwoTest(uint256 _leaf1, uint256 _leaf2) public { + _insertTwo(_leaf1, _leaf2); + } + + function insertTest(uint256 _leaf) public { + _insert(_leaf); + } + + function insertSubtreeTest(uint32 _subtreeId, uint256 _leaf) public { + _insertSubtree(_subtreeId, _leaf); + } } diff --git a/packages/contracts/contracts/mocks/MerkleTreePoseidonMock.sol b/packages/contracts/contracts/mocks/MerkleTreePoseidonMock.sol index 5778f3e73..ce4f5a681 100644 --- a/packages/contracts/contracts/mocks/MerkleTreePoseidonMock.sol +++ b/packages/contracts/contracts/mocks/MerkleTreePoseidonMock.sol @@ -5,9 +5,9 @@ import "../trees/MerkleTree.sol"; import "../hashers/IHasher.sol"; contract MerkleTreePoseidonMock is MerkleTree { - constructor(uint32 _treeLevels, IHasher _hasher) MerkleTree(_treeLevels, _hasher) {} + constructor(uint32 _treeLevels, IHasher _hasher) MerkleTree(_treeLevels, _hasher) {} - function insert(bytes32 _leaf) public { - _insert(_leaf); - } -} \ No newline at end of file + function insert(uint256 _leaf) public { + _insert(_leaf); + } +} diff --git a/packages/contracts/contracts/structs/Edge.sol b/packages/contracts/contracts/structs/Edge.sol index 3557ebd38..a98c8f927 100644 --- a/packages/contracts/contracts/structs/Edge.sol +++ b/packages/contracts/contracts/structs/Edge.sol @@ -6,15 +6,15 @@ pragma solidity ^0.8.0; /** - @dev The Edge struct is used to store the edge data for linkable tree connections. - @param chainId The chain id where the LinkableAnchor contract being linked is located. - @param root The latest merkle root of the LinkableAnchor contract being linked. - @param nonce The latest leaf insertion index of the LinkableAnchor contract being linked. - @param srcResourceID The contract address or tree identifier of the LinkableAnchor being linked. - */ + @dev The Edge struct is used to store the edge data for linkable tree connections. + @param chainId The chain id where the LinkableTree contract being linked is located. + @param root The latest merkle root of the LinkableTree contract being linked. + @param nonce The latest leaf insertion index of the LinkableTree contract being linked. + @param srcResourceID The contract address or tree identifier of the LinkableTree being linked. +*/ struct Edge { uint256 chainID; - bytes32 root; + uint256 root; uint256 latestLeafIndex; bytes32 srcResourceID; -} \ No newline at end of file +} diff --git a/packages/contracts/contracts/structs/MultiAssetExtData.sol b/packages/contracts/contracts/structs/MultiAssetExtData.sol index 6062f4107..d127575f5 100644 --- a/packages/contracts/contracts/structs/MultiAssetExtData.sol +++ b/packages/contracts/contracts/structs/MultiAssetExtData.sol @@ -6,7 +6,7 @@ pragma solidity ^0.8.0; struct ExtData { - uint256 assetId; + uint256 assetID; address recipient; int256 extAmount; address relayer; @@ -15,4 +15,4 @@ struct ExtData { address token; bytes encryptedOutput1; bytes encryptedOutput2; -} \ No newline at end of file +} diff --git a/packages/contracts/contracts/structs/PublicInputs.sol b/packages/contracts/contracts/structs/PublicInputs.sol new file mode 100644 index 000000000..8103a719d --- /dev/null +++ b/packages/contracts/contracts/structs/PublicInputs.sol @@ -0,0 +1,49 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +struct CommonExtData { + address recipient; + int256 extAmount; + address relayer; + uint256 fee; + uint256 refund; + address token; +} + +/** + @notice Public input struct for VAnchor proofs + @param roots The roots on the VAnchor commitment trees + @param extensionRoots The extra roots for extension VAnchors such as IdentityVAnchor + @param inputNullifiers The nullifiers of the UTXO records + @param outputCommitments The 2 new commitments for the join/split UTXO transaction + @param publicAmount The public amount being deposited to this VAnchor + @param extDataHash The external data hash for the proof verification +*/ +struct PublicInputs { + bytes roots; + bytes extensionRoots; + uint256[] inputNullifiers; + uint256[2] outputCommitments; + uint256 publicAmount; + uint256 extDataHash; +} + +/** + @notice Auxiliary public input struct made up of deserializable values + @param assetID the public asset ID of the asset being deposited or withdrawn + */ +struct AuxPublicInputs { + uint256 assetID; +} + +/** + @notice External encryptions for new output commitments + */ +struct Encryptions { + bytes encryptedOutput1; + bytes encryptedOutput2; +} diff --git a/packages/contracts/contracts/structs/SingleAssetExtData.sol b/packages/contracts/contracts/structs/SingleAssetExtData.sol index 0b3ae2171..0552a14d0 100644 --- a/packages/contracts/contracts/structs/SingleAssetExtData.sol +++ b/packages/contracts/contracts/structs/SingleAssetExtData.sol @@ -14,4 +14,4 @@ struct ExtData { address token; bytes encryptedOutput1; bytes encryptedOutput2; -} \ No newline at end of file +} diff --git a/packages/contracts/contracts/tokens/AaveTokenWrapper.sol b/packages/contracts/contracts/tokens/AaveTokenWrapper.sol index 90b55dab3..e686a200b 100644 --- a/packages/contracts/contracts/tokens/AaveTokenWrapper.sol +++ b/packages/contracts/contracts/tokens/AaveTokenWrapper.sol @@ -8,62 +8,61 @@ pragma solidity ^0.8.0; import "../interfaces/tokens/IAaveTokenWrapper.sol"; import "./FungibleTokenWrapper.sol"; import "../interfaces/external/aave/IAaveLendingPool.sol"; -import "hardhat/console.sol"; /** @title An AaveTokenWrapper system that deposits/withdraws into Aave lending pools @author Webb Technologies. */ contract AaveTokenWrapper is FungibleTokenWrapper, IAaveTokenWrapper { - using SafeMath for uint256; - IAaveLendingPool public aaveLendingPool; + using SafeMath for uint256; + IAaveLendingPool public aaveLendingPool; - /** + /** @notice AaveTokenWrapper constructor @param _name The name of the ERC20 TokenWrapper @param _symbol The symbol of the ERC20 TokenWrapper */ - constructor( - string memory _name, - string memory _symbol, - address _aaveLendingPool - ) FungibleTokenWrapper(_name, _symbol) { - aaveLendingPool = IAaveLendingPool(_aaveLendingPool); - } + constructor( + string memory _name, + string memory _symbol, + address _aaveLendingPool + ) FungibleTokenWrapper(_name, _symbol) { + aaveLendingPool = IAaveLendingPool(_aaveLendingPool); + } - /** + /** @notice AaveTokenWrapper initializer @param _feeRecipient The recipient for fees from wrapping @param _governor The address of the governor @param _limit The maximum amount of tokens that can be wrapped @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function initialize( - address _feeRecipient, - address _governor, - uint256 _limit, - bool _isNativeAllowed, - address _aaveLendingPool - ) public { - require(!initialized, "Contract already initialized"); - feeRecipient = payable(_feeRecipient); - wrappingLimit = _limit; - isNativeAllowed = _isNativeAllowed; - initialized = true; - aaveLendingPool = IAaveLendingPool(_aaveLendingPool); - } + function initialize( + address _feeRecipient, + address _governor, + uint256 _limit, + bool _isNativeAllowed, + address _aaveLendingPool + ) public { + require(!initialized, "Contract already initialized"); + feeRecipient = payable(_feeRecipient); + wrappingLimit = _limit; + isNativeAllowed = _isNativeAllowed; + initialized = true; + aaveLendingPool = IAaveLendingPool(_aaveLendingPool); + } - /// @inheritdoc IAaveTokenWrapper - function deposit(address _tokenAddress, uint256 _amount) external override { - IERC20(_tokenAddress).approve(address(aaveLendingPool), _amount); - aaveLendingPool.deposit(_tokenAddress, _amount, address(this), 0); - } + /// @inheritdoc IAaveTokenWrapper + function deposit(address _tokenAddress, uint256 _amount) external override { + IERC20(_tokenAddress).approve(address(aaveLendingPool), _amount); + aaveLendingPool.deposit(_tokenAddress, _amount, address(this), 0); + } - /// @inheritdoc IAaveTokenWrapper - function withdraw(address _tokenAddress, uint256 _amount) external override { - uint256 tokenBalance = IERC20(_tokenAddress).balanceOf(address(this)); - aaveLendingPool.withdraw(_tokenAddress, _amount, address(this)); - uint256 redeemed = IERC20(_tokenAddress).balanceOf(address(this)) - tokenBalance; - require(redeemed >= _amount, "Invalid withdraw"); - } + /// @inheritdoc IAaveTokenWrapper + function withdraw(address _tokenAddress, uint256 _amount) external override { + uint256 tokenBalance = IERC20(_tokenAddress).balanceOf(address(this)); + aaveLendingPool.withdraw(_tokenAddress, _amount, address(this)); + uint256 redeemed = IERC20(_tokenAddress).balanceOf(address(this)) - tokenBalance; + require(redeemed >= _amount, "Invalid withdraw"); + } } diff --git a/packages/contracts/contracts/tokens/FungibleTokenWrapper.sol b/packages/contracts/contracts/tokens/FungibleTokenWrapper.sol index 91b5baef1..65ff37a50 100644 --- a/packages/contracts/contracts/tokens/FungibleTokenWrapper.sol +++ b/packages/contracts/contracts/tokens/FungibleTokenWrapper.sol @@ -17,29 +17,31 @@ import "../utils/ProposalNonceTracker.sol"; sets fees for wrapping into itself. This contract is intended to be used with TokenHandler contract. */ -contract FungibleTokenWrapper is TokenWrapper, Initialized, IFungibleTokenWrapper, ProposalNonceTracker { - using SafeMath for uint256; - - address public handler; - address[] public tokens; - address[] public historicalTokens; - mapping (address => bool) valid; - mapping (address => bool) historicallyValid; - - bool public isNativeAllowed; - uint256 public wrappingLimit; - - /** +contract FungibleTokenWrapper is + TokenWrapper, + Initialized, + IFungibleTokenWrapper, + ProposalNonceTracker +{ + using SafeMath for uint256; + + address public handler; + address[] public tokens; + address[] public historicalTokens; + mapping(address => bool) valid; + mapping(address => bool) historicallyValid; + + bool public isNativeAllowed; + uint256 public wrappingLimit; + + /** @notice FungibleTokenWrapper constructor @param _name The name of the ERC20 TokenWrapper @param _symbol The symbol of the ERC20 TokenWrapper */ - constructor( - string memory _name, - string memory _symbol - ) TokenWrapper(_name, _symbol) {} + constructor(string memory _name, string memory _symbol) TokenWrapper(_name, _symbol) {} - /** + /** @notice FungibleTokenWrapper initializer @param _feePercentage The fee percentage for wrapping @param _feeRecipient The recipient for fees from wrapping. @@ -47,184 +49,192 @@ contract FungibleTokenWrapper is TokenWrapper, Initialized, IFungibleTokenWrappe @param _limit The maximum amount of tokens that can be wrapped @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function initialize( - uint16 _feePercentage, - address _feeRecipient, - address _handler, - uint256 _limit, - bool _isNativeAllowed - ) public onlyUninitialized { - initialized = true; - feePercentage = _feePercentage; - feeRecipient = payable(_feeRecipient); - handler = _handler; - wrappingLimit = _limit; - isNativeAllowed = _isNativeAllowed; - } - - /** + function initialize( + uint16 _feePercentage, + address _feeRecipient, + address _handler, + uint256 _limit, + bool _isNativeAllowed + ) public onlyUninitialized { + initialized = true; + feePercentage = _feePercentage; + feeRecipient = payable(_feeRecipient); + handler = _handler; + wrappingLimit = _limit; + isNativeAllowed = _isNativeAllowed; + } + + /** @notice Sets the handler of the FungibleTokenWrapper contract @param _handler The address of the new handler @notice Only the handler can call this function */ - function setHandler(address _handler) public onlyHandler { - handler = _handler; - } + function setHandler(address _handler) public onlyHandler { + handler = _handler; + } - /** + /** @notice Sets whether native tokens are allowed to be wrapped @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped @notice Only the handler can call this function */ - function setNativeAllowed(bool _isNativeAllowed) public onlyHandler { - isNativeAllowed = _isNativeAllowed; - } + function setNativeAllowed(bool _isNativeAllowed) public onlyHandler { + isNativeAllowed = _isNativeAllowed; + } - /** + /** @notice Adds a token at `_tokenAddress` to the FungibleTokenWrapper's wrapping list @param _tokenAddress The address of the token to be added @param _nonce The nonce tracking updates to this contract @notice Only the handler can call this function */ - function add( - address _tokenAddress, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - require(!valid[_tokenAddress], "FungibleTokenWrapper: Token should not be valid"); - tokens.push(_tokenAddress); - - if (!historicallyValid[_tokenAddress]) { - historicalTokens.push(_tokenAddress); - historicallyValid[_tokenAddress] = true; - } - valid[_tokenAddress] = true; - } - - /** + function add( + address _tokenAddress, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require(!valid[_tokenAddress], "FungibleTokenWrapper: Token should not be valid"); + tokens.push(_tokenAddress); + + if (!historicallyValid[_tokenAddress]) { + historicalTokens.push(_tokenAddress); + historicallyValid[_tokenAddress] = true; + } + valid[_tokenAddress] = true; + } + + /** @notice Removes a token at `_tokenAddress` from the FungibleTokenWrapper's wrapping list @param _tokenAddress The address of the token to be removed @param _nonce The nonce tracking updates to this contract @notice Only the handler can call this function */ - function remove( - address _tokenAddress, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - require(valid[_tokenAddress], "FungibleTokenWrapper: Token should be valid"); - uint index = 0; - for (uint i = 0; i < tokens.length; i++) { - if (tokens[i] == _tokenAddress) { - index = i; - break; - } - } - require(index < tokens.length, "FungibleTokenWrapper: Token not found"); - valid[_tokenAddress] = false; - removeTokenAtIndex(index); - } - - /** + function remove( + address _tokenAddress, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require(valid[_tokenAddress], "FungibleTokenWrapper: Token should be valid"); + uint index = 0; + for (uint i = 0; i < tokens.length; i++) { + if (tokens[i] == _tokenAddress) { + index = i; + break; + } + } + require(index < tokens.length, "FungibleTokenWrapper: Token not found"); + valid[_tokenAddress] = false; + removeTokenAtIndex(index); + } + + /** @notice Sets a new `_feePercentage` for the FungibleTokenWrapper @param _feePercentage The new fee percentage @param _nonce The nonce tracking updates to this contract @notice Only the handler can call this function */ - function setFee( - uint16 _feePercentage, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - require(0 <= _feePercentage && _feePercentage <= 10_000, "FungibleTokenWrapper: Invalid fee percentage"); - feePercentage = _feePercentage; - } - - /** + function setFee( + uint16 _feePercentage, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require( + 0 <= _feePercentage && _feePercentage <= 10_000, + "FungibleTokenWrapper: Invalid fee percentage" + ); + feePercentage = _feePercentage; + } + + /** @notice Sets a new `_feeRecipient` for the FungibleTokenWrapper @param _feeRecipient The new fee recipient @param _nonce The nonce tracking updates to this contract @notice Only the handler can call this function */ - function setFeeRecipient( - address payable _feeRecipient, - uint32 _nonce - ) override external onlyHandler onlyIncrementingByOne(_nonce) { - require(_feeRecipient != address(0), "FungibleTokenWrapper: Fee Recipient cannot be zero address"); - feeRecipient = _feeRecipient; - } - - /** + function setFeeRecipient( + address payable _feeRecipient, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require( + _feeRecipient != address(0), + "FungibleTokenWrapper: Fee Recipient cannot be zero address" + ); + feeRecipient = _feeRecipient; + } + + /** @notice Removes a token at `_index` from the FungibleTokenWrapper's wrapping list @param _index The index of the token to be removed */ - function removeTokenAtIndex(uint _index) internal { - tokens[_index] = tokens[tokens.length-1]; - tokens.pop(); - } + function removeTokenAtIndex(uint _index) internal { + tokens[_index] = tokens[tokens.length - 1]; + tokens.pop(); + } - /** + /** @notice Updates the `_limit` of tokens that can be wrapped @param _limit The new limit of tokens that can be wrapped @notice Only the handler can call this function */ - function updateLimit(uint256 _limit) public onlyHandler { - wrappingLimit = _limit; - } + function updateLimit(uint256 _limit) public onlyHandler { + wrappingLimit = _limit; + } - /** + /** @notice Gets the current fee percentage @return uint16 The fee percentage */ - function getFee() view external returns (uint16) { - return feePercentage; - } + function getFee() external view returns (uint16) { + return feePercentage; + } - /** + /** @notice Checks if the token at `tokenAddress` is valid (i.e. if it's in the wrapping list) @return bool Whether or not the token is valid */ - function _isValidAddress(address tokenAddress) override internal virtual returns (bool) { - return valid[tokenAddress]; - } - - /** + function _isValidAddress(address tokenAddress) internal view virtual override returns (bool) { + return valid[tokenAddress]; + } + + /** @notice Checks if the token at `tokenAddress` is historically valid (i.e. if it was in the wrapping list at any point in history). @param _tokenAddress The address of the token to be checked @return bool Whether or not the token is historically valid */ - function _isValidHistoricalAddress(address _tokenAddress) override internal virtual returns (bool) { - return historicallyValid[_tokenAddress]; - } + function _isValidHistoricalAddress( + address _tokenAddress + ) internal view virtual override returns (bool) { + return historicallyValid[_tokenAddress]; + } - /** + /** @notice Checks if an amount of the underlying token can be wrapped or if the limit has been reached @param _amount The amount of the underlying token to be wrapped @return bool Whether or not the amount can be wrapped */ - function _isValidAmount(uint256 _amount) override internal virtual returns (bool) { - return _amount + this.totalSupply() <= wrappingLimit; - } + function _isValidAmount(uint256 _amount) internal view virtual override returns (bool) { + return _amount + this.totalSupply() <= wrappingLimit; + } - /** + /** @notice Checks if the native token is allowed to be wrapped @return bool Whether or not the native token is allowed to be wrapped */ - function _isNativeValid() override internal virtual returns (bool) { - return isNativeAllowed; - } + function _isNativeValid() internal view virtual override returns (bool) { + return isNativeAllowed; + } - /** + /** @notice Gets the currently available wrappable tokens by their addresses @return address[] The currently available wrappable token addresses */ - function getTokens() external view returns (address[] memory) { - return tokens; - } + function getTokens() external view returns (address[] memory) { + return tokens; + } - /** + /** @notice Modifier for enforcing that the caller is the handler */ - modifier onlyHandler() { - require(msg.sender == handler, "FungibleTokenWrapper: Only handler can call this function"); - _; - } + modifier onlyHandler() { + require(msg.sender == handler, "FungibleTokenWrapper: Only handler can call this function"); + _; + } } diff --git a/packages/contracts/contracts/tokens/MultiFungibleTokenManager.sol b/packages/contracts/contracts/tokens/MultiFungibleTokenManager.sol index e68958566..c55f670b7 100644 --- a/packages/contracts/contracts/tokens/MultiFungibleTokenManager.sol +++ b/packages/contracts/contracts/tokens/MultiFungibleTokenManager.sol @@ -14,9 +14,9 @@ import "./MultiTokenManagerBase.sol"; @author Webb Technologies. */ contract MultiFungibleTokenManager is MultiTokenManagerBase { - using SafeMath for uint256; + using SafeMath for uint256; - /** + /** @notice Registers a new token and deploys the FungibleTokenWrapper contract @param _handler The address of the token handler contract @param _name The name of the ERC20 @@ -26,44 +26,41 @@ contract MultiFungibleTokenManager is MultiTokenManagerBase { @param _feePercentage The fee percentage for wrapping @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function registerToken( - address _handler, - string memory _name, - string memory _symbol, - bytes32 _salt, - uint256 _limit, - uint16 _feePercentage, - bool _isNativeAllowed - ) override external onlyRegistry onlyInitialized returns (address) { - FungibleTokenWrapper token = new FungibleTokenWrapper{salt: _salt}( - _name, - _symbol - ); + function registerToken( + address _handler, + string memory _name, + string memory _symbol, + bytes32 _salt, + uint256 _limit, + uint16 _feePercentage, + bool _isNativeAllowed + ) external override onlyRegistry onlyInitialized returns (address) { + FungibleTokenWrapper token = new FungibleTokenWrapper{ salt: _salt }(_name, _symbol); - token.initialize( - _feePercentage, - payable(masterFeeRecipient), - _handler, - _limit, - _isNativeAllowed - ); + token.initialize( + _feePercentage, + payable(masterFeeRecipient), + _handler, + _limit, + _isNativeAllowed + ); - wrappedTokens.push(address(token)); - return address(token); - } + wrappedTokens.push(address(token)); + return address(token); + } - /** + /** Registers an NFT token */ - function registerNftToken( - address, - string memory, - bytes32 - ) override public view onlyRegistry onlyInitialized returns (address) { - revert(); - } + function registerNftToken( + address, + string memory, + bytes32 + ) public view override onlyRegistry onlyInitialized returns (address) { + revert(); + } - function isFungible() override public pure returns (bool) { - return true; - } + function isFungible() public pure override returns (bool) { + return true; + } } diff --git a/packages/contracts/contracts/tokens/MultiNftTokenManager.sol b/packages/contracts/contracts/tokens/MultiNftTokenManager.sol index e79b40598..a9fa76ecb 100644 --- a/packages/contracts/contracts/tokens/MultiNftTokenManager.sol +++ b/packages/contracts/contracts/tokens/MultiNftTokenManager.sol @@ -14,34 +14,34 @@ import "./MultiTokenManagerBase.sol"; @author Webb Technologies. */ contract MultiNftTokenManager is MultiTokenManagerBase { - using SafeMath for uint256; - - function registerToken( - address, - string memory, - string memory, - bytes32, - uint256, - uint16, - bool - ) override public view onlyRegistry onlyInitialized returns (address) { - revert(); - } - - function registerNftToken( - address _handler, - string memory _uri, - bytes32 _salt - ) override external onlyRegistry onlyInitialized returns (address) { - NftTokenWrapper nftWrapper = new NftTokenWrapper{salt: _salt}(_uri); - - nftWrapper.initialize(_handler); - - wrappedTokens.push(address(nftWrapper)); - return address(nftWrapper); - } - - function isFungible() override public pure returns (bool) { - return false; - } + using SafeMath for uint256; + + function registerToken( + address, + string memory, + string memory, + bytes32, + uint256, + uint16, + bool + ) public view override onlyRegistry onlyInitialized returns (address) { + revert(); + } + + function registerNftToken( + address _handler, + string memory _uri, + bytes32 _salt + ) external override onlyRegistry onlyInitialized returns (address) { + NftTokenWrapper nftWrapper = new NftTokenWrapper{ salt: _salt }(_uri); + + nftWrapper.initialize(_handler); + + wrappedTokens.push(address(nftWrapper)); + return address(nftWrapper); + } + + function isFungible() public pure override returns (bool) { + return false; + } } diff --git a/packages/contracts/contracts/tokens/MultiTokenManagerBase.sol b/packages/contracts/contracts/tokens/MultiTokenManagerBase.sol index e5694bd7e..7dd9ab0f7 100644 --- a/packages/contracts/contracts/tokens/MultiTokenManagerBase.sol +++ b/packages/contracts/contracts/tokens/MultiTokenManagerBase.sol @@ -15,54 +15,60 @@ import "../interfaces/tokens/IMultiTokenManager.sol"; @author Webb Technologies. */ abstract contract MultiTokenManagerBase is IMultiTokenManager, Initialized, ProposalNonceTracker { - using SafeMath for uint256; - address public registry; - address public masterFeeRecipient; - address[] public wrappedTokens; + using SafeMath for uint256; + address public registry; + address public masterFeeRecipient; + address[] public wrappedTokens; - function initialize( - address _registry, - address _feeRecipient - ) external override onlyUninitialized { - initialized = true; - registry = _registry; - masterFeeRecipient = _feeRecipient; - } + function initialize( + address _registry, + address _feeRecipient + ) external override onlyUninitialized { + initialized = true; + registry = _registry; + masterFeeRecipient = _feeRecipient; + } - /** + /** @notice Sets the registry */ - function setRegistry(address _registry) onlyInitialized external { - require(msg.sender == registry, "MultiTokenManager: Only registry can set registry"); - registry = _registry; - } + function setRegistry(address _registry) external onlyInitialized { + require(msg.sender == registry, "MultiTokenManager: Only registry can set registry"); + registry = _registry; + } - /** + /** @notice Sets the master fee recipient */ - function setMasterFeeRecipient(address _feeRecipient) onlyInitialized external { - require(msg.sender == masterFeeRecipient, "MultiTokenManager: Only registry can set master fee recipient"); - masterFeeRecipient = _feeRecipient; - } + function setMasterFeeRecipient(address _feeRecipient) external onlyInitialized { + require( + msg.sender == masterFeeRecipient, + "MultiTokenManager: Only registry can set master fee recipient" + ); + masterFeeRecipient = _feeRecipient; + } - /** + /** @notice Gets the currently available wrappable tokens by their addresses @return address[] The currently available wrappable token addresses */ - function getWrappedTokens() external view returns (address[] memory) { - return wrappedTokens; - } + function getWrappedTokens() external view returns (address[] memory) { + return wrappedTokens; + } - /** + /** @notice A flag used to separate between fungible and non-fungible token managers */ - function isFungible() public virtual returns (bool); + function isFungible() public virtual returns (bool); - /** + /** @notice Modifier for enforcing that the caller is the governor */ - modifier onlyRegistry() { - require(msg.sender == registry, "MultiTokenManagerBase: Only registry can call this function"); - _; - } + modifier onlyRegistry() { + require( + msg.sender == registry, + "MultiTokenManagerBase: Only registry can call this function" + ); + _; + } } diff --git a/packages/contracts/contracts/tokens/NftTokenWrapper.sol b/packages/contracts/contracts/tokens/NftTokenWrapper.sol index 4a3c8b06a..ea7aae0ce 100644 --- a/packages/contracts/contracts/tokens/NftTokenWrapper.sol +++ b/packages/contracts/contracts/tokens/NftTokenWrapper.sol @@ -17,194 +17,216 @@ import "../utils/ProposalNonceTracker.sol"; @title A MultiTokenManager manages FungibleTokenWrapper systems using an external `governor` address @author Webb Technologies. */ -contract NftTokenWrapper is ERC1155, ERC1155Receiver, IERC721Receiver, Initialized, ProposalNonceTracker { - using SafeMath for uint256; - address public handler; +contract NftTokenWrapper is + ERC1155, + ERC1155Receiver, + IERC721Receiver, + Initialized, + ProposalNonceTracker +{ + using SafeMath for uint256; + address public handler; - constructor(string memory _uri) ERC1155(_uri) {} + constructor(string memory _uri) ERC1155(_uri) {} - /** + /** @notice Initializes the contract @param _handler The address of the token handler contract */ - function initialize(address _handler) onlyUninitialized external { - initialized = true; - handler = _handler; - } + function initialize(address _handler) external onlyUninitialized { + initialized = true; + handler = _handler; + } - function wrap721(uint256 _tokenId, address _tokenContract) external { - IERC721(_tokenContract).safeTransferFrom(msg.sender, address(this), _tokenId); - } + function wrap721(uint256 _tokenId, address _tokenContract) external { + IERC721(_tokenContract).safeTransferFrom(msg.sender, address(this), _tokenId); + } - function unwrap721(uint256 _tokenId, address _tokenContract) external { - // Ensure msg.sender is the owner of the wrapped token - require(balanceOf(msg.sender, _tokenId) == 1, "NftTokenWrapper: Not the owner of the token"); - // Ensure this contract is the owner of the token - require(IERC721(_tokenContract).ownerOf(_tokenId) == address(this), "NftTokenWrapper: Not the owner of the wrapped token"); - IERC721(_tokenContract).safeTransferFrom(address(this), msg.sender, _tokenId); - _burn(msg.sender, _tokenId, 1); - } + function unwrap721(uint256 _tokenId, address _tokenContract) external { + // Ensure msg.sender is the owner of the wrapped token + require( + balanceOf(msg.sender, _tokenId) == 1, + "NftTokenWrapper: Not the owner of the token" + ); + // Ensure this contract is the owner of the token + require( + IERC721(_tokenContract).ownerOf(_tokenId) == address(this), + "NftTokenWrapper: Not the owner of the wrapped token" + ); + IERC721(_tokenContract).safeTransferFrom(address(this), msg.sender, _tokenId); + _burn(msg.sender, _tokenId, 1); + } - function wrap1155(uint256 _tokenId, address _tokenContract) external { - IERC1155(_tokenContract).safeTransferFrom(msg.sender, address(this), _tokenId, 1, ""); - } + function wrap1155(uint256 _tokenId, address _tokenContract) external { + IERC1155(_tokenContract).safeTransferFrom(msg.sender, address(this), _tokenId, 1, ""); + } - function unwrap1155(uint256 _tokenId, address _tokenContract) external { - // Ensure msg.sender is the owner of the wrapped token - require(balanceOf(msg.sender, _tokenId) == 1, "NftTokenWrapper: Not the owner of the token"); - // Ensure this contract is the owner of the token - require(IERC1155(_tokenContract).balanceOf(address(this), _tokenId) == 1, "NftTokenWrapper: Not the owner of the wrapped token"); - IERC1155(_tokenContract).safeTransferFrom(address(this), msg.sender, _tokenId, 1, ""); - _burn(msg.sender, _tokenId, 1); - } + function unwrap1155(uint256 _tokenId, address _tokenContract) external { + // Ensure msg.sender is the owner of the wrapped token + require( + balanceOf(msg.sender, _tokenId) == 1, + "NftTokenWrapper: Not the owner of the token" + ); + // Ensure this contract is the owner of the token + require( + IERC1155(_tokenContract).balanceOf(address(this), _tokenId) == 1, + "NftTokenWrapper: Not the owner of the wrapped token" + ); + IERC1155(_tokenContract).safeTransferFrom(address(this), msg.sender, _tokenId, 1, ""); + _burn(msg.sender, _tokenId, 1); + } - /** - * @dev Hook that is called before any token transfer. This includes minting - * and burning, as well as batched variants. - * - * The same hook is called on both single and batched variants. For single - * transfers, the length of the `ids` and `amounts` arrays will be 1. - * - * Calling conditions (for each `id` and `amount` pair): - * - * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * of token type `id` will be transferred to `to`. - * - When `from` is zero, `amount` tokens of token type `id` will be minted - * for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` - * will be burned. - * - `from` and `to` are never both zero. - * - `ids` and `amounts` have the same, non-zero length. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer( - address operator, - address from, - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) override internal virtual {} + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `ids` and `amounts` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override {} - /** - * @dev Hook that is called after any token transfer. This includes minting - * and burning, as well as batched variants. - * - * The same hook is called on both single and batched variants. For single - * transfers, the length of the `id` and `amount` arrays will be 1. - * - * Calling conditions (for each `id` and `amount` pair): - * - * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * of token type `id` will be transferred to `to`. - * - When `from` is zero, `amount` tokens of token type `id` will be minted - * for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` - * will be burned. - * - `from` and `to` are never both zero. - * - `ids` and `amounts` have the same, non-zero length. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _afterTokenTransfer( - address operator, - address from, - address to, - uint256[] memory ids, - uint256[] memory amounts, - bytes memory data - ) override internal virtual {} + /** + * @dev Hook that is called after any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override {} - /** - * @dev Handles the receipt of a single ERC1155 token type. This function is - * called at the end of a `safeTransferFrom` after the balance has been updated. - * - * NOTE: To accept the transfer, this must return - * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` - * (i.e. 0xf23a6e61, or its own function selector). - * - * @param operator The address which initiated the transfer (i.e. msg.sender) - * @param from The address which previously owned the token - * @param id The ID of the token being transferred - * @param value The amount of tokens being transferred - * @param data Additional data with no specified format - * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed - */ - function onERC1155Received( - address operator, - address from, - uint256 id, - uint256 value, - bytes calldata data - ) override external returns (bytes4) { - _mint(from, id, value, data); - return this.onERC1155Received.selector; - } + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external override returns (bytes4) { + _mint(from, id, value, data); + return this.onERC1155Received.selector; + } - /** - * @dev Handles the receipt of a multiple ERC1155 token types. This function - * is called at the end of a `safeBatchTransferFrom` after the balances have - * been updated. - * - * NOTE: To accept the transfer(s), this must return - * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` - * (i.e. 0xbc197c81, or its own function selector). - * - * @param operator The address which initiated the batch transfer (i.e. msg.sender) - * @param from The address which previously owned the token - * @param ids An array containing ids of each token being transferred (order and length must match values array) - * @param values An array containing amounts of each token being transferred (order and length must match ids array) - * @param data Additional data with no specified format - * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed - */ - function onERC1155BatchReceived( - address operator, - address from, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) override external returns (bytes4) { - for (uint256 i = 0; i < ids.length; i++) { - _mint(from, ids[i], values[i], data); - } - return this.onERC1155BatchReceived.selector; - } + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external override returns (bytes4) { + for (uint256 i = 0; i < ids.length; i++) { + _mint(from, ids[i], values[i], data); + } + return this.onERC1155BatchReceived.selector; + } - /** - * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} - * by `operator` from `from`, this function is called. - * - * It must return its Solidity selector to confirm the token transfer. - * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. - * - * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. - */ - function onERC721Received( - address operator, - address from, - uint256 tokenId, - bytes calldata data - ) override external returns (bytes4) { - _mint(from, tokenId, 1, data); - return this.onERC721Received.selector; - } + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external override returns (bytes4) { + _mint(from, tokenId, 1, data); + return this.onERC721Received.selector; + } - /** - * @dev Implementation of the {IERC165} interface. - * - * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check - * for the additional interface id that will be supported. For example: - * - * ```solidity - * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); - * } - * ``` - * - * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. - */ - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC1155Receiver) returns (bool) { - return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); - } + /** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC1155, ERC1155Receiver) returns (bool) { + return + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } } diff --git a/packages/contracts/contracts/tokens/Registry.sol b/packages/contracts/contracts/tokens/Registry.sol index 094091109..0024473b0 100644 --- a/packages/contracts/contracts/tokens/Registry.sol +++ b/packages/contracts/contracts/tokens/Registry.sol @@ -18,54 +18,44 @@ import "../interfaces/tokens/IMultiTokenManager.sol"; @author Webb Technologies. */ contract Registry is Initialized, IRegistry, ProposalNonceTracker { - using SafeMath for uint256; + using SafeMath for uint256; - address public fungibleTokenManager; - address public nonFungibleTokenManager; + address public fungibleTokenManager; + address public nonFungibleTokenManager; - address public registryHandler; - address public masterFeeRecipient; - address public maspVAnchor; + address public registryHandler; + address public masterFeeRecipient; + address public maspVAnchor; - mapping (address => uint256) public wrappedAssetToId; - mapping (uint256 => address) public idToWrappedAsset; + mapping(address => uint256) public wrappedAssetToId; + mapping(uint256 => address) public idToWrappedAsset; - event TokenRegistered( - address indexed token, - address indexed handler, - uint256 indexed assetId - ); + event TokenRegistered(address indexed token, address indexed handler, uint256 indexed assetId); - constructor() { - registryHandler = msg.sender; - masterFeeRecipient = msg.sender; - } + constructor() { + registryHandler = msg.sender; + masterFeeRecipient = msg.sender; + } - function initialize( - address _fungibleTokenManager, - address _nonFungibleTokenManager, - address _handler, - address _masterFeeRecipient, - address _maspVAnchor - ) external onlyUninitialized { - initialized = true; - fungibleTokenManager = _fungibleTokenManager; - nonFungibleTokenManager = _nonFungibleTokenManager; - registryHandler = _handler; - masterFeeRecipient = _masterFeeRecipient; - maspVAnchor = _maspVAnchor; + function initialize( + address _fungibleTokenManager, + address _nonFungibleTokenManager, + address _handler, + address _masterFeeRecipient, + address _maspVAnchor + ) external onlyUninitialized { + initialized = true; + fungibleTokenManager = _fungibleTokenManager; + nonFungibleTokenManager = _nonFungibleTokenManager; + registryHandler = _handler; + masterFeeRecipient = _masterFeeRecipient; + maspVAnchor = _maspVAnchor; - IMultiTokenManager(_fungibleTokenManager).initialize( - address(this), - _masterFeeRecipient - ); - IMultiTokenManager(_nonFungibleTokenManager).initialize( - address(this), - _masterFeeRecipient - ); - } + IMultiTokenManager(_fungibleTokenManager).initialize(address(this), _masterFeeRecipient); + IMultiTokenManager(_nonFungibleTokenManager).initialize(address(this), _masterFeeRecipient); + } - /** + /** @notice Registers a new token and deploys the FungibleTokenWrapper contract @param _nonce The nonce of the proposal @param _tokenHandler The address of the token handler contract @@ -77,35 +67,37 @@ contract Registry is Initialized, IRegistry, ProposalNonceTracker { @param _feePercentage The fee percentage for wrapping @param _isNativeAllowed Whether or not native tokens are allowed to be wrapped */ - function registerToken( - uint32 _nonce, - address _tokenHandler, - uint256 _assetIdentifier, - string memory _name, - string memory _symbol, - bytes32 _salt, - uint256 _limit, - uint16 _feePercentage, - bool _isNativeAllowed - ) override external onlyHandler onlyInitialized onlyIncrementingByOne(_nonce) { - require(_assetIdentifier != 0, "Registry: Asset identifier cannot be 0"); - require(idToWrappedAsset[_assetIdentifier] == address(0x0), "Registry: Asset already registered"); - address token = IMultiTokenManager(fungibleTokenManager) - .registerToken( - _tokenHandler, - _name, - _symbol, - _salt, - _limit, - _feePercentage, - _isNativeAllowed - ); - emit TokenRegistered(token, _tokenHandler, _assetIdentifier); - idToWrappedAsset[_assetIdentifier] = token; - wrappedAssetToId[token] = _assetIdentifier; - } + function registerToken( + uint32 _nonce, + address _tokenHandler, + uint256 _assetIdentifier, + string memory _name, + string memory _symbol, + bytes32 _salt, + uint256 _limit, + uint16 _feePercentage, + bool _isNativeAllowed + ) external override onlyHandler onlyInitialized onlyIncrementingByOne(_nonce) { + require(_assetIdentifier != 0, "Registry: Asset identifier cannot be 0"); + require( + idToWrappedAsset[_assetIdentifier] == address(0x0), + "Registry: Asset already registered" + ); + address token = IMultiTokenManager(fungibleTokenManager).registerToken( + _tokenHandler, + _name, + _symbol, + _salt, + _limit, + _feePercentage, + _isNativeAllowed + ); + emit TokenRegistered(token, _tokenHandler, _assetIdentifier); + idToWrappedAsset[_assetIdentifier] = token; + wrappedAssetToId[token] = _assetIdentifier; + } - /** + /** @notice Registers a new NFT token and deploys the NftTokenWrapper contract @param _nonce The nonce of the proposal @param _tokenHandler The address of the token handler contract @@ -113,47 +105,49 @@ contract Registry is Initialized, IRegistry, ProposalNonceTracker { @param _uri The uri for the wrapped NFT @param _salt Salt used for matching addresses across chain using CREATE2 */ - function registerNftToken( - uint32 _nonce, - address _tokenHandler, - uint256 _assetIdentifier, - string memory _uri, - bytes32 _salt - ) override external onlyHandler onlyInitialized onlyIncrementingByOne(_nonce) { - require(_assetIdentifier != 0, "Registry: Asset identifier cannot be 0"); - require(idToWrappedAsset[_assetIdentifier] == address(0x0), "Registry: Asset already registered"); - address token = IMultiTokenManager(nonFungibleTokenManager) - .registerNftToken( - _tokenHandler, - _uri, - _salt - ); - emit TokenRegistered(token, _tokenHandler, _assetIdentifier); - idToWrappedAsset[_assetIdentifier] = token; - wrappedAssetToId[token] = _assetIdentifier; - } + function registerNftToken( + uint32 _nonce, + address _tokenHandler, + uint256 _assetIdentifier, + string memory _uri, + bytes32 _salt + ) external override onlyHandler onlyInitialized onlyIncrementingByOne(_nonce) { + require(_assetIdentifier != 0, "Registry: Asset identifier cannot be 0"); + require( + idToWrappedAsset[_assetIdentifier] == address(0x0), + "Registry: Asset already registered" + ); + address token = IMultiTokenManager(nonFungibleTokenManager).registerNftToken( + _tokenHandler, + _uri, + _salt + ); + emit TokenRegistered(token, _tokenHandler, _assetIdentifier); + idToWrappedAsset[_assetIdentifier] = token; + wrappedAssetToId[token] = _assetIdentifier; + } - /** + /** @notice Fetches the address for an asset ID @param _assetId The asset ID */ - function getAssetAddress(uint256 _assetId) override external view returns (address) { - return idToWrappedAsset[_assetId]; - } + function getAssetAddress(uint256 _assetId) external view override returns (address) { + return idToWrappedAsset[_assetId]; + } - /** + /** @notice Fetches the asset ID for an address @param _address The address */ - function getAssetId(address _address) override external view returns (uint256) { - return wrappedAssetToId[_address]; - } + function getAssetId(address _address) external view override returns (uint256) { + return wrappedAssetToId[_address]; + } - /** + /** @notice Modifier for enforcing that the caller is the governor */ - modifier onlyHandler() { - require(msg.sender == registryHandler, "Only governor can call this function"); - _; - } + modifier onlyHandler() { + require(msg.sender == registryHandler, "Only governor can call this function"); + _; + } } diff --git a/packages/contracts/contracts/tokens/TokenWrapper.sol b/packages/contracts/contracts/tokens/TokenWrapper.sol index b9beff400..68b9fa992 100644 --- a/packages/contracts/contracts/tokens/TokenWrapper.sol +++ b/packages/contracts/contracts/tokens/TokenWrapper.sol @@ -18,252 +18,258 @@ import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; @notice This contract is intended to be used with TokenHandler/FungibleToken contract. */ abstract contract TokenWrapper is ERC20PresetMinterPauser, ITokenWrapper { - using SafeMath for uint256; - uint16 public feePercentage; - address payable public feeRecipient; + using SafeMath for uint256; + uint16 public feePercentage; + address payable public feeRecipient; - /** + /** @notice TokenWrapper constructor @param _name The name of the ERC20 @param _symbol The symbol of the ERC20 */ - constructor(string memory _name, string memory _symbol) - ERC20PresetMinterPauser(_name, _symbol) - {} + constructor( + string memory _name, + string memory _symbol + ) ERC20PresetMinterPauser(_name, _symbol) {} - /** + /** @notice Get the fee for a target amount to wrap @param _amountToWrap The amount to wrap @return uint The fee amount of the token being wrapped */ - function getFeeFromAmount(uint256 _amountToWrap) public view override returns (uint256) { - return _amountToWrap.mul(feePercentage).div(10000); - } + function getFeeFromAmount(uint256 _amountToWrap) public view override returns (uint256) { + return _amountToWrap.mul(feePercentage).div(10000); + } - /** + /** @notice Get the amount to wrap for a target `_deposit` amount @param _deposit The deposit amount @return uint The amount to wrap conditioned on the deposit amount */ - function getAmountToWrap(uint256 _deposit) public view override returns (uint256) { - return _deposit.mul(10000).div(10000 - feePercentage); - } + function getAmountToWrap(uint256 _deposit) public view override returns (uint256) { + return _deposit.mul(10000).div(10000 - feePercentage); + } - /** + /** @notice Used to wrap tokens on behalf of a sender. Must be called by a minter role. @param tokenAddress Address of ERC20 to transfer. @param amount Amount of tokens to transfer. */ - function wrap(address tokenAddress, uint256 amount) - public - payable - override - isValidWrapping(tokenAddress, feeRecipient, amount) - { - uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); + function wrap( + address tokenAddress, + uint256 amount + ) public payable override isValidWrapping(tokenAddress, feeRecipient, amount) { + uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); - uint256 leftover = tokenAddress == address(0) - ? uint256(msg.value).sub(costToWrap) - : amount.sub(costToWrap); + uint256 leftover = tokenAddress == address(0) + ? uint256(msg.value).sub(costToWrap) + : amount.sub(costToWrap); - if (tokenAddress == address(0)) { - // mint the native value sent to the contract - _mint(_msgSender(), leftover); + if (tokenAddress == address(0)) { + // mint the native value sent to the contract + _mint(_msgSender(), leftover); - // transfer costToWrap to the feeRecipient - feeRecipient.transfer(costToWrap); - } else { - // transfer liquidity to the token wrapper - IERC20(tokenAddress).transferFrom(_msgSender(), address(this), leftover); - // transfer fee (costToWrap) to the feeRecipient - IERC20(tokenAddress).transferFrom(_msgSender(), feeRecipient, costToWrap); - // mint the wrapped token for the sender - _mint(_msgSender(), leftover); - } - } + // transfer costToWrap to the feeRecipient + feeRecipient.transfer(costToWrap); + } else { + // transfer liquidity to the token wrapper + IERC20(tokenAddress).transferFrom(_msgSender(), address(this), leftover); + // transfer fee (costToWrap) to the feeRecipient + IERC20(tokenAddress).transferFrom(_msgSender(), feeRecipient, costToWrap); + // mint the wrapped token for the sender + _mint(_msgSender(), leftover); + } + } - /** + /** @notice Used to unwrap/burn the wrapper token on behalf of a sender. @param tokenAddress Address of ERC20 to unwrap into. @param amount Amount of tokens to burn. */ - function unwrap(address tokenAddress, uint256 amount) - public - override - isValidUnwrapping(tokenAddress, amount) - { - // burn wrapped token from sender - _burn(_msgSender(), amount); - // unwrap liquidity and send to the sender - if (tokenAddress == address(0)) { - // transfer native liquidity from the token wrapper to the sender - payable(msg.sender).transfer(amount); - } else { - // transfer ERC20 liquidity from the token wrapper to the sender - IERC20(tokenAddress).transfer(_msgSender(), amount); - } - } + function unwrap( + address tokenAddress, + uint256 amount + ) public override isValidUnwrapping(tokenAddress, amount) { + // burn wrapped token from sender + _burn(_msgSender(), amount); + // unwrap liquidity and send to the sender + if (tokenAddress == address(0)) { + // transfer native liquidity from the token wrapper to the sender + payable(msg.sender).transfer(amount); + } else { + // transfer ERC20 liquidity from the token wrapper to the sender + IERC20(tokenAddress).transfer(_msgSender(), amount); + } + } - /** + /** @notice Used to unwrap/burn the wrapper token on behalf of a sender. @param tokenAddress Address of ERC20 to unwrap into. @param amount Amount of tokens to burn. */ - function unwrapAndSendTo( - address tokenAddress, - uint256 amount, - address recipient - ) public override isValidUnwrapping(tokenAddress, amount) { - // burn wrapped token from sender - _burn(_msgSender(), amount); - // unwrap liquidity and send to the sender - if (tokenAddress == address(0)) { - // transfer native liquidity from the token wrapper to the sender - payable(recipient).transfer(amount); - } else { - // transfer ERC20 liquidity from the token wrapper to the sender - IERC20(tokenAddress).transfer(recipient, amount); - } - } + function unwrapAndSendTo( + address tokenAddress, + uint256 amount, + address recipient + ) public override isValidUnwrapping(tokenAddress, amount) { + // burn wrapped token from sender + _burn(_msgSender(), amount); + // unwrap liquidity and send to the sender + if (tokenAddress == address(0)) { + // transfer native liquidity from the token wrapper to the sender + payable(recipient).transfer(amount); + } else { + // transfer ERC20 liquidity from the token wrapper to the sender + IERC20(tokenAddress).transfer(recipient, amount); + } + } - /** + /** @notice Used to wrap tokens on behalf of a sender @param sender Address of sender where assets are sent from. @param tokenAddress Address of ERC20 to transfer. @param amount Amount of tokens to transfer. */ - function wrapFor( - address sender, - address tokenAddress, - uint256 amount - ) public payable override isMinter isValidWrapping(tokenAddress, feeRecipient, amount) { - uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); - uint256 leftover = tokenAddress == address(0) - ? uint256(msg.value).sub(costToWrap) - : amount.sub(costToWrap); - if (tokenAddress == address(0)) { - // transfer fee (costToWrap) to feeRecipient - feeRecipient.transfer(costToWrap); - } else { - // transfer liquidity to the token wrapper - IERC20(tokenAddress).transferFrom(sender, address(this), leftover); - // transfer fee (costToWrap) to feeRecipient - IERC20(tokenAddress).transferFrom(sender, feeRecipient, costToWrap); - } - // mint the wrapped token for the sender - _mint(sender, leftover); - } + function wrapFor( + address sender, + address tokenAddress, + uint256 amount + ) public payable override isMinter isValidWrapping(tokenAddress, feeRecipient, amount) { + uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); + uint256 leftover = tokenAddress == address(0) + ? uint256(msg.value).sub(costToWrap) + : amount.sub(costToWrap); + if (tokenAddress == address(0)) { + // transfer fee (costToWrap) to feeRecipient + feeRecipient.transfer(costToWrap); + } else { + // transfer liquidity to the token wrapper + IERC20(tokenAddress).transferFrom(sender, address(this), leftover); + // transfer fee (costToWrap) to feeRecipient + IERC20(tokenAddress).transferFrom(sender, feeRecipient, costToWrap); + } + // mint the wrapped token for the sender + _mint(sender, leftover); + } - /** + /** @notice Used to wrap tokens on behalf of a sender and mint to a potentially different address @param sender Address of sender where assets are sent from. @param tokenAddress Address of ERC20 to transfer. @param amount Amount of tokens to transfer. @param recipient Recipient of the wrapped tokens. */ - function wrapForAndSendTo( - address sender, - address tokenAddress, - uint256 amount, - address recipient - ) public payable override isMinter isValidWrapping(tokenAddress, feeRecipient, amount) { - uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); - uint256 leftover = tokenAddress == address(0) - ? uint256(msg.value).sub(costToWrap) - : amount.sub(costToWrap); - if (tokenAddress == address(0)) { - // transfer fee (costToWrap) to feeRecipient - feeRecipient.transfer(costToWrap); - } else { - // transfer liquidity to the token wrapper - IERC20(tokenAddress).transferFrom(sender, address(this), leftover); - // transfer fee (costToWrap) to feeRecipient - IERC20(tokenAddress).transferFrom(sender, feeRecipient, costToWrap); - } - // mint the wrapped token for the recipient - _mint(recipient, leftover); - } + function wrapForAndSendTo( + address sender, + address tokenAddress, + uint256 amount, + address recipient + ) public payable override isMinter isValidWrapping(tokenAddress, feeRecipient, amount) { + uint256 costToWrap = getFeeFromAmount(tokenAddress == address(0) ? msg.value : amount); + uint256 leftover = tokenAddress == address(0) + ? uint256(msg.value).sub(costToWrap) + : amount.sub(costToWrap); + if (tokenAddress == address(0)) { + // transfer fee (costToWrap) to feeRecipient + feeRecipient.transfer(costToWrap); + } else { + // transfer liquidity to the token wrapper + IERC20(tokenAddress).transferFrom(sender, address(this), leftover); + // transfer fee (costToWrap) to feeRecipient + IERC20(tokenAddress).transferFrom(sender, feeRecipient, costToWrap); + } + // mint the wrapped token for the recipient + _mint(recipient, leftover); + } - /** + /** @notice Used to unwrap/burn the wrapper token. @param sender The address that the caller is unwrapping for @param tokenAddress Address of ERC20 to unwrap into. @param amount Amount of tokens to burn. */ - function unwrapFor( - address sender, - address tokenAddress, - uint256 amount - ) public override isMinter isValidUnwrapping(tokenAddress, amount) { - // burn wrapped token from sender - _burn(sender, amount); - if (tokenAddress == address(0)) { - payable(sender).transfer(amount); - } else { - // transfer liquidity from the token wrapper to the sender - IERC20(tokenAddress).transfer(sender, amount); - } - } + function unwrapFor( + address sender, + address tokenAddress, + uint256 amount + ) public override isMinter isValidUnwrapping(tokenAddress, amount) { + // burn wrapped token from sender + _burn(sender, amount); + if (tokenAddress == address(0)) { + payable(sender).transfer(amount); + } else { + // transfer liquidity from the token wrapper to the sender + IERC20(tokenAddress).transfer(sender, amount); + } + } - /** @dev this function is defined in a child contract */ - function _isValidAddress(address tokenAddress) internal virtual returns (bool); + function isValidToken(address tokenAddress) public view override returns (bool) { + if (tokenAddress == address(0)) { + return _isNativeValid(); + } else { + return _isValidAddress(tokenAddress); + } + } - /** @dev this function is defined in a child contract */ - function _isValidHistoricalAddress(address tokenAddress) internal virtual returns (bool); + /** @dev this function is defined in a child contract */ + function _isValidAddress(address tokenAddress) internal view virtual returns (bool); - /** @dev this function is defined in a child contract */ - function _isNativeValid() internal virtual returns (bool); + /** @dev this function is defined in a child contract */ + function _isValidHistoricalAddress(address tokenAddress) internal view virtual returns (bool); - /** @dev this function is defined in a child contract */ - function _isValidAmount(uint256 amount) internal virtual returns (bool); + /** @dev this function is defined in a child contract */ + function _isNativeValid() internal view virtual returns (bool); - modifier isMinter() { - require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role"); - _; - } + /** @dev this function is defined in a child contract */ + function _isValidAmount(uint256 amount) internal view virtual returns (bool); - /** + modifier isMinter() { + require(hasRole(MINTER_ROLE, msg.sender), "ERC20PresetMinterPauser: must have minter role"); + _; + } + + /** @notice Modifier to check if the wrapping is valid @param _tokenAddress The token address to wrap from @param _feeRecipient The fee recipient for the wrapping fee @param _amount The amount of tokens to wrap */ - modifier isValidWrapping( - address _tokenAddress, - address _feeRecipient, - uint256 _amount - ) { - if (_tokenAddress == address(0)) { - require(_amount == 0, "Invalid amount provided for native wrapping"); - require(_isNativeValid(), "Native wrapping is not allowed for this token wrapper"); - } else { - require(msg.value == 0, "Invalid value sent for wrapping"); - require(_isValidAddress(_tokenAddress), "Invalid token address"); - } + modifier isValidWrapping( + address _tokenAddress, + address _feeRecipient, + uint256 _amount + ) { + if (_tokenAddress == address(0)) { + require(_amount == 0, "Invalid amount provided for native wrapping"); + require(_isNativeValid(), "Native wrapping is not allowed for this token wrapper"); + } else { + require(msg.value == 0, "Invalid value sent for wrapping"); + require(_isValidAddress(_tokenAddress), "Invalid token address"); + } - require(_feeRecipient != address(0), "Fee Recipient cannot be zero address"); + require(_feeRecipient != address(0), "Fee Recipient cannot be zero address"); - require(_isValidAmount(_amount), "Invalid token amount"); - _; - } + require(_isValidAmount(_amount), "Invalid token amount"); + _; + } - /** + /** @notice Modifier to check if the unwrapping is valid @param _tokenAddress The token address to unwrap into @param _amount The amount of tokens to unwrap */ - modifier isValidUnwrapping(address _tokenAddress, uint256 _amount) { - if (_tokenAddress == address(0)) { - require(address(this).balance >= _amount, "Insufficient native balance"); - require(_isNativeValid(), "Native unwrapping is not allowed for this token wrapper"); - } else { - require( - IERC20(_tokenAddress).balanceOf(address(this)) >= _amount, - "Insufficient ERC20 balance" - ); - require(_isValidHistoricalAddress(_tokenAddress), "Invalid historical token address"); - } + modifier isValidUnwrapping(address _tokenAddress, uint256 _amount) { + if (_tokenAddress == address(0)) { + require(address(this).balance >= _amount, "Insufficient native balance"); + require(_isNativeValid(), "Native unwrapping is not allowed for this token wrapper"); + } else { + require( + IERC20(_tokenAddress).balanceOf(address(this)) >= _amount, + "Insufficient ERC20 balance" + ); + require(_isValidHistoricalAddress(_tokenAddress), "Invalid historical token address"); + } - _; - } + _; + } } diff --git a/packages/contracts/contracts/trees/LinkableIncrementalBinaryTree.sol b/packages/contracts/contracts/trees/LinkableIncrementalBinaryTree.sol index 9f018f57f..5ac0b003e 100644 --- a/packages/contracts/contracts/trees/LinkableIncrementalBinaryTree.sol +++ b/packages/contracts/contracts/trees/LinkableIncrementalBinaryTree.sol @@ -1,434 +1,334 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import {PoseidonT3} from "../hashers/Poseidon.sol"; - -/** - @dev The Edge struct is used to store the edge data for linkable tree connections. - @param chainId The chain id where the LinkableTree contract being linked is located. - @param root The latest merkle root of the LinkableTree contract being linked. - @param nonce The latest leaf insertion index of the LinkableTree contract being linked. - @param target The contract address or tree identifier of the LinkableTree being linked. -*/ -struct Edge { - uint256 chainID; - uint256 root; - uint256 latestLeafIndex; - bytes32 srcResourceID; -} +import { PoseidonT3 } from "../hashers/Poseidon.sol"; +import "../structs/Edge.sol"; // Each incremental tree has certain properties and data that will // be used to add new leaves. struct LinkableIncrementalTreeData { - uint8 maxEdges; - uint256 depth; // Depth of the tree (levels - 1). - uint32 currentRootIndex; - mapping(uint256 => uint256) roots; - uint32 numberOfLeaves; // Number of leaves of the tree. - // The nodes of the subtrees used in the last addition of a leaf (level -> [left node, right node]). - mapping(uint256 => uint256[2]) lastSubtrees; // Caching these values is essential to efficient appends. - // Maps sourceChainID to the index in the edge list - mapping(uint256 => uint256) edgeIndex; - mapping(uint256 => bool) edgeExistsForChain; - Edge[] edgeList; - // Map to store chainID => (rootIndex => root) to track neighbor histories - mapping(uint256 => mapping(uint32 => uint256)) neighborRoots; - // Map to store the current historical root index for a chainID - mapping(uint256 => uint32) currentNeighborRootIndex; + uint8 maxEdges; + uint256 depth; // Depth of the tree (levels - 1). + uint32 currentRootIndex; + mapping(uint256 => uint256) roots; + uint32 numberOfLeaves; // Number of leaves of the tree. + // The nodes of the subtrees used in the last addition of a leaf (level -> [left node, right node]). + mapping(uint256 => uint256[2]) lastSubtrees; // Caching these values is essential to efficient appends. + // Maps sourceChainID to the index in the edge list + mapping(uint256 => uint256) edgeIndex; + mapping(uint256 => bool) edgeExistsForChain; + Edge[] edgeList; + // Map to store chainID => (rootIndex => root) to track neighbor histories + mapping(uint256 => mapping(uint32 => uint256)) neighborRoots; + // Map to store the current historical root index for a chainID + mapping(uint256 => uint32) currentNeighborRootIndex; } /// @title Linkable Incremental binary Merkle tree. /// @dev The linkable incremental tree allows to calculate the root hash each time a leaf is added, ensuring /// the integrity of the tree. library LinkableIncrementalBinaryTree { - // Historical roots - bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; - uint32 internal constant ROOT_HISTORY_SIZE = 30; - uint8 internal constant MAX_DEPTH = 32; - uint256 internal constant SNARK_SCALAR_FIELD = - 21888242871839275222246405745257275088548364400416034343698204186575808495617; - - // Edge linking events - event EdgeAddition( - uint256 chainID, - uint256 latestLeafIndex, - uint256 merkleRoot - ); - event EdgeUpdate( - uint256 chainID, - uint256 latestLeafIndex, - uint256 merkleRoot - ); - - /// @dev Initializes a tree. - /// @param self: Tree data. - /// @param depth: Depth of the tree. - function init( - LinkableIncrementalTreeData storage self, - uint256 depth - ) public { - require( - depth > 0 && depth <= MAX_DEPTH, - "LinkableIncrementalBinaryTree: tree depth must be between 1 and 32" - ); - - self.depth = depth; - self.roots[0] = zeros(depth); - } - - /// @dev Inserts a leaf in the tree. - /// @param self: Tree data. - /// @param leaf: Leaf to be inserted. - function _insert( - LinkableIncrementalTreeData storage self, - uint256 leaf - ) internal { - uint256 index = self.numberOfLeaves; - _update(self, index, 0, leaf); - self.numberOfLeaves += 1; - } - - /// @dev Inserts a leaf in the tree. - /// @param self: Tree data. - /// @param leaf1: Leaf to be inserted. - /// @param leaf2: Leaf to be inserted. - function _insertTwo( - LinkableIncrementalTreeData storage self, - uint256 leaf1, - uint256 leaf2 - ) internal returns (uint32) { - uint32 index = self.numberOfLeaves; - uint parent = PoseidonT3.poseidon([leaf1, leaf2]); - _update(self, index, 1, parent); - self.numberOfLeaves += 2; - return self.numberOfLeaves; - } - - /// @dev updates a leaf directly by index. Use with caution. - /// @param self: Tree data. - /// @param index: index to be updated. - /// @param startLevel: allows for updating batches of transactions. - /// @param leaf: new leaf. - function _update( - LinkableIncrementalTreeData storage self, - uint256 index, - uint256 startLevel, - uint256 leaf - ) internal { - require( - leaf < SNARK_SCALAR_FIELD, - "LinkableIncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - index < 2 ** self.depth, - "Cannot update leaf outside of tree" - ); - uint256 hash = leaf; - for (uint i = 0; i < startLevel; i++) { - index /= 2; - } - - for (uint i = startLevel; i < self.depth; i++) { - if (index % 2 == 0) { - self.lastSubtrees[i] = [hash, uint256(zeros(i))]; - } else { - self.lastSubtrees[i][1] = hash; - } - - hash = PoseidonT3.poseidon(self.lastSubtrees[i]); - index /= 2; - } - - uint32 newRootIndex = (self.currentRootIndex + 1) % ROOT_HISTORY_SIZE; - self.roots[newRootIndex] = hash; - self.currentRootIndex = newRootIndex; - } - - /// @dev Updates a leaf in the tree. - /// @param self: Tree data. - /// @param leaf: Leaf to be updated. - /// @param newLeaf: New leaf. - /// @param proofSiblings: Array of the sibling nodes of the proof of membership. - /// @param proofPathIndices: Path of the proof of membership. - function update( - LinkableIncrementalTreeData storage self, - uint256 leaf, - uint256 newLeaf, - uint256[] calldata proofSiblings, - uint8[] calldata proofPathIndices - ) public { - require( - verify(self, leaf, proofSiblings, proofPathIndices), - "LinkableIncrementalBinaryTree: leaf is not part of the tree" - ); - - uint256 depth = self.depth; - uint256 hash = newLeaf; - - uint256 updateIndex; - for (uint8 i = 0; i < depth; ) { - updateIndex |= uint256(proofPathIndices[i] & 1) << uint256(i); - if (proofPathIndices[i] == 0) { - if (proofSiblings[i] == self.lastSubtrees[i][1]) { - self.lastSubtrees[i][0] = hash; - } - - hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); - } else { - if (proofSiblings[i] == self.lastSubtrees[i][0]) { - self.lastSubtrees[i][1] = hash; - } - - hash = PoseidonT3.poseidon([proofSiblings[i], hash]); - } - - unchecked { - ++i; - } - } - require( - updateIndex < self.numberOfLeaves, - "IncrementalBinaryTree: leaf index out of range" - ); - - self.roots[self.currentRootIndex] = hash; - } - - /// @dev Removes a leaf from the tree. - /// @param self: Tree data. - /// @param leaf: Leaf to be removed. - /// @param proofSiblings: Array of the sibling nodes of the proof of membership. - /// @param proofPathIndices: Path of the proof of membership. - function remove( - LinkableIncrementalTreeData storage self, - uint256 leaf, - uint256[] calldata proofSiblings, - uint8[] calldata proofPathIndices - ) internal { - require( - verify(self, leaf, proofSiblings, proofPathIndices), - "LinkableIncrementalBinaryTree: leaf is not part of the tree" - ); - - uint256 hash = uint256(zeros(0)); - - for (uint8 i = 0; i < self.depth; i++) { - if (proofPathIndices[i] == 0) { - if (proofSiblings[i] == self.lastSubtrees[i][1]) { - self.lastSubtrees[i][0] = hash; - } - - hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); - } else { - if (proofSiblings[i] == self.lastSubtrees[i][0]) { - self.lastSubtrees[i][1] = hash; - } - - hash = PoseidonT3.poseidon([proofSiblings[i], hash]); - } - } - - self.roots[self.currentRootIndex] = hash; - } - - /// @dev Verify if the path is correct and the leaf is part of the tree. - /// @param self: Tree data. - /// @param leaf: Leaf to be removed. - /// @param proofSiblings: Array of the sibling nodes of the proof of membership. - /// @param proofPathIndices: Path of the proof of membership. - /// @return True or false. - function verify( - LinkableIncrementalTreeData storage self, - uint256 leaf, - uint256[] calldata proofSiblings, - uint8[] calldata proofPathIndices - ) private view returns (bool) { - require( - leaf < SNARK_SCALAR_FIELD, - "LinkableIncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - proofPathIndices.length == self.depth && - proofSiblings.length == self.depth, - "LinkableIncrementalBinaryTree: length of path is not correct" - ); - - uint256 hash = leaf; - - for (uint8 i = 0; i < self.depth; i++) { - require( - proofSiblings[i] < SNARK_SCALAR_FIELD, - "LinkableIncrementalBinaryTree: sibling node must be < SNARK_SCALAR_FIELD" - ); - - if (proofPathIndices[i] == 0) { - hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); - } else { - hash = PoseidonT3.poseidon([proofSiblings[i], hash]); - } - } - - return hash == uint256(self.roots[self.currentRootIndex]); - } - - /** + // Historical roots + bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; + uint32 internal constant ROOT_HISTORY_SIZE = 30; + uint8 internal constant MAX_DEPTH = 32; + uint256 internal constant SNARK_SCALAR_FIELD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + // Edge linking events + event EdgeAddition(uint256 chainID, uint256 latestLeafIndex, uint256 merkleRoot); + event EdgeUpdate(uint256 chainID, uint256 latestLeafIndex, uint256 merkleRoot); + + /// @dev Initializes a tree. + /// @param self: Tree data. + /// @param depth: Depth of the tree. + function init(LinkableIncrementalTreeData storage self, uint256 depth) public { + require( + depth > 0 && depth <= MAX_DEPTH, + "LinkableIncrementalBinaryTree: tree depth must be between 1 and 32" + ); + + self.depth = depth; + self.roots[0] = zeros(depth); + } + + /// @dev Inserts a leaf in the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be inserted. + function _insert(LinkableIncrementalTreeData storage self, uint256 leaf) internal { + uint256 index = self.numberOfLeaves; + _update(self, index, 0, leaf); + self.numberOfLeaves += 1; + } + + /// @dev Inserts a leaf in the tree. + /// @param self: Tree data. + /// @param leaf1: Leaf to be inserted. + /// @param leaf2: Leaf to be inserted. + function _insertTwo( + LinkableIncrementalTreeData storage self, + uint256 leaf1, + uint256 leaf2 + ) internal returns (uint32) { + uint32 index = self.numberOfLeaves; + uint parent = PoseidonT3.poseidon([leaf1, leaf2]); + _update(self, index, 1, parent); + self.numberOfLeaves += 2; + return self.numberOfLeaves; + } + + /// @dev updates a leaf directly by index. Use with caution. + /// @param self: Tree data. + /// @param index: index to be updated. + /// @param startLevel: allows for updating batches of transactions. + /// @param leaf: new leaf. + function _update( + LinkableIncrementalTreeData storage self, + uint256 index, + uint256 startLevel, + uint256 leaf + ) internal { + require( + leaf < SNARK_SCALAR_FIELD, + "LinkableIncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require(index < 2 ** self.depth, "Cannot update leaf outside of tree"); + uint256 hash = leaf; + for (uint i = 0; i < startLevel; i++) { + index /= 2; + } + + for (uint i = startLevel; i < self.depth; i++) { + if (index % 2 == 0) { + self.lastSubtrees[i] = [hash, uint256(zeros(i))]; + } else { + self.lastSubtrees[i][1] = hash; + } + + hash = PoseidonT3.poseidon(self.lastSubtrees[i]); + index /= 2; + } + + uint32 newRootIndex = (self.currentRootIndex + 1) % ROOT_HISTORY_SIZE; + self.roots[newRootIndex] = hash; + self.currentRootIndex = newRootIndex; + } + + /// @dev Updates a leaf in the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be updated. + /// @param newLeaf: New leaf. + /// @param proofSiblings: Array of the sibling nodes of the proof of membership. + /// @param proofPathIndices: Path of the proof of membership. + function update( + LinkableIncrementalTreeData storage self, + uint256 leaf, + uint256 newLeaf, + uint256[] calldata proofSiblings, + uint8[] calldata proofPathIndices + ) public { + require( + verify(self, leaf, proofSiblings, proofPathIndices), + "LinkableIncrementalBinaryTree: leaf is not part of the tree" + ); + + uint256 depth = self.depth; + uint256 hash = newLeaf; + + uint256 updateIndex; + for (uint8 i = 0; i < depth; ) { + updateIndex |= uint256(proofPathIndices[i] & 1) << uint256(i); + if (proofPathIndices[i] == 0) { + if (proofSiblings[i] == self.lastSubtrees[i][1]) { + self.lastSubtrees[i][0] = hash; + } + + hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); + } else { + if (proofSiblings[i] == self.lastSubtrees[i][0]) { + self.lastSubtrees[i][1] = hash; + } + + hash = PoseidonT3.poseidon([proofSiblings[i], hash]); + } + + unchecked { + ++i; + } + } + require( + updateIndex < self.numberOfLeaves, + "IncrementalBinaryTree: leaf index out of range" + ); + + self.roots[self.currentRootIndex] = hash; + } + + /// @dev Removes a leaf from the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be removed. + /// @param proofSiblings: Array of the sibling nodes of the proof of membership. + /// @param proofPathIndices: Path of the proof of membership. + function remove( + LinkableIncrementalTreeData storage self, + uint256 leaf, + uint256[] calldata proofSiblings, + uint8[] calldata proofPathIndices + ) internal { + require( + verify(self, leaf, proofSiblings, proofPathIndices), + "LinkableIncrementalBinaryTree: leaf is not part of the tree" + ); + + uint256 hash = uint256(zeros(0)); + + for (uint8 i = 0; i < self.depth; i++) { + if (proofPathIndices[i] == 0) { + if (proofSiblings[i] == self.lastSubtrees[i][1]) { + self.lastSubtrees[i][0] = hash; + } + + hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); + } else { + if (proofSiblings[i] == self.lastSubtrees[i][0]) { + self.lastSubtrees[i][1] = hash; + } + + hash = PoseidonT3.poseidon([proofSiblings[i], hash]); + } + } + + self.roots[self.currentRootIndex] = hash; + } + + /// @dev Verify if the path is correct and the leaf is part of the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be removed. + /// @param proofSiblings: Array of the sibling nodes of the proof of membership. + /// @param proofPathIndices: Path of the proof of membership. + /// @return True or false. + function verify( + LinkableIncrementalTreeData storage self, + uint256 leaf, + uint256[] calldata proofSiblings, + uint8[] calldata proofPathIndices + ) private view returns (bool) { + require( + leaf < SNARK_SCALAR_FIELD, + "LinkableIncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + proofPathIndices.length == self.depth && proofSiblings.length == self.depth, + "LinkableIncrementalBinaryTree: length of path is not correct" + ); + + uint256 hash = leaf; + + for (uint8 i = 0; i < self.depth; i++) { + require( + proofSiblings[i] < SNARK_SCALAR_FIELD, + "LinkableIncrementalBinaryTree: sibling node must be < SNARK_SCALAR_FIELD" + ); + + if (proofPathIndices[i] == 0) { + hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); + } else { + hash = PoseidonT3.poseidon([proofSiblings[i], hash]); + } + } + + return hash == uint256(self.roots[self.currentRootIndex]); + } + + /** @dev Whether the root is present in the root history */ - function isKnownRoot( - LinkableIncrementalTreeData storage self, - uint256 _root - ) public view returns (bool) { - if (_root == 0) { - return false; - } - uint32 _currentRootIndex = self.currentRootIndex; - uint32 i = _currentRootIndex; - do { - if (_root == self.roots[i]) { - return true; - } - if (i == 0) { - i = ROOT_HISTORY_SIZE; - } - i--; - } while (i != _currentRootIndex); - - return false; - } - - /** + function isKnownRoot( + LinkableIncrementalTreeData storage self, + uint256 _root + ) public view returns (bool) { + if (_root == 0) { + return false; + } + uint32 _currentRootIndex = self.currentRootIndex; + uint32 i = _currentRootIndex; + do { + if (_root == self.roots[i]) { + return true; + } + if (i == 0) { + i = ROOT_HISTORY_SIZE; + } + i--; + } while (i != _currentRootIndex); + + return false; + } + + /** @dev Returns the last root */ - function getLastRoot( - LinkableIncrementalTreeData storage self - ) public view returns (uint256) { - return self.roots[self.currentRootIndex]; - } + function getLastRoot(LinkableIncrementalTreeData storage self) public view returns (uint256) { + return self.roots[self.currentRootIndex]; + } - /** + /** @notice Decodes a byte string of roots into its parts. @return bytes32[] An array of bytes32 merkle roots */ - function decodeRoots( - LinkableIncrementalTreeData storage self, - bytes calldata roots - ) internal view returns (bytes32[] memory) { - bytes32[] memory decodedRoots = new bytes32[](self.maxEdges + 1); - for (uint256 i = 0; i <= self.maxEdges; i++) { - decodedRoots[i] = bytes32(roots[(32 * i):(32 * (i + 1))]); - } - - return decodedRoots; - } - - /** + function decodeRoots( + LinkableIncrementalTreeData storage self, + bytes calldata roots + ) internal view returns (bytes32[] memory) { + bytes32[] memory decodedRoots = new bytes32[](self.maxEdges + 1); + for (uint256 i = 0; i <= self.maxEdges; i++) { + decodedRoots[i] = bytes32(roots[(32 * i):(32 * (i + 1))]); + } + + return decodedRoots; + } + + /** Parses the typed chain ID out from a 32-byte resource ID */ - function parseChainIdFromResourceId( - bytes32 _resourceId - ) public pure returns (uint64) { - return uint64(uint48(bytes6(_resourceId << (26 * 8)))); - } - - // solium-disable-next-line security/code-complexity - function zeros(uint256 i) public pure returns (uint256) { - if (i == 0) - return - 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c; - else if (i == 1) - return - 0x13e37f2d6cb86c78ccc1788607c2b199788c6bb0a615a21f2e7a8e88384222f8; - else if (i == 2) - return - 0x217126fa352c326896e8c2803eec8fd63ad50cf65edfef27a41a9e32dc622765; - else if (i == 3) - return - 0x0e28a61a9b3e91007d5a9e3ada18e1b24d6d230c618388ee5df34cacd7397eee; - else if (i == 4) - return - 0x27953447a6979839536badc5425ed15fadb0e292e9bc36f92f0aa5cfa5013587; - else if (i == 5) - return - 0x194191edbfb91d10f6a7afd315f33095410c7801c47175c2df6dc2cce0e3affc; - else if (i == 6) - return - 0x1733dece17d71190516dbaf1927936fa643dc7079fc0cc731de9d6845a47741f; - else if (i == 7) - return - 0x267855a7dc75db39d81d17f95d0a7aa572bf5ae19f4db0e84221d2b2ef999219; - else if (i == 8) - return - 0x1184e11836b4c36ad8238a340ecc0985eeba665327e33e9b0e3641027c27620d; - else if (i == 9) - return - 0x0702ab83a135d7f55350ab1bfaa90babd8fc1d2b3e6a7215381a7b2213d6c5ce; - else if (i == 10) - return - 0x2eecc0de814cfd8c57ce882babb2e30d1da56621aef7a47f3291cffeaec26ad7; - else if (i == 11) - return - 0x280bc02145c155d5833585b6c7b08501055157dd30ce005319621dc462d33b47; - else if (i == 12) - return - 0x045132221d1fa0a7f4aed8acd2cbec1e2189b7732ccb2ec272b9c60f0d5afc5b; - else if (i == 13) - return - 0x27f427ccbf58a44b1270abbe4eda6ba53bd6ac4d88cf1e00a13c4371ce71d366; - else if (i == 14) - return - 0x1617eaae5064f26e8f8a6493ae92bfded7fde71b65df1ca6d5dcec0df70b2cef; - else if (i == 15) - return - 0x20c6b400d0ea1b15435703c31c31ee63ad7ba5c8da66cec2796feacea575abca; - else if (i == 16) - return - 0x09589ddb438723f53a8e57bdada7c5f8ed67e8fece3889a73618732965645eec; - else if (i == 17) - return - 0x0064b6a738a5ff537db7b220f3394f0ecbd35bfd355c5425dc1166bf3236079b; - else if (i == 18) - return - 0x095de56281b1d5055e897c3574ff790d5ee81dbc5df784ad2d67795e557c9e9f; - else if (i == 19) - return - 0x11cf2e2887aa21963a6ec14289183efe4d4c60f14ecd3d6fe0beebdf855a9b63; - else if (i == 20) - return - 0x2b0f6fc0179fa65b6f73627c0e1e84c7374d2eaec44c9a48f2571393ea77bcbb; - else if (i == 21) - return - 0x16fdb637c2abf9c0f988dbf2fd64258c46fb6a273d537b2cf1603ea460b13279; - else if (i == 22) - return - 0x21bbd7e944f6124dad4c376df9cc12e7ca66e47dff703ff7cedb1a454edcf0ff; - else if (i == 23) - return - 0x2784f8220b1c963e468f590f137baaa1625b3b92a27ad9b6e84eb0d3454d9962; - else if (i == 24) - return - 0x16ace1a65b7534142f8cc1aad810b3d6a7a74ca905d9c275cb98ba57e509fc10; - else if (i == 25) - return - 0x2328068c6a8c24265124debd8fe10d3f29f0665ea725a65e3638f6192a96a013; - else if (i == 26) - return - 0x2ddb991be1f028022411b4c4d2c22043e5e751c120736f00adf54acab1c9ac14; - else if (i == 27) - return - 0x0113798410eaeb95056a464f70521eb58377c0155f2fe518a5594d38cc209cc0; - else if (i == 28) - return - 0x202d1ae61526f0d0d01ef80fb5d4055a7af45721024c2c24cffd6a3798f54d50; - else if (i == 29) - return - 0x23ab323453748129f2765f79615022f5bebd6f4096a796300aab049a60b0f187; - else if (i == 30) - return - 0x1f15585f8947e378bcf8bd918716799da909acdb944c57150b1eb4565fda8aa0; - else if (i == 31) - return - 0x1eb064b21055ac6a350cf41eb30e4ce2cb19680217df3a243617c2838185ad06; - else revert("Index out of bounds"); - } - + function parseChainIdFromResourceId(bytes32 _resourceId) public pure returns (uint64) { + return uint64(uint48(bytes6(_resourceId << (26 * 8)))); + } + + // solium-disable-next-line security/code-complexity + function zeros(uint256 i) public pure returns (uint256) { + if (i == 0) return 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c; + else if (i == 1) return 0x13e37f2d6cb86c78ccc1788607c2b199788c6bb0a615a21f2e7a8e88384222f8; + else if (i == 2) return 0x217126fa352c326896e8c2803eec8fd63ad50cf65edfef27a41a9e32dc622765; + else if (i == 3) return 0x0e28a61a9b3e91007d5a9e3ada18e1b24d6d230c618388ee5df34cacd7397eee; + else if (i == 4) return 0x27953447a6979839536badc5425ed15fadb0e292e9bc36f92f0aa5cfa5013587; + else if (i == 5) return 0x194191edbfb91d10f6a7afd315f33095410c7801c47175c2df6dc2cce0e3affc; + else if (i == 6) return 0x1733dece17d71190516dbaf1927936fa643dc7079fc0cc731de9d6845a47741f; + else if (i == 7) return 0x267855a7dc75db39d81d17f95d0a7aa572bf5ae19f4db0e84221d2b2ef999219; + else if (i == 8) return 0x1184e11836b4c36ad8238a340ecc0985eeba665327e33e9b0e3641027c27620d; + else if (i == 9) return 0x0702ab83a135d7f55350ab1bfaa90babd8fc1d2b3e6a7215381a7b2213d6c5ce; + else if (i == 10) return 0x2eecc0de814cfd8c57ce882babb2e30d1da56621aef7a47f3291cffeaec26ad7; + else if (i == 11) return 0x280bc02145c155d5833585b6c7b08501055157dd30ce005319621dc462d33b47; + else if (i == 12) return 0x045132221d1fa0a7f4aed8acd2cbec1e2189b7732ccb2ec272b9c60f0d5afc5b; + else if (i == 13) return 0x27f427ccbf58a44b1270abbe4eda6ba53bd6ac4d88cf1e00a13c4371ce71d366; + else if (i == 14) return 0x1617eaae5064f26e8f8a6493ae92bfded7fde71b65df1ca6d5dcec0df70b2cef; + else if (i == 15) return 0x20c6b400d0ea1b15435703c31c31ee63ad7ba5c8da66cec2796feacea575abca; + else if (i == 16) return 0x09589ddb438723f53a8e57bdada7c5f8ed67e8fece3889a73618732965645eec; + else if (i == 17) return 0x0064b6a738a5ff537db7b220f3394f0ecbd35bfd355c5425dc1166bf3236079b; + else if (i == 18) return 0x095de56281b1d5055e897c3574ff790d5ee81dbc5df784ad2d67795e557c9e9f; + else if (i == 19) return 0x11cf2e2887aa21963a6ec14289183efe4d4c60f14ecd3d6fe0beebdf855a9b63; + else if (i == 20) return 0x2b0f6fc0179fa65b6f73627c0e1e84c7374d2eaec44c9a48f2571393ea77bcbb; + else if (i == 21) return 0x16fdb637c2abf9c0f988dbf2fd64258c46fb6a273d537b2cf1603ea460b13279; + else if (i == 22) return 0x21bbd7e944f6124dad4c376df9cc12e7ca66e47dff703ff7cedb1a454edcf0ff; + else if (i == 23) return 0x2784f8220b1c963e468f590f137baaa1625b3b92a27ad9b6e84eb0d3454d9962; + else if (i == 24) return 0x16ace1a65b7534142f8cc1aad810b3d6a7a74ca905d9c275cb98ba57e509fc10; + else if (i == 25) return 0x2328068c6a8c24265124debd8fe10d3f29f0665ea725a65e3638f6192a96a013; + else if (i == 26) return 0x2ddb991be1f028022411b4c4d2c22043e5e751c120736f00adf54acab1c9ac14; + else if (i == 27) return 0x0113798410eaeb95056a464f70521eb58377c0155f2fe518a5594d38cc209cc0; + else if (i == 28) return 0x202d1ae61526f0d0d01ef80fb5d4055a7af45721024c2c24cffd6a3798f54d50; + else if (i == 29) return 0x23ab323453748129f2765f79615022f5bebd6f4096a796300aab049a60b0f187; + else if (i == 30) return 0x1f15585f8947e378bcf8bd918716799da909acdb944c57150b1eb4565fda8aa0; + else if (i == 31) return 0x1eb064b21055ac6a350cf41eb30e4ce2cb19680217df3a243617c2838185ad06; + else revert("Index out of bounds"); + } } diff --git a/packages/contracts/contracts/trees/MerkleForest.sol b/packages/contracts/contracts/trees/MerkleForest.sol index c92d03ba3..877747fcd 100644 --- a/packages/contracts/contracts/trees/MerkleForest.sol +++ b/packages/contracts/contracts/trees/MerkleForest.sol @@ -6,105 +6,126 @@ pragma solidity ^0.8.0; import "./LinkableIncrementalBinaryTree.sol"; +import "../interfaces/IMerkleSystem.sol"; import "../hashers/IHasher.sol"; -contract MerkleForest { - using LinkableIncrementalBinaryTree for LinkableIncrementalTreeData; - IHasher public hasher; - uint256 public currSubtreeIndex; - uint256 public numSubtreeElements; - uint256 public maxSubtreeElements; - - /// @dev Gets a group id and returns the group/tree data. - mapping(uint256 => LinkableIncrementalTreeData) public subtrees; - LinkableIncrementalTreeData public merkleForest; - - // bytes32[] public leaves; - constructor(uint32 _forestLevels, uint32 _subtreeLevels, IHasher _hasher) { - require(_forestLevels > 0, "_forestLevels should be greater than zero"); - require(_subtreeLevels > 0, "_subtreeLevels should be greater than zero"); - require(_forestLevels < 32, "_forestLevels should be less than 32"); - require(_subtreeLevels < 32, "_subtreeLevels should be less than 32"); - - for (uint32 i = 0; i < _forestLevels; i++) { - subtrees[i].init(_subtreeLevels); - } - merkleForest.init(_forestLevels); - - hasher = _hasher; - maxSubtreeElements = 2 ** _subtreeLevels; - currSubtreeIndex = 0; - numSubtreeElements = 0; - } - /** +contract MerkleForest is MerkleSystem { + using LinkableIncrementalBinaryTree for LinkableIncrementalTreeData; + IHasher public hasher; + uint32 public currSubtreeIndex; + uint32 public numSubtreeElements; + + uint32 public forestLevels; + uint32 public subtreeLevels; + + /// @dev Gets a group id and returns the group/tree data. + mapping(uint256 => LinkableIncrementalTreeData) public subtrees; + LinkableIncrementalTreeData public merkleForest; + + // bytes32[] public leaves; + constructor(uint32 _forestLevels, uint32 _subtreeLevels, IHasher _hasher) { + require(_forestLevels > 0, "_forestLevels should be greater than zero"); + require(_subtreeLevels > 0, "_subtreeLevels should be greater than zero"); + require(_forestLevels < 32, "_forestLevels should be less than 32"); + require(_subtreeLevels < 32, "_subtreeLevels should be less than 32"); + + for (uint32 i = 0; i < _forestLevels; i++) { + subtrees[i].init(_subtreeLevels); + } + merkleForest.init(_forestLevels); + + hasher = _hasher; + currSubtreeIndex = 0; + numSubtreeElements = 0; + forestLevels = _forestLevels; + subtreeLevels = _subtreeLevels; + } + + /** @dev inserts single leaf into subtree then update forest */ - function _insert(bytes32 _leaf) internal returns (bool) { - if (numSubtreeElements >= maxSubtreeElements) { - numSubtreeElements = 0; - currSubtreeIndex += 1; - } - subtrees[currSubtreeIndex]._insert(uint(_leaf)); - uint newLeaf = subtrees[currSubtreeIndex].getLastRoot(); - merkleForest._update(currSubtreeIndex, 0, newLeaf); - numSubtreeElements += 1; - return true; - // return merkleForest.getLastRoot(); - } - - /** + function _insert(uint256 _leaf) internal override returns (uint32) { + if (numSubtreeElements >= uint32(2 ** subtreeLevels)) { + numSubtreeElements = 0; + currSubtreeIndex += 1; + } + subtrees[currSubtreeIndex]._insert(uint(_leaf)); + uint newLeaf = subtrees[currSubtreeIndex].getLastRoot(); + merkleForest._update(currSubtreeIndex, 0, newLeaf); + numSubtreeElements += 1; + return numSubtreeElements; + } + + /** @dev inserts pair of leaves into subtree then update forest */ - function _insertTwo(bytes32 _leaf1, bytes32 _leaf2) internal returns (uint32) { - if (numSubtreeElements + 1 >= maxSubtreeElements) { - numSubtreeElements = 0; - currSubtreeIndex += 1; - } - uint32 index = subtrees[currSubtreeIndex]._insertTwo(uint(_leaf1), uint(_leaf2)); - uint newLeaf = subtrees[currSubtreeIndex].getLastRoot(); - merkleForest._update(currSubtreeIndex, 0, newLeaf); - numSubtreeElements += 2; - return index; - } - - /** + function _insertTwo(uint256 _leaf1, uint256 _leaf2) internal override returns (uint32) { + if (numSubtreeElements + 1 >= uint32(2 ** subtreeLevels)) { + numSubtreeElements = 0; + currSubtreeIndex += 1; + } + uint32 index = subtrees[currSubtreeIndex]._insertTwo(uint(_leaf1), uint(_leaf2)); + uint newLeaf = subtrees[currSubtreeIndex].getLastRoot(); + merkleForest._update(currSubtreeIndex, 0, newLeaf); + numSubtreeElements += 2; + return index; + } + + /** @dev inserts single leaf into specific subtreeId (if possible) */ - function _insertSubtree(uint32 _subtreeId, bytes32 _leaf) internal returns (uint) { - if (numSubtreeElements >= maxSubtreeElements) { - numSubtreeElements = 0; - currSubtreeIndex += 1; - } - subtrees[_subtreeId]._insert(uint(_leaf)); - uint newLeaf = subtrees[_subtreeId].getLastRoot(); - merkleForest._update(_subtreeId, 0, newLeaf); - return merkleForest.getLastRoot(); - } - /** + function _insertSubtree(uint32 _subtreeId, uint256 _leaf) internal returns (uint) { + if (numSubtreeElements >= uint32(2 ** subtreeLevels)) { + numSubtreeElements = 0; + currSubtreeIndex += 1; + } + subtrees[_subtreeId]._insert(uint(_leaf)); + uint newLeaf = subtrees[_subtreeId].getLastRoot(); + merkleForest._update(_subtreeId, 0, newLeaf); + return merkleForest.getLastRoot(); + } + + /** @dev Whether the root is present in any of the subtree's history */ - function isKnownSubtreeRoot(uint _subtreeId, bytes32 _root) public view returns (bool) { - return subtrees[_subtreeId].isKnownRoot(uint(_root)); - } + function isKnownSubtreeRoot(uint _subtreeId, uint256 _root) public view returns (bool) { + return subtrees[_subtreeId].isKnownRoot(uint(_root)); + } - /** - @dev Returns the last root of the forest + /** + @dev Whether the root is present in any of the subtree's history */ - function getLastRoot() public view returns (uint256) { - return merkleForest.getLastRoot(); - } + function getLastSubtreeRoot(uint256 _subtreeId) public view returns (uint) { + return subtrees[_subtreeId].getLastRoot(); + } - /** - @dev Whether the root is present in the root history of the forest - */ - function isKnownRoot(uint256 _root) public view returns (bool) { - return merkleForest.isKnownRoot(_root); - } + /// @inheritdoc IMerkleSystem + function isKnownRoot(uint256 _root) public view override returns (bool) { + return merkleForest.isKnownRoot(uint256(_root)); + } - /** - @dev Whether the root is present in any of the subtree's history - */ - function getLastSubtreeRoot(uint256 _subtreeId) public view returns (uint) { - return subtrees[_subtreeId].getLastRoot(); - } + /// @inheritdoc IMerkleSystem + function getLastRoot() external view override returns (uint256) { + return merkleForest.getLastRoot(); + } + + /// @inheritdoc IMerkleSystem + function getZeroHash(uint32 index) external pure override returns (uint256) { + return LinkableIncrementalBinaryTree.zeros(index); + } + + /// @inheritdoc IMerkleSystem + function getNextIndex() external view override returns (uint32) { + return numSubtreeElements; + } + + /// @inheritdoc IMerkleSystem + function getLevels() external view override returns (uint32) { + return forestLevels; + } + + /// @inheritdoc IMerkleSystem + function getHasher() external view override returns (IHasher) { + return hasher; + } } diff --git a/packages/contracts/contracts/trees/MerkleTree.sol b/packages/contracts/contracts/trees/MerkleTree.sol index 3902e8258..d9e9feb57 100644 --- a/packages/contracts/contracts/trees/MerkleTree.sol +++ b/packages/contracts/contracts/trees/MerkleTree.sol @@ -8,27 +8,16 @@ pragma solidity ^0.8.0; import "./MerkleTreeWithHistory.sol"; contract MerkleTree is MerkleTreeWithHistory { - constructor(uint32 _levels, IHasher _hasher) { - require(_levels > 0, "_levels should be greater than zero"); - require(_levels < 32, "_levels should be less than 32"); - levels = _levels; - hasher = _hasher; + constructor(uint32 _levels, IHasher _hasher) { + require(_levels > 0, "_levels should be greater than zero"); + require(_levels < 32, "_levels should be less than 32"); + levels = _levels; + hasher = _hasher; - for (uint32 i = 0; i < _levels; i++) { - filledSubtrees[i] = hasher.zeros(i); - } + for (uint32 i = 0; i < _levels; i++) { + filledSubtrees[i] = uint256(hasher.zeros(i)); + } - roots[0] = Root(hasher.zeros(_levels - 1), 0); - } - - /** - @dev Hash 2 tree leaves - */ - function hashLeftRight( - IHasher _hasher, - bytes32 _left, - bytes32 _right - ) override public view returns (bytes32) { - return bytes32(_hasher.hashLeftRight(uint256(_left), uint256(_right))); - } + roots[0] = Root(uint256(hasher.zeros(_levels - 1)), 0); + } } diff --git a/packages/contracts/contracts/trees/MerkleTreeWithHistory.sol b/packages/contracts/contracts/trees/MerkleTreeWithHistory.sol index e619d8f28..5c7356430 100644 --- a/packages/contracts/contracts/trees/MerkleTreeWithHistory.sol +++ b/packages/contracts/contracts/trees/MerkleTreeWithHistory.sol @@ -6,118 +6,119 @@ pragma solidity ^0.8.0; import "../hashers/IHasher.sol"; -import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "../interfaces/IMerkleSystem.sol"; -abstract contract MerkleTreeWithHistory is Initializable { - uint32 public currentRootIndex = 0; - uint32 public nextIndex = 0; - uint32 public levels; - uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE - // the `Root` struct is used to store the root and the index of the leaf triggering this root update - struct Root { - bytes32 root; - uint256 latestLeafindex; - } - // the mapping of root indices to roots for storing a history of ROOT_HISTORY_SIZE updates - mapping(uint256 => Root) public roots; - IHasher public hasher; +abstract contract MerkleTreeWithHistory is MerkleSystem { + uint32 public currentRootIndex = 0; + uint32 public nextIndex = 0; + uint32 public levels; - // the following variables are made public for easier testing and debugging and - // are not supposed to be accessed in regular code + IHasher public hasher; - // filledSubtrees and roots could be bytes32[size], but using mappings makes it cheaper because - // it removes index range check on every interaction - mapping(uint256 => bytes32) public filledSubtrees; - uint32 public constant ROOT_HISTORY_SIZE = 30; + /// @inheritdoc IMerkleSystem + function getLastRoot() public view override returns (uint256) { + return roots[currentRootIndex].root; + } - /** @dev this function is defined in a child contract */ - function hashLeftRight(IHasher _hasher, bytes32 _left, bytes32 _right) public virtual returns (bytes32); + /// @inheritdoc IMerkleSystem + function getZeroHash(uint32 index) external view override returns (uint256) { + return uint256(hasher.zeros(index)); + } - function _insert(bytes32 _leaf) internal returns (uint32 index) { - uint32 _nextIndex = nextIndex; - require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added"); - uint32 currentIndex = _nextIndex; - bytes32 currentLevelHash = _leaf; - bytes32 left; - bytes32 right; + /// @inheritdoc IMerkleSystem + function getLevels() external view override returns (uint32) { + return levels; + } - for (uint32 i = 0; i < levels; i++) { - if (currentIndex % 2 == 0) { - left = currentLevelHash; - right = hasher.zeros(i); - filledSubtrees[i] = currentLevelHash; - } else { - left = filledSubtrees[i]; - right = currentLevelHash; - } - currentLevelHash = hashLeftRight(hasher, left, right); - currentIndex /= 2; - } + /// @inheritdoc IMerkleSystem + function getNextIndex() external view override returns (uint32) { + return nextIndex; + } - uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; - currentRootIndex = newRootIndex; - nextIndex = _nextIndex + 1; - roots[newRootIndex] = Root(currentLevelHash, nextIndex); - return _nextIndex; - } + /// @inheritdoc IMerkleSystem + function getHasher() external view override returns (IHasher) { + return hasher; + } - // Modified to insert pairs of leaves for better efficiency - // Disclaimer: using this function assumes both leaves are siblings. - function _insertTwo(bytes32 _leaf1, bytes32 _leaf2) internal returns (uint32 index) { - uint32 _nextIndex = nextIndex; - require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added"); - uint32 currentIndex = _nextIndex / 2; - bytes32 currentLevelHash = hashLeftRight(hasher, _leaf1, _leaf2); - bytes32 left; - bytes32 right; - for (uint32 i = 1; i < levels; i++) { - if (currentIndex % 2 == 0) { - left = currentLevelHash; - right = hasher.zeros(i); - filledSubtrees[i] = currentLevelHash; - } else { - left = filledSubtrees[i]; - right = currentLevelHash; - } - currentLevelHash = hashLeftRight(hasher, left, right); - currentIndex /= 2; - } - - uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; - currentRootIndex = newRootIndex; - nextIndex = _nextIndex + 2; - roots[newRootIndex] = Root(currentLevelHash, nextIndex); - return _nextIndex; - } + /// @inheritdoc IMerkleSystem + function isKnownRoot(uint256 _root) public view override returns (bool) { + if (_root == 0) { + return false; + } + uint32 _currentRootIndex = currentRootIndex; + uint32 i = _currentRootIndex; + do { + if (_root == roots[i].root) { + return true; + } + if (i == 0) { + i = ROOT_HISTORY_SIZE; + } + i--; + } while (i != _currentRootIndex); + return false; + } - /** - @dev Whether the root is present in the root history - */ - function isKnownRoot(bytes32 _root) public view returns (bool) { - if (_root == 0) { - return false; - } - uint32 _currentRootIndex = currentRootIndex; - uint32 i = _currentRootIndex; - do { - if (_root == roots[i].root) { - return true; - } - if (i == 0) { - i = ROOT_HISTORY_SIZE; - } - i--; - } while (i != _currentRootIndex); - return false; - } + function _insert(uint256 _leaf) internal override returns (uint32 index) { + uint32 _nextIndex = nextIndex; + require( + _nextIndex != uint32(2) ** levels, + "Merkle tree is full. No more leaves can be added" + ); + uint32 currentIndex = _nextIndex; + uint256 currentLevelHash = _leaf; + uint256 left; + uint256 right; - /** - @dev Returns the last root - */ - function getLastRoot() public view returns (bytes32) { - return roots[currentRootIndex].root; - } + for (uint32 i = 0; i < levels; i++) { + if (currentIndex % 2 == 0) { + left = currentLevelHash; + right = uint256(hasher.zeros(i)); + filledSubtrees[i] = currentLevelHash; + } else { + left = filledSubtrees[i]; + right = currentLevelHash; + } + currentLevelHash = hashLeftRight(left, right); + currentIndex /= 2; + } - function _initialize() internal {} -} \ No newline at end of file + uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; + currentRootIndex = newRootIndex; + nextIndex = _nextIndex + 1; + roots[newRootIndex] = Root(currentLevelHash, nextIndex); + return _nextIndex; + } + + // Modified to insert pairs of leaves for better efficiency + // Disclaimer: using this function assumes both leaves are siblings. + function _insertTwo(uint256 _leaf1, uint256 _leaf2) internal override returns (uint32 index) { + uint32 _nextIndex = nextIndex; + require( + _nextIndex != uint32(2) ** levels, + "Merkle tree is full. No more leaves can be added" + ); + uint32 currentIndex = _nextIndex / 2; + uint256 currentLevelHash = hashLeftRight(_leaf1, _leaf2); + uint256 left; + uint256 right; + for (uint32 i = 1; i < levels; i++) { + if (currentIndex % 2 == 0) { + left = currentLevelHash; + right = uint256(hasher.zeros(i)); + filledSubtrees[i] = currentLevelHash; + } else { + left = filledSubtrees[i]; + right = currentLevelHash; + } + currentLevelHash = hashLeftRight(left, right); + currentIndex /= 2; + } + + uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; + currentRootIndex = newRootIndex; + nextIndex = _nextIndex + 2; + roots[newRootIndex] = Root(currentLevelHash, nextIndex); + return _nextIndex; + } +} diff --git a/packages/contracts/contracts/utils/ChainIdWithType.sol b/packages/contracts/contracts/utils/ChainIdWithType.sol index da65e7c58..c5087d537 100644 --- a/packages/contracts/contracts/utils/ChainIdWithType.sol +++ b/packages/contracts/contracts/utils/ChainIdWithType.sol @@ -5,43 +5,43 @@ pragma solidity ^0.8.5; -import "hardhat/console.sol"; - /** @title ChainIdWithType abstract contract */ abstract contract ChainIdWithType { - bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; + bytes2 public constant EVM_CHAIN_ID_TYPE = 0x0100; - /** + /** @notice Gets the chain id using the chain id opcode */ - function getChainId() public view returns (uint) { - uint chainId; - assembly { chainId := chainid() } - return chainId; - } + function getChainId() public view returns (uint) { + uint chainId; + assembly { + chainId := chainid() + } + return chainId; + } - /** + /** @notice Computes the modified chain id using the underlying chain type (EVM) */ - function getChainIdType() public view returns (uint48) { - // The chain ID and type pair is 6 bytes in length - // The first 2 bytes are reserved for the chain type. - // The last 4 bytes are reserved for a u32 (uint32) chain ID. - bytes4 chainID = bytes4(uint32(getChainId())); - bytes2 chainType = EVM_CHAIN_ID_TYPE; - // We encode the chain ID and type pair into packed bytes which - // should be 6 bytes using the encode packed method. We will - // cast this as a bytes32 in order to encode as a uint256 for zkp verification. - bytes memory chainIdWithType = abi.encodePacked(chainType, chainID); - return uint48(bytes6(chainIdWithType)); - } + function getChainIdType() public view returns (uint48) { + // The chain ID and type pair is 6 bytes in length + // The first 2 bytes are reserved for the chain type. + // The last 4 bytes are reserved for a u32 (uint32) chain ID. + bytes4 chainID = bytes4(uint32(getChainId())); + bytes2 chainType = EVM_CHAIN_ID_TYPE; + // We encode the chain ID and type pair into packed bytes which + // should be 6 bytes using the encode packed method. We will + // cast this as a bytes32 in order to encode as a uint256 for zkp verification. + bytes memory chainIdWithType = abi.encodePacked(chainType, chainID); + return uint48(bytes6(chainIdWithType)); + } - /** + /** Parses the typed chain ID out from a 32-byte resource ID */ - function parseChainIdFromResourceId(bytes32 _resourceId) public pure returns (uint64) { - return uint64(uint48(bytes6(_resourceId << (26 * 8)))); - } -} \ No newline at end of file + function parseChainIdFromResourceId(bytes32 _resourceId) public pure returns (uint64) { + return uint64(uint48(bytes6(_resourceId << (26 * 8)))); + } +} diff --git a/packages/contracts/contracts/utils/Governable.sol b/packages/contracts/contracts/utils/Governable.sol index 142e073af..4e28f0765 100644 --- a/packages/contracts/contracts/utils/Governable.sol +++ b/packages/contracts/contracts/utils/Governable.sol @@ -12,236 +12,265 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @author Webb Technologies */ contract Governable { - address private _governor; - - // Refresh nonce is for rotating the DKG - uint32 public refreshNonce = 0; - - /// Storage values relevant to proposer set update - - // The proposal nonce - uint32 public proposerSetUpdateNonce = 0; - // The root of the proposer set Merkle tree - bytes32 public proposerSetRoot; - // The average session length in millisecs - uint64 public averageSessionLengthInMillisecs = 2**64 - 1; - // The session length multiplier (see the voteInFavorForceSetGovernor function below) - uint256 public sessionLengthMultiplier = 2; - // The number of proposers - uint32 public numOfProposers; - // The current voting period - uint256 public currentVotingPeriod = 0; - // (currentVotingPeriod => (proposer => (true/false))) whether a proposer has - // voted in this period - mapping (uint256 => mapping(address => bool)) alreadyVoted; - // (currentVotingPeriod => (proposerGovernor => (uint))) number of votes a - // proposedGovernor has in the current period - mapping (uint256 => mapping(address => uint32)) numOfVotesForGovernor; - - // leafIndex: leafIndex of the proposer in the proposer set Merkle tree - // siblingPathNodes: Merkle proof path of sibling nodes - // proposedGovernor: the governor that the voter wants to force reset to - struct Vote { - uint32 leafIndex; - bytes32[] siblingPathNodes; - address proposedGovernor; - } - - // Last time ownership was transferred to a new govenror - uint256 public lastGovernorUpdateTime; - - event GovernanceOwnershipTransferred(address indexed previousOwner, address indexed newOwner); - event RecoveredAddress(address indexed recovered); - - constructor (address gov, uint32 nonce) { - _governor = gov; - refreshNonce = nonce; - lastGovernorUpdateTime = block.timestamp; - emit GovernanceOwnershipTransferred(address(0), _governor); - } - - /** - * @notice Returns the address of the current owner. - */ - function governor() public view returns (address) { - return _governor; - } + address private _governor; - /** - * @notice Throws if called by any account other than the owner. - */ - modifier onlyGovernor() { - require(isGovernor(), "Governable: caller is not the governor"); - _; - } + // Refresh nonce is for rotating the DKG + uint32 public refreshNonce = 0; + + /// Storage values relevant to proposer set update + + // The proposal nonce + uint32 public proposerSetUpdateNonce = 0; + // The root of the proposer set Merkle tree + bytes32 public proposerSetRoot; + // The average session length in millisecs + uint64 public averageSessionLengthInMillisecs = 2 ** 64 - 1; + // The session length multiplier (see the voteInFavorForceSetGovernor function below) + uint256 public sessionLengthMultiplier = 2; + // The number of proposers + uint32 public numOfProposers; + // The current voting period + uint256 public currentVotingPeriod = 0; + // (currentVotingPeriod => (proposer => (true/false))) whether a proposer has + // voted in this period + mapping(uint256 => mapping(address => bool)) alreadyVoted; + // (currentVotingPeriod => (proposerGovernor => (uint))) number of votes a + // proposedGovernor has in the current period + mapping(uint256 => mapping(address => uint32)) numOfVotesForGovernor; + + // leafIndex: leafIndex of the proposer in the proposer set Merkle tree + // siblingPathNodes: Merkle proof path of sibling nodes + // proposedGovernor: the governor that the voter wants to force reset to + struct Vote { + uint32 leafIndex; + bytes32[] siblingPathNodes; + address proposedGovernor; + } + + // Last time ownership was transferred to a new govenror + uint256 public lastGovernorUpdateTime; - /** + event GovernanceOwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event RecoveredAddress(address indexed recovered); + + constructor(address gov, uint32 nonce) { + _governor = gov; + refreshNonce = nonce; + lastGovernorUpdateTime = block.timestamp; + emit GovernanceOwnershipTransferred(address(0), _governor); + } + + /** + * @notice Returns the address of the current owner. + */ + function governor() public view returns (address) { + return _governor; + } + + /** + * @notice Throws if called by any account other than the owner. + */ + modifier onlyGovernor() { + require(isGovernor(), "Governable: caller is not the governor"); + _; + } + + /** @notice Returns true if the caller is the current owner. @return bool Whether the `msg.sender` is the governor */ - function isGovernor() public view returns (bool) { - return msg.sender == _governor; - } + function isGovernor() public view returns (bool) { + return msg.sender == _governor; + } - /** + /** @notice Returns true if the signature is signed by the current governor. @return bool Whether the signature of the data is signed by the governor */ - function isSignatureFromGovernor(bytes memory data, bytes memory sig) public view returns (bool) { - bytes32 hashedData = keccak256(data); - address signer = ECDSA.recover(hashedData, sig); - return signer == governor(); - } + function isSignatureFromGovernor( + bytes memory data, + bytes memory sig + ) public view returns (bool) { + bytes32 hashedData = keccak256(data); + address signer = ECDSA.recover(hashedData, sig); + return signer == governor(); + } - /** + /** @notice Leaves the contract without owner. It will not be possible to call `onlyGovernor` functions anymore. Can only be called by the current owner. @notice Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner. */ - function renounceOwnership() public onlyGovernor { - emit GovernanceOwnershipTransferred(_governor, address(0)); - _governor = address(0); - } + function renounceOwnership() public onlyGovernor { + emit GovernanceOwnershipTransferred(_governor, address(0)); + _governor = address(0); + } - /** + /** @notice Transfers ownership of the contract to a new account (`newOwner`). @param newOwner The new owner of the contract. @param nonce The nonce of the proposal. @notice Can only be called by the current owner. */ - function transferOwnership(address newOwner, uint32 nonce) public onlyGovernor { - _transferOwnership(newOwner); - refreshNonce = nonce; - } - - /** + function transferOwnership(address newOwner, uint32 nonce) public onlyGovernor { + _transferOwnership(newOwner); + refreshNonce = nonce; + } + + /** @notice Transfers ownership of the contract to a new account associated with the publicKey @param publicKey The public key of the new owner @param nonce The nonce of the proposal @param sig The signature of the transfer ownership/refresh proposal */ - function transferOwnershipWithSignaturePubKey(bytes memory publicKey, uint32 nonce, bytes memory sig) public { - require(refreshNonce < nonce, "Invalid nonce"); - require(nonce <= refreshNonce + 1, "Nonce must increment by 1"); - bytes32 pubKeyHash = keccak256(publicKey); - address newOwner = address(uint160(uint256(pubKeyHash))); - require(isSignatureFromGovernor(abi.encodePacked(nonce, publicKey), sig), "Governable: caller is not the governor"); - _transferOwnership(newOwner); - refreshNonce = nonce; - } - - /** + function transferOwnershipWithSignaturePubKey( + bytes memory publicKey, + uint32 nonce, + bytes memory sig + ) public { + require(refreshNonce < nonce, "Invalid nonce"); + require(nonce <= refreshNonce + 1, "Nonce must increment by 1"); + bytes32 pubKeyHash = keccak256(publicKey); + address newOwner = address(uint160(uint256(pubKeyHash))); + require( + isSignatureFromGovernor(abi.encodePacked(nonce, publicKey), sig), + "Governable: caller is not the governor" + ); + _transferOwnership(newOwner); + refreshNonce = nonce; + } + + /** @notice Helper function for recovering the address from the signature `sig` of `data` @param data The data being signed @param sig The signature of the data @return address The address of the signer */ - function recover(bytes memory data, bytes memory sig) public pure returns (address) { - bytes32 hashedData = keccak256(data); - address signer = ECDSA.recover(hashedData, sig); - return signer; - } + function recover(bytes memory data, bytes memory sig) public pure returns (address) { + bytes32 hashedData = keccak256(data); + address signer = ECDSA.recover(hashedData, sig); + return signer; + } - /** + /** @notice Transfers ownership of the contract to a new account (`newOwner`). @param newOwner The new owner of the contract */ - function _transferOwnership(address newOwner) internal { - require(newOwner != address(0), "Governable: new owner is the zero address"); - emit GovernanceOwnershipTransferred(_governor, newOwner); - _governor = newOwner; - lastGovernorUpdateTime = block.timestamp; - currentVotingPeriod++; - } - - /** - * @notice Updates the proposer set data if a valid signature from the DKG is provided. The * data consists proposerSetRoot, the average session length in milliseconds, the * number of proposers, and the proposal nonce. - * @param _proposerSetRoot the root hash of the proposer set Merkle tree - * @param _averageSessionLengthInMillisecs the average DKG session length in milliseconds - * @param _numOfProposers the total number of proposers - * @param _proposerSetUpdateNonce the proposal nonce (to prevent replay attacks) - * @param _sig the DKGs signature of the aforementioned parameters - */ - function updateProposerSetData( - bytes32 _proposerSetRoot, - uint64 _averageSessionLengthInMillisecs, - uint32 _numOfProposers, - uint32 _proposerSetUpdateNonce, - bytes memory _sig - ) public { - // Valid Nonce - require(proposerSetUpdateNonce < _proposerSetUpdateNonce, "Invalid nonce"); - require(_proposerSetUpdateNonce <= proposerSetUpdateNonce + 1, "Nonce must not increment more than 1"); - - // Valid Signature - require(isSignatureFromGovernor( - abi.encodePacked( - _proposerSetRoot, - bytes8(_averageSessionLengthInMillisecs), - bytes4(_numOfProposers), - bytes4(_proposerSetUpdateNonce)), - _sig - ), "Governable: caller is not the governor" - ); - - proposerSetRoot = _proposerSetRoot; - averageSessionLengthInMillisecs = _averageSessionLengthInMillisecs; - numOfProposers = _numOfProposers; - proposerSetUpdateNonce = _proposerSetUpdateNonce; - currentVotingPeriod++; - } - - /** + function _transferOwnership(address newOwner) internal { + require(newOwner != address(0), "Governable: new owner is the zero address"); + emit GovernanceOwnershipTransferred(_governor, newOwner); + _governor = newOwner; + lastGovernorUpdateTime = block.timestamp; + currentVotingPeriod++; + } + + /** + * @notice Updates the proposer set data if a valid signature from the DKG is provided. The * data consists proposerSetRoot, the average session length in milliseconds, the * number of proposers, and the proposal nonce. + * @param _proposerSetRoot the root hash of the proposer set Merkle tree + * @param _averageSessionLengthInMillisecs the average DKG session length in milliseconds + * @param _numOfProposers the total number of proposers + * @param _proposerSetUpdateNonce the proposal nonce (to prevent replay attacks) + * @param _sig the DKGs signature of the aforementioned parameters + */ + function updateProposerSetData( + bytes32 _proposerSetRoot, + uint64 _averageSessionLengthInMillisecs, + uint32 _numOfProposers, + uint32 _proposerSetUpdateNonce, + bytes memory _sig + ) public { + // Valid Nonce + require(proposerSetUpdateNonce < _proposerSetUpdateNonce, "Invalid nonce"); + require( + _proposerSetUpdateNonce <= proposerSetUpdateNonce + 1, + "Nonce must not increment more than 1" + ); + + // Valid Signature + require( + isSignatureFromGovernor( + abi.encodePacked( + _proposerSetRoot, + bytes8(_averageSessionLengthInMillisecs), + bytes4(_numOfProposers), + bytes4(_proposerSetUpdateNonce) + ), + _sig + ), + "Governable: caller is not the governor" + ); + + proposerSetRoot = _proposerSetRoot; + averageSessionLengthInMillisecs = _averageSessionLengthInMillisecs; + numOfProposers = _numOfProposers; + proposerSetUpdateNonce = _proposerSetUpdateNonce; + currentVotingPeriod++; + } + + /** @notice Casts a vote in favor of force refreshing the governor @param vote A vote struct */ - function voteInFavorForceSetGovernor(Vote memory vote) external { - // Check block time stamp is some length greater than the last time - // ownership transferred - require(block.timestamp >= lastGovernorUpdateTime + sessionLengthMultiplier * (averageSessionLengthInMillisecs / 1000), "Invalid time for vote"); - address proposerAddress = msg.sender; - // Check merkle proof is valid - require(_isValidMerkleProof(vote.siblingPathNodes, proposerAddress, vote.leafIndex), "invalid merkle proof"); - - // Make sure proposer has not already voted - require(!alreadyVoted[currentVotingPeriod][proposerAddress], "already voted"); - - alreadyVoted[currentVotingPeriod][proposerAddress] = true; - numOfVotesForGovernor[currentVotingPeriod][vote.proposedGovernor] += 1; - _tryResolveVote(vote.proposedGovernor); - } - - /** + function voteInFavorForceSetGovernor(Vote memory vote) external { + // Check block time stamp is some length greater than the last time + // ownership transferred + require( + block.timestamp >= + lastGovernorUpdateTime + + sessionLengthMultiplier * + (averageSessionLengthInMillisecs / 1000), + "Invalid time for vote" + ); + address proposerAddress = msg.sender; + // Check merkle proof is valid + require( + _isValidMerkleProof(vote.siblingPathNodes, proposerAddress, vote.leafIndex), + "invalid merkle proof" + ); + + // Make sure proposer has not already voted + require(!alreadyVoted[currentVotingPeriod][proposerAddress], "already voted"); + + alreadyVoted[currentVotingPeriod][proposerAddress] = true; + numOfVotesForGovernor[currentVotingPeriod][vote.proposedGovernor] += 1; + _tryResolveVote(vote.proposedGovernor); + } + + /** @notice Tries and resolves the vote by checking the number of votes for a proposed governor is greater than numOfProposers/2. @param proposedGovernor the address to transfer ownership to, if the vote passes */ - function _tryResolveVote(address proposedGovernor) internal { - if (numOfVotesForGovernor[currentVotingPeriod][proposedGovernor] > numOfProposers / 2) { - _transferOwnership(proposedGovernor); - } - } + function _tryResolveVote(address proposedGovernor) internal { + if (numOfVotesForGovernor[currentVotingPeriod][proposedGovernor] > numOfProposers / 2) { + _transferOwnership(proposedGovernor); + } + } - /** + /** @notice Checks a merkle proof given a leaf and merkle path of sibling nodes. @param siblingPathNodes the path of sibling nodes of the Merkle proof @param leaf the leaf to prove membership of in the Merkle tree @param leafIndex the index of the leaf in the Merkle tree */ - function _isValidMerkleProof(bytes32[] memory siblingPathNodes, address leaf, uint32 leafIndex) internal view returns (bool) { - bytes32 leafHash = keccak256(abi.encodePacked(leaf)); - bytes32 currNodeHash = leafHash; - uint32 nodeIndex = leafIndex; - - for (uint8 i = 0; i < siblingPathNodes.length; i++) { - if (nodeIndex % 2 == 0) { - currNodeHash = keccak256(abi.encodePacked(currNodeHash, siblingPathNodes[i])); - } else { - currNodeHash = keccak256(abi.encodePacked(siblingPathNodes[i], currNodeHash)); - } - nodeIndex = nodeIndex / 2; - } - return proposerSetRoot == currNodeHash; - } + function _isValidMerkleProof( + bytes32[] memory siblingPathNodes, + address leaf, + uint32 leafIndex + ) internal view returns (bool) { + bytes32 leafHash = keccak256(abi.encodePacked(leaf)); + bytes32 currNodeHash = leafHash; + uint32 nodeIndex = leafIndex; + + for (uint8 i = 0; i < siblingPathNodes.length; i++) { + if (nodeIndex % 2 == 0) { + currNodeHash = keccak256(abi.encodePacked(currNodeHash, siblingPathNodes[i])); + } else { + currNodeHash = keccak256(abi.encodePacked(siblingPathNodes[i], currNodeHash)); + } + nodeIndex = nodeIndex / 2; + } + return proposerSetRoot == currNodeHash; + } } diff --git a/packages/contracts/contracts/utils/Initialized.sol b/packages/contracts/contracts/utils/Initialized.sol index 4f21f53c7..8b694f269 100644 --- a/packages/contracts/contracts/utils/Initialized.sol +++ b/packages/contracts/contracts/utils/Initialized.sol @@ -10,15 +10,15 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ contract Initialized { - bool public initialized; + bool public initialized; - modifier onlyUninitialized() { - require(!initialized, "Initialized: Already initialized"); - _; - } + modifier onlyUninitialized() { + require(!initialized, "Initialized: Already initialized"); + _; + } - modifier onlyInitialized() { - require(initialized, "Initialized: Not initialized"); - _; - } + modifier onlyInitialized() { + require(initialized, "Initialized: Not initialized"); + _; + } } diff --git a/packages/contracts/contracts/utils/Pausable.sol b/packages/contracts/contracts/utils/Pausable.sol index e9ae71338..ee24cf83c 100644 --- a/packages/contracts/contracts/utils/Pausable.sol +++ b/packages/contracts/contracts/utils/Pausable.sol @@ -14,85 +14,85 @@ pragma solidity ^0.8.0; * */ abstract contract Pausable { - /** - * @dev Emitted when the pause is triggered by `account`. - */ - event Paused(address account); + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); - /** - * @dev Emitted when the pause is lifted by `account`. - */ - event Unpaused(address account); + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); - bool private _paused; + bool private _paused; - /** - * @dev Initializes the contract in unpaused state. - */ - constructor () { - _paused = false; - } + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view returns (bool) { - return _paused; - } + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view returns (bool) { + return _paused; + } - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenNotPaused() { - _whenNotPaused(); - _; - } + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _whenNotPaused(); + _; + } - function _whenNotPaused() private view { - require(!_paused, "Pausable: paused"); - } + function _whenNotPaused() private view { + require(!_paused, "Pausable: paused"); + } - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenPaused() { - _whenPaused(); - _; - } + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenPaused() { + _whenPaused(); + _; + } - function _whenPaused() private view { - require(_paused, "Pausable: not paused"); - } + function _whenPaused() private view { + require(_paused, "Pausable: not paused"); + } - /** - * @dev Triggers stopped state. - * - * Requirements: - * - * - The contract must not be paused. - */ - function _pause() internal virtual whenNotPaused { - _paused = true; - emit Paused(msg.sender); - } + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(msg.sender); + } - /** - * @dev Returns to normal state. - * - * Requirements: - * - * - The contract must be paused. - */ - function _unpause() internal virtual whenPaused { - _paused = false; - emit Unpaused(msg.sender); - } -} \ No newline at end of file + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(msg.sender); + } +} diff --git a/packages/contracts/contracts/utils/ProposalNonceTracker.sol b/packages/contracts/contracts/utils/ProposalNonceTracker.sol index d1604f8d0..056bfc656 100644 --- a/packages/contracts/contracts/utils/ProposalNonceTracker.sol +++ b/packages/contracts/contracts/utils/ProposalNonceTracker.sol @@ -10,23 +10,29 @@ pragma solidity ^0.8.0; @author Webb Technologies. */ contract ProposalNonceTracker { - uint256 public proposalNonce; + uint256 public proposalNonce; - modifier onlyIncrementingByOne(uint nonce) { - require(proposalNonce < nonce, "ProposalNonceTracker: Invalid nonce"); - require(nonce <= proposalNonce + 1, "ProposalNonceTracker: Nonce must not increment more than 1"); - proposalNonce = nonce; - _; - } + modifier onlyIncrementingByOne(uint nonce) { + require(proposalNonce < nonce, "ProposalNonceTracker: Invalid nonce"); + require( + nonce <= proposalNonce + 1, + "ProposalNonceTracker: Nonce must not increment more than 1" + ); + proposalNonce = nonce; + _; + } - modifier onlyIncrementingByAtMost1048(uint nonce) { - require(proposalNonce < nonce, "ProposalNonceTracker: Invalid nonce"); - require(nonce <= proposalNonce + 1048, "ProposalNonceTracker: Nonce must not increment more than 1"); - proposalNonce = nonce; - _; - } + modifier onlyIncrementingByAtMost1048(uint nonce) { + require(proposalNonce < nonce, "ProposalNonceTracker: Invalid nonce"); + require( + nonce <= proposalNonce + 1048, + "ProposalNonceTracker: Nonce must not increment more than 1" + ); + proposalNonce = nonce; + _; + } - function getProposalNonce() external view returns (uint256) { - return proposalNonce; - } + function getProposalNonce() external view returns (uint256) { + return proposalNonce; + } } diff --git a/packages/contracts/contracts/utils/SanctionFilter.sol b/packages/contracts/contracts/utils/SanctionFilter.sol index 2b098225a..03052714a 100644 --- a/packages/contracts/contracts/utils/SanctionFilter.sol +++ b/packages/contracts/contracts/utils/SanctionFilter.sol @@ -8,11 +8,11 @@ import "../interfaces/external/chainalysis/ISanctionsList.sol"; pragma solidity ^0.8.0; contract SanctionFilter { - address constant SANCTIONS_CONTRACT = 0x40C57923924B5c5c5455c48D93317139ADDaC8fb; + address constant SANCTIONS_CONTRACT = 0x40C57923924B5c5c5455c48D93317139ADDaC8fb; - modifier isNotSanctioned(address addr) { - ISanctionsList sanctionsList = ISanctionsList(SANCTIONS_CONTRACT); - require(!sanctionsList.isSanctioned(addr), "SanctionFilter: Sanctioned address"); - _; - } + modifier isNotSanctioned(address addr) { + ISanctionsList sanctionsList = ISanctionsList(SANCTIONS_CONTRACT); + require(!sanctionsList.isSanctioned(addr), "SanctionFilter: Sanctioned address"); + _; + } } diff --git a/packages/contracts/contracts/vanchors/ChainalysisVAnchor.sol b/packages/contracts/contracts/vanchors/ChainalysisVAnchor.sol deleted file mode 100644 index 0ade6dcc5..000000000 --- a/packages/contracts/contracts/vanchors/ChainalysisVAnchor.sol +++ /dev/null @@ -1,348 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "./VAnchorBase.sol"; -import "../structs/SingleAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../interfaces/verifiers/ISetVerifier.sol"; -import "../utils/SanctionFilter.sol"; -import "../libs/VAnchorEncodeInputs.sol"; -import "../verifiers/TxProofVerifier.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Chainalysis Variable Anchor contract - @author Webb Technologies - @notice The main addition here is a filter for sanctioned addresses on transactions. - */ -contract ChainalysisVAnchor is VAnchorBase, TxProofVerifier, SanctionFilter, ISetVerifier { - using SafeERC20 for IERC20; - using SafeMath for uint256; - address public immutable token; - - /** - @notice The VAnchor constructor - @param _verifier The address of SNARK verifier for this contract - @param _levels The height/# of levels of underlying Merkle Tree - @param _hasher The address of hash contract - @param _handler The address of AnchorHandler for this contract - @param _token The address of the token that is used to pay the deposit - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - IAnchorVerifier _verifier, - uint32 _levels, - IHasher _hasher, - address _handler, - address _token, - uint8 _maxEdges - ) - VAnchorBase (_levels, _hasher, _handler, _maxEdges) - TxProofVerifier(_verifier) - { - token = _token; - } - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _tokenAddress The address of the token to wrap - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).wrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _tokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @notice The amount is taken from `msg.value` - */ - function wrapNative() payable public { - ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wraps a token for the `msg.sender` - @param _tokenAddress The address of the token to wrap - @param _extAmount The external amount for the transaction - */ - function _executeWrapping( - address _tokenAddress, - uint256 _extAmount - ) payable public isNotSanctioned(msg.sender) { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(token).getAmountToWrap(_extAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_tokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Unwraps into a valid token for the `msg.sender` - @param _tokenAddress The token to unwrap into - @param _recipient The address of the recipient for the unwrapped assets - @param _minusExtAmount Negative external amount for the transaction - */ - function withdrawAndUnwrap( - address _tokenAddress, - address _recipient, - uint256 _minusExtAmount - ) public payable nonReentrant isNotSanctioned(msg.sender) isNotSanctioned(_recipient) { - // We first withdraw the assets and send them to `this` contract address. - // This ensure that when we unwrap the assets, `this` contract has the - // assets to unwrap into. - _processWithdraw(token, payable(address(this)), _minusExtAmount); - - ITokenWrapper(token).unwrapAndSendTo( - _tokenAddress, - _minusExtAmount, - _recipient - ); - } - - /** - @notice Registers and transacts in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function registerAndTransact( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData - ) public isNotSanctioned(msg.sender) isNotSanctioned(_extData.recipient) { - register(_account); - transact(_proofArgs, _extData); - } - - /** - @notice Registers and transacts and wraps in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from - */ - function registerAndTransactWrap( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData, - address _tokenAddress - ) public isNotSanctioned(msg.sender) isNotSanctioned(_extData.recipient) { - register(_account); - transactWrap(_proofArgs, _extData, _tokenAddress); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function transact( - VAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData - ) public nonReentrant isNotSanctioned(msg.sender) isNotSanctioned(_extData.recipient) { - _executeValidationAndVerification(_args, _extData); - - if (_extData.extAmount > 0) { - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - IMintableERC20(token).transferFrom(msg.sender, address(this), uint256(_extData.extAmount)); - } - - if (_extData.extAmount < 0) { - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); // prevents ddos attack to Bridge - _processWithdraw(token, _extData.recipient, uint256(-_extData.extAmount)); - } - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction including wrapping or unwrapping - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from or unwrap into depending on the positivity of `_extData.extAmount` - */ - function transactWrap( - VAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData, - address _tokenAddress - ) public payable isNotSanctioned(msg.sender) isNotSanctioned(_extData.recipient) { - _executeValidationAndVerification(_args, _extData); - - // Check if extAmount > 0, call wrapAndDeposit - if (_extData.extAmount > 0) { - //wrapAndDeposit - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - _executeWrapping(_tokenAddress, uint256(_extData.extAmount)); - } else if (_extData.extAmount < 0) { - // Otherwise, check if extAmount < 0, call withdrawAndUnwrap - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); - withdrawAndUnwrap(_tokenAddress, _extData.recipient, uint256(-_extData.extAmount)); - } - - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Checks whether the transaction is valid - 1. Checks that the nullifiers are not spent - 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) - 3. Checks that the zkSNARK proof verifies - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeValidationAndVerification(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); - } - require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); - _executeVerification(_args); - - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - // sets the nullifier for the input UTXO to spent - nullifierHashes[_args.inputNullifiers[i]] = true; - } - } - - /** - @notice Checks whether the zkSNARK proof is valid - @param _args The zkSNARK proof parameters - */ - function _executeVerification(VAnchorEncodeInputs.Proof memory _args) internal view { - require(_args.inputNullifiers.length == 2 || _args.inputNullifiers.length == 16, "Invalid number of inputs"); - bool smallInputs = _args.inputNullifiers.length == 2; - (bytes memory encodedInput, bytes32[] memory roots) = smallInputs - ? VAnchorEncodeInputs._encodeInputs2(_args, maxEdges) - : VAnchorEncodeInputs._encodeInputs16(_args, maxEdges); - - - require(isValidRoots(roots), "Invalid vanchor roots"); - require(verify(_args.proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); - } - - /** - @notice Inserts the output commitments into the underlying merkle tree - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeInsertions(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - insertTwo(_args.outputCommitments[0], _args.outputCommitments[1]); - emit NewCommitment(_args.outputCommitments[0], nextIndex - 2, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], nextIndex - 1, _extData.encryptedOutput2); - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - emit NewNullifier(_args.inputNullifiers[i]); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _token The token to withdraw - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _token The token to pay the fee in - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } - - /** - @notice Set a new verifier with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _verifier The new verifier address - @param _nonce The nonce for updating the new verifier - */ - function setVerifier( - address _verifier, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_verifier != address(0), "Handler cannot be 0"); - verifier = IAnchorVerifier(_verifier); - } -} diff --git a/packages/contracts/contracts/vanchors/IdentityVAnchor.sol b/packages/contracts/contracts/vanchors/IdentityVAnchor.sol deleted file mode 100644 index da2100911..000000000 --- a/packages/contracts/contracts/vanchors/IdentityVAnchor.sol +++ /dev/null @@ -1,357 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../structs/SingleAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../interfaces/anchors/ISemaphoreGroups.sol"; -import "../interfaces/verifiers/IAnchorVerifier.sol"; -import "../interfaces/verifiers/ISetVerifier.sol"; -import "../vanchors/VAnchorBase.sol"; -import "../verifiers/TxProofVerifier.sol"; -import "../libs/IdentityVAnchorEncodeInputs.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Identity VAnchor contract - @author Webb Technologies - - @notice The Identity Variable Anchor is a variable-denominated shielded pool system - derived from Tornado Nova (tornado-pool) with identity constrains on top. This system - extends the shielded pool system into a bridged system and allows for join/split transactions. - The identity extensions extends the shielded to pool to only allow for transactions from - users who maintain membership within a cross-chain Semaphore identity set. - - The system is built on top the VAnchorBase/AnchorBase/LinkableAnchor system which allows - it to be linked to other VAnchor contracts through a simple graph-like - interface where anchors maintain edges of their neighboring anchors. - - The system requires users to create and deposit UTXOs for the supported ERC20 - asset into the smart contract and insert a commitment into the underlying - merkle tree of the form: commitment = Poseidon(chainID, amount, pubKey, blinding). - The hash input is the UTXO data. All deposits/withdrawals are unified under - a common `transact` function which requires a zkSNARK proof that the UTXO commitments - are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). - - Information regarding the commitments: - - Poseidon is a zkSNARK friendly hash function - - destinationChainID is the chainId of the destination chain, where the withdrawal - is intended to be made - - Details of the UTXO and hashes are below - - UTXO = { destinationChainID, amount, pubkey, blinding } - commitment = Poseidon(destinationChainID, amount, pubKey, blinding) - nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) - - Commitments adhering to different hash functions and formats will invalidate - any attempt at withdrawal. - - Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that - the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's - destination chain id matches the underlying chain id of the VAnchor where the - transaction is taking place. The chain id opcode is leveraged to prevent any - tampering of this data. - */ -contract IdentityVAnchor is VAnchorBase, TxProofVerifier, ISetVerifier { - using SafeERC20 for IERC20; - using SafeMath for uint256; - address public immutable token; - ISemaphoreGroups SemaphoreContract; - uint256 public immutable groupId; // Assumes group is already setup on the semaphore contract - - /** - @notice The Identity VAnchor constructor - @param _semaphore The address of Semaphore contract - @param _verifier The address of SNARK verifier for this contract - @param _levels The height/# of levels of underlying Merkle Tree - @param _hasher The address of hash contract - @param _handler The address of AnchorHandler for this contract - @param _token The address of the token that is used to pay the deposit - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - ISemaphoreGroups _semaphore, - IAnchorVerifier _verifier, - uint8 _levels, - IHasher _hasher, - address _handler, - address _token, - uint8 _maxEdges, - uint256 _groupId - ) - VAnchorBase (_levels, _hasher, _handler, _maxEdges) - TxProofVerifier(_verifier) - { - token = _token; - SemaphoreContract = _semaphore; - groupId = _groupId; - } - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _tokenAddress The address of the token to wrap - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).wrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _tokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @notice The amount is taken from `msg.value` - */ - function wrapNative() payable public { - ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wraps a token for the `msg.sender` - @param _tokenAddress The address of the token to wrap - @param _extAmount The external amount for the transaction - */ - function _executeWrapping( - address _tokenAddress, - uint256 _extAmount - ) payable public { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(token).getAmountToWrap(_extAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_tokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Unwraps into a valid token for the `msg.sender` - @param _tokenAddress The token to unwrap into - @param _recipient The address of the recipient for the unwrapped assets - @param _minusExtAmount Negative external amount for the transaction - */ - function withdrawAndUnwrap( - address _tokenAddress, - address _recipient, - uint256 _minusExtAmount - ) public payable nonReentrant { - // We first withdraw the assets and send them to `this` contract address. - // This ensure that when we unwrap the assets, `this` contract has the - // assets to unwrap into. - _processWithdraw(token, payable(address(this)), _minusExtAmount); - - ITokenWrapper(token).unwrapAndSendTo( - _tokenAddress, - _minusExtAmount, - _recipient - ); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function transact(IdentityVAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) public nonReentrant { - _executeValidationAndVerification(_args, _extData); - - if (_extData.extAmount > 0) { - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - IMintableERC20(token).transferFrom(msg.sender, address(this), uint256(_extData.extAmount)); - } - - if (_extData.extAmount < 0) { - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); // prevents ddos attack to Bridge - _processWithdraw(token, _extData.recipient, uint256(-_extData.extAmount)); - } - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction including wrapping or unwrapping - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from or unwrap into depending on the positivity of `_extData.extAmount` - */ - function transactWrap( - IdentityVAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData, - address _tokenAddress - ) public payable { - _executeValidationAndVerification(_args, _extData); - - // Check if extAmount > 0, call wrapAndDeposit - if (_extData.extAmount > 0) { - // wrapAndDeposit - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - _executeWrapping(_tokenAddress, uint256(_extData.extAmount)); - } else if (_extData.extAmount < 0) { - // Otherwise, check if extAmount < 0, call withdrawAndUnwrap - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); - withdrawAndUnwrap(_tokenAddress, _extData.recipient, uint256(-_extData.extAmount)); - } - - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Checks whether the transaction is valid - 1. Checks that the nullifiers are not spent - 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) - 3. Checks that the zkSNARK proof verifies - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeValidationAndVerification(IdentityVAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); - } - require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); - _executeVerification(_args); - - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - // sets the nullifier for the input UTXO to spent - nullifierHashes[_args.inputNullifiers[i]] = true; - } - } - - /** - @notice Checks whether the zkSNARK proof is valid - @param _args The zkSNARK proof parameters - */ - function _executeVerification(IdentityVAnchorEncodeInputs.Proof memory _args) internal view { - require(_args.inputNullifiers.length == 2 || _args.inputNullifiers.length == 16, "Invalid number of inputs"); - bool smallInputs = _args.inputNullifiers.length == 2; - (bytes memory encodedInput, bytes32[] memory roots) = smallInputs - ? IdentityVAnchorEncodeInputs._encodeInputs2(_args, maxEdges) - : IdentityVAnchorEncodeInputs._encodeInputs16(_args, maxEdges); - - - require(SemaphoreContract.verifyRoots(groupId, _args.identityRoots), "Invalid identity roots"); - require(isValidRoots(roots), "Invalid vanchor roots"); - require(verify(_args.proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); - } - - /** - @notice Inserts the output commitments into the underlying merkle tree - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeInsertions(IdentityVAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - insertTwo(_args.outputCommitments[0], _args.outputCommitments[1]); - emit NewCommitment(_args.outputCommitments[0], nextIndex - 2, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], nextIndex - 1, _extData.encryptedOutput2); - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - emit NewNullifier(_args.inputNullifiers[i]); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _token The address of the token to withdraw - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _token The token to pay the fee in - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } - - /** - @notice Set a new verifier with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _verifier The new verifier address - @param _nonce The nonce for updating the new verifier - */ - function setVerifier( - address _verifier, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_verifier != address(0), "Handler cannot be 0"); - verifier = IAnchorVerifier(_verifier); - } -} diff --git a/packages/contracts/contracts/vanchors/MultiAssetVAnchor.sol b/packages/contracts/contracts/vanchors/MultiAssetVAnchor.sol deleted file mode 100644 index 5d9f12c0c..000000000 --- a/packages/contracts/contracts/vanchors/MultiAssetVAnchor.sol +++ /dev/null @@ -1,429 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../vanchors/VAnchorBase.sol"; -import "../structs/MultiAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../interfaces/tokens/IRegistry.sol"; -import "../interfaces/verifiers/IAnchorVerifier.sol"; -import "../verifiers/TxProofVerifier.sol"; -import "../libs/VAnchorEncodeInputs.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Multi Asset Variable Anchor contract - @author Webb Technologies - @notice The Multi Asset Variable Anchor is a variable-denominated shielded pool system - derived from Tornado Nova (tornado-pool) that supports multiple assets in a single pool. - This system extends the shielded pool system into a bridged system and allows for - join/split transactions of different assets at 2 same time. - - The system is built on top the MultiAssetVAnchorBase/AnchorBase/LinkableAnchor system - which allows it to be linked to other VAnchor contracts through a simple graph-like - interface where anchors maintain edges of their neighboring anchors. - - The system requires users to create UTXOs for any supported ERC20 asset into the smart - contract and insert a commitment into the underlying merkle tree of the form: - ``` - commitment = Poseidon(assetId, amount, Poseidon(destinationChainID, pubKey, blinding)). - ``` - The hash input is the UTXO data. All deposits/withdrawals are unified under - a common `transact` function which requires a zkSNARK proof that the UTXO commitments - are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). - - Information regarding the commitments: - - Poseidon is a zkSNARK friendly hash function - - destinationChainID is the chainId of the destination chain, where the withdrawal - is intended to be made - - Details of the UTXO and hashes are below - - UTXO = { assetId, amount, Poseidon(destinationChainID, pubKey, blinding) } - commitment = Poseidon(assetId, amount, Poseidon(destinationChainID, pubKey, blinding)) - nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) - - Commitments adhering to different hash functions and formats will invalidate - any attempt at withdrawal. - - Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that - the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's - destination chain id matches the underlying chain id of the VAnchor where the - transaction is taking place. The chain id opcode is leveraged to prevent any - tampering of this data. - - Part of the benefit of a MASP is the ability to handle multiple assets in a single pool. - To support this, the system uses a `assetId` field in the UTXO to identify the asset. - One thing to remember is that all assets in the pool must be wrapped ERC20 tokens specific - to the pool. We refer to this tokens as the bridge ERC20 tokens. Part of the challenge of building - the MASP then is dealing with the mapping between bridge ERC20s and their asset IDs. - - IMPORTANT: A bridge ERC20 token MUST have the same assetID across chain. - */ -contract MultiAssetVAnchor is VAnchorBase, TxProofVerifier { - using SafeERC20 for IERC20; - using SafeMath for uint256; - - address public registry; - - /** - @notice The VAnchor constructor - @param _verifier The address of SNARK verifier for this contract - @param _levels The height/# of levels of underlying Merkle Tree - @param _hasher The address of hash contract - @param _handler The address of AnchorHandler for this contract - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - IAnchorVerifier _verifier, - uint32 _levels, - IHasher _hasher, - address _handler, - uint8 _maxEdges - ) - VAnchorBase (_levels, _hasher, _handler, _maxEdges) - TxProofVerifier(_verifier) - {} - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _fromTokenAddress The address of the token to wrap from - @param _toTokenAddress The address of the token to wrap into - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _fromTokenAddress, address _toTokenAddress, uint256 _amount) public { - ITokenWrapper(_fromTokenAddress).wrapFor(msg.sender, _toTokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _fromTokenAddress The address of the token to unwrap from - @param _toTokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _fromTokenAddress, address _toTokenAddress, uint256 _amount) public { - ITokenWrapper(_fromTokenAddress).unwrapFor(msg.sender, _toTokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @param _toTokenAddress The address of the token to wrap into - @notice The amount is taken from `msg.value` - */ - function wrapNative(address _toTokenAddress) payable public { - ITokenWrapper(_toTokenAddress).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _fromTokenAddress The address of the token to unwrap from - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _fromTokenAddress, uint256 _amount) public { - ITokenWrapper(_fromTokenAddress).unwrapFor(msg.sender, address(0), _amount); - } - - /** - @notice Wraps a token for the `msg.sender` - @param _fromTokenAddress The address of the token to wrap from - @param _toTokenAddress The address of the token to wrap into - @param _extAmount The external amount for the transaction - */ - function _executeWrapping( - address _fromTokenAddress, - address _toTokenAddress, - uint256 _extAmount - ) payable public { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(_toTokenAddress).getAmountToWrap(_extAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_fromTokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(_toTokenAddress).wrapForAndSendTo{value: msg.value}( - msg.sender, - _fromTokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(_toTokenAddress).wrapForAndSendTo{value: msg.value}( - msg.sender, - _fromTokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Unwraps into a valid token for the `msg.sender` - @param _fromTokenAddress The address of the token to unwrap from - @param _toTokenAddress The address of the token to unwrap into - @param _recipient The address of the recipient for the unwrapped assets - @param _minusExtAmount Negative external amount for the transaction - */ - function withdrawAndUnwrap( - address _fromTokenAddress, - address _toTokenAddress, - address _recipient, - uint256 _minusExtAmount - ) public payable nonReentrant { - // We first withdraw the assets and send them to `this` contract address. - // This ensure that when we unwrap the assets, `this` contract has the - // assets to unwrap into. - _processWithdraw(_fromTokenAddress, payable(address(this)), _minusExtAmount); - - ITokenWrapper(_fromTokenAddress).unwrapAndSendTo( - _toTokenAddress, - _minusExtAmount, - _recipient - ); - } - - /** - @notice Registers and transacts in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function registerAndTransact( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData - ) public { - register(_account); - transact(_proofArgs, _extData); - } - - /** - @notice Registers and transacts and wraps in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from - */ - function registerAndTransactWrap( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData, - address _tokenAddress - ) public { - register(_account); - transactWrap(_proofArgs, _extData, _tokenAddress); - } - - /** - @notice Wraps and deposits in a single flow without a proof. Leads to a single non-zero UTXO. - @param _fromTokenAddress The address of the token to wrap from - @param _toTokenAddress The address of the token to wrap into - @param _amount The amount of tokens to wrap - @param partialCommitment The partial commitment of the UTXO - @param encryptedCommitment The encrypted commitment of the partial UTXO - */ - function wrapAndDepositERC20( - address _fromTokenAddress, - address _toTokenAddress, - uint256 _amount, - bytes32 partialCommitment, - bytes memory encryptedCommitment - ) public payable { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(_toTokenAddress).getAmountToWrap(_amount); - - if (_fromTokenAddress == address(0)) { - require(msg.value == _amount); - ITokenWrapper(_toTokenAddress).wrapForAndSendTo{value: msg.value}( - msg.sender, - _fromTokenAddress, - 0, - address(this) - ); - } else { - ITokenWrapper(_toTokenAddress).wrapForAndSendTo{value: msg.value}( - msg.sender, - _fromTokenAddress, - _amount, - address(this) - ); - } - - uint256 assetID = IRegistry(registry).getAssetId(_toTokenAddress); - bytes32 commitment = bytes32(IHasher(hasher).hash3([ - assetID, - wrapAmount, - uint256(partialCommitment) - ])); - bytes32 zeroCommitment = bytes32(IHasher(hasher).hash3([ - uint256(0), - uint256(0), - uint256(0) - ])); - insertTwo(commitment, zeroCommitment); - emit NewCommitment(commitment, nextIndex - 2, encryptedCommitment); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function transact(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) public nonReentrant { - _executeValidationAndVerification(_args, _extData); - - address wrappedToken = IRegistry(registry).getAssetAddress(_extData.assetId); - if (_extData.extAmount > 0) { - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - IMintableERC20(_extData.token).transferFrom(msg.sender, address(this), uint256(_extData.extAmount)); - } - - if (_extData.extAmount < 0) { - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); // prevents ddos attack to Bridge - _processWithdraw(_extData.token, _extData.recipient, uint256(-_extData.extAmount)); - } - if (_extData.fee > 0) { - _processFee(wrappedToken, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction including wrapping or unwrapping - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from or unwrap into depending on the positivity of `_extData.extAmount` - */ - function transactWrap( - VAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData, - address _tokenAddress - ) public payable { - _executeValidationAndVerification(_args, _extData); - - address wrappedToken = IRegistry(registry).getAssetAddress(_extData.assetId); - // Check if extAmount > 0, call wrapAndDeposit - if (_extData.extAmount > 0) { - //wrapAndDeposit - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - _executeWrapping(_tokenAddress, wrappedToken, uint256(_extData.extAmount)); - } else if (_extData.extAmount < 0) { - // Otherwise, check if extAmount < 0, call withdrawAndUnwrap - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); - withdrawAndUnwrap(wrappedToken, _tokenAddress, _extData.recipient, uint256(-_extData.extAmount)); - } - - if (_extData.fee > 0) { - _processFee(wrappedToken, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Checks whether the transaction is valid - 1. Checks that the nullifiers are not spent - 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) - 3. Checks that the zkSNARK proof verifies - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeValidationAndVerification(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); - } - require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); - _executeVerification(_args); - - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - // sets the nullifier for the input UTXO to spent - nullifierHashes[_args.inputNullifiers[i]] = true; - } - } - - /** - @notice Checks whether the zkSNARK proof is valid - @param _args The zkSNARK proof parameters - */ - function _executeVerification(VAnchorEncodeInputs.Proof memory _args) view internal { - require(_args.inputNullifiers.length == 2 || _args.inputNullifiers.length == 16, "Invalid number of inputs"); - bool smallInputs = _args.inputNullifiers.length == 2; - (bytes memory encodedInput, bytes32[] memory roots) = smallInputs - ? VAnchorEncodeInputs._encodeInputs2(_args, maxEdges) - : VAnchorEncodeInputs._encodeInputs16(_args, maxEdges); - - - require(isValidRoots(roots), "Invalid vanchor roots"); - require(verify(_args.proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); - } - - /** - @notice Inserts the output commitments into the underlying merkle tree - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeInsertions(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - insertTwo(_args.outputCommitments[0], _args.outputCommitments[1]); - emit NewCommitment(_args.outputCommitments[0], nextIndex - 2, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], nextIndex - 1, _extData.encryptedOutput2); - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - emit NewNullifier(_args.inputNullifiers[i]); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } -} diff --git a/packages/contracts/contracts/vanchors/OpenVAnchor.sol b/packages/contracts/contracts/vanchors/OpenVAnchor.sol deleted file mode 100644 index 3971007cf..000000000 --- a/packages/contracts/contracts/vanchors/OpenVAnchor.sol +++ /dev/null @@ -1,301 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "../vanchors/VAnchorBase.sol"; -import "../structs/SingleAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../utils/ChainIdWithType.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Open Variable Anchor contract - @author Webb Technologies - @notice The Variable Anchor is a variable-denominated public pool system - derived from Webb's Shielded VAnchor. This system extends the anchor protocol - in a public way by enabling public cross-chain asset transfers. - - The system is built on top the OpenAnchorBase/OpenLinkableAnchor system which allows - it to be linked to other OpenVAnchor contracts through a simple graph-like - interface where anchors maintain edges of their neighboring anchors. - - The system requires users to supply all inputs in the clear. Commitments are constructed - inside of the smart contract and inserted into a merkle tree for easy cross-chain state updates. - */ -contract OpenVAnchor is VAnchorBase { - using SafeERC20 for IERC20; - using SafeMath for uint256; - address public immutable token; - - constructor( - uint32 _levels, - IHasher _hasher, - address _handler, - address _token - ) VAnchorBase ( - _levels, - _hasher, - _handler, - 255 - ) { token = _token; } - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _tokenAddress The address of the token to wrap - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).wrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _tokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @notice The amount is taken from `msg.value` - */ - function wrapNative() payable public { - ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - function deposit( - uint48 destinationChainId, - uint256 depositAmount, - address recipient, - bytes calldata delegatedCalldata, - uint256 blinding, - uint256 relayingFee - ) public nonReentrant { - require(depositAmount <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - bytes32 commitment = keccak256(abi.encodePacked( - destinationChainId, - depositAmount, - recipient, - keccak256(delegatedCalldata), - blinding, - relayingFee - )); - // Send the wrapped asset directly to this contract. - IERC20(token).transferFrom(msg.sender, address(this), depositAmount); - // Insert the commitment - _executeInsertion(commitment); - } - - function wrapAndDeposit( - uint48 destinationChainId, - uint256 depositAmount, - address recipient, - bytes calldata delegatedCalldata, - uint256 blinding, - uint256 relayingFee, - address tokenAddress - ) public payable nonReentrant { - require(depositAmount <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - bytes32 commitment = keccak256(abi.encodePacked( - destinationChainId, - depositAmount, - recipient, - keccak256(delegatedCalldata), - blinding, - relayingFee - )); - // Send the `tokenAddress` asset to the `TokenWrapper` and mint this contract the wrapped asset. - _executeWrapping(tokenAddress, depositAmount); - // Insert the commitment - _executeInsertion(commitment); - } - - function withdraw( - uint256 withdrawAmount, - address recipient, - bytes memory delegatedCalldata, - uint256 blinding, - uint256 relayingFee, - bytes32[] memory merkleProof, - uint32 commitmentIndex, - bytes32 root - ) public nonReentrant { - bytes32 commitment = keccak256(abi.encodePacked( - getChainIdType(), - withdrawAmount, - recipient, - keccak256(delegatedCalldata), - blinding, - relayingFee - )); - require(_isValidMerkleProof(merkleProof, commitment, commitmentIndex, root), "Invalid Merkle Proof"); - nullifierHashes[commitment] = true; - // Send the wrapped token to the recipient. - _processWithdraw(token, recipient, withdrawAmount.sub(relayingFee)); - if (msg.sender != recipient) { - // Send the fee to the relayer - _processFee(token, msg.sender, relayingFee); - } - } - - function withdrawAndUnwrap( - uint256 withdrawAmount, - address recipient, - bytes memory delegatedCalldata, - uint256 blinding, - uint256 relayingFee, - bytes32[] memory merkleProof, - uint32 commitmentIndex, - bytes32 root, - address tokenAddress - ) public payable nonReentrant { - bytes32 commitment = keccak256(abi.encodePacked( - getChainIdType(), - withdrawAmount, - recipient, - keccak256(delegatedCalldata), - blinding, - relayingFee - )); - require(_isValidMerkleProof(merkleProof, commitment, commitmentIndex, root), "Invalid Merkle Proof"); - _processWithdraw(token, payable(address(this)), withdrawAmount); - nullifierHashes[commitment] = true; - - ITokenWrapper(token).unwrapAndSendTo( - tokenAddress, - withdrawAmount.sub(relayingFee), - recipient - ); - - if (msg.sender != recipient) { - // Send the fee to the relayer - _processFee(token, msg.sender, relayingFee); - } - } - - function _executeInsertion(bytes32 commitment) internal { - insert(commitment); - emit NewCommitment(commitment, nextIndex - 1, ""); - } - - function _executeWrapping( - address _tokenAddress, - uint256 depositAmount - ) payable public { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(token).getAmountToWrap(depositAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_tokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _token The address of the token to withdraw - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _token The token to pay the fee in - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } - - function _isValidMerkleProof( - bytes32[] memory siblingPathNodes, - bytes32 leaf, - uint32 leafIndex, - bytes32 root - ) internal view returns (bool) { - bytes32 currNodeHash = leaf; - uint32 nodeIndex = leafIndex; - - for (uint8 i = 0; i < siblingPathNodes.length; i++) { - if (nodeIndex % 2 == 0) { - currNodeHash = bytes32(hasher.hashLeftRight( - uint256(currNodeHash), - uint256(siblingPathNodes[i]) - )); - } else { - currNodeHash = bytes32(hasher.hashLeftRight( - uint256(siblingPathNodes[i]), - uint256(currNodeHash) - )); - } - nodeIndex = nodeIndex / 2; - } - bool isKnownRootBool= false; - for (uint i = 0; i < edgeList.length; i++) { - isKnownRootBool = isKnownRootBool || isKnownNeighborRoot(edgeList[i].chainID, root); - } - isKnownRootBool = isKnownRootBool || isKnownRoot(root); - return root == currNodeHash && isKnownRootBool; - } - -} diff --git a/packages/contracts/contracts/vanchors/VAnchor.sol b/packages/contracts/contracts/vanchors/VAnchor.sol deleted file mode 100644 index 30588bf7f..000000000 --- a/packages/contracts/contracts/vanchors/VAnchor.sol +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "./VAnchorBase.sol"; -import "../structs/SingleAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../interfaces/verifiers/ISetVerifier.sol"; -import "../libs/VAnchorEncodeInputs.sol"; -import "../verifiers/TxProofVerifier.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Variable Anchor contract - @author Webb Technologies - @notice The Variable Anchor is a variable-denominated shielded pool system - derived from Tornado Nova (tornado-pool). This system extends the shielded - pool system into a bridged system and allows for join/split transactions. - - The system is built on top the VAnchorBase/AnchorBase/LinkableAnchor system which allows - it to be linked to other VAnchor contracts through a simple graph-like - interface where anchors maintain edges of their neighboring anchors. - - The system requires users to create and deposit UTXOs for the supported ERC20 - asset into the smart contract and insert a commitment into the underlying - merkle tree of the form: commitment = Poseidon(chainID, amount, pubKey, blinding). - The hash input is the UTXO data. All deposits/withdrawals are unified under - a common `transact` function which requires a zkSNARK proof that the UTXO commitments - are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). - - Information regarding the commitments: - - Poseidon is a zkSNARK friendly hash function - - destinationChainID is the chainId of the destination chain, where the withdrawal - is intended to be made - - Details of the UTXO and hashes are below - - UTXO = { destinationChainID, amount, pubkey, blinding } - commitment = Poseidon(destinationChainID, amount, pubKey, blinding) - nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) - - Commitments adhering to different hash functions and formats will invalidate - any attempt at withdrawal. - - Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that - the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's - destination chain id matches the underlying chain id of the VAnchor where the - transaction is taking place. The chain id opcode is leveraged to prevent any - tampering of this data. - */ -contract VAnchor is VAnchorBase, TxProofVerifier, ISetVerifier { - using SafeERC20 for IERC20; - using SafeMath for uint256; - address public immutable token; - - /** - @notice The VAnchor constructor - @param _verifier The address of SNARK verifier for this contract - @param _levels The height/# of levels of underlying Merkle Tree - @param _hasher The address of hash contract - @param _handler The address of AnchorHandler for this contract - @param _token The address of the token that is used to pay the deposit - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - IAnchorVerifier _verifier, - uint32 _levels, - IHasher _hasher, - address _handler, - address _token, - uint8 _maxEdges - ) - VAnchorBase (_levels, _hasher, _handler, _maxEdges) - TxProofVerifier(_verifier) - { - token = _token; - } - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _tokenAddress The address of the token to wrap - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).wrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _tokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @notice The amount is taken from `msg.value` - */ - function wrapNative() payable public { - ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wraps a token for the `msg.sender` - @param _tokenAddress The address of the token to wrap - @param _extAmount The external amount for the transaction - */ - function _executeWrapping( - address _tokenAddress, - uint256 _extAmount - ) payable public { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(token).getAmountToWrap(_extAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_tokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Unwraps into a valid token for the `msg.sender` - @param _tokenAddress The token to unwrap into - @param _recipient The address of the recipient for the unwrapped assets - @param _minusExtAmount Negative external amount for the transaction - */ - function withdrawAndUnwrap( - address _tokenAddress, - address _recipient, - uint256 _minusExtAmount - ) public payable nonReentrant { - // We first withdraw the assets and send them to `this` contract address. - // This ensure that when we unwrap the assets, `this` contract has the - // assets to unwrap into. - _processWithdraw(token, payable(address(this)), _minusExtAmount); - - ITokenWrapper(token).unwrapAndSendTo( - _tokenAddress, - _minusExtAmount, - _recipient - ); - } - - /** - @notice Registers and transacts in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function registerAndTransact( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData - ) public { - register(_account); - transact(_proofArgs, _extData); - } - - /** - @notice Registers and transacts and wraps in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from - */ - function registerAndTransactWrap( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData, - address _tokenAddress - ) public { - register(_account); - transactWrap(_proofArgs, _extData, _tokenAddress); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function transact(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) public nonReentrant { - _executeValidationAndVerification(_args, _extData); - - if (_extData.extAmount > 0) { - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - IMintableERC20(token).transferFrom(msg.sender, address(this), uint256(_extData.extAmount)); - } - - if (_extData.extAmount < 0) { - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); // prevents ddos attack to Bridge - _processWithdraw(token, _extData.recipient, uint256(-_extData.extAmount)); - } - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction including wrapping or unwrapping - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from or unwrap into depending on the positivity of `_extData.extAmount` - */ - function transactWrap( - VAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData, - address _tokenAddress - ) public payable { - _executeValidationAndVerification(_args, _extData); - - // Check if extAmount > 0, call wrapAndDeposit - if (_extData.extAmount > 0) { - //wrapAndDeposit - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - _executeWrapping(_tokenAddress, uint256(_extData.extAmount)); - } else if (_extData.extAmount < 0) { - // Otherwise, check if extAmount < 0, call withdrawAndUnwrap - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); - withdrawAndUnwrap(_tokenAddress, _extData.recipient, uint256(-_extData.extAmount)); - } - - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Checks whether the transaction is valid - 1. Checks that the nullifiers are not spent - 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) - 3. Checks that the zkSNARK proof verifies - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeValidationAndVerification(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); - } - require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); - _executeVerification(_args); - - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - // sets the nullifier for the input UTXO to spent - nullifierHashes[_args.inputNullifiers[i]] = true; - } - } - - /** - @notice Checks whether the zkSNARK proof is valid - @param _args The zkSNARK proof parameters - */ - function _executeVerification(VAnchorEncodeInputs.Proof memory _args) internal view { - require(_args.inputNullifiers.length == 2 || _args.inputNullifiers.length == 16, "Invalid number of inputs"); - bool smallInputs = _args.inputNullifiers.length == 2; - (bytes memory encodedInput, bytes32[] memory roots) = smallInputs - ? VAnchorEncodeInputs._encodeInputs2(_args, maxEdges) - : VAnchorEncodeInputs._encodeInputs16(_args, maxEdges); - - - require(isValidRoots(roots), "Invalid vanchor roots"); - require(verify(_args.proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); - } - - /** - @notice Inserts the output commitments into the underlying merkle tree - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeInsertions(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - insertTwo(_args.outputCommitments[0], _args.outputCommitments[1]); - emit NewCommitment(_args.outputCommitments[0], nextIndex - 2, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], nextIndex - 1, _extData.encryptedOutput2); - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - emit NewNullifier(_args.inputNullifiers[i]); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _token The token to withdraw - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _token The token to pay the fee in - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } - - /** - @notice Set a new verifier with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _verifier The new verifier address - @param _nonce The nonce for updating the new verifier - */ - function setVerifier( - address _verifier, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_verifier != address(0), "Handler cannot be 0"); - verifier = IAnchorVerifier(_verifier); - } -} diff --git a/packages/contracts/contracts/vanchors/VAnchorBase.sol b/packages/contracts/contracts/vanchors/VAnchorBase.sol deleted file mode 100644 index 417734611..000000000 --- a/packages/contracts/contracts/vanchors/VAnchorBase.sol +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -import "../anchors/AnchorBase.sol"; -import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -/** @dev This contract(pool) allows deposit of an arbitrary amount to it, shielded transfer to another registered user inside the pool - * and withdrawal from the pool. Project utilizes UTXO model to handle users' funds. - */ -abstract contract VAnchorBase is AnchorBase { - int256 public constant MAX_EXT_AMOUNT = 2**248; - uint256 public constant MAX_FEE = 2**248; - - uint256 public lastBalance; - uint256 public minimalWithdrawalAmount; - uint256 public maximumDepositAmount; - - struct Account { - address owner; - // A byte array which contains the public key from (0,64) and - // the encryption key from (64, 128) - bytes keyData; - } - - event NewCommitment(bytes32 commitment, uint256 index, bytes encryptedOutput); - event NewNullifier(bytes32 nullifier); - event PublicKey(address indexed owner, bytes key); - - /** - @dev The constructor - @param _levels The number of levels in the merkle tree - @param _hasher hasher address for the merkle tree - @param _handler handler address for the merkle tree - @param _maxEdges The maximum number of edges for the linked anchor - */ - constructor( - uint32 _levels, - IHasher _hasher, - address _handler, - uint8 _maxEdges - ) - AnchorBase(_handler, _hasher, _levels, _maxEdges) - {} - - function initialize(uint256 _minimalWithdrawalAmount, uint256 _maximumDepositAmount) external initializer { - super._initialize(); - _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); - _configureMaximumDepositLimit(_maximumDepositAmount); - - } - - function register(Account memory _account) public { - require(_account.owner == msg.sender, "only owner can be registered"); - _register(_account); - } - - function configureMinimalWithdrawalLimit( - uint256 _minimalWithdrawalAmount, - uint32 _nonce - ) override public onlyHandler onlyIncrementingByOne(_nonce) { - _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); - } - - function configureMaximumDepositLimit( - uint256 _maximumDepositAmount, - uint32 _nonce - ) override public onlyHandler onlyIncrementingByOne(_nonce) { - _configureMaximumDepositLimit(_maximumDepositAmount); - } - - function calculatePublicAmount(int256 _extAmount, uint256 _fee) public pure returns (uint256) { - require(_fee < MAX_FEE, "Invalid fee"); - require(_extAmount > -MAX_EXT_AMOUNT && _extAmount < MAX_EXT_AMOUNT, "Invalid ext amount"); - int256 publicAmount = _extAmount - int256(_fee); - return (publicAmount >= 0) ? uint256(publicAmount) : FIELD_SIZE - uint256(-publicAmount); - } - - function _register(Account memory _account) internal { - emit PublicKey(_account.owner, _account.keyData); - } - - /** @dev this function is defined in a child contract */ - //removed payable from address might need to add it back if things don't work - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal virtual; - - /** similar to _processWithdraw. Is defined in a child contract */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal virtual; - - function _configureMinimalWithdrawalLimit(uint256 _minimalWithdrawalAmount) internal { - minimalWithdrawalAmount = _minimalWithdrawalAmount; - } - - function _configureMaximumDepositLimit(uint256 _maximumDepositAmount) internal { - maximumDepositAmount = _maximumDepositAmount; - } -} \ No newline at end of file diff --git a/packages/contracts/contracts/vanchors/VAnchorForest.sol b/packages/contracts/contracts/vanchors/VAnchorForest.sol deleted file mode 100644 index 3b68b401c..000000000 --- a/packages/contracts/contracts/vanchors/VAnchorForest.sol +++ /dev/null @@ -1,406 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; - -import "./VAnchorForestBase.sol"; -import "../structs/SingleAssetExtData.sol"; -import "../interfaces/tokens/ITokenWrapper.sol"; -import "../interfaces/tokens/IMintableERC20.sol"; -import "../interfaces/verifiers/ISetVerifier.sol"; -import "../libs/VAnchorEncodeInputs.sol"; -import "../verifiers/TxProofVerifier.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; - -/** - @title Variable Anchor contract - @author Webb Technologies - @notice The Variable Anchor is a variable-denominated shielded pool system - derived from Tornado Nova (tornado-pool). This system extends the shielded - pool system into a bridged system and allows for join/split transactions. - - The system is built on top the VAnchorBase/AnchorBase/LinkableAnchor system which allows - it to be linked to other VAnchor contracts through a simple graph-like - interface where anchors maintain edges of their neighboring anchors. - - The system requires users to create and deposit UTXOs for the supported ERC20 - asset into the smart contract and insert a commitment into the underlying - merkle tree of the form: commitment = Poseidon(chainID, amount, pubKey, blinding). - The hash input is the UTXO data. All deposits/withdrawals are unified under - a common `transact` function which requires a zkSNARK proof that the UTXO commitments - are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). - - Information regarding the commitments: - - Poseidon is a zkSNARK friendly hash function - - destinationChainID is the chainId of the destination chain, where the withdrawal - is intended to be made - - Details of the UTXO and hashes are below - - UTXO = { destinationChainID, amount, pubkey, blinding } - commitment = Poseidon(destinationChainID, amount, pubKey, blinding) - nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) - - Commitments adhering to different hash functions and formats will invalidate - any attempt at withdrawal. - - Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that - the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's - destination chain id matches the underlying chain id of the VAnchor where the - transaction is taking place. The chain id opcode is leveraged to prevent any - tampering of this data. - */ -contract VAnchorForest is VAnchorForestBase, TxProofVerifier, ISetVerifier { - using SafeERC20 for IERC20; - using SafeMath for uint256; - address public immutable token; - uint public immutable forestLevels; - uint public immutable subtreeLevels; - - /** - @notice The VAnchor constructor - @param _verifier The address of SNARK verifier for this contract - @param _forestLevels The height/# of levels of underlying Merkle Forest - @param _subtreeLevels The height/# of levels of underlying Merkle Tree - @param _hasher The address of hash contract - @param _handler The address of AnchorHandler for this contract - @param _token The address of the token that is used to pay the deposit - @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. - @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the - `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to - limit the size of the LinkableAnchor with this parameter. - */ - constructor( - IAnchorVerifier _verifier, - uint32 _forestLevels, - uint32 _subtreeLevels, - IHasher _hasher, - address _handler, - address _token, - uint8 _maxEdges - ) - VAnchorForestBase (_forestLevels, _subtreeLevels, _hasher, _handler, _maxEdges) - TxProofVerifier(_verifier) - { - token = _token; - forestLevels = _forestLevels; - subtreeLevels = _subtreeLevels; - } - - /** - @notice Wraps a token for the `msg.sender` using the underlying TokenWrapper contract - @param _tokenAddress The address of the token to wrap - @param _amount The amount of tokens to wrap - */ - function wrapToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).wrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Unwraps the TokenWrapper token for the `msg.sender` into one of its wrappable tokens. - @param _tokenAddress The address of the token to unwrap into - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoToken(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wrap the native token for the `msg.sender` into the TokenWrapper token - @notice The amount is taken from `msg.value` - */ - function wrapNative() payable public { - ITokenWrapper(token).wrapFor{value: msg.value}(msg.sender, address(0), 0); - } - - /** - @notice Unwrap the TokenWrapper token for the `msg.sender` into the native token - @param _amount The amount of tokens to unwrap - */ - function unwrapIntoNative(address _tokenAddress, uint256 _amount) public { - ITokenWrapper(token).unwrapFor(msg.sender, _tokenAddress, _amount); - } - - /** - @notice Wraps a token for the `msg.sender` - @param _tokenAddress The address of the token to wrap - @param _extAmount The external amount for the transaction - */ - function _executeWrapping( - address _tokenAddress, - uint256 _extAmount - ) payable public { - // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper - uint256 wrapAmount = ITokenWrapper(token).getAmountToWrap(_extAmount); - - // If the address is zero, this is meant to wrap native tokens - if (_tokenAddress == address(0)) { - require(msg.value == wrapAmount); - // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - 0, - address(this) - ); - } else { - // wrap into the token and send directly to this contract - ITokenWrapper(token).wrapForAndSendTo{value: msg.value}( - msg.sender, - _tokenAddress, - wrapAmount, - address(this) - ); - } - } - - /** - @notice Unwraps into a valid token for the `msg.sender` - @param _tokenAddress The token to unwrap into - @param _recipient The address of the recipient for the unwrapped assets - @param _minusExtAmount Negative external amount for the transaction - */ - function withdrawAndUnwrap( - address _tokenAddress, - address _recipient, - uint256 _minusExtAmount - ) public payable nonReentrant { - // We first withdraw the assets and send them to `this` contract address. - // This ensure that when we unwrap the assets, `this` contract has the - // assets to unwrap into. - _processWithdraw(token, payable(address(this)), _minusExtAmount); - - ITokenWrapper(token).unwrapAndSendTo( - _tokenAddress, - _minusExtAmount, - _recipient - ); - } - - // /** - // @notice Registers and transacts in a single flow - // @param _account The account to register - // @param _proofArgs The zkSNARK proof parameters - // @param _extData The external data for the transaction - // */ - // function registerAndTransact( - // Account memory _account - // // VAnchorEncodeInputs.Proof memory _proofArgs, - // // ExtData memory _extData - // ) public { - // register(_account); - // // transact(_proofArgs, _extData); - // } - - /** - @notice Registers and transacts in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function registerAndTransact( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData - ) public { - register(_account); - transact(_proofArgs, _extData); - } - - /** - @notice Registers and transacts and wraps in a single flow - @param _account The account to register - @param _proofArgs The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from - */ - function registerAndTransactWrap( - Account memory _account, - VAnchorEncodeInputs.Proof memory _proofArgs, - ExtData memory _extData, - address _tokenAddress - ) public { - register(_account); - transactWrap(_proofArgs, _extData, _tokenAddress); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function transact(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) public nonReentrant { - _executeValidationAndVerification(_args, _extData); - - if (_extData.extAmount > 0) { - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - IMintableERC20(token).transferFrom(msg.sender, address(this), uint256(_extData.extAmount)); - } - - if (_extData.extAmount < 0) { - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); // prevents ddos attack to Bridge - _processWithdraw(token, _extData.recipient, uint256(-_extData.extAmount)); - } - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Executes a deposit/withdrawal or combination join/split transaction including wrapping or unwrapping - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - @param _tokenAddress The token to wrap from or unwrap into depending on the positivity of `_extData.extAmount` - */ - function transactWrap( - VAnchorEncodeInputs.Proof memory _args, - ExtData memory _extData, - address _tokenAddress - ) public payable { - _executeValidationAndVerification(_args, _extData); - - // Check if extAmount > 0, call wrapAndDeposit - if (_extData.extAmount > 0) { - //wrapAndDeposit - require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount"); - _executeWrapping(_tokenAddress, uint256(_extData.extAmount)); - } else if (_extData.extAmount < 0) { - // Otherwise, check if extAmount < 0, call withdrawAndUnwrap - require(_extData.recipient != address(0), "Can't withdraw to zero address"); - require(uint256(-_extData.extAmount) >= minimalWithdrawalAmount, "amount is less than minimalWithdrawalAmount"); - withdrawAndUnwrap(_tokenAddress, _extData.recipient, uint256(-_extData.extAmount)); - } - - if (_extData.fee > 0) { - _processFee(token, _extData.relayer, _extData.fee); - } - - _executeInsertions(_args, _extData); - } - - /** - @notice Checks whether the transaction is valid - 1. Checks that the nullifiers are not spent - 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) - 3. Checks that the zkSNARK proof verifies - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeValidationAndVerification(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); - } - require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); - _executeVerification(_args); - - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - // sets the nullifier for the input UTXO to spent - nullifierHashes[_args.inputNullifiers[i]] = true; - } - } - - /** - @notice Checks whether the zkSNARK proof is valid - @param _args The zkSNARK proof parameters - */ - function _executeVerification(VAnchorEncodeInputs.Proof memory _args) internal view { - require(_args.inputNullifiers.length == 2 || _args.inputNullifiers.length == 16, "Invalid number of inputs"); - bool smallInputs = _args.inputNullifiers.length == 2; - (bytes memory encodedInput, bytes32[] memory roots) = smallInputs - ? VAnchorEncodeInputs._encodeInputs2(_args, maxEdges) - : VAnchorEncodeInputs._encodeInputs16(_args, maxEdges); - - - require(isValidRoots(roots), "Invalid vanchor roots"); - require(verify(_args.proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); - } - - /** - @notice Inserts the output commitments into the underlying merkle tree - @param _args The zkSNARK proof parameters - @param _extData The external data for the transaction - */ - function _executeInsertions(VAnchorEncodeInputs.Proof memory _args, ExtData memory _extData) internal { - uint beforeInsertSubtreeIdx = currSubtreeIndex; - insertTwo(_args.outputCommitments[0], _args.outputCommitments[1]); - uint afterInsertSubtreeIdx = currSubtreeIndex; - uint leafIndex = numSubtreeElements; - if (beforeInsertSubtreeIdx != afterInsertSubtreeIdx) { - afterInsertSubtreeIdx -= 1; - if (leafIndex <= 1) { - leafIndex = 2 ** subtreeDepth; - } - } - emit NewCommitment(_args.outputCommitments[0], afterInsertSubtreeIdx, leafIndex - 2, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], afterInsertSubtreeIdx, leafIndex - 1, _extData.encryptedOutput2); - for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { - emit NewNullifier(_args.inputNullifiers[i]); - } - } - - /** - @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient - @param _token The token to withdraw - @param _recipient The recipient of the tokens - @param _minusExtAmount The amount of tokens to withdraw. Since - withdrawal ext amount is negative we apply a minus sign once more. - */ - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (balance >= _minusExtAmount) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_recipient, _minusExtAmount); - } else { - // mint tokens when not enough balance exists - IMintableERC20(_token).mint(_recipient, _minusExtAmount); - } - } - - /** - @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. - @param _token The token to pay the fee in - @param _relayer The relayer of the transaction - @param _fee The fee to pay - */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal override { - uint balance = IERC20(_token).balanceOf(address(this)); - if (_fee > 0) { - if (balance >= _fee) { - // transfer tokens when balance exists - IERC20(_token).safeTransfer(_relayer, _fee); - } - else { - IMintableERC20(_token).mint(_relayer, _fee); - } - } - } - - /** - @notice Set a new verifier with a nonce - @dev Can only be called by the `AnchorHandler` contract - @param _verifier The new verifier address - @param _nonce The nonce for updating the new verifier - */ - function setVerifier( - address _verifier, - uint32 _nonce - ) override onlyHandler onlyIncrementingByOne(_nonce) external { - require(_verifier != address(0), "Handler cannot be 0"); - verifier = IAnchorVerifier(_verifier); - } -} diff --git a/packages/contracts/contracts/vanchors/VAnchorForestBase.sol b/packages/contracts/contracts/vanchors/VAnchorForestBase.sol deleted file mode 100644 index 5d8d34bbb..000000000 --- a/packages/contracts/contracts/vanchors/VAnchorForestBase.sol +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright 2021-2022 Webb Technologies - * SPDX-License-Identifier: GPL-3.0-or-later-only - */ - -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -import "../anchors/AnchorForest.sol"; -import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -/** @dev This contract(pool) allows deposit of an arbitrary amount to it, shielded transfer to another registered user inside the pool - * and withdrawal from the pool. Project utilizes UTXO model to handle users' funds. - */ -abstract contract VAnchorForestBase is AnchorForest { - int256 public constant MAX_EXT_AMOUNT = 2**248; - uint256 public constant MAX_FEE = 2**248; - - uint256 public lastBalance; - uint256 public minimalWithdrawalAmount; - uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 public maximumDepositAmount; - - struct Account { - address owner; - // A byte array which contains the public key from (0,64) and - // the encryption key from (64, 128) - bytes keyData; - } - - event NewCommitment(bytes32 commitment, uint256 subtreeIndex, uint256 leafIndex, bytes encryptedOutput); - event NewNullifier(bytes32 nullifier); - event PublicKey(address indexed owner, bytes key); - - /** - @dev The constructor - @param _levels The number of levels in the merkle tree - @param _hasher hasher address for the merkle tree - @param _handler handler address for the merkle tree - @param _maxEdges The maximum number of edges for the linked anchor - */ - constructor( - uint32 _ForestLevels, - uint32 _levels, - IHasher _hasher, - address _handler, - uint8 _maxEdges - ) - AnchorForest(_handler, _hasher, _ForestLevels, _levels, _maxEdges) - {} - - // function initialize(uint256 _minimalWithdrawalAmount, uint256 _maximumDepositAmount) external initializer { - // super._initialize(); - // _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); - // _configureMaximumDepositLimit(_maximumDepositAmount); - // - // } - - function register(Account memory _account) public { - require(_account.owner == msg.sender, "only owner can be registered"); - _register(_account); - } - - function configureMinimalWithdrawalLimit( - uint256 _minimalWithdrawalAmount, - uint32 _nonce - ) override public onlyHandler onlyIncrementingByOne(_nonce) { - _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); - } - - function configureMaximumDepositLimit( - uint256 _maximumDepositAmount, - uint32 _nonce - ) override public onlyHandler onlyIncrementingByOne(_nonce) { - _configureMaximumDepositLimit(_maximumDepositAmount); - } - - function calculatePublicAmount(int256 _extAmount, uint256 _fee) public pure returns (uint256) { - require(_fee < MAX_FEE, "Invalid fee"); - require(_extAmount > -MAX_EXT_AMOUNT && _extAmount < MAX_EXT_AMOUNT, "Invalid ext amount"); - int256 publicAmount = _extAmount - int256(_fee); - return (publicAmount >= 0) ? uint256(publicAmount) : FIELD_SIZE - uint256(-publicAmount); - } - - function _register(Account memory _account) internal { - emit PublicKey(_account.owner, _account.keyData); - } - - /** @dev this function is defined in a child contract */ - //removed payable from address might need to add it back if things don't work - function _processWithdraw( - address _token, - address _recipient, - uint256 _minusExtAmount - ) internal virtual; - - /** similar to _processWithdraw. Is defined in a child contract */ - function _processFee( - address _token, - address _relayer, - uint256 _fee - ) internal virtual; - - function _configureMinimalWithdrawalLimit(uint256 _minimalWithdrawalAmount) internal { - minimalWithdrawalAmount = _minimalWithdrawalAmount; - } - - function _configureMaximumDepositLimit(uint256 _maximumDepositAmount) internal { - maximumDepositAmount = _maximumDepositAmount; - } -} diff --git a/packages/contracts/contracts/vanchors/base/MultiAssetVAnchor.sol b/packages/contracts/contracts/vanchors/base/MultiAssetVAnchor.sol new file mode 100644 index 000000000..ae84da849 --- /dev/null +++ b/packages/contracts/contracts/vanchors/base/MultiAssetVAnchor.sol @@ -0,0 +1,150 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "./ZKVAnchorBase.sol"; +import "../../structs/MultiAssetExtData.sol"; +import "../../libs/MASPVAnchorEncodeInputs.sol"; +import "../../interfaces/tokens/IRegistry.sol"; +import "../../trees/MerkleTree.sol"; + +/** + @title Multi Asset Variable Anchor contract + @author Webb Technologies + @notice The Multi Asset Variable Anchor is a variable-denominated shielded pool system + derived from Tornado Nova (tornado-pool) that supports multiple assets in a single pool. + This system extends the shielded pool system into a bridged system and allows for + join/split transactions of different assets at 2 same time. + + The system is built on top the MultiAssetVAnchorBase/AnchorBase/LinkableAnchor system + which allows it to be linked to other VAnchor contracts through a simple graph-like + interface where anchors maintain edges of their neighboring anchors. + + Part of the benefit of a MASP is the ability to handle multiple assets in a single pool. + To support this, the system uses a `assetId` field in the UTXO to identify the asset. + One thing to remember is that all assets in the pool must be wrapped ERC20 tokens specific + to the pool. We refer to this tokens as the bridge ERC20 tokens. Part of the challenge of building + the MASP then is dealing with the mapping between bridge ERC20s and their asset IDs. + + IMPORTANT: A bridge ERC20 token MUST have the same assetID across chain. + */ +abstract contract MultiAssetVAnchor is ZKVAnchorBase { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + address public registry; + + /** + @notice The VAnchor constructor + @param _verifier The address of SNARK verifier for this contract + @param _levels The height/# of levels of underlying Merkle Tree + @param _handler The address of AnchorHandler for this contract + @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. + @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the + `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to + limit the size of the LinkableAnchor with this parameter. + */ + constructor( + IRegistry _registry, + IAnchorVerifier _verifier, + uint32 _levels, + address _handler, + uint8 _maxEdges + ) ZKVAnchorBase(_verifier, _levels, _handler, _maxEdges) { + registry = address(_registry); + } + + /** + @notice Wraps and deposits in a single flow without a proof. Leads to a single non-zero UTXO. + @param _fromTokenAddress The address of the token to wrap from + @param _toTokenAddress The address of the token to wrap into + @param _amount The amount of tokens to wrap + @param partialCommitment The partial commitment of the UTXO + @param encryptedCommitment The encrypted commitment of the partial UTXO + */ + function wrapAndDepositERC20( + address _fromTokenAddress, + address _toTokenAddress, + uint256 _amount, + bytes32 partialCommitment, + bytes memory encryptedCommitment + ) public payable { + // Execute the wrapping + uint256 wrapAmount = _executeWrapping(_fromTokenAddress, _toTokenAddress, _amount); + // Create the record commitment + uint256 assetID = IRegistry(registry).getAssetId(_toTokenAddress); + uint256 commitment = IHasher(this.getHasher()).hash3( + [assetID, wrapAmount, uint256(partialCommitment)] + ); + _insertTwo(commitment, 0); + emit NewCommitment(commitment, 0, this.getNextIndex() - 2, encryptedCommitment); + } + + /// @inheritdoc ZKVAnchorBase + function transact( + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) public payable virtual override { + AuxPublicInputs memory aux = abi.decode(_auxPublicInputs, (AuxPublicInputs)); + address wrappedToken = IRegistry(registry).getAssetAddress(aux.assetID); + _transact( + wrappedToken, + _proof, + _auxPublicInputs, + _externalData, + _publicInputs, + _encryptions + ); + } + + /// @inheritdoc ZKVAnchorBase + function _executeVerification( + bytes memory _proof, + bytes memory _auxPublicInputs, + PublicInputs memory _publicInputs, + Encryptions memory + ) internal virtual override { + require( + _publicInputs.inputNullifiers.length == 2 || _publicInputs.inputNullifiers.length == 16, + "Invalid number of inputs" + ); + bool smallInputs = _publicInputs.inputNullifiers.length == 2; + (bytes memory encodedInput, uint256[] memory roots) = smallInputs + ? MASPVAnchorEncodeInputs._encodeInputs2(_publicInputs, _auxPublicInputs, maxEdges) + : MASPVAnchorEncodeInputs._encodeInputs16(_publicInputs, _auxPublicInputs, maxEdges); + + require(isValidRoots(roots), "Invalid vanchor roots"); + require(verify(_proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); + } + + /// @inheritdoc ZKVAnchorBase + function _genExtDataHash( + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + Encryptions memory _encryptions + ) internal virtual override returns (bytes32) { + AuxPublicInputs memory aux = abi.decode(_auxPublicInputs, (AuxPublicInputs)); + return + keccak256( + abi.encode( + ExtData( + aux.assetID, + _externalData.recipient, + _externalData.extAmount, + _externalData.relayer, + _externalData.fee, + _externalData.refund, + _externalData.token, + _encryptions.encryptedOutput1, + _encryptions.encryptedOutput2 + ) + ) + ); + } +} diff --git a/packages/contracts/contracts/vanchors/base/VAnchor.sol b/packages/contracts/contracts/vanchors/base/VAnchor.sol new file mode 100644 index 000000000..61abe2c69 --- /dev/null +++ b/packages/contracts/contracts/vanchors/base/VAnchor.sol @@ -0,0 +1,115 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "./ZKVAnchorBase.sol"; +import "../../structs/SingleAssetExtData.sol"; +import "../../libs/VAnchorEncodeInputs.sol"; + +/** + @title Variable Anchor contract + @author Webb Technologies + @notice The Variable Anchor is a variable-denominated shielded pool system + derived from Tornado Nova (tornado-pool). This system extends the shielded + pool system into a bridged system and allows for join/split transactions. + + The system is built on top the VAnchorBase/AnchorBase/LinkableAnchor system which allows + it to be linked to other VAnchor contracts through a simple graph-like + interface where anchors maintain edges of their neighboring anchors. + + The system requires users to create and deposit UTXOs for the supported ERC20 + asset into the smart contract and insert a commitment into the underlying + merkle tree of the form: commitment = Poseidon(chainID, amount, pubKey, blinding). + The hash input is the UTXO data. All deposits/withdrawals are unified under + a common `transact` function which requires a zkSNARK proof that the UTXO commitments + are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). + + Information regarding the commitments: + - Poseidon is a zkSNARK friendly hash function + - destinationChainID is the chainId of the destination chain, where the withdrawal + is intended to be made + - Details of the UTXO and hashes are below + + UTXO = { destinationChainID, amount, pubkey, blinding } + commitment = Poseidon(destinationChainID, amount, pubKey, blinding) + nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) + + Commitments adhering to different hash functions and formats will invalidate + any attempt at withdrawal. + + Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that + the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's + destination chain id matches the underlying chain id of the VAnchor where the + transaction is taking place. The chain id opcode is leveraged to prevent any + tampering of this data. + */ +abstract contract VAnchor is ZKVAnchorBase { + address public immutable token; + + constructor( + IAnchorVerifier _verifier, + uint32 _levels, + address _handler, + address _token, + uint8 _maxEdges + ) ZKVAnchorBase(_verifier, _levels, _handler, _maxEdges) { + token = _token; + } + + /// @inheritdoc ZKVAnchorBase + function transact( + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) public payable virtual override { + _transact(token, _proof, _auxPublicInputs, _externalData, _publicInputs, _encryptions); + } + + /// @inheritdoc ZKVAnchorBase + function _executeVerification( + bytes memory _proof, + bytes memory _auxPublicInputs, + PublicInputs memory _publicInputs, + Encryptions memory + ) internal virtual override { + require( + _publicInputs.inputNullifiers.length == 2 || _publicInputs.inputNullifiers.length == 16, + "Invalid number of inputs" + ); + bool smallInputs = _publicInputs.inputNullifiers.length == 2; + (bytes memory encodedInput, uint256[] memory roots) = smallInputs + ? VAnchorEncodeInputs._encodeInputs2(_publicInputs, _auxPublicInputs, maxEdges) + : VAnchorEncodeInputs._encodeInputs16(_publicInputs, _auxPublicInputs, maxEdges); + + require(isValidRoots(roots), "Invalid vanchor roots"); + require(verify(_proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); + } + + /// @inheritdoc ZKVAnchorBase + function _genExtDataHash( + bytes memory, + CommonExtData memory _externalData, + Encryptions memory _encryptions + ) internal virtual override returns (bytes32) { + return + keccak256( + abi.encode( + ExtData( + _externalData.recipient, + _externalData.extAmount, + _externalData.relayer, + _externalData.fee, + _externalData.refund, + _externalData.token, + _encryptions.encryptedOutput1, + _encryptions.encryptedOutput2 + ) + ) + ); + } +} diff --git a/packages/contracts/contracts/vanchors/base/VAnchorBase.sol b/packages/contracts/contracts/vanchors/base/VAnchorBase.sol new file mode 100644 index 000000000..25a76833b --- /dev/null +++ b/packages/contracts/contracts/vanchors/base/VAnchorBase.sol @@ -0,0 +1,290 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; +pragma experimental ABIEncoderV2; + +import "../../anchors/LinkableAnchor.sol"; +import "../../structs/PublicInputs.sol"; +import "../../interfaces/tokens/IMintableERC20.sol"; +import "../../interfaces/tokens/ITokenWrapper.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; + +/** @dev This contract(pool) allows deposit of an arbitrary amount to it, shielded transfer to another registered user inside the pool + * and withdrawal from the pool. Project utilizes UTXO model to handle users' funds. + */ +abstract contract VAnchorBase is LinkableAnchor { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + int256 public constant MAX_EXT_AMOUNT = 2 ** 248; + uint256 public constant MAX_FEE = 2 ** 248; + + uint256 public lastBalance; + uint256 public minimalWithdrawalAmount; + uint256 public maximumDepositAmount; + + struct Account { + address owner; + // A byte array which contains the public key from (0,64) and + // the encryption key from (64, 128) + bytes keyData; + } + + event NewCommitment( + uint256 commitment, + uint256 subTreeIndex, + uint256 leafIndex, + bytes encryptedOutput + ); + event NewNullifier(uint256 nullifier); + event PublicKey(address indexed owner, bytes key); + + /** + @dev The constructor + @param _levels The number of levels in the merkle tree + @param _handler handler address for the merkle tree + @param _maxEdges The maximum number of edges for the linked anchor + */ + constructor( + uint32 _levels, + address _handler, + uint8 _maxEdges + ) LinkableAnchor(_handler, _levels, _maxEdges) {} + + function initialize( + uint256 _minimalWithdrawalAmount, + uint256 _maximumDepositAmount + ) external onlyUninitialized { + super._initialize(); + _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); + _configureMaximumDepositLimit(_maximumDepositAmount); + } + + function register(Account memory _account) public { + require(_account.owner == msg.sender, "only owner can be registered"); + _register(_account); + } + + function configureMinimalWithdrawalLimit( + uint256 _minimalWithdrawalAmount, + uint32 _nonce + ) public override onlyHandler onlyIncrementingByOne(_nonce) { + _configureMinimalWithdrawalLimit(_minimalWithdrawalAmount); + } + + function configureMaximumDepositLimit( + uint256 _maximumDepositAmount, + uint32 _nonce + ) public override onlyHandler onlyIncrementingByOne(_nonce) { + _configureMaximumDepositLimit(_maximumDepositAmount); + } + + function calculatePublicAmount(int256 _extAmount, uint256 _fee) public pure returns (uint256) { + require(_fee < MAX_FEE, "Invalid fee"); + require(_extAmount > -MAX_EXT_AMOUNT && _extAmount < MAX_EXT_AMOUNT, "Invalid ext amount"); + int256 publicAmount = _extAmount - int256(_fee); + return (publicAmount >= 0) ? uint256(publicAmount) : FIELD_SIZE - uint256(-publicAmount); + } + + function _register(Account memory _account) internal { + emit PublicKey(_account.owner, _account.keyData); + } + + function _configureMinimalWithdrawalLimit(uint256 _minimalWithdrawalAmount) internal { + minimalWithdrawalAmount = _minimalWithdrawalAmount; + } + + function _configureMaximumDepositLimit(uint256 _maximumDepositAmount) internal { + maximumDepositAmount = _maximumDepositAmount; + } + + /** + @notice Inserts a commitment into the tree + @notice This is an internal function and meant to be used by a child contract. + @param _commitment The note commitment = Poseidon(chainId, nullifier, secret) + @return uint32 The index of the inserted commitment + */ + function insert(uint256 _commitment) internal returns (uint32) { + require(!commitments[_commitment], "The commitment has been submitted"); + + uint32 insertedIndex = _insert(_commitment); + commitments[_commitment] = true; + emit Insertion(_commitment, insertedIndex, block.timestamp); + + return insertedIndex; + } + + /** + @notice Inserts two commitments into the tree. Useful for contracts + that need to insert two commitments at once. + @notice This is an internal function and meant to be used by a child contract. + @param _firstCommitment The first note commitment + @param _secondCommitment The second note commitment + @return uint32 The index of the first inserted commitment + */ + function insertTwo( + uint256 _firstCommitment, + uint256 _secondCommitment + ) internal returns (uint32) { + require(!commitments[_firstCommitment], "The commitment has been submitted"); + require(!commitments[_secondCommitment], "The commitment has been submitted"); + + uint32 insertedIndex = _insertTwo([_firstCommitment, _secondCommitment]); + commitments[_firstCommitment] = true; + commitments[_secondCommitment] = true; + emit Insertion(_firstCommitment, insertedIndex, block.timestamp); + emit Insertion(_secondCommitment, insertedIndex + 1, block.timestamp); + + return insertedIndex; + } + + /** + @notice Wraps a token for the `msg.sender` + @param _fromTokenAddress The address of the token to wrap from + @param _toTokenAddress The address of the token to wrap into + @param _extAmount The external amount for the transaction + */ + function _executeWrapping( + address _fromTokenAddress, + address _toTokenAddress, + uint256 _extAmount + ) public payable returns (uint256) { + // Before executing the wrapping, determine the amount which needs to be sent to the tokenWrapper + uint256 wrapAmount = ITokenWrapper(_toTokenAddress).getAmountToWrap(_extAmount); + + // If the address is zero, this is meant to wrap native tokens + if (_fromTokenAddress == address(0)) { + require(msg.value == wrapAmount); + // If the wrapping is native, ensure the amount sent to the tokenWrapper is 0 + ITokenWrapper(_toTokenAddress).wrapForAndSendTo{ value: msg.value }( + msg.sender, + _fromTokenAddress, + 0, + address(this) + ); + } else { + // wrap into the token and send directly to this contract + ITokenWrapper(_toTokenAddress).wrapForAndSendTo{ value: msg.value }( + msg.sender, + _fromTokenAddress, + wrapAmount, + address(this) + ); + } + + return wrapAmount; + } + + /** + @notice Unwraps into a valid token for the `msg.sender` + @param _fromTokenAddress The address of the token to unwrap from + @param _toTokenAddress The address of the token to unwrap into + @param _recipient The address of the recipient for the unwrapped assets + @param _minusExtAmount Negative external amount for the transaction + */ + function _withdrawAndUnwrap( + address _fromTokenAddress, + address _toTokenAddress, + address _recipient, + uint256 _minusExtAmount + ) public payable { + // We first withdraw the assets and send them to `this` contract address. + // This ensure that when we unwrap the assets, `this` contract has the + // assets to unwrap into. + _processWithdraw(_fromTokenAddress, payable(address(this)), _minusExtAmount); + + ITokenWrapper(_fromTokenAddress).unwrapAndSendTo( + _toTokenAddress, + _minusExtAmount, + _recipient + ); + } + + /** + @notice Process the withdrawal by sending/minting the wrapped tokens to/for the recipient + @param _token The token to withdraw + @param _recipient The recipient of the tokens + @param _minusExtAmount The amount of tokens to withdraw. Since + withdrawal ext amount is negative we apply a minus sign once more. + */ + function _processWithdraw( + address _token, + address _recipient, + uint256 _minusExtAmount + ) internal virtual { + uint balance = IERC20(_token).balanceOf(address(this)); + if (balance >= _minusExtAmount) { + // transfer tokens when balance exists + IERC20(_token).safeTransfer(_recipient, _minusExtAmount); + } else { + // mint tokens when not enough balance exists + IMintableERC20(_token).mint(_recipient, _minusExtAmount); + } + } + + /** + @notice Process and pay the relayer their fee. Mint the fee if contract has no balance. + @param _token The token to pay the fee in + @param _relayer The relayer of the transaction + @param _fee The fee to pay + */ + function _processFee(address _token, address _relayer, uint256 _fee) internal virtual { + uint balance = IERC20(_token).balanceOf(address(this)); + if (_fee > 0) { + if (balance >= _fee) { + // transfer tokens when balance exists + IERC20(_token).safeTransfer(_relayer, _fee); + } else { + IMintableERC20(_token).mint(_relayer, _fee); + } + } + } + + /** + @notice Whether a note is already spent + @param _nullifierHash The nullifier hash of the deposit note + @return bool Whether the note is already spent + */ + function isSpent(uint256 _nullifierHash) public view returns (bool) { + return nullifierHashes[_nullifierHash]; + } + + /** + @notice Whether an array of notes is already spent + @param _nullifierHashes The array of nullifier hashes of the deposit notes + @return bool[] An array indicated whether each note's nullifier hash is already spent + */ + function isSpentArray( + uint256[] calldata _nullifierHashes + ) external view returns (bool[] memory) { + bool[] memory spent = new bool[](_nullifierHashes.length); + for (uint256 i = 0; i < _nullifierHashes.length; i++) { + if (isSpent(_nullifierHashes[i])) { + spent[i] = true; + } + } + + return spent; + } + + /** + @notice Set a new handler with a nonce + @dev Can only be called by the `AnchorHandler` contract + @param _handler The new handler address + @param _nonce The nonce for updating the new handler + */ + function setHandler( + address _handler, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require(_handler != address(0), "Handler cannot be 0"); + handler = _handler; + } +} diff --git a/packages/contracts/contracts/vanchors/base/ZKVAnchorBase.sol b/packages/contracts/contracts/vanchors/base/ZKVAnchorBase.sol new file mode 100644 index 000000000..6412f765b --- /dev/null +++ b/packages/contracts/contracts/vanchors/base/ZKVAnchorBase.sol @@ -0,0 +1,236 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "./VAnchorBase.sol"; +import "../../interfaces/verifiers/ISetVerifier.sol"; +import "../../verifiers/TxProofVerifier.sol"; + +/** + @title ZK VAnchor Base + @author Webb Technologies + @notice The base VAnchor contract for all VAnchors leveraging zero knowledge proofs. + This contract implements the most basic VAnchor for a single token. All other + contracts should inherit from this contract and override methods as needed. + */ +abstract contract ZKVAnchorBase is VAnchorBase, TxProofVerifier, ISetVerifier { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + /** + @notice The VAnchor constructor + @param _verifier The address of SNARK verifier for this contract + @param _levels The height/# of levels of underlying Merkle Tree + @param _handler The address of AnchorHandler for this contract + @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. + @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the + `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to + limit the size of the LinkableAnchor with this parameter. + */ + constructor( + IAnchorVerifier _verifier, + uint32 _levels, + address _handler, + uint8 _maxEdges + ) VAnchorBase(_levels, _handler, _maxEdges) TxProofVerifier(_verifier) {} + + /** + @notice Registers and transacts in a single flow + @param _proof The zkSNARK proof + @param _externalData The serialized external data + @param _auxPublicInputs The extension public inputs for the zkSNARK proof + @param _publicInputs The public inputs for the zkSNARK proof + @param _encryptions The encrypted outputs + */ + function registerAndTransact( + Account memory _account, + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) public payable virtual { + register(_account); + transact(_proof, _auxPublicInputs, _externalData, _publicInputs, _encryptions); + } + + /** + @notice Transacts in a single flow + @param _proof The zkSNARK proof + @param _externalData The serialized external data + @param _auxPublicInputs The extension public inputs for the zkSNARK proof + @param _publicInputs The public inputs for the zkSNARK proof + @param _encryptions The encrypted outputs + */ + function transact( + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) public payable virtual; + + /** + @notice Executes a deposit/withdrawal or combination join/split transaction + including possible wrapping or unwrapping if a valid token is provided. + @param _wrappedToken The wrapped token address (only tokens living on the bridge) + @param _proof The zkSNARK proof + @param _externalData The serialized external data + @param _auxPublicInputs The extension public inputs for the zkSNARK proof + @param _publicInputs The public inputs for the zkSNARK proof + @param _encryptions The encrypted outputs + */ + function _transact( + address _wrappedToken, + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal virtual { + _executeValidationAndVerification( + _proof, + _auxPublicInputs, + _externalData, + _publicInputs, + _encryptions + ); + + // Check if extAmount > 0, call wrapAndDeposit + if (_externalData.extAmount > 0) { + require( + uint256(_externalData.extAmount) <= maximumDepositAmount, + "amount is larger than maximumDepositAmount" + ); + if (_externalData.token == _wrappedToken) { + IMintableERC20(_wrappedToken).transferFrom( + msg.sender, + address(this), + uint256(_externalData.extAmount) + ); + } else { + _executeWrapping( + _externalData.token, + _wrappedToken, + uint256(_externalData.extAmount) + ); + } + } + + if (_externalData.extAmount < 0) { + require(_externalData.recipient != address(0), "Can't withdraw to zero address"); + // Prevents ddos attack to Bridge + require( + uint256(-_externalData.extAmount) >= minimalWithdrawalAmount, + "amount is less than minimalWithdrawalAmount" + ); + if (_externalData.token == _wrappedToken) { + _processWithdraw( + _wrappedToken, + _externalData.recipient, + uint256(-_externalData.extAmount) + ); + } else { + _withdrawAndUnwrap( + _wrappedToken, + _externalData.token, + _externalData.recipient, + uint256(-_externalData.extAmount) + ); + } + } + + if (_externalData.fee > 0) { + _processFee(_wrappedToken, _externalData.relayer, _externalData.fee); + } + + _executeInsertions(_publicInputs, _encryptions); + } + + /** + @notice Inserts the output commitments into the underlying merkle system + @param _publicInputs The public inputs for the proof + @param _encryptions The encryptions of the output commitments + */ + function _executeInsertions( + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal virtual; + + /** + @notice Checks whether the transaction is valid + 1. Checks that the nullifiers are not spent + 2. Checks that the public amount is valid (doesn't exceed the MAX_FEE or MAX_EXT_AMOUNT and doesn't overflow) + 3. Checks that the zkSNARK proof verifies + @param _proof The zkSNARK proof + @param _externalData The serialized external data + @param _auxPublicInputs The extension public inputs for the zkSNARK proof + @param _publicInputs The public inputs for the zkSNARK proof + @param _encryptions The encrypted outputs + */ + function _executeValidationAndVerification( + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal virtual { + bytes32 extDataHash = _genExtDataHash(_auxPublicInputs, _externalData, _encryptions); + + for (uint256 i = 0; i < _publicInputs.inputNullifiers.length; i++) { + require(!isSpent(_publicInputs.inputNullifiers[i]), "Input is already spent"); + } + require( + uint256(_publicInputs.extDataHash) == uint256(extDataHash) % FIELD_SIZE, + "Incorrect external data hash" + ); + require( + _publicInputs.publicAmount == + calculatePublicAmount(_externalData.extAmount, _externalData.fee), + "Invalid public amount" + ); + _executeVerification(_proof, _auxPublicInputs, _publicInputs, _encryptions); + + for (uint256 i = 0; i < _publicInputs.inputNullifiers.length; i++) { + // sets the nullifier for the input UTXO to spent + nullifierHashes[_publicInputs.inputNullifiers[i]] = true; + } + } + + /** + @notice Verifies the zero-knowledge proof and validity of roots/public inputs. + @param _proof The zkSNARK proof + @param _auxPublicInputs The extension public inputs for the zkSNARK proof + @param _publicInputs The public inputs for the zkSNARK proof + @param _encryptions The encrypted outputs + */ + function _executeVerification( + bytes memory _proof, + bytes memory _auxPublicInputs, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal virtual; + + function _genExtDataHash( + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + Encryptions memory _encryptions + ) internal virtual returns (bytes32); + + /** + @notice Set a new verifier with a nonce + @dev Can only be called by the `AnchorHandler` contract + @param _verifier The new verifier address + @param _nonce The nonce for updating the new verifier + */ + function setVerifier( + address _verifier, + uint32 _nonce + ) external override onlyHandler onlyIncrementingByOne(_nonce) { + require(_verifier != address(0), "Handler cannot be 0"); + verifier = IAnchorVerifier(_verifier); + } +} diff --git a/packages/contracts/contracts/vanchors/extensions/ChainalysisVAnchor.sol b/packages/contracts/contracts/vanchors/extensions/ChainalysisVAnchor.sol new file mode 100644 index 000000000..e85792205 --- /dev/null +++ b/packages/contracts/contracts/vanchors/extensions/ChainalysisVAnchor.sol @@ -0,0 +1,65 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../instances/VAnchorTree.sol"; +import "../../utils/SanctionFilter.sol"; + +/** + @title Chainalysis Variable Anchor contract + @author Webb Technologies + @notice The main addition here is a filter for sanctioned addresses on transactions. + */ +contract ChainalysisVAnchor is VAnchorTree, SanctionFilter { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + constructor( + IAnchorVerifier _verifier, + uint32 _merkleTreeLevels, + IHasher _hasher, + address _handler, + address _token, + uint8 _maxEdges + ) VAnchorTree(_verifier, _merkleTreeLevels, _hasher, _handler, _token, _maxEdges) {} + + /// @inheritdoc ZKVAnchorBase + function registerAndTransact( + Account memory _account, + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) public payable override isNotSanctioned(msg.sender) isNotSanctioned(_externalData.recipient) { + super.registerAndTransact( + _account, + _proof, + _auxPublicInputs, + _externalData, + _publicInputs, + _encryptions + ); + } + + /// @inheritdoc ZKVAnchorBase + function transact( + bytes memory _proof, + bytes memory _auxPublicInputs, + CommonExtData memory _externalData, + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) + public + payable + override + nonReentrant + isNotSanctioned(msg.sender) + isNotSanctioned(_externalData.recipient) + { + super.transact(_proof, _auxPublicInputs, _externalData, _publicInputs, _encryptions); + } +} diff --git a/packages/contracts/contracts/vanchors/extensions/IdentityVAnchor.sol b/packages/contracts/contracts/vanchors/extensions/IdentityVAnchor.sol new file mode 100644 index 000000000..da71aece0 --- /dev/null +++ b/packages/contracts/contracts/vanchors/extensions/IdentityVAnchor.sol @@ -0,0 +1,113 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../instances/VAnchorTree.sol"; +import "../../libs/IdentityVAnchorEncodeInputs.sol"; +import "../../interfaces/anchors/ISemaphoreGroups.sol"; + +/** + @title Identity VAnchor contract + @author Webb Technologies + + @notice The Identity Variable Anchor is a variable-denominated shielded pool system + derived from Tornado Nova (tornado-pool) with identity constrains on top. This system + extends the shielded pool system into a bridged system and allows for join/split transactions. + The identity extensions extends the shielded to pool to only allow for transactions from + users who maintain membership within a cross-chain Semaphore identity set. + + The system is built on top the VAnchorBase/AnchorBase/LinkableAnchor system which allows + it to be linked to other VAnchor contracts through a simple graph-like + interface where anchors maintain edges of their neighboring anchors. + + The system requires users to create and deposit UTXOs for the supported ERC20 + asset into the smart contract and insert a commitment into the underlying + merkle tree of the form: commitment = Poseidon(chainID, amount, pubKey, blinding). + The hash input is the UTXO data. All deposits/withdrawals are unified under + a common `transact` function which requires a zkSNARK proof that the UTXO commitments + are well-formed (i.e. that the deposit amount matches the sum of new UTXOs' amounts). + + Information regarding the commitments: + - Poseidon is a zkSNARK friendly hash function + - destinationChainID is the chainId of the destination chain, where the withdrawal + is intended to be made + - Details of the UTXO and hashes are below + + UTXO = { destinationChainID, amount, pubkey, blinding } + commitment = Poseidon(destinationChainID, amount, pubKey, blinding) + nullifier = Poseidon(commitment, merklePath, sign(privKey, commitment, merklePath)) + + Commitments adhering to different hash functions and formats will invalidate + any attempt at withdrawal. + + Using the preimage / UTXO of the commitment, users can generate a zkSNARK proof that + the UTXO is located in one-of-many VAnchor merkle trees and that the commitment's + destination chain id matches the underlying chain id of the VAnchor where the + transaction is taking place. The chain id opcode is leveraged to prevent any + tampering of this data. + */ +contract IdentityVAnchor is VAnchorTree { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + ISemaphoreGroups SemaphoreContract; + uint256 public immutable groupId; // Assumes group is already setup on the semaphore contract + + /** + @notice The Identity VAnchor constructor + @param _semaphore The address of Semaphore contract + @param _verifier The address of SNARK verifier for this contract + @param _hasher The address of the hasher for this contract + @param _levels The height/# of levels of underlying Merkle Tree + @param _handler The address of AnchorHandler for this contract + @param _token The address of the token that is used to pay the deposit + @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. + @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the + `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to + limit the size of the LinkableAnchor with this parameter. + */ + constructor( + ISemaphoreGroups _semaphore, + IAnchorVerifier _verifier, + IHasher _hasher, + uint8 _levels, + address _handler, + address _token, + uint8 _maxEdges, + uint256 _groupId + ) VAnchorTree(_verifier, _levels, _hasher, _handler, _token, _maxEdges) { + SemaphoreContract = _semaphore; + groupId = _groupId; + } + + /// @inheritdoc ZKVAnchorBase + function _executeVerification( + bytes memory _proof, + bytes memory _auxPublicInputs, + PublicInputs memory _publicInputs, + Encryptions memory + ) internal view override { + require( + _publicInputs.inputNullifiers.length == 2 || _publicInputs.inputNullifiers.length == 16, + "Invalid number of inputs" + ); + bool smallInputs = _publicInputs.inputNullifiers.length == 2; + (bytes memory encodedInput, uint256[] memory roots) = smallInputs + ? IdentityVAnchorEncodeInputs._encodeInputs2(_publicInputs, _auxPublicInputs, maxEdges) + : IdentityVAnchorEncodeInputs._encodeInputs16( + _publicInputs, + _auxPublicInputs, + maxEdges + ); + + require( + SemaphoreContract.verifyRoots(groupId, _publicInputs.extensionRoots), + "Invalid identity roots" + ); + require(isValidRoots(roots), "Invalid vanchor roots"); + require(verify(_proof, encodedInput, smallInputs, maxEdges), "Invalid transaction proof"); + } +} diff --git a/packages/contracts/contracts/vanchors/extensions/OpenVAnchor.sol b/packages/contracts/contracts/vanchors/extensions/OpenVAnchor.sol new file mode 100644 index 000000000..98db58116 --- /dev/null +++ b/packages/contracts/contracts/vanchors/extensions/OpenVAnchor.sol @@ -0,0 +1,182 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../base/VAnchorBase.sol"; +import "../../trees/MerkleTree.sol"; +import "../../structs/SingleAssetExtData.sol"; + +/** + @title Open Variable Anchor contract + @author Webb Technologies + @notice The Open Variable Anchor is a variable-denominated public pool system + derived from Webb's VAnchorBase. This system extends the anchor protocol + in a public way by enabling public cross-chain asset transfers. + + The system requires users to supply all inputs in the clear. Commitments are constructed + inside of the smart contract and inserted into a merkle tree for easy cross-chain state updates. + */ +contract OpenVAnchor is VAnchorBase, MerkleTree { + using SafeERC20 for IERC20; + using SafeMath for uint256; + address public immutable token; + + constructor( + IHasher _hasher, + uint32 _levels, + address _handler, + address _token + ) VAnchorBase(_levels, _handler, 255) MerkleTree(_levels, _hasher) { + token = _token; + } + + function deposit( + uint48 destinationChainId, + uint256 depositAmount, + address recipient, + bytes calldata delegatedCalldata, + uint256 blinding, + uint256 relayingFee + ) public nonReentrant { + require( + depositAmount <= maximumDepositAmount, + "amount is larger than maximumDepositAmount" + ); + bytes32 commitment = keccak256( + abi.encodePacked( + destinationChainId, + depositAmount, + recipient, + keccak256(delegatedCalldata), + blinding, + relayingFee + ) + ); + // Send the wrapped asset directly to this contract. + IERC20(token).transferFrom(msg.sender, address(this), depositAmount); + // Insert the commitment + _executeInsertion(uint256(commitment)); + } + + function wrapAndDeposit( + uint48 destinationChainId, + uint256 depositAmount, + address recipient, + bytes calldata delegatedCalldata, + uint256 blinding, + uint256 relayingFee, + address tokenAddress + ) public payable nonReentrant { + require( + depositAmount <= maximumDepositAmount, + "amount is larger than maximumDepositAmount" + ); + bytes32 commitment = keccak256( + abi.encodePacked( + destinationChainId, + depositAmount, + recipient, + keccak256(delegatedCalldata), + blinding, + relayingFee + ) + ); + // Send the `tokenAddress` asset to the `TokenWrapper` and mint this contract the wrapped asset. + _executeWrapping(tokenAddress, token, depositAmount); + // Insert the commitment + _executeInsertion(uint256(commitment)); + } + + function withdraw( + uint256 withdrawAmount, + address recipient, + bytes memory delegatedCalldata, + uint256 blinding, + uint256 relayingFee, + uint256[] memory merkleProof, + uint32 commitmentIndex, + uint256 root + ) public nonReentrant { + bytes32 commitment = keccak256( + abi.encodePacked( + getChainIdType(), + withdrawAmount, + recipient, + keccak256(delegatedCalldata), + blinding, + relayingFee + ) + ); + require( + _isValidMerkleProof(merkleProof, uint256(commitment), commitmentIndex, root), + "Invalid Merkle Proof" + ); + nullifierHashes[uint256(commitment)] = true; + // Send the wrapped token to the recipient. + _processWithdraw(token, recipient, withdrawAmount.sub(relayingFee)); + _processFee(token, msg.sender, relayingFee); + } + + function withdrawAndUnwrap( + uint256 withdrawAmount, + address recipient, + bytes memory delegatedCalldata, + uint256 blinding, + uint256 relayingFee, + uint256[] memory merkleProof, + uint32 commitmentIndex, + uint256 root, + address tokenAddress + ) public payable nonReentrant { + bytes32 commitment = keccak256( + abi.encodePacked( + getChainIdType(), + withdrawAmount, + recipient, + keccak256(delegatedCalldata), + blinding, + relayingFee + ) + ); + require( + _isValidMerkleProof(merkleProof, uint256(commitment), commitmentIndex, root), + "Invalid Merkle Proof" + ); + nullifierHashes[uint256(commitment)] = true; + _withdrawAndUnwrap(token, tokenAddress, recipient, withdrawAmount.sub(relayingFee)); + _processFee(token, msg.sender, relayingFee); + } + + function _executeInsertion(uint256 commitment) internal { + insert(commitment); + emit NewCommitment(commitment, 0, this.getNextIndex() - 1, ""); + } + + function _isValidMerkleProof( + uint256[] memory siblingPathNodes, + uint256 leaf, + uint32 leafIndex, + uint256 root + ) internal view returns (bool) { + uint256 currNodeHash = leaf; + uint32 nodeIndex = leafIndex; + + for (uint8 i = 0; i < siblingPathNodes.length; i++) { + if (nodeIndex % 2 == 0) { + currNodeHash = hashLeftRight(currNodeHash, siblingPathNodes[i]); + } else { + currNodeHash = hashLeftRight(siblingPathNodes[i], currNodeHash); + } + nodeIndex = nodeIndex / 2; + } + bool isKnownRootBool = false; + for (uint i = 0; i < edgeList.length; i++) { + isKnownRootBool = isKnownRootBool || isKnownNeighborRoot(edgeList[i].chainID, root); + } + isKnownRootBool = isKnownRootBool || this.isKnownRoot(root); + return root == currNodeHash && isKnownRootBool; + } +} diff --git a/packages/contracts/contracts/vanchors/instances/VAnchorForest.sol b/packages/contracts/contracts/vanchors/instances/VAnchorForest.sol new file mode 100644 index 000000000..e0fddc973 --- /dev/null +++ b/packages/contracts/contracts/vanchors/instances/VAnchorForest.sol @@ -0,0 +1,78 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../base/VAnchor.sol"; +import "../../trees/MerkleForest.sol"; + +/** + @title Variable Anchor Forest contract + @author Webb Technologies + @notice The Variable Anchor Forest is the same as a VAnchor system but with + many merkle trees for commitment storage. + */ +contract VAnchorForest is VAnchor, MerkleForest { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + /** + @notice The VAnchor Forest constructor + @param _verifier The address of SNARK verifier for this contract + @param _forestLevels The height/# of levels of underlying Merkle Forest + @param _subtreeLevels The height/# of levels of underlying Merkle Trees in the forest + @param _hasher The address of hash contract + @param _handler The address of AnchorHandler for this contract + @param _token The address of the token that is used to pay the deposit + @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. + @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the + `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to + limit the size of the LinkableAnchor with this parameter. + */ + constructor( + IAnchorVerifier _verifier, + uint32 _forestLevels, + uint32 _subtreeLevels, + IHasher _hasher, + address _handler, + address _token, + uint8 _maxEdges + ) + VAnchor(_verifier, _forestLevels, _handler, _token, _maxEdges) + MerkleForest(_forestLevels, _subtreeLevels, _hasher) + {} + + /// @inheritdoc ZKVAnchorBase + function _executeInsertions( + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal override { + uint beforeInsertSubtreeIdx = currSubtreeIndex; + insertTwo(_publicInputs.outputCommitments[0], _publicInputs.outputCommitments[1]); + uint afterInsertSubtreeIdx = currSubtreeIndex; + uint leafIndex = numSubtreeElements; + if (beforeInsertSubtreeIdx != afterInsertSubtreeIdx) { + afterInsertSubtreeIdx -= 1; + if (leafIndex <= 1) { + leafIndex = 2 ** subtreeLevels; + } + } + emit NewCommitment( + _publicInputs.outputCommitments[0], + afterInsertSubtreeIdx, + leafIndex - 2, + _encryptions.encryptedOutput1 + ); + emit NewCommitment( + _publicInputs.outputCommitments[1], + afterInsertSubtreeIdx, + leafIndex - 1, + _encryptions.encryptedOutput2 + ); + for (uint256 i = 0; i < _publicInputs.inputNullifiers.length; i++) { + emit NewNullifier(_publicInputs.inputNullifiers[i]); + } + } +} diff --git a/packages/contracts/contracts/vanchors/instances/VAnchorTree.sol b/packages/contracts/contracts/vanchors/instances/VAnchorTree.sol new file mode 100644 index 000000000..684d7b4e9 --- /dev/null +++ b/packages/contracts/contracts/vanchors/instances/VAnchorTree.sol @@ -0,0 +1,67 @@ +/** + * Copyright 2021-2022 Webb Technologies + * SPDX-License-Identifier: GPL-3.0-or-later-only + */ + +pragma solidity ^0.8.0; + +import "../base/VAnchor.sol"; +import "../../trees/MerkleTree.sol"; + +/** + @title Variable Anchor Forest contract + @author Webb Technologies + @notice The Variable Anchor Forest is the same as a VAnchor system but with + many merkle trees for commitment storage. + */ +contract VAnchorTree is VAnchor, MerkleTree { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + /** + @notice The VAnchorTree constructor + @param _verifier The address of SNARK verifier for this contract + @param _merkleTreeLevels The height/# of levels of underlying Merkle Tree + @param _hasher The address of hash contract + @param _handler The address of AnchorHandler for this contract + @param _token The address of the token that is used to pay the deposit + @param _maxEdges The maximum number of edges in the LinkableAnchor + Verifier supports. + @notice The `_maxEdges` is zero-knowledge circuit dependent, meaning the + `_verifier` ONLY supports a certain maximum # of edges. Therefore we need to + limit the size of the LinkableAnchor with this parameter. + */ + constructor( + IAnchorVerifier _verifier, + uint32 _merkleTreeLevels, + IHasher _hasher, + address _handler, + address _token, + uint8 _maxEdges + ) + VAnchor(_verifier, _merkleTreeLevels, _handler, _token, _maxEdges) + MerkleTree(_merkleTreeLevels, _hasher) + {} + + /// @inheritdoc ZKVAnchorBase + function _executeInsertions( + PublicInputs memory _publicInputs, + Encryptions memory _encryptions + ) internal override { + insertTwo(_publicInputs.outputCommitments[0], _publicInputs.outputCommitments[1]); + emit NewCommitment( + _publicInputs.outputCommitments[0], + 0, + this.getNextIndex() - 2, + _encryptions.encryptedOutput1 + ); + emit NewCommitment( + _publicInputs.outputCommitments[1], + 0, + this.getNextIndex() - 1, + _encryptions.encryptedOutput2 + ); + for (uint256 i = 0; i < _publicInputs.inputNullifiers.length; i++) { + emit NewNullifier(_publicInputs.inputNullifiers[i]); + } + } +} diff --git a/packages/contracts/contracts/verifiers/AnchorVerifier.sol b/packages/contracts/contracts/verifiers/AnchorVerifier.sol index a331c39cf..2ac0117ce 100644 --- a/packages/contracts/contracts/verifiers/AnchorVerifier.sol +++ b/packages/contracts/contracts/verifiers/AnchorVerifier.sol @@ -28,6 +28,7 @@ contract Verifier is IAnchorVerifier { v5 = _verifier5; v6 = _verifier6; } + function verifyProof( uint[2] memory a, uint[2][2] memory b, @@ -35,7 +36,7 @@ contract Verifier is IAnchorVerifier { bytes memory input, uint8 maxEdges, bool - ) override external view returns (bool r) { + ) external view override returns (bool r) { if (maxEdges == 1) { uint256[5] memory _inputs = abi.decode(input, (uint256[5])); return v2.verifyProof(a, b, c, _inputs); diff --git a/packages/contracts/contracts/verifiers/IdentityVAnchorVerifier.sol b/packages/contracts/contracts/verifiers/IdentityVAnchorVerifier.sol index 17f99a79c..a48644652 100644 --- a/packages/contracts/contracts/verifiers/IdentityVAnchorVerifier.sol +++ b/packages/contracts/contracts/verifiers/IdentityVAnchorVerifier.sol @@ -14,7 +14,6 @@ contract IdentityVAnchorVerifier is IAnchorVerifier { IIdentityVAnchorVerifier8_2 public v8_2; IIdentityVAnchorVerifier8_16 public v8_16; - constructor( IIdentityVAnchorVerifier2_2 _verifier_2_2, @@ -35,7 +34,7 @@ contract IdentityVAnchorVerifier is IAnchorVerifier { bytes memory input, uint8 maxEdges, bool smallInputs - ) override external view returns (bool r) { + ) external view override returns (bool r) { if (maxEdges == 1) { if (smallInputs) { uint256[11] memory _inputs = abi.decode(input, (uint256[11])); diff --git a/packages/contracts/contracts/verifiers/MASPVAnchorVerifier.sol b/packages/contracts/contracts/verifiers/MASPVAnchorVerifier.sol index c749d9a68..e0f54a7f9 100644 --- a/packages/contracts/contracts/verifiers/MASPVAnchorVerifier.sol +++ b/packages/contracts/contracts/verifiers/MASPVAnchorVerifier.sol @@ -14,7 +14,6 @@ contract MASPVAnchorVerifier is IAnchorVerifier { IMASPVAnchorVerifier8_2 public v8_2; IMASPVAnchorVerifier8_16 public v8_16; - constructor( IMASPVAnchorVerifier2_2 _verifier_2_2, @@ -35,7 +34,7 @@ contract MASPVAnchorVerifier is IAnchorVerifier { bytes memory input, uint8 maxEdges, bool smallInputs - ) override external view returns (bool r) { + ) external view override returns (bool r) { if (maxEdges == 1) { if (smallInputs) { uint256[10] memory _inputs = abi.decode(input, (uint256[10])); diff --git a/packages/contracts/contracts/verifiers/TxProofVerifier.sol b/packages/contracts/contracts/verifiers/TxProofVerifier.sol index fdf83a140..57b0ee837 100644 --- a/packages/contracts/contracts/verifiers/TxProofVerifier.sol +++ b/packages/contracts/contracts/verifiers/TxProofVerifier.sol @@ -8,13 +8,13 @@ import "../interfaces/verifiers/IAnchorVerifier.sol"; pragma solidity ^0.8.0; contract TxProofVerifier { - IAnchorVerifier public verifier; + IAnchorVerifier public verifier; - constructor(IAnchorVerifier _verifier) { - verifier = _verifier; - } + constructor(IAnchorVerifier _verifier) { + verifier = _verifier; + } - /** + /** @notice Verifies a zero-knowledge proof of knowledge over the tree according to the underlying `Verifier` circuit this `AnchorBase` is using. @notice This aims to be as generic as currently needed to support our VAnchor (variable deposit) contracts. @@ -22,48 +22,32 @@ contract TxProofVerifier { @param _input The public input packed bytes @return bool Whether the proof is valid */ - function verify( - bytes memory _proof, - bytes memory _input, - bool smallInputs, - uint8 maxEdges - ) internal view returns (bool) { - uint256[8] memory p = abi.decode(_proof, (uint256[8])); - ( - uint256[2] memory a, - uint256[2][2] memory b, - uint256[2] memory c - ) = unpackProof(p); - bool r = verifier.verifyProof( - a, b, c, - _input, - maxEdges, - smallInputs - ); - require(r, "Invalid withdraw proof"); - return r; - } + function verify( + bytes memory _proof, + bytes memory _input, + bool smallInputs, + uint8 maxEdges + ) internal view returns (bool) { + uint256[8] memory p = abi.decode(_proof, (uint256[8])); + (uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c) = unpackProof(p); + bool r = verifier.verifyProof(a, b, c, _input, maxEdges, smallInputs); + require(r, "Invalid withdraw proof"); + return r; + } - /** + /** @notice A helper function to convert an array of 8 uint256 values into the a, b, and c array values that the zk-SNARK verifier's verifyProof accepts. @param _proof The array of 8 uint256 values @return (uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c) The unpacked proof values */ - function unpackProof( - uint256[8] memory _proof - ) public pure returns ( - uint256[2] memory, - uint256[2][2] memory, - uint256[2] memory - ) { - return ( - [_proof[0], _proof[1]], - [ - [_proof[2], _proof[3]], - [_proof[4], _proof[5]] - ], - [_proof[6], _proof[7]] - ); - } + function unpackProof( + uint256[8] memory _proof + ) public pure returns (uint256[2] memory, uint256[2][2] memory, uint256[2] memory) { + return ( + [_proof[0], _proof[1]], + [[_proof[2], _proof[3]], [_proof[4], _proof[5]]], + [_proof[6], _proof[7]] + ); + } } diff --git a/packages/contracts/contracts/verifiers/VAnchorVerifier.sol b/packages/contracts/contracts/verifiers/VAnchorVerifier.sol index e9e3b7894..2c88cdcc0 100644 --- a/packages/contracts/contracts/verifiers/VAnchorVerifier.sol +++ b/packages/contracts/contracts/verifiers/VAnchorVerifier.sol @@ -14,7 +14,6 @@ contract VAnchorVerifier is IAnchorVerifier { IVAnchorVerifier8_2 public v8_2; IVAnchorVerifier8_16 public v8_16; - constructor( IVAnchorVerifier2_2 _verifier_2_2, @@ -35,7 +34,7 @@ contract VAnchorVerifier is IAnchorVerifier { bytes memory input, uint8 maxEdges, bool smallInputs - ) override external view returns (bool r) { + ) external view override returns (bool r) { if (maxEdges == 1) { if (smallInputs) { uint256[9] memory _inputs = abi.decode(input, (uint256[9])); diff --git a/packages/contracts/contracts/verifiers/anchor/Verifier2.sol b/packages/contracts/contracts/verifiers/anchor/Verifier2.sol index 9596ff620..0fb206ca9 100644 --- a/packages/contracts/contracts/verifiers/anchor/Verifier2.sol +++ b/packages/contracts/contracts/verifiers/anchor/Verifier2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,231 +53,288 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 15635276308160559792004133274137521635544708393707107117296778344248550957505, - 3717741945256314195289865075076907359794502490207866014317755229824121091817 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [7050980761034239836998401171330113822559450636994971400449179984680945710605, - 7245004549500637626631429097675336758284887245753968402756783758231816600578], - [1912372262250363594846622538306495689461171293922464070666397682496221820996, - 4448756910343248867349276404521881079098652604464026018719784207380017616504] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [16100445600596381683114132728744721979852054947074130093102933836954778235468, - 19961562334665128105262069067723333683468636005927921440429930523745609545807], - [5550430966172033009246913203472970990554607997744256034818447746404852025544, - 8320537606097428397424926906674844970286586234324488474338418250974689236115] - ); - vk.IC = new Pairing.G1Point[](6); - - vk.IC[0] = Pairing.G1Point( - 14717147193944563440410872994669596026696010170148727921990806692633156088626, - 7471479213060219807694028286460385766077320741764860972321118383576515945444 - ); - - vk.IC[1] = Pairing.G1Point( - 13184731128465797069402278738328182037054348932829455741974328646706126245501, - 7708188207959959336460514523530632499335027102281541843857906085467251078319 - ); - - vk.IC[2] = Pairing.G1Point( - 20052120214749040417552462130073538405684441838763574289252662694810600705289, - 4465733732512860161571120551124205294233813772987845174565260688742827465734 - ); - - vk.IC[3] = Pairing.G1Point( - 11224259360430904483388060196956785414237397505065953074062452295790924639666, - 17870016520185264626503196442232279025680385287053940331414217395341819284836 - ); - - vk.IC[4] = Pairing.G1Point( - 9961038058301866005166173117921737638369876149577556373065469731144832617856, - 71442754753126856098765327498194791529419664718505250623434450384974508077 - ); - - vk.IC[5] = Pairing.G1Point( - 10345907020676699535682628456411094754270466783274707467001094607615021327806, - 16988120233832890880354716815139505914471302167164132592244762040391282047452 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[5] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 15635276308160559792004133274137521635544708393707107117296778344248550957505, + 3717741945256314195289865075076907359794502490207866014317755229824121091817 + ); + + vk.beta2 = Pairing.G2Point( + [ + 7050980761034239836998401171330113822559450636994971400449179984680945710605, + 7245004549500637626631429097675336758284887245753968402756783758231816600578 + ], + [ + 1912372262250363594846622538306495689461171293922464070666397682496221820996, + 4448756910343248867349276404521881079098652604464026018719784207380017616504 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 16100445600596381683114132728744721979852054947074130093102933836954778235468, + 19961562334665128105262069067723333683468636005927921440429930523745609545807 + ], + [ + 5550430966172033009246913203472970990554607997744256034818447746404852025544, + 8320537606097428397424926906674844970286586234324488474338418250974689236115 + ] + ); + vk.IC = new Pairing.G1Point[](6); + + vk.IC[0] = Pairing.G1Point( + 14717147193944563440410872994669596026696010170148727921990806692633156088626, + 7471479213060219807694028286460385766077320741764860972321118383576515945444 + ); + + vk.IC[1] = Pairing.G1Point( + 13184731128465797069402278738328182037054348932829455741974328646706126245501, + 7708188207959959336460514523530632499335027102281541843857906085467251078319 + ); + + vk.IC[2] = Pairing.G1Point( + 20052120214749040417552462130073538405684441838763574289252662694810600705289, + 4465733732512860161571120551124205294233813772987845174565260688742827465734 + ); + + vk.IC[3] = Pairing.G1Point( + 11224259360430904483388060196956785414237397505065953074062452295790924639666, + 17870016520185264626503196442232279025680385287053940331414217395341819284836 + ); + + vk.IC[4] = Pairing.G1Point( + 9961038058301866005166173117921737638369876149577556373065469731144832617856, + 71442754753126856098765327498194791529419664718505250623434450384974508077 + ); + + vk.IC[5] = Pairing.G1Point( + 10345907020676699535682628456411094754270466783274707467001094607615021327806, + 16988120233832890880354716815139505914471302167164132592244762040391282047452 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[5] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/anchor/Verifier3.sol b/packages/contracts/contracts/verifiers/anchor/Verifier3.sol index 682915ccc..212d18b1f 100644 --- a/packages/contracts/contracts/verifiers/anchor/Verifier3.sol +++ b/packages/contracts/contracts/verifiers/anchor/Verifier3.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,236 +53,293 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier3 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 15635276308160559792004133274137521635544708393707107117296778344248550957505, - 3717741945256314195289865075076907359794502490207866014317755229824121091817 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [7050980761034239836998401171330113822559450636994971400449179984680945710605, - 7245004549500637626631429097675336758284887245753968402756783758231816600578], - [1912372262250363594846622538306495689461171293922464070666397682496221820996, - 4448756910343248867349276404521881079098652604464026018719784207380017616504] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [15733965034487182864900681844134229511416839823422777397532244780668511425358, - 20041254994873346094954540336310036403465511981171831080537095618944385267619], - [5334911943248275202691498376824127618724472748887653008019278472383384344518, - 3891472656584197739806360943883186206800332404534264982724250027804657201960] - ); - vk.IC = new Pairing.G1Point[](7); - - vk.IC[0] = Pairing.G1Point( - 16944712254428931477354017521432128191765309927097592352257184835408367139518, - 21817596928571353828027901055618131217963061835710889923270311510425228326865 - ); - - vk.IC[1] = Pairing.G1Point( - 3126510407857186270498940177381614876462494514073392445504078059807590219680, - 18828249724838370662952984170240608139731991953412931239546503930918345653262 - ); - - vk.IC[2] = Pairing.G1Point( - 15305230080563245917928644124139802801091768953552660350980570430414296885619, - 3293502721299658226091016748272134939915895674472581938946458315000046512111 - ); - - vk.IC[3] = Pairing.G1Point( - 18603028331773144849147703035567332388145475675634471824230816087510911692816, - 17967582370514354676463809337278091556129714042339348179732720603813703742036 - ); - - vk.IC[4] = Pairing.G1Point( - 8340871177994069770767241934966285885034372456130041927487885460400817362651, - 8891272716077694440242611161909172028035991103869501208206936891773539115616 - ); - - vk.IC[5] = Pairing.G1Point( - 19706594624048499455620240940221868848069652318811693543051078415126764827524, - 19423532298556297566653665713686864862354879717392215440891693214943224877001 - ); - - vk.IC[6] = Pairing.G1Point( - 1637529497699247553781485752520251888861420991445640274648082816842695731653, - 357180725776237119135868761350235624405347833120793643338509964584392316801 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[6] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 15635276308160559792004133274137521635544708393707107117296778344248550957505, + 3717741945256314195289865075076907359794502490207866014317755229824121091817 + ); + + vk.beta2 = Pairing.G2Point( + [ + 7050980761034239836998401171330113822559450636994971400449179984680945710605, + 7245004549500637626631429097675336758284887245753968402756783758231816600578 + ], + [ + 1912372262250363594846622538306495689461171293922464070666397682496221820996, + 4448756910343248867349276404521881079098652604464026018719784207380017616504 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 15733965034487182864900681844134229511416839823422777397532244780668511425358, + 20041254994873346094954540336310036403465511981171831080537095618944385267619 + ], + [ + 5334911943248275202691498376824127618724472748887653008019278472383384344518, + 3891472656584197739806360943883186206800332404534264982724250027804657201960 + ] + ); + vk.IC = new Pairing.G1Point[](7); + + vk.IC[0] = Pairing.G1Point( + 16944712254428931477354017521432128191765309927097592352257184835408367139518, + 21817596928571353828027901055618131217963061835710889923270311510425228326865 + ); + + vk.IC[1] = Pairing.G1Point( + 3126510407857186270498940177381614876462494514073392445504078059807590219680, + 18828249724838370662952984170240608139731991953412931239546503930918345653262 + ); + + vk.IC[2] = Pairing.G1Point( + 15305230080563245917928644124139802801091768953552660350980570430414296885619, + 3293502721299658226091016748272134939915895674472581938946458315000046512111 + ); + + vk.IC[3] = Pairing.G1Point( + 18603028331773144849147703035567332388145475675634471824230816087510911692816, + 17967582370514354676463809337278091556129714042339348179732720603813703742036 + ); + + vk.IC[4] = Pairing.G1Point( + 8340871177994069770767241934966285885034372456130041927487885460400817362651, + 8891272716077694440242611161909172028035991103869501208206936891773539115616 + ); + + vk.IC[5] = Pairing.G1Point( + 19706594624048499455620240940221868848069652318811693543051078415126764827524, + 19423532298556297566653665713686864862354879717392215440891693214943224877001 + ); + + vk.IC[6] = Pairing.G1Point( + 1637529497699247553781485752520251888861420991445640274648082816842695731653, + 357180725776237119135868761350235624405347833120793643338509964584392316801 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[6] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/anchor/Verifier4.sol b/packages/contracts/contracts/verifiers/anchor/Verifier4.sol index 83bc9667b..255fe41d9 100644 --- a/packages/contracts/contracts/verifiers/anchor/Verifier4.sol +++ b/packages/contracts/contracts/verifiers/anchor/Verifier4.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,241 +53,298 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier4 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 15635276308160559792004133274137521635544708393707107117296778344248550957505, - 3717741945256314195289865075076907359794502490207866014317755229824121091817 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [7050980761034239836998401171330113822559450636994971400449179984680945710605, - 7245004549500637626631429097675336758284887245753968402756783758231816600578], - [1912372262250363594846622538306495689461171293922464070666397682496221820996, - 4448756910343248867349276404521881079098652604464026018719784207380017616504] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [1347549105526305435938490163534824914387814596314189861540078200893385539848, - 14008228913583280307615133608679771236489197919260936727531063915799190386926], - [19606811476578140723618979542159743001248090210823662117389858299705667666570, - 1655172566317457152561797016733300132953013157259848013448112172360551873718] - ); - vk.IC = new Pairing.G1Point[](8); - - vk.IC[0] = Pairing.G1Point( - 8599556570529902275384325778498615066366172890302759728000294918238536032559, - 14667655886678180908782323224056589453116813625444334796160957690749758056530 - ); - - vk.IC[1] = Pairing.G1Point( - 6746690988157594325567069832664733047214808747223978725627284102277165976493, - 19015217633144518430606450581306439422151763107804795289575931369162900132363 - ); - - vk.IC[2] = Pairing.G1Point( - 13308504352058120332520812706107354554234442282511071150072849062784304732199, - 11316595239581610283850116056991683803098705348519901497380386906959245245113 - ); - - vk.IC[3] = Pairing.G1Point( - 21419321609093159273513607274170390308662081028479148567612386481747856703262, - 4422896612273319606550360603783201142484667524227712426624834963226222015486 - ); - - vk.IC[4] = Pairing.G1Point( - 6413432904210018552645945403193092179840332012972739172525152438524453053912, - 9918644206653988296752312729462613401720555901787714693438761813458601046768 - ); - - vk.IC[5] = Pairing.G1Point( - 13072237708348586304238053594505235178074183088351334482971724285346008393758, - 2807588600768322957409526074303265694277563355073860714569007590271784856366 - ); - - vk.IC[6] = Pairing.G1Point( - 17214467794201982723700121136038264905565872558127687258737733339893590123802, - 14015842382154516424861212369521254408393223881839405043995157661818814149780 - ); - - vk.IC[7] = Pairing.G1Point( - 10922871230717696780244225710499815182404604630000986495661237272170210732251, - 5053575481323049082550829168273538906614916948195828944631662881262003519603 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[7] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 15635276308160559792004133274137521635544708393707107117296778344248550957505, + 3717741945256314195289865075076907359794502490207866014317755229824121091817 + ); + + vk.beta2 = Pairing.G2Point( + [ + 7050980761034239836998401171330113822559450636994971400449179984680945710605, + 7245004549500637626631429097675336758284887245753968402756783758231816600578 + ], + [ + 1912372262250363594846622538306495689461171293922464070666397682496221820996, + 4448756910343248867349276404521881079098652604464026018719784207380017616504 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 1347549105526305435938490163534824914387814596314189861540078200893385539848, + 14008228913583280307615133608679771236489197919260936727531063915799190386926 + ], + [ + 19606811476578140723618979542159743001248090210823662117389858299705667666570, + 1655172566317457152561797016733300132953013157259848013448112172360551873718 + ] + ); + vk.IC = new Pairing.G1Point[](8); + + vk.IC[0] = Pairing.G1Point( + 8599556570529902275384325778498615066366172890302759728000294918238536032559, + 14667655886678180908782323224056589453116813625444334796160957690749758056530 + ); + + vk.IC[1] = Pairing.G1Point( + 6746690988157594325567069832664733047214808747223978725627284102277165976493, + 19015217633144518430606450581306439422151763107804795289575931369162900132363 + ); + + vk.IC[2] = Pairing.G1Point( + 13308504352058120332520812706107354554234442282511071150072849062784304732199, + 11316595239581610283850116056991683803098705348519901497380386906959245245113 + ); + + vk.IC[3] = Pairing.G1Point( + 21419321609093159273513607274170390308662081028479148567612386481747856703262, + 4422896612273319606550360603783201142484667524227712426624834963226222015486 + ); + + vk.IC[4] = Pairing.G1Point( + 6413432904210018552645945403193092179840332012972739172525152438524453053912, + 9918644206653988296752312729462613401720555901787714693438761813458601046768 + ); + + vk.IC[5] = Pairing.G1Point( + 13072237708348586304238053594505235178074183088351334482971724285346008393758, + 2807588600768322957409526074303265694277563355073860714569007590271784856366 + ); + + vk.IC[6] = Pairing.G1Point( + 17214467794201982723700121136038264905565872558127687258737733339893590123802, + 14015842382154516424861212369521254408393223881839405043995157661818814149780 + ); + + vk.IC[7] = Pairing.G1Point( + 10922871230717696780244225710499815182404604630000986495661237272170210732251, + 5053575481323049082550829168273538906614916948195828944631662881262003519603 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[7] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/anchor/Verifier5.sol b/packages/contracts/contracts/verifiers/anchor/Verifier5.sol index 61f9e9f69..376fdf8c3 100644 --- a/packages/contracts/contracts/verifiers/anchor/Verifier5.sol +++ b/packages/contracts/contracts/verifiers/anchor/Verifier5.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,246 +53,303 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier5 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 15635276308160559792004133274137521635544708393707107117296778344248550957505, - 3717741945256314195289865075076907359794502490207866014317755229824121091817 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [7050980761034239836998401171330113822559450636994971400449179984680945710605, - 7245004549500637626631429097675336758284887245753968402756783758231816600578], - [1912372262250363594846622538306495689461171293922464070666397682496221820996, - 4448756910343248867349276404521881079098652604464026018719784207380017616504] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [10386785173203277016286536862189620026369918147210722548529875639964738492365, - 10260101631204322380590458978388206190754312680054648449700080390119838842352], - [17499857054563879156025506727072492071039844715020065260480569946937485671386, - 20482166523252423179517681492516183602449981226837665118307063641102395645980] - ); - vk.IC = new Pairing.G1Point[](9); - - vk.IC[0] = Pairing.G1Point( - 5217029074363191009153168293602949732122867269059742615780145104028588755243, - 7302528814060166943448843452169732430580601844394772798554284494470974378241 - ); - - vk.IC[1] = Pairing.G1Point( - 1205542870209938855953419429705928537996975130868276548852443121438792536192, - 4594047774862512977856578329557095241274578262029405625789973824041284807524 - ); - - vk.IC[2] = Pairing.G1Point( - 2090413075041956165021556588123563982176255690132585222281529528833370464495, - 5401720164354808207712354060695914484566014751420069619562362528917396073927 - ); - - vk.IC[3] = Pairing.G1Point( - 10112618262104835718303354235520200519324718553977123990575583292776721566949, - 1484441975998545105342393038709757833277156905841911049470613059230922095285 - ); - - vk.IC[4] = Pairing.G1Point( - 3485773240265716524274565786103171033284165224198188896851257238068926226233, - 10241464363953829543826671743176597873041079844085286664571792265893022282343 - ); - - vk.IC[5] = Pairing.G1Point( - 1619962777178475472974359431190838169548339667367397269154590259773021111971, - 7380811362405771914044805159484141255669216971422085438210318233262935992143 - ); - - vk.IC[6] = Pairing.G1Point( - 12902033569088085579283660292309177183033077213436362874179341430754361528607, - 6005076429094166387114717765564250931327041105169881999902295325721859831516 - ); - - vk.IC[7] = Pairing.G1Point( - 705201658105691565168867520788769496876391316758382706073229317710886909910, - 18004377023727330049451106698619926196213214239745810823029715995515282885247 - ); - - vk.IC[8] = Pairing.G1Point( - 21016184848904378266398627005331366145988824667580666066134717872632623261843, - 7959088307989609496256161278063491203047381192140659560379742877588539011291 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[8] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 15635276308160559792004133274137521635544708393707107117296778344248550957505, + 3717741945256314195289865075076907359794502490207866014317755229824121091817 + ); + + vk.beta2 = Pairing.G2Point( + [ + 7050980761034239836998401171330113822559450636994971400449179984680945710605, + 7245004549500637626631429097675336758284887245753968402756783758231816600578 + ], + [ + 1912372262250363594846622538306495689461171293922464070666397682496221820996, + 4448756910343248867349276404521881079098652604464026018719784207380017616504 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 10386785173203277016286536862189620026369918147210722548529875639964738492365, + 10260101631204322380590458978388206190754312680054648449700080390119838842352 + ], + [ + 17499857054563879156025506727072492071039844715020065260480569946937485671386, + 20482166523252423179517681492516183602449981226837665118307063641102395645980 + ] + ); + vk.IC = new Pairing.G1Point[](9); + + vk.IC[0] = Pairing.G1Point( + 5217029074363191009153168293602949732122867269059742615780145104028588755243, + 7302528814060166943448843452169732430580601844394772798554284494470974378241 + ); + + vk.IC[1] = Pairing.G1Point( + 1205542870209938855953419429705928537996975130868276548852443121438792536192, + 4594047774862512977856578329557095241274578262029405625789973824041284807524 + ); + + vk.IC[2] = Pairing.G1Point( + 2090413075041956165021556588123563982176255690132585222281529528833370464495, + 5401720164354808207712354060695914484566014751420069619562362528917396073927 + ); + + vk.IC[3] = Pairing.G1Point( + 10112618262104835718303354235520200519324718553977123990575583292776721566949, + 1484441975998545105342393038709757833277156905841911049470613059230922095285 + ); + + vk.IC[4] = Pairing.G1Point( + 3485773240265716524274565786103171033284165224198188896851257238068926226233, + 10241464363953829543826671743176597873041079844085286664571792265893022282343 + ); + + vk.IC[5] = Pairing.G1Point( + 1619962777178475472974359431190838169548339667367397269154590259773021111971, + 7380811362405771914044805159484141255669216971422085438210318233262935992143 + ); + + vk.IC[6] = Pairing.G1Point( + 12902033569088085579283660292309177183033077213436362874179341430754361528607, + 6005076429094166387114717765564250931327041105169881999902295325721859831516 + ); + + vk.IC[7] = Pairing.G1Point( + 705201658105691565168867520788769496876391316758382706073229317710886909910, + 18004377023727330049451106698619926196213214239745810823029715995515282885247 + ); + + vk.IC[8] = Pairing.G1Point( + 21016184848904378266398627005331366145988824667580666066134717872632623261843, + 7959088307989609496256161278063491203047381192140659560379742877588539011291 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[8] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/anchor/Verifier6.sol b/packages/contracts/contracts/verifiers/anchor/Verifier6.sol index 923d9a2ce..e64287b02 100644 --- a/packages/contracts/contracts/verifiers/anchor/Verifier6.sol +++ b/packages/contracts/contracts/verifiers/anchor/Verifier6.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,251 +53,308 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier6 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 15635276308160559792004133274137521635544708393707107117296778344248550957505, - 3717741945256314195289865075076907359794502490207866014317755229824121091817 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [7050980761034239836998401171330113822559450636994971400449179984680945710605, - 7245004549500637626631429097675336758284887245753968402756783758231816600578], - [1912372262250363594846622538306495689461171293922464070666397682496221820996, - 4448756910343248867349276404521881079098652604464026018719784207380017616504] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [8709039110629303451143133225383626091695101077173163219528573795121084319578, - 17636152048734678166695455732979574623720886151558180835345714408612856669862], - [16816907039512221899937642320480759644086098075679797380845308974784445149013, - 14856200062463918176294567144281250312443009191861707522912899919341640597546] - ); - vk.IC = new Pairing.G1Point[](10); - - vk.IC[0] = Pairing.G1Point( - 5923631864235052074406544007994411084719384010323655087535806350226008889939, - 12175403793793718683308416574751858176529006221486461692902077563067598366988 - ); - - vk.IC[1] = Pairing.G1Point( - 20682141288036894211495624768687575662186498086484208656468903821066214114586, - 13333099095196864627757882205510867637574334908555335929674435398845804874567 - ); - - vk.IC[2] = Pairing.G1Point( - 3799983121758077274486270902121847687941692460472677168687648453818385072903, - 18631334569661882849766940289382849676478148794661899969172728930148270633344 - ); - - vk.IC[3] = Pairing.G1Point( - 20539663705720157909212510997017651894731494776974711871057375013489954388589, - 20282267041783480152298559202844193425161586258145576992946308537068821986419 - ); - - vk.IC[4] = Pairing.G1Point( - 10046530921222124793667916117873734998265740698658709712719507660710016257106, - 15330021723184807622673216480489605272961105031407928956675274637725535888628 - ); - - vk.IC[5] = Pairing.G1Point( - 21011111978392244221157378779821568326225782491406539851244356708873509677870, - 4989430395712938823713450404865452075000874307770623941951274114489213572547 - ); - - vk.IC[6] = Pairing.G1Point( - 4649165914183451903070229538796423555432129625890859082344905189685172052498, - 3063281552182071905699847827032198355688663102985721894191049730416930259337 - ); - - vk.IC[7] = Pairing.G1Point( - 21509217376116677011895337948818687612118873779085333569301956331062354558756, - 5745411812407363558306912927696712741764424638150731194844483418055205524714 - ); - - vk.IC[8] = Pairing.G1Point( - 9112265128259799734225563823358930999238048571643544645310632880164911857939, - 10920829268983456735284026512999939724034813783813569128224296325141275801387 - ); - - vk.IC[9] = Pairing.G1Point( - 13872120945619431884090923278909532177530582303405742596282387905787509514225, - 19324383284959762382974833409781603167748011680826516271172249666127471438565 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[9] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 15635276308160559792004133274137521635544708393707107117296778344248550957505, + 3717741945256314195289865075076907359794502490207866014317755229824121091817 + ); + + vk.beta2 = Pairing.G2Point( + [ + 7050980761034239836998401171330113822559450636994971400449179984680945710605, + 7245004549500637626631429097675336758284887245753968402756783758231816600578 + ], + [ + 1912372262250363594846622538306495689461171293922464070666397682496221820996, + 4448756910343248867349276404521881079098652604464026018719784207380017616504 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 8709039110629303451143133225383626091695101077173163219528573795121084319578, + 17636152048734678166695455732979574623720886151558180835345714408612856669862 + ], + [ + 16816907039512221899937642320480759644086098075679797380845308974784445149013, + 14856200062463918176294567144281250312443009191861707522912899919341640597546 + ] + ); + vk.IC = new Pairing.G1Point[](10); + + vk.IC[0] = Pairing.G1Point( + 5923631864235052074406544007994411084719384010323655087535806350226008889939, + 12175403793793718683308416574751858176529006221486461692902077563067598366988 + ); + + vk.IC[1] = Pairing.G1Point( + 20682141288036894211495624768687575662186498086484208656468903821066214114586, + 13333099095196864627757882205510867637574334908555335929674435398845804874567 + ); + + vk.IC[2] = Pairing.G1Point( + 3799983121758077274486270902121847687941692460472677168687648453818385072903, + 18631334569661882849766940289382849676478148794661899969172728930148270633344 + ); + + vk.IC[3] = Pairing.G1Point( + 20539663705720157909212510997017651894731494776974711871057375013489954388589, + 20282267041783480152298559202844193425161586258145576992946308537068821986419 + ); + + vk.IC[4] = Pairing.G1Point( + 10046530921222124793667916117873734998265740698658709712719507660710016257106, + 15330021723184807622673216480489605272961105031407928956675274637725535888628 + ); + + vk.IC[5] = Pairing.G1Point( + 21011111978392244221157378779821568326225782491406539851244356708873509677870, + 4989430395712938823713450404865452075000874307770623941951274114489213572547 + ); + + vk.IC[6] = Pairing.G1Point( + 4649165914183451903070229538796423555432129625890859082344905189685172052498, + 3063281552182071905699847827032198355688663102985721894191049730416930259337 + ); + + vk.IC[7] = Pairing.G1Point( + 21509217376116677011895337948818687612118873779085333569301956331062354558756, + 5745411812407363558306912927696712741764424638150731194844483418055205524714 + ); + + vk.IC[8] = Pairing.G1Point( + 9112265128259799734225563823358930999238048571643544645310632880164911857939, + 10920829268983456735284026512999939724034813783813569128224296325141275801387 + ); + + vk.IC[9] = Pairing.G1Point( + 13872120945619431884090923278909532177530582303405742596282387905787509514225, + 19324383284959762382974833409781603167748011680826516271172249666127471438565 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[9] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID2_16.sol b/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID2_16.sol index e14dea706..4804d37ca 100644 --- a/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID2_16.sol +++ b/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID2_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } -/* + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,331 +53,388 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierID2_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [14657607130299255293077190941496326198533041986079519324728829898803110190986, - 14398356285663295195409926011591734854158245586998701324369694015987556680392], - [2292248176593559989752658172913829845686014578337509448532426730358844381004, - 14932740719064665183832388332291287328602878323290352780317454203426441504614] - ); - vk.IC = new Pairing.G1Point[](26); - - vk.IC[0] = Pairing.G1Point( - 1862832167956501745853748595854724406302483208556781253006709654551206108199, - 8551073296617541564220622739990630644079732459859369269481647544398171186319 - ); - - vk.IC[1] = Pairing.G1Point( - 19449273730074653754026584714265970627732389245959173614293967105632584584038, - 19124079672506434997245929248446620625001305673039228386822794701739656909 - ); - - vk.IC[2] = Pairing.G1Point( - 9944563376524985697282551723688329677065202159758622990321665947480369032833, - 20900295422482616592807804506452796178520684447072683875004219848027091379977 - ); - - vk.IC[3] = Pairing.G1Point( - 781657127175646513838965163506571962557526055170703305785848144037008291851, - 10522792075061559486066003810529679268245107910757960177188849501107232407569 - ); - - vk.IC[4] = Pairing.G1Point( - 21589545712952461676474636239923614632905661675105801704258725334178026293923, - 18375572687141249860439797062822536697131987741777196557455751873338227597309 - ); - - vk.IC[5] = Pairing.G1Point( - 7682540871237450581632461135898027541895950077979447746829891026287572555649, - 11746724751521186797776874829301827164408622915132472245627856212399792798744 - ); - - vk.IC[6] = Pairing.G1Point( - 20783065847434526464137016413797563068886289455346058672349076866630406530685, - 20793389594981279941568451477810041913321815315123486273073690295597821524324 - ); - - vk.IC[7] = Pairing.G1Point( - 6049365897720626381297816906049364603478670592827693408964421022518430095255, - 669635970429727333534411063228071898031242203030376411515507948240932464303 - ); - - vk.IC[8] = Pairing.G1Point( - 15989486587596313812295860971050269776980446168903368956653001987669415291269, - 20530517255532511400577966384078360871251245234090435785388962674797298928050 - ); - - vk.IC[9] = Pairing.G1Point( - 17605328793370954816852278220627201407718003879421726096330657255954047662213, - 13008380666684908234497501721195701883317641227358176011996695490582942701973 - ); - - vk.IC[10] = Pairing.G1Point( - 10219502347387765531008902354537398853958211016238758918155419685192385997015, - 5800793735604819825310974076292638852208495526323063390393362201206588950355 - ); - - vk.IC[11] = Pairing.G1Point( - 16824155659520789931146946175024763661017162767492745545574222157131302261308, - 15423338396899440471598524542778502725650666891019508366933439188732597950628 - ); - - vk.IC[12] = Pairing.G1Point( - 6041501983136521078671441137648324905622903321963314622041544629930008145738, - 17268331052892280206476512840688816414304054110611347555143025524437363958643 - ); - - vk.IC[13] = Pairing.G1Point( - 1427337525254444270771499951826436096513174916431002573639590773166233661554, - 6041601222001006296746293580462731718841319585488600155079482796388936843039 - ); - - vk.IC[14] = Pairing.G1Point( - 16649466491991152382628837195982958187212471475409318346893434595512056621795, - 20532127497203888386589976699350148235325423018605785221845204915037036942437 - ); - - vk.IC[15] = Pairing.G1Point( - 21092074290684879444200361406051347727963670240291812003406025715606138376381, - 9532675857057091956121352325596408253395597060161904436299354437649535587633 - ); - - vk.IC[16] = Pairing.G1Point( - 19809075818002973918436922374798343419047502693433651039905622352110336442466, - 9116046131623173051812542396682289958966883397123034908361487346576044630360 - ); - - vk.IC[17] = Pairing.G1Point( - 14709053857389534896901800480023461098628440631125293539754952235377690878999, - 9056551674567093392336523943961508361025175584497509225261140696140984721595 - ); - - vk.IC[18] = Pairing.G1Point( - 7718557886406584960509537259710586189003194276677061526088723529889162695960, - 10434885639394753945846797015966072117165577141758988572427066164474235209410 - ); - - vk.IC[19] = Pairing.G1Point( - 15381196696112479142284265824277471185626180003613962867849179253048230429735, - 7456187409434153703109801469705562705844571488848747273400717715593891118278 - ); - - vk.IC[20] = Pairing.G1Point( - 8376144245156967380053177957588769706269475013130780300181781862980927671048, - 6574922661947842251800744493008206688123817023410734105973543756571165732749 - ); - - vk.IC[21] = Pairing.G1Point( - 9248845890775451259732290436428003210908898871960180168511696976055808970345, - 10417417874227922893902255313522755506282223649964907508403971336739197781068 - ); - - vk.IC[22] = Pairing.G1Point( - 6929438488202303412063903790277704257076066263341349665828939986808024420192, - 7449567621074681790322174517873975202026560780786489070347404688568694653815 - ); - - vk.IC[23] = Pairing.G1Point( - 15120334675194086999618528672847583601423118353437993342285777301803288813747, - 3897995782081045238026883170318383589082164540949857607584859232350578054072 - ); - - vk.IC[24] = Pairing.G1Point( - 1941782210390795053241077554989644578077553930971253113979524746711137829895, - 12429588978001094361936504846018332080020222597437212838886842759287758925728 - ); - - vk.IC[25] = Pairing.G1Point( - 19186543379436433365775183073338485026739838314420384291473373052657653875377, - 5399475157212436927492718820406594055332157686916147692136152004850758131832 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[25] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 14657607130299255293077190941496326198533041986079519324728829898803110190986, + 14398356285663295195409926011591734854158245586998701324369694015987556680392 + ], + [ + 2292248176593559989752658172913829845686014578337509448532426730358844381004, + 14932740719064665183832388332291287328602878323290352780317454203426441504614 + ] + ); + vk.IC = new Pairing.G1Point[](26); + + vk.IC[0] = Pairing.G1Point( + 1862832167956501745853748595854724406302483208556781253006709654551206108199, + 8551073296617541564220622739990630644079732459859369269481647544398171186319 + ); + + vk.IC[1] = Pairing.G1Point( + 19449273730074653754026584714265970627732389245959173614293967105632584584038, + 19124079672506434997245929248446620625001305673039228386822794701739656909 + ); + + vk.IC[2] = Pairing.G1Point( + 9944563376524985697282551723688329677065202159758622990321665947480369032833, + 20900295422482616592807804506452796178520684447072683875004219848027091379977 + ); + + vk.IC[3] = Pairing.G1Point( + 781657127175646513838965163506571962557526055170703305785848144037008291851, + 10522792075061559486066003810529679268245107910757960177188849501107232407569 + ); + + vk.IC[4] = Pairing.G1Point( + 21589545712952461676474636239923614632905661675105801704258725334178026293923, + 18375572687141249860439797062822536697131987741777196557455751873338227597309 + ); + + vk.IC[5] = Pairing.G1Point( + 7682540871237450581632461135898027541895950077979447746829891026287572555649, + 11746724751521186797776874829301827164408622915132472245627856212399792798744 + ); + + vk.IC[6] = Pairing.G1Point( + 20783065847434526464137016413797563068886289455346058672349076866630406530685, + 20793389594981279941568451477810041913321815315123486273073690295597821524324 + ); + + vk.IC[7] = Pairing.G1Point( + 6049365897720626381297816906049364603478670592827693408964421022518430095255, + 669635970429727333534411063228071898031242203030376411515507948240932464303 + ); + + vk.IC[8] = Pairing.G1Point( + 15989486587596313812295860971050269776980446168903368956653001987669415291269, + 20530517255532511400577966384078360871251245234090435785388962674797298928050 + ); + + vk.IC[9] = Pairing.G1Point( + 17605328793370954816852278220627201407718003879421726096330657255954047662213, + 13008380666684908234497501721195701883317641227358176011996695490582942701973 + ); + + vk.IC[10] = Pairing.G1Point( + 10219502347387765531008902354537398853958211016238758918155419685192385997015, + 5800793735604819825310974076292638852208495526323063390393362201206588950355 + ); + + vk.IC[11] = Pairing.G1Point( + 16824155659520789931146946175024763661017162767492745545574222157131302261308, + 15423338396899440471598524542778502725650666891019508366933439188732597950628 + ); + + vk.IC[12] = Pairing.G1Point( + 6041501983136521078671441137648324905622903321963314622041544629930008145738, + 17268331052892280206476512840688816414304054110611347555143025524437363958643 + ); + + vk.IC[13] = Pairing.G1Point( + 1427337525254444270771499951826436096513174916431002573639590773166233661554, + 6041601222001006296746293580462731718841319585488600155079482796388936843039 + ); + + vk.IC[14] = Pairing.G1Point( + 16649466491991152382628837195982958187212471475409318346893434595512056621795, + 20532127497203888386589976699350148235325423018605785221845204915037036942437 + ); + + vk.IC[15] = Pairing.G1Point( + 21092074290684879444200361406051347727963670240291812003406025715606138376381, + 9532675857057091956121352325596408253395597060161904436299354437649535587633 + ); + + vk.IC[16] = Pairing.G1Point( + 19809075818002973918436922374798343419047502693433651039905622352110336442466, + 9116046131623173051812542396682289958966883397123034908361487346576044630360 + ); + + vk.IC[17] = Pairing.G1Point( + 14709053857389534896901800480023461098628440631125293539754952235377690878999, + 9056551674567093392336523943961508361025175584497509225261140696140984721595 + ); + + vk.IC[18] = Pairing.G1Point( + 7718557886406584960509537259710586189003194276677061526088723529889162695960, + 10434885639394753945846797015966072117165577141758988572427066164474235209410 + ); + + vk.IC[19] = Pairing.G1Point( + 15381196696112479142284265824277471185626180003613962867849179253048230429735, + 7456187409434153703109801469705562705844571488848747273400717715593891118278 + ); + + vk.IC[20] = Pairing.G1Point( + 8376144245156967380053177957588769706269475013130780300181781862980927671048, + 6574922661947842251800744493008206688123817023410734105973543756571165732749 + ); + + vk.IC[21] = Pairing.G1Point( + 9248845890775451259732290436428003210908898871960180168511696976055808970345, + 10417417874227922893902255313522755506282223649964907508403971336739197781068 + ); + + vk.IC[22] = Pairing.G1Point( + 6929438488202303412063903790277704257076066263341349665828939986808024420192, + 7449567621074681790322174517873975202026560780786489070347404688568694653815 + ); + + vk.IC[23] = Pairing.G1Point( + 15120334675194086999618528672847583601423118353437993342285777301803288813747, + 3897995782081045238026883170318383589082164540949857607584859232350578054072 + ); + + vk.IC[24] = Pairing.G1Point( + 1941782210390795053241077554989644578077553930971253113979524746711137829895, + 12429588978001094361936504846018332080020222597437212838886842759287758925728 + ); + + vk.IC[25] = Pairing.G1Point( + 19186543379436433365775183073338485026739838314420384291473373052657653875377, + 5399475157212436927492718820406594055332157686916147692136152004850758131832 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[25] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID8_16.sol b/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID8_16.sol index 1af072708..9f45a6414 100644 --- a/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID8_16.sol +++ b/packages/contracts/contracts/verifiers/identity_vanchor_16/VerifierID8_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,391 +53,448 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierID8_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [14218094164716868305873729111377446674332253889872578474640132516623270053143, - 2508776180378170018967638606435675263723027897828795197914221155227733473784], - [2729393781834482459112256059542021127394957192979527446114345723196799311401, - 10907381609139027668319725469139917772870155951599818981350422308476726892006] - ); - vk.IC = new Pairing.G1Point[](38); - - vk.IC[0] = Pairing.G1Point( - 13450895664588552036708971481147349549288074436300096573006570879638164669110, - 17490656400764351421618696846174620715793393323120228978737858300615187019394 - ); - - vk.IC[1] = Pairing.G1Point( - 5078498626711059735015917986345047489646199682765334897700200866907572032376, - 11650262732058313077910850058972887580527499882161401061541710523096229236195 - ); - - vk.IC[2] = Pairing.G1Point( - 5921413903015294333764285158507901150281997990897804292721038348419170779419, - 14299203451734936424859776204640844742821123313777289125592303435401420285696 - ); - - vk.IC[3] = Pairing.G1Point( - 6219629406291913168282830956465692927385502642992387572909364644746568093167, - 6723570697172916795250821196407975971987165684323180265474709190920251547727 - ); - - vk.IC[4] = Pairing.G1Point( - 4833223589742194706688217608316858436742854272655220278718617354790088103636, - 7114099040105576856596673691394101298466968670533136337203649916912569822827 - ); - - vk.IC[5] = Pairing.G1Point( - 3156524197926762461999361092004537582133101386559082941977475435088414659014, - 2255406582903697762410889514445195179115268662989992867783669750959115640701 - ); - - vk.IC[6] = Pairing.G1Point( - 14176641248483081161465827092637304738656679469210522893783787954784260930494, - 356308364287309782924095289646880940682444095656373084622959745420125950717 - ); - - vk.IC[7] = Pairing.G1Point( - 12190200200371614803773402917638814850600036594803370738855616589995386972671, - 15508832277269766106748468676314410978483488961392831482404546160576546836777 - ); - - vk.IC[8] = Pairing.G1Point( - 2547731272607859253569051392930484194825513247367248775224187672897557045458, - 18984027592482581579122160900629633862876098385160461809794749696077781646754 - ); - - vk.IC[9] = Pairing.G1Point( - 17967931870219746874746299800707055709388502171183311117143724897350528075813, - 20830742190713315190870165488802078078000505077417777487545655040055368276555 - ); - - vk.IC[10] = Pairing.G1Point( - 4375527235836585093409977152742587278885942220540705173557534358432692949928, - 9553786172152137736294645387836594556147906069464510698727578314876689878947 - ); - - vk.IC[11] = Pairing.G1Point( - 15650829351118754460133893761109692233438347868567908556726530245724350203082, - 9465977829976777777987917270738664434519514718942242807786992236409111033463 - ); - - vk.IC[12] = Pairing.G1Point( - 3974250896717003752550315937830823705297882192893473112982385109078375508175, - 1182271536722827358305841912882745892770653975554440193432262325604899080676 - ); - - vk.IC[13] = Pairing.G1Point( - 18429777727481654856096435066918313380287210807995663696274403178659573030330, - 8348308802526591746919426718827320979807278250119751846272487656651102997943 - ); - - vk.IC[14] = Pairing.G1Point( - 19170572410164971265778412429448270122870811958116570394606152192794174282791, - 17307647701749989268514119055204021036466229763424623024253162520869693805703 - ); - - vk.IC[15] = Pairing.G1Point( - 21128212960224380391997884389342322113402701111913586900670762836174097424170, - 11159054333976491757910646178678817042422121329699044216662552089712488564634 - ); - - vk.IC[16] = Pairing.G1Point( - 11157393442412708398646186095212202660592128978269554749033193107175355381127, - 13618455712049828684677653105410276895197572777477106619435108278678909647403 - ); - - vk.IC[17] = Pairing.G1Point( - 21233633316642139604252727477308007193100835320482352567888441574791218141821, - 5545850937248876137641103047869572515226945609176768773040400986040446389495 - ); - - vk.IC[18] = Pairing.G1Point( - 6307248548465897790434152892268231157606578008204118571910815512211918103075, - 18125408605853654177608969688121445864875598306671063625432522402584530316869 - ); - - vk.IC[19] = Pairing.G1Point( - 384876531051716462062354681472265394421065044881978279137947170926928423513, - 13321913136307018806212776879988478743273000903125732849503237212217839545967 - ); - - vk.IC[20] = Pairing.G1Point( - 9010221655112567472185957099908428623262780821706494586540276395830648820994, - 18875503843517917587066808502634680470949971212551383338937897926316094306059 - ); - - vk.IC[21] = Pairing.G1Point( - 21361648665472658954569392259080109864110037802393658728397571905484907486500, - 6974537634026315065474728000251587152379238493591263432838346179600596607305 - ); - - vk.IC[22] = Pairing.G1Point( - 15439973549924044152816612682487896544442271809828723657638419433515637196645, - 12728572758991806503463266312344596990071946087439406315102059808748662002235 - ); - - vk.IC[23] = Pairing.G1Point( - 16921583945315529803833533505785438090099182287531005464789389520801573992396, - 17930228154180739498419375006600489158455693367538991842677437933336250164297 - ); - - vk.IC[24] = Pairing.G1Point( - 3286279099679051851318993223017304040808661112628548943372576655674076429459, - 1902736740482644908059776498052993980219301553481806018497760119997543107594 - ); - - vk.IC[25] = Pairing.G1Point( - 19599081070085877602397811941683326835399713190914236314731083164695004377146, - 1067105681915777478495892472818259780518676729996063342224532167804233656269 - ); - - vk.IC[26] = Pairing.G1Point( - 1780729381180285671841769263674498755932780952259318814333518894548332698256, - 15801339467253812602329564596950424447764475451287316736793034051800036898948 - ); - - vk.IC[27] = Pairing.G1Point( - 4240805071164939657115788471392787340333899337057726710962948838251465819998, - 7249904915836172728249720843356511585679467595071689663709977676989453126523 - ); - - vk.IC[28] = Pairing.G1Point( - 1175371894402468981263549114312428715289996510117909111763507491754802057681, - 20116683251061346595406100541437880711842432375916743788543753603811865713206 - ); - - vk.IC[29] = Pairing.G1Point( - 14115125023778431533737121177726521283386685118512614574402453434611293533365, - 2134282569277720047181292069852024359156288627848346661789872430483303910775 - ); - - vk.IC[30] = Pairing.G1Point( - 6548499707228722998665190451310574674145690660317293037774342862736859720403, - 2034728861301364513250238400440546586441609827794261335970759006302749657580 - ); - - vk.IC[31] = Pairing.G1Point( - 11800518647547654743187123885350442425003772301552409723222584384698821012485, - 20786628783637482620965001985411817335708440140406547026559536301295764038892 - ); - - vk.IC[32] = Pairing.G1Point( - 18000148985062927493106478536760508159943320403514365549205786295292306775603, - 2505001846207926443849621579745955499482532137550834120575608438182196726621 - ); - - vk.IC[33] = Pairing.G1Point( - 6412200607402661720856134657747730643050255691746521736493635598396913182987, - 19214550649402985915003059676499998597885000073825664917206932079483232248772 - ); - - vk.IC[34] = Pairing.G1Point( - 15932607765962678553885288241847680998762705235462598321394298175123696588651, - 19800192896322269856196282321698384682967703716418763012611664801305455764633 - ); - - vk.IC[35] = Pairing.G1Point( - 4626648440982321851189155685689951227690145691194894483704886483460539162649, - 12403756309499488805291744663583015000107937773054567003159016355325552278190 - ); - - vk.IC[36] = Pairing.G1Point( - 197627240563968593592396100381555042889790622839139920472695918956077943454, - 20633403429212366113910052425361062596129074894975269260043454359561918444184 - ); - - vk.IC[37] = Pairing.G1Point( - 18259462768058195543273269457919444217881139492916669943214288847051417174035, - 2092612117781437687652945283122548419738870144286141755052235340119090587196 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[37] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 14218094164716868305873729111377446674332253889872578474640132516623270053143, + 2508776180378170018967638606435675263723027897828795197914221155227733473784 + ], + [ + 2729393781834482459112256059542021127394957192979527446114345723196799311401, + 10907381609139027668319725469139917772870155951599818981350422308476726892006 + ] + ); + vk.IC = new Pairing.G1Point[](38); + + vk.IC[0] = Pairing.G1Point( + 13450895664588552036708971481147349549288074436300096573006570879638164669110, + 17490656400764351421618696846174620715793393323120228978737858300615187019394 + ); + + vk.IC[1] = Pairing.G1Point( + 5078498626711059735015917986345047489646199682765334897700200866907572032376, + 11650262732058313077910850058972887580527499882161401061541710523096229236195 + ); + + vk.IC[2] = Pairing.G1Point( + 5921413903015294333764285158507901150281997990897804292721038348419170779419, + 14299203451734936424859776204640844742821123313777289125592303435401420285696 + ); + + vk.IC[3] = Pairing.G1Point( + 6219629406291913168282830956465692927385502642992387572909364644746568093167, + 6723570697172916795250821196407975971987165684323180265474709190920251547727 + ); + + vk.IC[4] = Pairing.G1Point( + 4833223589742194706688217608316858436742854272655220278718617354790088103636, + 7114099040105576856596673691394101298466968670533136337203649916912569822827 + ); + + vk.IC[5] = Pairing.G1Point( + 3156524197926762461999361092004537582133101386559082941977475435088414659014, + 2255406582903697762410889514445195179115268662989992867783669750959115640701 + ); + + vk.IC[6] = Pairing.G1Point( + 14176641248483081161465827092637304738656679469210522893783787954784260930494, + 356308364287309782924095289646880940682444095656373084622959745420125950717 + ); + + vk.IC[7] = Pairing.G1Point( + 12190200200371614803773402917638814850600036594803370738855616589995386972671, + 15508832277269766106748468676314410978483488961392831482404546160576546836777 + ); + + vk.IC[8] = Pairing.G1Point( + 2547731272607859253569051392930484194825513247367248775224187672897557045458, + 18984027592482581579122160900629633862876098385160461809794749696077781646754 + ); + + vk.IC[9] = Pairing.G1Point( + 17967931870219746874746299800707055709388502171183311117143724897350528075813, + 20830742190713315190870165488802078078000505077417777487545655040055368276555 + ); + + vk.IC[10] = Pairing.G1Point( + 4375527235836585093409977152742587278885942220540705173557534358432692949928, + 9553786172152137736294645387836594556147906069464510698727578314876689878947 + ); + + vk.IC[11] = Pairing.G1Point( + 15650829351118754460133893761109692233438347868567908556726530245724350203082, + 9465977829976777777987917270738664434519514718942242807786992236409111033463 + ); + + vk.IC[12] = Pairing.G1Point( + 3974250896717003752550315937830823705297882192893473112982385109078375508175, + 1182271536722827358305841912882745892770653975554440193432262325604899080676 + ); + + vk.IC[13] = Pairing.G1Point( + 18429777727481654856096435066918313380287210807995663696274403178659573030330, + 8348308802526591746919426718827320979807278250119751846272487656651102997943 + ); + + vk.IC[14] = Pairing.G1Point( + 19170572410164971265778412429448270122870811958116570394606152192794174282791, + 17307647701749989268514119055204021036466229763424623024253162520869693805703 + ); + + vk.IC[15] = Pairing.G1Point( + 21128212960224380391997884389342322113402701111913586900670762836174097424170, + 11159054333976491757910646178678817042422121329699044216662552089712488564634 + ); + + vk.IC[16] = Pairing.G1Point( + 11157393442412708398646186095212202660592128978269554749033193107175355381127, + 13618455712049828684677653105410276895197572777477106619435108278678909647403 + ); + + vk.IC[17] = Pairing.G1Point( + 21233633316642139604252727477308007193100835320482352567888441574791218141821, + 5545850937248876137641103047869572515226945609176768773040400986040446389495 + ); + + vk.IC[18] = Pairing.G1Point( + 6307248548465897790434152892268231157606578008204118571910815512211918103075, + 18125408605853654177608969688121445864875598306671063625432522402584530316869 + ); + + vk.IC[19] = Pairing.G1Point( + 384876531051716462062354681472265394421065044881978279137947170926928423513, + 13321913136307018806212776879988478743273000903125732849503237212217839545967 + ); + + vk.IC[20] = Pairing.G1Point( + 9010221655112567472185957099908428623262780821706494586540276395830648820994, + 18875503843517917587066808502634680470949971212551383338937897926316094306059 + ); + + vk.IC[21] = Pairing.G1Point( + 21361648665472658954569392259080109864110037802393658728397571905484907486500, + 6974537634026315065474728000251587152379238493591263432838346179600596607305 + ); + + vk.IC[22] = Pairing.G1Point( + 15439973549924044152816612682487896544442271809828723657638419433515637196645, + 12728572758991806503463266312344596990071946087439406315102059808748662002235 + ); + + vk.IC[23] = Pairing.G1Point( + 16921583945315529803833533505785438090099182287531005464789389520801573992396, + 17930228154180739498419375006600489158455693367538991842677437933336250164297 + ); + + vk.IC[24] = Pairing.G1Point( + 3286279099679051851318993223017304040808661112628548943372576655674076429459, + 1902736740482644908059776498052993980219301553481806018497760119997543107594 + ); + + vk.IC[25] = Pairing.G1Point( + 19599081070085877602397811941683326835399713190914236314731083164695004377146, + 1067105681915777478495892472818259780518676729996063342224532167804233656269 + ); + + vk.IC[26] = Pairing.G1Point( + 1780729381180285671841769263674498755932780952259318814333518894548332698256, + 15801339467253812602329564596950424447764475451287316736793034051800036898948 + ); + + vk.IC[27] = Pairing.G1Point( + 4240805071164939657115788471392787340333899337057726710962948838251465819998, + 7249904915836172728249720843356511585679467595071689663709977676989453126523 + ); + + vk.IC[28] = Pairing.G1Point( + 1175371894402468981263549114312428715289996510117909111763507491754802057681, + 20116683251061346595406100541437880711842432375916743788543753603811865713206 + ); + + vk.IC[29] = Pairing.G1Point( + 14115125023778431533737121177726521283386685118512614574402453434611293533365, + 2134282569277720047181292069852024359156288627848346661789872430483303910775 + ); + + vk.IC[30] = Pairing.G1Point( + 6548499707228722998665190451310574674145690660317293037774342862736859720403, + 2034728861301364513250238400440546586441609827794261335970759006302749657580 + ); + + vk.IC[31] = Pairing.G1Point( + 11800518647547654743187123885350442425003772301552409723222584384698821012485, + 20786628783637482620965001985411817335708440140406547026559536301295764038892 + ); + + vk.IC[32] = Pairing.G1Point( + 18000148985062927493106478536760508159943320403514365549205786295292306775603, + 2505001846207926443849621579745955499482532137550834120575608438182196726621 + ); + + vk.IC[33] = Pairing.G1Point( + 6412200607402661720856134657747730643050255691746521736493635598396913182987, + 19214550649402985915003059676499998597885000073825664917206932079483232248772 + ); + + vk.IC[34] = Pairing.G1Point( + 15932607765962678553885288241847680998762705235462598321394298175123696588651, + 19800192896322269856196282321698384682967703716418763012611664801305455764633 + ); + + vk.IC[35] = Pairing.G1Point( + 4626648440982321851189155685689951227690145691194894483704886483460539162649, + 12403756309499488805291744663583015000107937773054567003159016355325552278190 + ); + + vk.IC[36] = Pairing.G1Point( + 197627240563968593592396100381555042889790622839139920472695918956077943454, + 20633403429212366113910052425361062596129074894975269260043454359561918444184 + ); + + vk.IC[37] = Pairing.G1Point( + 18259462768058195543273269457919444217881139492916669943214288847051417174035, + 2092612117781437687652945283122548419738870144286141755052235340119090587196 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[37] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID2_2.sol b/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID2_2.sol index 8e15e4e46..376614e94 100644 --- a/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID2_2.sol +++ b/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID2_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,261 +53,318 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierID2_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [11826690979669972116939990254806647167390059450253908856368964033162661418264, - 18055782634989749677734377465143480904960098352318174705593774187529055496506], - [955025003822420631362961727870849681469323976269425585779581955834071227106, - 8430992846155543856081095306594643080846256049271622926950482490479246102246] - ); - vk.IC = new Pairing.G1Point[](12); - - vk.IC[0] = Pairing.G1Point( - 1574357329104546039145995440490773644670311887210558430250181197179783054515, - 20746215800516149916656982258858832796337927421517622238290958776503205453746 - ); - - vk.IC[1] = Pairing.G1Point( - 19291888342864901243120985483360514673249942256581778208648550688538607038768, - 11637873723410142066930871190805596509636636965722316552556302261301769461143 - ); - - vk.IC[2] = Pairing.G1Point( - 899897646714659097871432272350829748075576246748840509082297811472164942865, - 5862535610238101019379112910191183256949915983843431478846249031874186017401 - ); - - vk.IC[3] = Pairing.G1Point( - 6106232062887101182229892496814753015228313726463035794975323581658072519165, - 11476557787039073324117192548637487209769782006986184153781253170717620998546 - ); - - vk.IC[4] = Pairing.G1Point( - 4823537300879205664855420107621427768719705460436704020435527064520537651057, - 4856390107995991416016671581155721915016098071226064182472322805504274491741 - ); - - vk.IC[5] = Pairing.G1Point( - 7206438955653115010508206212063909239128235333207546574141212296873205215609, - 15538038567264492215369598794905574914997564414424399397695827482191641421352 - ); - - vk.IC[6] = Pairing.G1Point( - 17866978622960823299162469664262377166551186298687874184586891129487158673531, - 1798319668094528761242511995491664563157101592171427220310567500156411284718 - ); - - vk.IC[7] = Pairing.G1Point( - 1364250946720787832278785287622461276358806587158764660550134419307681406803, - 6768872450515271347633182193339069232054385941847722337347503515969143483198 - ); - - vk.IC[8] = Pairing.G1Point( - 7077325730713076585165789714079946115159446394768996822876863017444105375901, - 4408128172287564357811900721688707050977805247305795775216459239969530734703 - ); - - vk.IC[9] = Pairing.G1Point( - 17940179899348855702273664875413222940968646092251224058971924969002509465232, - 8067878197322328710590484114560363996672055429270604143908906147649133835641 - ); - - vk.IC[10] = Pairing.G1Point( - 1198361527424839588548673634537765964575353088816885049846046001362817946501, - 12786845578425791619075124870735914087163667468306028936856767180636955919062 - ); - - vk.IC[11] = Pairing.G1Point( - 14598137811236069495921998920178847126287384133618267685416870805490269562211, - 1590825300873387383927370466287974720041217673532877445658882661355876706355 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[11] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 11826690979669972116939990254806647167390059450253908856368964033162661418264, + 18055782634989749677734377465143480904960098352318174705593774187529055496506 + ], + [ + 955025003822420631362961727870849681469323976269425585779581955834071227106, + 8430992846155543856081095306594643080846256049271622926950482490479246102246 + ] + ); + vk.IC = new Pairing.G1Point[](12); + + vk.IC[0] = Pairing.G1Point( + 1574357329104546039145995440490773644670311887210558430250181197179783054515, + 20746215800516149916656982258858832796337927421517622238290958776503205453746 + ); + + vk.IC[1] = Pairing.G1Point( + 19291888342864901243120985483360514673249942256581778208648550688538607038768, + 11637873723410142066930871190805596509636636965722316552556302261301769461143 + ); + + vk.IC[2] = Pairing.G1Point( + 899897646714659097871432272350829748075576246748840509082297811472164942865, + 5862535610238101019379112910191183256949915983843431478846249031874186017401 + ); + + vk.IC[3] = Pairing.G1Point( + 6106232062887101182229892496814753015228313726463035794975323581658072519165, + 11476557787039073324117192548637487209769782006986184153781253170717620998546 + ); + + vk.IC[4] = Pairing.G1Point( + 4823537300879205664855420107621427768719705460436704020435527064520537651057, + 4856390107995991416016671581155721915016098071226064182472322805504274491741 + ); + + vk.IC[5] = Pairing.G1Point( + 7206438955653115010508206212063909239128235333207546574141212296873205215609, + 15538038567264492215369598794905574914997564414424399397695827482191641421352 + ); + + vk.IC[6] = Pairing.G1Point( + 17866978622960823299162469664262377166551186298687874184586891129487158673531, + 1798319668094528761242511995491664563157101592171427220310567500156411284718 + ); + + vk.IC[7] = Pairing.G1Point( + 1364250946720787832278785287622461276358806587158764660550134419307681406803, + 6768872450515271347633182193339069232054385941847722337347503515969143483198 + ); + + vk.IC[8] = Pairing.G1Point( + 7077325730713076585165789714079946115159446394768996822876863017444105375901, + 4408128172287564357811900721688707050977805247305795775216459239969530734703 + ); + + vk.IC[9] = Pairing.G1Point( + 17940179899348855702273664875413222940968646092251224058971924969002509465232, + 8067878197322328710590484114560363996672055429270604143908906147649133835641 + ); + + vk.IC[10] = Pairing.G1Point( + 1198361527424839588548673634537765964575353088816885049846046001362817946501, + 12786845578425791619075124870735914087163667468306028936856767180636955919062 + ); + + vk.IC[11] = Pairing.G1Point( + 14598137811236069495921998920178847126287384133618267685416870805490269562211, + 1590825300873387383927370466287974720041217673532877445658882661355876706355 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[11] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID8_2.sol b/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID8_2.sol index 57829aca0..623701c01 100644 --- a/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID8_2.sol +++ b/packages/contracts/contracts/verifiers/identity_vanchor_2/VerifierID8_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } -/* + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,321 +53,378 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierID8_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [5470771292357224324162037181600593787310803236698332408392365334773005080585, - 3494342642698632792945493330785761039749005378104858604249520700320120879349], - [19636949787553396692208866092658536686505317638394158311560046322207714016321, - 17154689793746496271935789244545520802485941475858327269600346416623923159021] - ); - vk.IC = new Pairing.G1Point[](24); - - vk.IC[0] = Pairing.G1Point( - 18611062343511170357026553953758987681531643503394025314707050482396395666255, - 21871937856609315565490828962524566910389201797830976035654654241259185294189 - ); - - vk.IC[1] = Pairing.G1Point( - 2626850471938876016272250995132059732766702802414678794136113436467701497381, - 15856809560815353250215675532518053108284293527737276069251944177094696612831 - ); - - vk.IC[2] = Pairing.G1Point( - 17149445972624492180406560554997486059080227363063999877151374883685294369167, - 923370209582343483534382902433360877085518011178862782681518488009892052028 - ); - - vk.IC[3] = Pairing.G1Point( - 20417473811553148448619050325254449341381176913153415632705990668648880964082, - 19212842676028502782078905502288513898901775609524694908204599507508359056512 - ); - - vk.IC[4] = Pairing.G1Point( - 3113839248998919148150222311966457667798838587744947227414067830080164495439, - 17599350298379402061066711963207622488966698676898236075850530935406080595355 - ); - - vk.IC[5] = Pairing.G1Point( - 15161933654458687779531138005738701071948822246351767415002403707117254709593, - 4283456777077685653627504970688766667750285278794900008396392917183318189844 - ); - - vk.IC[6] = Pairing.G1Point( - 14783083858372666270392070738487037527332066739312315309127555992780471167892, - 19987096935750677139560540890546967144803812783740042793332962283466560905367 - ); - - vk.IC[7] = Pairing.G1Point( - 2896624934114960471561612808888961000430237704000903604598413400777978522138, - 20863685015972891668404373255113900974340301846718583278325205870259261191221 - ); - - vk.IC[8] = Pairing.G1Point( - 6508340445764958285310639653039019394593107384867849792347263007890734482117, - 19356821758081560488138321972663477016666642851877428394098667268356486543665 - ); - - vk.IC[9] = Pairing.G1Point( - 16388142491063093532693947815829290664145211304802056002760078794768526047841, - 17093442606964487364267161412828723948788786864591060879778342916916281873355 - ); - - vk.IC[10] = Pairing.G1Point( - 21063873767815155348022518442384127489291649486720053943734052788865613453122, - 5757053647888665951846263262066463598769080435404670032554805038676954192976 - ); - - vk.IC[11] = Pairing.G1Point( - 7835709697997100403722492282043383726078532353700579251453524362622755128258, - 13398026612042421924647048351949123170996095802448143488137869573581757767277 - ); - - vk.IC[12] = Pairing.G1Point( - 16905486623626811833650946186914564652495265079775833606574281122133319312510, - 4427027193758025301553694612964889583972267813249871797238570154256349746056 - ); - - vk.IC[13] = Pairing.G1Point( - 10000842517562602959069155718156794808544709834332678159917179926701945774390, - 4938704773073298251056144005210432625250079279710139910301587372734289587663 - ); - - vk.IC[14] = Pairing.G1Point( - 20633394807876201703297996957750972575066996755381011587934686084288053805476, - 13704564904538428141779528316331135999912524274190405323646245869532676333954 - ); - - vk.IC[15] = Pairing.G1Point( - 14443387715676296192674906794544384137311168721188704733523522408724932219752, - 6428088729870240750338580955220436051158180682246281479413611985744717149203 - ); - - vk.IC[16] = Pairing.G1Point( - 13956305720059725136522097658313647870684299367665993695129046258000048965217, - 20225563638691166821878074327855277932767593218972275595102121226540550298950 - ); - - vk.IC[17] = Pairing.G1Point( - 16587738518047281634627910596882357687319266831719360348032787256147500768889, - 20861431405239551971326025727032583540133917147214344185224021812242565453623 - ); - - vk.IC[18] = Pairing.G1Point( - 18340957541386761368230404588626882995488718633543788802532598537693896834249, - 20505757121991843408984353998515449759033993550178326915106374590854632518049 - ); - - vk.IC[19] = Pairing.G1Point( - 18823107582955243296749545767012978506913487366567388961249897410933119158266, - 2540295498873080502738278084748378187334294388859366491553697022944581365683 - ); - - vk.IC[20] = Pairing.G1Point( - 8713435974062649198166277037854849354941613305499674037468202588658393009983, - 6751826882427118872560815217109209602886713988448117071506516767514586509133 - ); - - vk.IC[21] = Pairing.G1Point( - 15555705049575593729216030156045190112934764433714326390183763977750636367151, - 14825433821645698374432221682580079748012262619055046242161314180820722900986 - ); - - vk.IC[22] = Pairing.G1Point( - 13955185291957381082762655488723861296722142172046360205871383587363520827916, - 12054242459929492955672760406108328147348907458023215701419619669424077744084 - ); - - vk.IC[23] = Pairing.G1Point( - 2662864612618040313825745082358546624115513040317168822917956601329214766228, - 24333352333740327414230288716985133323391062618552697207636706298003243643 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[23] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 5470771292357224324162037181600593787310803236698332408392365334773005080585, + 3494342642698632792945493330785761039749005378104858604249520700320120879349 + ], + [ + 19636949787553396692208866092658536686505317638394158311560046322207714016321, + 17154689793746496271935789244545520802485941475858327269600346416623923159021 + ] + ); + vk.IC = new Pairing.G1Point[](24); + + vk.IC[0] = Pairing.G1Point( + 18611062343511170357026553953758987681531643503394025314707050482396395666255, + 21871937856609315565490828962524566910389201797830976035654654241259185294189 + ); + + vk.IC[1] = Pairing.G1Point( + 2626850471938876016272250995132059732766702802414678794136113436467701497381, + 15856809560815353250215675532518053108284293527737276069251944177094696612831 + ); + + vk.IC[2] = Pairing.G1Point( + 17149445972624492180406560554997486059080227363063999877151374883685294369167, + 923370209582343483534382902433360877085518011178862782681518488009892052028 + ); + + vk.IC[3] = Pairing.G1Point( + 20417473811553148448619050325254449341381176913153415632705990668648880964082, + 19212842676028502782078905502288513898901775609524694908204599507508359056512 + ); + + vk.IC[4] = Pairing.G1Point( + 3113839248998919148150222311966457667798838587744947227414067830080164495439, + 17599350298379402061066711963207622488966698676898236075850530935406080595355 + ); + + vk.IC[5] = Pairing.G1Point( + 15161933654458687779531138005738701071948822246351767415002403707117254709593, + 4283456777077685653627504970688766667750285278794900008396392917183318189844 + ); + + vk.IC[6] = Pairing.G1Point( + 14783083858372666270392070738487037527332066739312315309127555992780471167892, + 19987096935750677139560540890546967144803812783740042793332962283466560905367 + ); + + vk.IC[7] = Pairing.G1Point( + 2896624934114960471561612808888961000430237704000903604598413400777978522138, + 20863685015972891668404373255113900974340301846718583278325205870259261191221 + ); + + vk.IC[8] = Pairing.G1Point( + 6508340445764958285310639653039019394593107384867849792347263007890734482117, + 19356821758081560488138321972663477016666642851877428394098667268356486543665 + ); + + vk.IC[9] = Pairing.G1Point( + 16388142491063093532693947815829290664145211304802056002760078794768526047841, + 17093442606964487364267161412828723948788786864591060879778342916916281873355 + ); + + vk.IC[10] = Pairing.G1Point( + 21063873767815155348022518442384127489291649486720053943734052788865613453122, + 5757053647888665951846263262066463598769080435404670032554805038676954192976 + ); + + vk.IC[11] = Pairing.G1Point( + 7835709697997100403722492282043383726078532353700579251453524362622755128258, + 13398026612042421924647048351949123170996095802448143488137869573581757767277 + ); + + vk.IC[12] = Pairing.G1Point( + 16905486623626811833650946186914564652495265079775833606574281122133319312510, + 4427027193758025301553694612964889583972267813249871797238570154256349746056 + ); + + vk.IC[13] = Pairing.G1Point( + 10000842517562602959069155718156794808544709834332678159917179926701945774390, + 4938704773073298251056144005210432625250079279710139910301587372734289587663 + ); + + vk.IC[14] = Pairing.G1Point( + 20633394807876201703297996957750972575066996755381011587934686084288053805476, + 13704564904538428141779528316331135999912524274190405323646245869532676333954 + ); + + vk.IC[15] = Pairing.G1Point( + 14443387715676296192674906794544384137311168721188704733523522408724932219752, + 6428088729870240750338580955220436051158180682246281479413611985744717149203 + ); + + vk.IC[16] = Pairing.G1Point( + 13956305720059725136522097658313647870684299367665993695129046258000048965217, + 20225563638691166821878074327855277932767593218972275595102121226540550298950 + ); + + vk.IC[17] = Pairing.G1Point( + 16587738518047281634627910596882357687319266831719360348032787256147500768889, + 20861431405239551971326025727032583540133917147214344185224021812242565453623 + ); + + vk.IC[18] = Pairing.G1Point( + 18340957541386761368230404588626882995488718633543788802532598537693896834249, + 20505757121991843408984353998515449759033993550178326915106374590854632518049 + ); + + vk.IC[19] = Pairing.G1Point( + 18823107582955243296749545767012978506913487366567388961249897410933119158266, + 2540295498873080502738278084748378187334294388859366491553697022944581365683 + ); + + vk.IC[20] = Pairing.G1Point( + 8713435974062649198166277037854849354941613305499674037468202588658393009983, + 6751826882427118872560815217109209602886713988448117071506516767514586509133 + ); + + vk.IC[21] = Pairing.G1Point( + 15555705049575593729216030156045190112934764433714326390183763977750636367151, + 14825433821645698374432221682580079748012262619055046242161314180820722900986 + ); + + vk.IC[22] = Pairing.G1Point( + 13955185291957381082762655488723861296722142172046360205871383587363520827916, + 12054242459929492955672760406108328147348907458023215701419619669424077744084 + ); + + vk.IC[23] = Pairing.G1Point( + 2662864612618040313825745082358546624115513040317168822917956601329214766228, + 24333352333740327414230288716985133323391062618552697207636706298003243643 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[23] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP2_16.sol b/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP2_16.sol index 10a1d8beb..a85e481ca 100644 --- a/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP2_16.sol +++ b/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP2_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } -/* + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,326 +53,383 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierMASP2_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [19180462702074729436866426490959625703231294283974114256513661058757580193492, - 11872716658380852287658085802089352395718671019431737589229157041919732476420], - [13614266533937469101763003288197476173123850471562909773483971664514463761235, - 4709419576381928321377075250496670237061698793603232560101657014694338288906] - ); - vk.IC = new Pairing.G1Point[](25); - - vk.IC[0] = Pairing.G1Point( - 15343344284491743896210224992754499641142537699795745163642548137336848746537, - 7044932874161674155424365563235556793374255996637350694926454115183685117900 - ); - - vk.IC[1] = Pairing.G1Point( - 18122921614512926596747996731219876786945999245171101943622271651935055910739, - 21532681096143411579215810005090413224377169612777118989201060534844395805121 - ); - - vk.IC[2] = Pairing.G1Point( - 15593775557975528928387802551085398439799989790763158486181594527026438746683, - 10541018910877242726520720719929777034703532393742689177726200071507899973761 - ); - - vk.IC[3] = Pairing.G1Point( - 7552381801505719330585000576026942561595242304533526926546775612048762594304, - 7727562369261637869049455116277280965696977048377379378430353492550396742779 - ); - - vk.IC[4] = Pairing.G1Point( - 586909901135242875664940588580483583144371140865508518477909625986749488448, - 21342391789913310392136694321241055008784248422362427304552317852301535039715 - ); - - vk.IC[5] = Pairing.G1Point( - 12031453272505113350204902280413847026745818277330427619416632949907099561177, - 19625925523363700699679824734963454576938619924681169499450180526542340438261 - ); - - vk.IC[6] = Pairing.G1Point( - 14258024005372322658537935326341836427673045528382286292258688824085923497951, - 9422413678605302763494442206158348078240326176521571380879313552928846456362 - ); - - vk.IC[7] = Pairing.G1Point( - 17988191963674578304088145349336316194871229877598929530900954693111195164046, - 19273576222703139570471437007207747500481049142386298517872851718359346361532 - ); - - vk.IC[8] = Pairing.G1Point( - 9016120177394004496242960651611352572242013728700999910005396698409872337160, - 17943495173337349559731285555805557845221250609963597313954948773356947721762 - ); - - vk.IC[9] = Pairing.G1Point( - 833469605386385031660954720350833299379000115142959645222504215680902128309, - 14160571544121820518826824414577812139640451948562689083119450630170923579375 - ); - - vk.IC[10] = Pairing.G1Point( - 16534786220050921593326546756079014555568785721497034218464933372637087749678, - 17688032278244890968757262852501180062013886988593864984697640895968680049636 - ); - - vk.IC[11] = Pairing.G1Point( - 4935065459511975105270131670996256059305064280326612059107265749616727188346, - 21694078147982275686654486143041236552944640570409762190318155637442694946991 - ); - - vk.IC[12] = Pairing.G1Point( - 4975141229936738488521385230313111116162345241735527655782110089604745451899, - 14032712824473083657342149872041223655655462558904353303686364243701915980841 - ); - - vk.IC[13] = Pairing.G1Point( - 8326804671851410475871518943472564054921319522511739757486485129442302861077, - 2962820978650068806054314640809224423157930057801484963193827601178782385096 - ); - - vk.IC[14] = Pairing.G1Point( - 8352508603846624339973740899236390979821280815959846049642696322828396391580, - 4727125801701073854727536632348039559205641742551403649234423593366545372712 - ); - - vk.IC[15] = Pairing.G1Point( - 6513317127500227350048862104399037893059451498098744524368218832223918948107, - 17137043595105924228480352328349208915370272504733626013289937191009893804726 - ); - - vk.IC[16] = Pairing.G1Point( - 3162624093634831006101328494419350596150598161668090847030747181956631637334, - 215524113663406859697608620273681872302602732538663539214002990639859474841 - ); - - vk.IC[17] = Pairing.G1Point( - 1532814133679412606836584378257102743102835707986623002556280336784896927027, - 5507089207706878821010401179000228084258951831092218364563673227675629201500 - ); - - vk.IC[18] = Pairing.G1Point( - 19053188513602985621950192317844293597166205265502333781122636241721539175985, - 12830533657615776899748156265143136925374904986995382757727993689019566441896 - ); - - vk.IC[19] = Pairing.G1Point( - 21613018211484379518285339577180828096044953025229446380441548114158578916673, - 12494523305445231027854540807515532565607677950121009520716523494426175985239 - ); - - vk.IC[20] = Pairing.G1Point( - 16526029509477234422174402104618406309525947908017344363817094513625105132941, - 4728944478088672456601094923728020647308460345327944498030426966930329367588 - ); - - vk.IC[21] = Pairing.G1Point( - 19810829745544574353072063697079836224791757942379963598131199605987154319327, - 12902337886756655386809515898778596837233874384187523970185629308275952462406 - ); - - vk.IC[22] = Pairing.G1Point( - 10649601568203885568648062603636089075413527454982253116182441302990894045560, - 9041432883708426946045378385718605969358940553829739206109056810405457448231 - ); - - vk.IC[23] = Pairing.G1Point( - 3789423282442994149729255932426609296364242420229602392930277094328976660777, - 1377758212534630238371046136447317772272497925566703001464194436145139614228 - ); - - vk.IC[24] = Pairing.G1Point( - 703050616551966465308643417711235207334605003829775405853199296619679000468, - 1580370501823605551002363798955269861916164380295174353920461898063332609487 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[24] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 19180462702074729436866426490959625703231294283974114256513661058757580193492, + 11872716658380852287658085802089352395718671019431737589229157041919732476420 + ], + [ + 13614266533937469101763003288197476173123850471562909773483971664514463761235, + 4709419576381928321377075250496670237061698793603232560101657014694338288906 + ] + ); + vk.IC = new Pairing.G1Point[](25); + + vk.IC[0] = Pairing.G1Point( + 15343344284491743896210224992754499641142537699795745163642548137336848746537, + 7044932874161674155424365563235556793374255996637350694926454115183685117900 + ); + + vk.IC[1] = Pairing.G1Point( + 18122921614512926596747996731219876786945999245171101943622271651935055910739, + 21532681096143411579215810005090413224377169612777118989201060534844395805121 + ); + + vk.IC[2] = Pairing.G1Point( + 15593775557975528928387802551085398439799989790763158486181594527026438746683, + 10541018910877242726520720719929777034703532393742689177726200071507899973761 + ); + + vk.IC[3] = Pairing.G1Point( + 7552381801505719330585000576026942561595242304533526926546775612048762594304, + 7727562369261637869049455116277280965696977048377379378430353492550396742779 + ); + + vk.IC[4] = Pairing.G1Point( + 586909901135242875664940588580483583144371140865508518477909625986749488448, + 21342391789913310392136694321241055008784248422362427304552317852301535039715 + ); + + vk.IC[5] = Pairing.G1Point( + 12031453272505113350204902280413847026745818277330427619416632949907099561177, + 19625925523363700699679824734963454576938619924681169499450180526542340438261 + ); + + vk.IC[6] = Pairing.G1Point( + 14258024005372322658537935326341836427673045528382286292258688824085923497951, + 9422413678605302763494442206158348078240326176521571380879313552928846456362 + ); + + vk.IC[7] = Pairing.G1Point( + 17988191963674578304088145349336316194871229877598929530900954693111195164046, + 19273576222703139570471437007207747500481049142386298517872851718359346361532 + ); + + vk.IC[8] = Pairing.G1Point( + 9016120177394004496242960651611352572242013728700999910005396698409872337160, + 17943495173337349559731285555805557845221250609963597313954948773356947721762 + ); + + vk.IC[9] = Pairing.G1Point( + 833469605386385031660954720350833299379000115142959645222504215680902128309, + 14160571544121820518826824414577812139640451948562689083119450630170923579375 + ); + + vk.IC[10] = Pairing.G1Point( + 16534786220050921593326546756079014555568785721497034218464933372637087749678, + 17688032278244890968757262852501180062013886988593864984697640895968680049636 + ); + + vk.IC[11] = Pairing.G1Point( + 4935065459511975105270131670996256059305064280326612059107265749616727188346, + 21694078147982275686654486143041236552944640570409762190318155637442694946991 + ); + + vk.IC[12] = Pairing.G1Point( + 4975141229936738488521385230313111116162345241735527655782110089604745451899, + 14032712824473083657342149872041223655655462558904353303686364243701915980841 + ); + + vk.IC[13] = Pairing.G1Point( + 8326804671851410475871518943472564054921319522511739757486485129442302861077, + 2962820978650068806054314640809224423157930057801484963193827601178782385096 + ); + + vk.IC[14] = Pairing.G1Point( + 8352508603846624339973740899236390979821280815959846049642696322828396391580, + 4727125801701073854727536632348039559205641742551403649234423593366545372712 + ); + + vk.IC[15] = Pairing.G1Point( + 6513317127500227350048862104399037893059451498098744524368218832223918948107, + 17137043595105924228480352328349208915370272504733626013289937191009893804726 + ); + + vk.IC[16] = Pairing.G1Point( + 3162624093634831006101328494419350596150598161668090847030747181956631637334, + 215524113663406859697608620273681872302602732538663539214002990639859474841 + ); + + vk.IC[17] = Pairing.G1Point( + 1532814133679412606836584378257102743102835707986623002556280336784896927027, + 5507089207706878821010401179000228084258951831092218364563673227675629201500 + ); + + vk.IC[18] = Pairing.G1Point( + 19053188513602985621950192317844293597166205265502333781122636241721539175985, + 12830533657615776899748156265143136925374904986995382757727993689019566441896 + ); + + vk.IC[19] = Pairing.G1Point( + 21613018211484379518285339577180828096044953025229446380441548114158578916673, + 12494523305445231027854540807515532565607677950121009520716523494426175985239 + ); + + vk.IC[20] = Pairing.G1Point( + 16526029509477234422174402104618406309525947908017344363817094513625105132941, + 4728944478088672456601094923728020647308460345327944498030426966930329367588 + ); + + vk.IC[21] = Pairing.G1Point( + 19810829745544574353072063697079836224791757942379963598131199605987154319327, + 12902337886756655386809515898778596837233874384187523970185629308275952462406 + ); + + vk.IC[22] = Pairing.G1Point( + 10649601568203885568648062603636089075413527454982253116182441302990894045560, + 9041432883708426946045378385718605969358940553829739206109056810405457448231 + ); + + vk.IC[23] = Pairing.G1Point( + 3789423282442994149729255932426609296364242420229602392930277094328976660777, + 1377758212534630238371046136447317772272497925566703001464194436145139614228 + ); + + vk.IC[24] = Pairing.G1Point( + 703050616551966465308643417711235207334605003829775405853199296619679000468, + 1580370501823605551002363798955269861916164380295174353920461898063332609487 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[24] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP8_16.sol b/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP8_16.sol index 2ae13eeb9..b9345af17 100644 --- a/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP8_16.sol +++ b/packages/contracts/contracts/verifiers/masp_vanchor_16/VerifierMASP8_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,356 +53,413 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierMASP8_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [10790949692170501432992571555578800115913264668570327419087979778464094934231, - 18402296092508114103359939429238665785771585926503846657326985699641168528552], - [15141170033574420351399642670079410215038884580733779820764237717380435844111, - 11540688333590444159971211523396362793389527107214734561922937642695518144402] - ); - vk.IC = new Pairing.G1Point[](31); - - vk.IC[0] = Pairing.G1Point( - 9361139992222371287406208619768818826009709398960890368138398766629978136094, - 4991194408004489410962733969520860131862494655071144401656423191845778877042 - ); - - vk.IC[1] = Pairing.G1Point( - 13262729788049016839842606753123547122022851693845681418656259949947545088424, - 10058773363460385040827639009154250663772277651086239970703656810150151491283 - ); - - vk.IC[2] = Pairing.G1Point( - 18417450696834510333327679219122199666552974357597889850830080127299776214834, - 21608441946456313111523493751709769358192876621775806636188885244048415762363 - ); - - vk.IC[3] = Pairing.G1Point( - 16959293405837559986340367652440755274937660632289208486596563009235177700789, - 19486964197375296352689355283769514011141124885858834402426867843109909250176 - ); - - vk.IC[4] = Pairing.G1Point( - 4280240120519930855655793415628018703536489232176049126531983269107689095968, - 4600051297560012702931739992634186365428544958102309279785109253107750428118 - ); - - vk.IC[5] = Pairing.G1Point( - 6993143268990143842363634424159718035455631094828599671169116139907241592585, - 18625896264869453662084159630963910831319155423839282737021906315759964319658 - ); - - vk.IC[6] = Pairing.G1Point( - 7285710444848177418789400268683059212777952246418156852181014752981161758429, - 13142978805900648873595170326966328139262924728791502597550192254094830275382 - ); - - vk.IC[7] = Pairing.G1Point( - 18137028035948676019693296522588795227516772728113899007663054244741149957769, - 5577823921797980464336326172943422889457067983835718242772331300678937547289 - ); - - vk.IC[8] = Pairing.G1Point( - 14234940695213366302907353797610765731182304255481043249548995908285396504379, - 19561712223083704081424810946912914316442388556667896986626055489942197178114 - ); - - vk.IC[9] = Pairing.G1Point( - 14996171882698137565361335772574641700417992940526155506351060510193486238527, - 395344635693810611732378185280669670483959106184120817801708324982722085781 - ); - - vk.IC[10] = Pairing.G1Point( - 17700818520856082499902166727197679260322658260462812833573760994705113192647, - 16305742904448233440934711924685887255366501125851807654723015870178524725255 - ); - - vk.IC[11] = Pairing.G1Point( - 13027146255729941627831249148035936911754060637958511164861932188717483380366, - 50692554650911609525725180099997828747714646192192253305035945527706384384 - ); - - vk.IC[12] = Pairing.G1Point( - 5412078680136089272243679606302908272439814122570968657128424122734913114094, - 9681584241595933272953255509373000094767451992503964534397058461618151079015 - ); - - vk.IC[13] = Pairing.G1Point( - 11199805197649223997253372995796085376070007959520560468325195308626151348243, - 21249920260077227188322330473535404191541517116249866100881870254089049731107 - ); - - vk.IC[14] = Pairing.G1Point( - 900459325929594723309270328931993804206072209599706863756618286808495763034, - 8072985795673562068131309426907859324081877832226003333142627780110651325157 - ); - - vk.IC[15] = Pairing.G1Point( - 2622156154406344647394708541881551906189252743194453898254051340067036448220, - 15443777536881747505547781726452442428894267364055645623093940523884037306333 - ); - - vk.IC[16] = Pairing.G1Point( - 16408062593564465619904943017727240445766207176616645457964076294894955751303, - 4058053640898395551632473134592386384568059232867763384894330728888749285955 - ); - - vk.IC[17] = Pairing.G1Point( - 2402880303576131516541439767525628323233365468859200489347472646369595167963, - 1602759785330935416237918155220380681566064945786400382624833381458241475195 - ); - - vk.IC[18] = Pairing.G1Point( - 668001678872475100178757622625451384966260114927571717003358737898748676672, - 20136879078760655426662606491660590486355005715854026808615274087047395880217 - ); - - vk.IC[19] = Pairing.G1Point( - 10291809134463518232349421466800947813230769588627387895115942415336397126473, - 3468759755822788364198946561271953158652557044684923353813915383676987163241 - ); - - vk.IC[20] = Pairing.G1Point( - 3179992380656125231963370633204310949042287099562897512425634465541926563684, - 3380307348527802668451465388168751983904503492094933959836245674985627718888 - ); - - vk.IC[21] = Pairing.G1Point( - 11926043218298537445196574560260228385302576469083258802948024568009125908557, - 12840792390870740533973941900354118733535004949678082480476735842003808946322 - ); - - vk.IC[22] = Pairing.G1Point( - 7261362614572306727907226590097464258878852996125723059362679931322194576802, - 15070089352109298314737767219265214552535662518363126843496588128373192258015 - ); - - vk.IC[23] = Pairing.G1Point( - 8463355924601894742425871931491985706382524507543423075512794373670041907320, - 10842519204868112462792556726545786746569168367446814373911315637311822851525 - ); - - vk.IC[24] = Pairing.G1Point( - 2095703513294499130529991829732638194858912546572512773732263754657146408152, - 4688449145941113654544797953120979495573528529399285791713125270365730037187 - ); - - vk.IC[25] = Pairing.G1Point( - 137761621135334445144891708400975101407347722655680421407948508648960313012, - 13527636856709418835111807092985493617053487964106669298370112385156802469082 - ); - - vk.IC[26] = Pairing.G1Point( - 4771746522936294568688823407999155479907150251953103514086451211882170948144, - 11038859613427488808465541341418310343646240259972930943188731684744372112843 - ); - - vk.IC[27] = Pairing.G1Point( - 1380654713941912541834973570965088543924762497808579062001024182234930067686, - 9942628843193441221117252591884105823786320417146509322815342473403545379494 - ); - - vk.IC[28] = Pairing.G1Point( - 5221464250954132015162676328104614690085846931241323744681196286950049196055, - 17248074819791890110866456488468512315725910970838180204744223357840054500309 - ); - - vk.IC[29] = Pairing.G1Point( - 10305195293566943844412416580978881233855078610414931134230042917561530777274, - 15905331705383550087902090677438972829835292797980309725840764941353581185272 - ); - - vk.IC[30] = Pairing.G1Point( - 18337593239091139831246006230184876296331165871670784672837548307868299168677, - 18253007549941235765547948677682585798051130919450210020320100266105103948894 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[30] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 10790949692170501432992571555578800115913264668570327419087979778464094934231, + 18402296092508114103359939429238665785771585926503846657326985699641168528552 + ], + [ + 15141170033574420351399642670079410215038884580733779820764237717380435844111, + 11540688333590444159971211523396362793389527107214734561922937642695518144402 + ] + ); + vk.IC = new Pairing.G1Point[](31); + + vk.IC[0] = Pairing.G1Point( + 9361139992222371287406208619768818826009709398960890368138398766629978136094, + 4991194408004489410962733969520860131862494655071144401656423191845778877042 + ); + + vk.IC[1] = Pairing.G1Point( + 13262729788049016839842606753123547122022851693845681418656259949947545088424, + 10058773363460385040827639009154250663772277651086239970703656810150151491283 + ); + + vk.IC[2] = Pairing.G1Point( + 18417450696834510333327679219122199666552974357597889850830080127299776214834, + 21608441946456313111523493751709769358192876621775806636188885244048415762363 + ); + + vk.IC[3] = Pairing.G1Point( + 16959293405837559986340367652440755274937660632289208486596563009235177700789, + 19486964197375296352689355283769514011141124885858834402426867843109909250176 + ); + + vk.IC[4] = Pairing.G1Point( + 4280240120519930855655793415628018703536489232176049126531983269107689095968, + 4600051297560012702931739992634186365428544958102309279785109253107750428118 + ); + + vk.IC[5] = Pairing.G1Point( + 6993143268990143842363634424159718035455631094828599671169116139907241592585, + 18625896264869453662084159630963910831319155423839282737021906315759964319658 + ); + + vk.IC[6] = Pairing.G1Point( + 7285710444848177418789400268683059212777952246418156852181014752981161758429, + 13142978805900648873595170326966328139262924728791502597550192254094830275382 + ); + + vk.IC[7] = Pairing.G1Point( + 18137028035948676019693296522588795227516772728113899007663054244741149957769, + 5577823921797980464336326172943422889457067983835718242772331300678937547289 + ); + + vk.IC[8] = Pairing.G1Point( + 14234940695213366302907353797610765731182304255481043249548995908285396504379, + 19561712223083704081424810946912914316442388556667896986626055489942197178114 + ); + + vk.IC[9] = Pairing.G1Point( + 14996171882698137565361335772574641700417992940526155506351060510193486238527, + 395344635693810611732378185280669670483959106184120817801708324982722085781 + ); + + vk.IC[10] = Pairing.G1Point( + 17700818520856082499902166727197679260322658260462812833573760994705113192647, + 16305742904448233440934711924685887255366501125851807654723015870178524725255 + ); + + vk.IC[11] = Pairing.G1Point( + 13027146255729941627831249148035936911754060637958511164861932188717483380366, + 50692554650911609525725180099997828747714646192192253305035945527706384384 + ); + + vk.IC[12] = Pairing.G1Point( + 5412078680136089272243679606302908272439814122570968657128424122734913114094, + 9681584241595933272953255509373000094767451992503964534397058461618151079015 + ); + + vk.IC[13] = Pairing.G1Point( + 11199805197649223997253372995796085376070007959520560468325195308626151348243, + 21249920260077227188322330473535404191541517116249866100881870254089049731107 + ); + + vk.IC[14] = Pairing.G1Point( + 900459325929594723309270328931993804206072209599706863756618286808495763034, + 8072985795673562068131309426907859324081877832226003333142627780110651325157 + ); + + vk.IC[15] = Pairing.G1Point( + 2622156154406344647394708541881551906189252743194453898254051340067036448220, + 15443777536881747505547781726452442428894267364055645623093940523884037306333 + ); + + vk.IC[16] = Pairing.G1Point( + 16408062593564465619904943017727240445766207176616645457964076294894955751303, + 4058053640898395551632473134592386384568059232867763384894330728888749285955 + ); + + vk.IC[17] = Pairing.G1Point( + 2402880303576131516541439767525628323233365468859200489347472646369595167963, + 1602759785330935416237918155220380681566064945786400382624833381458241475195 + ); + + vk.IC[18] = Pairing.G1Point( + 668001678872475100178757622625451384966260114927571717003358737898748676672, + 20136879078760655426662606491660590486355005715854026808615274087047395880217 + ); + + vk.IC[19] = Pairing.G1Point( + 10291809134463518232349421466800947813230769588627387895115942415336397126473, + 3468759755822788364198946561271953158652557044684923353813915383676987163241 + ); + + vk.IC[20] = Pairing.G1Point( + 3179992380656125231963370633204310949042287099562897512425634465541926563684, + 3380307348527802668451465388168751983904503492094933959836245674985627718888 + ); + + vk.IC[21] = Pairing.G1Point( + 11926043218298537445196574560260228385302576469083258802948024568009125908557, + 12840792390870740533973941900354118733535004949678082480476735842003808946322 + ); + + vk.IC[22] = Pairing.G1Point( + 7261362614572306727907226590097464258878852996125723059362679931322194576802, + 15070089352109298314737767219265214552535662518363126843496588128373192258015 + ); + + vk.IC[23] = Pairing.G1Point( + 8463355924601894742425871931491985706382524507543423075512794373670041907320, + 10842519204868112462792556726545786746569168367446814373911315637311822851525 + ); + + vk.IC[24] = Pairing.G1Point( + 2095703513294499130529991829732638194858912546572512773732263754657146408152, + 4688449145941113654544797953120979495573528529399285791713125270365730037187 + ); + + vk.IC[25] = Pairing.G1Point( + 137761621135334445144891708400975101407347722655680421407948508648960313012, + 13527636856709418835111807092985493617053487964106669298370112385156802469082 + ); + + vk.IC[26] = Pairing.G1Point( + 4771746522936294568688823407999155479907150251953103514086451211882170948144, + 11038859613427488808465541341418310343646240259972930943188731684744372112843 + ); + + vk.IC[27] = Pairing.G1Point( + 1380654713941912541834973570965088543924762497808579062001024182234930067686, + 9942628843193441221117252591884105823786320417146509322815342473403545379494 + ); + + vk.IC[28] = Pairing.G1Point( + 5221464250954132015162676328104614690085846931241323744681196286950049196055, + 17248074819791890110866456488468512315725910970838180204744223357840054500309 + ); + + vk.IC[29] = Pairing.G1Point( + 10305195293566943844412416580978881233855078610414931134230042917561530777274, + 15905331705383550087902090677438972829835292797980309725840764941353581185272 + ); + + vk.IC[30] = Pairing.G1Point( + 18337593239091139831246006230184876296331165871670784672837548307868299168677, + 18253007549941235765547948677682585798051130919450210020320100266105103948894 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[30] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP2_2.sol b/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP2_2.sol index 094f6c2a1..9048dfce9 100644 --- a/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP2_2.sol +++ b/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP2_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,256 +53,313 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierMASP2_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [10159958606039057447457238545790108967891254746694768329564788172523675511744, - 2634919097621550006580275467974415172701863544109339036789982409178327793561], - [9122252848365009061634837899183452169909487595645635843763296583964206428467, - 6861681806912280102504971031598863996481499274538430492248090320676791078644] - ); - vk.IC = new Pairing.G1Point[](11); - - vk.IC[0] = Pairing.G1Point( - 16205375052757936426835450562112550355007870415956590361828206053286472978688, - 7805362994730843319938059231343299801872415005204375113877619468861744026923 - ); - - vk.IC[1] = Pairing.G1Point( - 748464326037094676165220232504937385524979046924041143466610580632046746231, - 5301542965072933111111981753887665375533632394751794536392106171176661085172 - ); - - vk.IC[2] = Pairing.G1Point( - 11837635892063267149126837623469601330429388498845799571237760739452160967391, - 9327584920986298594323935222630556570853161109010273805115415411411660434946 - ); - - vk.IC[3] = Pairing.G1Point( - 16144729794598778771664347916464692557534760608064124744489336636990097272128, - 17624087878847957706378819910277864401849342925336762872934044441153383418739 - ); - - vk.IC[4] = Pairing.G1Point( - 15745623948180643575803428266306200157739026237019278610483474431159235807516, - 16620058276720953464977896702836116193733345936810081839019983721931769185455 - ); - - vk.IC[5] = Pairing.G1Point( - 16938904872491417848352509634661722646253779069428915476212279030400205046528, - 20921008118688014742166247422020366617991074732512027587491885887482853819940 - ); - - vk.IC[6] = Pairing.G1Point( - 16150263348073771536644940636053727935899003388729811868516466486375518173634, - 13275019735794911597554321098400576155151993309520923926248988089428750494035 - ); - - vk.IC[7] = Pairing.G1Point( - 13280904354071792033833271721458518212320663493502952944274896069922100113635, - 1627704202791768849223639152529508875453051464170692967138746126274083592771 - ); - - vk.IC[8] = Pairing.G1Point( - 820434474475449723522793253571244767873683642269180917476303708050442234460, - 3005897978866631523868942136853395164058745504576106498466068187707257632511 - ); - - vk.IC[9] = Pairing.G1Point( - 7847220964382890782062202981695794018752060689472524256055586287871849377225, - 18042210191976434414637310423649535413586502893944894077865185801005227382751 - ); - - vk.IC[10] = Pairing.G1Point( - 7198595535818727591073196620316637255880456065121564068013581603068383856522, - 13433851487990282320984528415444011174454081098212567578460222880236909755660 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[10] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 10159958606039057447457238545790108967891254746694768329564788172523675511744, + 2634919097621550006580275467974415172701863544109339036789982409178327793561 + ], + [ + 9122252848365009061634837899183452169909487595645635843763296583964206428467, + 6861681806912280102504971031598863996481499274538430492248090320676791078644 + ] + ); + vk.IC = new Pairing.G1Point[](11); + + vk.IC[0] = Pairing.G1Point( + 16205375052757936426835450562112550355007870415956590361828206053286472978688, + 7805362994730843319938059231343299801872415005204375113877619468861744026923 + ); + + vk.IC[1] = Pairing.G1Point( + 748464326037094676165220232504937385524979046924041143466610580632046746231, + 5301542965072933111111981753887665375533632394751794536392106171176661085172 + ); + + vk.IC[2] = Pairing.G1Point( + 11837635892063267149126837623469601330429388498845799571237760739452160967391, + 9327584920986298594323935222630556570853161109010273805115415411411660434946 + ); + + vk.IC[3] = Pairing.G1Point( + 16144729794598778771664347916464692557534760608064124744489336636990097272128, + 17624087878847957706378819910277864401849342925336762872934044441153383418739 + ); + + vk.IC[4] = Pairing.G1Point( + 15745623948180643575803428266306200157739026237019278610483474431159235807516, + 16620058276720953464977896702836116193733345936810081839019983721931769185455 + ); + + vk.IC[5] = Pairing.G1Point( + 16938904872491417848352509634661722646253779069428915476212279030400205046528, + 20921008118688014742166247422020366617991074732512027587491885887482853819940 + ); + + vk.IC[6] = Pairing.G1Point( + 16150263348073771536644940636053727935899003388729811868516466486375518173634, + 13275019735794911597554321098400576155151993309520923926248988089428750494035 + ); + + vk.IC[7] = Pairing.G1Point( + 13280904354071792033833271721458518212320663493502952944274896069922100113635, + 1627704202791768849223639152529508875453051464170692967138746126274083592771 + ); + + vk.IC[8] = Pairing.G1Point( + 820434474475449723522793253571244767873683642269180917476303708050442234460, + 3005897978866631523868942136853395164058745504576106498466068187707257632511 + ); + + vk.IC[9] = Pairing.G1Point( + 7847220964382890782062202981695794018752060689472524256055586287871849377225, + 18042210191976434414637310423649535413586502893944894077865185801005227382751 + ); + + vk.IC[10] = Pairing.G1Point( + 7198595535818727591073196620316637255880456065121564068013581603068383856522, + 13433851487990282320984528415444011174454081098212567578460222880236909755660 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[10] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP8_2.sol b/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP8_2.sol index 2361c0d33..d6850f31b 100644 --- a/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP8_2.sol +++ b/packages/contracts/contracts/verifiers/masp_vanchor_2/VerifierMASP8_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); -/* + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,286 +53,343 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierMASP8_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [17055826447087146731405041612276707866998363626015013665718032922949960783352, - 877658602495440374261015558617894670429776092371861910837695994581082322539], - [6606718409012307792237687813386590484545976534779453481303610582523126119593, - 14983118693957398826671974167075514898369540487202232519880809049141912048377] - ); - vk.IC = new Pairing.G1Point[](17); - - vk.IC[0] = Pairing.G1Point( - 15372065424978751013024375272647224860439021770939846446677691607479552530910, - 14792919840880875549427197661859137960262890039895684087124296701568953118374 - ); - - vk.IC[1] = Pairing.G1Point( - 5009864503174455001405574894163644729878940527557491331294870395258785003180, - 5584709361328832775223961802231653860589662172559357833432730463725527851920 - ); - - vk.IC[2] = Pairing.G1Point( - 9361983020699115770263529139006626763653567304821525195283396691532433086237, - 9977862709592117323509470735863494115576102330154939526956058238076857154669 - ); - - vk.IC[3] = Pairing.G1Point( - 1309108996607635425661717093773562115895358482894253873240914169201332603823, - 4558410773080625233534597170992455871938561209855318015017123899545199979209 - ); - - vk.IC[4] = Pairing.G1Point( - 162687339154199112094195960670716935419785934629588811011871127669978255346, - 21453201846969353024990732146338450260293798037960563810841324882954112438808 - ); - - vk.IC[5] = Pairing.G1Point( - 15896390986939278752040033322756382210594559732247484302670439247967108886267, - 13896917024207690028968034227257351107055367566376653082476051214911064968231 - ); - - vk.IC[6] = Pairing.G1Point( - 7359043449430603592264269049201855253268711096917388595445617548719983403351, - 4208527691689830166328581040629019534451277776208920885635809775122141647281 - ); - - vk.IC[7] = Pairing.G1Point( - 6094666972908865763711525942494895835931350308152054256091077271975469659806, - 2882351827117506578939541547485523161326625095336908048097867047573032241698 - ); - - vk.IC[8] = Pairing.G1Point( - 12767377838917523148341256643913895732171086961664611309336465954252627056644, - 11175996209212952500273997204348726077051508586065638461763937698048087190578 - ); - - vk.IC[9] = Pairing.G1Point( - 7796824610830556686451015617230004706291625921204612795885314384276565670221, - 8696880280420507009446096812384012180175306807703303364425980333415876729156 - ); - - vk.IC[10] = Pairing.G1Point( - 14058627368543813815612218639715786644115978922603547948062919924330843459916, - 11335895205206512459850940743905008115839981401122633915036822902569045192660 - ); - - vk.IC[11] = Pairing.G1Point( - 8020657644445742634096241377228623442556050830137935615905132453926892762558, - 10905094440376181500774217102376887367019055348274198850786887287961287206169 - ); - - vk.IC[12] = Pairing.G1Point( - 4080799340256098228927691569132208882321194493219580220410415823074253862735, - 1913919771711961792682866784755844975998316462734868605733691128488506408802 - ); - - vk.IC[13] = Pairing.G1Point( - 19239022850043026867410595513654462578671533126696492796489181857375571025875, - 1733832617472449490431645161871229893384659069931495793413006038453569328860 - ); - - vk.IC[14] = Pairing.G1Point( - 18610499142318330348842907152041890368833454997802733994579958549574390665964, - 2820309986512404992951889309975012015454219316422964768567933683838804049622 - ); - - vk.IC[15] = Pairing.G1Point( - 1878419331806618372293455084313751193633896824860615108117314296132916464837, - 8159647087997275958901293454745511272287734424130857960932713894705024062140 - ); - - vk.IC[16] = Pairing.G1Point( - 1191495737020464380586229026305988745108210931499035652019994132587659309264, - 7293366852852276282332806179364662083866519013125409845513533763752425219139 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[16] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 17055826447087146731405041612276707866998363626015013665718032922949960783352, + 877658602495440374261015558617894670429776092371861910837695994581082322539 + ], + [ + 6606718409012307792237687813386590484545976534779453481303610582523126119593, + 14983118693957398826671974167075514898369540487202232519880809049141912048377 + ] + ); + vk.IC = new Pairing.G1Point[](17); + + vk.IC[0] = Pairing.G1Point( + 15372065424978751013024375272647224860439021770939846446677691607479552530910, + 14792919840880875549427197661859137960262890039895684087124296701568953118374 + ); + + vk.IC[1] = Pairing.G1Point( + 5009864503174455001405574894163644729878940527557491331294870395258785003180, + 5584709361328832775223961802231653860589662172559357833432730463725527851920 + ); + + vk.IC[2] = Pairing.G1Point( + 9361983020699115770263529139006626763653567304821525195283396691532433086237, + 9977862709592117323509470735863494115576102330154939526956058238076857154669 + ); + + vk.IC[3] = Pairing.G1Point( + 1309108996607635425661717093773562115895358482894253873240914169201332603823, + 4558410773080625233534597170992455871938561209855318015017123899545199979209 + ); + + vk.IC[4] = Pairing.G1Point( + 162687339154199112094195960670716935419785934629588811011871127669978255346, + 21453201846969353024990732146338450260293798037960563810841324882954112438808 + ); + + vk.IC[5] = Pairing.G1Point( + 15896390986939278752040033322756382210594559732247484302670439247967108886267, + 13896917024207690028968034227257351107055367566376653082476051214911064968231 + ); + + vk.IC[6] = Pairing.G1Point( + 7359043449430603592264269049201855253268711096917388595445617548719983403351, + 4208527691689830166328581040629019534451277776208920885635809775122141647281 + ); + + vk.IC[7] = Pairing.G1Point( + 6094666972908865763711525942494895835931350308152054256091077271975469659806, + 2882351827117506578939541547485523161326625095336908048097867047573032241698 + ); + + vk.IC[8] = Pairing.G1Point( + 12767377838917523148341256643913895732171086961664611309336465954252627056644, + 11175996209212952500273997204348726077051508586065638461763937698048087190578 + ); + + vk.IC[9] = Pairing.G1Point( + 7796824610830556686451015617230004706291625921204612795885314384276565670221, + 8696880280420507009446096812384012180175306807703303364425980333415876729156 + ); + + vk.IC[10] = Pairing.G1Point( + 14058627368543813815612218639715786644115978922603547948062919924330843459916, + 11335895205206512459850940743905008115839981401122633915036822902569045192660 + ); + + vk.IC[11] = Pairing.G1Point( + 8020657644445742634096241377228623442556050830137935615905132453926892762558, + 10905094440376181500774217102376887367019055348274198850786887287961287206169 + ); + + vk.IC[12] = Pairing.G1Point( + 4080799340256098228927691569132208882321194493219580220410415823074253862735, + 1913919771711961792682866784755844975998316462734868605733691128488506408802 + ); + + vk.IC[13] = Pairing.G1Point( + 19239022850043026867410595513654462578671533126696492796489181857375571025875, + 1733832617472449490431645161871229893384659069931495793413006038453569328860 + ); + + vk.IC[14] = Pairing.G1Point( + 18610499142318330348842907152041890368833454997802733994579958549574390665964, + 2820309986512404992951889309975012015454219316422964768567933683838804049622 + ); + + vk.IC[15] = Pairing.G1Point( + 1878419331806618372293455084313751193633896824860615108117314296132916464837, + 8159647087997275958901293454745511272287734424130857960932713894705024062140 + ); + + vk.IC[16] = Pairing.G1Point( + 1191495737020464380586229026305988745108210931499035652019994132587659309264, + 7293366852852276282332806179364662083866519013125409845513533763752425219139 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[16] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_16/Verifier2_16.sol b/packages/contracts/contracts/verifiers/vanchor_16/Verifier2_16.sol index 29a639c6c..70ec816a8 100644 --- a/packages/contracts/contracts/verifiers/vanchor_16/Verifier2_16.sol +++ b/packages/contracts/contracts/verifiers/vanchor_16/Verifier2_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } -/* + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,321 +53,378 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier2_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [6135275490561704281641768100871882031636787897821494851889237343812159201470, - 4352419702060053761754088042436595107259930199282090477059397569316728807300], - [11647931451530612993471737688336035497678746844947094152135992332982707892335, - 7202201863359038351798056260817144902652470955371947690551739148772751871018] - ); - vk.IC = new Pairing.G1Point[](24); - - vk.IC[0] = Pairing.G1Point( - 18481268487153754348465391643372088782494364641004266881805072433434291864922, - 2392837291795392078034427383372840849112984369177256480949924258155696817742 - ); - - vk.IC[1] = Pairing.G1Point( - 4511608921533856518188342967539915448743766074890022625995347642188520376207, - 10080409264036392748329888311455704841256069147428558175234319269821311554654 - ); - - vk.IC[2] = Pairing.G1Point( - 5785944718791183385885977836608202831101162445427999352115468229643342801611, - 9314309836304297002630796985988892779588482774750530368844482667155867561171 - ); - - vk.IC[3] = Pairing.G1Point( - 5915415365864833976113611443265633577016065766993827554429120614390947943369, - 12464069075931422155959082829109638281776996909471173378452414040132419843322 - ); - - vk.IC[4] = Pairing.G1Point( - 14954991951119199592182035542860681901841003633921296096576709305436976267021, - 17412715473066159696534241225813184499979118511140203502980693993868736318178 - ); - - vk.IC[5] = Pairing.G1Point( - 5017397525820733081352715201202174079011833410121776448616709405337784776391, - 10708900100056480956794717197191545435550865736835028835883627394458034919072 - ); - - vk.IC[6] = Pairing.G1Point( - 15693705374092784485749041213237243315958604834854044236442171037946879551330, - 1274740880340669874270619440926125852848652648222820897503265301336085944765 - ); - - vk.IC[7] = Pairing.G1Point( - 4830312491272269751969090272318215339946047783788316956140450370194376942633, - 2364483128414802579024168366373334852874621135338347341425587383122837742909 - ); - - vk.IC[8] = Pairing.G1Point( - 4341330212309877039801986302994549494585763564844029366769391689804207075017, - 14808039164886177973520236185617769992245789695748079244742017707193665488909 - ); - - vk.IC[9] = Pairing.G1Point( - 21246713748324811563646405867356518093990754472337610021146967803466744518869, - 11375685806872900171964658380829011988838099148985164044123125764998857236865 - ); - - vk.IC[10] = Pairing.G1Point( - 10425875368786742614663867602950808206417716656723443400779068213401945435086, - 3630246760878384799882646445178910294488088373003971582166542745572558861407 - ); - - vk.IC[11] = Pairing.G1Point( - 6553315986850504721332670961099781702020643519008937284606333677655639748563, - 8396767501740261405314033398690082323347192657200213264011983387753424262943 - ); - - vk.IC[12] = Pairing.G1Point( - 16258135015273806338335465757513260077643410335645516121846742217091335989505, - 13784441077544058486890156278332645538604218924995194446930550857770274113111 - ); - - vk.IC[13] = Pairing.G1Point( - 12293138913242770088631393318804280019350601923514587751409375497539147502329, - 12276034830900042942665746808394110488012771945203000213309389445139586218003 - ); - - vk.IC[14] = Pairing.G1Point( - 15329043677908325513528185368282649925359195168671719111344819154933015958952, - 15735517887740763543427948290960876627299936895499363650834566520053067982920 - ); - - vk.IC[15] = Pairing.G1Point( - 1525796633278450185011910123942556097062474202987051897861669625276935050243, - 940432000404014341436585384963861838228176917428596973996732831922686476923 - ); - - vk.IC[16] = Pairing.G1Point( - 17573369255163820484079029925637719186387775076215343873899275712692939460638, - 10936971462962309626106238709077908951299038355388865230602371387595442584743 - ); - - vk.IC[17] = Pairing.G1Point( - 364016731910596411154791776721392932406733729237268436286867984576046090712, - 17520847958504868331538456974998655472558164098118198598433599601872974098957 - ); - - vk.IC[18] = Pairing.G1Point( - 19007567193264889029336214115763935305903154885097258007817149362900967308551, - 5206000435186805396271499277406751590260715867320142970292181961602415578321 - ); - - vk.IC[19] = Pairing.G1Point( - 18328086335235898970864247477628478672487246009159957723229382521193079749138, - 14903344434047900717081935479870307462601380233233651111278842683363612257162 - ); - - vk.IC[20] = Pairing.G1Point( - 18264620957247254677713113103089683059146760268459895432905072524442448228445, - 7756961996063837314260029503332056308149453503239272383129990774399213580743 - ); - - vk.IC[21] = Pairing.G1Point( - 146200724107134576983407875694590259944105187131268772144196133043727242788, - 6351011991406573648374881208900648956826909959760831810414877026988247002980 - ); - - vk.IC[22] = Pairing.G1Point( - 14479754959739023633445362898987608116102436716792986988720012181815127854528, - 17957677120605693066796639064253427462629411452641259915402949783639432384036 - ); - - vk.IC[23] = Pairing.G1Point( - 13100482703952677724510053958576445720906063934033927337535849144335934376578, - 13510281352111804752424102177081887511153227500831886298717494748628104993663 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[23] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 6135275490561704281641768100871882031636787897821494851889237343812159201470, + 4352419702060053761754088042436595107259930199282090477059397569316728807300 + ], + [ + 11647931451530612993471737688336035497678746844947094152135992332982707892335, + 7202201863359038351798056260817144902652470955371947690551739148772751871018 + ] + ); + vk.IC = new Pairing.G1Point[](24); + + vk.IC[0] = Pairing.G1Point( + 18481268487153754348465391643372088782494364641004266881805072433434291864922, + 2392837291795392078034427383372840849112984369177256480949924258155696817742 + ); + + vk.IC[1] = Pairing.G1Point( + 4511608921533856518188342967539915448743766074890022625995347642188520376207, + 10080409264036392748329888311455704841256069147428558175234319269821311554654 + ); + + vk.IC[2] = Pairing.G1Point( + 5785944718791183385885977836608202831101162445427999352115468229643342801611, + 9314309836304297002630796985988892779588482774750530368844482667155867561171 + ); + + vk.IC[3] = Pairing.G1Point( + 5915415365864833976113611443265633577016065766993827554429120614390947943369, + 12464069075931422155959082829109638281776996909471173378452414040132419843322 + ); + + vk.IC[4] = Pairing.G1Point( + 14954991951119199592182035542860681901841003633921296096576709305436976267021, + 17412715473066159696534241225813184499979118511140203502980693993868736318178 + ); + + vk.IC[5] = Pairing.G1Point( + 5017397525820733081352715201202174079011833410121776448616709405337784776391, + 10708900100056480956794717197191545435550865736835028835883627394458034919072 + ); + + vk.IC[6] = Pairing.G1Point( + 15693705374092784485749041213237243315958604834854044236442171037946879551330, + 1274740880340669874270619440926125852848652648222820897503265301336085944765 + ); + + vk.IC[7] = Pairing.G1Point( + 4830312491272269751969090272318215339946047783788316956140450370194376942633, + 2364483128414802579024168366373334852874621135338347341425587383122837742909 + ); + + vk.IC[8] = Pairing.G1Point( + 4341330212309877039801986302994549494585763564844029366769391689804207075017, + 14808039164886177973520236185617769992245789695748079244742017707193665488909 + ); + + vk.IC[9] = Pairing.G1Point( + 21246713748324811563646405867356518093990754472337610021146967803466744518869, + 11375685806872900171964658380829011988838099148985164044123125764998857236865 + ); + + vk.IC[10] = Pairing.G1Point( + 10425875368786742614663867602950808206417716656723443400779068213401945435086, + 3630246760878384799882646445178910294488088373003971582166542745572558861407 + ); + + vk.IC[11] = Pairing.G1Point( + 6553315986850504721332670961099781702020643519008937284606333677655639748563, + 8396767501740261405314033398690082323347192657200213264011983387753424262943 + ); + + vk.IC[12] = Pairing.G1Point( + 16258135015273806338335465757513260077643410335645516121846742217091335989505, + 13784441077544058486890156278332645538604218924995194446930550857770274113111 + ); + + vk.IC[13] = Pairing.G1Point( + 12293138913242770088631393318804280019350601923514587751409375497539147502329, + 12276034830900042942665746808394110488012771945203000213309389445139586218003 + ); + + vk.IC[14] = Pairing.G1Point( + 15329043677908325513528185368282649925359195168671719111344819154933015958952, + 15735517887740763543427948290960876627299936895499363650834566520053067982920 + ); + + vk.IC[15] = Pairing.G1Point( + 1525796633278450185011910123942556097062474202987051897861669625276935050243, + 940432000404014341436585384963861838228176917428596973996732831922686476923 + ); + + vk.IC[16] = Pairing.G1Point( + 17573369255163820484079029925637719186387775076215343873899275712692939460638, + 10936971462962309626106238709077908951299038355388865230602371387595442584743 + ); + + vk.IC[17] = Pairing.G1Point( + 364016731910596411154791776721392932406733729237268436286867984576046090712, + 17520847958504868331538456974998655472558164098118198598433599601872974098957 + ); + + vk.IC[18] = Pairing.G1Point( + 19007567193264889029336214115763935305903154885097258007817149362900967308551, + 5206000435186805396271499277406751590260715867320142970292181961602415578321 + ); + + vk.IC[19] = Pairing.G1Point( + 18328086335235898970864247477628478672487246009159957723229382521193079749138, + 14903344434047900717081935479870307462601380233233651111278842683363612257162 + ); + + vk.IC[20] = Pairing.G1Point( + 18264620957247254677713113103089683059146760268459895432905072524442448228445, + 7756961996063837314260029503332056308149453503239272383129990774399213580743 + ); + + vk.IC[21] = Pairing.G1Point( + 146200724107134576983407875694590259944105187131268772144196133043727242788, + 6351011991406573648374881208900648956826909959760831810414877026988247002980 + ); + + vk.IC[22] = Pairing.G1Point( + 14479754959739023633445362898987608116102436716792986988720012181815127854528, + 17957677120605693066796639064253427462629411452641259915402949783639432384036 + ); + + vk.IC[23] = Pairing.G1Point( + 13100482703952677724510053958576445720906063934033927337535849144335934376578, + 13510281352111804752424102177081887511153227500831886298717494748628104993663 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[23] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_16/Verifier8_16.sol b/packages/contracts/contracts/verifiers/vanchor_16/Verifier8_16.sol index 054663981..9621cea4b 100644 --- a/packages/contracts/contracts/verifiers/vanchor_16/Verifier8_16.sol +++ b/packages/contracts/contracts/verifiers/vanchor_16/Verifier8_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,351 +53,408 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier8_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [13017550493988466644306535285042476596582308864000718572429926659337487008062, - 14856771105816615091993080706209542200744809750803377545729753492136173010068], - [1639757951335352444590703903266257208546445317157378838233778249245005443451, - 8228846489198793726728612873341866744152889515407866702874987683690350320785] - ); - vk.IC = new Pairing.G1Point[](30); - - vk.IC[0] = Pairing.G1Point( - 11534482493478758346886554192618238784883448248883037109296878007318870886114, - 3021578327008362591781717827042852569151198189937907073815431819190117333459 - ); - - vk.IC[1] = Pairing.G1Point( - 8437006433191134090933539257090916563966460686730952344054105933289780705986, - 14076630508405657688854819167174110408338608435514504307755468016721152419221 - ); - - vk.IC[2] = Pairing.G1Point( - 19481809003329402566511184920311426387342895327645894163133459779757861726452, - 10606712050466163180737273542956159200123134513589970534757669384578864652957 - ); - - vk.IC[3] = Pairing.G1Point( - 11283441978498122568323495341370819860975737168789248530039711500814988964800, - 3766443652612214546438091906065529856800857407595318103380049491431189797181 - ); - - vk.IC[4] = Pairing.G1Point( - 21112151485599195426045781966421449151369181964964542278406175427850878773365, - 18805183651169444283499450297667267630309541295308575863953965504469085588273 - ); - - vk.IC[5] = Pairing.G1Point( - 17980756450348850804014332324918645640723886359771728401792336918234788987116, - 11178296895366011939141046753944738530309280026395100628865360829550758483779 - ); - - vk.IC[6] = Pairing.G1Point( - 2674573573303597030781072813022637979312197245689162447173717997112314107936, - 18088887041445460180588786672830028207586969228127644472621239825727690726299 - ); - - vk.IC[7] = Pairing.G1Point( - 15096872362619907490956168714510793373532548489941482012772520136074880071630, - 13663124255644696589055702579665927211258943740636471819124814582898252617405 - ); - - vk.IC[8] = Pairing.G1Point( - 16852599010242070414183180556317919017761549942479907396045898672480199541390, - 2201265772370876998647824383610628519217078377451444483021323306085768152150 - ); - - vk.IC[9] = Pairing.G1Point( - 17983843086967802232657071976026270105140875471302106433304487216483620986278, - 6437742068149576480628019629981247558323706189228959102130473687376868963102 - ); - - vk.IC[10] = Pairing.G1Point( - 9814205576634535845524951960002811251579121725422762438308314894435509078558, - 2649853708475777964179826849491606940685201037245793103660657754500643918434 - ); - - vk.IC[11] = Pairing.G1Point( - 12503003047352397324660418137403195929701273716104674366647012296390184780806, - 17563975225346708351379891921375128255820226656406158352119680438965606467378 - ); - - vk.IC[12] = Pairing.G1Point( - 8095166215758711731690495895079081889375860847278822228614204225415633694621, - 20371203423792737510793555197148435583774549342234457303148593390777266332953 - ); - - vk.IC[13] = Pairing.G1Point( - 18750538343391941018457728942005196699059741541188724157116020101439095962548, - 21367160466217949887579169013694874009276618350686490303153755525515467893863 - ); - - vk.IC[14] = Pairing.G1Point( - 13189451441287887192358039158409298806828260719731486012239552391970906005488, - 984351270492770849203444597324526654654761000778398371082635710687726435283 - ); - - vk.IC[15] = Pairing.G1Point( - 14236643271647365776249327280172453623880710593928809134569691653988707781058, - 18379313406053387558859780176174758437563425800495313528391998533788572166982 - ); - - vk.IC[16] = Pairing.G1Point( - 14885882306758798937679394610772138922556123227880385870344808873436814022930, - 3934873393257063133916075434168945234055631293765592292343901673375181552269 - ); - - vk.IC[17] = Pairing.G1Point( - 20852410337525408428992795899695004554330381739936516870441901299905205279256, - 20648432346885856575420078255725230748619702397387201087589450468340771874297 - ); - - vk.IC[18] = Pairing.G1Point( - 6167699461166003748566567594747289131674547000150454009904996589304626584167, - 14110003077488418487783057098556325603292353141295332863985055993945398206528 - ); - - vk.IC[19] = Pairing.G1Point( - 20892317574252659735090624277245258193082807848049224448955777134073345685108, - 17727848959971681921713809931721849771484313017968391732789870806782840679927 - ); - - vk.IC[20] = Pairing.G1Point( - 20612376222610731408990545559739965790917945837965228469728226036495441146036, - 20351143376878226978145381965490573601268154635222697512049461276320828895668 - ); - - vk.IC[21] = Pairing.G1Point( - 20522947517427072557578167925733739815026195252456061540822404306528133008950, - 6036034786533315595464011703289331465287433898610658104234001410127390275895 - ); - - vk.IC[22] = Pairing.G1Point( - 20410796723096686566641699882879596519818754353289647070493357891405051737549, - 13189125262776114153651642489071019957668901126196870035821651431860467422633 - ); - - vk.IC[23] = Pairing.G1Point( - 3146788100852253288066278206133464680402002171505031301031229329226719437043, - 10396715094779767544731813785877872331726145317387352477574918383699931707909 - ); - - vk.IC[24] = Pairing.G1Point( - 21439687928968958399465185756652639162478589285565752006575911526852009438130, - 7297135059223284256740384214554937800272136142055798242764527036404583557135 - ); - - vk.IC[25] = Pairing.G1Point( - 12371325521158807364116536202166634842652368662231086806709494938994904680364, - 13133220971573998953122116499486922534369651074468739893016021893214504285030 - ); - - vk.IC[26] = Pairing.G1Point( - 21516003372014895147156904238565871466006669740508136449703899324711326195467, - 16278744532999316901560028522840185484837939454171671064194197332363447266974 - ); - - vk.IC[27] = Pairing.G1Point( - 5912019115796213199781760116500241215410486247272843508998060723047993766740, - 12312071263749771417514700530216961108776744423975472983260514323185579798281 - ); - - vk.IC[28] = Pairing.G1Point( - 20446140985339560388808125805050522681828992995015649353631750743722843544033, - 12985063191741477329911930314893245225347903321658616477211126417641819425305 - ); - - vk.IC[29] = Pairing.G1Point( - 7574545305046950711320318712229623062744829304153153967356279538993555666824, - 8122817517496954688328220645343524414698571600813771393507204249091215144851 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[29] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 13017550493988466644306535285042476596582308864000718572429926659337487008062, + 14856771105816615091993080706209542200744809750803377545729753492136173010068 + ], + [ + 1639757951335352444590703903266257208546445317157378838233778249245005443451, + 8228846489198793726728612873341866744152889515407866702874987683690350320785 + ] + ); + vk.IC = new Pairing.G1Point[](30); + + vk.IC[0] = Pairing.G1Point( + 11534482493478758346886554192618238784883448248883037109296878007318870886114, + 3021578327008362591781717827042852569151198189937907073815431819190117333459 + ); + + vk.IC[1] = Pairing.G1Point( + 8437006433191134090933539257090916563966460686730952344054105933289780705986, + 14076630508405657688854819167174110408338608435514504307755468016721152419221 + ); + + vk.IC[2] = Pairing.G1Point( + 19481809003329402566511184920311426387342895327645894163133459779757861726452, + 10606712050466163180737273542956159200123134513589970534757669384578864652957 + ); + + vk.IC[3] = Pairing.G1Point( + 11283441978498122568323495341370819860975737168789248530039711500814988964800, + 3766443652612214546438091906065529856800857407595318103380049491431189797181 + ); + + vk.IC[4] = Pairing.G1Point( + 21112151485599195426045781966421449151369181964964542278406175427850878773365, + 18805183651169444283499450297667267630309541295308575863953965504469085588273 + ); + + vk.IC[5] = Pairing.G1Point( + 17980756450348850804014332324918645640723886359771728401792336918234788987116, + 11178296895366011939141046753944738530309280026395100628865360829550758483779 + ); + + vk.IC[6] = Pairing.G1Point( + 2674573573303597030781072813022637979312197245689162447173717997112314107936, + 18088887041445460180588786672830028207586969228127644472621239825727690726299 + ); + + vk.IC[7] = Pairing.G1Point( + 15096872362619907490956168714510793373532548489941482012772520136074880071630, + 13663124255644696589055702579665927211258943740636471819124814582898252617405 + ); + + vk.IC[8] = Pairing.G1Point( + 16852599010242070414183180556317919017761549942479907396045898672480199541390, + 2201265772370876998647824383610628519217078377451444483021323306085768152150 + ); + + vk.IC[9] = Pairing.G1Point( + 17983843086967802232657071976026270105140875471302106433304487216483620986278, + 6437742068149576480628019629981247558323706189228959102130473687376868963102 + ); + + vk.IC[10] = Pairing.G1Point( + 9814205576634535845524951960002811251579121725422762438308314894435509078558, + 2649853708475777964179826849491606940685201037245793103660657754500643918434 + ); + + vk.IC[11] = Pairing.G1Point( + 12503003047352397324660418137403195929701273716104674366647012296390184780806, + 17563975225346708351379891921375128255820226656406158352119680438965606467378 + ); + + vk.IC[12] = Pairing.G1Point( + 8095166215758711731690495895079081889375860847278822228614204225415633694621, + 20371203423792737510793555197148435583774549342234457303148593390777266332953 + ); + + vk.IC[13] = Pairing.G1Point( + 18750538343391941018457728942005196699059741541188724157116020101439095962548, + 21367160466217949887579169013694874009276618350686490303153755525515467893863 + ); + + vk.IC[14] = Pairing.G1Point( + 13189451441287887192358039158409298806828260719731486012239552391970906005488, + 984351270492770849203444597324526654654761000778398371082635710687726435283 + ); + + vk.IC[15] = Pairing.G1Point( + 14236643271647365776249327280172453623880710593928809134569691653988707781058, + 18379313406053387558859780176174758437563425800495313528391998533788572166982 + ); + + vk.IC[16] = Pairing.G1Point( + 14885882306758798937679394610772138922556123227880385870344808873436814022930, + 3934873393257063133916075434168945234055631293765592292343901673375181552269 + ); + + vk.IC[17] = Pairing.G1Point( + 20852410337525408428992795899695004554330381739936516870441901299905205279256, + 20648432346885856575420078255725230748619702397387201087589450468340771874297 + ); + + vk.IC[18] = Pairing.G1Point( + 6167699461166003748566567594747289131674547000150454009904996589304626584167, + 14110003077488418487783057098556325603292353141295332863985055993945398206528 + ); + + vk.IC[19] = Pairing.G1Point( + 20892317574252659735090624277245258193082807848049224448955777134073345685108, + 17727848959971681921713809931721849771484313017968391732789870806782840679927 + ); + + vk.IC[20] = Pairing.G1Point( + 20612376222610731408990545559739965790917945837965228469728226036495441146036, + 20351143376878226978145381965490573601268154635222697512049461276320828895668 + ); + + vk.IC[21] = Pairing.G1Point( + 20522947517427072557578167925733739815026195252456061540822404306528133008950, + 6036034786533315595464011703289331465287433898610658104234001410127390275895 + ); + + vk.IC[22] = Pairing.G1Point( + 20410796723096686566641699882879596519818754353289647070493357891405051737549, + 13189125262776114153651642489071019957668901126196870035821651431860467422633 + ); + + vk.IC[23] = Pairing.G1Point( + 3146788100852253288066278206133464680402002171505031301031229329226719437043, + 10396715094779767544731813785877872331726145317387352477574918383699931707909 + ); + + vk.IC[24] = Pairing.G1Point( + 21439687928968958399465185756652639162478589285565752006575911526852009438130, + 7297135059223284256740384214554937800272136142055798242764527036404583557135 + ); + + vk.IC[25] = Pairing.G1Point( + 12371325521158807364116536202166634842652368662231086806709494938994904680364, + 13133220971573998953122116499486922534369651074468739893016021893214504285030 + ); + + vk.IC[26] = Pairing.G1Point( + 21516003372014895147156904238565871466006669740508136449703899324711326195467, + 16278744532999316901560028522840185484837939454171671064194197332363447266974 + ); + + vk.IC[27] = Pairing.G1Point( + 5912019115796213199781760116500241215410486247272843508998060723047993766740, + 12312071263749771417514700530216961108776744423975472983260514323185579798281 + ); + + vk.IC[28] = Pairing.G1Point( + 20446140985339560388808125805050522681828992995015649353631750743722843544033, + 12985063191741477329911930314893245225347903321658616477211126417641819425305 + ); + + vk.IC[29] = Pairing.G1Point( + 7574545305046950711320318712229623062744829304153153967356279538993555666824, + 8122817517496954688328220645343524414698571600813771393507204249091215144851 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[29] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_2/Verifier2_2.sol b/packages/contracts/contracts/verifiers/vanchor_2/Verifier2_2.sol index 2b9ebe80c..39705cb4d 100644 --- a/packages/contracts/contracts/verifiers/vanchor_2/Verifier2_2.sol +++ b/packages/contracts/contracts/verifiers/vanchor_2/Verifier2_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,251 +53,308 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier2_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [5770515424550714891684354989363775914661317310936150862909206943687235179278, - 3277096202261880020490418733272830998560817123913709724955056210909784096188], - [13201709061541219755441466761967584452809028390595277172526414258738691817373, - 17801471892170478998472715034263449407900476807258073926062011900645670761012] - ); - vk.IC = new Pairing.G1Point[](10); - - vk.IC[0] = Pairing.G1Point( - 9875031730454291265661398784969215691099666568149351477123909427110274988448, - 14975563365066173191608485491890853046216664292759562166389185110430739238722 - ); - - vk.IC[1] = Pairing.G1Point( - 3569984815443165412032738650481153588608758723372780000851889975215000022720, - 958862776158106529915538160799495931138154330356738660221491545229065772334 - ); - - vk.IC[2] = Pairing.G1Point( - 10548277824201477783134023272596015247467626112761897251710029940886827115207, - 2506335019279413754505426083397632654028705316964319686810052091342300212362 - ); - - vk.IC[3] = Pairing.G1Point( - 17578134084520215786596661156275926358476458534081272365751282701493467216760, - 12416641761067586291962385908272305711053036813611155249468882838726309050300 - ); - - vk.IC[4] = Pairing.G1Point( - 16194025399294803843434404942880652126340725376729947797457993000358419964533, - 7540113415596478114042601995094790307400753187672847354765879807350651243141 - ); - - vk.IC[5] = Pairing.G1Point( - 9635189033444581784013077626252792264553276623507166435436437862093634545550, - 2331855331110757464904891353703561058532684028096644855280433003237992013582 - ); - - vk.IC[6] = Pairing.G1Point( - 16021452509651682890328276074005634855497104232735477293117764980786876481282, - 14695565377420366800695550889380004539197764293835862412247308854088030901169 - ); - - vk.IC[7] = Pairing.G1Point( - 11501840616890741065850376638450040379599424538485671201658208161887673116497, - 16883948695633658705103884839736856176037170930063659200379626364666023787997 - ); - - vk.IC[8] = Pairing.G1Point( - 14226940309162299101083347735647615221061761003237894165913298742033142143983, - 4368991203349785633397190203135908028891830268822002462961763567901972541432 - ); - - vk.IC[9] = Pairing.G1Point( - 21584882930047698029590549038680765506453222930973144734089979137526649892058, - 10567308222860360438759008698774448331431726793827940108541081863245850536893 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[9] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 5770515424550714891684354989363775914661317310936150862909206943687235179278, + 3277096202261880020490418733272830998560817123913709724955056210909784096188 + ], + [ + 13201709061541219755441466761967584452809028390595277172526414258738691817373, + 17801471892170478998472715034263449407900476807258073926062011900645670761012 + ] + ); + vk.IC = new Pairing.G1Point[](10); + + vk.IC[0] = Pairing.G1Point( + 9875031730454291265661398784969215691099666568149351477123909427110274988448, + 14975563365066173191608485491890853046216664292759562166389185110430739238722 + ); + + vk.IC[1] = Pairing.G1Point( + 3569984815443165412032738650481153588608758723372780000851889975215000022720, + 958862776158106529915538160799495931138154330356738660221491545229065772334 + ); + + vk.IC[2] = Pairing.G1Point( + 10548277824201477783134023272596015247467626112761897251710029940886827115207, + 2506335019279413754505426083397632654028705316964319686810052091342300212362 + ); + + vk.IC[3] = Pairing.G1Point( + 17578134084520215786596661156275926358476458534081272365751282701493467216760, + 12416641761067586291962385908272305711053036813611155249468882838726309050300 + ); + + vk.IC[4] = Pairing.G1Point( + 16194025399294803843434404942880652126340725376729947797457993000358419964533, + 7540113415596478114042601995094790307400753187672847354765879807350651243141 + ); + + vk.IC[5] = Pairing.G1Point( + 9635189033444581784013077626252792264553276623507166435436437862093634545550, + 2331855331110757464904891353703561058532684028096644855280433003237992013582 + ); + + vk.IC[6] = Pairing.G1Point( + 16021452509651682890328276074005634855497104232735477293117764980786876481282, + 14695565377420366800695550889380004539197764293835862412247308854088030901169 + ); + + vk.IC[7] = Pairing.G1Point( + 11501840616890741065850376638450040379599424538485671201658208161887673116497, + 16883948695633658705103884839736856176037170930063659200379626364666023787997 + ); + + vk.IC[8] = Pairing.G1Point( + 14226940309162299101083347735647615221061761003237894165913298742033142143983, + 4368991203349785633397190203135908028891830268822002462961763567901972541432 + ); + + vk.IC[9] = Pairing.G1Point( + 21584882930047698029590549038680765506453222930973144734089979137526649892058, + 10567308222860360438759008698774448331431726793827940108541081863245850536893 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[9] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_2/Verifier8_2.sol b/packages/contracts/contracts/verifiers/vanchor_2/Verifier8_2.sol index b1fa61639..a790ecbd8 100644 --- a/packages/contracts/contracts/verifiers/vanchor_2/Verifier8_2.sol +++ b/packages/contracts/contracts/verifiers/vanchor_2/Verifier8_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); -/* + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,281 +53,338 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract Verifier8_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [7434371754087225408396156352498661187352238662731049337409748012380719012765, - 5216082431039694148751915410587454165520380699854452523427781853735010025875], - [15184980459062039543130601164963358047590884661190325319344494152621354412189, - 18687813503823380355087392633570673917603936307973596261714918893107538098264] - ); - vk.IC = new Pairing.G1Point[](16); - - vk.IC[0] = Pairing.G1Point( - 5759469359398897869214354370254448805220567692542206229214727290429508005922, - 16324943845828044648837998647130081671558913416655605370553262092374931228300 - ); - - vk.IC[1] = Pairing.G1Point( - 9078381715335281623605983643603275346557999883408570836142975872467053550156, - 14119123366861612496582098112991609169117791507966069053917635775586728541028 - ); - - vk.IC[2] = Pairing.G1Point( - 14905428413443688059822519549549540048715381238222816414952725434757571527049, - 5455468540723796945610188688836217178717898839232705558209367499526066642987 - ); - - vk.IC[3] = Pairing.G1Point( - 4054120629258075371844653830657540293600718540090665264516840246387051624967, - 4055221144836332573714766874809344615990803938674917214786219997965376587849 - ); - - vk.IC[4] = Pairing.G1Point( - 2323834002558131571330850654336070657736442742763009424707321468787433426112, - 13918720923906388691217235854481727688145863416285179463858179733135004895708 - ); - - vk.IC[5] = Pairing.G1Point( - 5977209808188332684219305571851452509432206189145817441844928985645619443470, - 16651937928729866915914548754184849480869188364429876908004905443743338310699 - ); - - vk.IC[6] = Pairing.G1Point( - 10370112149202317732822991426133554823898115909504990578783632278955607023229, - 12694732024107219384766265249379939982809622934521467005553435065767867715083 - ); - - vk.IC[7] = Pairing.G1Point( - 7232961220247447605087762167857724929574639698307142847215864804122535720017, - 16561039097422068566240101645949188899611717236416237994803616028269051842291 - ); - - vk.IC[8] = Pairing.G1Point( - 8069013777085992025608622330164121138697724089042841792547446455809694722188, - 13209895842039139656642248394175426307299384122871816844143970967259495321532 - ); - - vk.IC[9] = Pairing.G1Point( - 5390348099635810743056945670268342212027738824774757815978305387963839519830, - 19956938171660662466542129653322814698599148211783512066363062550495424146972 - ); - - vk.IC[10] = Pairing.G1Point( - 1691734295880844883505634224390221989807357747570399715034511701689002517758, - 21769199836162497097525408114279156405765969803812532322766496627152970841108 - ); - - vk.IC[11] = Pairing.G1Point( - 16357332803332330398863510709274371072257545913962570293133493350689001124573, - 11137305192239035860046653907725106422190698251278743771459155026780548360756 - ); - - vk.IC[12] = Pairing.G1Point( - 21502570972155172998815401561002058860932076249297083697210631609393076947204, - 12662166195115638504500419223396953983497368309217036348825639540051927641175 - ); - - vk.IC[13] = Pairing.G1Point( - 12013872063813985482342258659501929413323020261195321545799160279485243656784, - 17728443342754900218826152683711688243589031657293910367328133029328593404857 - ); - - vk.IC[14] = Pairing.G1Point( - 1343561160594842028820426197677054023465716422621699867264404024169501032710, - 13750725881957087501589026015908501014100342495525810806990602063568636261226 - ); - - vk.IC[15] = Pairing.G1Point( - 19117526445273377691225278654270324021124282982492462517617021580770263648814, - 4234036292134161954009428275925826619619299132733967119044397227588852710151 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[15] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 7434371754087225408396156352498661187352238662731049337409748012380719012765, + 5216082431039694148751915410587454165520380699854452523427781853735010025875 + ], + [ + 15184980459062039543130601164963358047590884661190325319344494152621354412189, + 18687813503823380355087392633570673917603936307973596261714918893107538098264 + ] + ); + vk.IC = new Pairing.G1Point[](16); + + vk.IC[0] = Pairing.G1Point( + 5759469359398897869214354370254448805220567692542206229214727290429508005922, + 16324943845828044648837998647130081671558913416655605370553262092374931228300 + ); + + vk.IC[1] = Pairing.G1Point( + 9078381715335281623605983643603275346557999883408570836142975872467053550156, + 14119123366861612496582098112991609169117791507966069053917635775586728541028 + ); + + vk.IC[2] = Pairing.G1Point( + 14905428413443688059822519549549540048715381238222816414952725434757571527049, + 5455468540723796945610188688836217178717898839232705558209367499526066642987 + ); + + vk.IC[3] = Pairing.G1Point( + 4054120629258075371844653830657540293600718540090665264516840246387051624967, + 4055221144836332573714766874809344615990803938674917214786219997965376587849 + ); + + vk.IC[4] = Pairing.G1Point( + 2323834002558131571330850654336070657736442742763009424707321468787433426112, + 13918720923906388691217235854481727688145863416285179463858179733135004895708 + ); + + vk.IC[5] = Pairing.G1Point( + 5977209808188332684219305571851452509432206189145817441844928985645619443470, + 16651937928729866915914548754184849480869188364429876908004905443743338310699 + ); + + vk.IC[6] = Pairing.G1Point( + 10370112149202317732822991426133554823898115909504990578783632278955607023229, + 12694732024107219384766265249379939982809622934521467005553435065767867715083 + ); + + vk.IC[7] = Pairing.G1Point( + 7232961220247447605087762167857724929574639698307142847215864804122535720017, + 16561039097422068566240101645949188899611717236416237994803616028269051842291 + ); + + vk.IC[8] = Pairing.G1Point( + 8069013777085992025608622330164121138697724089042841792547446455809694722188, + 13209895842039139656642248394175426307299384122871816844143970967259495321532 + ); + + vk.IC[9] = Pairing.G1Point( + 5390348099635810743056945670268342212027738824774757815978305387963839519830, + 19956938171660662466542129653322814698599148211783512066363062550495424146972 + ); + + vk.IC[10] = Pairing.G1Point( + 1691734295880844883505634224390221989807357747570399715034511701689002517758, + 21769199836162497097525408114279156405765969803812532322766496627152970841108 + ); + + vk.IC[11] = Pairing.G1Point( + 16357332803332330398863510709274371072257545913962570293133493350689001124573, + 11137305192239035860046653907725106422190698251278743771459155026780548360756 + ); + + vk.IC[12] = Pairing.G1Point( + 21502570972155172998815401561002058860932076249297083697210631609393076947204, + 12662166195115638504500419223396953983497368309217036348825639540051927641175 + ); + + vk.IC[13] = Pairing.G1Point( + 12013872063813985482342258659501929413323020261195321545799160279485243656784, + 17728443342754900218826152683711688243589031657293910367328133029328593404857 + ); + + vk.IC[14] = Pairing.G1Point( + 1343561160594842028820426197677054023465716422621699867264404024169501032710, + 13750725881957087501589026015908501014100342495525810806990602063568636261226 + ); + + vk.IC[15] = Pairing.G1Point( + 19117526445273377691225278654270324021124282982492462517617021580770263648814, + 4234036292134161954009428275925826619619299132733967119044397227588852710151 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[15] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF2_16.sol b/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF2_16.sol index e73353569..9fe72763b 100644 --- a/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF2_16.sol +++ b/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF2_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } -/* + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,321 +53,378 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierF2_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [9594163765008457007052483351135837548991883620671327820875087487618278420358, - 19919076038656581822242308020471980209714897465930189015640177987594303060341], - [15306016222563636424237526902306059796829764475437954911891547698336805531839, - 21481934666819858882111333231811663159263832609803746451895026275397219044837] - ); - vk.IC = new Pairing.G1Point[](24); - - vk.IC[0] = Pairing.G1Point( - 1968551090408633137223850024480814193306571327545815800174609541193849792963, - 2547578541367050400490424732204589523924787910567455208656901385499898650349 - ); - - vk.IC[1] = Pairing.G1Point( - 9870781033015821859048345608785924448275256526395494463498892465268594042272, - 7843986601281751930816353933031993959017612081443799030807249696236193082471 - ); - - vk.IC[2] = Pairing.G1Point( - 7344093169384241378495332928570145914214744882831556271267208258256037709171, - 9905875090237672003065284213886524228867836338624845493406604810342223808970 - ); - - vk.IC[3] = Pairing.G1Point( - 11672546925736945058722603774034996778471612427967586422739539525969836360071, - 8427948268357686936994159125386990170179499477464207892302241814458326379224 - ); - - vk.IC[4] = Pairing.G1Point( - 6595207522120912418904682830570208373480828555777861770434035880966019007932, - 2201376714581688031275900005618853472978355893825685818968275971053250910796 - ); - - vk.IC[5] = Pairing.G1Point( - 15337755318651648835030293772534561000763561782154096898773319508172900429025, - 1161668505164873599608019072177064549578565307367102629505369549135312490306 - ); - - vk.IC[6] = Pairing.G1Point( - 3630194644436613240562658401471522880173787006523445266479652434725735499654, - 3639947340499613495301889510240402469644201959623498052524243841905943734151 - ); - - vk.IC[7] = Pairing.G1Point( - 37867044780453718012925696569535306249760980938489122405130339187227580597, - 5983836446829664980850712131551500793331562776955359605031042531983518195640 - ); - - vk.IC[8] = Pairing.G1Point( - 18718829455815052115364070074700105755744865287644303650352684922149899124041, - 15394792270302362551205801110670795286275917549931390540814976179986371957750 - ); - - vk.IC[9] = Pairing.G1Point( - 5995742172146683195337898820003575349924802478985270134178956467934199626614, - 16033578990242569974374721792369657383829558579957321549705786307492888152536 - ); - - vk.IC[10] = Pairing.G1Point( - 6616177429728658958420610643477762544818989849717161399268501492605698335307, - 16658500397569623874875736714328039340705988992194956622154792135307266982976 - ); - - vk.IC[11] = Pairing.G1Point( - 11748774962072186172110404650496135790629447508253002156314546290393027409776, - 8059716897835802985765524968567720509081331897492175329000907769308210865840 - ); - - vk.IC[12] = Pairing.G1Point( - 15985827869311966443808513155792735483533836602867312412820766036298111179514, - 13959288370115880833101585121285622521031410630558739406456940876474635257933 - ); - - vk.IC[13] = Pairing.G1Point( - 9379579979170153402082414107474682247729205103855186218145280164706715599748, - 16002997304108090916112335006384806935411002650415172031246755220159507830730 - ); - - vk.IC[14] = Pairing.G1Point( - 20988082800994844215749720528930397437644116959608603198606919663270429085020, - 2810288440941933874204924201633443774315463972928927437801539509492426852736 - ); - - vk.IC[15] = Pairing.G1Point( - 2232718141937033629499033510689631179207578491700864491248877302701276695928, - 15414641162343479800666490788979379631220271694464027192344478237426604784227 - ); - - vk.IC[16] = Pairing.G1Point( - 18775791435018748442069554313263948207126551450650205812732618377658641281242, - 21496943231760316703369512657111881495737644357438541501361177409471968736350 - ); - - vk.IC[17] = Pairing.G1Point( - 9103442104837547516221756146050780632194849245175894043737964469496834856205, - 7322279057996449002125992116172306394509000829927768357475245709951995729611 - ); - - vk.IC[18] = Pairing.G1Point( - 11239904001411003184251919693395371443019467767525502315087659842581195238573, - 91662349997568491378763670808448237458731940829349796579913132134641260969 - ); - - vk.IC[19] = Pairing.G1Point( - 1656738020037038217281253315134577526300123353246283531114024556867850676821, - 9368360893459474086211924926147112231168133317842851072702555340131182216148 - ); - - vk.IC[20] = Pairing.G1Point( - 17109197493336641649162476250899763488345113708797582719617814141271909975401, - 507527357909498704564339084500435068250348729073713075507090562638975736973 - ); - - vk.IC[21] = Pairing.G1Point( - 2715763725696116690002830716960505442518191210596746536344819966272228418209, - 12037976113902635960677155179552925363335110667504376518719938936459739385703 - ); - - vk.IC[22] = Pairing.G1Point( - 6084144504649412158048367671117153598467411467977657901857623574946071907320, - 8633213747613919286921913753501586643554981398718376088597061147779849724232 - ); - - vk.IC[23] = Pairing.G1Point( - 12553868140946631419732258649532933048805431462057922774600839100559528986052, - 2941521808599363909575164945549901734660236697139158344282037366040209638922 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[23] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 9594163765008457007052483351135837548991883620671327820875087487618278420358, + 19919076038656581822242308020471980209714897465930189015640177987594303060341 + ], + [ + 15306016222563636424237526902306059796829764475437954911891547698336805531839, + 21481934666819858882111333231811663159263832609803746451895026275397219044837 + ] + ); + vk.IC = new Pairing.G1Point[](24); + + vk.IC[0] = Pairing.G1Point( + 1968551090408633137223850024480814193306571327545815800174609541193849792963, + 2547578541367050400490424732204589523924787910567455208656901385499898650349 + ); + + vk.IC[1] = Pairing.G1Point( + 9870781033015821859048345608785924448275256526395494463498892465268594042272, + 7843986601281751930816353933031993959017612081443799030807249696236193082471 + ); + + vk.IC[2] = Pairing.G1Point( + 7344093169384241378495332928570145914214744882831556271267208258256037709171, + 9905875090237672003065284213886524228867836338624845493406604810342223808970 + ); + + vk.IC[3] = Pairing.G1Point( + 11672546925736945058722603774034996778471612427967586422739539525969836360071, + 8427948268357686936994159125386990170179499477464207892302241814458326379224 + ); + + vk.IC[4] = Pairing.G1Point( + 6595207522120912418904682830570208373480828555777861770434035880966019007932, + 2201376714581688031275900005618853472978355893825685818968275971053250910796 + ); + + vk.IC[5] = Pairing.G1Point( + 15337755318651648835030293772534561000763561782154096898773319508172900429025, + 1161668505164873599608019072177064549578565307367102629505369549135312490306 + ); + + vk.IC[6] = Pairing.G1Point( + 3630194644436613240562658401471522880173787006523445266479652434725735499654, + 3639947340499613495301889510240402469644201959623498052524243841905943734151 + ); + + vk.IC[7] = Pairing.G1Point( + 37867044780453718012925696569535306249760980938489122405130339187227580597, + 5983836446829664980850712131551500793331562776955359605031042531983518195640 + ); + + vk.IC[8] = Pairing.G1Point( + 18718829455815052115364070074700105755744865287644303650352684922149899124041, + 15394792270302362551205801110670795286275917549931390540814976179986371957750 + ); + + vk.IC[9] = Pairing.G1Point( + 5995742172146683195337898820003575349924802478985270134178956467934199626614, + 16033578990242569974374721792369657383829558579957321549705786307492888152536 + ); + + vk.IC[10] = Pairing.G1Point( + 6616177429728658958420610643477762544818989849717161399268501492605698335307, + 16658500397569623874875736714328039340705988992194956622154792135307266982976 + ); + + vk.IC[11] = Pairing.G1Point( + 11748774962072186172110404650496135790629447508253002156314546290393027409776, + 8059716897835802985765524968567720509081331897492175329000907769308210865840 + ); + + vk.IC[12] = Pairing.G1Point( + 15985827869311966443808513155792735483533836602867312412820766036298111179514, + 13959288370115880833101585121285622521031410630558739406456940876474635257933 + ); + + vk.IC[13] = Pairing.G1Point( + 9379579979170153402082414107474682247729205103855186218145280164706715599748, + 16002997304108090916112335006384806935411002650415172031246755220159507830730 + ); + + vk.IC[14] = Pairing.G1Point( + 20988082800994844215749720528930397437644116959608603198606919663270429085020, + 2810288440941933874204924201633443774315463972928927437801539509492426852736 + ); + + vk.IC[15] = Pairing.G1Point( + 2232718141937033629499033510689631179207578491700864491248877302701276695928, + 15414641162343479800666490788979379631220271694464027192344478237426604784227 + ); + + vk.IC[16] = Pairing.G1Point( + 18775791435018748442069554313263948207126551450650205812732618377658641281242, + 21496943231760316703369512657111881495737644357438541501361177409471968736350 + ); + + vk.IC[17] = Pairing.G1Point( + 9103442104837547516221756146050780632194849245175894043737964469496834856205, + 7322279057996449002125992116172306394509000829927768357475245709951995729611 + ); + + vk.IC[18] = Pairing.G1Point( + 11239904001411003184251919693395371443019467767525502315087659842581195238573, + 91662349997568491378763670808448237458731940829349796579913132134641260969 + ); + + vk.IC[19] = Pairing.G1Point( + 1656738020037038217281253315134577526300123353246283531114024556867850676821, + 9368360893459474086211924926147112231168133317842851072702555340131182216148 + ); + + vk.IC[20] = Pairing.G1Point( + 17109197493336641649162476250899763488345113708797582719617814141271909975401, + 507527357909498704564339084500435068250348729073713075507090562638975736973 + ); + + vk.IC[21] = Pairing.G1Point( + 2715763725696116690002830716960505442518191210596746536344819966272228418209, + 12037976113902635960677155179552925363335110667504376518719938936459739385703 + ); + + vk.IC[22] = Pairing.G1Point( + 6084144504649412158048367671117153598467411467977657901857623574946071907320, + 8633213747613919286921913753501586643554981398718376088597061147779849724232 + ); + + vk.IC[23] = Pairing.G1Point( + 12553868140946631419732258649532933048805431462057922774600839100559528986052, + 2941521808599363909575164945549901734660236697139158344282037366040209638922 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[23] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF8_16.sol b/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF8_16.sol index 80e76fed9..e8ba78b7c 100644 --- a/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF8_16.sol +++ b/packages/contracts/contracts/verifiers/vanchor_forest_16/VerifierF8_16.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,351 +53,408 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierF8_16 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [9137829261227853319328407668705280049260721197800905204131118463259447709303, - 18240373378425513191163409502127073139253432295977826439244385424247299960016], - [17199478087021256540899411513147108337074281737580930998158134566614948811465, - 13577643676595970460655161488590062022050966418829552870313256998304380715448] - ); - vk.IC = new Pairing.G1Point[](30); - - vk.IC[0] = Pairing.G1Point( - 1450011838548851651641301933999774981622444793059717843108702251278335684039, - 5657829732733922043666985930559136613027148013492528612833948225392533512613 - ); - - vk.IC[1] = Pairing.G1Point( - 21065372017713601681796343766284246542391766169647702603754541847319098605736, - 20881845036117753709191937581863376367583052128729220902620100015488675770991 - ); - - vk.IC[2] = Pairing.G1Point( - 15353340779764599533800846569309726455859374267766197697362258170868605514020, - 120570168604805986885063254121770802311051435738429229579758141583741794010 - ); - - vk.IC[3] = Pairing.G1Point( - 2539121985998089600306539847889571116832259694916091396425235921181194086327, - 4151732329447005403440248163622691730937462551554018927909403467864007714091 - ); - - vk.IC[4] = Pairing.G1Point( - 15323925103025042721778770621700183002273525446371586472172112442840051359246, - 11478405650682688254563076494552866705529497856834818746090804769158300751930 - ); - - vk.IC[5] = Pairing.G1Point( - 191742465120971493929517671872161382475043323843955685125844956300231556401, - 14870151133168236122750573225105358593229760245537846326372902770358931648223 - ); - - vk.IC[6] = Pairing.G1Point( - 1825908795536485206778317178131246382343990788260887211449068807495990795050, - 15337875411529039362078733984195282720826476992873753585523168751290606546951 - ); - - vk.IC[7] = Pairing.G1Point( - 7802975787858898559468144663678715098711477225441314526871563930432331889518, - 2120224153121266893638511609876872651408243786835127334866565142731058828860 - ); - - vk.IC[8] = Pairing.G1Point( - 15629689373059909070204239910405456827002507716255806801643413163095667792356, - 18526493998386006101119472434585622110129199202878101967498665057403244610864 - ); - - vk.IC[9] = Pairing.G1Point( - 18148755098745044270539618149361848877486130698053071878255450838701865867935, - 1836414065968808482155134686094650917330494396840062169773633511349471353445 - ); - - vk.IC[10] = Pairing.G1Point( - 14911184585260651869099191315932351505714841274601780932889926177352182884497, - 21445106892989259922268871647401804886937278082874022677016999484374847970743 - ); - - vk.IC[11] = Pairing.G1Point( - 17260374027013717527447226911192580929112688219404569020553865936607552933279, - 736156925842590115074764307657929209761714547267732658989294406462534537278 - ); - - vk.IC[12] = Pairing.G1Point( - 19796793307345958849971405170854264813416566749303889689416423834984221876567, - 12252169404861211186777642441020029087664521907311518339101364287779055367642 - ); - - vk.IC[13] = Pairing.G1Point( - 14341104484722142715126571750851329635581223719680420142648603077697119728249, - 11929404244845748916051340792376018056127518064427442160800392188866741910869 - ); - - vk.IC[14] = Pairing.G1Point( - 20489119043122758287880020739195863218249493448402876847025116275120396389375, - 20745210335763935517605502866899342008998009159913645028980283144059392892034 - ); - - vk.IC[15] = Pairing.G1Point( - 8802242149192902430332521506452254787713878740360235379952985010912365893195, - 1635900202880541399819629027242744057850501825579354756928074878423668987517 - ); - - vk.IC[16] = Pairing.G1Point( - 17970032071672624743780327680268291582699931753120837226170818180627171766230, - 15272104793176209279602297296380501123107847481120204256373280438336785759666 - ); - - vk.IC[17] = Pairing.G1Point( - 13930529930520789788457662910762025884704699956969157430179976387659742955847, - 9356037898969127805079423182396107130415726279888956319564382614059661704243 - ); - - vk.IC[18] = Pairing.G1Point( - 14980020802236569574607259833149341680568941840053215349607011210119907525531, - 15821299511087207332665303095311543371759738172937474795206644685908461201143 - ); - - vk.IC[19] = Pairing.G1Point( - 21247192883189872839054338878162666878677535672075396678365247342429558131825, - 10792487213740687023921199466733756063469287658852281107640262499204606037664 - ); - - vk.IC[20] = Pairing.G1Point( - 2450461710841260873076963999495650797010470729456418612768388541707740374074, - 127255499907210354037595244552570445459161184510203135194501731914566721800 - ); - - vk.IC[21] = Pairing.G1Point( - 17452257715902836437701967480787689150073881966461666661450849745405817677829, - 17688249103083820067808861253204591424647397907795601740473702101485424259501 - ); - - vk.IC[22] = Pairing.G1Point( - 2751689873528791108227267791205173168828392970493811293316853969854036392712, - 3138857182585254375737148307738072432928329876820236107601935646889179795471 - ); - - vk.IC[23] = Pairing.G1Point( - 14165012795452973229854378190408829725672774202549211435350596749407454675987, - 9768897102858589267111486338883322943580059970501849119978791133037758740803 - ); - - vk.IC[24] = Pairing.G1Point( - 20315952858983474148541324757154446100751661189946495203766014111254599731327, - 7478949822525657670881251834766267844049207228745624652607287782532147355614 - ); - - vk.IC[25] = Pairing.G1Point( - 16174022796801329166295410534394643378764735194524132518508404681008613806807, - 10577493861429946200966446914456013427077146908154984824621559716596264771118 - ); - - vk.IC[26] = Pairing.G1Point( - 19732205216838727872103239361116307648327773644919049576402603184196679270979, - 9841691036630121781058354181243178604043908436540644011817375996050965127201 - ); - - vk.IC[27] = Pairing.G1Point( - 14098912923508093789282940018585736618765149955365304636375605963008593697339, - 1901740508573033640805903912046846273061503753297718453468280437350492875259 - ); - - vk.IC[28] = Pairing.G1Point( - 5964004496785729999441273341551367226254981026509500624597927001534544955288, - 21833943734824800942630878240613553551574286472335076332389661992963577350749 - ); - - vk.IC[29] = Pairing.G1Point( - 8822803044578337543292653922761671312977959133422874067881538544776456960099, - 14687379142923506806590245984698515606953175821396083351443259691019905677231 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[29] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 9137829261227853319328407668705280049260721197800905204131118463259447709303, + 18240373378425513191163409502127073139253432295977826439244385424247299960016 + ], + [ + 17199478087021256540899411513147108337074281737580930998158134566614948811465, + 13577643676595970460655161488590062022050966418829552870313256998304380715448 + ] + ); + vk.IC = new Pairing.G1Point[](30); + + vk.IC[0] = Pairing.G1Point( + 1450011838548851651641301933999774981622444793059717843108702251278335684039, + 5657829732733922043666985930559136613027148013492528612833948225392533512613 + ); + + vk.IC[1] = Pairing.G1Point( + 21065372017713601681796343766284246542391766169647702603754541847319098605736, + 20881845036117753709191937581863376367583052128729220902620100015488675770991 + ); + + vk.IC[2] = Pairing.G1Point( + 15353340779764599533800846569309726455859374267766197697362258170868605514020, + 120570168604805986885063254121770802311051435738429229579758141583741794010 + ); + + vk.IC[3] = Pairing.G1Point( + 2539121985998089600306539847889571116832259694916091396425235921181194086327, + 4151732329447005403440248163622691730937462551554018927909403467864007714091 + ); + + vk.IC[4] = Pairing.G1Point( + 15323925103025042721778770621700183002273525446371586472172112442840051359246, + 11478405650682688254563076494552866705529497856834818746090804769158300751930 + ); + + vk.IC[5] = Pairing.G1Point( + 191742465120971493929517671872161382475043323843955685125844956300231556401, + 14870151133168236122750573225105358593229760245537846326372902770358931648223 + ); + + vk.IC[6] = Pairing.G1Point( + 1825908795536485206778317178131246382343990788260887211449068807495990795050, + 15337875411529039362078733984195282720826476992873753585523168751290606546951 + ); + + vk.IC[7] = Pairing.G1Point( + 7802975787858898559468144663678715098711477225441314526871563930432331889518, + 2120224153121266893638511609876872651408243786835127334866565142731058828860 + ); + + vk.IC[8] = Pairing.G1Point( + 15629689373059909070204239910405456827002507716255806801643413163095667792356, + 18526493998386006101119472434585622110129199202878101967498665057403244610864 + ); + + vk.IC[9] = Pairing.G1Point( + 18148755098745044270539618149361848877486130698053071878255450838701865867935, + 1836414065968808482155134686094650917330494396840062169773633511349471353445 + ); + + vk.IC[10] = Pairing.G1Point( + 14911184585260651869099191315932351505714841274601780932889926177352182884497, + 21445106892989259922268871647401804886937278082874022677016999484374847970743 + ); + + vk.IC[11] = Pairing.G1Point( + 17260374027013717527447226911192580929112688219404569020553865936607552933279, + 736156925842590115074764307657929209761714547267732658989294406462534537278 + ); + + vk.IC[12] = Pairing.G1Point( + 19796793307345958849971405170854264813416566749303889689416423834984221876567, + 12252169404861211186777642441020029087664521907311518339101364287779055367642 + ); + + vk.IC[13] = Pairing.G1Point( + 14341104484722142715126571750851329635581223719680420142648603077697119728249, + 11929404244845748916051340792376018056127518064427442160800392188866741910869 + ); + + vk.IC[14] = Pairing.G1Point( + 20489119043122758287880020739195863218249493448402876847025116275120396389375, + 20745210335763935517605502866899342008998009159913645028980283144059392892034 + ); + + vk.IC[15] = Pairing.G1Point( + 8802242149192902430332521506452254787713878740360235379952985010912365893195, + 1635900202880541399819629027242744057850501825579354756928074878423668987517 + ); + + vk.IC[16] = Pairing.G1Point( + 17970032071672624743780327680268291582699931753120837226170818180627171766230, + 15272104793176209279602297296380501123107847481120204256373280438336785759666 + ); + + vk.IC[17] = Pairing.G1Point( + 13930529930520789788457662910762025884704699956969157430179976387659742955847, + 9356037898969127805079423182396107130415726279888956319564382614059661704243 + ); + + vk.IC[18] = Pairing.G1Point( + 14980020802236569574607259833149341680568941840053215349607011210119907525531, + 15821299511087207332665303095311543371759738172937474795206644685908461201143 + ); + + vk.IC[19] = Pairing.G1Point( + 21247192883189872839054338878162666878677535672075396678365247342429558131825, + 10792487213740687023921199466733756063469287658852281107640262499204606037664 + ); + + vk.IC[20] = Pairing.G1Point( + 2450461710841260873076963999495650797010470729456418612768388541707740374074, + 127255499907210354037595244552570445459161184510203135194501731914566721800 + ); + + vk.IC[21] = Pairing.G1Point( + 17452257715902836437701967480787689150073881966461666661450849745405817677829, + 17688249103083820067808861253204591424647397907795601740473702101485424259501 + ); + + vk.IC[22] = Pairing.G1Point( + 2751689873528791108227267791205173168828392970493811293316853969854036392712, + 3138857182585254375737148307738072432928329876820236107601935646889179795471 + ); + + vk.IC[23] = Pairing.G1Point( + 14165012795452973229854378190408829725672774202549211435350596749407454675987, + 9768897102858589267111486338883322943580059970501849119978791133037758740803 + ); + + vk.IC[24] = Pairing.G1Point( + 20315952858983474148541324757154446100751661189946495203766014111254599731327, + 7478949822525657670881251834766267844049207228745624652607287782532147355614 + ); + + vk.IC[25] = Pairing.G1Point( + 16174022796801329166295410534394643378764735194524132518508404681008613806807, + 10577493861429946200966446914456013427077146908154984824621559716596264771118 + ); + + vk.IC[26] = Pairing.G1Point( + 19732205216838727872103239361116307648327773644919049576402603184196679270979, + 9841691036630121781058354181243178604043908436540644011817375996050965127201 + ); + + vk.IC[27] = Pairing.G1Point( + 14098912923508093789282940018585736618765149955365304636375605963008593697339, + 1901740508573033640805903912046846273061503753297718453468280437350492875259 + ); + + vk.IC[28] = Pairing.G1Point( + 5964004496785729999441273341551367226254981026509500624597927001534544955288, + 21833943734824800942630878240613553551574286472335076332389661992963577350749 + ); + + vk.IC[29] = Pairing.G1Point( + 8822803044578337543292653922761671312977959133422874067881538544776456960099, + 14687379142923506806590245984698515606953175821396083351443259691019905677231 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[29] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF2_2.sol b/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF2_2.sol index 80bcd9502..54332cadd 100644 --- a/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF2_2.sol +++ b/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF2_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } -/* + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,251 +53,308 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierF2_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [7795494129814823673763243347006077987530673778035294094575428032977443971633, - 12713402787919338320692930134937177181943331491345738544393343814529610439699], - [8111223477195830645481688281642531115296840719170110927025749215581129696131, - 21352475213884269255285477161275186705770220035908614951666733467023354927198] - ); - vk.IC = new Pairing.G1Point[](10); - - vk.IC[0] = Pairing.G1Point( - 5433699783684187123301277036550396675559895275221030305868349819645336499284, - 20388703899968610468664439964422583179977423422801434433700527274388580092926 - ); - - vk.IC[1] = Pairing.G1Point( - 3889742554240764963453999801006309019939408001783752443033771815906951249121, - 5728907656599929333876411479162709986147336222217526192766553610948770030684 - ); - - vk.IC[2] = Pairing.G1Point( - 19403454997711764252006612636212586912289711026251888146650558045649547257262, - 14196331825038822279146051132577292316529084357462397463952989997818093520486 - ); - - vk.IC[3] = Pairing.G1Point( - 5068643977097966499233696248458201783238856536755116817343661339506224836552, - 4000927077805109364040843562253837641657331847969850185232495837600950333430 - ); - - vk.IC[4] = Pairing.G1Point( - 14786153083218703239799702782929376967797604881984526598490230401562629142729, - 21037315442427514157439400647502788468580632982164845087413355953194745912605 - ); - - vk.IC[5] = Pairing.G1Point( - 10542083606828677731350854866782192214910250327891817775612086940269408123168, - 5465843796048701673669811957316998297008974227973792428961374465957051935782 - ); - - vk.IC[6] = Pairing.G1Point( - 10670599920975785116476594072201275001601019346276620859981025879483775023740, - 11954832923956563853112541280170167952643587882943951077337737556304490051891 - ); - - vk.IC[7] = Pairing.G1Point( - 1234655087421637362751569198110219600116523681501622821002248682090652059206, - 18662034535039777621532737095987536698386199130614140550399508667756323118484 - ); - - vk.IC[8] = Pairing.G1Point( - 2584631564390616879004724628904264741081366979935482334078950954290708194190, - 6759785782277162321065027178573370529305611130073352502401108166869268140179 - ); - - vk.IC[9] = Pairing.G1Point( - 677470967128555815924810386856292131272611612285985459132969962566916494173, - 13439376486093118752001794956511898371543881490816762474751565296542028091003 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[9] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 7795494129814823673763243347006077987530673778035294094575428032977443971633, + 12713402787919338320692930134937177181943331491345738544393343814529610439699 + ], + [ + 8111223477195830645481688281642531115296840719170110927025749215581129696131, + 21352475213884269255285477161275186705770220035908614951666733467023354927198 + ] + ); + vk.IC = new Pairing.G1Point[](10); + + vk.IC[0] = Pairing.G1Point( + 5433699783684187123301277036550396675559895275221030305868349819645336499284, + 20388703899968610468664439964422583179977423422801434433700527274388580092926 + ); + + vk.IC[1] = Pairing.G1Point( + 3889742554240764963453999801006309019939408001783752443033771815906951249121, + 5728907656599929333876411479162709986147336222217526192766553610948770030684 + ); + + vk.IC[2] = Pairing.G1Point( + 19403454997711764252006612636212586912289711026251888146650558045649547257262, + 14196331825038822279146051132577292316529084357462397463952989997818093520486 + ); + + vk.IC[3] = Pairing.G1Point( + 5068643977097966499233696248458201783238856536755116817343661339506224836552, + 4000927077805109364040843562253837641657331847969850185232495837600950333430 + ); + + vk.IC[4] = Pairing.G1Point( + 14786153083218703239799702782929376967797604881984526598490230401562629142729, + 21037315442427514157439400647502788468580632982164845087413355953194745912605 + ); + + vk.IC[5] = Pairing.G1Point( + 10542083606828677731350854866782192214910250327891817775612086940269408123168, + 5465843796048701673669811957316998297008974227973792428961374465957051935782 + ); + + vk.IC[6] = Pairing.G1Point( + 10670599920975785116476594072201275001601019346276620859981025879483775023740, + 11954832923956563853112541280170167952643587882943951077337737556304490051891 + ); + + vk.IC[7] = Pairing.G1Point( + 1234655087421637362751569198110219600116523681501622821002248682090652059206, + 18662034535039777621532737095987536698386199130614140550399508667756323118484 + ); + + vk.IC[8] = Pairing.G1Point( + 2584631564390616879004724628904264741081366979935482334078950954290708194190, + 6759785782277162321065027178573370529305611130073352502401108166869268140179 + ); + + vk.IC[9] = Pairing.G1Point( + 677470967128555815924810386856292131272611612285985459132969962566916494173, + 13439376486093118752001794956511898371543881490816762474751565296542028091003 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[9] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF8_2.sol b/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF8_2.sol index 5c1dd7a4d..564aebcb6 100644 --- a/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF8_2.sol +++ b/packages/contracts/contracts/verifiers/vanchor_forest_2/VerifierF8_2.sol @@ -12,31 +12,39 @@ // // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.0; + library Pairing { - struct G1Point { - uint X; - uint Y; - } - // Encoding of field elements is: X[0] * z + X[1] - struct G2Point { - uint[2] X; - uint[2] Y; - } - /// @return the generator of G1 - function P1() internal pure returns (G1Point memory) { - return G1Point(1, 2); - } - /// @return the generator of G2 - function P2() internal pure returns (G2Point memory) { - // Original code point - return G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); + struct G1Point { + uint X; + uint Y; + } + // Encoding of field elements is: X[0] * z + X[1] + struct G2Point { + uint[2] X; + uint[2] Y; + } + + /// @return the generator of G1 + function P1() internal pure returns (G1Point memory) { + return G1Point(1, 2); + } + + /// @return the generator of G2 + function P2() internal pure returns (G2Point memory) { + // Original code point + return + G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); -/* + /* // Changed by Jordi point return G2Point( [10857046999023057135944570762232829481370756359578518086990519993285655852781, @@ -45,281 +53,338 @@ library Pairing { 4082367875863433681332203403145435568316851327593401208105741076214120093531] ); */ - } - /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. - function negate(G1Point memory p) internal pure returns (G1Point memory r) { - // The prime q in the base field F_q for G1 - uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - if (p.X == 0 && p.Y == 0) - return G1Point(0, 0); - return G1Point(p.X, q - (p.Y % q)); - } - /// @return r the sum of two points of G1 - function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) { - uint[4] memory input; - input[0] = p1.X; - input[1] = p1.Y; - input[2] = p2.X; - input[3] = p2.Y; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-add-failed"); - } - /// @return r the product of a point on G1 and a scalar, i.e. - /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. - function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { - uint[3] memory input; - input[0] = p.X; - input[1] = p.Y; - input[2] = s; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require (success,"pairing-mul-failed"); - } - /// @return the result of computing the pairing check - /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 - /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should - /// return true. - function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { - require(p1.length == p2.length,"pairing-lengths-failed"); - uint elements = p1.length; - uint inputSize = elements * 6; - uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) - { - input[i * 6 + 0] = p1[i].X; - input[i * 6 + 1] = p1[i].Y; - input[i * 6 + 2] = p2[i].X[0]; - input[i * 6 + 3] = p2[i].X[1]; - input[i * 6 + 4] = p2[i].Y[0]; - input[i * 6 + 5] = p2[i].Y[1]; - } - uint[1] memory out; - bool success; - // solium-disable-next-line security/no-inline-assembly - assembly { - success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) - // Use "invalid" to make gas estimation work - switch success case 0 { invalid() } - } - require(success,"pairing-opcode-failed"); - return out[0] != 0; - } - /// Convenience method for a pairing check for two pairs. - function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](2); - G2Point[] memory p2 = new G2Point[](2); - p1[0] = a1; - p1[1] = b1; - p2[0] = a2; - p2[1] = b2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for three pairs. - function pairingProd3( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](3); - G2Point[] memory p2 = new G2Point[](3); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - return pairing(p1, p2); - } - /// Convenience method for a pairing check for four pairs. - function pairingProd4( - G1Point memory a1, G2Point memory a2, - G1Point memory b1, G2Point memory b2, - G1Point memory c1, G2Point memory c2, - G1Point memory d1, G2Point memory d2 - ) internal view returns (bool) { - G1Point[] memory p1 = new G1Point[](4); - G2Point[] memory p2 = new G2Point[](4); - p1[0] = a1; - p1[1] = b1; - p1[2] = c1; - p1[3] = d1; - p2[0] = a2; - p2[1] = b2; - p2[2] = c2; - p2[3] = d2; - return pairing(p1, p2); - } + } + + /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero. + function negate(G1Point memory p) internal pure returns (G1Point memory r) { + // The prime q in the base field F_q for G1 + uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + if (p.X == 0 && p.Y == 0) return G1Point(0, 0); + return G1Point(p.X, q - (p.Y % q)); + } + + /// @return r the sum of two points of G1 + function addition( + G1Point memory p1, + G1Point memory p2 + ) internal view returns (G1Point memory r) { + uint[4] memory input; + input[0] = p1.X; + input[1] = p1.Y; + input[2] = p2.X; + input[3] = p2.Y; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-add-failed"); + } + + /// @return r the product of a point on G1 and a scalar, i.e. + /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. + function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) { + uint[3] memory input; + input[0] = p.X; + input[1] = p.Y; + input[2] = s; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-mul-failed"); + } + + /// @return the result of computing the pairing check + /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 + /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should + /// return true. + function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) { + require(p1.length == p2.length, "pairing-lengths-failed"); + uint elements = p1.length; + uint inputSize = elements * 6; + uint[] memory input = new uint[](inputSize); + for (uint i = 0; i < elements; i++) { + input[i * 6 + 0] = p1[i].X; + input[i * 6 + 1] = p1[i].Y; + input[i * 6 + 2] = p2[i].X[0]; + input[i * 6 + 3] = p2[i].X[1]; + input[i * 6 + 4] = p2[i].Y[0]; + input[i * 6 + 5] = p2[i].Y[1]; + } + uint[1] memory out; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall( + sub(gas(), 2000), + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + // Use "invalid" to make gas estimation work + switch success + case 0 { + invalid() + } + } + require(success, "pairing-opcode-failed"); + return out[0] != 0; + } + + /// Convenience method for a pairing check for two pairs. + function pairingProd2( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](2); + G2Point[] memory p2 = new G2Point[](2); + p1[0] = a1; + p1[1] = b1; + p2[0] = a2; + p2[1] = b2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for three pairs. + function pairingProd3( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](3); + G2Point[] memory p2 = new G2Point[](3); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + return pairing(p1, p2); + } + + /// Convenience method for a pairing check for four pairs. + function pairingProd4( + G1Point memory a1, + G2Point memory a2, + G1Point memory b1, + G2Point memory b2, + G1Point memory c1, + G2Point memory c2, + G1Point memory d1, + G2Point memory d2 + ) internal view returns (bool) { + G1Point[] memory p1 = new G1Point[](4); + G2Point[] memory p2 = new G2Point[](4); + p1[0] = a1; + p1[1] = b1; + p1[2] = c1; + p1[3] = d1; + p2[0] = a2; + p2[1] = b2; + p2[2] = c2; + p2[3] = d2; + return pairing(p1, p2); + } } + contract VerifierF8_2 { - using Pairing for *; - struct VerifyingKey { - Pairing.G1Point alfa1; - Pairing.G2Point beta2; - Pairing.G2Point gamma2; - Pairing.G2Point delta2; - Pairing.G1Point[] IC; - } - struct Proof { - Pairing.G1Point A; - Pairing.G2Point B; - Pairing.G1Point C; - } - function verifyingKey() internal pure returns (VerifyingKey memory vk) { - vk.alfa1 = Pairing.G1Point( - 20491192805390485299153009773594534940189261866228447918068658471970481763042, - 9383485363053290200918347156157836566562967994039712273449902621266178545958 - ); + using Pairing for *; + struct VerifyingKey { + Pairing.G1Point alfa1; + Pairing.G2Point beta2; + Pairing.G2Point gamma2; + Pairing.G2Point delta2; + Pairing.G1Point[] IC; + } + struct Proof { + Pairing.G1Point A; + Pairing.G2Point B; + Pairing.G1Point C; + } - vk.beta2 = Pairing.G2Point( - [4252822878758300859123897981450591353533073413197771768651442665752259397132, - 6375614351688725206403948262868962793625744043794305715222011528459656738731], - [21847035105528745403288232691147584728191162732299865338377159692350059136679, - 10505242626370262277552901082094356697409835680220590971873171140371331206856] - ); - vk.gamma2 = Pairing.G2Point( - [11559732032986387107991004021392285783925812861821192530917403151452391805634, - 10857046999023057135944570762232829481370756359578518086990519993285655852781], - [4082367875863433681332203403145435568316851327593401208105741076214120093531, - 8495653923123431417604973247489272438418190587263600148770280649306958101930] - ); - vk.delta2 = Pairing.G2Point( - [4101819593354226489627185744948219146284254260020747337516454817323872623153, - 16312926127837412914304749388062040631223734098480854938577169349206671145005], - [15798396951803195663306539706407541090525701543970076947342060111984421473921, - 6146495669243812966711312184546984117478458329596951681464984462576273302147] - ); - vk.IC = new Pairing.G1Point[](16); - - vk.IC[0] = Pairing.G1Point( - 17406446840619355482960854845673857514368286230877361498724308666892463540222, - 9888022385403265228092911417423018587882222845026637861588403008032699306065 - ); - - vk.IC[1] = Pairing.G1Point( - 3101636353144809266631290022771685817296007240357556516857369740941254411638, - 7782114554541741202604410551986066076079061571455795328318586857747338312152 - ); - - vk.IC[2] = Pairing.G1Point( - 3249963135958910799618758685558142868098534198539578062283924836947418340008, - 2536984057766249468298821365219900871233204275975503507139637734141413488132 - ); - - vk.IC[3] = Pairing.G1Point( - 19973240051223807380418884182430302573134011303331683385550622936625359097527, - 15472548698786788289533128579963071125189738393135357125417522919771411307325 - ); - - vk.IC[4] = Pairing.G1Point( - 16100603681177454032734747454146365623879586006813352703635987411940054435204, - 18513523202922728565016469671724410658823137173105459533252153953534765325740 - ); - - vk.IC[5] = Pairing.G1Point( - 13385652744343925319927726559087500089092460492521316840498748006979293824753, - 10331069569283047275117949346574546495465544951058847842999358513411439871588 - ); - - vk.IC[6] = Pairing.G1Point( - 7091587407808030572634303454363396723058710878239991455559070569397080193376, - 11786178010375605319477196293449020160990226771409951425597258522825529437812 - ); - - vk.IC[7] = Pairing.G1Point( - 3370498181616639507010336589240374425473328213277062178266993569278441182496, - 208554759356562659951923102628100000927795571447875462259917619133215987764 - ); - - vk.IC[8] = Pairing.G1Point( - 10114559279113725779416180939244626152674077910532448067618791591257514571777, - 1085943459246208068457818459257966463429777365135542792499492949872606077345 - ); - - vk.IC[9] = Pairing.G1Point( - 12228234228665331580109643582556777166258343180613023891373989501188911253885, - 5889395245956708949140696271075490321990337946385843903772262316292791940797 - ); - - vk.IC[10] = Pairing.G1Point( - 17920208395613026536389768416043781368438348497437244851060776764815837334537, - 20909939458473048951373785017956219364678580930949340023269791411998953707426 - ); - - vk.IC[11] = Pairing.G1Point( - 7502603285914654513825913412031531851423807672335412529628895169218378888441, - 16582735949321959327619916801162656624847308625828481061520494584806700299148 - ); - - vk.IC[12] = Pairing.G1Point( - 2674059411878044773756304145971572087677670777816426293482211884221424959524, - 5483955026785293525762145273220520218985844993752607504277008070993844970132 - ); - - vk.IC[13] = Pairing.G1Point( - 13372220490650160535482193456375141208052300303323340635570407061298426612599, - 20122765984176750966042398652358842750887743273774706546530919695759550796566 - ); - - vk.IC[14] = Pairing.G1Point( - 20917060074018568223625938173313521240079198964473935545023634815244471273, - 15345215138767012251296220242585644611982255668215762397847467510129713752645 - ); - - vk.IC[15] = Pairing.G1Point( - 17604295447509898327111073665512607001283051640657890019140652679562830622451, - 21657381944268282064087379960365132709558008408156851206764358949799538905626 - ); - - } - function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { - uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - VerifyingKey memory vk = verifyingKey(); - require(input.length + 1 == vk.IC.length,"verifier-bad-input"); - // Compute the linear combination vk_x - Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); - for (uint i = 0; i < input.length; i++) { - require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field"); - vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); - } - vk_x = Pairing.addition(vk_x, vk.IC[0]); - if (!Pairing.pairingProd4( - Pairing.negate(proof.A), proof.B, - vk.alfa1, vk.beta2, - vk_x, vk.gamma2, - proof.C, vk.delta2 - )) return 1; - return 0; - } - /// @return r bool true if proof is valid - function verifyProof( - uint[2] memory a, - uint[2][2] memory b, - uint[2] memory c, - uint[15] memory input - ) public view returns (bool r) { - Proof memory proof; - proof.A = Pairing.G1Point(a[0], a[1]); - proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); - proof.C = Pairing.G1Point(c[0], c[1]); - uint[] memory inputValues = new uint[](input.length); - for(uint i = 0; i < input.length; i++){ - inputValues[i] = input[i]; - } - if (verify(inputValues, proof) == 0) { - return true; - } else { - return false; - } - } + function verifyingKey() internal pure returns (VerifyingKey memory vk) { + vk.alfa1 = Pairing.G1Point( + 20491192805390485299153009773594534940189261866228447918068658471970481763042, + 9383485363053290200918347156157836566562967994039712273449902621266178545958 + ); + + vk.beta2 = Pairing.G2Point( + [ + 4252822878758300859123897981450591353533073413197771768651442665752259397132, + 6375614351688725206403948262868962793625744043794305715222011528459656738731 + ], + [ + 21847035105528745403288232691147584728191162732299865338377159692350059136679, + 10505242626370262277552901082094356697409835680220590971873171140371331206856 + ] + ); + vk.gamma2 = Pairing.G2Point( + [ + 11559732032986387107991004021392285783925812861821192530917403151452391805634, + 10857046999023057135944570762232829481370756359578518086990519993285655852781 + ], + [ + 4082367875863433681332203403145435568316851327593401208105741076214120093531, + 8495653923123431417604973247489272438418190587263600148770280649306958101930 + ] + ); + vk.delta2 = Pairing.G2Point( + [ + 4101819593354226489627185744948219146284254260020747337516454817323872623153, + 16312926127837412914304749388062040631223734098480854938577169349206671145005 + ], + [ + 15798396951803195663306539706407541090525701543970076947342060111984421473921, + 6146495669243812966711312184546984117478458329596951681464984462576273302147 + ] + ); + vk.IC = new Pairing.G1Point[](16); + + vk.IC[0] = Pairing.G1Point( + 17406446840619355482960854845673857514368286230877361498724308666892463540222, + 9888022385403265228092911417423018587882222845026637861588403008032699306065 + ); + + vk.IC[1] = Pairing.G1Point( + 3101636353144809266631290022771685817296007240357556516857369740941254411638, + 7782114554541741202604410551986066076079061571455795328318586857747338312152 + ); + + vk.IC[2] = Pairing.G1Point( + 3249963135958910799618758685558142868098534198539578062283924836947418340008, + 2536984057766249468298821365219900871233204275975503507139637734141413488132 + ); + + vk.IC[3] = Pairing.G1Point( + 19973240051223807380418884182430302573134011303331683385550622936625359097527, + 15472548698786788289533128579963071125189738393135357125417522919771411307325 + ); + + vk.IC[4] = Pairing.G1Point( + 16100603681177454032734747454146365623879586006813352703635987411940054435204, + 18513523202922728565016469671724410658823137173105459533252153953534765325740 + ); + + vk.IC[5] = Pairing.G1Point( + 13385652744343925319927726559087500089092460492521316840498748006979293824753, + 10331069569283047275117949346574546495465544951058847842999358513411439871588 + ); + + vk.IC[6] = Pairing.G1Point( + 7091587407808030572634303454363396723058710878239991455559070569397080193376, + 11786178010375605319477196293449020160990226771409951425597258522825529437812 + ); + + vk.IC[7] = Pairing.G1Point( + 3370498181616639507010336589240374425473328213277062178266993569278441182496, + 208554759356562659951923102628100000927795571447875462259917619133215987764 + ); + + vk.IC[8] = Pairing.G1Point( + 10114559279113725779416180939244626152674077910532448067618791591257514571777, + 1085943459246208068457818459257966463429777365135542792499492949872606077345 + ); + + vk.IC[9] = Pairing.G1Point( + 12228234228665331580109643582556777166258343180613023891373989501188911253885, + 5889395245956708949140696271075490321990337946385843903772262316292791940797 + ); + + vk.IC[10] = Pairing.G1Point( + 17920208395613026536389768416043781368438348497437244851060776764815837334537, + 20909939458473048951373785017956219364678580930949340023269791411998953707426 + ); + + vk.IC[11] = Pairing.G1Point( + 7502603285914654513825913412031531851423807672335412529628895169218378888441, + 16582735949321959327619916801162656624847308625828481061520494584806700299148 + ); + + vk.IC[12] = Pairing.G1Point( + 2674059411878044773756304145971572087677670777816426293482211884221424959524, + 5483955026785293525762145273220520218985844993752607504277008070993844970132 + ); + + vk.IC[13] = Pairing.G1Point( + 13372220490650160535482193456375141208052300303323340635570407061298426612599, + 20122765984176750966042398652358842750887743273774706546530919695759550796566 + ); + + vk.IC[14] = Pairing.G1Point( + 20917060074018568223625938173313521240079198964473935545023634815244471273, + 15345215138767012251296220242585644611982255668215762397847467510129713752645 + ); + + vk.IC[15] = Pairing.G1Point( + 17604295447509898327111073665512607001283051640657890019140652679562830622451, + 21657381944268282064087379960365132709558008408156851206764358949799538905626 + ); + } + + function verify(uint[] memory input, Proof memory proof) internal view returns (uint) { + uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + VerifyingKey memory vk = verifyingKey(); + require(input.length + 1 == vk.IC.length, "verifier-bad-input"); + // Compute the linear combination vk_x + Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); + for (uint i = 0; i < input.length; i++) { + require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field"); + vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i])); + } + vk_x = Pairing.addition(vk_x, vk.IC[0]); + if ( + !Pairing.pairingProd4( + Pairing.negate(proof.A), + proof.B, + vk.alfa1, + vk.beta2, + vk_x, + vk.gamma2, + proof.C, + vk.delta2 + ) + ) return 1; + return 0; + } + + /// @return r bool true if proof is valid + function verifyProof( + uint[2] memory a, + uint[2][2] memory b, + uint[2] memory c, + uint[15] memory input + ) public view returns (bool r) { + Proof memory proof; + proof.A = Pairing.G1Point(a[0], a[1]); + proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); + proof.C = Pairing.G1Point(c[0], c[1]); + uint[] memory inputValues = new uint[](input.length); + for (uint i = 0; i < input.length; i++) { + inputValues[i] = input[i]; + } + if (verify(inputValues, proof) == 0) { + return true; + } else { + return false; + } + } } diff --git a/packages/contracts/hardhat.config.ts b/packages/contracts/hardhat.config.ts index 9917768c7..17f514775 100644 --- a/packages/contracts/hardhat.config.ts +++ b/packages/contracts/hardhat.config.ts @@ -48,7 +48,7 @@ const config: HardhatUserConfig = { ], }, mocha: { - timeout: 60000, + timeout: 100000, }, gasReporter: { enabled: process.env.REPORT_GAS ? true : false, diff --git a/packages/contracts/test/anchor/addEdges.test.ts b/packages/contracts/test/anchor/addEdges.test.ts index 2ccbf6fbc..a212a2147 100644 --- a/packages/contracts/test/anchor/addEdges.test.ts +++ b/packages/contracts/test/anchor/addEdges.test.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later-only */ +import { BigNumber } from 'ethers'; import { artifacts, contract, assert } from 'hardhat'; const TruffleAssert = require('truffle-assertions'); @@ -52,6 +53,7 @@ contract('LinkableAnchor - [add edges]', async (accounts) => { merkleTreeHeight, MAX_EDGES ); + await AnchorInstance.initialize(); setHandler = (handler, sender, proposalNonce) => AnchorInstance.setHandler(handler, proposalNonce + 1, { @@ -70,7 +72,7 @@ contract('LinkableAnchor - [add edges]', async (accounts) => { it('LinkableAnchor edges should be modifiable by handler only', async () => { const edge = { - root: '0x1111111111111111111111111111111111111111111111111111111111111111', + root: BigNumber.from('0x1111111111111111111111111111111111111111111111111111111111111111'), latestLeafIndex: 1, srcResourceID: '0x1111111111111111111111111111111111111111111111111111001000000001', }; @@ -80,7 +82,7 @@ contract('LinkableAnchor - [add edges]', async (accounts) => { const roots = await AnchorInstance.getLatestNeighborRoots(); assert.strictEqual(roots.length, maxRoots); - assert.strictEqual(roots[0], edge.root); + assert.strictEqual(roots[0].toString(), edge.root); }); it('LinkableAnchor edges should update edgeIndex', async () => { @@ -116,23 +118,22 @@ contract('LinkableAnchor - [add edges]', async (accounts) => { it('latestNeighborRoots should return correct roots', async () => { const edge = { - root: '0x1111111111111111111111111111111111111111111111111111111111111111', + root: BigNumber.from('0x1111111111111111111111111111111111111111111111111111111111111111'), latestLeafIndex: 1, srcResourceID: '0x1111111111111111111111111111111111111111111111111111001000000001', }; await TruffleAssert.passes(updateEdge(edge, accounts[0])); - const roots = await AnchorInstance.getLatestNeighborRoots(); assert.strictEqual(roots.length, maxRoots); - assert.strictEqual(roots[0], edge.root); + assert.strictEqual(roots[0].toString(), edge.root.toString()); }); it('Adding edge should emit correct EdgeAddition event', async () => { const edge = { - sourceChainID: '0x100000000001', - root: '0x1111111111111111111111111111111111111111111111111111111111111111', - latestLeafIndex: 1, + sourceChainID: BigNumber.from('0x100000000001'), + root: BigNumber.from('0x1111111111111111111111111111111111111111111111111111111111111111'), + latestLeafIndex: BigNumber.from(1), srcResourceID: '0x1111111111111111111111111111111111111111111111111111100000000001', }; @@ -140,9 +141,9 @@ contract('LinkableAnchor - [add edges]', async (accounts) => { TruffleAssert.eventEmitted(result, 'EdgeAddition', (ev) => { return ( - ev.chainID == parseInt(edge.sourceChainID, 16) && - ev.latestLeafIndex == edge.latestLeafIndex && - ev.merkleRoot == edge.root + ev.chainID.toString() == edge.sourceChainID.toString() && + ev.latestLeafIndex.toString() == edge.latestLeafIndex && + ev.merkleRoot.toString() == edge.root ); }); }); diff --git a/packages/contracts/test/anchor/updateEdges.test.ts b/packages/contracts/test/anchor/updateEdges.test.ts index 28bdc63bc..5316b628e 100644 --- a/packages/contracts/test/anchor/updateEdges.test.ts +++ b/packages/contracts/test/anchor/updateEdges.test.ts @@ -2,8 +2,9 @@ * Copyright 2021-2022 Webb Technologies * SPDX-License-Identifier: GPL-3.0-or-later-only */ -// @ts-nocheck +import { BigNumber } from 'ethers'; import { artifacts, contract, assert } from 'hardhat'; +import { toFixedHex } from '@webb-tools/sdk-core'; const TruffleAssert = require('truffle-assertions'); const Anchor = artifacts.require('LinkableAnchorMock'); @@ -51,7 +52,7 @@ contract('LinkableAnchor - [update edges]', async (accounts) => { merkleTreeHeight, MAX_EDGES ); - + await AnchorInstance.initialize(); setHandler = (handler, sender, proposalNonce) => AnchorInstance.setHandler(handler, proposalNonce + 1, { from: sender, @@ -111,26 +112,26 @@ contract('LinkableAnchor - [update edges]', async (accounts) => { it('getLatestNeighborRoots should return updated values', async () => { const edge = { - root: '0x1111111111111111111111111111111111111111111111111111111111111111', + root: BigNumber.from('0x1111111111111111111111111111111111111111111111111111111111111111'), latestLeafIndex: 100, - srcResourceID: '0x1111111111111111111111111111111111111111111111111111001000000001', + srcResourceID: '0x1111111111111111111111111111111111111111111111111111100000000001', }; const edgeUpdated = { - root: '0x2222111111111111111111111111111111111111111111111111111111111111', - latestLeafIndex: 101, - srcResourceID: '0x1111111111111111111111111111111111111111111111111111001000000001', + root: BigNumber.from('0x2222111111111111111111111111111111111111111111111111111111111111'), + latestLeafIndex: BigNumber.from(101), + srcResourceID: '0x1111111111111111111111111111111111111111111111111111100000000001', }; await TruffleAssert.passes(updateEdge(edge, accounts[0])); const roots = await AnchorInstance.getLatestNeighborRoots(); assert.strictEqual(roots.length, 1); - assert.strictEqual(roots[0], edge.root); + assert.strictEqual(BigNumber.from(roots[0].toString()), edge.root); await TruffleAssert.passes(updateEdge(edgeUpdated, accounts[0])); const rootsUpdated = await AnchorInstance.getLatestNeighborRoots(); assert.strictEqual(rootsUpdated.length, 1); - assert.strictEqual(rootsUpdated[0], edgeUpdated.root); + assert.strictEqual(BigNumber.from(rootsUpdated[0].toString()), edgeUpdated.root); }); it('Updating edge should emit correct EdgeUpdate event', async () => { @@ -141,18 +142,18 @@ contract('LinkableAnchor - [update edges]', async (accounts) => { srcResourceID: '0x1111111111111111111111111111111111111111111111111111100000000001', }; const edgeUpdated = { - sourceChainID: '0x100000000001', - root: '0x2222111111111111111111111111111111111111111111111111111111111111', - latestLeafIndex: 101, + sourceChainID: BigNumber.from('0x100000000001'), + root: BigNumber.from('0x2222111111111111111111111111111111111111111111111111111111111111'), + latestLeafIndex: BigNumber.from(101), srcResourceID: '0x1111111111111111111111111111111111111111111111111111100000000001', }; await updateEdge(edge, accounts[0]); const result = await updateEdge(edgeUpdated, accounts[0]); TruffleAssert.eventEmitted(result, 'EdgeUpdate', (ev) => { return ( - ev.chainID == parseInt(edgeUpdated.sourceChainID, 16) && - ev.latestLeafIndex == edgeUpdated.latestLeafIndex && - ev.merkleRoot == edgeUpdated.root + ev.chainID.toString() == edgeUpdated.sourceChainID.toString() && + ev.latestLeafIndex.toString() == edgeUpdated.latestLeafIndex.toString() && + ev.merkleRoot.toString() == edgeUpdated.root.toString() ); }); }); diff --git a/packages/contracts/test/identityVAnchor/identityVAnchor.test.ts b/packages/contracts/test/identityVAnchor/identityVAnchor.test.ts index 50a44d7f8..4fc857f5b 100644 --- a/packages/contracts/test/identityVAnchor/identityVAnchor.test.ts +++ b/packages/contracts/test/identityVAnchor/identityVAnchor.test.ts @@ -21,6 +21,7 @@ import { ZkComponents, u8aToHex, UTXOInputs, + ZERO_BYTES32, } from '@webb-tools/utils'; import { BigNumber } from 'ethers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; @@ -369,7 +370,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); const encOutput1 = outputs[0].encrypt(); @@ -407,7 +409,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); const encOutput1 = outputs[0].encrypt(); @@ -457,7 +460,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); let receipt = await tx.wait(); @@ -505,7 +509,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), bob.address, - relayer + relayer, + '' ); const aliceBalanceAfter = await token.balanceOf(alice.address); @@ -532,7 +537,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); aliceBalanceAfterDeposit = await token.balanceOf(alice.address); expect(aliceBalanceAfterDeposit.toString()).equal( @@ -561,7 +567,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); }); @@ -579,7 +586,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); const aliceDoubleSpendTransaction = await generateUTXOForTest( @@ -596,7 +604,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ) ).to.revertedWith('Input is already spent'); }); @@ -620,7 +629,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ) ).to.revertedWith('ERC20: transfer amount exceeds balance'); }); @@ -643,7 +653,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); const aliceBalanceAfterSecondDeposit = await token.balanceOf(alice.address); expect(aliceBalanceAfterFirstDeposit.sub(aliceBalanceAfterSecondDeposit).toString()).equal( @@ -664,7 +675,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); const aliceBalanceAfterJoin = await token.balanceOf(alice.address); expect(aliceBalanceBeforeDeposit.sub(aliceBalanceAfterJoin).toString()).equal('30000000'); @@ -682,7 +694,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), alice.address, - relayer + relayer, + '' ); // alice shouldn't have deposited into tornado as input utxo has enough @@ -709,7 +722,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee, BigNumber.from(0), aliceETHAddress, - relayer + relayer, + '' ); expect(aliceWithdrawAmount.toString()).equal( @@ -718,7 +732,6 @@ describe('IdentityVAnchor for 2 max edges', () => { }); }); it('should reject proofs made against VAnchor empty edges', async () => { - // const tx = await expect(idAnchor.contract.edgeList(BigNumber.from(0))).revertedWith('CALL_EXCEPTION'); const vanchorRoots = await idAnchor.populateVAnchorRootsForProof(); @@ -824,7 +837,31 @@ describe('IdentityVAnchor for 2 max edges', () => { extDataHash.toString() ); - const tx = idAnchor.contract.transact({ ...publicInputs }, extData, { gasLimit: '0x5B8D80' }); + const tx = idAnchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ); await expect(tx).revertedWith('non-existent edge is not set to the default root'); }); it('should reject proofs made against Semaphore empty edges', async () => { @@ -914,7 +951,31 @@ describe('IdentityVAnchor for 2 max edges', () => { extDataHash.toString() ); - const tx = idAnchor.contract.transact({ ...publicInputs }, extData, { gasLimit: '0x5B8D80' }); + const tx = idAnchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [publicInputs.outputCommitments[0], publicInputs.outputCommitments[1]], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ); await expect(tx).revertedWith('non-existent edge is not set to the default root'); }); @@ -930,6 +991,9 @@ describe('IdentityVAnchor for 2 max edges', () => { let aliceExtData: any; let aliceExtDataHash: BigNumber; + let encOutput1; + let encOutput2; + // should be before but it says idAnchor is undefined in this case beforeEach(async () => { const vanchorRoots = await idAnchor.populateVAnchorRootsForProof(); @@ -943,8 +1007,8 @@ describe('IdentityVAnchor for 2 max edges', () => { fee = BigInt(0); - const encOutput1 = outputs[0].encrypt(); - const encOutput2 = outputs[1].encrypt(); + encOutput1 = outputs[0].encrypt(); + encOutput2 = outputs[1].encrypt(); aliceExtData = { recipient: toFixedHex(alice.address, 20), @@ -1016,7 +1080,34 @@ describe('IdentityVAnchor for 2 max edges', () => { invalidInputs.publicAmount = toFixedHex(BigNumber.from(1e10)); await expect( - idAnchor.contract.transact({ ...invalidInputs }, aliceExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + invalidInputs.proof, + ZERO_BYTES32, + { + recipient: aliceExtData.recipient, + extAmount: aliceExtData.extAmount, + relayer: aliceExtData.relayer, + fee: aliceExtData.fee, + refund: aliceExtData.refund, + token: aliceExtData.token, + }, + { + roots: invalidInputs.vanchorRoots, + extensionRoots: invalidInputs.identityRoots, + inputNullifiers: invalidInputs.inputNullifiers, + outputCommitments: [ + invalidInputs.outputCommitments[0], + invalidInputs.outputCommitments[1], + ], + publicAmount: invalidInputs.publicAmount, + extDataHash: invalidInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.revertedWith('Invalid public amount'); }); it('should reject tampering with external data hash', async () => { @@ -1024,7 +1115,34 @@ describe('IdentityVAnchor for 2 max edges', () => { invalidInputs.extDataHash = toFixedHex(BigNumber.from(publicInputs.extDataHash).add(1)); await expect( - idAnchor.contract.transact({ ...invalidInputs }, aliceExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + invalidInputs.proof, + ZERO_BYTES32, + { + recipient: aliceExtData.recipient, + extAmount: aliceExtData.extAmount, + relayer: aliceExtData.relayer, + fee: aliceExtData.fee, + refund: aliceExtData.refund, + token: aliceExtData.token, + }, + { + roots: invalidInputs.vanchorRoots, + extensionRoots: invalidInputs.identityRoots, + inputNullifiers: invalidInputs.inputNullifiers, + outputCommitments: [ + invalidInputs.outputCommitments[0], + invalidInputs.outputCommitments[1], + ], + publicAmount: invalidInputs.publicAmount, + extDataHash: invalidInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Incorrect external data hash'); }); @@ -1034,7 +1152,34 @@ describe('IdentityVAnchor for 2 max edges', () => { BigNumber.from(publicInputs.outputCommitments[0]).add(1) ); await expect( - idAnchor.contract.transact({ ...invalidInputs }, aliceExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + invalidInputs.proof, + ZERO_BYTES32, + { + recipient: aliceExtData.recipient, + extAmount: aliceExtData.extAmount, + relayer: aliceExtData.relayer, + fee: aliceExtData.fee, + refund: aliceExtData.refund, + token: aliceExtData.token, + }, + { + roots: invalidInputs.vanchorRoots, + extensionRoots: invalidInputs.identityRoots, + inputNullifiers: invalidInputs.inputNullifiers, + outputCommitments: [ + invalidInputs.outputCommitments[0], + invalidInputs.outputCommitments[1], + ], + publicAmount: invalidInputs.publicAmount, + extDataHash: invalidInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Invalid withdraw proof'); }); it('should reject tampering with input commitments', async () => { @@ -1044,7 +1189,34 @@ describe('IdentityVAnchor for 2 max edges', () => { ); await expect( - idAnchor.contract.transact({ ...invalidInputs }, aliceExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + invalidInputs.proof, + ZERO_BYTES32, + { + recipient: aliceExtData.recipient, + extAmount: aliceExtData.extAmount, + relayer: aliceExtData.relayer, + fee: aliceExtData.fee, + refund: aliceExtData.refund, + token: aliceExtData.token, + }, + { + roots: invalidInputs.vanchorRoots, + extensionRoots: invalidInputs.identityRoots, + inputNullifiers: invalidInputs.inputNullifiers, + outputCommitments: [ + invalidInputs.outputCommitments[0], + invalidInputs.outputCommitments[1], + ], + publicAmount: invalidInputs.publicAmount, + extDataHash: invalidInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Invalid withdraw proof'); }); @@ -1055,25 +1227,106 @@ describe('IdentityVAnchor for 2 max edges', () => { 20 ); await expect( - idAnchor.contract.transact({ ...publicInputs }, invalidExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: invalidExtData.recipient, + extAmount: invalidExtData.extAmount, + relayer: invalidExtData.relayer, + fee: invalidExtData.fee, + refund: invalidExtData.refund, + token: invalidExtData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + publicInputs.outputCommitments[0], + publicInputs.outputCommitments[1], + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Incorrect external data hash'); }); it('should reject tampering with extData extAmount', async () => { const invalidExtData = aliceExtData; invalidExtData.extAmount = toFixedHex(aliceDepositAmount * 100, 20); await expect( - idAnchor.contract.transact({ ...publicInputs }, invalidExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: invalidExtData.recipient, + extAmount: invalidExtData.extAmount, + relayer: invalidExtData.relayer, + fee: invalidExtData.fee, + refund: invalidExtData.refund, + token: invalidExtData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + publicInputs.outputCommitments[0], + publicInputs.outputCommitments[1], + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Incorrect external data hash'); }); it('should reject tampering with extData fee', async () => { const invalidExtData = aliceExtData; invalidExtData.fee = toFixedHex(fee + BigInt(1000), 20); await expect( - idAnchor.contract.transact({ ...publicInputs }, invalidExtData, { gasLimit: '0x5B8D80' }) + idAnchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: invalidExtData.recipient, + extAmount: invalidExtData.extAmount, + relayer: invalidExtData.relayer, + fee: invalidExtData.fee, + refund: invalidExtData.refund, + token: invalidExtData.token, + }, + { + roots: publicInputs.vanchorRoots, + extensionRoots: publicInputs.identityRoots, + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + publicInputs.outputCommitments[0], + publicInputs.outputCommitments[1], + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + }, + { gasLimit: '0x5B8D80' } + ) ).to.be.revertedWith('Incorrect external data hash'); }); }); - describe('# transactWrap', () => { + describe('#transact and wrap', () => { let wrappedIdAnchor: IdentityVAnchor; let wrapFee: number = 0; // between 0-10000 @@ -1130,19 +1383,20 @@ describe('IdentityVAnchor for 2 max edges', () => { const relayer = '0x2111111111111111111111111111111111111111'; const aliceDepositAmount = 1e7; const aliceDepositUtxo = await generateUTXOForTest(chainID, aliceKeypair, aliceDepositAmount); - const tx = await wrappedIdAnchor.transactWrap( - token.address, + const tx = await wrappedIdAnchor.transact( aliceKeypair, [], [aliceDepositUtxo], fee, BigNumber.from(0), '0', - relayer + relayer, + token.address ); const balTokenAfterDepositSender = await token.balanceOf(alice.address); - // Fix: this aint working. Might be bc of gas cost? - // expect(balTokenBeforeDepositSender.sub(balTokenAfterDepositSender).toString()).equal('10000100'); + expect(balTokenBeforeDepositSender.sub(balTokenAfterDepositSender).toString()).equal( + aliceDepositAmount.toString() + ); const balWrappedTokenAfterDepositAnchor = await wrappedToken.balanceOf( wrappedIdAnchor.contract.address @@ -1151,13 +1405,13 @@ describe('IdentityVAnchor for 2 max edges', () => { expect(balWrappedTokenAfterDepositAnchor.toString()).equal('10000000'); expect(balWrappedTokenAfterDepositSender.toString()).equal('0'); }); + it('should wrap and deposit', async () => { const balTokenBeforeDepositSender = await token.balanceOf(alice.address); const relayer = '0x2111111111111111111111111111111111111111'; const aliceDepositAmount = 1e7; let aliceDepositUtxo = await generateUTXOForTest(chainID, aliceKeypair, aliceDepositAmount); - await wrappedIdAnchor.transactWrap( - token.address, + await wrappedIdAnchor.transact( aliceKeypair, [], [aliceDepositUtxo], @@ -1165,7 +1419,8 @@ describe('IdentityVAnchor for 2 max edges', () => { BigNumber.from(0), BigNumber.from(0), '0', - relayer + relayer, + token.address ); const balTokenAfterDepositSender = await token.balanceOf(alice.address); // Fix: why the magic 2? no idea @@ -1193,15 +1448,15 @@ describe('IdentityVAnchor for 2 max edges', () => { const aliceChangeAmount = 0; const aliceChangeUtxo = await generateUTXOForTest(chainID, aliceKeypair, aliceChangeAmount); - const tx1 = await wrappedIdAnchor.transactWrap( - token.address, + const tx1 = await wrappedIdAnchor.transact( aliceKeypair, [aliceDepositUtxo], [aliceChangeUtxo], BigNumber.from(0), BigNumber.from(0), alice.address, - relayer + relayer, + token.address ); const balTokenAfterWithdrawAndUnwrapSender = await token.balanceOf(alice.address); diff --git a/packages/contracts/test/open-vanchor/openVAnchor.test.ts b/packages/contracts/test/open-vanchor/openVAnchor.test.ts index 493e29ce3..f7d174d7d 100644 --- a/packages/contracts/test/open-vanchor/openVAnchor.test.ts +++ b/packages/contracts/test/open-vanchor/openVAnchor.test.ts @@ -63,7 +63,7 @@ describe('Open VAnchor Contract', () => { sender ); // Allow the contracts to spend the token - let tx = await token.approveSpending(webbToken.contract.address); + let tx = await token.approveSpending(webbToken.contract.address, BigNumber.from(1e7)); await tx.wait(); await webbToken.grantMinterRole(openVAnchor.contract.address); @@ -281,7 +281,7 @@ describe('Open VAnchor Contract - cross chain', () => { // GanacheWallet2 wants to send `depositAmount` tokens to the `recipient` on chain 1. await vAnchor2.setSigner(ganacheWallet2); // First GanacheWallet2 must approve the `webbToken2` to spend `tokenInstance2` tokens. - let tx = await tokenInstance2.approveSpending(webbToken2.contract.address); + let tx = await tokenInstance2.approveSpending(webbToken2.contract.address, BigNumber.from(1e7)); await tx.wait(); // Then, GanacheWallet2 can deposit `depositAmount` tokens to the vanchor2. await vAnchor2.wrapAndDeposit( diff --git a/packages/contracts/test/trees/MerkleForest.test.ts b/packages/contracts/test/trees/MerkleForest.test.ts index 36c8c92b6..800f95750 100644 --- a/packages/contracts/test/trees/MerkleForest.test.ts +++ b/packages/contracts/test/trees/MerkleForest.test.ts @@ -85,9 +85,9 @@ describe('MerkleForest', () => { const initialSubtreeRoot = await merkleForest.getLastSubtreeRoot(0); assert.strictEqual(initialSubtreeRoot.toString(), defaultSubtreeRoot.toString()); const subtree = await merkleForest.subtrees(0); - assert.strictEqual(await subtree.depth.toNumber(), tree.levels); + assert.strictEqual(subtree.depth.toString(), tree.levels.toString()); const forestData = await merkleForest.merkleForest(); - assert.strictEqual(forestData.depth.toNumber(), forest.levels); + assert.strictEqual(forestData.depth.toString(), forest.levels.toString()); assert.strictEqual(0, forestData.numberOfLeaves); assert.strictEqual(0, await forestData.currentRootIndex); @@ -198,13 +198,13 @@ describe('MerkleForest', () => { await merkleForest.deployed(); // const MerkleTreeWithHistory = new MerkleTreeWithHistory__factory(); const initialIndex = await merkleForest.currSubtreeIndex(); - assert.strictEqual(initialIndex.toNumber(), 0); + assert.strictEqual(initialIndex, 0); for (let i = 0; i < 2 ** levels; i++) { TruffleAssert.passes(await merkleForest.insertTest(toFixedHex(i + 42))); } await merkleForest.insertTest(toFixedHex(2 ** levels + 42)); const endIndex = await merkleForest.currSubtreeIndex(); - assert.strictEqual(endIndex.toNumber(), 1); + assert.strictEqual(endIndex, 1); await TruffleAssert.reverts( merkleForest.insertSubtreeTest(0, toFixedHex(1337)), @@ -233,7 +233,7 @@ describe('MerkleForest', () => { await merkleForest.deployed(); // const MerkleTreeWithHistory = new MerkleTreeWithHistory__factory(); const initialIndex = await merkleForest.currSubtreeIndex(); - assert.strictEqual(initialIndex.toNumber(), 0); + assert.strictEqual(initialIndex, 0); for (let i = 0; i <= 2 ** levels; i++) { TruffleAssert.passes( await merkleForest.insertTwoTest(toFixedHex(i + 43), toFixedHex(i + 42)) @@ -241,7 +241,7 @@ describe('MerkleForest', () => { } // await merkleForest.insertTest(toFixedHex(2 ** levels + 42)) const endIndex = await merkleForest.currSubtreeIndex(); - assert.strictEqual(endIndex.toNumber(), 2); + assert.strictEqual(endIndex, 2); await TruffleAssert.reverts( merkleForest.insertSubtreeTest(0, toFixedHex(1337)), diff --git a/packages/contracts/test/trees/MerkleTreePoseidon.test.ts b/packages/contracts/test/trees/MerkleTreePoseidon.test.ts index 3007bc483..244ceaa5c 100644 --- a/packages/contracts/test/trees/MerkleTreePoseidon.test.ts +++ b/packages/contracts/test/trees/MerkleTreePoseidon.test.ts @@ -35,10 +35,10 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => { it('should initialize', async () => { const zeroValue = await merkleTreeWithHistory.ZERO_VALUE(); const firstSubtree = await merkleTreeWithHistory.filledSubtrees(0); - assert.strictEqual(firstSubtree, toFixedHex(BigNumber.from(zeroValue.toString()))); + assert.strictEqual(firstSubtree.toString(), zeroValue.toString()); const firstZero = await hasherInstance.contract.zeros(0); - assert.strictEqual(firstZero, toFixedHex(BigNumber.from(zeroValue.toString()))); + assert.strictEqual(toFixedHex(firstZero), toFixedHex(BigNumber.from(zeroValue.toString()))); }); }); @@ -71,7 +71,7 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => { await tree.insert(i); let { merkleRoot } = await tree.path(i - 1); rootFromContract = await merkleTreeWithHistory.getLastRoot(); - assert.strictEqual(toFixedHex(merkleRoot), rootFromContract.toString()); + assert.strictEqual(merkleRoot.toString(), rootFromContract.toString()); } }); @@ -134,7 +134,10 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => { const { merkleRoot, pathElements, pathIndices } = await tree.path(0); await merkleTreeWithHistory.insert(toFixedHex(commitment), { from: sender }); const rootFromContract = await merkleTreeWithHistory.getLastRoot(); - assert.strictEqual(toFixedHex(merkleRoot), rootFromContract.toString()); + assert.strictEqual( + merkleRoot.toString(), + BigNumber.from(rootFromContract.toString()).toString() + ); let curr = commitment; for (var i = 0; i < pathElements.length; i++) { diff --git a/packages/contracts/test/vanchor/ChainalysisVAnchor.test.ts b/packages/contracts/test/vanchor/ChainalysisVAnchor.test.ts index 4bb01fbc6..c9ea7097a 100644 --- a/packages/contracts/test/vanchor/ChainalysisVAnchor.test.ts +++ b/packages/contracts/test/vanchor/ChainalysisVAnchor.test.ts @@ -159,6 +159,7 @@ describe('ChainalysisVAnchor', () => { 0, '0', '0', + '', {} ) ).to.be.revertedWith('SanctionFilter: Sanctioned address'); diff --git a/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts b/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts index 6cd351a7e..415b0016e 100644 --- a/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts +++ b/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts @@ -13,10 +13,10 @@ import { } from '@webb-tools/sdk-core'; import { IVariableAnchorExtData, IVariableAnchorPublicInputs } from '@webb-tools/interfaces'; import { hexToU8a, u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils'; -import { VAnchor as VAnchorContract } from '../../../typechain'; +import { VAnchorTree as VAnchorContract } from '../../../typechain'; export class SetupTxVAnchorMock extends VAnchor { - private rootsForProof: string[]; + private rootsForProof: BigNumber[]; constructor( contract: VAnchorContract, @@ -25,7 +25,7 @@ export class SetupTxVAnchorMock extends VAnchor { maxEdges: number, smallCircuitZkComponents: ZkComponents, largeCircuitZkComponents: ZkComponents, - roots: string[] + roots: BigNumber[] ) { super( contract, @@ -44,9 +44,9 @@ export class SetupTxVAnchorMock extends VAnchor { extAmount: BigNumberish, fee: BigNumberish, refund: BigNumberish, - token: string, recipient: string, relayer: string, + wrapUnwrapToken: string, leavesMap: Record ) { // first, check if the merkle root is known on chain - if not, then update @@ -73,7 +73,7 @@ export class SetupTxVAnchorMock extends VAnchor { inputUtxos: inputs, leavesMap, leafIds, - roots: this.rootsForProof.map((root) => hexToU8a(root)), + roots: this.rootsForProof.map((root) => hexToU8a(root.toHexString())), chainId: chainId.toString(), output: outputs, encryptedCommitments, @@ -82,7 +82,7 @@ export class SetupTxVAnchorMock extends VAnchor { inputs.length > 2 ? this.largeCircuitZkComponents.zkey : this.smallCircuitZkComponents.zkey, relayer: hexToU8a(relayer), refund: BigNumber.from(refund).toString(), - token: hexToU8a(token), + token: hexToU8a(wrapUnwrapToken), recipient: hexToU8a(recipient), extAmount: toFixedHex(BigNumber.from(extAmount)), fee: BigNumber.from(fee).toString(), @@ -101,14 +101,13 @@ export class SetupTxVAnchorMock extends VAnchor { )); const proof = await this.provingManager.prove('vanchor', proofInput); - const publicInputs: IVariableAnchorPublicInputs = this.generatePublicInputs( proof.proof, this.rootsForProof, inputs, outputs, proofInput.publicAmount, - u8aToHex(proof.extDataHash) + proof.extDataHash ); const extData: IVariableAnchorExtData = { diff --git a/packages/contracts/test/vanchor/vanchor.test.ts b/packages/contracts/test/vanchor/vanchor.test.ts index 7174c9dd6..660f2148f 100644 --- a/packages/contracts/test/vanchor/vanchor.test.ts +++ b/packages/contracts/test/vanchor/vanchor.test.ts @@ -21,6 +21,7 @@ import { getChainIdType, ZkComponents, u8aToHex, + ZERO_BYTES32, } from '@webb-tools/utils'; import { BigNumber } from 'ethers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; @@ -40,6 +41,8 @@ import { VAnchor, PoseidonHasher } from '@webb-tools/anchors'; import { Verifier } from '@webb-tools/vbridge'; import { writeFileSync } from 'fs'; import { SetupTxVAnchorMock } from './mocks/SetupTxVAnchorMock'; +import { isTupleTypeNode } from 'typescript'; +import { TokenWrapper__factory } from 'packages/contracts/typechain'; const BN = require('bn.js'); @@ -47,7 +50,7 @@ const path = require('path'); const snarkjs = require('snarkjs'); const { toBN } = require('web3-utils'); -describe('VAnchor for 2 max edges', () => { +describe('VAnchor for 1 max edge', () => { let anchor: VAnchor; const levels = 30; @@ -129,13 +132,29 @@ describe('VAnchor for 2 max edges', () => { await token.deployed(); await token.mint(sender.address, '10000000000000000000000'); + // create wrapped token + const name = 'webbETH'; + const symbol = 'webbETH'; + const dummyFeeRecipient = '0x0000000000010000000010000000000000000000'; + const wrappedTokenFactory = new WrappedTokenFactory(wallet); + wrappedToken = await wrappedTokenFactory.deploy(name, symbol); + await wrappedToken.deployed(); + await wrappedToken.initialize( + 0, + dummyFeeRecipient, + sender.address, + '10000000000000000000000000', + true + ); + await wrappedToken.add(token.address, (await wrappedToken.proposalNonce()).add(1)); + // create Anchor anchor = await VAnchor.createVAnchor( verifier.contract.address, levels, hasherInstance.contract.address, sender.address, - token.address, + wrappedToken.address, 1, zkComponents2_2, zkComponents16_2, @@ -147,8 +166,9 @@ describe('VAnchor for 2 max edges', () => { BigNumber.from(tokenDenomination).mul(1_000_000), 2 ); - - await token.approve(anchor.contract.address, '1000000000000000000000000'); + const MINTER_ROLE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('MINTER_ROLE')); + await wrappedToken.grantRole(MINTER_ROLE, anchor.contract.address); + await token.approve(wrappedToken.address, '1000000000000000000000000'); create2InputWitness = async (data: any) => { const witnessCalculator = require('../../solidity-fixtures/solidity-fixtures/vanchor_2/2/witness_calculator.cjs'); @@ -170,8 +190,8 @@ describe('VAnchor for 2 max edges', () => { describe('snark proof native verification on js side', () => { it('should work', async () => { - const relayer = '0x2111111111111111111111111111111111111111'; const extAmount = 1e7; + const relayer = '0x2111111111111111111111111111111111111111'; const aliceDepositAmount = 1e7; const roots = await anchor.populateRootsForProof(); const inputs = [await generateUTXOForTest(chainID), await generateUTXOForTest(chainID)]; @@ -254,7 +274,6 @@ describe('VAnchor for 2 max edges', () => { // Alice deposits into tornado pool const aliceDepositAmount = 1e7; const aliceDepositUtxo = await generateUTXOForTest(chainID, aliceDepositAmount); - await anchor.registerAndTransact( sender.address, aliceDepositUtxo.keypair.toString(), @@ -264,6 +283,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); }); @@ -285,8 +305,9 @@ describe('VAnchor for 2 max edges', () => { [aliceDepositUtxo, await generateUTXOForTest(chainID)], BigNumber.from(fee), BigNumber.from(0), - '0', + sender.address, relayer, + token.address, {} ); @@ -299,7 +320,7 @@ describe('VAnchor for 2 max edges', () => { //Step 3 Check relayers balance assert.strictEqual( - (await token.balanceOf(relayer)).toString(), + (await wrappedToken.balanceOf(relayer)).toString(), BigNumber.from(fee).toString() ); }); @@ -318,6 +339,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -333,17 +355,9 @@ describe('VAnchor for 2 max edges', () => { const anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); - await anchor.transact( - [aliceDepositUtxo], - [aliceRefreshUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceRefreshUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }); }); it('should spend input utxo and split', async () => { @@ -360,6 +374,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -372,13 +387,14 @@ describe('VAnchor for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo], [aliceSplitUtxo1, aliceSplitUtxo2], - { - [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + { + [chainID.toString()]: anchorLeaves, + } ); }); @@ -395,6 +411,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -411,17 +428,9 @@ describe('VAnchor for 2 max edges', () => { blinding: hexToU8a(randomBN().toHexString()), }); - await anchor.transact( - [], - [aliceDepositUtxo2], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([], [aliceDepositUtxo2], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }); anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -437,13 +446,14 @@ describe('VAnchor for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo1, aliceDepositUtxo2], [aliceJoinUtxo], - { - [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + { + [chainID.toString()]: anchorLeaves, + } ); }); @@ -469,6 +479,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -484,17 +495,9 @@ describe('VAnchor for 2 max edges', () => { keypair: aliceDepositUtxo1.keypair, }); - await anchor.transact( - [], - [aliceDepositUtxo3], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([], [aliceDepositUtxo3], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }); anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -519,13 +522,14 @@ describe('VAnchor for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo1, aliceDepositUtxo2, aliceDepositUtxo3], [aliceJoinUtxo], - { - [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + { + [chainID.toString()]: anchorLeaves, + } ); }).timeout(120000); @@ -542,6 +546,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -558,20 +563,13 @@ describe('VAnchor for 2 max edges', () => { }); const aliceETHAddress = '0xDeaD00000000000000000000000000000000BEEf'; - await anchor.transact( - [aliceDepositUtxo], - [aliceChangeUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - aliceETHAddress, - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceChangeUtxo], 0, 0, aliceETHAddress, '0', '', { + [chainID.toString()]: anchorLeaves, + }); + assert.strictEqual( aliceWithdrawAmount.toString(), - await (await token.balanceOf(aliceETHAddress)).toString() + await (await wrappedToken.balanceOf(aliceETHAddress)).toString() ); }); @@ -596,6 +594,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -613,32 +612,16 @@ describe('VAnchor for 2 max edges', () => { keypair: aliceDepositUtxo.keypair, }); - await anchor.transact( - [aliceDepositUtxo], - [aliceTransferUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceTransferUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }); anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); await TruffleAssert.reverts( - anchor.transact( - [aliceDepositUtxo], - [aliceTransferUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ), + anchor.transact([aliceDepositUtxo], [aliceTransferUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }), 'Input is already spent' ); }); @@ -666,6 +649,7 @@ describe('VAnchor for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -690,17 +674,9 @@ describe('VAnchor for 2 max edges', () => { }); //Step 4: Check that step 3 fails await TruffleAssert.reverts( - anchor.transact( - [aliceDepositUtxo], - [aliceOutputUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ), + anchor.transact([aliceDepositUtxo], [aliceOutputUtxo], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }), 'ERC20: transfer amount exceeds balance' ); }); @@ -786,10 +762,17 @@ describe('VAnchor for 2 max edges', () => { let incorrectPublicInputs = VAnchor.convertToPublicInputsStruct(incorrectPublicInputArgs); let extAmountInputs = VAnchor.convertToExtDataStruct(extDataArgs); - //anchor.contract.transact(incorrectPublicInputs, extAmountInputs, { gasPrice: '100' }); - await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid public amount' ); @@ -806,7 +789,16 @@ describe('VAnchor for 2 max edges', () => { incorrectPublicInputs = VAnchor.convertToPublicInputsStruct(incorrectPublicInputArgs); await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -824,12 +816,19 @@ describe('VAnchor for 2 max edges', () => { ]; incorrectPublicInputs = VAnchor.convertToPublicInputsStruct(incorrectPublicInputArgs); - await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid withdraw proof' ); - // input nullifier incorrectPublicInputArgs = [ `0x${proofEncoded}`, @@ -843,7 +842,16 @@ describe('VAnchor for 2 max edges', () => { incorrectPublicInputs = VAnchor.convertToPublicInputsStruct(incorrectPublicInputArgs); await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid withdraw proof' ); @@ -863,7 +871,16 @@ describe('VAnchor for 2 max edges', () => { let incorrectExtAmountInputs = VAnchor.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -882,7 +899,16 @@ describe('VAnchor for 2 max edges', () => { incorrectExtAmountInputs = VAnchor.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -901,7 +927,16 @@ describe('VAnchor for 2 max edges', () => { incorrectExtAmountInputs = VAnchor.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); }); @@ -941,7 +976,7 @@ describe('VAnchor for 2 max edges', () => { }); // Insert the UTXO into the tree - receipt = await anchor.transact([], [aliceTransferUtxo], {}, 0, 0, '0', '0'); + receipt = await anchor.transact([], [aliceTransferUtxo], 0, 0, '0', '0', token.address, {}); // Bob queries encrypted commitments on chain const encryptedCommitments: string[] = receipt.events @@ -980,13 +1015,14 @@ describe('VAnchor for 2 max edges', () => { receipt = await anchor.transact( spendableUtxos, [], - { - [chainID.toString()]: leaves, - }, 0, 0, recipient.address, - '0' + '0', + token.address, + { + [chainID.toString()]: leaves, + } ); // get balances after transfer interactions @@ -1007,22 +1043,14 @@ describe('VAnchor for 2 max edges', () => { const aliceDepositAmount = 1e7; const aliceDepositUtxo = await generateUTXOForTest(chainID, aliceDepositAmount); - await anchor.transact([], [aliceDepositUtxo], {}, 0, 0, '0', '0'); + await anchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); const anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); // withdrawal - await anchor.transact( - [aliceDepositUtxo], - [], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - sender.address, - '0' - ); + await anchor.transact([aliceDepositUtxo], [], 0, 0, sender.address, '0', '', { + [chainID.toString()]: anchorLeaves, + }); //build merkle tree start const filter = anchor.contract.filters.NewCommitment(); @@ -1056,7 +1084,7 @@ describe('VAnchor for 2 max edges', () => { // and the tx with NewNullifier event is where alice spent the UTXO }); - it('Should reject proofs made against roots of empty edges', async () => { + it('should reject proofs made against roots of empty edges', async () => { // This test has not been linked to another anchor - edgeList should be empty. await TruffleAssert.reverts(anchor.contract.edgeList(0)); @@ -1083,7 +1111,7 @@ describe('VAnchor for 2 max edges', () => { const fakeRoot = fakeTree.root(); const roots = await anchor.populateRootsForProof(); - roots[1] = fakeRoot.toHexString(); + roots[1] = fakeRoot; const setupVAnchor = new SetupTxVAnchorMock( anchor.contract, @@ -1137,17 +1165,19 @@ describe('VAnchor for 2 max edges', () => { extAmount, 0, 0, - setupVAnchor.token, recipient, '0', + setupVAnchor.token, { [fakeChainId.toString()]: [fakeUtxo.commitment], [chainID.toString()]: [hexToU8a(fakeTree.zeroElement.toHexString())], } ); - await TruffleAssert.reverts( - anchor.contract.transact(publicInputs, extData), + anchor.contract.transact(publicInputs.proof, ZERO_BYTES32, extData, publicInputs, { + encryptedOutput1: outputs[0].encrypt(), + encryptedOutput2: outputs[1].encrypt(), + }), 'non-existent edge is not set to the default root' ); }); @@ -1213,16 +1243,7 @@ describe('VAnchor for 2 max edges', () => { index: null, }); //create a deposit on the anchor already setup - await wrappedAnchor.transactWrap( - token.address, - [], - [aliceDepositUtxo], - '0', - '0', - '0', - '0', - {} - ); + await wrappedAnchor.transact([], [aliceDepositUtxo], '0', '0', '0', '0', token.address, {}); const balTokenAfterDepositSender = await token.balanceOf(sender.address); assert.strictEqual( balTokenBeforeDepositSender.sub(balTokenAfterDepositSender).toString(), @@ -1299,16 +1320,7 @@ describe('VAnchor for 2 max edges', () => { index: null, }); // create a deposit on the anchor already setup - await wrappedAnchor.transactWrap( - token.address, - [], - [aliceDepositUtxo], - '0', - '0', - '0', - '0', - {} - ); + await wrappedAnchor.transact([], [aliceDepositUtxo], '0', '0', '0', '0', token.address, {}); } assert.equal( @@ -1385,7 +1397,7 @@ describe('VAnchor for 2 max edges', () => { keypair, }); //create a deposit on the anchor already setup - await wrappedVAnchor.transactWrap(token.address, [], [aliceDepositUtxo], 0, 0, '0', '0', {}); + await wrappedVAnchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); let anchorLeaves = wrappedVAnchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -1408,14 +1420,14 @@ describe('VAnchor for 2 max edges', () => { amount: aliceChangeAmount.toString(), }); - await wrappedVAnchor.transactWrap( - token.address, + await wrappedVAnchor.transact( [aliceDepositUtxo], [aliceChangeUtxo], 0, 0, sender.address, '0', + token.address, { [chainID.toString()]: anchorLeaves, } @@ -1428,7 +1440,7 @@ describe('VAnchor for 2 max edges', () => { ); }); - it('wrapping fee should work correctly with transactWrap', async () => { + it('wrapping fee should work correctly with transact and wrap', async () => { const signers = await ethers.getSigners(); const wallet = signers[0]; const sender = wallet; @@ -1495,7 +1507,7 @@ describe('VAnchor for 2 max edges', () => { const balUnwrappedTokenBeforeDepositSender = await token.balanceOf(sender.address); const balUnwrappedTokenBeforeDepositWrapper = await token.balanceOf(wrappedToken.address); - await wrappedVAnchor.transactWrap(token.address, [], [aliceDepositUtxo], 0, 0, '0', '0', {}); + await wrappedVAnchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); // Limitations on UTXO index readonly value. create a new UTXO with the proper index. const aliceDepositIndex = wrappedVAnchor.tree.getIndexByElement(aliceDepositUtxo.commitment); @@ -1538,14 +1550,14 @@ describe('VAnchor for 2 max edges', () => { keypair: aliceDepositUtxo.keypair, }); - await wrappedVAnchor.transactWrap( - token.address, + await wrappedVAnchor.transact( [aliceDepositUtxo], [aliceChangeUtxo], 0, 0, sender.address, '0', + token.address, { [chainID.toString()]: anchorLeaves, } @@ -1576,18 +1588,9 @@ describe('VAnchor for 2 max edges', () => { ); await TruffleAssert.passes( - wrappedVAnchor.transactWrap( - token.address, - [aliceChangeUtxo], - [], - 0, - 0, - sender.address, - '0', - { - [chainID.toString()]: anchorLeaves, - } - ) + wrappedVAnchor.transact([aliceChangeUtxo], [], 0, 0, sender.address, '0', token.address, { + [chainID.toString()]: anchorLeaves, + }) ); let originalTokenDifference = expectedSenderTokenOutflows - 2e7; diff --git a/packages/contracts/test/vanchor/vanchorForest.test.ts b/packages/contracts/test/vanchor/vanchorForest.test.ts index 3375e208c..9726a2fd5 100644 --- a/packages/contracts/test/vanchor/vanchorForest.test.ts +++ b/packages/contracts/test/vanchor/vanchorForest.test.ts @@ -22,6 +22,7 @@ import { UTXOInputs, ZkComponents, u8aToHex, + ZERO_BYTES32, } from '@webb-tools/utils'; import { BigNumber } from 'ethers'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; @@ -48,7 +49,7 @@ const path = require('path'); const snarkjs = require('snarkjs'); const { toBN } = require('web3-utils'); -describe('VAnchorForest for 2 max edges', () => { +describe('VAnchorForest for 1 max edge', () => { let anchor: VAnchorForest; const subtreeLevels = 30; @@ -132,6 +133,22 @@ describe('VAnchorForest for 2 max edges', () => { await token.deployed(); await token.mint(sender.address, '10000000000000000000000'); + // create wrapped token + const name = 'webbETH'; + const symbol = 'webbETH'; + const dummyFeeRecipient = '0x0000000000010000000010000000000000000000'; + const wrappedTokenFactory = new WrappedTokenFactory(wallet); + wrappedToken = await wrappedTokenFactory.deploy(name, symbol); + await wrappedToken.deployed(); + await wrappedToken.initialize( + 0, + dummyFeeRecipient, + sender.address, + '10000000000000000000000000', + true + ); + await wrappedToken.add(token.address, (await wrappedToken.proposalNonce()).add(1)); + // create Anchor anchor = await VAnchorForest.createVAnchor( verifier.contract.address, @@ -139,7 +156,7 @@ describe('VAnchorForest for 2 max edges', () => { subtreeLevels, hasherInstance.contract.address, sender.address, - token.address, + wrappedToken.address, 1, zkComponents2_2, zkComponents16_2, @@ -152,7 +169,9 @@ describe('VAnchorForest for 2 max edges', () => { 2 ); - await token.approve(anchor.contract.address, '1000000000000000000000000'); + const MINTER_ROLE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('MINTER_ROLE')); + await wrappedToken.grantRole(MINTER_ROLE, anchor.contract.address); + await token.approve(wrappedToken.address, '1000000000000000000000000'); create2InputWitness = async (data: any) => { const witnessCalculator = require('../../solidity-fixtures/solidity-fixtures/vanchor_2/2/witness_calculator.cjs'); @@ -267,6 +286,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); }); @@ -289,6 +309,7 @@ describe('VAnchorForest for 2 max edges', () => { BigNumber.from(0), '0', relayer, + token.address, {} ); @@ -301,7 +322,7 @@ describe('VAnchorForest for 2 max edges', () => { //Step 3 Check relayers balance assert.strictEqual( - (await token.balanceOf(relayer)).toString(), + (await wrappedToken.balanceOf(relayer)).toString(), BigNumber.from(fee).toString() ); }); @@ -320,6 +341,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -335,17 +357,9 @@ describe('VAnchorForest for 2 max edges', () => { const anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); - await anchor.transact( - [aliceDepositUtxo], - [aliceRefreshUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceRefreshUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }); }); it('should spend input utxo and split', async () => { @@ -362,6 +376,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -374,13 +389,14 @@ describe('VAnchorForest for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo], [aliceSplitUtxo1, aliceSplitUtxo2], - { - [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + { + [chainID.toString()]: anchorLeaves, + } ); }); @@ -397,6 +413,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -413,17 +430,9 @@ describe('VAnchorForest for 2 max edges', () => { blinding: hexToU8a(randomBN().toHexString()), }); - await anchor.transact( - [], - [aliceDepositUtxo2], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([], [aliceDepositUtxo2], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }); anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -439,13 +448,14 @@ describe('VAnchorForest for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo1, aliceDepositUtxo2], [aliceJoinUtxo], - { - [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + { + [chainID.toString()]: anchorLeaves, + } ); }); @@ -471,6 +481,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -486,17 +497,9 @@ describe('VAnchorForest for 2 max edges', () => { keypair: aliceDepositUtxo1.keypair, }); - await anchor.transact( - [], - [aliceDepositUtxo3], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([], [aliceDepositUtxo3], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }); const subtreeLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); const forestLeaves = anchor.forest.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -522,13 +525,12 @@ describe('VAnchorForest for 2 max edges', () => { await anchor.transact( [aliceDepositUtxo1, aliceDepositUtxo2, aliceDepositUtxo3], [aliceJoinUtxo], - { - // [chainID.toString()]: anchorLeaves, - }, 0, 0, '0', - '0' + '0', + '', + {} ); }).timeout(120000); @@ -545,6 +547,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -561,20 +564,12 @@ describe('VAnchorForest for 2 max edges', () => { }); const aliceETHAddress = '0xDeaD00000000000000000000000000000000BEEf'; - await anchor.transact( - [aliceDepositUtxo], - [aliceChangeUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - aliceETHAddress, - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceChangeUtxo], 0, 0, aliceETHAddress, '0', '', { + [chainID.toString()]: anchorLeaves, + }); assert.strictEqual( aliceWithdrawAmount.toString(), - await (await token.balanceOf(aliceETHAddress)).toString() + await (await wrappedToken.balanceOf(aliceETHAddress)).toString() ); }); @@ -599,6 +594,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -616,32 +612,16 @@ describe('VAnchorForest for 2 max edges', () => { keypair: aliceDepositUtxo.keypair, }); - await anchor.transact( - [aliceDepositUtxo], - [aliceTransferUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ); + await anchor.transact([aliceDepositUtxo], [aliceTransferUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }); anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); await TruffleAssert.reverts( - anchor.transact( - [aliceDepositUtxo], - [aliceTransferUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ), + anchor.transact([aliceDepositUtxo], [aliceTransferUtxo], 0, 0, '0', '0', '', { + [chainID.toString()]: anchorLeaves, + }), 'Input is already spent' ); }); @@ -669,6 +649,7 @@ describe('VAnchorForest for 2 max edges', () => { 0, '0', '0', + token.address, {} ); @@ -693,17 +674,9 @@ describe('VAnchorForest for 2 max edges', () => { }); //Step 4: Check that step 3 fails await TruffleAssert.reverts( - anchor.transact( - [aliceDepositUtxo], - [aliceOutputUtxo], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - '0', - '0' - ), + anchor.transact([aliceDepositUtxo], [aliceOutputUtxo], 0, 0, '0', '0', token.address, { + [chainID.toString()]: anchorLeaves, + }), 'ERC20: transfer amount exceeds balance' ); }); @@ -790,10 +763,17 @@ describe('VAnchorForest for 2 max edges', () => { VAnchorForest.convertToPublicInputsStruct(incorrectPublicInputArgs); let extAmountInputs = VAnchorForest.convertToExtDataStruct(extDataArgs); - //anchor.contract.transact(incorrectPublicInputs, extAmountInputs, { gasPrice: '100' }); - await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid public amount' ); @@ -810,7 +790,16 @@ describe('VAnchorForest for 2 max edges', () => { incorrectPublicInputs = VAnchorForest.convertToPublicInputsStruct(incorrectPublicInputArgs); await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -830,7 +819,16 @@ describe('VAnchorForest for 2 max edges', () => { incorrectPublicInputs = VAnchorForest.convertToPublicInputsStruct(incorrectPublicInputArgs); await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid withdraw proof' ); @@ -847,7 +845,16 @@ describe('VAnchorForest for 2 max edges', () => { incorrectPublicInputs = VAnchorForest.convertToPublicInputsStruct(incorrectPublicInputArgs); await TruffleAssert.reverts( - anchor.contract.transact(incorrectPublicInputs, extAmountInputs), + anchor.contract.transact( + incorrectPublicInputs.proof, + ZERO_BYTES32, + extAmountInputs, + incorrectPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Invalid withdraw proof' ); @@ -867,7 +874,16 @@ describe('VAnchorForest for 2 max edges', () => { let incorrectExtAmountInputs = VAnchorForest.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -886,7 +902,16 @@ describe('VAnchorForest for 2 max edges', () => { incorrectExtAmountInputs = VAnchorForest.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); @@ -905,14 +930,23 @@ describe('VAnchorForest for 2 max edges', () => { incorrectExtAmountInputs = VAnchorForest.convertToExtDataStruct(incorrectExtDataArgs); await TruffleAssert.reverts( - anchor.contract.transact(correctPublicInputs, incorrectExtAmountInputs), + anchor.contract.transact( + correctPublicInputs.proof, + ZERO_BYTES32, + incorrectExtAmountInputs, + correctPublicInputs, + { + encryptedOutput1: encOutput1, + encryptedOutput2: encOutput2, + } + ), 'Incorrect external data hash' ); }); // This test is meant to prove that utxo transfer flows are possible, and the receiver // can query on-chain data to construct and spend a utxo generated by the sender. - it('should be able to transfer without direct communication between sender and recipient', async function() { + it('should be able to transfer without direct communication between sender and recipient', async function () { const [sender, recipient] = await ethers.getSigners(); const bobKeypair = new Keypair(); @@ -945,7 +979,7 @@ describe('VAnchorForest for 2 max edges', () => { }); // Insert the UTXO into the tree - receipt = await anchor.transact([], [aliceTransferUtxo], {}, 0, 0, '0', '0'); + receipt = await anchor.transact([], [aliceTransferUtxo], 0, 0, '0', '0', token.address, {}); // Bob queries encrypted commitments on chain const encryptedCommitments: string[] = receipt.events @@ -984,13 +1018,14 @@ describe('VAnchorForest for 2 max edges', () => { receipt = await anchor.transact( spendableUtxos, [], - { - [chainID.toString()]: leaves, - }, 0, 0, recipient.address, - '0' + '0', + token.address, + { + [chainID.toString()]: leaves, + } ); // get balances after transfer interactions @@ -1004,29 +1039,21 @@ describe('VAnchorForest for 2 max edges', () => { assert.strictEqual(bobBalanceAfter.sub(bobBalanceBefore).toString(), '10000000'); }); - it('should be compliant', async function() { + it('should be compliant', async function () { // basically verifier should check if a commitment and a nullifier hash are on chain const [sender] = await ethers.getSigners(); const aliceDepositAmount = 1e7; const aliceDepositUtxo = await generateUTXOForTest(chainID, aliceDepositAmount); - await anchor.transact([], [aliceDepositUtxo], {}, 0, 0, '0', '0'); + await anchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); const anchorLeaves = anchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); // withdrawal - await anchor.transact( - [aliceDepositUtxo], - [], - { - [chainID.toString()]: anchorLeaves, - }, - 0, - 0, - sender.address, - '0' - ); + await anchor.transact([aliceDepositUtxo], [], 0, 0, sender.address, '0', '', { + [chainID.toString()]: anchorLeaves, + }); //build merkle tree start const filter = anchor.contract.filters.NewCommitment(); @@ -1054,12 +1081,9 @@ describe('VAnchorForest for 2 max edges', () => { await anchor.contract.nullifierHashes(toFixedHex('0x' + aliceDepositUtxo.nullifier)), true ); - // expect commitmentV present onchain (it will be in NewCommitment events) - - // in report we can see the tx with NewCommitment event (this is how alice got money) - // and the tx with NewNullifier event is where alice spent the UTXO }); - it('Should reject proofs made against roots of empty edges', async () => { + + it('should reject proofs made against roots of empty edges', async () => { // This test has not been linked to another anchor - edgeList should be empty. await TruffleAssert.reverts(anchor.contract.edgeList(0)); @@ -1113,7 +1137,7 @@ describe('VAnchorForest for 2 max edges', () => { ]; const roots = await anchor.populateRootsForProof(); - roots[1] = fakeRoot.toHexString(); + roots[1] = fakeRoot; const { extData, extDataHash } = await anchor.generateExtData( recipient, @@ -1121,14 +1145,11 @@ describe('VAnchorForest for 2 max edges', () => { relayer, BigNumber.from(fee), BigNumber.from(0), + wrappedToken.address, outputs[0].encrypt(), outputs[1].encrypt() ); - const outputCommitment = outputs.map((x) => - BigNumber.from(u8aToHex(x.commitment)).toString() - ); - // const merkleProofs = [ const merkleProofs = [fakeSubtreeProof, emptyMerkleProof]; const vanchorInput: UTXOInputs = await generateVariableWitnessInput( @@ -1184,8 +1205,6 @@ describe('VAnchorForest for 2 max edges', () => { throw new Error('!!!!!!!!!!!!!!!!!!!!!!!!!!Invalid proof'); } - console.log('PROOF HAS BEEN VERIFIED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!', res); - // const proof = await this.provingManager.prove('vanchor', proofInput); const publicInputs = await anchor.generatePublicInputs(proof); const contractInput = { ...publicInputs, @@ -1193,7 +1212,34 @@ describe('VAnchorForest for 2 max edges', () => { }; await TruffleAssert.reverts( - anchor.contract.transact(contractInput, extData, { gasLimit: '0x5B8D80' }), + anchor.contract.transact( + publicInputs.proof, + ZERO_BYTES32, + { + recipient: extData.recipient, + extAmount: extData.extAmount, + relayer: extData.relayer, + fee: extData.fee, + refund: extData.refund, + token: extData.token, + }, + { + roots: publicInputs.roots, + extensionRoots: '0x', + inputNullifiers: publicInputs.inputNullifiers, + outputCommitments: [ + publicInputs.outputCommitments[0], + publicInputs.outputCommitments[1], + ], + publicAmount: publicInputs.publicAmount, + extDataHash: publicInputs.extDataHash, + }, + { + encryptedOutput1: extData.encryptedOutput1, + encryptedOutput2: extData.encryptedOutput2, + }, + { gasLimit: '0x5B8D80' } + ), 'non-existent edge is not set to the default root' ); }); @@ -1260,16 +1306,7 @@ describe('VAnchorForest for 2 max edges', () => { index: null, }); //create a deposit on the anchor already setup - await wrappedAnchor.transactWrap( - token.address, - [], - [aliceDepositUtxo], - '0', - '0', - '0', - '0', - {} - ); + await wrappedAnchor.transact([], [aliceDepositUtxo], '0', '0', '0', '0', token.address, {}); const balTokenAfterDepositSender = await token.balanceOf(sender.address); assert.strictEqual( balTokenBeforeDepositSender.sub(balTokenAfterDepositSender).toString(), @@ -1347,16 +1384,7 @@ describe('VAnchorForest for 2 max edges', () => { index: null, }); // create a deposit on the anchor already setup - await wrappedAnchor.transactWrap( - token.address, - [], - [aliceDepositUtxo], - '0', - '0', - '0', - '0', - {} - ); + await wrappedAnchor.transact([], [aliceDepositUtxo], '0', '0', '0', '0', token.address, {}); } assert.equal( @@ -1434,7 +1462,7 @@ describe('VAnchorForest for 2 max edges', () => { keypair, }); //create a deposit on the anchor already setup - await wrappedVAnchor.transactWrap(token.address, [], [aliceDepositUtxo], 0, 0, '0', '0', {}); + await wrappedVAnchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); let anchorLeaves = wrappedVAnchor.tree.elements().map((leaf) => hexToU8a(leaf.toHexString())); @@ -1457,14 +1485,14 @@ describe('VAnchorForest for 2 max edges', () => { amount: aliceChangeAmount.toString(), }); - await wrappedVAnchor.transactWrap( - token.address, + await wrappedVAnchor.transact( [aliceDepositUtxo], [aliceChangeUtxo], 0, 0, sender.address, '0', + token.address, { [chainID.toString()]: anchorLeaves, } @@ -1477,7 +1505,7 @@ describe('VAnchorForest for 2 max edges', () => { ); }); - it('wrapping fee should work correctly with transactWrap', async () => { + it('wrapping fee should work correctly with transact', async () => { const signers = await ethers.getSigners(); const wallet = signers[0]; const sender = wallet; @@ -1545,7 +1573,7 @@ describe('VAnchorForest for 2 max edges', () => { const balUnwrappedTokenBeforeDepositSender = await token.balanceOf(sender.address); const balUnwrappedTokenBeforeDepositWrapper = await token.balanceOf(wrappedToken.address); - await wrappedVAnchor.transactWrap(token.address, [], [aliceDepositUtxo], 0, 0, '0', '0', {}); + await wrappedVAnchor.transact([], [aliceDepositUtxo], 0, 0, '0', '0', token.address, {}); // Limitations on UTXO index readonly value. create a new UTXO with the proper index. const aliceDepositIndex = wrappedVAnchor.tree.getIndexByElement(aliceDepositUtxo.commitment); @@ -1588,14 +1616,14 @@ describe('VAnchorForest for 2 max edges', () => { keypair: aliceDepositUtxo.keypair, }); - await wrappedVAnchor.transactWrap( - token.address, + await wrappedVAnchor.transact( [aliceDepositUtxo], [aliceChangeUtxo], 0, 0, sender.address, '0', + token.address, { [chainID.toString()]: anchorLeaves, } @@ -1626,18 +1654,9 @@ describe('VAnchorForest for 2 max edges', () => { ); await TruffleAssert.passes( - wrappedVAnchor.transactWrap( - token.address, - [aliceChangeUtxo], - [], - 0, - 0, - sender.address, - '0', - { - [chainID.toString()]: anchorLeaves, - } - ) + wrappedVAnchor.transact([aliceChangeUtxo], [], 0, 0, sender.address, '0', token.address, { + [chainID.toString()]: anchorLeaves, + }) ); let originalTokenDifference = expectedSenderTokenOutflows - 2e7; diff --git a/packages/contracts/test/vbridge/signatureVBridge.test.ts b/packages/contracts/test/vbridge/signatureVBridge.test.ts index cc6aca784..ab7074457 100644 --- a/packages/contracts/test/vbridge/signatureVBridge.test.ts +++ b/packages/contracts/test/vbridge/signatureVBridge.test.ts @@ -139,7 +139,7 @@ describe('2-sided multichain tests for signature vbridge', () => { // Should be able to retrieve the token address (so we can mint tokens for test scenario) const webbTokenAddress = vBridge.getWebbTokenAddress(chainID1); const webbToken = await MintableToken.tokenFromAddress(webbTokenAddress!, signers[1]); - const tx = await webbToken.mintTokens(signers[2].address, '100000000000000000000000'); + await webbToken.mintTokens(signers[2].address, '100000000000000000000000'); // Get the state of anchors before deposit const sourceAnchorRootBefore = await vAnchor1.contract.getLastRoot(); // Define inputs/outputs for transact function @@ -151,7 +151,7 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); // Transact on the bridge - await vBridge.transact([], [depositUtxo], 0, 0, '0', '0', signers[2]); + await vBridge.transact([], [depositUtxo], 0, 0, '0', '0', '', signers[2]); // Check the state of anchors after deposit let edgeIndex = await vAnchor2.contract.edgeIndex(chainID1); @@ -169,7 +169,7 @@ describe('2-sided multichain tests for signature vbridge', () => { amount: (1e7).toString(), keypair: depositUtxo.keypair, }); - await vBridge.transact([depositUtxo], [transferUtxo], 0, 0, '0', '0', signers[2]); + await vBridge.transact([depositUtxo], [transferUtxo], 0, 0, '0', '0', '', signers[2]); }); it('should create properly initialize governor if passed address', async () => { @@ -288,14 +288,15 @@ describe('2-sided multichain tests for signature vbridge', () => { const tx2 = await webbToken2.mintTokens(ganacheWallet2.address, '100000000000000000000000'); // Transact on the bridge - await vBridge.transact([], [depositUtxo1], 0, 0, '0', '0', signers[1]); - await vBridge.transact([], [depositUtxo2], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [depositUtxo1], 0, 0, '0', '0', '', signers[1]); + await vBridge.transact([], [depositUtxo2], 0, 0, '0', '0', '', ganacheWallet2); // Now there is a bidirectional edge between chain1 and chain2 }); describe('#bridging', () => { it('basic ganache deposit should withdraw on hardhat', async () => { // Fetch information about the anchor to be updated. + console.log('init') const signers = await ethers.getSigners(); const vAnchor1: VAnchor = vBridge.getVAnchor(chainID1)! as VAnchor; @@ -304,6 +305,7 @@ describe('2-sided multichain tests for signature vbridge', () => { const webbTokenAddress1 = vBridge.getWebbTokenAddress(chainID1); const webbToken1 = await MintableToken.tokenFromAddress(webbTokenAddress1!, signers[1]); const signers2BalanceBefore = await webbToken1.getBalance(await signers[2].getAddress()); + console.log('start generating utxos') //ganacheWallet2 makes a deposit with dest chain chainID1 const ganacheDepositUtxo = await CircomUtxo.generateUtxo({ @@ -314,7 +316,7 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); - await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', '', ganacheWallet2); //check latest leaf index is incremented const destAnchorEdge2After = await vAnchor1.contract.edgeList(edgeIndex); @@ -331,6 +333,7 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID1.toString(), chainId: chainID1.toString(), }); + console.log("before transact") await vBridge.transact( [ganacheDepositUtxo], [hardhatWithdrawUtxo], @@ -338,6 +341,7 @@ describe('2-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', signers[2] ); const signers2BalanceAfter = await webbToken1.getBalance(await signers[2].getAddress()); @@ -372,7 +376,7 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID2.toString(), }); - await vBridge.transact([], [hardhatDepositUtxo], 0, 0, '0', '0', signers[1]); + await vBridge.transact([], [hardhatDepositUtxo], 0, 0, '0', '0', '', signers[1]); //check latest leaf index is incremented const destAnchorEdge2After = await vAnchorGanache.contract.edgeList(edgeIndex); @@ -396,6 +400,7 @@ describe('2-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', ganacheWallet2 ); const signers2BalanceAfter = await webbTokenGanache.getBalance( @@ -434,8 +439,8 @@ describe('2-sided multichain tests for signature vbridge', () => { keypair: ganacheDepositUtxo1.keypair, }); - await vBridge.transact([], [ganacheDepositUtxo1], 0, 0, '0', '0', ganacheWallet2); - await vBridge.transact([], [ganacheDepositUtxo2], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo1], 0, 0, '0', '0', '', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo2], 0, 0, '0', '0', '', ganacheWallet2); //check latest leaf index is incremented const destAnchorEdge2After = await vAnchor1.contract.edgeList(edgeIndex); @@ -459,6 +464,7 @@ describe('2-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', signers[2] ); @@ -495,8 +501,8 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID2.toString(), chainId: chainID1.toString(), }); - await vBridge.transact([], [ganacheDepositUtxo1], 0, 0, '0', '0', ganacheWallet2); - await vBridge.transact([], [ganacheDepositUtxo2], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo1], 0, 0, '0', '0', '', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo2], 0, 0, '0', '0', '', ganacheWallet2); // Check the leaf index is incremented by two const destAnchorEdge2After = await vAnchor1.contract.edgeList(edgeIndex); @@ -520,6 +526,7 @@ describe('2-sided multichain tests for signature vbridge', () => { 0, await signers[1].getAddress(), '0', + '', signers[2] ); @@ -548,10 +555,10 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); - await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', ganacheWallet2); - await vBridge.transact([ganacheDepositUtxo], [hardhatUtxo], 0, 0, '0', '0', signers[2]); + await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', '', ganacheWallet2); + await vBridge.transact([ganacheDepositUtxo], [hardhatUtxo], 0, 0, '0', '0', '', signers[2]); await TruffleAssert.reverts( - vBridge.transact([ganacheDepositUtxo], [hardhatUtxo], 0, 0, '0', '0', signers[2]), + vBridge.transact([ganacheDepositUtxo], [hardhatUtxo], 0, 0, '0', '0', '', signers[2]), 'Input is already spent' ); }); @@ -582,7 +589,7 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); - await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', '', ganacheWallet2); //Check that deposit went through assert.strictEqual( @@ -618,6 +625,7 @@ describe('2-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', signers[2] ); const signers2BalanceAfter = await webbToken1.getBalance(await signers[2].getAddress()); @@ -706,26 +714,25 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID2.toString(), chainId: chainID1.toString(), }); - //Transact on the bridge - await vBridge.transactWrap( - existingToken1.contract.address, + await vBridge.transact( [], [depositUtxo1], 0, 0, '0', '0', + '0x0000000000000000000000000000000000000000', signers[1] ); - await vBridge.transactWrap( - existingToken2.contract.address, + await vBridge.transact( [], [depositUtxo2], 0, 0, '0', '0', + '0x0000000000000000000000000000000000000000', ganacheWallet2 ); //Now there is a bidirectional edge between chain1 and chain2 @@ -766,8 +773,20 @@ describe('2-sided multichain tests for signature vbridge', () => { assert.strictEqual(vAnchor2Balance.toString(), BigNumber.from(1e7).toString()); }); - it('should transactWrap with native', async () => { + it('should transact and wrap with native', async () => { const signers = await ethers.getSigners(); + const webbTokenAddress = vBridge.getWebbTokenAddress(chainID1); + const webbToken = await MintableToken.tokenFromAddress(webbTokenAddress!, signers[1]); + console.log('after transact signer balance token: ', await webbToken.getBalance(await signers[1].getAddress())) + console.log('before transact signer balance eth: ', await ethers.provider.getBalance(await signers[1].getAddress())) + const vAnchor1: VAnchor = vBridge.getVAnchor(chainID1)! as VAnchor; + const vAnchor1Address = vAnchor1.contract.address; + console.log('after transact vanchor1 balance token: ', await webbToken.getBalance(vAnchor1Address)) + console.log('before transact vanchor1 balance eth: ', await ethers.provider.getBalance(vAnchor1Address)) + const vAnchor2: VAnchor = vBridge.getVAnchor(chainID2)! as VAnchor; + const vAnchor2Address = vAnchor2.contract.address; + console.log('after transact vanchor2 balance token: ', await webbToken.getBalance(vAnchor2Address)) + console.log('before transact vanchor2 balance eth: ', await ethers.provider.getBalance(vAnchor2Address)) //Deposit UTXO const hardhatDepositUtxo1 = await CircomUtxo.generateUtxo({ curve: 'Bn254', @@ -776,20 +795,33 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID1.toString(), chainId: chainID2.toString(), }); + const b4EthBalance = await ethers.provider.getBalance(await signers[1].getAddress()) - await vBridge.transactWrap( - '0x0000000000000000000000000000000000000000', + await vBridge.transact( [], [hardhatDepositUtxo1], 0, 0, '0', '0', + '0x0000000000000000000000000000000000000000', signers[1] ); + // const afterEthBalance = await ethers.provider.getBalance(await signers[1].getAddress()) + // console.log('after transact signer balance token: ', await webbToken.getBalance(await signers[1].getAddress())) + // console.log('after transact signer balance eth: ', await ethers.provider.getBalance(await signers[1].getAddress())) + // console.log('after transact vanchor1 balance token: ', await webbToken.getBalance(vAnchor1Address)) + // console.log('after transact vanchor1 balance eth: ', await ethers.provider.getBalance(vAnchor1Address)) + // console.log('after transact vanchor2 balance token: ', await webbToken.getBalance(vAnchor2Address)) + // console.log('after transact vanchor2 balance eth: ', await ethers.provider.getBalance(vAnchor2Address)) + // console.log('delta eth: ', b4EthBalance.sub(afterEthBalance)) + // console.log('delta eth magnitude: ', b4EthBalance.sub(afterEthBalance).toString().length) + // console.log('deposit size: ', (2.5e7).toString()) + // console.log('delta eth - depositsize: ', b4EthBalance.sub(afterEthBalance).sub(2.5e7)) + // assert(false) }); - it('wrap and deposit, withdraw and unwrap works join split via transactWrap', async () => { + it('wrap and deposit, withdraw and unwrap works join split via transact and wrap', async () => { const signers = await ethers.getSigners(); const vAnchor1: VAnchor = vBridge.getVAnchor(chainID1)! as VAnchor; @@ -814,30 +846,51 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID2.toString(), chainId: chainID1.toString(), }); - await vBridge.transactWrap( - existingToken2.contract.address, + const webbTokenAddress2 = vBridge.getWebbTokenAddress(chainID2); + const webbToken2 = await MintableToken.tokenFromAddress(webbTokenAddress2!, ganacheWallet2); + console.log('before transact balance token1: ', await webbToken1.getBalance(vAnchor2Address)) + console.log('before transact balance token2: ', await webbToken2.getBalance(vAnchor2Address)) + const b4EthBalance = await ethers.provider.getBalance(vAnchor2Address) + console.log('before transact balance eth: ', b4EthBalance) + await vBridge.transact( [], [ganacheDepositUtxo1, ganacheDepositUtxo2], 0, 0, '0', '0', - ganacheWallet2 + existingToken2.contract.address, + ganacheWallet2, ); + console.log('b4 first assert') + const afterEthBalance = await ethers.provider.getBalance(vAnchor2Address) + console.log('after transact signer balance token1: ', await webbToken1.getBalance(await signers[1].getAddress())) + console.log('after transact signer balance token2: ', await webbToken2.getBalance(await signers[1].getAddress())) + console.log('after transact signer balance eth: ', await ethers.provider.getBalance(await signers[1].getAddress())) + console.log('after transact vanchor1 balance token1: ', await webbToken1.getBalance(vAnchor1Address)) + console.log('after transact vanchor1 balance token2: ', await webbToken2.getBalance(vAnchor1Address)) + console.log('after transact vanchor1 balance eth: ', await ethers.provider.getBalance(vAnchor1Address)) + console.log('after transact vanchor2 balance token1: ', await webbToken1.getBalance(vAnchor2Address)) + console.log('after transact vanchor2 balance token2: ', await webbToken2.getBalance(vAnchor2Address)) + console.log('after transact vanchor2 balance eth: ', await ethers.provider.getBalance(vAnchor2Address)) + console.log('delta eth: ', b4EthBalance.sub(afterEthBalance)) + console.log('delta eth magnitude: ', b4EthBalance.sub(afterEthBalance).toString().length) + console.log('deposit size: ', (2.5e7).toString()) + console.log('delta eth - depositsize: ', b4EthBalance.sub(afterEthBalance).sub(2.5e7)) - const webbTokenAddress2 = vBridge.getWebbTokenAddress(chainID2); - const webbToken2 = await MintableToken.tokenFromAddress(webbTokenAddress2!, ganacheWallet2); assert.strictEqual( (await webbToken2.getBalance(vAnchor2Address)).toString(), BigNumber.from(6e7).toString() ); + console.log('after first assert') - //Withdraw UTXO + // Withdraw UTXO const vAnchor1TokenAddr = await vAnchor1.contract.token(); await existingToken1.mintTokens(vAnchor1TokenAddr, '100000000'); const balWrapper1UnwrappedBefore = await existingToken1.contract.balanceOf( vAnchor1TokenAddr ); + console.log('balWrapper1UnwrappedBefore: ', balWrapper1UnwrappedBefore.toString()) const hardhatWithdrawUtxo = await CircomUtxo.generateUtxo({ curve: 'Bn254', backend: 'Circom', @@ -845,38 +898,40 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID1.toString(), chainId: chainID1.toString(), }); - - await vBridge.transactWrap( - existingToken1.contract.address, + await vBridge.transact( [ganacheDepositUtxo1, ganacheDepositUtxo2], [hardhatWithdrawUtxo], 0, 0, await signers[2].getAddress(), '0', + existingToken1.contract.address, signers[1] ); - //Check relevant balances - //Unwrapped Balance of signers[2] should be 3e7 + //Unwrapped Balance of signers[2] should be 4e7 const balSigners2Unwrapped = await existingToken1.contract.balanceOf( await signers[2].getAddress() ); + console.log('b4 second assert') assert.strictEqual(balSigners2Unwrapped.toString(), BigNumber.from(4e7).toString()); + console.log('after second assert') //Unwrapped balance of vanchor1tokenaddr should be const balWrapper1UnwrappedAfter = await existingToken1.contract.balanceOf( vAnchor1TokenAddr ); + console.log('b4 third assert') assert.strictEqual( balWrapper1UnwrappedBefore.sub(BigNumber.from(4e7)).toString(), balWrapper1UnwrappedAfter.toString() ); + console.log('after forth assert') //wrapped balance of vanchor1 should be 1e7 const balVAnchor1Wrapped = await webbToken1.getBalance(vAnchor1.contract.address); assert.strictEqual(balVAnchor1Wrapped.toString(), BigNumber.from(1e7).toString()); }); - it('wrap and deposit, withdraw and unwrap works join split 16 input via transactWrap', async () => { + it('wrap and deposit, withdraw and unwrap works join split 16 input via transact and wrapping', async () => { const signers = await ethers.getSigners(); const vAnchor1: VAnchor = vBridge.getVAnchor(chainID1)! as VAnchor; @@ -909,37 +964,37 @@ describe('2-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); - await vBridge.transactWrap( - existingToken2.contract.address, + await vBridge.transact( [], [ganacheDepositUtxo1], 0, 0, '0', '0', - ganacheWallet2 + existingToken2.contract.address, + ganacheWallet2, ); - await vBridge.transactWrap( - existingToken2.contract.address, + await vBridge.transact( [], [ganacheDepositUtxo2], 0, 0, '0', '0', - ganacheWallet2 + existingToken2.contract.address, + ganacheWallet2, ); - await vBridge.transactWrap( - existingToken2.contract.address, + await vBridge.transact( [], [ganacheDepositUtxo3], 0, 0, '0', '0', - ganacheWallet2 + existingToken2.contract.address, + ganacheWallet2, ); const webbTokenAddress2 = vBridge.getWebbTokenAddress(chainID2); @@ -966,14 +1021,14 @@ describe('2-sided multichain tests for signature vbridge', () => { originChainId: chainID1.toString(), chainId: chainID1.toString(), }); - await vBridge.transactWrap( - existingToken1.contract.address, + await vBridge.transact( [ganacheDepositUtxo1, ganacheDepositUtxo2, ganacheDepositUtxo3], [hardhatWithdrawUtxo], 0, 0, await signers[2].getAddress(), '0', + existingToken1.contract.address, signers[1] ); @@ -1180,14 +1235,15 @@ describe('8-sided multichain tests for signature vbridge', () => { chainId: chainID3.toString(), }); - await vBridge.transact([], [depositUtxo1], 0, 0, '0', '0', signers[1]); - await vBridge.transact([], [depositUtxo2], 0, 0, '0', '0', ganacheWallet2); - await vBridge.transact([], [depositUtxo3], 0, 0, '0', '0', ganacheWallet3); + await vBridge.transact([], [depositUtxo1], 0, 0, '0', '0', '', signers[1]); + await vBridge.transact([], [depositUtxo2], 0, 0, '0', '0', '', ganacheWallet2); + await vBridge.transact([], [depositUtxo3], 0, 0, '0', '0', '', ganacheWallet3); }); describe('#bridging', () => { it('basic ganache deposit should withdraw on hardhat', async () => { // Fetch information about the anchor to be updated. + console.log('init') const signers = await ethers.getSigners(); const vAnchor1: VAnchor = vBridge.getVAnchor(chainID1)! as VAnchor; @@ -1196,6 +1252,7 @@ describe('8-sided multichain tests for signature vbridge', () => { const webbTokenAddress1 = vBridge.getWebbTokenAddress(chainID1); const webbToken1 = await MintableToken.tokenFromAddress(webbTokenAddress1!, signers[1]); const signers2BalanceBefore = await webbToken1.getBalance(await signers[2].getAddress()); + console.log('start generating utxos') //ganacheWallet2 makes a deposit with dest chain chainID1 const ganacheDepositUtxo = await CircomUtxo.generateUtxo({ @@ -1206,7 +1263,7 @@ describe('8-sided multichain tests for signature vbridge', () => { chainId: chainID1.toString(), }); - await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', ganacheWallet2); + await vBridge.transact([], [ganacheDepositUtxo], 0, 0, '0', '0', '', ganacheWallet2); //check latest leaf index is incremented const destAnchorEdge2After = await vAnchor1.contract.edgeList(edgeIndex); @@ -1230,6 +1287,7 @@ describe('8-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', signers[2] ); const signers2BalanceAfter = await webbToken1.getBalance(await signers[2].getAddress()); @@ -1265,7 +1323,7 @@ describe('8-sided multichain tests for signature vbridge', () => { chainId: chainID2.toString(), }); - await vBridge.transact([], [hardhatDepositUtxo], 0, 0, '0', '0', signers[1]); + await vBridge.transact([], [hardhatDepositUtxo], 0, 0, '0', '0', '', signers[1]); //check latest leaf index is incremented const destAnchorEdge2After = await vAnchorGanache.contract.edgeList(edgeIndex); @@ -1289,6 +1347,7 @@ describe('8-sided multichain tests for signature vbridge', () => { 0, await signers[2].getAddress(), '0', + '', ganacheWallet2 ); const signers2BalanceAfter = await webbTokenGanache.getBalance( diff --git a/packages/contracts/test/vbridge/signatureVBridgeSide.test.ts b/packages/contracts/test/vbridge/signatureVBridgeSide.test.ts index 490e0ccbc..974351389 100644 --- a/packages/contracts/test/vbridge/signatureVBridgeSide.test.ts +++ b/packages/contracts/test/vbridge/signatureVBridgeSide.test.ts @@ -92,7 +92,7 @@ describe('SignatureBridgeSide use', () => { zkComponents16_2, admin ); - await tokenInstance.approveSpending(anchor.contract.address); + await tokenInstance.approveSpending(anchor.contract.address, BigNumber.from(1e7)); bridgeSide.setAnchorHandler(anchorHandler); // Function call below sets resource with signature await bridgeSide.connectAnchorWithSignature(anchor); @@ -128,7 +128,7 @@ describe('SignatureBridgeSide use', () => { admin ); - await tokenInstance.approveSpending(srcAnchor.contract.address); + await tokenInstance.approveSpending(srcAnchor.contract.address, BigNumber.from(1e7)); bridgeSide.setAnchorHandler(anchorHandler); const res = await bridgeSide.connectAnchorWithSignature(srcAnchor); @@ -146,21 +146,15 @@ describe('SignatureBridgeSide use', () => { const depositUtxo = await CircomUtxo.generateUtxo({ curve: 'Bn254', backend: 'Circom', - amount: (1e7).toString(), + amount: BigNumber.from(1e7).toString(), originChainId: chainID1.toString(), chainId: chainID1.toString(), keypair: new Keypair(), }); // Transact on the bridge - await srcAnchor.transact( - [], - [depositUtxo], - { [chainID1.toString()]: [] }, - '0', - '0', - zeroAddress, - zeroAddress - ); + await srcAnchor.transact([], [depositUtxo], '0', '0', zeroAddress, zeroAddress, '', { + [chainID1.toString()]: [], + }); }); it('execute fee proposal', async () => { @@ -456,7 +450,7 @@ describe('SignatureBridgeSide use', () => { admin ); - await tokenInstance.approveSpending(anchor.contract.address); + await tokenInstance.approveSpending(anchor.contract.address, BigNumber.from(1e7)); await bridgeSide.setAnchorHandler(anchorHandler); // Function call below sets resource with signature @@ -622,8 +616,10 @@ describe('Rescue Tokens Tests for ERC20 Tokens', () => { ); await fungibleToken.grantMinterRole(srcAnchor.contract.address); - await erc20TokenInstance.approveSpending(fungibleToken.contract.address); - await erc20TokenInstance.approveSpending(srcAnchor.contract.address); + let amountToWrap = await fungibleToken.contract.getAmountToWrap( + BigNumber.from(1e7) + ); + await erc20TokenInstance.approveSpending(fungibleToken.contract.address, amountToWrap); bridgeSide.setAnchorHandler(anchorHandler); const res = await bridgeSide.connectAnchorWithSignature(srcAnchor); await bridgeSide.executeMinWithdrawalLimitProposalWithSig( @@ -646,15 +642,15 @@ describe('Rescue Tokens Tests for ERC20 Tokens', () => { }); await TruffleAssert.reverts( - srcAnchor.transactWrap( - erc20TokenInstance.contract.address, + srcAnchor.transact( [], [depositUtxo], '0', '0', zeroAddress, zeroAddress, - { [chainID1.toString()]: [] } + erc20TokenInstance.contract.address, + {} ), 'Fee Recipient cannot be zero address' ); @@ -662,16 +658,17 @@ describe('Rescue Tokens Tests for ERC20 Tokens', () => { // Change Fee Recipient to treasury Address await bridgeSide.executeFeeRecipientProposalWithSig(fungibleToken, treasury.contract.address); + // For ERC20 Tests - await srcAnchor.transactWrap( - erc20TokenInstance.contract.address, + await srcAnchor.transact( [], [depositUtxo], '0', '0', zeroAddress, zeroAddress, - { [chainID1.toString()]: [] } + erc20TokenInstance.contract.address, + {} ); // Anchor Denomination amount should go to TokenWrapper @@ -892,7 +889,7 @@ describe('Rescue Tokens Tests for Native ETH', () => { }); await TruffleAssert.reverts( - srcAnchor.transactWrap(zeroAddress, [], [depositUtxo], '0', '0', zeroAddress, zeroAddress, { + srcAnchor.transact([], [depositUtxo], '0', '0', zeroAddress, zeroAddress, zeroAddress, { [chainID1.toString()]: [], }), 'Fee Recipient cannot be zero address' @@ -902,16 +899,9 @@ describe('Rescue Tokens Tests for Native ETH', () => { await bridgeSide.executeFeeRecipientProposalWithSig(fungibleToken, treasury.contract.address); // For Native ETH Tests - await srcAnchor.transactWrap( - zeroAddress, - [], - [depositUtxo], - '0', - '0', - zeroAddress, - zeroAddress, - { [chainID1.toString()]: [] } - ); + await srcAnchor.transact([], [depositUtxo], '0', '0', zeroAddress, zeroAddress, zeroAddress, { + [chainID1.toString()]: [], + }); // Anchor Denomination amount should go to TokenWrapper assert.strictEqual( diff --git a/packages/interfaces/src/IAnchor.ts b/packages/interfaces/src/IVAnchor.ts similarity index 89% rename from packages/interfaces/src/IAnchor.ts rename to packages/interfaces/src/IVAnchor.ts index b5e7864e7..e14fabec3 100644 --- a/packages/interfaces/src/IAnchor.ts +++ b/packages/interfaces/src/IVAnchor.ts @@ -1,10 +1,10 @@ -import { AnchorBase } from '@webb-tools/contracts'; +import { VAnchorBase } from '@webb-tools/contracts'; import { MerkleProof, Utxo } from '@webb-tools/sdk-core'; import { ethers } from 'ethers'; -export interface IAnchor { +export interface IVAnchor { signer: ethers.Signer; - contract: AnchorBase; + contract: VAnchorBase; tree: any; // hex string of the connected root latestSyncedBlock: number; diff --git a/packages/interfaces/src/anchor/index.ts b/packages/interfaces/src/anchor/index.ts deleted file mode 100644 index dfc6e5688..000000000 --- a/packages/interfaces/src/anchor/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -export interface IAnchorDepositInfo { - chainID: BigInt; - secret: BigInt; - nullifier: BigInt; - commitment: string; - nullifierHash: string; -} - -export interface IAnchorDeposit { - deposit: IAnchorDepositInfo; - index: number; - originChainId: number; -} - -export interface IFixedAnchorPublicInputs { - proof: string; - _roots: string; - _nullifierHash: string; - _extDataHash: string; -} - -export interface IFixedAnchorExtData { - _refreshCommitment: string; - _recipient: string; - _relayer: string; - _fee: bigint; - _refund: bigint; -} diff --git a/packages/interfaces/src/bridge/index.ts b/packages/interfaces/src/bridge/index.ts index eb8d19301..e7f7296c3 100644 --- a/packages/interfaces/src/bridge/index.ts +++ b/packages/interfaces/src/bridge/index.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { IAnchor } from '..'; +import { IVAnchor } from '..'; import { IBridgeSide } from '../IBridgeSide'; // Deployer config matches the chainId to the signer for that chain @@ -43,7 +43,7 @@ export type BridgeConfig = { // The addresses of the anchors for the FungibleTokenWrapper // {anchorIdentifier} => anchorAddress - anchors: Map; + anchors: Map; // The addresses of the Bridge contracts (bridgeSides) to interact with bridgeSides: Map; diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index d646d2b9e..f4ab1df4d 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -1,6 +1,5 @@ -export * from './anchor'; export * from './vanchor'; export * from './identity-vanchor'; export * from './bridge'; -export * from './IAnchor'; +export * from './IVAnchor'; export * from './IBridgeSide'; diff --git a/packages/interfaces/src/vanchor/index.ts b/packages/interfaces/src/vanchor/index.ts index 2c570703b..0658cd657 100644 --- a/packages/interfaces/src/vanchor/index.ts +++ b/packages/interfaces/src/vanchor/index.ts @@ -18,10 +18,11 @@ export interface IUTXOInput { export interface IVariableAnchorPublicInputs { proof: string; roots: string; - inputNullifiers: string[]; - outputCommitments: [string, string]; + extensionRoots: string; + inputNullifiers: BigNumber[]; + outputCommitments: [BigNumber, BigNumber]; publicAmount: string; - extDataHash: string; + extDataHash: BigNumber; } export interface IVariableAnchorExtData { diff --git a/packages/tokens/src/MintableToken.ts b/packages/tokens/src/MintableToken.ts index 79f7294c5..fd02d4f18 100644 --- a/packages/tokens/src/MintableToken.ts +++ b/packages/tokens/src/MintableToken.ts @@ -44,10 +44,10 @@ class MintableToken { return this.contract.balanceOf(address); } - public async approveSpending(spender: string): Promise { - return this.contract.approve(spender, '10000000000000000000000000000000000', { - gasLimit: '0x5B8D80', - }); + public async approveSpending(spender: string, amount: BigNumber): Promise { + const tx = await this.contract.approve(spender, amount); + await tx.wait(); + return tx; } public async mintTokens(address: string, amount: BigNumberish) { diff --git a/packages/utils/src/utils.ts b/packages/utils/src/utils.ts index 4d8338217..ea492ecf0 100644 --- a/packages/utils/src/utils.ts +++ b/packages/utils/src/utils.ts @@ -11,6 +11,9 @@ import path from 'path'; import { ZkComponents } from './types'; import { toFixedHex, Keypair, MerkleProof, MerkleTree, Utxo } from '@webb-tools/sdk-core'; +export const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000'; +export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + export const FIELD_SIZE = BigNumber.from( '21888242871839275222246405745257275088548364400416034343698204186575808495617' ); diff --git a/packages/vbridge/src/VBridge.ts b/packages/vbridge/src/VBridge.ts index 63b233cd3..cf9f39d46 100644 --- a/packages/vbridge/src/VBridge.ts +++ b/packages/vbridge/src/VBridge.ts @@ -338,6 +338,7 @@ export class VBridge { refund: BigNumberish, recipient: string, relayer: string, + wrapUnwrapToken: string, signer: ethers.Signer ) { const chainId = getChainIdType(await signer.getChainId()); @@ -362,123 +363,44 @@ export class VBridge { } } - const tokenAddress = await vAnchor.contract.token(); + const webbTokenAddress = await vAnchor.contract.token(); - if (!tokenAddress) { + if (!webbTokenAddress) { throw new Error('Token not supported'); } - const tokenInstance = await MintableToken.tokenFromAddress(tokenAddress, signer); - - const extAmount = BigNumber.from(fee) - .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) - .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))); - - const publicAmount = extAmount.sub(fee); - // Approve spending if needed - const userTokenAllowance = await tokenInstance.getAllowance( - signerAddress, - vAnchor.contract.address - ); - if (userTokenAllowance.lt(publicAmount)) { - await tokenInstance.approveSpending(vAnchor.contract.address); - } - - // Populate the leaves map - const leavesMap: Record = {}; - - // Always include the leaves of the chain which we are interacting on - leavesMap[chainId] = vAnchor.tree - .elements() - .map((commitment) => hexToU8a(commitment.toHexString())); - - for (let input of inputs) { - const inputTree = this.getVAnchor(Number(input.originChainId)).tree; - - if (!leavesMap[input.originChainId]) { - leavesMap[input.originChainId] = inputTree - .elements() - .map((commitment) => hexToU8a(commitment.toHexString())); - } - - // update the utxo with the proper index - const utxoIndex = inputTree.getIndexByElement(u8aToHex(input.commitment)); - input.setIndex(utxoIndex); - } - - // Create dummy UTXOs to satisfy the circuit - while (inputs.length !== 2 && inputs.length < 16) { - inputs.push( - await CircomUtxo.generateUtxo({ - curve: 'Bn254', - backend: 'Circom', - chainId: chainId.toString(), - originChainId: chainId.toString(), - index: '0', - amount: '0', - }) - ); - } - - await vAnchor.transact(inputs, outputs, leavesMap, fee, refund, recipient, relayer); - await this.update(chainId); - } - - //token address is address of unwrapped erc20 - public async transactWrap( - tokenAddress: string, - inputs: Utxo[], - outputs: Utxo[], - fee: BigNumberish, - refund: BigNumberish, - recipient: string, - relayer: string, - signer: ethers.Signer - ) { - const chainId = getChainIdType(await signer.getChainId()); - const signerAddress = await signer.getAddress(); - const vAnchor = this.getVAnchor(chainId); - if (!vAnchor) { - throw new Error('VAnchor does not exist on this chain'); - } - await vAnchor.setSigner(signer); - - //do we have to check if amount is greater than 0 before the checks? - //Check that input dest chain is this chain - for (let i = 0; i < inputs.length; i++) { - if (inputs[i].chainId.toString() !== chainId.toString()) { - throw new Error('Trying to spend an input with wrong destination chainId'); - } - } - - //check that output origin chain is this chain - for (let i = 0; i < outputs.length; i++) { - if (outputs[i].originChainId.toString() !== chainId.toString()) { - throw new Error('Trying to form an output with the wrong originChainId'); - } - } - const extAmount = BigNumber.from(fee) .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))); const publicAmount = extAmount.sub(fee); - // Approve spending if needed - const webbTokenAddress = await vAnchor.contract.token(); - if (tokenAddress != zeroAddress) { - const tokenInstance = await MintableToken.tokenFromAddress(tokenAddress, signer); + // If the wrapUnwrapToken is unspecified ('') then we assume that + // the user is trying to transact directly with the webbToken. We instead + // check if the anchor's allowed to spend webbToken funds from the user. + if (wrapUnwrapToken.length === 0) { + const tokenInstance = await MintableToken.tokenFromAddress(webbTokenAddress, signer); const userTokenAllowance = await tokenInstance.getAllowance( signerAddress, vAnchor.contract.address ); if (userTokenAllowance.lt(publicAmount)) { - await tokenInstance.approveSpending(webbTokenAddress); + await tokenInstance.approveSpending(vAnchor.contract.address, publicAmount); + } + + wrapUnwrapToken = webbTokenAddress; + } else if (wrapUnwrapToken != zeroAddress) { + const tokenInstance = await MintableToken.tokenFromAddress(wrapUnwrapToken, signer); + const userTokenAllowance = await tokenInstance.getAllowance(signerAddress, webbTokenAddress); + if (userTokenAllowance.lt(publicAmount)) { + await tokenInstance.approveSpending(webbTokenAddress, publicAmount); } } // Populate the leaves map const leavesMap: Record = {}; + + // Always include the leaves of the chain which we are interacting on leavesMap[chainId] = vAnchor.tree .elements() .map((commitment) => hexToU8a(commitment.toHexString())); @@ -511,14 +433,14 @@ export class VBridge { ); } - await vAnchor.transactWrap( - tokenAddress, + await vAnchor.transact( inputs, outputs, fee, refund, recipient, relayer, + wrapUnwrapToken, leavesMap ); await this.update(chainId); diff --git a/yarn.lock b/yarn.lock index 2fecebd15..43dfbe228 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4084,7 +4084,7 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@solidity-parser/parser@^0.14.0": +"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.5": version "0.14.5" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== @@ -9056,6 +9056,11 @@ emittery@^0.13.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== +emoji-regex@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f" + integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -15894,6 +15899,18 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== +prettier-plugin-solidity@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0.tgz#5b23f48cc9c28a1246c6dd89af117234b813f48b" + integrity sha512-gRJCeZ7imbWtNYN2SudjJoPmka5r6jcd2cSTV6FC3pVCtY6LFZbeQQjpKufUEp88hXBAAnkOTOh7TA5xwj9M3A== + dependencies: + "@solidity-parser/parser" "^0.14.5" + emoji-regex "^10.2.1" + escape-string-regexp "^4.0.0" + semver "^7.3.8" + solidity-comments-extractor "^0.0.7" + string-width "^4.2.3" + "prettier@^1.18.2 || ^2.0.0", prettier@^2.1.2, prettier@^2.2.1, prettier@^2.3.2, prettier@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" @@ -17085,7 +17102,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: +semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -17484,6 +17501,11 @@ solc@^0.6.3: semver "^5.5.0" tmp "0.0.33" +solidity-comments-extractor@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" + integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== + sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128"