From 58259290afd09c9cc15b65b5365f35e19ccf34a9 Mon Sep 17 00:00:00 2001 From: bigq <99990370+yum0e@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:41:08 +0200 Subject: [PATCH] feat: add tests and scripts (#1) --- .github/workflows/forge.yml | 28 + .gitmodules | 6 + .hardhat/README.md | 69 +++ .hardhat/package.json | 25 + README.md | 8 +- deployments/arbitrum-goerli.json | 18 + deployments/arbitrum-one.json | 18 + deployments/gnosis.json | 18 + deployments/mainnet.json | 18 + deployments/optimism-goerli.json | 18 + deployments/optimism.json | 18 + deployments/polygon.json | 18 + deployments/scroll-testnet-goerli.json | 18 + deployments/testnet-goerli.json | 18 + deployments/testnet-mumbai.json | 18 + deployments/testnet-sepolia.json | 18 + deployments/tmp/example.json | 18 + foundry.toml | 3 - lib/hydra-s3-zkps | 1 + lib/openzeppelin-contracts | 1 + remappings.txt | 4 +- script/01_DeployAll.s.sol | 257 ++++++++ script/BaseConfig.sol | 560 ++++++++++++++++++ script/DeployAddressesProviderV2.s.sol | 130 ++++ script/DeployAvailableRootsRegistry.s.sol | 133 +++++ script/DeployCommitmentMapperRegistry.s.sol | 144 +++++ script/bash/setup-fork.sh | 60 ++ script/utils/PrankAddressesProvider.sol | 21 + script/utils/SetAddressesProvider.s.sol | 55 ++ .../TransparentUpgradeableProxy.sol | 137 +++++ src/SismoConnectVerifier.sol | 250 ++++++++ src/misc/CheatSheet.sol | 92 +++ src/misc/ZKDropERC721.sol | 60 ++ src/periphery/AddressesProviderV2.sol | 132 +++++ src/periphery/AvailableRootsRegistry.sol | 75 +++ src/periphery/CommitmentMapperRegistry.sol | 67 +++ .../interfaces/IAddressesProvider.sol | 50 ++ .../interfaces/IAvailableRootsRegistry.sol | 38 ++ .../interfaces/ICommitmentMapperRegistry.sol | 27 + src/verifiers/HydraS3Lib.sol | 135 +++++ src/verifiers/HydraS3Verifier.sol | 347 +++++++++++ src/verifiers/IHydraS3Verifier.sol | 35 ++ test/BaseTest.t.sol | 59 ++ test/e2e/SismoConnectE2E.t.sol | 356 +++++++++++ test/harness/SismoConnectHarness.sol | 108 ++++ test/libs/SismoConnectLib.t.sol | 449 ++++++++++++++ test/misc/UpgradeableExample.sol | 46 ++ test/mocks/AddressesProviderMock.sol | 28 + test/mocks/AvailableRootsRegistryMock.sol | 31 + test/mocks/CommitmentMapperRegistryMock.sol | 18 + test/mocks/VerifierMock.sol | 51 ++ test/script/01_DeployAll.t.sol | 83 +++ test/utils/GroupLib.sol | 17 + test/utils/ResponseBuilderLib.sol | 283 +++++++++ test/verifiers/hydra-s3/HydraS3BaseTest.t.sol | 37 ++ test/verifiers/hydra-s3/HydraS3Proofs.sol | 271 +++++++++ test/verifiers/hydra-s3/HydraS3Verifier.t.sol | 521 ++++++++++++++++ .../mocks/VerifierMockBaseTest.t.sol | 19 + 58 files changed, 5535 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/forge.yml create mode 100644 .hardhat/README.md create mode 100644 .hardhat/package.json create mode 100644 deployments/arbitrum-goerli.json create mode 100644 deployments/arbitrum-one.json create mode 100644 deployments/gnosis.json create mode 100644 deployments/mainnet.json create mode 100644 deployments/optimism-goerli.json create mode 100644 deployments/optimism.json create mode 100644 deployments/polygon.json create mode 100644 deployments/scroll-testnet-goerli.json create mode 100644 deployments/testnet-goerli.json create mode 100644 deployments/testnet-mumbai.json create mode 100644 deployments/testnet-sepolia.json create mode 100644 deployments/tmp/example.json create mode 160000 lib/hydra-s3-zkps create mode 160000 lib/openzeppelin-contracts create mode 100644 script/01_DeployAll.s.sol create mode 100644 script/BaseConfig.sol create mode 100644 script/DeployAddressesProviderV2.s.sol create mode 100644 script/DeployAvailableRootsRegistry.s.sol create mode 100644 script/DeployCommitmentMapperRegistry.s.sol create mode 100755 script/bash/setup-fork.sh create mode 100644 script/utils/PrankAddressesProvider.sol create mode 100644 script/utils/SetAddressesProvider.s.sol create mode 100644 script/utils/deterministic-deployments/TransparentUpgradeableProxy.sol create mode 100644 src/SismoConnectVerifier.sol create mode 100644 src/misc/CheatSheet.sol create mode 100644 src/misc/ZKDropERC721.sol create mode 100644 src/periphery/AddressesProviderV2.sol create mode 100644 src/periphery/AvailableRootsRegistry.sol create mode 100644 src/periphery/CommitmentMapperRegistry.sol create mode 100644 src/periphery/interfaces/IAddressesProvider.sol create mode 100644 src/periphery/interfaces/IAvailableRootsRegistry.sol create mode 100644 src/periphery/interfaces/ICommitmentMapperRegistry.sol create mode 100644 src/verifiers/HydraS3Lib.sol create mode 100644 src/verifiers/HydraS3Verifier.sol create mode 100644 src/verifiers/IHydraS3Verifier.sol create mode 100644 test/BaseTest.t.sol create mode 100644 test/e2e/SismoConnectE2E.t.sol create mode 100644 test/harness/SismoConnectHarness.sol create mode 100644 test/libs/SismoConnectLib.t.sol create mode 100644 test/misc/UpgradeableExample.sol create mode 100644 test/mocks/AddressesProviderMock.sol create mode 100644 test/mocks/AvailableRootsRegistryMock.sol create mode 100644 test/mocks/CommitmentMapperRegistryMock.sol create mode 100644 test/mocks/VerifierMock.sol create mode 100644 test/script/01_DeployAll.t.sol create mode 100644 test/utils/GroupLib.sol create mode 100644 test/utils/ResponseBuilderLib.sol create mode 100644 test/verifiers/hydra-s3/HydraS3BaseTest.t.sol create mode 100644 test/verifiers/hydra-s3/HydraS3Proofs.sol create mode 100644 test/verifiers/hydra-s3/HydraS3Verifier.t.sol create mode 100644 test/verifiers/mocks/VerifierMockBaseTest.t.sol diff --git a/.github/workflows/forge.yml b/.github/workflows/forge.yml new file mode 100644 index 0000000..344fd22 --- /dev/null +++ b/.github/workflows/forge.yml @@ -0,0 +1,28 @@ +on: [push] + +name: Forge Tests + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Install submodules + run: | + git config --global url."https://github.com/".insteadOf "git@github.com:" + git submodule update --init --recursive + + - name: Install dependencies + run: forge install + + - name: Compile + run: forge build + + - name: Run Forge tests + run: forge test -vvv diff --git a/.gitmodules b/.gitmodules index 888d42d..30eccb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/hydra-s3-zkps"] + path = lib/hydra-s3-zkps + url = https://github.com/sismo-core/hydra-s3-zkps +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/.hardhat/README.md b/.hardhat/README.md new file mode 100644 index 0000000..125f958 --- /dev/null +++ b/.hardhat/README.md @@ -0,0 +1,69 @@ +
+
+ Logo + +

+ Sismo Connect Solidity +

+ +

+ Made by Sismo +

+ +

+ + + + + + + + + +

+
+ + +Sismo Connect Solidity is a Solidity library that allows you to verify the zk-proofs of your Sismo Connect Application onchain and simplify the use of the [sismo-connect-onchain-verifier](https://github.com/sismo-core/sismo-connect-onchain-verifier). + +Here is the link to the full documentation of the library: [Sismo Connect Solidity Library](https://docs.sismo.io/build-with-sismo-connect/technical-documentation/solidity) + +You can learn more on Sismo Connect [here](https://docs.sismo.io/discover-sismo-connect/empower-your-app). + +### Prerequisites + +- [Node.js](https://nodejs.org/en/download/) >= 18.15.0 (Latest LTS version) +- [Yarn](https://classic.yarnpkg.com/en/docs/install) + +## Usage + +### Installation + +```bash +# install the package +yarn add @sismo-core/sismo-connect-solidity +``` + +### Import the library +In your solidity file: + +```solidity +import {SismoConnect} from "@sismo-core/sismo-connect-solidity/contracts/libs/SismoLib.sol"; +``` + +You will find here how to use the library: [Sismo Connect Solidity Library](https://docs.sismo.io/build-with-sismo-connect/technical-documentation/solidity) + +## License + +Distributed under the MIT License. + +## Contribute + +Please, feel free to open issues, PRs or simply provide feedback! + +## Contact + +Send us a message in [Telegram](https://builders.sismo.io/) or [Discord](https://discord.gg/sismo) + +
+bottom diff --git a/.hardhat/package.json b/.hardhat/package.json new file mode 100644 index 0000000..360b5e4 --- /dev/null +++ b/.hardhat/package.json @@ -0,0 +1,25 @@ +{ + "name": "@sismo-core/sismo-connect-solidity", + "description": "Sismo Connect Library", + "version": "0.0.19", + "scripts": { + "prepare": "mkdir -p contracts; cp -r ../src/* contracts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/sismo-core/sismo-connect-onchain-verifier.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts" + ], + "author": "Sismo ", + "license": "MIT", + "bugs": { + "url": "https://github.com/sismo-core/sismo-connect-onchain-verifier/issues" + }, + "homepage": "https://github.com/sismo-core/sismo-connect-onchain-verifier#readme", + "main": "index.js" +} diff --git a/README.md b/README.md index ef50180..cd1cfaa 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,11 @@ -Sismo Connect Solidity is a Solidity library that allows you to verify the zk-proofs of your Sismo Connect Application onchain and simplify the use of the [sismo-connect-onchain-verifier](https://github.com/sismo-core/sismo-connect-onchain-verifier). +Sismo Connect Solidity is a Solidity library that allows you to verify the zk-proofs of your Sismo Connect Application onchain. Here is the link to the full documentation of the library: [Sismo Connect Solidity Library](https://docs.sismo.io/build-with-sismo-connect/technical-documentation/solidity) -You can learn more on Sismo Connect [here](https://docs.sismo.io/discover-sismo-connect/empower-your-app). +You can learn more on Sismo Connect [here](https://docs.sismo.io/sismo-docs/build-with-sismo-connect/getting-started). ### Prerequisites @@ -48,7 +48,7 @@ foundryup forge install sismo-core/sismo-connect-solidity --no-commit # add the remapping in remappings.txt -echo $'sismo-connect-solidity/=lib/sismo-connect-packages/src/' >> remappings.txt +echo $'sismo-connect-solidity/=lib/sismo-connect-solidity/src/' >> remappings.txt ``` ### Import the library @@ -58,7 +58,7 @@ In your solidity file: // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "sismo-connect-solidity/SismoLib.sol"; // import the library +import "sismo-connect-solidity/SismoConnectLib.sol"; // import the library ``` ## License diff --git a/deployments/arbitrum-goerli.json b/deployments/arbitrum-goerli.json new file mode 100644 index 0000000..3aa216d --- /dev/null +++ b/deployments/arbitrum-goerli.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xD4339e6d873b584FFfeACceE4CcB8Bf31Cd96ebb", + "availableRootsRegistry": "0x32725B00400b799D41c852b6Fd94604e10cb487F", + "claimRequestBuilder": "0xF03dA119efEc165DbDc15D593aB455810C7fEd74", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x497f369f94F207663A348b0ac085397C71279bf5", + "hydraS3Verifier": "0x9854860CBEa52E19Ca252D1948F04070eBC46b2C", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0x0bB5c193aa815F7815aB8e854A87E041519CD2ad", + "rootsOwner": "0x8eAb4616d47F82C890fdb6eE311A4C0aE34ba7fb", + "signatureBuilder": "0xc8F165a3B4CfB7CD2Ae92A582F17b0d7EB3BcE11", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xb1327210BAF0E8793f3f4D671573ac1A45619edf" +} \ No newline at end of file diff --git a/deployments/arbitrum-one.json b/deployments/arbitrum-one.json new file mode 100644 index 0000000..41e1819 --- /dev/null +++ b/deployments/arbitrum-one.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x8D090172DA53A21D27E7B651ab6E7D9334Ea0783", + "availableRootsRegistry": "0xEB2952A4098e15C97E1Ce126FE479f27E2FFB40c", + "claimRequestBuilder": "0x1B05f16686396398F16f8916A032D738005126b7", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x43A6b844f52CB2CC3c9dBcAE9D853B21fF05c4bD", + "hydraS3Verifier": "0xAa745f3833faCE895E0e7f99eD0A4989a470E150", + "owner": "0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc", + "proxyAdmin": "0x2110475dfbB8d331b300178A867372991ff35fA3", + "requestBuilder": "0x40e208f4815Ce25b32BeEEC7415C6CA9424a898F", + "rootsOwner": "0x1BB9AD70F529e36B7Ffed0cfA44fA4cf0213Fa09", + "signatureBuilder": "0x1e7a99e06Ca2C1A63330eC2df8D4fC15EfDa4C55", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0x80a914AaFB60519a58f531D80fd402ae88047896" +} \ No newline at end of file diff --git a/deployments/gnosis.json b/deployments/gnosis.json new file mode 100644 index 0000000..eb8621d --- /dev/null +++ b/deployments/gnosis.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x900F4aD11Ec071e7f93Bf4e0c8976aE2Af5D28E5", + "availableRootsRegistry": "0x9B0C9EF48DEc082904054cf9183878E1f4e04D79", + "claimRequestBuilder": "0x0c5a188E778a9A0736fCBf25aF6298E92182D676", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0xEB2952A4098e15C97E1Ce126FE479f27E2FFB40c", + "hydraS3Verifier": "0x0F85c4Fe7644E85579e27A027D94d1Fb3A388710", + "owner": "0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc", + "proxyAdmin": "0x2110475dfbB8d331b300178A867372991ff35fA3", + "requestBuilder": "0x1B05f16686396398F16f8916A032D738005126b7", + "rootsOwner": "0xEf809a50de35c762FBaCf1ae1F6B861CE42911D1", + "signatureBuilder": "0x8D090172DA53A21D27E7B651ab6E7D9334Ea0783", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xd1fbf35B45748B2F6998fb7B86eb6A3d73fe91ED" +} \ No newline at end of file diff --git a/deployments/mainnet.json b/deployments/mainnet.json new file mode 100644 index 0000000..f49d27e --- /dev/null +++ b/deployments/mainnet.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x94E772DBe3ce4BD32274a2053C444C802Bb836A5", + "availableRootsRegistry": "0x2E7f4aC6AC90faeC2D870D012A3BCDBcF792B25C", + "claimRequestBuilder": "0x900F4aD11Ec071e7f93Bf4e0c8976aE2Af5D28E5", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0xb4463Dbcd773F7Ca37E63f12dce9852e59dC86C9", + "hydraS3Verifier": "0x89f40fd037e62eAec7511b0711f781AA57A3e96f", + "owner": "0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc", + "proxyAdmin": "0x2110475dfbB8d331b300178A867372991ff35fA3", + "requestBuilder": "0x8D090172DA53A21D27E7B651ab6E7D9334Ea0783", + "rootsOwner": "0x2a265b954B96d4940B94eb69E8Fc8E7346369D05", + "signatureBuilder": "0x0c5a188E778a9A0736fCBf25aF6298E92182D676", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0x0568ecE836a0881cd305ad53046AB51467B0886a" +} diff --git a/deployments/optimism-goerli.json b/deployments/optimism-goerli.json new file mode 100644 index 0000000..7a483e0 --- /dev/null +++ b/deployments/optimism-goerli.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xD4339e6d873b584FFfeACceE4CcB8Bf31Cd96ebb", + "availableRootsRegistry": "0x32725B00400b799D41c852b6Fd94604e10cb487F", + "claimRequestBuilder": "0xF03dA119efEc165DbDc15D593aB455810C7fEd74", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x497f369f94F207663A348b0ac085397C71279bf5", + "hydraS3Verifier": "0x51B3ec080D1459232dbea86B751F75b5204a4abC", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0x0bB5c193aa815F7815aB8e854A87E041519CD2ad", + "rootsOwner": "0xe807B5153e3eD4767C3F4EB50b65Fab90c57596B", + "signatureBuilder": "0xc8F165a3B4CfB7CD2Ae92A582F17b0d7EB3BcE11", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xAe5f6F591d9F8a5eEB3E6853888B0E80eC9B25E4" +} \ No newline at end of file diff --git a/deployments/optimism.json b/deployments/optimism.json new file mode 100644 index 0000000..90d54f7 --- /dev/null +++ b/deployments/optimism.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x8D090172DA53A21D27E7B651ab6E7D9334Ea0783", + "availableRootsRegistry": "0xEB2952A4098e15C97E1Ce126FE479f27E2FFB40c", + "claimRequestBuilder": "0x1B05f16686396398F16f8916A032D738005126b7", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x43A6b844f52CB2CC3c9dBcAE9D853B21fF05c4bD", + "hydraS3Verifier": "0x1C4Bd61F5b19750ffb7b0b2D97c77dcf68F49152", + "owner": "0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc", + "proxyAdmin": "0x2110475dfbB8d331b300178A867372991ff35fA3", + "requestBuilder": "0x40e208f4815Ce25b32BeEEC7415C6CA9424a898F", + "rootsOwner": "0xf8640cE5532BCbc788489Bf5A786635ae585258B", + "signatureBuilder": "0x1e7a99e06Ca2C1A63330eC2df8D4fC15EfDa4C55", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xAE116c797ae424BF232DfFcdF8a3b741D9e6460c" +} \ No newline at end of file diff --git a/deployments/polygon.json b/deployments/polygon.json new file mode 100644 index 0000000..063795f --- /dev/null +++ b/deployments/polygon.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x900F4aD11Ec071e7f93Bf4e0c8976aE2Af5D28E5", + "availableRootsRegistry": "0x818c0f863C6B8E92c316924711bfEb2D903B4A77", + "claimRequestBuilder": "0x0c5a188E778a9A0736fCBf25aF6298E92182D676", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0xEB2952A4098e15C97E1Ce126FE479f27E2FFB40c", + "hydraS3Verifier": "0x027AcA627F7D13572A54ac2d027A770ca3eF22c8", + "owner": "0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc", + "proxyAdmin": "0x2110475dfbB8d331b300178A867372991ff35fA3", + "requestBuilder": "0x1B05f16686396398F16f8916A032D738005126b7", + "rootsOwner": "0xF0a0B692e1c764281c211948D03edEeF5Fb57111", + "signatureBuilder": "0x8D090172DA53A21D27E7B651ab6E7D9334Ea0783", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0x1C4Bd61F5b19750ffb7b0b2D97c77dcf68F49152" +} \ No newline at end of file diff --git a/deployments/scroll-testnet-goerli.json b/deployments/scroll-testnet-goerli.json new file mode 100644 index 0000000..29045a6 --- /dev/null +++ b/deployments/scroll-testnet-goerli.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xD4339e6d873b584FFfeACceE4CcB8Bf31Cd96ebb", + "availableRootsRegistry": "0x32725B00400b799D41c852b6Fd94604e10cb487F", + "claimRequestBuilder": "0xF03dA119efEc165DbDc15D593aB455810C7fEd74", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x497f369f94F207663A348b0ac085397C71279bf5", + "hydraS3Verifier": "0x51B3ec080D1459232dbea86B751F75b5204a4abC", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0x0bB5c193aa815F7815aB8e854A87E041519CD2ad", + "rootsOwner": "0x8f9c04d7bA132Fd0CbA124eFCE3936328d217458", + "signatureBuilder": "0xc8F165a3B4CfB7CD2Ae92A582F17b0d7EB3BcE11", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xAe5f6F591d9F8a5eEB3E6853888B0E80eC9B25E4" +} \ No newline at end of file diff --git a/deployments/testnet-goerli.json b/deployments/testnet-goerli.json new file mode 100644 index 0000000..628d5f1 --- /dev/null +++ b/deployments/testnet-goerli.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xD4339e6d873b584FFfeACceE4CcB8Bf31Cd96ebb", + "availableRootsRegistry": "0x32725B00400b799D41c852b6Fd94604e10cb487F", + "claimRequestBuilder": "0xF03dA119efEc165DbDc15D593aB455810C7fEd74", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x497f369f94F207663A348b0ac085397C71279bf5", + "hydraS3Verifier": "0x1F60E4023C84e7e5897722b04BEc3De7eEa78DEF", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0x0bB5c193aa815F7815aB8e854A87E041519CD2ad", + "rootsOwner": "0xa687922C4bf2eB22297FdF89156B49eD3727618b", + "signatureBuilder": "0xc8F165a3B4CfB7CD2Ae92A582F17b0d7EB3BcE11", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0x2bF68E251A94c83dB3da30a5A997c73705DF1B8b" +} \ No newline at end of file diff --git a/deployments/testnet-mumbai.json b/deployments/testnet-mumbai.json new file mode 100644 index 0000000..5f85447 --- /dev/null +++ b/deployments/testnet-mumbai.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xF392c4EAB659Ba22cF40F201996178929f3C9d65", + "availableRootsRegistry": "0x51B3ec080D1459232dbea86B751F75b5204a4abC", + "claimRequestBuilder": "0xb1327210BAF0E8793f3f4D671573ac1A45619edf", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0xAe5f6F591d9F8a5eEB3E6853888B0E80eC9B25E4", + "hydraS3Verifier": "0xBA63Ad5f5570B7Adc82319529eB0694B31f2422E", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0xc33d0496571513c676de73b13c7166e245CD4d5E", + "rootsOwner": "0xCA0583A6682607282963d3E2545Cd2e75697C2bb", + "signatureBuilder": "0x16Cb98567cE6f177C1855906230874AE8c5a8B7f", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xf219113C648dA1D9F0f12EB1898A6a22fEe86dF8" +} \ No newline at end of file diff --git a/deployments/testnet-sepolia.json b/deployments/testnet-sepolia.json new file mode 100644 index 0000000..d23fe51 --- /dev/null +++ b/deployments/testnet-sepolia.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0xD4339e6d873b584FFfeACceE4CcB8Bf31Cd96ebb", + "availableRootsRegistry": "0x32725B00400b799D41c852b6Fd94604e10cb487F", + "claimRequestBuilder": "0xF03dA119efEc165DbDc15D593aB455810C7fEd74", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x497f369f94F207663A348b0ac085397C71279bf5", + "hydraS3Verifier": "0x51B3ec080D1459232dbea86B751F75b5204a4abC", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0x0bB5c193aa815F7815aB8e854A87E041519CD2ad", + "rootsOwner": "0x1C0c54EA7Bb55f655fb8Ff6D51557368bA8624E6", + "signatureBuilder": "0xc8F165a3B4CfB7CD2Ae92A582F17b0d7EB3BcE11", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0xAe5f6F591d9F8a5eEB3E6853888B0E80eC9B25E4" +} \ No newline at end of file diff --git a/deployments/tmp/example.json b/deployments/tmp/example.json new file mode 100644 index 0000000..159f9e9 --- /dev/null +++ b/deployments/tmp/example.json @@ -0,0 +1,18 @@ +{ + "authRequestBuilder": "0x99BDC397D261C8B2D15967dd4605d9785e2E7761", + "availableRootsRegistry": "0xfB548eC30347c220E4e7733248ff25e3699A4648", + "claimRequestBuilder": "0x32D604958f5b2206a426E85cc8d965E5148dA1F9", + "commitmentMapperEdDSAPubKey": { + "pubKeyX": 3602196582082511412345093208859330584743530098298494929484637038525722574265, + "pubKeyY": 14672613011011178056703002414016466661118036128791343632962870104486584019450 + }, + "commitmentMapperRegistry": "0x2ff87b43dbE95d94F56F059cA3506d5d4E8F0470", + "hydraS3Verifier": "0x6DfBF9f1610CB69d5722ED4b8366eB7Ed3c2C77a", + "owner": "0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B", + "proxyAdmin": "0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc", + "requestBuilder": "0xDb7Ec66521700F00ccaf7F7B8aA1853b9541484B", + "rootsOwner": "0xa687922C4bf2eB22297FdF89156B49eD3727618b", + "signatureBuilder": "0xD6710F81Be249EA575Fe9A39Ff6D28da6601f37c", + "sismoAddressesProviderV2": "0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6", + "sismoConnectVerifier": "0x9dbC9d0ce3CC784BB5fD42a6f7686670a7e0b4eE" +} diff --git a/foundry.toml b/foundry.toml index 4d9fd31..08e868a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,9 +6,6 @@ fs_permissions = [{ access = "read-write", path = "./"}] bytecode_hash="none" -[fmt] -ignore = ["test/libs/SimoConnectLib.t.sol"] - [rpc_endpoints] polygon = "${RPC_URL}" gnosis = "${RPC_URL}" diff --git a/lib/hydra-s3-zkps b/lib/hydra-s3-zkps new file mode 160000 index 0000000..33ac760 --- /dev/null +++ b/lib/hydra-s3-zkps @@ -0,0 +1 @@ +Subproject commit 33ac7603405dfa5d1806da4c150dab160e763e18 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 0000000..d00acef --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit d00acef4059807535af0bd0dd0ddf619747a044b diff --git a/remappings.txt b/remappings.txt index 83fbb69..3a33c7a 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1 +1,3 @@ -forge-std/=lib/forge-std/src/ \ No newline at end of file +forge-std/=lib/forge-std/src/ +@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +@sismo-core/hydra-s3/=lib/hydra-s3-zkps/package/contracts/ \ No newline at end of file diff --git a/script/01_DeployAll.s.sol b/script/01_DeployAll.s.sol new file mode 100644 index 0000000..01f232d --- /dev/null +++ b/script/01_DeployAll.s.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import "forge-std/console.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; + +import "src/periphery/AvailableRootsRegistry.sol"; +import "src/periphery/CommitmentMapperRegistry.sol"; +import {HydraS3Verifier} from "src/verifiers/HydraS3Verifier.sol"; + +import {SismoConnectVerifier} from "src/SismoConnectVerifier.sol"; +import {AuthRequestBuilder} from "src/utils/AuthRequestBuilder.sol"; +import {ClaimRequestBuilder} from "src/utils/ClaimRequestBuilder.sol"; +import {SignatureBuilder} from "src/utils/SignatureBuilder.sol"; +import {RequestBuilder} from "src/utils/RequestBuilder.sol"; +import {DeploymentConfig, BaseDeploymentConfig} from "script/BaseConfig.sol"; +import {IAddressesProvider} from "src/periphery/interfaces/IAddressesProvider.sol"; + +contract DeployAll is Script, BaseDeploymentConfig { + AvailableRootsRegistry availableRootsRegistry; + CommitmentMapperRegistry commitmentMapperRegistry; + HydraS3Verifier hydraS3Verifier; + SismoConnectVerifier sismoConnectVerifier; + + // external libraries + AuthRequestBuilder authRequestBuilder; + ClaimRequestBuilder claimRequestBuilder; + SignatureBuilder signatureBuilder; + RequestBuilder requestBuilder; + + function runFor( + string memory chainName + ) public returns (ScriptTypes.DeployAllContracts memory contracts) { + console.log("Run for CHAIN_NAME:", chainName); + console.log("Deployer:", msg.sender); + + vm.startBroadcast(); + + _setDeploymentConfig({chainName: chainName, checkIfEmpty: true}); + + availableRootsRegistry = _deployAvailableRootsRegistry(config.rootsOwner); + commitmentMapperRegistry = _deployCommitmentMapperRegistry( + config.owner, + config.commitmentMapperEdDSAPubKey + ); + + hydraS3Verifier = _deployHydraS3Verifier( + address(commitmentMapperRegistry), + address(availableRootsRegistry) + ); + sismoConnectVerifier = _deploySismoConnectVerifier(msg.sender); + + sismoConnectVerifier.registerVerifier( + hydraS3Verifier.HYDRA_S3_VERSION(), + address(hydraS3Verifier) + ); + + sismoConnectVerifier.transferOwnership(config.owner); + + contracts.availableRootsRegistry = availableRootsRegistry; + contracts.commitmentMapperRegistry = commitmentMapperRegistry; + contracts.hydraS3Verifier = hydraS3Verifier; + contracts.sismoConnectVerifier = sismoConnectVerifier; + + // external libraries + + authRequestBuilder = _deployAuthRequestBuilder(); + claimRequestBuilder = _deployClaimRequestBuilder(); + signatureBuilder = _deploySignatureBuilder(); + requestBuilder = _deployRequestBuilder(); + + contracts.authRequestBuilder = authRequestBuilder; + contracts.claimRequestBuilder = claimRequestBuilder; + contracts.signatureBuilder = signatureBuilder; + contracts.requestBuilder = requestBuilder; + + DeploymentConfig memory newDeploymentConfig = DeploymentConfig({ + proxyAdmin: config.proxyAdmin, + owner: config.owner, + rootsOwner: config.rootsOwner, + commitmentMapperEdDSAPubKey: config.commitmentMapperEdDSAPubKey, + sismoAddressesProviderV2: config.sismoAddressesProviderV2, + availableRootsRegistry: address(availableRootsRegistry), + commitmentMapperRegistry: address(commitmentMapperRegistry), + hydraS3Verifier: address(hydraS3Verifier), + sismoConnectVerifier: address(sismoConnectVerifier), + authRequestBuilder: address(authRequestBuilder), + claimRequestBuilder: address(claimRequestBuilder), + signatureBuilder: address(signatureBuilder), + requestBuilder: address(requestBuilder) + }); + + _saveDeploymentConfig(chainName, newDeploymentConfig); + + vm.stopBroadcast(); + } + + function _deployAvailableRootsRegistry(address owner) private returns (AvailableRootsRegistry) { + address availableRootsRegistryAddress = config.availableRootsRegistry; + if (availableRootsRegistryAddress != address(0)) { + console.log("Using existing availableRootsRegistry:", availableRootsRegistryAddress); + return AvailableRootsRegistry(availableRootsRegistryAddress); + } + AvailableRootsRegistry rootsRegistryImplem = new AvailableRootsRegistry(owner); + console.log("rootsRegistry Implem Deployed:", address(rootsRegistryImplem)); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(rootsRegistryImplem), + config.proxyAdmin, + abi.encodeWithSelector(rootsRegistryImplem.initialize.selector, owner) + ); + console.log("rootsRegistry Proxy Deployed:", address(proxy)); + return AvailableRootsRegistry(address(proxy)); + } + + function _deployCommitmentMapperRegistry( + address owner, + uint256[2] memory commitmentMapperEdDSAPubKey + ) private returns (CommitmentMapperRegistry) { + address commitmentMapperRegistryAddress = config.commitmentMapperRegistry; + if (commitmentMapperRegistryAddress != address(0)) { + console.log("Using existing commitmentMapperRegistry:", commitmentMapperRegistryAddress); + return CommitmentMapperRegistry(commitmentMapperRegistryAddress); + } + CommitmentMapperRegistry commitmentMapperImplem = new CommitmentMapperRegistry( + owner, + commitmentMapperEdDSAPubKey + ); + console.log("commitmentMapper Implem Deployed:", address(commitmentMapperImplem)); + console.log("owner:", owner); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(commitmentMapperImplem), + config.proxyAdmin, + abi.encodeWithSelector( + commitmentMapperImplem.initialize.selector, + owner, + commitmentMapperEdDSAPubKey + ) + ); + console.log("commitmentMapper Proxy Deployed:", address(proxy)); + return CommitmentMapperRegistry(address(proxy)); + } + + function _deployHydraS3Verifier( + address commitmentMapperRegistryAddr, + address availableRootsRegistryAddr + ) private returns (HydraS3Verifier) { + address hydraS3VerifierAddress = config.hydraS3Verifier; + if (hydraS3VerifierAddress != address(0)) { + console.log("Using existing hydraS3Verifier:", hydraS3VerifierAddress); + return HydraS3Verifier(hydraS3VerifierAddress); + } + HydraS3Verifier hydraS3VerifierImplem = new HydraS3Verifier( + commitmentMapperRegistryAddr, + availableRootsRegistryAddr + ); + console.log("hydraS3Verifier Implem Deployed:", address(hydraS3VerifierImplem)); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(hydraS3VerifierImplem), + config.proxyAdmin, + abi.encodeWithSelector(hydraS3VerifierImplem.initialize.selector) + ); + console.log("hydraS3Verifier Proxy Deployed:", address(proxy)); + return HydraS3Verifier(address(proxy)); + } + + function _deploySismoConnectVerifier(address owner) private returns (SismoConnectVerifier) { + address sismoConnectVerifierAddress = config.sismoConnectVerifier; + if (sismoConnectVerifierAddress != address(0)) { + console.log("Using existing sismoConnectVerifier:", sismoConnectVerifierAddress); + return SismoConnectVerifier(sismoConnectVerifierAddress); + } + SismoConnectVerifier sismoConnectVerifierImplem = new SismoConnectVerifier(owner); + console.log("sismoConnectVerifier Implem Deployed:", address(sismoConnectVerifierImplem)); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(sismoConnectVerifierImplem), + config.proxyAdmin, + abi.encodeWithSelector(sismoConnectVerifierImplem.initialize.selector, owner) + ); + console.log("sismoConnectVerifier Proxy Deployed:", address(proxy)); + return SismoConnectVerifier(address(proxy)); + } + + // External libraries + + function _deployAuthRequestBuilder() private returns (AuthRequestBuilder) { + address authRequestBuilderAddress = config.authRequestBuilder; + if (authRequestBuilderAddress != address(0)) { + console.log("Using existing authrequestBuilder:", authRequestBuilderAddress); + return AuthRequestBuilder(authRequestBuilderAddress); + } + authRequestBuilder = new AuthRequestBuilder(); + console.log("authRequestBuilder Deployed:", address(authRequestBuilder)); + return authRequestBuilder; + } + + function _deployClaimRequestBuilder() private returns (ClaimRequestBuilder) { + address claimRequestBuilderAddress = config.claimRequestBuilder; + if (claimRequestBuilderAddress != address(0)) { + console.log("Using existing claimRequestBuilder:", claimRequestBuilderAddress); + return ClaimRequestBuilder(claimRequestBuilderAddress); + } + claimRequestBuilder = new ClaimRequestBuilder(); + console.log("claimRequestBuilder Deployed:", address(claimRequestBuilder)); + return claimRequestBuilder; + } + + function _deploySignatureBuilder() private returns (SignatureBuilder) { + address signatureBuilderAddress = config.signatureBuilder; + if (signatureBuilderAddress != address(0)) { + console.log("Using existing signatureBuilder:", signatureBuilderAddress); + return SignatureBuilder(signatureBuilderAddress); + } + signatureBuilder = new SignatureBuilder(); + console.log("signatureBuilder Deployed:", address(signatureBuilder)); + return signatureBuilder; + } + + function _deployRequestBuilder() private returns (RequestBuilder) { + address requestBuilderAddress = config.requestBuilder; + if (requestBuilderAddress != address(0)) { + console.log("Using existing requestBuilder:", requestBuilderAddress); + return RequestBuilder(requestBuilderAddress); + } + requestBuilder = new RequestBuilder(); + console.log("requestBuilder Deployed:", address(requestBuilder)); + return requestBuilder; + } + + function run() public returns (ScriptTypes.DeployAllContracts memory contracts) { + string memory chainName = vm.envString("CHAIN_NAME"); + return runFor(chainName); + } + + function deploymentConfigFilePath() external view returns (string memory) { + return _deploymentConfigFilePath(); + } +} + +library ScriptTypes { + struct DeployAllContracts { + AvailableRootsRegistry availableRootsRegistry; + CommitmentMapperRegistry commitmentMapperRegistry; + HydraS3Verifier hydraS3Verifier; + SismoConnectVerifier sismoConnectVerifier; + // external libraries + AuthRequestBuilder authRequestBuilder; + ClaimRequestBuilder claimRequestBuilder; + SignatureBuilder signatureBuilder; + RequestBuilder requestBuilder; + } +} diff --git a/script/BaseConfig.sol b/script/BaseConfig.sol new file mode 100644 index 0000000..8206353 --- /dev/null +++ b/script/BaseConfig.sol @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Script} from "forge-std/Script.sol"; +import "forge-std/console.sol"; + +// struct fields are sorted by alphabetical order to be able to parse the config from the deployment files +struct DeploymentConfig { + address authRequestBuilder; + address availableRootsRegistry; + address claimRequestBuilder; + uint256[2] commitmentMapperEdDSAPubKey; + address commitmentMapperRegistry; + address hydraS3Verifier; + address owner; + address proxyAdmin; + address requestBuilder; + address rootsOwner; + address signatureBuilder; + address sismoAddressesProviderV2; + address sismoConnectVerifier; +} + +// Minimal config is used to create empty config files +struct MinimalConfig { + address owner; + address proxyAdmin; + address rootsOwner; + uint256[2] commitmentMapperEdDSAPubKey; +} + +contract BaseDeploymentConfig is Script { + MinimalConfig minimalConfig; + DeploymentConfig config; + + string public _chainName; + bool public _checkIfEmpty; + + address immutable SISMO_ADDRESSES_PROVIDER_V2 = 0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6; + address immutable ZERO_ADDRESS = 0x0000000000000000000000000000000000000000; + + // Main Env + address immutable MAIN_PROXY_ADMIN = 0x2110475dfbB8d331b300178A867372991ff35fA3; + address immutable MAIN_OWNER = 0x00c92065F759c3d1c94d08C27a2Ab97a1c874Cbc; + address immutable MAIN_GNOSIS_ROOTS_OWNER = 0xEf809a50de35c762FBaCf1ae1F6B861CE42911D1; + address immutable MAIN_POLYGON_ROOTS_OWNER = 0xF0a0B692e1c764281c211948D03edEeF5Fb57111; + address immutable MAIN_OPTIMISM_ROOTS_OWNER = 0xf8640cE5532BCbc788489Bf5A786635ae585258B; + address immutable MAIN_ARBITRUM_ONE_ROOTS_OWNER = 0x1BB9AD70F529e36B7Ffed0cfA44fA4cf0213Fa09; + address immutable MAIN_MAINNET_ROOTS_OWNER = 0x2a265b954B96d4940B94eb69E8Fc8E7346369D05; + + // Testnet Env + address immutable TESTNET_PROXY_ADMIN = 0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc; + address immutable TESTNET_OWNER = 0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B; + address immutable TESTNET_GOERLI_ROOTS_OWNER = 0xa687922C4bf2eB22297FdF89156B49eD3727618b; + address immutable TESTNET_SEPOLIA_ROOTS_OWNER = 0x1C0c54EA7Bb55f655fb8Ff6D51557368bA8624E6; + address immutable TESTNET_MUMBAI_ROOTS_OWNER = 0xCA0583A6682607282963d3E2545Cd2e75697C2bb; + address immutable TESTNET_OPTIMISM_GOERLI_ROOTS_OWNER = + 0xe807B5153e3eD4767C3F4EB50b65Fab90c57596B; + address immutable TESTNET_ARBITRUM_GOERLI_ROOTS_OWNER = + 0x8eAb4616d47F82C890fdb6eE311A4C0aE34ba7fb; + address immutable TESTNET_SCROLL_GOERLI_ROOTS_OWNER = 0x8f9c04d7bA132Fd0CbA124eFCE3936328d217458; + + // Sismo Staging env (Sismo internal use only) + address immutable STAGING_PROXY_ADMIN = 0x246E71bC2a257f4BE9C7fAD4664E6D7444844Adc; + address immutable STAGING_OWNER = 0xBB8FcA8f2381CFeEDe5D7541d7bF76343EF6c67B; + address immutable STAGING_GOERLI_ROOTS_OWNER = 0x7f2e6E158643BCaF85f30c57Ae8625f623D82659; + address immutable STAGING_MUMBAI_ROOTS_OWNER = 0x63F08f8F13126B9eADC76dd683902C61c5115138; + + // commitment mapper pubkeys + uint256 immutable PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X = + 0x07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb9; + uint256 immutable PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y = + 0x20706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa; + + error ChainNotConfigured(DeployChain chain); + error ChainNameNotFound(string chainName); + + enum DeployChain { + Mainnet, + Gnosis, + Polygon, + Optimism, + ArbitrumOne, + TestnetGoerli, + TestnetSepolia, + TestnetMumbai, + OptimismGoerli, + ArbitrumGoerli, + ScrollTestnetGoerli, + StagingGoerli, + StagingMumbai, + Test + } + + function getChainName(string memory chainName) internal pure returns (DeployChain) { + if (_compareStrings(chainName, "mainnet")) { + return DeployChain.Mainnet; + } else if (_compareStrings(chainName, "gnosis")) { + return DeployChain.Gnosis; + } else if (_compareStrings(chainName, "polygon")) { + return DeployChain.Polygon; + } else if (_compareStrings(chainName, "optimism")) { + return DeployChain.Optimism; + } else if (_compareStrings(chainName, "arbitrum-one")) { + return DeployChain.ArbitrumOne; + } else if (_compareStrings(chainName, "testnet-goerli")) { + return DeployChain.TestnetGoerli; + } else if (_compareStrings(chainName, "testnet-sepolia")) { + return DeployChain.TestnetSepolia; + } else if (_compareStrings(chainName, "testnet-mumbai")) { + return DeployChain.TestnetMumbai; + } else if (_compareStrings(chainName, "optimism-goerli")) { + return DeployChain.OptimismGoerli; + } else if (_compareStrings(chainName, "arbitrum-goerli")) { + return DeployChain.ArbitrumGoerli; + } else if (_compareStrings(chainName, "scroll-testnet-goerli")) { + return DeployChain.ScrollTestnetGoerli; + } else if (_compareStrings(chainName, "staging-goerli")) { + return DeployChain.StagingGoerli; + } else if (_compareStrings(chainName, "staging-mumbai")) { + return DeployChain.StagingMumbai; + } else if (_compareStrings(chainName, "test")) { + return DeployChain.Test; + } + revert ChainNameNotFound(chainName); + } + + function _getEmptyDeploymentConfig(DeployChain chain) internal returns (DeploymentConfig memory) { + minimalConfig = _getMinimalConfig(chain); + + config = DeploymentConfig({ + proxyAdmin: minimalConfig.proxyAdmin, + owner: minimalConfig.owner, + rootsOwner: minimalConfig.rootsOwner, + commitmentMapperEdDSAPubKey: minimalConfig.commitmentMapperEdDSAPubKey, + availableRootsRegistry: ZERO_ADDRESS, + commitmentMapperRegistry: ZERO_ADDRESS, + sismoAddressesProviderV2: _tryReadingAddressFromDeploymentConfigAtKey( + ".sismoAddressesProviderV2" + ), + sismoConnectVerifier: ZERO_ADDRESS, + hydraS3Verifier: ZERO_ADDRESS, + // external libraries + authRequestBuilder: ZERO_ADDRESS, + claimRequestBuilder: ZERO_ADDRESS, + signatureBuilder: ZERO_ADDRESS, + requestBuilder: ZERO_ADDRESS + }); + + return config; + } + + function _getMinimalConfig(DeployChain chain) internal returns (MinimalConfig memory) { + if (chain == DeployChain.Mainnet) { + minimalConfig = MinimalConfig({ + proxyAdmin: MAIN_PROXY_ADMIN, + owner: MAIN_OWNER, + rootsOwner: MAIN_MAINNET_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.Gnosis) { + minimalConfig = MinimalConfig({ + proxyAdmin: MAIN_PROXY_ADMIN, + owner: MAIN_OWNER, + rootsOwner: MAIN_GNOSIS_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.Polygon) { + minimalConfig = MinimalConfig({ + proxyAdmin: MAIN_PROXY_ADMIN, + owner: MAIN_OWNER, + rootsOwner: MAIN_POLYGON_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.Optimism) { + minimalConfig = MinimalConfig({ + proxyAdmin: MAIN_PROXY_ADMIN, + owner: MAIN_OWNER, + rootsOwner: MAIN_OPTIMISM_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.ArbitrumOne) { + minimalConfig = MinimalConfig({ + proxyAdmin: MAIN_PROXY_ADMIN, + owner: MAIN_OWNER, + rootsOwner: MAIN_ARBITRUM_ONE_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.TestnetGoerli) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_GOERLI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.TestnetSepolia) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_SEPOLIA_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.TestnetMumbai) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_MUMBAI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.OptimismGoerli) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_OPTIMISM_GOERLI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.ArbitrumGoerli) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_ARBITRUM_GOERLI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.ScrollTestnetGoerli) { + minimalConfig = MinimalConfig({ + proxyAdmin: TESTNET_PROXY_ADMIN, + owner: TESTNET_OWNER, + rootsOwner: TESTNET_SCROLL_GOERLI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.StagingGoerli) { + minimalConfig = MinimalConfig({ + proxyAdmin: STAGING_PROXY_ADMIN, + owner: STAGING_OWNER, + rootsOwner: STAGING_GOERLI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.StagingMumbai) { + minimalConfig = MinimalConfig({ + proxyAdmin: STAGING_PROXY_ADMIN, + owner: STAGING_OWNER, + rootsOwner: STAGING_MUMBAI_ROOTS_OWNER, + commitmentMapperEdDSAPubKey: [ + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_X, + PROD_BETA_COMMITMENT_MAPPER_PUB_KEY_Y + ] + }); + } else if (chain == DeployChain.Test) { + minimalConfig = MinimalConfig({ + proxyAdmin: address(1), + owner: address(2), + rootsOwner: address(3), + commitmentMapperEdDSAPubKey: [uint256(10), uint256(11)] + }); + } else { + revert ChainNotConfigured(chain); + } + + return minimalConfig; + } + + function _setDeploymentConfig(string memory chainName, bool checkIfEmpty) internal { + _chainName = chainName; + _checkIfEmpty = checkIfEmpty; + // read deployment config from file if the chain is different from `test` + string memory filePath = string.concat(_deploymentConfigFilePath()); + + string memory json; + try vm.readFile(filePath) returns (string memory _json) { + json = _json; + } catch { + console.log( + string.concat("Deployment config file not found, creating a new one at ", filePath, ".") + ); + // create a new empty file + vm.writeFile(filePath, ""); + json = ""; + } + + // if the config is not created, create a new empty one + if (checkIfEmpty) { + if (_compareStrings(json, "") || _compareStrings(chainName, "test") || _isLocalFork()) { + _saveDeploymentConfig(chainName, _getEmptyDeploymentConfig(getChainName(_chainName))); + } else { + _readDeploymentConfig(_chainName); + } + } else { + _readDeploymentConfig(_chainName); + } + } + + function _readDeploymentConfig(string memory chainName) internal { + _chainName = chainName; + minimalConfig = _getMinimalConfig(getChainName(chainName)); + address owner = minimalConfig.owner; + address proxyAdmin = minimalConfig.proxyAdmin; + address rootsOwner = minimalConfig.rootsOwner; + uint256[2] memory commitmentMapperEdDSAPubKey = minimalConfig.commitmentMapperEdDSAPubKey; + address availableRootsRegistry = _tryReadingAddressFromDeploymentConfigAtKey( + ".availableRootsRegistry" + ); + address commitmentMapperRegistry = _tryReadingAddressFromDeploymentConfigAtKey( + ".commitmentMapperRegistry" + ); + address sismoAddressesProviderV2 = _tryReadingAddressFromDeploymentConfigAtKey( + ".sismoAddressesProviderV2" + ); + address sismoConnectVerifier = _tryReadingAddressFromDeploymentConfigAtKey( + ".sismoConnectVerifier" + ); + address hydraS3Verifier = _tryReadingAddressFromDeploymentConfigAtKey(".hydraS3Verifier"); + address authRequestBuilder = _tryReadingAddressFromDeploymentConfigAtKey(".authRequestBuilder"); + address claimRequestBuilder = _tryReadingAddressFromDeploymentConfigAtKey( + ".claimRequestBuilder" + ); + address signatureBuilder = _tryReadingAddressFromDeploymentConfigAtKey(".signatureBuilder"); + address requestBuilder = _tryReadingAddressFromDeploymentConfigAtKey(".requestBuilder"); + + config = DeploymentConfig({ + proxyAdmin: proxyAdmin, + owner: owner, + rootsOwner: rootsOwner, + commitmentMapperEdDSAPubKey: commitmentMapperEdDSAPubKey, + availableRootsRegistry: availableRootsRegistry, + commitmentMapperRegistry: commitmentMapperRegistry, + sismoAddressesProviderV2: sismoAddressesProviderV2, + sismoConnectVerifier: sismoConnectVerifier, + hydraS3Verifier: hydraS3Verifier, + // external libraries + authRequestBuilder: authRequestBuilder, + claimRequestBuilder: claimRequestBuilder, + signatureBuilder: signatureBuilder, + requestBuilder: requestBuilder + }); + } + + function _readAddressFromDeploymentConfigAtKey( + string memory key + ) internal view returns (address) { + bytes memory encodedAddress = vm.parseJson(vm.readFile(_deploymentConfigFilePath()), key); + return + abi.decode(encodedAddress, (address)) == address(0x20) + ? address(0) + : abi.decode(encodedAddress, (address)); + } + + function _tryReadingAddressFromDeploymentConfigAtKey( + string memory key + ) internal view returns (address) { + try vm.parseJson(vm.readFile(_deploymentConfigFilePath()), key) returns ( + bytes memory encodedAddress + ) { + return + abi.decode(encodedAddress, (address)) == address(0x20) + ? address(0) + : abi.decode(encodedAddress, (address)); + } catch { + return ZERO_ADDRESS; + } + } + + function _readCommitmentMapperEdDSAPubKeyFromDeploymentConfig() + internal + view + returns (uint256[2] memory pubKey) + { + try + vm.parseJson(vm.readFile(_deploymentConfigFilePath()), ".commitmentMapperEdDSAPubKey") + returns (bytes memory value) { + return abi.decode(value, (uint256[2])); + } catch { + require( + false, + string.concat( + "Error reading commitmentMapperEdDSAPubKey from deployment config, you need to specify a public key." + ) + ); + } + } + + function _tryReadingCommitmentMapperEdDSAPubKeyFromDeploymentConfig() + internal + view + returns (uint256[2] memory pubKey) + { + try + vm.parseJson(vm.readFile(_deploymentConfigFilePath()), ".commitmentMapperEdDSAPubKey") + returns (bytes memory value) { + return abi.decode(value, (uint256[2])); + } catch { + return [uint256(0), uint256(0)]; + } + } + + function _saveDeploymentConfig( + string memory chainName, + DeploymentConfig memory deploymentConfig + ) internal { + // serialize deployment config by creating an object with key `chainName` + vm.serializeAddress( + chainName, + "availableRootsRegistry", + address(deploymentConfig.availableRootsRegistry) + ); + vm.serializeAddress( + chainName, + "commitmentMapperRegistry", + address(deploymentConfig.commitmentMapperRegistry) + ); + vm.serializeAddress(chainName, "hydraS3Verifier", address(deploymentConfig.hydraS3Verifier)); + vm.serializeAddress( + chainName, + "sismoConnectVerifier", + address(deploymentConfig.sismoConnectVerifier) + ); + vm.serializeAddress( + chainName, + "authRequestBuilder", + address(deploymentConfig.authRequestBuilder) + ); + vm.serializeAddress( + chainName, + "claimRequestBuilder", + address(deploymentConfig.claimRequestBuilder) + ); + vm.serializeAddress(chainName, "signatureBuilder", address(deploymentConfig.signatureBuilder)); + vm.serializeAddress(chainName, "requestBuilder", address(deploymentConfig.requestBuilder)); + vm.serializeAddress(chainName, "proxyAdmin", address(deploymentConfig.proxyAdmin)); + vm.serializeAddress(chainName, "owner", address(deploymentConfig.owner)); + vm.serializeAddress(chainName, "rootsOwner", address(deploymentConfig.rootsOwner)); + + // serialize commitment mapper pub key by creating a new json object with key "commitmentMapperEdDSAPubKey + vm.serializeUint( + "commitmentMapperEdDSAPubKey", + "pubKeyX", + deploymentConfig.commitmentMapperEdDSAPubKey[0] + ); + string memory commitmentMapperPubKeyConfig = vm.serializeUint( + "commitmentMapperEdDSAPubKey", + "pubKeyY", + deploymentConfig.commitmentMapperEdDSAPubKey[1] + ); + + // serialize this json object as a string to be able to save it in the main json object with key `chainName` + vm.serializeString(chainName, "commitmentMapperEdDSAPubKey", commitmentMapperPubKeyConfig); + string memory finalJson = vm.serializeAddress( + chainName, + "sismoAddressesProviderV2", + address(deploymentConfig.sismoAddressesProviderV2) + ); + + if (_compareStrings(chainName, "test") || _isLocalFork()) { + vm.writeJson(finalJson, _deploymentConfigFilePath()); + } else { + try vm.envBool("OVERRIDE_DEPLOYMENT_CONFIG") returns (bool overrideDeploymentConfig) { + if (overrideDeploymentConfig == true) { + vm.writeJson(finalJson, _deploymentConfigFilePath()); + } + } catch { + console.log("OVERRIDE_DEPLOYMENT_CONFIG not set, skipping deployment config override."); + } + } + } + + function _deploymentConfigFilePath() internal view returns (string memory) { + // we return the real config if USE_DEPLOYMENT_CONFIG is true + // and the RPC_URL is different from localhost + // otherwise we return the temporary config + try vm.envBool("USE_DEPLOYMENT_CONFIG") returns (bool useDeploymentConfig) { + return _checkLocalhostFork(useDeploymentConfig == true); + } catch { + return _checkLocalhostFork(false); + } + } + + function _checkLocalhostFork(bool useDeploymentConfig) internal view returns (string memory) { + // check if we are using a fork + bool isLocalFork = _isLocalFork(); + + // if the chainId is different from 31337 (localhost) we need to check if the user wants to use the real development config + // otherwise it can be dangerous to deploy to a real chain with a config that is temporary + if (!_compareStrings(vm.toString(block.chainid), "31337")) { + require( + useDeploymentConfig == true || isLocalFork == true, + "If you want to deploy to a chain different from localhost, you either need to use the deployment config by specifying `USE_DEPLOYMENT_CONFIG=true` in your command. Or set `FORK=true` and `--rpc-url http://localhost:8545` in your command to deploy to a fork." + ); + require( + !_compareStrings(_chainName, "test"), + "If you want to deploy to a chain different from localhost, you need to specify a chain name different from `test`." + ); + // return the real config if we are NOT using a fork + return + isLocalFork == true + ? string.concat(vm.projectRoot(), "/deployments/tmp/", _chainName, ".json") + : string.concat(vm.projectRoot(), "/deployments/", _chainName, ".json"); + } + // return the temporary config + return string.concat(vm.projectRoot(), "/deployments/tmp/", _chainName, ".json"); + } + + function _isLocalFork() internal view returns (bool) { + bool isLocalFork; + try vm.envBool("FORK") returns (bool fork) { + isLocalFork = fork; + } catch { + isLocalFork = false; + } + return isLocalFork; + } + + function _compareStrings(string memory a, string memory b) internal pure returns (bool) { + return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); + } + + /// @dev broadcast transaction modifier + /// @param pk private key to broadcast transaction + modifier broadcast(uint256 pk) { + vm.startBroadcast(pk); + + _; + + vm.stopBroadcast(); + } +} diff --git a/script/DeployAddressesProviderV2.s.sol b/script/DeployAddressesProviderV2.s.sol new file mode 100644 index 0000000..be3db99 --- /dev/null +++ b/script/DeployAddressesProviderV2.s.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import {DeploymentConfig, BaseDeploymentConfig} from "script/BaseConfig.sol"; +import {AddressesProviderV2} from "../src/periphery/AddressesProviderV2.sol"; +import {TransparentUpgradeableProxy} from "./utils/deterministic-deployments/TransparentUpgradeableProxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; + +contract DeployAddressesProviderV2 is Script, BaseDeploymentConfig { + bytes32 internal constant SALT = keccak256("sismo-addresses-provider-V2"); + // create2Factory address from https://github.com/Arachnid/deterministic-deployment-proxy + address internal constant CREATE2_FACTORY_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + address internal constant DETERMINISTIC_DEPLOYMENT_ADDRESS = + 0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6; + + function run() public returns (AddressesProviderV2) { + string memory chainName = vm.envString("CHAIN_NAME"); + return runFor(chainName); + } + + function runFor(string memory chainName) public returns (AddressesProviderV2) { + console.log("Run for CHAIN_NAME:", chainName); + console.log("Deployer:", msg.sender); + + _setDeploymentConfig({chainName: chainName, checkIfEmpty: true}); + + address addressesProviderV2Address = config.sismoAddressesProviderV2; + address owner = config.owner; + address proxyAdmin = config.proxyAdmin; + address deployer = msg.sender; + + bytes32 TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH = keccak256( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(CREATE2_FACTORY_ADDRESS, deployer, bytes("")) + ) + ); + + vm.startBroadcast(deployer); + + if (addressesProviderV2Address != address(0)) { + require(false, "AddressesPoviderV2 contract is already deployed!"); + } + + if (deployer != 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24) { + require( + false, + "Only 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24 can deploy AddressesPoviderV2 contract!" + ); + } + if ( + _getAddress(SALT, TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH, CREATE2_FACTORY_ADDRESS) != + DETERMINISTIC_DEPLOYMENT_ADDRESS + ) { + require( + false, + "AddressesPoviderV2 contract address should be 0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6!" + ); + } + + console.log("Deploying AddressesPoviderV2 Proxy..."); + + // deterministicly deploy the proxy by porviding the create2Factory address as implementation address + TransparentUpgradeableProxy addressesProviderV2Proxy = new TransparentUpgradeableProxy{ + salt: SALT + }(CREATE2_FACTORY_ADDRESS, deployer, bytes("")); + console.log("AddressesPoviderV2 Proxy Deployed:", address(addressesProviderV2Proxy)); + + AddressesProviderV2 addressesProviderV2Implem = new AddressesProviderV2(deployer); + console.log("AddressesPoviderV2 Implem Deployed:", address(addressesProviderV2Implem)); + + // Upgrade the proxy to use the correct deployed implementation + addressesProviderV2Proxy.upgradeToAndCall( + address(addressesProviderV2Implem), + abi.encodeWithSelector(addressesProviderV2Implem.initialize.selector, deployer) + ); + + // change proxy admin to proxyAdmin + if (addressesProviderV2Proxy.admin() != proxyAdmin) { + addressesProviderV2Proxy.changeAdmin(proxyAdmin); + console.log("AddressesPoviderV2 proxy admin changed from", deployer, "to", proxyAdmin); + } + + AddressesProviderV2 addressesProviderV2 = AddressesProviderV2( + address(addressesProviderV2Proxy) + ); + + // transfer ownership to owner + if (addressesProviderV2.owner() != owner) { + addressesProviderV2.transferOwnership(owner); + console.log("AddressesPoviderV2 ownership transferred from", deployer, "to", owner); + } + + DeploymentConfig memory newDeploymentConfig = DeploymentConfig({ + proxyAdmin: config.proxyAdmin, + owner: config.owner, + rootsOwner: config.rootsOwner, + commitmentMapperEdDSAPubKey: config.commitmentMapperEdDSAPubKey, + sismoAddressesProviderV2: address(addressesProviderV2), + availableRootsRegistry: config.availableRootsRegistry, + commitmentMapperRegistry: config.commitmentMapperRegistry, + hydraS3Verifier: config.hydraS3Verifier, + sismoConnectVerifier: config.sismoConnectVerifier, + authRequestBuilder: config.authRequestBuilder, + claimRequestBuilder: config.claimRequestBuilder, + signatureBuilder: config.signatureBuilder, + requestBuilder: config.requestBuilder + }); + + _saveDeploymentConfig(chainName, newDeploymentConfig); + + vm.stopBroadcast(); + + return addressesProviderV2; + } + + function _getAddress( + bytes32 _salt, + bytes32 _initCodeHash, + address create2FactoryAddress + ) private pure returns (address) { + address deterministicAddress = Create2.computeAddress( + _salt, + _initCodeHash, + create2FactoryAddress + ); + return deterministicAddress; + } +} diff --git a/script/DeployAvailableRootsRegistry.s.sol b/script/DeployAvailableRootsRegistry.s.sol new file mode 100644 index 0000000..8f2c16d --- /dev/null +++ b/script/DeployAvailableRootsRegistry.s.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import {DeploymentConfig, BaseDeploymentConfig} from "script/BaseConfig.sol"; +import {AvailableRootsRegistry} from "../src/periphery/AvailableRootsRegistry.sol"; +import {TransparentUpgradeableProxy} from "./utils/deterministic-deployments/TransparentUpgradeableProxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; + +contract DeployAvailableRootsRegistry is Script, BaseDeploymentConfig { + bytes32 internal constant SALT = keccak256("sismo-available-roots-registry"); + // create2Factory address from https://github.com/Arachnid/deterministic-deployment-proxy + address internal constant CREATE2_FACTORY_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + address internal constant DETERMINISTIC_DEPLOYMENT_ADDRESS = + 0xfB548eC30347c220E4e7733248ff25e3699A4648; + + function run() public returns (AvailableRootsRegistry) { + string memory chainName = vm.envString("CHAIN_NAME"); + return runFor(chainName); + } + + function runFor(string memory chainName) public returns (AvailableRootsRegistry) { + console.log("Run for CHAIN_NAME:", chainName); + console.log("Deployer:", msg.sender); + + _setDeploymentConfig({chainName: chainName, checkIfEmpty: true}); + + address availableRootsRegistryAddress = config.availableRootsRegistry; + address owner = config.owner; + address proxyAdmin = config.proxyAdmin; + address deployer = msg.sender; + + bytes32 TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH = keccak256( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(CREATE2_FACTORY_ADDRESS, deployer, bytes("")) + ) + ); + + vm.startBroadcast(deployer); + + if ((availableRootsRegistryAddress != address(0)) && (!_compareStrings(chainName, "test"))) { + require(false, "AvailableRootsRegistry contract is already deployed!"); + } + + if ( + (deployer != 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24) && + (!_compareStrings(chainName, "test")) + ) { + require( + false, + "Only 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24 can deploy AvailableRootsRegistry contract!" + ); + } + if ( + (_getAddress(SALT, TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH, CREATE2_FACTORY_ADDRESS) != + DETERMINISTIC_DEPLOYMENT_ADDRESS) && (!_compareStrings(chainName, "test")) + ) { + require( + false, + "AvailableRootsRegistry contract address should be 0xfB548eC30347c220E4e7733248ff25e3699A4648!" + ); + } + + console.log("Deploying AvailableRootsRegistry Proxy..."); + + // deterministicly deploy the proxy by porviding the create2Factory address as implementation address + TransparentUpgradeableProxy availableRootsRegistryProxy = new TransparentUpgradeableProxy{ + salt: SALT + }(CREATE2_FACTORY_ADDRESS, deployer, bytes("")); + console.log("AvailableRootsRegistry Proxy Deployed:", address(availableRootsRegistryProxy)); + + AvailableRootsRegistry availableRootsRegistryImplem = new AvailableRootsRegistry(deployer); + console.log("AvailableRootsRegistry Implem Deployed:", address(availableRootsRegistryImplem)); + + // Upgrade the proxy to use the correct deployed implementation + availableRootsRegistryProxy.upgradeToAndCall( + address(availableRootsRegistryImplem), + abi.encodeWithSelector(availableRootsRegistryImplem.initialize.selector, deployer) + ); + + if (availableRootsRegistryProxy.admin() != proxyAdmin) { + // change proxy admin to proxyAdmin + availableRootsRegistryProxy.changeAdmin(proxyAdmin); + console.log("AvailableRootsRegistry proxy admin changed from", deployer, "to", proxyAdmin); + } + + AvailableRootsRegistry availableRootsRegistry = AvailableRootsRegistry( + address(availableRootsRegistryProxy) + ); + + if (availableRootsRegistry.owner() != owner) { + // transfer ownership to owner + availableRootsRegistry.transferOwnership(owner); + console.log("AvailableRootsRegistry ownership transferred from", deployer, "to", owner); + } + + DeploymentConfig memory newDeploymentConfig = DeploymentConfig({ + proxyAdmin: proxyAdmin, + owner: owner, + rootsOwner: config.rootsOwner, + commitmentMapperEdDSAPubKey: config.commitmentMapperEdDSAPubKey, + sismoAddressesProviderV2: config.sismoAddressesProviderV2, + availableRootsRegistry: address(availableRootsRegistry), + commitmentMapperRegistry: config.commitmentMapperRegistry, + hydraS3Verifier: config.hydraS3Verifier, + sismoConnectVerifier: config.sismoConnectVerifier, + authRequestBuilder: config.authRequestBuilder, + claimRequestBuilder: config.claimRequestBuilder, + signatureBuilder: config.signatureBuilder, + requestBuilder: config.requestBuilder + }); + + _saveDeploymentConfig(chainName, newDeploymentConfig); + + vm.stopBroadcast(); + + return availableRootsRegistry; + } + + function _getAddress( + bytes32 _salt, + bytes32 _initCodeHash, + address create2FactoryAddress + ) private pure returns (address) { + address deterministicAddress = Create2.computeAddress( + _salt, + _initCodeHash, + create2FactoryAddress + ); + return deterministicAddress; + } +} diff --git a/script/DeployCommitmentMapperRegistry.s.sol b/script/DeployCommitmentMapperRegistry.s.sol new file mode 100644 index 0000000..5ef954d --- /dev/null +++ b/script/DeployCommitmentMapperRegistry.s.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import {DeploymentConfig, BaseDeploymentConfig} from "script/BaseConfig.sol"; +import {CommitmentMapperRegistry} from "../src/periphery/CommitmentMapperRegistry.sol"; +import {TransparentUpgradeableProxy} from "./utils/deterministic-deployments/TransparentUpgradeableProxy.sol"; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; + +contract DeployCommitmentMapperRegistry is Script, BaseDeploymentConfig { + bytes32 internal constant SALT = keccak256("sismo-commitment-mapper-registry"); + // create2Factory address from https://github.com/Arachnid/deterministic-deployment-proxy + address internal constant CREATE2_FACTORY_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + address internal constant DETERMINISTIC_DEPLOYMENT_ADDRESS = + 0x2ff87b43dbE95d94F56F059cA3506d5d4E8F0470; + + function run() public returns (CommitmentMapperRegistry) { + string memory chainName = vm.envString("CHAIN_NAME"); + return runFor(chainName); + } + + function runFor(string memory chainName) public returns (CommitmentMapperRegistry) { + console.log("Run for CHAIN_NAME:", chainName); + console.log("Deployer:", msg.sender); + + _setDeploymentConfig({chainName: chainName, checkIfEmpty: true}); + + address commitmentMapperRegistryAddress = config.commitmentMapperRegistry; + address owner = config.owner; + uint256[2] memory commitmentMapperPubKeys = config.commitmentMapperEdDSAPubKey; + address proxyAdmin = config.proxyAdmin; + address deployer = msg.sender; + + bytes32 TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH = keccak256( + abi.encodePacked( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(CREATE2_FACTORY_ADDRESS, deployer, bytes("")) + ) + ); + + vm.startBroadcast(deployer); + + if ((commitmentMapperRegistryAddress != address(0)) && (!_compareStrings(chainName, "test"))) { + require(false, "CommitmentMapperRegistry contract is already deployed!"); + } + + if ( + (deployer != 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24) && + (!_compareStrings(chainName, "test")) + ) { + require( + false, + "Only 0x36D79cf2448b6063DdA4338352da4AFD4C16bf24 can deploy CommitmentMapperRegistry contract!" + ); + } + if ( + (_getAddress(SALT, TRANSPARENT_UPGRADEABLE_PROXY_INIT_CODE_HASH, CREATE2_FACTORY_ADDRESS) != + DETERMINISTIC_DEPLOYMENT_ADDRESS) && (!_compareStrings(chainName, "test")) + ) { + require( + false, + "CommitmentMapperRegistry contract address should be 0x2ff87b43dbE95d94F56F059cA3506d5d4E8F0470!" + ); + } + + console.log("Deploying CommitmentMapperRegistry Proxy..."); + + // deterministicly deploy the proxy by porviding the create2Factory address as implementation address + TransparentUpgradeableProxy commitmentMapperRegistryProxy = new TransparentUpgradeableProxy{ + salt: SALT + }(CREATE2_FACTORY_ADDRESS, deployer, bytes("")); + console.log("CommitmentMapperRegistry Proxy Deployed:", address(commitmentMapperRegistryProxy)); + + CommitmentMapperRegistry commitmentMapperRegistryImplem = new CommitmentMapperRegistry( + deployer, + commitmentMapperPubKeys + ); + console.log( + "CommitmentMapperRegistry Implem Deployed:", + address(commitmentMapperRegistryImplem) + ); + + // Upgrade the proxy to use the correct deployed implementation + commitmentMapperRegistryProxy.upgradeToAndCall( + address(commitmentMapperRegistryImplem), + abi.encodeWithSelector( + commitmentMapperRegistryImplem.initialize.selector, + deployer, + commitmentMapperPubKeys + ) + ); + + if (commitmentMapperRegistryProxy.admin() != proxyAdmin) { + // change proxy admin to proxyAdmin + commitmentMapperRegistryProxy.changeAdmin(proxyAdmin); + console.log("CommitmentMapperRegistry proxy admin changed from", deployer, "to", proxyAdmin); + } + + CommitmentMapperRegistry commitmentMapperRegistry = CommitmentMapperRegistry( + address(commitmentMapperRegistryProxy) + ); + + if (commitmentMapperRegistry.owner() != owner) { + // change owner to owner + commitmentMapperRegistry.transferOwnership(owner); + console.log("CommitmentMapperRegistry ownership transferred from", deployer, "to", owner); + } + + DeploymentConfig memory newDeploymentConfig = DeploymentConfig({ + proxyAdmin: proxyAdmin, + owner: owner, + rootsOwner: config.rootsOwner, + commitmentMapperEdDSAPubKey: commitmentMapperPubKeys, + sismoAddressesProviderV2: config.sismoAddressesProviderV2, + availableRootsRegistry: config.availableRootsRegistry, + commitmentMapperRegistry: address(commitmentMapperRegistry), + hydraS3Verifier: config.hydraS3Verifier, + sismoConnectVerifier: config.sismoConnectVerifier, + authRequestBuilder: config.authRequestBuilder, + claimRequestBuilder: config.claimRequestBuilder, + signatureBuilder: config.signatureBuilder, + requestBuilder: config.requestBuilder + }); + + _saveDeploymentConfig(chainName, newDeploymentConfig); + + vm.stopBroadcast(); + + return commitmentMapperRegistry; + } + + function _getAddress( + bytes32 _salt, + bytes32 _initCodeHash, + address create2FactoryAddress + ) private pure returns (address) { + address deterministicAddress = Create2.computeAddress( + _salt, + _initCodeHash, + create2FactoryAddress + ); + return deterministicAddress; + } +} diff --git a/script/bash/setup-fork.sh b/script/bash/setup-fork.sh new file mode 100755 index 0000000..54e00e8 --- /dev/null +++ b/script/bash/setup-fork.sh @@ -0,0 +1,60 @@ +#! /bin/bash + +# Usage +# in a first terminal, launch a fork with anvil: `anvil --fork-url https://rpc.ankr.com/polygon_mumbai` +# in a second terminal, setup the fork to your needs: `yarn setup-fork testnet-mumbai` + +# Get chain name from command line arguments to get the config file +chain_name=$1 +config_file="./deployments/tmp/${chain_name}.json" +ADDRESSES_PROVIDER_V2_ADDRESS=0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6 + +# Deploy Sismo Connect protocol contracts on a local fork +# Deployment is made from the first account of anvil +FORK=true CHAIN_NAME=$chain_name forge script DeployAll --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast + +# Get AddressesProvider owner +ADDRESSES_PROVIDER_OWNER=$(cast call $ADDRESSES_PROVIDER_V2_ADDRESS 'owner()' --rpc-url http://localhost:8545 | sed 's/000000000000000000000000//') +# Impersonate AddressesProvider owner +cast rpc anvil_impersonateAccount "$ADDRESSES_PROVIDER_OWNER" + +# Check if config file is provided and exists +if [[ -z "$config_file" ]]; then + echo "Usage: $0 " + exit 1 +elif [[ ! -f "$config_file" ]]; then + echo "Error: Config file $config_file does not exist." + exit 1 +fi + +# Define the contract names +declare -a contract_keys=("authRequestBuilder" + "availableRootsRegistry" + "claimRequestBuilder" + "commitmentMapperRegistry" + "hydraS3Verifier" + "requestBuilder" + "signatureBuilder" + "sismoConnectVerifier") + +declare -a contract_values=("authRequestBuilder-v1.1" + "sismoConnectAvailableRootsRegistry" + "claimRequestBuilder-v1.1" + "sismoConnectCommitmentMapperRegistry" + "hydraS3Verifier" + "requestBuilder-v1.1" + "signatureBuilder-v1.1" + "sismoConnectVerifier-v1.2") + +# Loop over contract names +for index in "${!contract_keys[@]}" +do + name=${contract_keys[$index]} + value=${contract_values[$index]} + echo "Set address of contract ${name} to ${value} in the AddressesProvider" + # Use jq to parse the JSON file and get the contract address + contract_address=$(jq -r .${name} ${config_file}) + + # Set the contract address in the AddressesProvider by impersonating the owner thanks to --unlocked + cast send $ADDRESSES_PROVIDER_V2_ADDRESS "set(address,string)" ${contract_address} ${value} --unlocked --from $ADDRESSES_PROVIDER_OWNER +done \ No newline at end of file diff --git a/script/utils/PrankAddressesProvider.sol b/script/utils/PrankAddressesProvider.sol new file mode 100644 index 0000000..d2dc174 --- /dev/null +++ b/script/utils/PrankAddressesProvider.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import "forge-std/console.sol"; + +import {IAddressesProvider} from "src/periphery/interfaces/IAddressesProvider.sol"; + +contract PrankAddressesProvider is Script { + function run() external { + IAddressesProvider sismoAddressProvider = IAddressesProvider( + 0x3340Ac0CaFB3ae34dDD53dba0d7344C1Cf3EFE05 + ); + // Addressess Provider owner + vm.prank(0xaee4acd5c4Bf516330ca8fe11B07206fC6709294); + sismoAddressProvider.set( + 0xB8159fe3E3a41213d8AeCE447cfE41037F714cA4, + string("sismoConnectVerifier") + ); + } +} diff --git a/script/utils/SetAddressesProvider.s.sol b/script/utils/SetAddressesProvider.s.sol new file mode 100644 index 0000000..b2eed77 --- /dev/null +++ b/script/utils/SetAddressesProvider.s.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Script.sol"; +import "forge-std/console.sol"; + +import {IAddressesProvider} from "src/periphery/interfaces/IAddressesProvider.sol"; +import {BaseDeploymentConfig, DeploymentConfig} from "script/BaseConfig.sol"; + +contract SetAddressesProvider is Script, BaseDeploymentConfig { + function run() external { + string memory chainName = vm.envString("CHAIN_NAME"); + _setDeploymentConfig({chainName: chainName, checkIfEmpty: false}); + + console.log("Run for CHAIN_NAME:", chainName); + console.log("Sender:", msg.sender); + + vm.startBroadcast(); + + _setAddress(config.sismoConnectVerifier, string("sismoConnectVerifier-v1.2")); + _setAddress(config.hydraS3Verifier, string("hydraS3Verifier")); + _setAddress(config.availableRootsRegistry, string("sismoConnectAvailableRootsRegistry")); + _setAddress(config.commitmentMapperRegistry, string("sismoConnectCommitmentMapperRegistry")); + + // external libraries + + _setAddress(config.authRequestBuilder, string("authRequestBuilder-v1.1")); + _setAddress(config.claimRequestBuilder, string("claimRequestBuilder-v1.1")); + _setAddress(config.signatureBuilder, string("signatureBuilder-v1.1")); + _setAddress(config.requestBuilder, string("requestBuilder-v1.1")); + + vm.stopBroadcast(); + } + + function _setAddress(address contractAddress, string memory contractName) internal { + IAddressesProvider sismoAddressProvider = IAddressesProvider(SISMO_ADDRESSES_PROVIDER_V2); + address currentContractAddress = sismoAddressProvider.get(contractName); + + if (currentContractAddress != contractAddress) { + console.log( + "current contract address for ", + contractName, + " is different. Updating address to ", + contractAddress + ); + sismoAddressProvider.set(contractAddress, contractName); + } else { + console.log( + "current contract address for ", + contractName, + " is already the expected one. skipping update" + ); + } + } +} diff --git a/script/utils/deterministic-deployments/TransparentUpgradeableProxy.sol b/script/utils/deterministic-deployments/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..fe45503 --- /dev/null +++ b/script/utils/deterministic-deployments/TransparentUpgradeableProxy.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +///////////////////////////////////////////////////////////////////////////////////// +// This contract should be used for Sismo's deterministic deployments of proxies. // +// It is a copy of the OpenZeppelin's TransparentUpgradeableProxy.sol contract. // +// The tag of the OpenZeppelin library used along this contract should be v4.8.2. // +// The commit hash should be d00acef4059807535af0bd0dd0ddf619747a044b. // +///////////////////////////////////////////////////////////////////////////////////// + +pragma solidity ^0.8.0; + +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +/** + * @dev This contract implements a proxy that is upgradeable by an admin. + * + * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector + * clashing], which can potentially be used in an attack, this contract uses the + * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two + * things that go hand in hand: + * + * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if + * that call matches one of the admin functions exposed by the proxy itself. + * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the + * implementation. If the admin tries to call a function on the implementation it will fail with an error that says + * "admin cannot fallback to proxy target". + * + * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing + * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due + * to sudden errors when trying to call a function from the proxy implementation. + * + * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, + * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. + */ +contract TransparentUpgradeableProxy is ERC1967Proxy { + /** + * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and + * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. + */ + constructor( + address _logic, + address admin_, + bytes memory _data + ) payable ERC1967Proxy(_logic, _data) { + _changeAdmin(admin_); + } + + /** + * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. + */ + modifier ifAdmin() { + if (msg.sender == _getAdmin()) { + _; + } else { + _fallback(); + } + } + + /** + * @dev Returns the current admin. + * + * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. + * + * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the + * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. + * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` + */ + function admin() external ifAdmin returns (address admin_) { + admin_ = _getAdmin(); + } + + /** + * @dev Returns the current implementation. + * + * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. + * + * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the + * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. + * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` + */ + function implementation() external ifAdmin returns (address implementation_) { + implementation_ = _implementation(); + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + * + * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. + */ + function changeAdmin(address newAdmin) external virtual ifAdmin { + _changeAdmin(newAdmin); + } + + /** + * @dev Upgrade the implementation of the proxy. + * + * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. + */ + function upgradeTo(address newImplementation) external ifAdmin { + _upgradeToAndCall(newImplementation, bytes(""), false); + } + + /** + * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified + * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the + * proxied contract. + * + * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. + */ + function upgradeToAndCall( + address newImplementation, + bytes calldata data + ) external payable ifAdmin { + _upgradeToAndCall(newImplementation, data, true); + } + + /** + * @dev Returns the current admin. + */ + function _admin() internal view virtual returns (address) { + return _getAdmin(); + } + + /** + * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. + */ + function _beforeFallback() internal virtual override { + require( + msg.sender != _getAdmin(), + "TransparentUpgradeableProxy: admin cannot fallback to proxy target" + ); + super._beforeFallback(); + } +} diff --git a/src/SismoConnectVerifier.sol b/src/SismoConnectVerifier.sol new file mode 100644 index 0000000..c306fe6 --- /dev/null +++ b/src/SismoConnectVerifier.sol @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "./interfaces/ISismoConnectVerifier.sol"; +import {AuthMatchingLib} from "./utils/AuthMatchingLib.sol"; +import {ClaimMatchingLib} from "./utils/ClaimMatchingLib.sol"; +import {IBaseVerifier} from "./interfaces/IBaseVerifier.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract SismoConnectVerifier is ISismoConnectVerifier, Initializable, Ownable { + using AuthMatchingLib for Auth; + using ClaimMatchingLib for Claim; + + uint8 public constant IMPLEMENTATION_VERSION = 1; + bytes32 public immutable SISMO_CONNECT_VERSION = "sismo-connect-v1.1"; + + mapping(bytes32 => IBaseVerifier) public _verifiers; + + // struct to store informations about the number of verified auths and claims returned + // indexes of the first available slot in the arrays of auths and claims are also stored + // this struct is used to avoid stack to deep errors without using via_ir in foundry + struct VerifiedArraysInfos { + uint256 nbOfAuths; // number of verified auths + uint256 nbOfClaims; // number of verified claims + uint256 authsIndex; // index of the first available slot in the array of verified auths + uint256 claimsIndex; // index of the first available slot in the array of verified claims + } + + // Struct holding the verified Auths and Claims from the snark proofs + // This struct is used to avoid stack too deep error + struct VerifiedProofs { + VerifiedAuth[] auths; + VerifiedClaim[] claims; + } + + constructor(address owner) { + initialize(owner); + } + + function initialize(address ownerAddress) public reinitializer(IMPLEMENTATION_VERSION) { + // if proxy did not setup owner yet or if called by constructor (for implem setup) + if (owner() == address(0) || address(this).code.length == 0) { + _transferOwnership(ownerAddress); + } + } + + function verify( + SismoConnectResponse memory response, + SismoConnectRequest memory request, + SismoConnectConfig memory config + ) external override returns (SismoConnectVerifiedResult memory) { + if (response.appId != config.appId) { + revert AppIdMismatch(response.appId, config.appId); + } + + _checkResponseMatchesWithRequest(response, request); + + uint256 responseProofsArrayLength = response.proofs.length; + VerifiedArraysInfos memory infos = VerifiedArraysInfos({ + nbOfAuths: 0, + nbOfClaims: 0, + authsIndex: 0, + claimsIndex: 0 + }); + + // Count the number of auths and claims in the response + for (uint256 i = 0; i < responseProofsArrayLength; i++) { + infos.nbOfAuths += response.proofs[i].auths.length; + infos.nbOfClaims += response.proofs[i].claims.length; + } + + VerifiedProofs memory verifiedProofs = VerifiedProofs({ + auths: new VerifiedAuth[](infos.nbOfAuths), + claims: new VerifiedClaim[](infos.nbOfClaims) + }); + + for (uint256 i = 0; i < responseProofsArrayLength; i++) { + (VerifiedAuth memory verifiedAuth, VerifiedClaim memory verifiedClaim) = _verifiers[ + response.proofs[i].provingScheme + ].verify({ + appId: response.appId, + namespace: response.namespace, + isImpersonationMode: config.vault.isImpersonationMode, + signedMessage: response.signedMessage, + sismoConnectProof: response.proofs[i] + }); + + // we only want to add the verified auths and claims to the result + // if they are not empty, for that we check the length of the proofData that should always be different from 0 + if (verifiedAuth.proofData.length != 0) { + verifiedProofs.auths[infos.authsIndex] = verifiedAuth; + infos.authsIndex++; + } + if (verifiedClaim.proofData.length != 0) { + verifiedProofs.claims[infos.claimsIndex] = verifiedClaim; + infos.claimsIndex++; + } + } + + return + SismoConnectVerifiedResult({ + appId: response.appId, + namespace: response.namespace, + version: response.version, + auths: verifiedProofs.auths, + claims: verifiedProofs.claims, + signedMessage: response.signedMessage + }); + } + + function _checkResponseMatchesWithRequest( + SismoConnectResponse memory response, + SismoConnectRequest memory request + ) internal view { + if (response.version != SISMO_CONNECT_VERSION) { + revert VersionMismatch(response.version, SISMO_CONNECT_VERSION); + } + + if (response.namespace != request.namespace) { + revert NamespaceMismatch(response.namespace, request.namespace); + } + + // Check if the message of the signature matches between the request and the response + // if the signature request is NOT selectable by the user + if (request.signature.isSelectableByUser == false) { + // Check if the message signature matches between the request and the response + // only if the content of the signature is different from the hash of "MESSAGE_SELECTED_BY_USER" + if ( + keccak256(request.signature.message) != keccak256("MESSAGE_SELECTED_BY_USER") && + // we hash the messages to be able to compare them (as they are of type bytes) + keccak256(request.signature.message) != keccak256(response.signedMessage) + ) { + revert SignatureMessageMismatch(request.signature.message, response.signedMessage); + } + } + + // we store the auths and claims in the response + uint256 nbOfAuths = 0; + uint256 nbOfClaims = 0; + for (uint256 i = 0; i < response.proofs.length; i++) { + nbOfAuths += response.proofs[i].auths.length; + nbOfClaims += response.proofs[i].claims.length; + } + + Auth[] memory authsInResponse = new Auth[](nbOfAuths); + uint256 authsIndex = 0; + Claim[] memory claimsInResponse = new Claim[](nbOfClaims); + uint256 claimsIndex = 0; + // we store the auths and claims in the response in a single respective array + for (uint256 i = 0; i < response.proofs.length; i++) { + // we do a loop on the proofs array and on the auths array of each proof + for (uint256 j = 0; j < response.proofs[i].auths.length; j++) { + authsInResponse[authsIndex] = response.proofs[i].auths[j]; + authsIndex++; + } + // we do a loop on the proofs array and on the claims array of each proof + for (uint256 j = 0; j < response.proofs[i].claims.length; j++) { + claimsInResponse[claimsIndex] = response.proofs[i].claims[j]; + claimsIndex++; + } + } + + // Check if the auths and claims in the request match the auths and claims int the response + _checkAuthsInRequestMatchWithAuthsInResponse({ + authsInRequest: request.auths, + authsInResponse: authsInResponse + }); + _checkClaimsInRequestMatchWithClaimsInResponse({ + claimsInRequest: request.claims, + claimsInResponse: claimsInResponse + }); + } + + function _checkAuthsInRequestMatchWithAuthsInResponse( + AuthRequest[] memory authsInRequest, + Auth[] memory authsInResponse + ) internal pure { + // for each auth in the request, we check if it matches with one of the auths in the response + for (uint256 i = 0; i < authsInRequest.length; i++) { + AuthRequest memory authRequest = authsInRequest[i]; + if (authRequest.isOptional) { + // if the auth in the request is optional, we consider that its properties are all matching + // and we don't need to check for errors + continue; + } + // we store the information about the maximum matching properties in a uint8 + // if the auth in the request matches with an auth in the response, the matchingProperties will be equal to 7 (111) + // otherwise, we can look at the binary representation of the matchingProperties to know which properties are not matching and throw an error + uint8 maxMatchingPropertiesLevel = 0; + + for (uint256 j = 0; j < authsInResponse.length; j++) { + // we store the matching properties for the current auth in the response in a uint8 + // we will store it in the maxMatchingPropertiesLevel variable if it is greater than the current value of maxMatchingPropertiesLevel + Auth memory auth = authsInResponse[j]; + uint8 matchingPropertiesLevel = auth._matchLevel(authRequest); + + // if the matchingPropertiesLevel are greater than the current value of maxMatchingPropertiesLevel, we update the value of maxMatchingPropertiesLevel + // by doing so we will be able to know how close the auth in the request is to the auth in the response + if (matchingPropertiesLevel > maxMatchingPropertiesLevel) { + maxMatchingPropertiesLevel = matchingPropertiesLevel; + } + } + AuthMatchingLib.handleAuthErrors(maxMatchingPropertiesLevel, authRequest); + } + } + + function _checkClaimsInRequestMatchWithClaimsInResponse( + ClaimRequest[] memory claimsInRequest, + Claim[] memory claimsInResponse + ) internal pure { + // for each claim in the request, we check if it matches with one of the claims in the response + for (uint256 i = 0; i < claimsInRequest.length; i++) { + ClaimRequest memory claimRequest = claimsInRequest[i]; + if (claimRequest.isOptional) { + // if the claim in the request is optional, we consider that its properties are all matching + continue; + } + // we store the information about the maximum matching properties in a uint8 + // if the claim in the request matches with a claim in the response, the matchingProperties will be equal to 7 (111) + // otherwise, we can look at the binary representation of the matchingProperties to know which properties are not matching and throw an error + uint8 maxMatchingProperties = 0; + + for (uint256 j = 0; j < claimsInResponse.length; j++) { + Claim memory claim = claimsInResponse[j]; + uint8 matchingProperties = claim._matchLevel(claimRequest); + + // if the matchingProperties are greater than the current value of maxMatchingProperties, we update the value of maxMatchingProperties + // by doing so we will be able to know how close the claim in the request is to the claim in the response + if (matchingProperties > maxMatchingProperties) { + maxMatchingProperties = matchingProperties; + } + } + ClaimMatchingLib.handleClaimErrors(maxMatchingProperties, claimRequest); + } + } + + function registerVerifier(bytes32 provingScheme, address verifierAddress) public onlyOwner { + _setVerifier(provingScheme, verifierAddress); + } + + function getVerifier(bytes32 provingScheme) public view returns (address) { + return address(_verifiers[provingScheme]); + } + + function _setVerifier(bytes32 provingScheme, address verifierAddress) internal { + _verifiers[provingScheme] = IBaseVerifier(verifierAddress); + emit VerifierSet(provingScheme, verifierAddress); + } +} diff --git a/src/misc/CheatSheet.sol b/src/misc/CheatSheet.sol new file mode 100644 index 0000000..cbe7fae --- /dev/null +++ b/src/misc/CheatSheet.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "src/SismoConnectLib.sol"; +import "forge-std/console.sol"; + +contract CheatSheet is SismoConnect { + // reference your appId + bytes16 private _appId = 0x32403ced4b65f2079eda77c84e7d2be6; + // allow impersonation + bool private _isImpersonationMode = true; + + constructor() + // use buildConfig helper to easily build a Sismo Connect config in Solidity + SismoConnect(buildConfig({appId: _appId, isImpersonationMode: _isImpersonationMode})) + {} + + function verifySismoConnectResponse(bytes memory response) public { + // Recreate the request made in the fontend to verify the proof + AuthRequest[] memory auths = new AuthRequest[](6); + auths[0] = _authRequestBuilder.build({authType: AuthType.VAULT}); + auths[1] = _authRequestBuilder.build({authType: AuthType.EVM_ACCOUNT}); + auths[2] = _authRequestBuilder.build({ + authType: AuthType.EVM_ACCOUNT, + userId: uint160(0xA4C94A6091545e40fc9c3E0982AEc8942E282F38) + }); + auths[3] = _authRequestBuilder.build({authType: AuthType.GITHUB}); + auths[4] = _authRequestBuilder.build({ + authType: AuthType.TWITTER, + userId: 295218901, + isOptional: true, + isSelectableByUser: false + }); + auths[5] = _authRequestBuilder.build({ + authType: AuthType.TELEGRAM, + userId: 875608110, + isOptional: true, + isSelectableByUser: false + }); + + ClaimRequest[] memory claims = new ClaimRequest[](6); + claims[0] = _claimRequestBuilder.build({groupId: 0xfae674b6cba3ff2f8ce2114defb200b1}); + claims[1] = _claimRequestBuilder.build({ + groupId: 0x1cde61966decb8600dfd0749bd371f12, + claimType: ClaimType.GTE, + value: 15 + }); + claims[2] = _claimRequestBuilder.build({ + groupId: 0xfae674b6cba3ff2f8ce2114defb200b1, + claimType: ClaimType.EQ, + value: 10 + }); + claims[3] = _claimRequestBuilder.build({ + groupId: 0x1cde61966decb8600dfd0749bd371f12, + claimType: ClaimType.EQ, + value: 15, + isSelectableByUser: true, + isOptional: true + }); + claims[4] = _claimRequestBuilder.build({ + groupId: 0xfae674b6cba3ff2f8ce2114defb200b1, + claimType: ClaimType.GTE, + isSelectableByUser: true, + isOptional: true + }); + claims[5] = _claimRequestBuilder.build({ + groupId: 0x1cde61966decb8600dfd0749bd371f12, + claimType: ClaimType.GTE, + value: 25, + isSelectableByUser: true, + isOptional: false + }); + + SismoConnectVerifiedResult memory result = verify({ + responseBytes: response, + auths: auths, + claims: claims, + signature: _signatureBuilder.build({message: abi.encode("I love Sismo!")}) + }); + + uint256 vaultId = SismoConnectHelper.getUserId(result, AuthType.VAULT); + uint256 githubId = SismoConnectHelper.getUserId(result, AuthType.GITHUB); + uint256 telegramId = SismoConnectHelper.getUserId(result, AuthType.TELEGRAM); + uint256[] memory evmAccountIds = SismoConnectHelper.getUserIds(result, AuthType.EVM_ACCOUNT); + + console.log("Vault ID: %s", vaultId); + console.log("Github ID: %s", githubId); + console.log("Telegram ID: %s", telegramId); + console.log("First EVM Account ID: %s", evmAccountIds[0]); + console.log("Second EVM Account ID: %s", evmAccountIds[1]); + } +} diff --git a/src/misc/ZKDropERC721.sol b/src/misc/ZKDropERC721.sol new file mode 100644 index 0000000..87281a3 --- /dev/null +++ b/src/misc/ZKDropERC721.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "src/SismoConnectLib.sol"; +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract ZKDropERC721 is ERC721, SismoConnect { + using SismoConnectHelper for SismoConnectVerifiedResult; + + bytes16 public immutable GROUP_ID; + + string private _baseTokenURI; + + event BaseTokenURIChanged(string baseTokenURI); + + constructor( + string memory name, + string memory symbol, + string memory baseTokenURI, + bytes16 appId, + bytes16 groupId + ) ERC721(name, symbol) SismoConnect(buildConfig(appId)) { + GROUP_ID = groupId; + _setBaseTokenURI(baseTokenURI); + } + + function claimWithSismoConnect(bytes memory response, address to) public { + SismoConnectVerifiedResult memory result = verify({ + responseBytes: response, + auth: buildAuth({authType: AuthType.VAULT}), + claim: buildClaim({groupId: GROUP_ID}), + signature: buildSignature({message: abi.encode(to)}) + }); + + uint256 tokenId = result.getUserId(AuthType.VAULT); + _mint(to, tokenId); + } + + function transferWithSismoConnect(bytes memory response, address to) public { + SismoConnectVerifiedResult memory result = verify({ + responseBytes: response, + auth: buildAuth({authType: AuthType.VAULT}), + claim: buildClaim({groupId: GROUP_ID}), + signature: buildSignature({message: abi.encode(to)}) + }); + + uint256 tokenId = result.getUserId(AuthType.VAULT); + address from = ownerOf(tokenId); + _transfer(from, to, tokenId); + } + + function tokenURI(uint256) public view virtual override returns (string memory) { + return _baseTokenURI; + } + + function _setBaseTokenURI(string memory baseURI) private { + _baseTokenURI = baseURI; + emit BaseTokenURIChanged(baseURI); + } +} diff --git a/src/periphery/AddressesProviderV2.sol b/src/periphery/AddressesProviderV2.sol new file mode 100644 index 0000000..3acecd7 --- /dev/null +++ b/src/periphery/AddressesProviderV2.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +import {IAddressesProvider} from "./interfaces/IAddressesProvider.sol"; + +contract AddressesProviderV2 is IAddressesProvider, Initializable, Ownable { + uint8 public constant IMPLEMENTATION_VERSION = 1; + + mapping(bytes32 => address) private _contractAddresses; + string[] private _contractNames; + + event ContractAddressSet(address contractAddress, string contractName); + + constructor(address ownerAddress) { + initialize(ownerAddress); + } + + function initialize(address ownerAddress) public reinitializer(IMPLEMENTATION_VERSION) { + // if proxy did not setup owner yet or if called by constructor (for implem setup) + if (owner() == address(0) || address(this).code.length == 0) { + _transferOwnership(ownerAddress); + } + } + + /** + * @dev Sets the address of a contract. + * @param contractAddress Address of the contract. + * @param contractName Name of the contract. + */ + function set(address contractAddress, string memory contractName) public onlyOwner { + _set(contractAddress, contractName); + } + + /** + * @dev Sets the address of multiple contracts. + * @param contractAddresses Addresses of the contracts. + * @param contractNames Names of the contracts. + */ + function setBatch( + address[] calldata contractAddresses, + string[] calldata contractNames + ) external onlyOwner { + for (uint256 i = 0; i < contractAddresses.length; i++) { + _set(contractAddresses[i], contractNames[i]); + } + } + + /** + * @dev Returns the address of a contract. + * @param contractName Name of the contract (string). + * @return Address of the contract. + */ + function get(string memory contractName) public view returns (address) { + bytes32 contractNameHash = keccak256(abi.encodePacked(contractName)); + + return _contractAddresses[contractNameHash]; + } + + /** + * @dev Returns the address of a contract. + * @param contractNameHash Hash of the name of the contract (bytes32). + * @return Address of the contract. + */ + function get(bytes32 contractNameHash) public view returns (address) { + return _contractAddresses[contractNameHash]; + } + + /** + * @dev Returns the addresses of all contracts inputed. + * @param contractNames Names of the contracts as strings. + */ + function getBatch(string[] calldata contractNames) external view returns (address[] memory) { + address[] memory contractAddresses = new address[](contractNames.length); + + for (uint256 i = 0; i < contractNames.length; i++) { + contractAddresses[i] = get(contractNames[i]); + } + + return contractAddresses; + } + + /** + * @dev Returns the addresses of all contracts inputed. + * @param contractNamesHash Names of the contracts as bytes32. + */ + function getBatch(bytes32[] calldata contractNamesHash) external view returns (address[] memory) { + address[] memory contractAddresses = new address[](contractNamesHash.length); + + for (uint256 i = 0; i < contractNamesHash.length; i++) { + contractAddresses[i] = get(contractNamesHash[i]); + } + + return contractAddresses; + } + + /** + * @dev Returns the addresses of all contracts in `_contractNames` + * @return Names, Hashed Names and Addresses of all contracts. + */ + function getAll() external view returns (string[] memory, bytes32[] memory, address[] memory) { + string[] memory contractNames = _contractNames; + bytes32[] memory contractNamesHash = new bytes32[](contractNames.length); + address[] memory contractAddresses = new address[](contractNames.length); + + for (uint256 i = 0; i < contractNames.length; i++) { + contractAddresses[i] = get(contractNames[i]); + contractNamesHash[i] = keccak256(abi.encodePacked(contractNames[i])); + } + + return (contractNames, contractNamesHash, contractAddresses); + } + + /** + * @dev Sets the address of a contract. + * @param contractAddress Address of the contract. + * @param contractName Name of the contract. + */ + function _set(address contractAddress, string memory contractName) internal { + bytes32 contractNameHash = keccak256(abi.encodePacked(contractName)); + + if (_contractAddresses[contractNameHash] == address(0)) { + _contractNames.push(contractName); + } + + _contractAddresses[contractNameHash] = contractAddress; + + emit ContractAddressSet(contractAddress, contractName); + } +} diff --git a/src/periphery/AvailableRootsRegistry.sol b/src/periphery/AvailableRootsRegistry.sol new file mode 100644 index 0000000..3265927 --- /dev/null +++ b/src/periphery/AvailableRootsRegistry.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IAvailableRootsRegistry} from "./interfaces/IAvailableRootsRegistry.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +/** + * @title Attesters Groups Registry + * @author Sismo + * @notice This contract stores that data required by attesters to be available so they can verify user claims + * This contract is deployed behind a proxy and this implementation is focused on storing merkle roots + * For more information: https://available-roots-registry.docs.sismo.io + * + * + */ +contract AvailableRootsRegistry is IAvailableRootsRegistry, Initializable, Ownable { + uint8 public constant IMPLEMENTATION_VERSION = 1; + + mapping(uint256 => bool) public _roots; + + /** + * @dev Constructor + * @param owner Owner of the contract, can register/ unregister roots + */ + constructor(address owner) { + initialize(owner); + } + + /** + * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation + * @param ownerAddress Owner of the contract, can update public key and address + * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. + */ + function initialize(address ownerAddress) public reinitializer(IMPLEMENTATION_VERSION) { + // if proxy did not setup owner yet or if called by constructor (for implem setup) + if (owner() == address(0) || address(this).code.length == 0) { + _transferOwnership(ownerAddress); + } + } + + /** + * @dev Registers a root + * @param root Root to register + */ + function registerRoot(uint256 root) external onlyOwner { + _registerRoot(root); + } + + /** + * @dev Unregister a root + * @param root Root to unregister + */ + function unregisterRoot(uint256 root) external onlyOwner { + _unregisterRoot(root); + } + + /** + * @dev returns whether a root is available + * @param root root to check whether it is registered + */ + function isRootAvailable(uint256 root) external view returns (bool) { + return _roots[root]; + } + + function _registerRoot(uint256 root) internal { + _roots[root] = true; + emit RegisteredRoot(root); + } + + function _unregisterRoot(uint256 root) internal { + _roots[root] = false; + emit UnregisteredRoot(root); + } +} diff --git a/src/periphery/CommitmentMapperRegistry.sol b/src/periphery/CommitmentMapperRegistry.sol new file mode 100644 index 0000000..f2cbe88 --- /dev/null +++ b/src/periphery/CommitmentMapperRegistry.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {ICommitmentMapperRegistry} from "./interfaces/ICommitmentMapperRegistry.sol"; + +/** + * @title Commitment Mapper Registry Contract + * @author Sismo + * @notice This contract stores information about the commitment mapper. + * Its ethereum address and its EdDSA public key + * For more information: https://commitment-mapper.docs.sismo.io + * + * + */ +contract CommitmentMapperRegistry is ICommitmentMapperRegistry, Initializable, Ownable { + uint8 public constant IMPLEMENTATION_VERSION = 1; + + uint256[2] internal _commitmentMapperPubKey; + + /** + * @dev Constructor + * @param owner Owner of the contract, can update public key and address + * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper + */ + constructor(address owner, uint256[2] memory commitmentMapperEdDSAPubKey) { + initialize(owner, commitmentMapperEdDSAPubKey); + } + + /** + * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation + * @param ownerAddress Owner of the contract, can update public key and address + * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper + * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. + */ + function initialize( + address ownerAddress, + uint256[2] memory commitmentMapperEdDSAPubKey + ) public reinitializer(IMPLEMENTATION_VERSION) { + // if proxy did not setup owner yet or if called by constructor (for implem setup) + if (owner() == address(0) || address(this).code.length == 0) { + _transferOwnership(ownerAddress); + _updateCommitmentMapperEdDSAPubKey(commitmentMapperEdDSAPubKey); + } + } + + /** + * @dev Updates the EdDSA public key + * @param newEdDSAPubKey new EdDSA pubic key + */ + function updateCommitmentMapperEdDSAPubKey(uint256[2] memory newEdDSAPubKey) external onlyOwner { + _updateCommitmentMapperEdDSAPubKey(newEdDSAPubKey); + } + + /** + * @dev Getter of the EdDSA public key of the commitment mapper + */ + function getEdDSAPubKey() external view override returns (uint256[2] memory) { + return _commitmentMapperPubKey; + } + + function _updateCommitmentMapperEdDSAPubKey(uint256[2] memory pubKey) internal { + _commitmentMapperPubKey = pubKey; + emit UpdatedCommitmentMapperEdDSAPubKey(pubKey); + } +} diff --git a/src/periphery/interfaces/IAddressesProvider.sol b/src/periphery/interfaces/IAddressesProvider.sol new file mode 100644 index 0000000..54b42e6 --- /dev/null +++ b/src/periphery/interfaces/IAddressesProvider.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +interface IAddressesProvider { + /** + * @dev Sets the address of a contract. + * @param contractAddress Address of the contract. + * @param contractName Name of the contract. + */ + function set(address contractAddress, string memory contractName) external; + + /** + * @dev Sets the address of multiple contracts. + * @param contractAddresses Addresses of the contracts. + * @param contractNames Names of the contracts. + */ + function setBatch(address[] calldata contractAddresses, string[] calldata contractNames) external; + + /** + * @dev Returns the address of a contract. + * @param contractName Name of the contract (string). + * @return Address of the contract. + */ + function get(string memory contractName) external view returns (address); + + /** + * @dev Returns the address of a contract. + * @param contractNameHash Hash of the name of the contract (bytes32). + * @return Address of the contract. + */ + function get(bytes32 contractNameHash) external view returns (address); + + /** + * @dev Returns the addresses of all contracts inputed. + * @param contractNames Names of the contracts as strings. + */ + function getBatch(string[] calldata contractNames) external view returns (address[] memory); + + /** + * @dev Returns the addresses of all contracts inputed. + * @param contractNamesHash Names of the contracts as strings. + */ + function getBatch(bytes32[] calldata contractNamesHash) external view returns (address[] memory); + + /** + * @dev Returns the addresses of all contracts in `_contractNames` + * @return Names, Hashed Names and Addresses of all contracts. + */ + function getAll() external view returns (string[] memory, bytes32[] memory, address[] memory); +} diff --git a/src/periphery/interfaces/IAvailableRootsRegistry.sol b/src/periphery/interfaces/IAvailableRootsRegistry.sol new file mode 100644 index 0000000..338218b --- /dev/null +++ b/src/periphery/interfaces/IAvailableRootsRegistry.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +/** + * @title IAvailableRootsRegistry + * @author Sismo + * @notice Interface for (Merkle) Roots Registry + */ +interface IAvailableRootsRegistry { + event RegisteredRoot(uint256 root); + event UnregisteredRoot(uint256 root); + + /** + * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation + * @param owner Owner of the contract, can update public key and address + * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. + */ + function initialize(address owner) external; + + /** + * @dev Register a root + * @param root Root to register + */ + function registerRoot(uint256 root) external; + + /** + * @dev Unregister a root + * @param root Root to unregister + */ + function unregisterRoot(uint256 root) external; + + /** + * @dev returns whether a root is available + * @param root root to check whether it is registered + */ + function isRootAvailable(uint256 root) external view returns (bool); +} diff --git a/src/periphery/interfaces/ICommitmentMapperRegistry.sol b/src/periphery/interfaces/ICommitmentMapperRegistry.sol new file mode 100644 index 0000000..9b4df2d --- /dev/null +++ b/src/periphery/interfaces/ICommitmentMapperRegistry.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +interface ICommitmentMapperRegistry { + event UpdatedCommitmentMapperEdDSAPubKey(uint256[2] newEdDSAPubKey); + + error PubKeyNotValid(uint256[2] pubKey); + + /** + * @dev Initializes the contract, to be called by the proxy delegating calls to this implementation + * @param owner Owner of the contract, can update public key and address + * @param commitmentMapperEdDSAPubKey EdDSA public key of the commitment mapper + * @notice The reinitializer modifier is needed to configure modules that are added through upgrades and that require initialization. + */ + function initialize(address owner, uint256[2] memory commitmentMapperEdDSAPubKey) external; + + /** + * @dev Updates the EdDSA public key + * @param newEdDSAPubKey new EdDSA pubic key + */ + function updateCommitmentMapperEdDSAPubKey(uint256[2] memory newEdDSAPubKey) external; + + /** + * @dev Getter of the address of the commitment mapper + */ + function getEdDSAPubKey() external view returns (uint256[2] memory); +} diff --git a/src/verifiers/HydraS3Lib.sol b/src/verifiers/HydraS3Lib.sol new file mode 100644 index 0000000..7ba5307 --- /dev/null +++ b/src/verifiers/HydraS3Lib.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +struct HydraS3CircomSnarkProof { + uint256[2] a; + uint256[2][2] b; + uint256[2] c; +} + +struct HydraS3ProofData { + HydraS3CircomSnarkProof proof; + uint256[14] input; + // destinationIdentifier; + // extraData; + // commitmentMapperPubKey.X; + // commitmentMapperPubKey.Y; + // registryTreeRoot; + // requestIdentifier; + // proofIdentifier; + // claimValue; + // accountsTreeValue; + // claimComparator; + // vaultIdentifier; + // vaultNamespace; + // sourceVerificationEnabled; + // destinationVerificationEnabled; +} + +struct HydraS3ProofInput { + address destinationIdentifier; + uint256 extraData; + uint256[2] commitmentMapperPubKey; + uint256 registryTreeRoot; + uint256 requestIdentifier; + uint256 proofIdentifier; + uint256 claimValue; + uint256 accountsTreeValue; + uint256 claimComparator; + uint256 vaultIdentifier; + uint256 vaultNamespace; + bool sourceVerificationEnabled; + bool destinationVerificationEnabled; +} + +library HydraS3Lib { + uint256 public constant SNARK_FIELD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + function _input(HydraS3ProofData memory self) internal pure returns (HydraS3ProofInput memory) { + return + HydraS3ProofInput( + _getDestinationIdentifier(self), + _getExtraData(self), + _getCommitmentMapperPubKey(self), + _getRegistryRoot(self), + _getRequestIdentifier(self), + _getProofIdentifier(self), + _getClaimValue(self), + _getAccountsTreeValue(self), + _getClaimComparator(self), + _getVaultIdentifier(self), + _getVaultNamespace(self), + _getSourceVerificationEnabled(self), + _getDestinationVerificationEnabled(self) + ); + } + + function _toCircomFormat( + HydraS3ProofData memory self + ) + internal + pure + returns (uint256[2] memory, uint256[2][2] memory, uint256[2] memory, uint256[14] memory) + { + return (self.proof.a, self.proof.b, self.proof.c, self.input); + } + + function _getDestinationIdentifier(HydraS3ProofData memory self) internal pure returns (address) { + return address(uint160(self.input[0])); + } + + function _getExtraData(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[1]; + } + + function _getCommitmentMapperPubKey( + HydraS3ProofData memory self + ) internal pure returns (uint256[2] memory) { + return [self.input[2], self.input[3]]; + } + + function _getRegistryRoot(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[4]; + } + + function _getRequestIdentifier(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[5]; + } + + function _getProofIdentifier(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[6]; + } + + function _getClaimValue(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[7]; + } + + function _getAccountsTreeValue(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[8]; + } + + function _getClaimComparator(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[9]; + } + + function _getVaultIdentifier(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[10]; + } + + function _getVaultNamespace(HydraS3ProofData memory self) internal pure returns (uint256) { + return self.input[11]; + } + + function _getSourceVerificationEnabled( + HydraS3ProofData memory self + ) internal pure returns (bool) { + return self.input[12] == 1; + } + + function _getDestinationVerificationEnabled( + HydraS3ProofData memory self + ) internal pure returns (bool) { + return self.input[13] == 1; + } +} diff --git a/src/verifiers/HydraS3Verifier.sol b/src/verifiers/HydraS3Verifier.sol new file mode 100644 index 0000000..959632b --- /dev/null +++ b/src/verifiers/HydraS3Verifier.sol @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import {IBaseVerifier} from "../interfaces/IBaseVerifier.sol"; +import {IHydraS3Verifier} from "./IHydraS3Verifier.sol"; +import {HydraS3Verifier as HydraS3SnarkVerifier} from "@sismo-core/hydra-s3/HydraS3Verifier.sol"; +import {ICommitmentMapperRegistry} from "../periphery/interfaces/ICommitmentMapperRegistry.sol"; +import {IAvailableRootsRegistry} from "../periphery/interfaces/IAvailableRootsRegistry.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import {HydraS3ProofData, HydraS3Lib, HydraS3ProofInput} from "./HydraS3Lib.sol"; +import {Auth, ClaimType, AuthType, Claim, SismoConnectProof, VerifiedAuth, VerifiedClaim} from "src/utils/Structs.sol"; + +contract HydraS3Verifier is IHydraS3Verifier, IBaseVerifier, HydraS3SnarkVerifier, Initializable { + using HydraS3Lib for HydraS3ProofData; + using HydraS3Lib for Auth; + using HydraS3Lib for Claim; + + // Struct holding the decoded Hydra-S3 snark proof and decoded public inputs + // This struct is used to avoid stack too deep error + struct HydraS3Proof { + HydraS3ProofData data; + HydraS3ProofInput input; + } + + // Struct holding the verified Auth and Claim from the Hydra-S3 snark proof + // This struct is used to avoid stack too deep error + struct VerifiedProof { + VerifiedAuth auth; + VerifiedClaim claim; + } + + uint8 public constant IMPLEMENTATION_VERSION = 1; + bytes32 public immutable HYDRA_S3_VERSION = "hydra-s3.1"; + // Registry storing the Commitment Mapper EdDSA Public key + ICommitmentMapperRegistry public immutable COMMITMENT_MAPPER_REGISTRY; + // Registry storing the Registry Tree Roots of the Attester's available ClaimData + IAvailableRootsRegistry public immutable AVAILABLE_ROOTS_REGISTRY; + + // Impersonation Commitment Mapper EdDSA Public key + uint256 public constant impersonationCommitmentMapperPubKeyX = + 0x1801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b; + uint256 public constant impersonationCommitmentMapperPubKeyY = + 0x057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b; + + constructor(address commitmentMapperRegistry, address availableRootsRegistry) { + COMMITMENT_MAPPER_REGISTRY = ICommitmentMapperRegistry(commitmentMapperRegistry); + AVAILABLE_ROOTS_REGISTRY = IAvailableRootsRegistry(availableRootsRegistry); + initialize(); + } + + function initialize() public reinitializer(IMPLEMENTATION_VERSION) {} + + function verify( + bytes16 appId, + bytes16 namespace, + bool isImpersonationMode, + bytes memory signedMessage, + SismoConnectProof memory sismoConnectProof + ) external returns (VerifiedAuth memory, VerifiedClaim memory) { + // Verify the sismoConnectProof version corresponds to the current verifier. + if (sismoConnectProof.provingScheme != HYDRA_S3_VERSION) { + revert InvalidVersion(sismoConnectProof.provingScheme); + } + + HydraS3Proof memory hydraS3Proof = HydraS3Proof({ + // Decode the snark proof data from the sismoConnectProof + data: abi.decode(sismoConnectProof.proofData, (HydraS3ProofData)), + // Get the public inputs from the snark proof data + input: abi.decode(sismoConnectProof.proofData, (HydraS3ProofData))._input() + }); + + // We only support one Auth and one Claim in the hydra-s3 proving scheme + // We revert if there is more than one Auth or Claim in the sismoConnectProof + if (sismoConnectProof.auths.length > 1 || sismoConnectProof.claims.length > 1) { + revert OnlyOneAuthAndOneClaimIsSupported(); + } + + // Verify Claim, Auth and SignedMessage validity by checking corresponding + // snarkProof public input + VerifiedProof memory verifiedProof; + if (sismoConnectProof.auths.length == 1) { + // Get the Auth from the sismoConnectProof + // We only support one Auth in the hydra-s3 proving scheme + Auth memory auth = sismoConnectProof.auths[0]; + verifiedProof.auth = _verifyAuthValidity( + hydraS3Proof.input, + sismoConnectProof.proofData, + auth, + appId, + isImpersonationMode + ); + } + if (sismoConnectProof.claims.length == 1) { + // Get the Claim from the sismoConnectProof + // We only support one Claim in the hydra-s3 proving scheme + Claim memory claim = sismoConnectProof.claims[0]; + verifiedProof.claim = _verifyClaimValidity( + hydraS3Proof.input, + sismoConnectProof.proofData, + claim, + appId, + namespace, + isImpersonationMode + ); + } + + _validateSignedMessageInput(hydraS3Proof.input, signedMessage); + + // Check the snarkProof is valid + _checkSnarkProof(hydraS3Proof.data); + return (verifiedProof.auth, verifiedProof.claim); + } + + function _verifyClaimValidity( + HydraS3ProofInput memory input, + bytes memory proofData, + Claim memory claim, + bytes16 appId, + bytes16 namespace, + bool isImpersonationMode + ) private view returns (VerifiedClaim memory) { + // Check claim value validity + if (input.claimValue != claim.value) { + revert ClaimValueMismatch(); + } + + // Check requestIdentifier validity + uint256 expectedRequestIdentifier = _encodeRequestIdentifier( + claim.groupId, + claim.groupTimestamp, + appId, + namespace + ); + if (input.requestIdentifier != expectedRequestIdentifier) { + revert RequestIdentifierMismatch(input.requestIdentifier, expectedRequestIdentifier); + } + + // commitmentMapperPubKey + // In impersonation mode, we use the EdDSA public key of the Impersonation Commitment Mapper + // otherwise we use the EdDSA public key of the Commitment Mapper Registry + uint256[2] memory commitmentMapperPubKey = isImpersonationMode + ? [impersonationCommitmentMapperPubKeyX, impersonationCommitmentMapperPubKeyY] + : COMMITMENT_MAPPER_REGISTRY.getEdDSAPubKey(); + + if ( + input.commitmentMapperPubKey[0] != commitmentMapperPubKey[0] || + input.commitmentMapperPubKey[1] != commitmentMapperPubKey[1] + ) { + revert CommitmentMapperPubKeyMismatch( + bytes32(commitmentMapperPubKey[0]), + bytes32(commitmentMapperPubKey[1]), + bytes32(input.commitmentMapperPubKey[0]), + bytes32(input.commitmentMapperPubKey[1]) + ); + } + + // sourceVerificationEnabled + if (input.sourceVerificationEnabled == false) { + revert SourceVerificationNotEnabled(); + } + // isRootAvailable + if (!AVAILABLE_ROOTS_REGISTRY.isRootAvailable(input.registryTreeRoot)) { + revert RegistryRootNotAvailable(input.registryTreeRoot); + } + // accountsTreeValue + uint256 groupSnapshotId = _encodeAccountsTreeValue(claim.groupId, claim.groupTimestamp); + if (input.accountsTreeValue != groupSnapshotId) { + revert AccountsTreeValueMismatch(input.accountsTreeValue, groupSnapshotId); + } + + bool claimComparatorEQ = input.claimComparator == 1; + bool isClaimTypeFromClaimEqualToEQ = claim.claimType == ClaimType.EQ; + if (claimComparatorEQ != isClaimTypeFromClaimEqualToEQ) { + revert ClaimTypeMismatch(input.claimComparator, uint256(claim.claimType)); + } + + return + VerifiedClaim({ + groupId: claim.groupId, + groupTimestamp: claim.groupTimestamp, + value: claim.value, + claimType: claim.claimType, + proofId: input.proofIdentifier, + proofData: proofData, + extraData: claim.extraData + }); + } + + function _verifyAuthValidity( + HydraS3ProofInput memory input, + bytes memory proofData, + Auth memory auth, + bytes16 appId, + bool isImpersonationMode + ) private view returns (VerifiedAuth memory) { + uint256 userIdFromProof; + if (auth.authType == AuthType.VAULT) { + // vaultNamespace validity + uint256 vaultNamespaceFromProof = input.vaultNamespace; + uint256 expectedVaultNamespace = _encodeVaultNamespace(appId); + if (vaultNamespaceFromProof != expectedVaultNamespace) { + revert VaultNamespaceMismatch(vaultNamespaceFromProof, expectedVaultNamespace); + } + userIdFromProof = input.vaultIdentifier; + } else { + if (input.destinationVerificationEnabled == false) { + revert DestinationVerificationNotEnabled(); + } + // commitmentMapperPubKey + uint256[2] memory commitmentMapperPubKey = isImpersonationMode + ? [impersonationCommitmentMapperPubKeyX, impersonationCommitmentMapperPubKeyY] + : COMMITMENT_MAPPER_REGISTRY.getEdDSAPubKey(); + if ( + input.commitmentMapperPubKey[0] != commitmentMapperPubKey[0] || + input.commitmentMapperPubKey[1] != commitmentMapperPubKey[1] + ) { + revert CommitmentMapperPubKeyMismatch( + bytes32(commitmentMapperPubKey[0]), + bytes32(commitmentMapperPubKey[1]), + bytes32(input.commitmentMapperPubKey[0]), + bytes32(input.commitmentMapperPubKey[1]) + ); + } + userIdFromProof = uint256(uint160(input.destinationIdentifier)); + _checkSismoIdentifierValidity(userIdFromProof, auth.authType); + } + + // check that the userId from the proof is the same as the userId in the auth + // the userId in the proof is the vaultIdentifier for AuthType.VAULT and the destinationIdentifier for other Auth types + if ( + auth.userId != userIdFromProof && !auth.isSelectableByUser // we do NOT check the userId if it has been made selectable by user in the vault app + ) { + revert UserIdMismatch(userIdFromProof, auth.userId); + } + + return + VerifiedAuth({ + authType: auth.authType, + isAnon: auth.isAnon, + userId: userIdFromProof, + extraData: auth.extraData, + proofData: proofData + }); + } + + function _validateSignedMessageInput( + HydraS3ProofInput memory input, + bytes memory signedMessage + ) private pure { + // don't check extraData if signedMessage from response is empty + if (keccak256(signedMessage) == keccak256(abi.encode(0x00))) { + return; + } + if (input.extraData != uint256(keccak256(signedMessage)) % HydraS3Lib.SNARK_FIELD) { + revert InvalidExtraData( + input.extraData, + uint256(keccak256(signedMessage)) % HydraS3Lib.SNARK_FIELD + ); + } + } + + function _checkSismoIdentifierValidity(uint256 userId, AuthType authType) private pure { + // the userId is 160 bits long (20 bytes), since it has the format of an evm address + if (authType == AuthType.GITHUB) { + // check that the userId starts with 0x1001 -> sismoIdentifier for dataSource GITHUB + // 160 bits - 16 bits = 144 bits + // we check that the first 16 bits are equal to 0x1001 + if ((userId) >> 144 != 0x1001) { + revert InvalidSismoIdentifier(bytes32(userId), uint8(authType)); + } + } + if (authType == AuthType.TWITTER) { + // check that the userId starts with 0x1002 -> sismoIdentifier for dataSource Twitter + // 160 bits - 16 bits = 144 bits + // we check that the first 16 bits are equal to 0x1002 + if ((userId) >> 144 != 0x1002) { + revert InvalidSismoIdentifier(bytes32(userId), uint8(authType)); + } + } + if (authType == AuthType.TELEGRAM) { + // check that the userId starts with 0x1003 -> sismoIdentifier for dataSource Telegram + // 160 bits - 16 bits = 144 bits + // we check that the first 16 bits are equal to 0x1003 + if ((userId) >> 144 != 0x1003) { + revert InvalidSismoIdentifier(bytes32(userId), uint8(authType)); + } + } + } + + function _checkSnarkProof(HydraS3ProofData memory snarkProofData) internal { + // low-level call to the `verifyProof` function + // since the function only accepts arguments located in calldata + (bool success, bytes memory result) = address(this).call( + abi.encodeWithSelector( + this.verifyProof.selector, + snarkProofData.proof.a, + snarkProofData.proof.b, + snarkProofData.proof.c, + snarkProofData.input + ) + ); + + if (!success) { + revert CallToVerifyProofFailed(); + } + bool isVerified = abi.decode(result, (bool)); + + if (!isVerified) { + revert InvalidProof(); + } + } + + function _encodeRequestIdentifier( + bytes16 groupId, + bytes16 groupTimestamp, + bytes16 appId, + bytes16 namespace + ) internal pure returns (uint256) { + bytes32 groupSnapshotId = _encodeGroupSnapshotId(groupId, groupTimestamp); + bytes32 serviceId = _encodeServiceId(appId, namespace); + return + uint256(keccak256(abi.encodePacked(serviceId, groupSnapshotId))) % HydraS3Lib.SNARK_FIELD; + } + + function _encodeAccountsTreeValue( + bytes16 groupId, + bytes16 groupTimestamp + ) internal pure returns (uint256) { + return uint256(_encodeGroupSnapshotId(groupId, groupTimestamp)) % HydraS3Lib.SNARK_FIELD; + } + + function _encodeGroupSnapshotId( + bytes16 groupId, + bytes16 groupTimestamp + ) internal pure returns (bytes32) { + return bytes32(abi.encodePacked(groupId, groupTimestamp)); + } + + function _encodeServiceId(bytes16 appId, bytes16 namespace) internal pure returns (bytes32) { + return bytes32(abi.encodePacked(appId, namespace)); + } + + function _encodeVaultNamespace(bytes16 appId) internal pure returns (uint256) { + return uint256(keccak256(abi.encodePacked(appId, bytes16(0)))) % HydraS3Lib.SNARK_FIELD; + } +} diff --git a/src/verifiers/IHydraS3Verifier.sol b/src/verifiers/IHydraS3Verifier.sol new file mode 100644 index 0000000..a73c766 --- /dev/null +++ b/src/verifiers/IHydraS3Verifier.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract IHydraS3Verifier { + error InvalidProof(); + error CallToVerifyProofFailed(); + error InvalidSismoIdentifier(bytes32 userId, uint8 authType); + error OnlyOneAuthAndOneClaimIsSupported(); + + error InvalidVersion(bytes32 version); + error RegistryRootNotAvailable(uint256 inputRoot); + error DestinationMismatch(address destinationFromProof, address expectedDestination); + error CommitmentMapperPubKeyMismatch( + bytes32 expectedX, + bytes32 expectedY, + bytes32 inputX, + bytes32 inputY + ); + + error ClaimTypeMismatch(uint256 claimTypeFromProof, uint256 expectedClaimType); + error RequestIdentifierMismatch( + uint256 requestIdentifierFromProof, + uint256 expectedRequestIdentifier + ); + error InvalidExtraData(uint256 extraDataFromProof, uint256 expectedExtraData); + error ClaimValueMismatch(); + error DestinationVerificationNotEnabled(); + error SourceVerificationNotEnabled(); + error AccountsTreeValueMismatch( + uint256 accountsTreeValueFromProof, + uint256 expectedAccountsTreeValue + ); + error VaultNamespaceMismatch(uint256 vaultNamespaceFromProof, uint256 expectedVaultNamespace); + error UserIdMismatch(uint256 userIdFromProof, uint256 expectedUserId); +} diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol new file mode 100644 index 0000000..dd68314 --- /dev/null +++ b/test/BaseTest.t.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +import {AddressesProviderMock} from "./mocks/AddressesProviderMock.sol"; +import {IAddressesProvider} from "src/periphery/interfaces/IAddressesProvider.sol"; +import {SismoConnectVerifier} from "src/SismoConnectVerifier.sol"; +import {RequestBuilder, AuthRequestBuilder, ClaimRequestBuilder, SignatureBuilder} from "src/SismoConnectLib.sol"; + +contract BaseTest is Test { + address immutable user1 = vm.addr(1); + address immutable user2 = vm.addr(2); + address immutable owner = vm.addr(3); + address immutable sismoAddressProviderV2 = 0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6; + + AddressesProviderMock addressesProvider; + SismoConnectVerifier sismoConnectVerifier; + + // external libraries + AuthRequestBuilder authRequestBuilder; + ClaimRequestBuilder claimRequestBuilder; + SignatureBuilder signatureBuilder; + RequestBuilder requestBuilder; + + function setUp() public virtual { + addressesProvider = new AddressesProviderMock(); + sismoConnectVerifier = new SismoConnectVerifier(owner); + + // external libraries + authRequestBuilder = new AuthRequestBuilder(); + claimRequestBuilder = new ClaimRequestBuilder(); + signatureBuilder = new SignatureBuilder(); + requestBuilder = new RequestBuilder(); + + vm.etch(sismoAddressProviderV2, address(addressesProvider).code); + + IAddressesProvider(sismoAddressProviderV2).set( + address(sismoConnectVerifier), + string("sismoConnectVerifier-v1.2") + ); + IAddressesProvider(sismoAddressProviderV2).set( + address(authRequestBuilder), + string("authRequestBuilder-v1.1") + ); + IAddressesProvider(sismoAddressProviderV2).set( + address(claimRequestBuilder), + string("claimRequestBuilder-v1.1") + ); + IAddressesProvider(sismoAddressProviderV2).set( + address(signatureBuilder), + string("signatureBuilder-v1.1") + ); + IAddressesProvider(sismoAddressProviderV2).set( + address(requestBuilder), + string("requestBuilder-v1.1") + ); + } +} diff --git a/test/e2e/SismoConnectE2E.t.sol b/test/e2e/SismoConnectE2E.t.sol new file mode 100644 index 0000000..3aef7b0 --- /dev/null +++ b/test/e2e/SismoConnectE2E.t.sol @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import "src/utils/Fmt.sol"; +import {HydraS3BaseTest} from "../verifiers/hydra-s3/HydraS3BaseTest.t.sol"; +import {SismoConnect, RequestBuilder, ClaimRequestBuilder} from "src/SismoConnectLib.sol"; +import {ZKDropERC721} from "src/misc/ZKDropERC721.sol"; +import {CheatSheet} from "src/misc/CheatSheet.sol"; +import "src/utils/Structs.sol"; +import {SismoConnectHarness} from "../harness/SismoConnectHarness.sol"; + +import {AuthBuilder} from "src/utils/AuthBuilder.sol"; +import {ClaimBuilder} from "src/utils/ClaimBuilder.sol"; +import {ResponseBuilder, ResponseWithoutProofs} from "../utils/ResponseBuilderLib.sol"; +import {BaseDeploymentConfig} from "script/BaseConfig.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {UpgradeableExample} from "../misc/UpgradeableExample.sol"; + +// E2E tests for SismoConnect Solidity Library +// These tests are made with proofs generated from the Vault App +// These tests should not use any Verifier mocks + +contract SismoConnectE2E is HydraS3BaseTest { + using ResponseBuilder for SismoConnectResponse; + using ResponseBuilder for ResponseWithoutProofs; + + SismoConnectHarness sismoConnect; + address user = 0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE; + + // default values for tests + bytes16 public DEFAULT_APP_ID = 0x11b1de449c6c4adb0b5775b3868b28b3; + bytes16 public DEFAULT_NAMESPACE = bytes16(keccak256("main")); + bytes32 public DEFAULT_VERSION = bytes32("sismo-connect-v1.1"); + bytes public DEFAULT_SIGNED_MESSAGE = abi.encode(user); + + bool public DEFAULT_IS_IMPERSONATION_MODE = false; + + ResponseWithoutProofs public DEFAULT_RESPONSE = + ResponseBuilder + .emptyResponseWithoutProofs() + .withAppId(DEFAULT_APP_ID) + .withVersion(DEFAULT_VERSION) + .withNamespace(DEFAULT_NAMESPACE) + .withSignedMessage(DEFAULT_SIGNED_MESSAGE); + + ClaimRequest claimRequest; + AuthRequest authRequest; + SignatureRequest signature; + + bytes16 immutable APP_ID_ZK_DROP = 0x11b1de449c6c4adb0b5775b3868b28b3; + bytes16 immutable ZK = 0xe9ed316946d3d98dfcd829a53ec9822e; + ZKDropERC721 zkdrop; + + CheatSheet cheatsheet; + + function setUp() public virtual override { + super.setUp(); + sismoConnect = new SismoConnectHarness(DEFAULT_APP_ID, DEFAULT_IS_IMPERSONATION_MODE); + claimRequest = sismoConnect.exposed_buildClaim({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + authRequest = sismoConnect.exposed_buildAuth({authType: AuthType.VAULT}); + signature = sismoConnect.exposed_buildSignature({message: abi.encode(user)}); + + zkdrop = new ZKDropERC721({ + appId: APP_ID_ZK_DROP, + groupId: ZK, + name: "ZKDrop test", + symbol: "test", + baseTokenURI: "https://test.com" + }); + console.log("ZkDrop contract deployed at", address(zkdrop)); + + cheatsheet = new CheatSheet(); + } + + function test_SismoConnectLibWithOnlyClaimAndMessage() public { + (, bytes memory responseEncoded) = hydraS3Proofs.getResponseWithOneClaimAndSignature(); + + sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: requestBuilder.build({ + claim: sismoConnect.exposed_buildClaim({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}), + signature: sismoConnect.exposed_buildSignature({message: abi.encode(user)}) + }) + }); + } + + function test_SismoConnectLibWithTwoClaimsAndMessage() public { + (, bytes memory responseEncoded) = hydraS3Proofs.getResponseWithTwoClaimsAndSignature(); + + ClaimRequest[] memory claims = new ClaimRequest[](2); + claims[0] = sismoConnect.exposed_buildClaim({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + claims[1] = sismoConnect.exposed_buildClaim({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + + sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: requestBuilder.build({ + claims: claims, + signature: sismoConnect.exposed_buildSignature({message: abi.encode(user)}) + }) + }); + } + + function test_SismoConnectLibWithOnlyOneAuth() public { + (, bytes memory responseEncoded) = hydraS3Proofs.getResponseWithOnlyOneAuthAndMessage(); + + SismoConnectRequest memory request = requestBuilder.build({ + auth: sismoConnect.exposed_buildAuth({authType: AuthType.VAULT}), + signature: signature + }); + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify( + responseEncoded, + request + ); + assertTrue(verifiedResult.auths[0].userId != 0); + } + + function test_SismoConnectLibWithClaimAndAuth() public { + (, bytes memory responseEncoded) = hydraS3Proofs.getResponseWithOneClaimOneAuthAndOneMessage(); + SismoConnectRequest memory request = requestBuilder.build({ + auth: sismoConnect.exposed_buildAuth({authType: AuthType.VAULT}), + claim: sismoConnect.exposed_buildClaim({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}), + signature: signature + }); + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify( + responseEncoded, + request + ); + assertTrue(verifiedResult.auths[0].userId != 0); + } + + function test_ClaimAndAuthWithSignedMessageZKDROP() public { + // address that reverts if not modulo SNARK_FIELD after hashing the signedMessage for the circuit + // should keep this address for testing purposes + user = 0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE; + + // proof of membership for user in group 0xe9ed316946d3d98dfcd829a53ec9822e + // vault ownership + // signedMessage: 0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE + bytes + memory responseEncoded = hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c00e13d5898f45a0578526ca3d9048c9a0ed6a6dc6af46118f330a10c2bd905a180a5606df9b8c074aa82aa92fba759f79bfe2ea93b120f88477fc2506071e07932953767a6bba7cde1264cd886e85f97233cf12dec2cdf5ee8f3d295a1c603ee200a14357ed867808c4c9cfdd3eadbaaccab985c3c98563eb9bd97f0ae4a86dfb1854e21c9405301c914a1bcd93e827f34bcedb21419c5edcf2c022a719da63262a905da8df1c751d7aa8761ca691f950011a9016f152e06d67a076f72547002b1af4e79cb9e150f94bfb43b295ee3eba90f4f21c096cbda50215e37d86b095920d953743b8c045b0d4342370648b1f9444ce5c706602f20d2df4a2139997ee4b000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02f1f6f738b95cb3ad82c8d6f9d3f76542a489959b5c54da7d9d7b48413136b580dcd5851ffe286e00cbcdb644972e2f98b96772258f243160c501fa350a98282301793ae676f391ef110b70c0fd3286c5f2679582cbb3371792174af6f1c78490851df3f5b6054ab215fd07ad52bcaac91e7a342611126ec56ceed3ce47a756e066fea74f29aba48ed861174b8adb71406661e423e19a9c49df73c8b2b868d3d2c9fe708d9654b09e0ae44948b81d3970118e6bc771ca258f79a5047bfac8e8c2bd36792147ed1c1e4d5bea0ccc70abc636b98e49aa89f3b857673b3cac2cad809c1face7ad71275738dd61ca3683d1edb5d6acea0b177ddcf7771ff8758f057000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + zkdrop.claimWithSismoConnect(responseEncoded, user); + } + + function test_TwoClaimsOneVaultAuthWithSignature() public { + ClaimRequest[] memory claims = new ClaimRequest[](2); + claims[0] = claimRequestBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + claims[1] = claimRequestBuilder.build({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + + AuthRequest[] memory auths = new AuthRequest[](1); + auths[0] = authRequestBuilder.build({authType: AuthType.VAULT}); + + SismoConnectRequest memory request = requestBuilder.build({ + claims: claims, + auths: auths, + signature: signature + }); + + (, bytes memory responseEncoded) = hydraS3Proofs + .getResponseWithTwoClaimsOneAuthAndOneSignature(); + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: request + }); + console.log("Claims in Verified result: %s", verifiedResult.claims.length); + } + + function test_ThreeClaimsOneVaultAuthWithSignatureOneClaimOptional() public { + ClaimRequest[] memory claims = new ClaimRequest[](3); + claims[0] = claimRequestBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + claims[1] = claimRequestBuilder.build({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + claims[2] = claimRequestBuilder.build({ + groupId: 0x42c768bb8ae79e4c5c05d3b51a4ec74a, + isOptional: true, + isSelectableByUser: false + }); + + AuthRequest[] memory auths = new AuthRequest[](1); + auths[0] = authRequestBuilder.build({authType: AuthType.VAULT}); + + SismoConnectRequest memory request = requestBuilder.build({ + claims: claims, + auths: auths, + signature: signature + }); + + (, bytes memory responseEncoded) = hydraS3Proofs + .getResponseWithTwoClaimsOneAuthAndOneSignature(); + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: request + }); + console.log("Claims in Verified result: %s", verifiedResult.claims.length); + } + + function test_ThreeClaimsOneVaultAuthOneTwitterAuthWithSignatureOneClaimOptional() public { + ClaimRequest[] memory claims = new ClaimRequest[](3); + claims[0] = claimRequestBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + claims[1] = claimRequestBuilder.build({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + claims[2] = claimRequestBuilder.build({ + groupId: 0x42c768bb8ae79e4c5c05d3b51a4ec74a, + isOptional: true, + isSelectableByUser: false + }); + + AuthRequest[] memory auths = new AuthRequest[](2); + auths[0] = authRequestBuilder.build({authType: AuthType.VAULT}); + auths[1] = authRequestBuilder.build({ + authType: AuthType.TWITTER, + isOptional: true, + isSelectableByUser: true + }); + + SismoConnectRequest memory request = requestBuilder.build({ + claims: claims, + auths: auths, + signature: signature + }); + + (, bytes memory responseEncoded) = hydraS3Proofs + .getResponseWithTwoClaimsOneAuthAndOneSignature(); + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: request + }); + console.log("Claims in Verified result: %s", verifiedResult.claims.length); + } + + function test_OneClaimOneOptionalTwitterAuthOneGithubAuthWithSignature() public { + ClaimRequest[] memory claims = new ClaimRequest[](1); + claims[0] = claimRequestBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + + AuthRequest[] memory auths = new AuthRequest[](2); + auths[0] = authRequestBuilder.build({authType: AuthType.GITHUB}); + auths[1] = authRequestBuilder.build({ + authType: AuthType.TWITTER, + isOptional: true, + isSelectableByUser: true + }); + + SismoConnectRequest memory request = requestBuilder.build({ + claims: claims, + auths: auths, + signature: signature + }); + + bytes + memory responseEncoded = hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009e000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100100000000000000000000000000009999037000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c01f5237cda37ca2237bfa10de427ae030eeec24a6ce9d8d1131b15f7fcb5f168f2cd27a37a8cecf4a922e209910d04ab67165610d401aeb8d3f9c8b4a6f81239425860952ce7cdf52b06c6f7861e10ab049b8df45c18b1fec6230c1bb9d5744fe1cc5acd00634a05a6dbf82f95b338f2d71fb3c88ec5219b2b8c98bea55a4dd3014d0a71a383a1e1d31902460cf0fa23c528be517436887dd4b82af41d6ab09c2062c4454dca040336cda21c314f5bc213f0b917908a89c5b0c1b2db31b8953ba1e1b07dbd0f19bec715b1aa331f632c258d9e084e309972550004c05f6340d732ca967c1ff768dd26409f9f987b9522fad5c4112f203a9b93119fadc85e30c9a000000000000000000000000100100000000000000000000000000009999037009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100200000000000000000000000000288480976500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0254797b44b8f3a253c02e3b84c8694458a8d498c2592e7b36c965519fc92503400c58413e606342362077d258766e55fc09135bdcb933e11db23bdcdce4ad23c2828525ef73b62575d2f2e6a471349e28e3ca63bc6b542bd6a0c8a3995750deb2da5fc828781d6aa5c5993bc43cb1e58cf6ddb8353503efc0d8f927956c9ec871dc864a6441d35fd9b774ac4a5380933666f6ad7c9e1ef1f1b24b87037fa2f5513ac71eaa4f51ddcf248dafff8e6c8205cabafcfacab21b7adb98167e9c5bb5f2aea54095c0246922547be93dce8b8e3fd87d4c5399d67377e63d9b90a30195025918b506c8d12293e48f224acddf120e8f890fe851bb9ba178b642beb4ded23000000000000000000000000100200000000000000000000000000288480976509f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c025f517407b6ea0ed90092fefb10a570a25e5c769acb42b98671e5ecc381a01bc26f2a04c85eec86c263e919be89ed6bae72fff9267e25674b0b1242f68c9722601dc85685a7d3423f9b1a3b63ef08a76379118fb1eb29821acd8165ae8e1d12f0528e916f26707be18a37f1c8f0a2792a5891d340438d6221cb137614c8b5b7520c0d1e29393509cbd8822cd8f5278e8a4203ca6baf007f5328b5abe9e175d802d3ecc77bb73e2f85b32033405a3dbe0920ac3a318bd329fc1b410e22f98f518269b9554c33dbc905c5f210d9555ca2b166733c814e904bd21ea298e2894ae6b0251474f760ccc6c335321cc4fb58f6d858ac6d6de7c2670a93148f9d3a1b060000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + SismoConnectVerifiedResult memory verifiedResult = sismoConnect.exposed_verify({ + responseBytes: responseEncoded, + request: request + }); + console.log("Claims in Verified result: %s", verifiedResult.claims.length); + } + + function test_GitHubAuth() public { + (, bytes memory encodedResponse) = hydraS3Proofs.getResponseWithGitHubAuth(); + + SismoConnectRequest memory request = requestBuilder.build({ + auth: sismoConnect.exposed_buildAuth({authType: AuthType.GITHUB}), + signature: signature + }); + + sismoConnect.exposed_verify({responseBytes: encodedResponse, request: request}); + } + + function test_GitHubAuthWithoutSignature() public { + (, bytes memory encodedResponse) = hydraS3Proofs.getResponseWithGitHubAuthWithoutSignature(); + + SismoConnectRequest memory request = requestBuilder.build({ + auth: sismoConnect.exposed_buildAuth({authType: AuthType.GITHUB}) + }); + + sismoConnect.exposed_verify({responseBytes: encodedResponse, request: request}); + } + + function test_withProxy() public { + SignatureRequest memory signatureRequest = sismoConnect.exposed_buildSignature({ + message: abi.encode(user) + }); + + UpgradeableExample sismoConnectImplem = new UpgradeableExample( + DEFAULT_APP_ID, + DEFAULT_IS_IMPERSONATION_MODE, + 0xe9ed316946d3d98dfcd829a53ec9822e + ); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(sismoConnectImplem), + address(1), + abi.encodeWithSelector( + sismoConnectImplem.initialize.selector, + bytes16(0xe9ed316946d3d98dfcd829a53ec9822e) + ) + ); + + UpgradeableExample upgradeable = UpgradeableExample(address(proxy)); + + (, bytes memory responseEncoded) = hydraS3Proofs.getResponseWithOneClaimAndSignature(); + + upgradeable.exposed_verify({responseBytes: responseEncoded, signature: signatureRequest}); + + // add an additional groupId in the contract + upgradeable.addGroupId({groupId: 0xff7653240feecd7448150005a95ac86b}); + + // verify again + // it should throw since the response is the same but another claim request is required + vm.expectRevert( + abi.encodeWithSignature( + "ClaimGroupIdNotFound(bytes16)", + bytes16(0xff7653240feecd7448150005a95ac86b) + ) + ); + upgradeable.exposed_verify({responseBytes: responseEncoded, signature: signatureRequest}); + } + + function test_RevertWithInvalidSismoIdentifier() public { + (SismoConnectResponse memory response, ) = hydraS3Proofs + .getResponseWithGitHubAuthWithoutSignature(); + + // specify in the response that the proof comes from a telegram ownership + // but the proof is actually a github ownership + response.proofs[0].auths[0].authType = AuthType.TELEGRAM; + + // request a telegram proof of ownership + SismoConnectRequest memory request = requestBuilder.build({ + auth: sismoConnect.exposed_buildAuth({authType: AuthType.TELEGRAM}) + }); + + vm.expectRevert( + abi.encodeWithSignature( + "InvalidSismoIdentifier(bytes32,uint8)", + 0x0000000000000000000000001001000000000000000000000000000099990370, + 4 + ) + ); + sismoConnect.exposed_verify({responseBytes: abi.encode(response), request: request}); + } + + function test_CheatSheet() public { + bytes memory responseBytes = hydraS3Proofs.getCheatSheetResponse(); + cheatsheet.verifySismoConnectResponse(responseBytes); + } + + // helpers + + function emptyResponse() private pure returns (SismoConnectResponse memory) { + return ResponseBuilder.empty(); + } +} diff --git a/test/harness/SismoConnectHarness.sol b/test/harness/SismoConnectHarness.sol new file mode 100644 index 0000000..ac6f133 --- /dev/null +++ b/test/harness/SismoConnectHarness.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "src/SismoConnectLib.sol"; + +// This contract is used to expose internal functions of SismoConnect for testing purposes +// It is NOT deployed in production +// see: https://book.getfoundry.sh/tutorials/best-practices?highlight=coverage#test-harnesses +contract SismoConnectHarness is SismoConnect { + constructor( + bytes16 appId, + bool isImpersonationMode + ) SismoConnect(buildConfig(appId, isImpersonationMode)) {} + + function exposed_buildClaim(bytes16 groupId) external view returns (ClaimRequest memory) { + return buildClaim(groupId); + } + + function exposed_buildAuth(AuthType authType) external view returns (AuthRequest memory) { + return buildAuth(authType); + } + + function exposed_buildAuth( + AuthType authType, + bool isAnon + ) external view returns (AuthRequest memory) { + return buildAuth({authType: authType, isAnon: isAnon}); + } + + function exposed_buildAuth( + AuthType authType, + bool isOptional, + bool isSelectableByUser + ) external view returns (AuthRequest memory) { + return + buildAuth({ + authType: authType, + isOptional: isOptional, + isSelectableByUser: isSelectableByUser + }); + } + + function exposed_buildAuth( + AuthType authType, + uint256 userId + ) external view returns (AuthRequest memory) { + return buildAuth({authType: authType, userId: userId}); + } + + function exposed_buildAuth( + AuthType authType, + bool isSelectableByUser, + bool isOptional, + uint256 userId + ) external view returns (AuthRequest memory) { + return + buildAuth({ + authType: authType, + isSelectableByUser: isSelectableByUser, + isOptional: isOptional, + userId: userId + }); + } + + function exposed_buildSignature( + bytes memory message + ) external view returns (SignatureRequest memory) { + return buildSignature(message); + } + + function exposed_verify( + bytes memory responseBytes, + ClaimRequest memory claim + ) external returns (SismoConnectVerifiedResult memory) { + return verify({responseBytes: responseBytes, claim: claim}); + } + + function exposed_verify( + bytes memory responseBytes, + ClaimRequest memory claim, + bytes16 namespace + ) external returns (SismoConnectVerifiedResult memory) { + return verify({responseBytes: responseBytes, claim: claim, namespace: namespace}); + } + + function exposed_verify( + bytes memory responseBytes, + ClaimRequest memory claim, + SignatureRequest memory signature + ) external returns (SismoConnectVerifiedResult memory) { + return verify({responseBytes: responseBytes, claim: claim, signature: signature}); + } + + function exposed_verify( + bytes memory responseBytes, + AuthRequest memory auth, + SignatureRequest memory signature + ) external returns (SismoConnectVerifiedResult memory) { + return verify({responseBytes: responseBytes, auth: auth, signature: signature}); + } + + function exposed_verify( + bytes memory responseBytes, + SismoConnectRequest memory request + ) external returns (SismoConnectVerifiedResult memory) { + return verify({responseBytes: responseBytes, request: request}); + } +} diff --git a/test/libs/SismoConnectLib.t.sol b/test/libs/SismoConnectLib.t.sol new file mode 100644 index 0000000..a11e797 --- /dev/null +++ b/test/libs/SismoConnectLib.t.sol @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import "src/utils/Fmt.sol"; +import {VerifierMockBaseTest} from "../verifiers/mocks/VerifierMockBaseTest.t.sol"; +import {SismoConnect, RequestBuilder, ClaimRequestBuilder} from "src/SismoConnectLib.sol"; +import {ZKDropERC721} from "src/misc/ZKDropERC721.sol"; +import "src/utils/Structs.sol"; +import {SismoConnectHarness} from "../harness/SismoConnectHarness.sol"; + +import {AuthBuilder} from "src/utils/AuthBuilder.sol"; +import {ClaimBuilder} from "src/utils/ClaimBuilder.sol"; +import {ResponseBuilder, ResponseWithoutProofs} from "../utils/ResponseBuilderLib.sol"; +import {BaseDeploymentConfig} from "script/BaseConfig.sol"; + +contract SismoConnectLibTest is VerifierMockBaseTest { + using ResponseBuilder for SismoConnectResponse; + using ResponseBuilder for ResponseWithoutProofs; + + SismoConnectHarness sismoConnect; + address user = 0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE; + + // default values for tests + bytes16 public DEFAULT_APP_ID = 0x11b1de449c6c4adb0b5775b3868b28b3; + bytes16 public DEFAULT_NAMESPACE = bytes16(keccak256("main")); + bytes32 public DEFAULT_VERSION = bytes32("sismo-connect-v1.1"); + bytes public DEFAULT_SIGNED_MESSAGE = abi.encode(user); + + bool public DEFAULT_IS_IMPERSONATION_MODE = false; + + bytes32 public DEFAULT_PROVING_SCHEME = bytes32("mock-scheme"); + + ResponseWithoutProofs public DEFAULT_RESPONSE = + ResponseBuilder + .emptyResponseWithoutProofs() + .withAppId(DEFAULT_APP_ID) + .withVersion(DEFAULT_VERSION) + .withNamespace(DEFAULT_NAMESPACE) + .withSignedMessage(DEFAULT_SIGNED_MESSAGE); + + ClaimRequest claimRequest; + AuthRequest authRequest; + SignatureRequest signature; + + bytes16 immutable APP_ID_ZK_DROP = 0x11b1de449c6c4adb0b5775b3868b28b3; + bytes16 immutable ZK = 0xe9ed316946d3d98dfcd829a53ec9822e; + ZKDropERC721 zkdrop; + + function setUp() public virtual override { + super.setUp(); + sismoConnect = new SismoConnectHarness(DEFAULT_APP_ID, DEFAULT_IS_IMPERSONATION_MODE); + claimRequest = sismoConnect.exposed_buildClaim({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + authRequest = sismoConnect.exposed_buildAuth({authType: AuthType.VAULT}); + signature = sismoConnect.exposed_buildSignature({message: abi.encode(user)}); + + zkdrop = new ZKDropERC721({ + appId: APP_ID_ZK_DROP, + groupId: ZK, + name: "ZKDrop test", + symbol: "test", + baseTokenURI: "https://test.com" + }); + console.log("ZkDrop contract deployed at", address(zkdrop)); + } + + // Tests that should revert + + function test_RevertWith_EmptyMessageIfSismoConnectResponseIsEmpty() public { + bytes memory responseBytes = hex""; + // we just expect a revert with an empty responseBytes as far as the decoding will not be successful + vm.expectRevert(); + sismoConnect.exposed_verify({responseBytes: responseBytes, claim: claimRequest}); + } + + function test_RevertWith_InvalidUserIdAndIsSelectableByUserAuthType() public { + // When `userId` is 0, it means the app does not require a specific auth account and the user needs + // to choose the account they want to use for the app. + // When `isSelectableByUser` is true, the user can select the account they want to use. + // The combination of `userId = 0` and `isSelectableByUser = false` does not make sense and should not be used. + + // Here we do expect the revert since we set isSelectableByUser to false + // and we keep the default value for userId which is 0 + // effectivelly triggering the revert + // Note: we use an AuthType different from VAULT to not trigger another revert + vm.expectRevert(abi.encodeWithSignature("InvalidUserIdAndIsSelectableByUserAuthType()")); + sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB, + isOptional: false, + isSelectableByUser: false + }); + } + + function test_RevertWith_InvalidUserIdAndAuthType() public { + // When `userId` is 0, it means the app does not require a specific auth account and the user needs + // to choose the account they want to use for the app. + // When `isSelectableByUser` is true, the user can select the account they want to use. + // The combination of `userId = 0` and `isSelectableByUser = false` does not make sense and should not be used. + + // Here we set isSelectableByUser to false but we add a userId different from zero + // while choosing The AuthType VAULT, which does NOT make sense since it states that we allow the user to choose a vault account in his vault + // but in the case of the AuthType VAULT, the account is the vault itself and therefore there is no choice to make + // we should definitely revert based on this reasoning + vm.expectRevert(abi.encodeWithSignature("InvalidUserIdAndAuthType()")); + sismoConnect.exposed_buildAuth({ + authType: AuthType.VAULT, + isOptional: false, + isSelectableByUser: false, + userId: uint256(bytes32("wrong-id")) + }); + } + + function test_RevertWith_VersionMismatch() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE + .withVersion(bytes32("wrong-version")) + .build(); + vm.expectRevert( + abi.encodeWithSignature( + "VersionMismatch(bytes32,bytes32)", + invalidResponse.version, + DEFAULT_VERSION + ) + ); + sismoConnect.exposed_verify({responseBytes: abi.encode(invalidResponse), claim: claimRequest}); + } + + function test_RevertWith_NamespaceMismatch() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE + .withNamespace(bytes16(keccak256("wrong-namespace"))) + .build(); + + vm.expectRevert( + abi.encodeWithSignature( + "NamespaceMismatch(bytes16,bytes16)", + invalidResponse.namespace, + DEFAULT_NAMESPACE + ) + ); + sismoConnect.exposed_verify({responseBytes: abi.encode(invalidResponse), claim: claimRequest}); + } + + function test_RevertWith_AppIdMismatch() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAppId("wrong-id").build(); + vm.expectRevert( + abi.encodeWithSignature( + "AppIdMismatch(bytes16,bytes16)", + invalidResponse.appId, + DEFAULT_APP_ID + ) + ); + sismoConnect.exposed_verify({responseBytes: abi.encode(invalidResponse), claim: claimRequest}); + } + + function test_RevertWith_SignatureMessageMismatch() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE + .withSignedMessage("wrong-signed-message") + .build(); + vm.expectRevert( + abi.encodeWithSignature( + "SignatureMessageMismatch(bytes,bytes)", + signature.message, + invalidResponse.signedMessage + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_AuthInRequestNotFoundInResponse() public { + // we expect a revert since no proofs are provided in the response + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.build(); + vm.expectRevert( + abi.encodeWithSignature( + "AuthInRequestNotFoundInResponse(uint8,bool,uint256,bytes)", + authRequest.authType, + authRequest.isAnon, + authRequest.userId, + authRequest.extraData + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: authRequest, + signature: signature + }); + } + + function test_RevertWith_AuthIsAnonAndUserIdNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.GITHUB, isAnon: true, userId: uint256(0xc0de)}) + }); + // we need to choose a different AuthType than AUthType.VAULT to be able to test if the userId error is thrown + // we also need to set the userId different from zero since isSelectableByUser is false + // it means that we are waiting for a userId in the response that actually means something so different from zero + // we set userId of the request to 0xf00 to be different from the one in the response + AuthRequest memory auth = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB, + isOptional: false, + isSelectableByUser: false, + userId: uint256(0xf00) + }); + + vm.expectRevert( + abi.encodeWithSignature("AuthIsAnonAndUserIdNotFound(bool,uint256)", auth.isAnon, auth.userId) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_AuthTypeAndUserIdNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.VAULT, userId: uint256(bytes32("wrong-id"))}) + }); + // we need to choose a different AuthType than AUthType.VAULT to be able to test if the userId error is thrown + // we set userId of the request to 0xf00 to be different from the one in the response + AuthRequest memory auth = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB, + userId: uint256(0xf00) + }); // wrong userId + vm.expectRevert( + abi.encodeWithSignature( + "AuthTypeAndUserIdNotFound(uint8,uint256)", + auth.authType, + auth.userId + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_AuthUserIdNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.GITHUB, userId: uint256(bytes32("wrong-id"))}) + }); + // we need to choose a different AuthType than AUthType.VAULT to be able to test if the userId error is thrown + // we set userId of the request to 0xf00 to be different from the one in the response + AuthRequest memory auth = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB, + userId: uint256(0xf00) + }); // wrong userId + vm.expectRevert(abi.encodeWithSignature("AuthUserIdNotFound(uint256)", auth.userId)); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_AuthTypeAndIsAnonNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.VAULT, isAnon: true}) + }); + AuthRequest memory auth = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB, + isAnon: false + }); + vm.expectRevert( + abi.encodeWithSignature("AuthTypeAndIsAnonNotFound(uint8,bool)", auth.authType, auth.isAnon) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_AuthIsAnonNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.VAULT, isAnon: true}) + }); + AuthRequest memory auth = sismoConnect.exposed_buildAuth({ + authType: AuthType.VAULT, + isAnon: false + }); + vm.expectRevert(abi.encodeWithSignature("AuthIsAnonNotFound(bool)", auth.isAnon)); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_AuthTypeNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withAuth({ + auth: AuthBuilder.build({authType: AuthType.VAULT}) + }); + AuthRequest memory auth = sismoConnect.exposed_buildAuth({authType: AuthType.GITHUB}); + vm.expectRevert(abi.encodeWithSignature("AuthTypeNotFound(uint8)", auth.authType)); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: auth, + signature: signature + }); + } + + function test_RevertWith_ClaimInRequestNotFoundInResponse() public { + // we expect a revert since no proofs are provided in the response + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.build(); + vm.expectRevert( + abi.encodeWithSignature( + "ClaimInRequestNotFoundInResponse(uint8,bytes16,bytes16,uint256,bytes)", + claimRequest.claimType, + claimRequest.groupId, + claimRequest.groupTimestamp, + claimRequest.value, + claimRequest.extraData + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimGroupIdAndGroupTimestampNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({groupId: "wrong-id", groupTimestamp: bytes16("fake-timestamp")}) + }); + vm.expectRevert( + abi.encodeWithSignature( + "ClaimGroupIdAndGroupTimestampNotFound(bytes16,bytes16)", + claimRequest.groupId, + claimRequest.groupTimestamp + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimTypeAndGroupTimestampNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({ + groupId: claimRequest.groupId, + groupTimestamp: bytes16("fake-timestamp"), + claimType: ClaimType.LTE + }) + }); + vm.expectRevert( + abi.encodeWithSignature( + "ClaimTypeAndGroupTimestampNotFound(uint8,bytes16)", + claimRequest.claimType, + claimRequest.groupTimestamp + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimGroupTimestampNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({ + groupId: claimRequest.groupId, + groupTimestamp: bytes16("wrong-timestamp") + }) + }); + invalidResponse.proofs[0].claims[0].groupTimestamp = bytes16("fake-timestamp"); + vm.expectRevert( + abi.encodeWithSignature("ClaimGroupTimestampNotFound(bytes16)", claimRequest.groupTimestamp) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimTypeAndGroupIdNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({groupId: "wrong-id", claimType: ClaimType.LTE}) + }); + vm.expectRevert( + abi.encodeWithSignature( + "ClaimTypeAndGroupIdNotFound(uint8,bytes16)", + claimRequest.claimType, + claimRequest.groupId + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimGroupIdNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({groupId: bytes16("wrong-group-id")}) + }); + vm.expectRevert(abi.encodeWithSignature("ClaimGroupIdNotFound(bytes16)", claimRequest.groupId)); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimTypeNotFound() public { + SismoConnectResponse memory invalidResponse = DEFAULT_RESPONSE.withClaim({ + claim: ClaimBuilder.build({groupId: claimRequest.groupId, claimType: ClaimType.LTE}) + }); + vm.expectRevert( + abi.encodeWithSignature("ClaimTypeNotFound(uint8)", uint8(claimRequest.claimType)) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_OneAuthOneClaimOneSignature() public { + SismoConnectResponse memory validResponse = DEFAULT_RESPONSE + .withAuth({ + auth: AuthBuilder.build({authType: AuthType.VAULT}), + provingScheme: DEFAULT_PROVING_SCHEME + }) + .withClaim({ + claim: ClaimBuilder.build({groupId: claimRequest.groupId}), + provingScheme: DEFAULT_PROVING_SCHEME + }); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(validResponse), + claim: claimRequest, + signature: signature + }); + } + + // helpers + + function emptyResponse() private pure returns (SismoConnectResponse memory) { + return ResponseBuilder.empty(); + } +} diff --git a/test/misc/UpgradeableExample.sol b/test/misc/UpgradeableExample.sol new file mode 100644 index 0000000..67137f8 --- /dev/null +++ b/test/misc/UpgradeableExample.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "src/SismoConnectLib.sol"; + +contract UpgradeableExample is SismoConnect, Initializable { + bytes16[] private _groupIds; + + constructor( + bytes16 appId, + bool isImpersonationMode, + bytes16 groupId + ) SismoConnect(buildConfig(appId, isImpersonationMode)) { + initialize(groupId); + } + + function initialize(bytes16 groupId) public initializer { + _groupIds.push(groupId); + } + + function addGroupId(bytes16 groupId) public { + _groupIds.push(groupId); + } + + function getGroupIds() public view returns (bytes16[] memory) { + return _groupIds; + } + + function exposed_buildSignature( + bytes memory message + ) external view returns (SignatureRequest memory) { + return buildSignature(message); + } + + function exposed_verify( + bytes memory responseBytes, + SignatureRequest memory signature + ) external returns (SismoConnectVerifiedResult memory) { + ClaimRequest[] memory claims = new ClaimRequest[](_groupIds.length); + for (uint256 i = 0; i < _groupIds.length; i++) { + claims[i] = buildClaim(_groupIds[i]); + } + return verify({responseBytes: responseBytes, claims: claims, signature: signature}); + } +} diff --git a/test/mocks/AddressesProviderMock.sol b/test/mocks/AddressesProviderMock.sol new file mode 100644 index 0000000..3401bfe --- /dev/null +++ b/test/mocks/AddressesProviderMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Unlicensed +pragma solidity ^0.8.17; + +contract AddressesProviderMock { + mapping(bytes32 => address) private _contractAddresses; + string[] private _contractNames; + + /** + * @dev Sets the address of a contract. + * @param contractAddress Address of the contract. + * @param contractName Name of the contract. + */ + function set(address contractAddress, string memory contractName) public { + bytes32 contractNameHash = keccak256(abi.encodePacked(contractName)); + + if (_contractAddresses[contractNameHash] == address(0)) { + _contractNames.push(contractName); + } + + _contractAddresses[contractNameHash] = contractAddress; + } + + function get(string memory contractName) public view returns (address) { + bytes32 contractNameHash = keccak256(abi.encodePacked(contractName)); + + return _contractAddresses[contractNameHash]; + } +} diff --git a/test/mocks/AvailableRootsRegistryMock.sol b/test/mocks/AvailableRootsRegistryMock.sol new file mode 100644 index 0000000..b4ba969 --- /dev/null +++ b/test/mocks/AvailableRootsRegistryMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {IAvailableRootsRegistry} from "src/periphery/interfaces/IAvailableRootsRegistry.sol"; + +contract AvailableRootsRegistryMock is IAvailableRootsRegistry { + mapping(uint256 => bool) public _roots; + bool internal _isRootAvailable; + + constructor() { + _isRootAvailable = true; + } + + function initialize(address) external {} + + function isRootAvailable(uint256) external view returns (bool) { + return _isRootAvailable; + } + + function registerRoot(uint256 root) external { + _roots[root] = true; + } + + function unregisterRoot(uint256 root) external { + _roots[root] = false; + } + + function switchIsRootAvailable() external { + _isRootAvailable = !_isRootAvailable; + } +} diff --git a/test/mocks/CommitmentMapperRegistryMock.sol b/test/mocks/CommitmentMapperRegistryMock.sol new file mode 100644 index 0000000..d8b6f26 --- /dev/null +++ b/test/mocks/CommitmentMapperRegistryMock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {ICommitmentMapperRegistry} from "src/periphery/interfaces/ICommitmentMapperRegistry.sol"; + +contract CommitmentMapperRegistryMock is ICommitmentMapperRegistry { + uint256[2] public edDSAPubKey; + + function initialize(address, uint256[2] memory) external {} + + function updateCommitmentMapperEdDSAPubKey(uint256[2] memory newEdDSAPubKey) external { + edDSAPubKey = newEdDSAPubKey; + } + + function getEdDSAPubKey() external view returns (uint256[2] memory) { + return edDSAPubKey; + } +} diff --git a/test/mocks/VerifierMock.sol b/test/mocks/VerifierMock.sol new file mode 100644 index 0000000..7b4f9b1 --- /dev/null +++ b/test/mocks/VerifierMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import {IBaseVerifier} from "src/interfaces/IBaseVerifier.sol"; +import {Auth, ClaimType, AuthType, Claim, SismoConnectProof, VerifiedAuth, VerifiedClaim} from "src/utils/Structs.sol"; + +contract VerifierMock is IBaseVerifier { + bytes32 public immutable VERSION = "mock-scheme"; + + function verify( + bytes16, + bytes16, + bool, + bytes memory, + SismoConnectProof memory sismoConnectProof + ) external pure override returns (VerifiedAuth memory, VerifiedClaim memory) { + // Verify Claim, Auth and SignedMessage validity by checking corresponding + // snarkProof public input + VerifiedAuth memory verifiedAuth; + VerifiedClaim memory verifiedClaim; + if (sismoConnectProof.auths.length == 1) { + // Get the Auth from the sismoConnectProof + // We only support one Auth in the hydra-s3 proving scheme + Auth memory auth = sismoConnectProof.auths[0]; + verifiedAuth = VerifiedAuth({ + authType: auth.authType, + isAnon: auth.isAnon, + userId: auth.userId, + extraData: auth.extraData, + proofData: hex"" + }); + } + if (sismoConnectProof.claims.length == 1) { + // Get the Claim from the sismoConnectProof + // We only support one Claim in the hydra-s3 proving scheme + Claim memory claim = sismoConnectProof.claims[0]; + verifiedClaim = VerifiedClaim({ + claimType: claim.claimType, + groupId: claim.groupId, + groupTimestamp: claim.groupTimestamp, + value: claim.value, + extraData: claim.extraData, + proofId: 0x0, + proofData: hex"" + }); + } + + return (verifiedAuth, verifiedClaim); + } +} diff --git a/test/script/01_DeployAll.t.sol b/test/script/01_DeployAll.t.sol new file mode 100644 index 0000000..8de6c59 --- /dev/null +++ b/test/script/01_DeployAll.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import "script/01_DeployAll.s.sol"; +import {DeployAvailableRootsRegistry} from "script/DeployAvailableRootsRegistry.s.sol"; +import {DeployCommitmentMapperRegistry} from "script/DeployCommitmentMapperRegistry.s.sol"; +import "script/BaseConfig.sol"; + +contract DeployAllTest is Test, BaseDeploymentConfig { + ScriptTypes.DeployAllContracts contracts; + + address immutable PROXY_ADMIN = address(1); + address immutable OWNER = address(2); + address immutable ROOTS_OWNER = address(3); + + function setUp() public virtual { + _chainName = "test"; + _checkIfEmpty = true; + + DeployAll deploy = new DeployAll(); + + (bool success, bytes memory result) = address(deploy).delegatecall( + abi.encodeWithSelector(DeployAll.runFor.selector, "test") + ); + require(success, "Deploy script did not run successfully!"); + contracts = abi.decode(result, (ScriptTypes.DeployAllContracts)); + } + + function testAvailableRootsRegistryDeployed() public { + _expectDeployedWithProxy(address(contracts.availableRootsRegistry), PROXY_ADMIN); + assertEq(contracts.availableRootsRegistry.owner(), ROOTS_OWNER); + } + + function testCommitmentMapperRegistryDeployed() public { + _expectDeployedWithProxy(address(contracts.commitmentMapperRegistry), PROXY_ADMIN); + assertEq(contracts.commitmentMapperRegistry.owner(), OWNER); + } + + function testHydraS3Verifier() public { + _expectDeployedWithProxy(address(contracts.hydraS3Verifier), PROXY_ADMIN); + assertEq( + address(contracts.hydraS3Verifier.COMMITMENT_MAPPER_REGISTRY()), + address(contracts.commitmentMapperRegistry) + ); + assertEq( + address(contracts.hydraS3Verifier.AVAILABLE_ROOTS_REGISTRY()), + address(contracts.availableRootsRegistry) + ); + } + + function testSismoConnectVerifier() public { + _expectDeployedWithProxy(address(contracts.sismoConnectVerifier), PROXY_ADMIN); + assertEq( + contracts.sismoConnectVerifier.getVerifier("hydra-s3.1"), + address(contracts.hydraS3Verifier) + ); + assertEq(contracts.sismoConnectVerifier.owner(), OWNER); + } + + function test_RemoveFile() public { + removeFile(); + } + + function _expectDeployedWithProxy(address proxy, address expectedAdmin) internal { + // Expect proxy is deployed behin a TransparentUpgradeableProxy proxy with the right admin + vm.prank(expectedAdmin); + (bool success, bytes memory result) = address(proxy).call( + abi.encodeWithSelector(TransparentUpgradeableProxy.admin.selector) + ); + assertEq(success, true); + assertEq(abi.decode(result, (address)), PROXY_ADMIN); + } + + function removeFile() internal { + console.log("Removing deploymentConfigFilePath", _deploymentConfigFilePath()); + + vm.removeFile(_deploymentConfigFilePath()); + } +} diff --git a/test/utils/GroupLib.sol b/test/utils/GroupLib.sol new file mode 100644 index 0000000..b5e325f --- /dev/null +++ b/test/utils/GroupLib.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +struct Group { + AccountData[] accountsData; +} + +struct AccountData { + address accountIdentifier; + uint256 value; +} + +library GroupLib { + function build(AccountData[] memory accountsData) public pure returns (Group memory) { + return Group({accountsData: accountsData}); + } +} diff --git a/test/utils/ResponseBuilderLib.sol b/test/utils/ResponseBuilderLib.sol new file mode 100644 index 0000000..7b71c93 --- /dev/null +++ b/test/utils/ResponseBuilderLib.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "src/utils/Structs.sol"; +import {ProofBuilder} from "src/utils/SismoConnectProofBuilder.sol"; + +// We introduce an intermediate struct that will not store the proofs +// This is useful to be able to store this struct in the a contract storage +// We will then use different function to add the proofs and build the SismoConnectResponse struct +struct ResponseWithoutProofs { + bytes16 appId; + bytes16 namespace; + bytes32 version; + bytes signedMessage; +} + +// This library aims at building SismoConnectResponse structs with less overhead +// than using the SismoConnectResponse struct directly +// It also allows to build the SismoConnectResponse struct in multiple steps +// by adding the proofs later, ensuring modularity and flexibility in the code +library ResponseBuilder { + ////////////////////////////////// + // Simple Field Initialization // + //////////////////////////////// + + function withAppId( + SismoConnectResponse memory response, + bytes16 appId + ) external pure returns (SismoConnectResponse memory) { + response.appId = appId; + return response; + } + + function withAppId( + ResponseWithoutProofs memory response, + bytes16 appId + ) external pure returns (ResponseWithoutProofs memory) { + response.appId = appId; + return response; + } + + function withVersion( + SismoConnectResponse memory response, + bytes32 version + ) external pure returns (SismoConnectResponse memory) { + response.version = version; + return response; + } + + function withVersion( + ResponseWithoutProofs memory response, + bytes32 version + ) external pure returns (ResponseWithoutProofs memory) { + response.version = version; + return response; + } + + function withNamespace( + SismoConnectResponse memory response, + bytes16 namespace + ) external pure returns (SismoConnectResponse memory) { + response.namespace = namespace; + return response; + } + + function withNamespace( + ResponseWithoutProofs memory response, + bytes16 namespace + ) external pure returns (ResponseWithoutProofs memory) { + response.namespace = namespace; + return response; + } + + function withSignedMessage( + SismoConnectResponse memory response, + bytes memory signedMessage + ) external pure returns (SismoConnectResponse memory) { + response.signedMessage = signedMessage; + return response; + } + + function withSignedMessage( + ResponseWithoutProofs memory response, + bytes memory signedMessage + ) external pure returns (ResponseWithoutProofs memory) { + response.signedMessage = signedMessage; + return response; + } + + ////////////////////////////////// + // Proof Initialization // + //////////////////////////////// + + // the `build` function is used to build a valid Sismo Connect response from a ResponseWithoutProofs struct + // it just adds an empty array of proofs to the ResponseWithoutProofs struct + // it has a public visibility because it is used inside this library to transform a ResponseWithoutProofs struct into a SismoConnectResponse struct + // but it can also be used outside this library to build a SismoConnectResponse struct from a ResponseWithoutProofs struct + function build( + ResponseWithoutProofs memory response + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](0); + return + SismoConnectResponse({ + appId: response.appId, + namespace: response.namespace, + version: response.version, + signedMessage: response.signedMessage, + proofs: proofs + }); + } + + function withAuth( + SismoConnectResponse memory response, + Auth memory auth, + bytes memory proofData, + bytes32 provingScheme + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + auth: auth, + proofData: proofData, + provingScheme: provingScheme + }); + response.proofs = proofs; + return response; + } + + function withAuth( + SismoConnectResponse memory response, + Auth memory auth, + bytes memory proofData + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({auth: auth, proofData: proofData, provingScheme: ""}); + response.proofs = proofs; + return response; + } + + function withAuth( + SismoConnectResponse memory response, + Auth memory auth + ) external pure returns (SismoConnectResponse memory) { + return withAuth(response, auth, ""); + } + + function withAuth( + ResponseWithoutProofs memory response, + Auth memory auth, + bytes memory proofData, + bytes32 provingScheme + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + auth: auth, + proofData: proofData, + provingScheme: provingScheme + }); + SismoConnectResponse memory responseWithProofs = build(response); + responseWithProofs.proofs = proofs; + return responseWithProofs; + } + + function withAuth( + ResponseWithoutProofs memory response, + Auth memory auth, + bytes memory proofData + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({auth: auth, proofData: proofData, provingScheme: ""}); + SismoConnectResponse memory responseWithProofs = build(response); + responseWithProofs.proofs = proofs; + return responseWithProofs; + } + + function withAuth( + ResponseWithoutProofs memory response, + Auth memory auth, + bytes32 provingScheme + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({auth: auth, proofData: "", provingScheme: provingScheme}); + SismoConnectResponse memory responseWithProofs = build(response); + responseWithProofs.proofs = proofs; + return responseWithProofs; + } + + function withAuth( + ResponseWithoutProofs memory response, + Auth memory auth + ) external pure returns (SismoConnectResponse memory) { + return withAuth({response: response, auth: auth, proofData: ""}); + } + + function withClaim( + SismoConnectResponse memory response, + Claim memory claim, + bytes memory proofData, + bytes32 provingScheme + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + claim: claim, + proofData: proofData, + provingScheme: provingScheme + }); + response.proofs = proofs; + return response; + } + + function withClaim( + SismoConnectResponse memory response, + Claim memory claim, + bytes memory proofData + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({claim: claim, proofData: proofData, provingScheme: ""}); + response.proofs = proofs; + return response; + } + + function withClaim( + SismoConnectResponse memory response, + Claim memory claim, + bytes32 provingScheme + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({claim: claim, proofData: "", provingScheme: provingScheme}); + response.proofs = proofs; + return response; + } + + function withClaim( + SismoConnectResponse memory response, + Claim memory claim + ) external pure returns (SismoConnectResponse memory) { + return withClaim({response: response, claim: claim, proofData: ""}); + } + + function withClaim( + ResponseWithoutProofs memory response, + Claim memory claim, + bytes memory proofData + ) public pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({claim: claim, proofData: proofData}); + SismoConnectResponse memory responseWithProofs = build(response); + responseWithProofs.proofs = proofs; + return responseWithProofs; + } + + function withClaim( + ResponseWithoutProofs memory response, + Claim memory claim + ) external pure returns (SismoConnectResponse memory) { + return withClaim(response, claim, ""); + } + + //////////////////////////////// + // Empty structs // + ////////////////////////////// + + function emptyResponseWithoutProofs() external pure returns (ResponseWithoutProofs memory) { + return + ResponseWithoutProofs({ + appId: bytes16(0), + namespace: bytes16(0), + version: bytes32(0), + signedMessage: "" + }); + } + + function empty() external pure returns (SismoConnectResponse memory) { + SismoConnectProof[] memory proofs = new SismoConnectProof[](0); + return + SismoConnectResponse({ + appId: bytes16(0), + namespace: bytes16(0), + version: bytes32(0), + signedMessage: "", + proofs: proofs + }); + } +} diff --git a/test/verifiers/hydra-s3/HydraS3BaseTest.t.sol b/test/verifiers/hydra-s3/HydraS3BaseTest.t.sol new file mode 100644 index 0000000..d4ece1e --- /dev/null +++ b/test/verifiers/hydra-s3/HydraS3BaseTest.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import {BaseTest} from "test/BaseTest.t.sol"; +import "src/verifiers/HydraS3Verifier.sol"; +import "test/verifiers/hydra-s3//HydraS3Proofs.sol"; +import {CommitmentMapperRegistryMock, ICommitmentMapperRegistry} from "test/mocks/CommitmentMapperRegistryMock.sol"; +import {AvailableRootsRegistryMock} from "test/mocks/AvailableRootsRegistryMock.sol"; + +contract HydraS3BaseTest is BaseTest { + HydraS3Proofs immutable hydraS3Proofs = new HydraS3Proofs(); + HydraS3Verifier hydraS3Verifier; + ICommitmentMapperRegistry commitmentMapperRegistry; + AvailableRootsRegistryMock availableRootsRegistry; + + function setUp() public virtual override { + super.setUp(); + + commitmentMapperRegistry = new CommitmentMapperRegistryMock(); + availableRootsRegistry = new AvailableRootsRegistryMock(); + + hydraS3Verifier = new HydraS3Verifier( + address(commitmentMapperRegistry), + address(availableRootsRegistry) + ); + + vm.startPrank(owner); + sismoConnectVerifier.registerVerifier( + hydraS3Verifier.HYDRA_S3_VERSION(), + address(hydraS3Verifier) + ); + vm.stopPrank(); + + commitmentMapperRegistry.updateCommitmentMapperEdDSAPubKey(hydraS3Proofs.getEdDSAPubKey()); + availableRootsRegistry.registerRoot(hydraS3Proofs.getRoot()); + } +} diff --git a/test/verifiers/hydra-s3/HydraS3Proofs.sol b/test/verifiers/hydra-s3/HydraS3Proofs.sol new file mode 100644 index 0000000..6bb5722 --- /dev/null +++ b/test/verifiers/hydra-s3/HydraS3Proofs.sol @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import "src/utils/Structs.sol"; +import {AuthBuilder} from "src/utils/AuthBuilder.sol"; +import {ClaimBuilder} from "src/utils/ClaimBuilder.sol"; +import {ProofBuilder} from "src/utils/SismoConnectProofBuilder.sol"; +import {ResponseBuilder} from "test/utils/ResponseBuilderLib.sol"; +import {ICommitmentMapperRegistry} from "test/mocks/CommitmentMapperRegistryMock.sol"; + +contract HydraS3Proofs { + using ResponseBuilder for SismoConnectResponse; + + // default value for Claim + bytes16 public constant DEFAULT_CLAIM_GROUP_TIMESTAMP = bytes16("latest"); + uint256 public constant DEFAULT_CLAIM_VALUE = 1; + bytes16 public constant DEFAULT_CLAIM_GROUP_ID = ""; + ClaimType public constant DEFAULT_CLAIM_TYPE = ClaimType.GTE; + bytes public constant DEFAULT_CLAIM_EXTRA_DATA = ""; + + // default values for Auth + bool public constant DEFAULT_AUTH_ANON_MODE = false; + uint256 public constant DEFAULT_AUTH_USER_ID = 0; + bytes public constant DEFAULT_AUTH_EXTRA_DATA = ""; + + // default values for MessageSignature + bytes public constant DEFAULT_MESSAGE_SIGNATURE_REQUEST = "MESSAGE_SELECTED_BY_USER"; + + // default value for appId + bytes16 public constant DEFAULT_APP_ID = 0x11b1de449c6c4adb0b5775b3868b28b3; + // default value for namespace + bytes16 public constant DEFAULT_NAMESPACE = bytes16(keccak256("main")); + + // default value for version + bytes32 public constant DEFAULT_VERSION = bytes32("sismo-connect-v1.1"); + + // default proving scheme + bytes32 public constant DEFAULT_PROVING_SCHEME = bytes32("hydra-s3.1"); + + function getEdDSAPubKey() public pure returns (uint256[2] memory) { + return [ + 0x07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb9, + 0x20706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa + ]; + } + + function getImpersonationEdDSAPubKey() public pure returns (uint256[2] memory) { + return [ + 0x1801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b, + 0x057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b + ]; + } + + function getRoot() public pure returns (uint256) { + return 0x0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d85210; + } + + // simple sismoConnect with 1 claim + function getResponseWithOneClaimAndSignature() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + return ( + ResponseBuilder + .empty() + .withAppId(DEFAULT_APP_ID) + .withNamespace(DEFAULT_NAMESPACE) + .withVersion(DEFAULT_VERSION) + .withClaim({ + claim: ClaimBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}), + proofData: hex"2f9bbf1553b98848be543f1a3e0ac887c82d8927fc89e59e4bc0f46500b2f53803054cf63a56f54ee3116729939d5c285e4d6e0f2881f30b0d2c1ee2811ada090b5870dde9d003024c21122e122eac3d53aa9fc116159bf3385fce8fe194485f062384d38ebaac2bc59c1e74a86ab2b516b97a66df4160d6429bea6513d1942c291277ee22a603133f26d18b754867d40c059405a380252d30e8e1b6784c15a80770eee902fba2468672835e68512d6e2be18308e65b2ed62ddf8462877d70b002d8b41e2ebffee6ea7a520b4245211834c44c9ae158f18bfd52f922c8c7b70e2489f6b7d34333f5b5cf3482df7106cf69e8847284ef2fe00e227f2c52ab0d5b000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + provingScheme: DEFAULT_PROVING_SCHEME + }) + .withSignedMessage({signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE)}), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02f9bbf1553b98848be543f1a3e0ac887c82d8927fc89e59e4bc0f46500b2f53803054cf63a56f54ee3116729939d5c285e4d6e0f2881f30b0d2c1ee2811ada090b5870dde9d003024c21122e122eac3d53aa9fc116159bf3385fce8fe194485f062384d38ebaac2bc59c1e74a86ab2b516b97a66df4160d6429bea6513d1942c291277ee22a603133f26d18b754867d40c059405a380252d30e8e1b6784c15a80770eee902fba2468672835e68512d6e2be18308e65b2ed62ddf8462877d70b002d8b41e2ebffee6ea7a520b4245211834c44c9ae158f18bfd52f922c8c7b70e2489f6b7d34333f5b5cf3482df7106cf69e8847284ef2fe00e227f2c52ab0d5b000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + } + + // simple sismoConnect with 2 claims + function getResponseWithTwoClaimsAndSignature() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Claim memory claim = ClaimBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + + Claim memory claimTwo = ClaimBuilder.build({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](2); + proofs[0] = ProofBuilder.build({ + claim: claim, + proofData: hex"112a90db82673ac2dc9d3b0c94fe4bdec60c54fc1f2fb9db24fd778939b0bc571e844e09218e08edf85ded69c70cf173b3973d1dc1861084214ed990f4a8940112e22fb69156b526f5d9205bdfb86fac13465ca6417e8d8358ec16ac9da5f3bc29bb9877f10cd882a788e79d10d60cb1c26a95f6fcfaac914b86f4e929bb29a6019aaf53837786c4cc6d4d94cb551fde1bfda52bd4baf84f5b7b683d6beb55d12f8826b3051c6766f1112dc12ee1121423f694d2549d87b2db3909e2db042f642a4e82e7ea049f01792bb8dd9db687c19aa2e63b47fb32d5bd61a808433cbd3028639724873b9591f0e850c0edfcfb854509f41f8b8e1f6247bf3338b795069a000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }); + proofs[1] = ProofBuilder.build({ + claim: claimTwo, + proofData: hex"1abb9a37eb98d68e994f4bcfd45b784ca2d6b4aa6d2aa77f5245681cafc79b82165e8c16c944d1a943a58fbf32a7be7c641a30d94c53e4d18695740c8a4b15cd06f95c66190ba95f2f4366f8c1b7582f8f9cfc4690674086cca42b1c55cb65b60c34dccd92e5fa17c49de842eb8e3bd70c09a1fba7e3e44e2543d280353b6dd919d06da5a98df5667bf2a41cc00329afc1aa0b2c1f9907539b2a784bb79f68bc0f5d9af52436adf7a02d1645eaa3f46e42e8c6944dba7c0dc94c2e4f3be3a86d164267c480df8bd1aca9195c89f2c6d06c13629aa41c3726f06d833a078781721317c863b582112f085883b36cd4f8e48288f0d2c02739a0a45ff6311a693e9e000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852100f1d1d7e673892c9109c8b536253aa86d1d9dbd317ee37e71f22391e3a9fa5b3138cc656a4ed3352a074f68b57d684b33506d71ef40054fa928402c4897d14b8000000000000000000000000000000000000000000000000000000000000000102d241fdb9d4330c564ffc0a36af05f66c6174657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE), + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0112a90db82673ac2dc9d3b0c94fe4bdec60c54fc1f2fb9db24fd778939b0bc571e844e09218e08edf85ded69c70cf173b3973d1dc1861084214ed990f4a8940112e22fb69156b526f5d9205bdfb86fac13465ca6417e8d8358ec16ac9da5f3bc29bb9877f10cd882a788e79d10d60cb1c26a95f6fcfaac914b86f4e929bb29a6019aaf53837786c4cc6d4d94cb551fde1bfda52bd4baf84f5b7b683d6beb55d12f8826b3051c6766f1112dc12ee1121423f694d2549d87b2db3909e2db042f642a4e82e7ea049f01792bb8dd9db687c19aa2e63b47fb32d5bd61a808433cbd3028639724873b9591f0e850c0edfcfb854509f41f8b8e1f6247bf3338b795069a000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000002d241fdb9d4330c564ffc0a36af05f6000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c01abb9a37eb98d68e994f4bcfd45b784ca2d6b4aa6d2aa77f5245681cafc79b82165e8c16c944d1a943a58fbf32a7be7c641a30d94c53e4d18695740c8a4b15cd06f95c66190ba95f2f4366f8c1b7582f8f9cfc4690674086cca42b1c55cb65b60c34dccd92e5fa17c49de842eb8e3bd70c09a1fba7e3e44e2543d280353b6dd919d06da5a98df5667bf2a41cc00329afc1aa0b2c1f9907539b2a784bb79f68bc0f5d9af52436adf7a02d1645eaa3f46e42e8c6944dba7c0dc94c2e4f3be3a86d164267c480df8bd1aca9195c89f2c6d06c13629aa41c3726f06d833a078781721317c863b582112f085883b36cd4f8e48288f0d2c02739a0a45ff6311a693e9e000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852100f1d1d7e673892c9109c8b536253aa86d1d9dbd317ee37e71f22391e3a9fa5b3138cc656a4ed3352a074f68b57d684b33506d71ef40054fa928402c4897d14b8000000000000000000000000000000000000000000000000000000000000000102d241fdb9d4330c564ffc0a36af05f66c6174657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + } + + // simple sismoConnect with only auth + function getResponseWithOnlyOneAuthAndMessage() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Auth memory auth = AuthBuilder.build({authType: AuthType.VAULT}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + auth: auth, + proofData: hex"138e0d99b4b1fff0128090b63d69da3ccb11b3241ede465119fe13e614e3995f21125ff7d8ff5acdd47a6955c78ecaa079fd4089399f4a92a427e15c3281d8660754ae52a95639d42f53c8b81ed49303a85734b3b9e95e338601ed84c2e8c9920828518d257cb789012f6b2f2c211b02e1062e6623b5aa50dd136eac4fc937ab2dcec087dbeeb3bfe12e255cb5751f6c2f4015a9017cd2f6fbf4a46dcba74eb6290e64a13eaae874d6f6cce1368495dadf20dd5adfb2c801d5cabafa2d078ede270724551d579b5c3d73744a96a8e8a723339d504ac50c71f0a005dca32868d20cdbe42ab4a27fa33ff7388dc1322ce5a2eb2cccf11aaa67a6a755f4ed3d2f1f000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d2ab71fb864979b71106135acfa84afc1d756cda74f8f258896f896b4864f025630423b4c502f1cd4179a425723bf1e15c843733af2ecdee9aef6a0451ef2db7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018202c14c40a8bc84b8fc8748836190f53fc45c66ad969c7bfa2a91afdd1ad8d01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE), + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000118202c14c40a8bc84b8fc8748836190f53fc45c66ad969c7bfa2a91afdd1ad8d00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0138e0d99b4b1fff0128090b63d69da3ccb11b3241ede465119fe13e614e3995f21125ff7d8ff5acdd47a6955c78ecaa079fd4089399f4a92a427e15c3281d8660754ae52a95639d42f53c8b81ed49303a85734b3b9e95e338601ed84c2e8c9920828518d257cb789012f6b2f2c211b02e1062e6623b5aa50dd136eac4fc937ab2dcec087dbeeb3bfe12e255cb5751f6c2f4015a9017cd2f6fbf4a46dcba74eb6290e64a13eaae874d6f6cce1368495dadf20dd5adfb2c801d5cabafa2d078ede270724551d579b5c3d73744a96a8e8a723339d504ac50c71f0a005dca32868d20cdbe42ab4a27fa33ff7388dc1322ce5a2eb2cccf11aaa67a6a755f4ed3d2f1f000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d2ab71fb864979b71106135acfa84afc1d756cda74f8f258896f896b4864f025630423b4c502f1cd4179a425723bf1e15c843733af2ecdee9aef6a0451ef2db7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018202c14c40a8bc84b8fc8748836190f53fc45c66ad969c7bfa2a91afdd1ad8d01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + } + + // simple sismoConnect with one claim and one auth + function getResponseWithOneClaimOneAuthAndOneMessage() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Claim memory claim = ClaimBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + + Auth memory auth = AuthBuilder.build({authType: AuthType.VAULT}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](2); + proofs[0] = ProofBuilder.build({ + claim: claim, + proofData: hex"0ca19971a2d025de05de77c2f1aeda6cc57424c7ac7b3237c90cdcd84412077a1886754c486cae08ea652c173ae1870debef85a80d95d6725e0b37256d695584107aa68653fb67722e07237654af11107d299618a7f312421c62522c76ba51d308540f29626f1443da6c11e54622b23222339ea6da09f8ac77ec315693f24b132925ca9016386c891aa3bac9797a9b43a3313bfd98629d6fb95d2417ae5534e0001017552d3d3e8911f5e5aa4384d8a6e1dfb385e585667626d0aeb9b0c8c95326d41320eb53032f108cf48fcbf17ecf166979272210647d09153113c56871fc165bc6274afbc88352572cfb118bda16a7ba1b99f24c37d1bd31c10f6b4d7607000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }); + proofs[1] = ProofBuilder.build({ + auth: auth, + proofData: hex"2dc5aba5f01c9d989e252e7c14662c0140e0e03cf7e646528c252d423cc72f1f03189aff86d2a4c1a5e14b886f75f51b4210087de5cab5fd39b5567f27eff9902adcb81f9e9f6739d563c61ea80f1602455def27a07a90bbaf1df87b1c01b89621c37053f086bf8b57446a88e15b5501f00a756fcfa57cbc4f3776a930de2b9102137447707533080a013ebde8fb887f8576cdcb9d65c4ed06422e3721c30eb11ebc69e9c11e192ca5c0b392492ad413dd7095705b9e66758dd39aed176511fa23ec1761e651c6d9cd300c48ba1daa3abc5a5c0df7ebbe2338d0bcf53fb2600015d397326c95eadd529aaafd249d9d8288f2aa83635311dda3dc2a1b81cd4c1c000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE), + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02dc5aba5f01c9d989e252e7c14662c0140e0e03cf7e646528c252d423cc72f1f03189aff86d2a4c1a5e14b886f75f51b4210087de5cab5fd39b5567f27eff9902adcb81f9e9f6739d563c61ea80f1602455def27a07a90bbaf1df87b1c01b89621c37053f086bf8b57446a88e15b5501f00a756fcfa57cbc4f3776a930de2b9102137447707533080a013ebde8fb887f8576cdcb9d65c4ed06422e3721c30eb11ebc69e9c11e192ca5c0b392492ad413dd7095705b9e66758dd39aed176511fa23ec1761e651c6d9cd300c48ba1daa3abc5a5c0df7ebbe2338d0bcf53fb2600015d397326c95eadd529aaafd249d9d8288f2aa83635311dda3dc2a1b81cd4c1c000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c00ca19971a2d025de05de77c2f1aeda6cc57424c7ac7b3237c90cdcd84412077a1886754c486cae08ea652c173ae1870debef85a80d95d6725e0b37256d695584107aa68653fb67722e07237654af11107d299618a7f312421c62522c76ba51d308540f29626f1443da6c11e54622b23222339ea6da09f8ac77ec315693f24b132925ca9016386c891aa3bac9797a9b43a3313bfd98629d6fb95d2417ae5534e0001017552d3d3e8911f5e5aa4384d8a6e1dfb385e585667626d0aeb9b0c8c95326d41320eb53032f108cf48fcbf17ecf166979272210647d09153113c56871fc165bc6274afbc88352572cfb118bda16a7ba1b99f24c37d1bd31c10f6b4d7607000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + } + + function getResponseWithTwoClaimsOneAuthAndOneSignature() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Claim memory claim = ClaimBuilder.build({groupId: 0xe9ed316946d3d98dfcd829a53ec9822e}); + + Claim memory claimTwo = ClaimBuilder.build({groupId: 0x02d241fdb9d4330c564ffc0a36af05f6}); + + Auth memory auth = AuthBuilder.build({authType: AuthType.VAULT}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](3); + proofs[0] = ProofBuilder.build({ + claim: claim, + proofData: hex"2d53f40dfd231e94db1a1d5759818fb65788cc5a586dd52a87086c6ef52c2ea5067f9e6672e0fad253a4fe3884a9474a86f76c452ffb70ce828f49ff271c157a212abb5dd8ad3ebe98c1df40799e224a0b6a91af68f97531f8987abd58abc3a10f93cb8848bbe50947bbc22b5c97b388ba7998cd532c20da56567f476b1e76a31105d06e1f880f4048a98a4df35b275375f27e6044dbb2cf04ccacdbe07b823e28afe9c052d68931c22f0e0fa54431072857eab1835faa2d675021facea397ca28d2278d4aa71184d6240498c2b30cad7270f561f8322338e7b93259560e7b6a1560ee42f01bc475cc1f4791f9cabd2c9061e1f4545030271fe81b0c076cb4e4000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }); + + proofs[1] = ProofBuilder.build({ + claim: claimTwo, + proofData: hex"05b949d85f762a54b7400547132026c5d0995d671297872ebfb3dbac1917659f2755fb3f4599b1be254b810f9c973d8d539e56fb599f9d024508b5940a4334ab2368727d07b8fbaa568f5fa27a4cda0c0160243a010f1efcc0db7a6973b247620569ef4735403a355f762108a4d140aa0dc4b2333b8542438953e6f72dc57cce10c14af2d6f21dbcfe917df6e872277a928e5bc2760f3fc4e6a59466089cb23b2b1ecda73e41abed5fe373923efc6a5724a8a865f829d600afc22ad5a846b02a203c58db94f189f5e9d0805f37c30de93e0af2dc930fc138d20cc4b0655df11f0ef8a2c8bbec2d701c5ebb5caf18a04847748c43ef52efd9422effa8b23651fd000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852100f1d1d7e673892c9109c8b536253aa86d1d9dbd317ee37e71f22391e3a9fa5b3138cc656a4ed3352a074f68b57d684b33506d71ef40054fa928402c4897d14b8000000000000000000000000000000000000000000000000000000000000000102d241fdb9d4330c564ffc0a36af05f66c6174657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + }); + + proofs[2] = ProofBuilder.build({ + auth: auth, + proofData: hex"2225b3a9e7f6ddd7774daf4578d38ba58a6d21db07b86ea3852d3e89157cba4200e73eae485f989e2a1a06c0c1b2567c38dd018a25bca5dbc8fdbab9e4bdf7990e94589641fead66343771f10429363a94cae1f25110153e6ed60be3e4aaec302c969077aa9383e862faa80d7399079c627a948c924fcfcae04f8191bb5f164d0253c2b4562cbed45c8d7a0bff785b7157101e957d912882f20a9e91b4a514b80269193c78b666a71cf497bf03d82a1a5938e01ad372cdea3deefb00450a5b1416fe1a4cef14962a2d79f59caedee4ad4a9420ae09b4b0971e59582fb254ddcc2c4a231ac34c6fb2caaeb8a558c1e30c26411503878185bd82728c6193e4ff4f000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE), + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000005400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ee000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02225b3a9e7f6ddd7774daf4578d38ba58a6d21db07b86ea3852d3e89157cba4200e73eae485f989e2a1a06c0c1b2567c38dd018a25bca5dbc8fdbab9e4bdf7990e94589641fead66343771f10429363a94cae1f25110153e6ed60be3e4aaec302c969077aa9383e862faa80d7399079c627a948c924fcfcae04f8191bb5f164d0253c2b4562cbed45c8d7a0bff785b7157101e957d912882f20a9e91b4a514b80269193c78b666a71cf497bf03d82a1a5938e01ad372cdea3deefb00450a5b1416fe1a4cef14962a2d79f59caedee4ad4a9420ae09b4b0971e59582fb254ddcc2c4a231ac34c6fb2caaeb8a558c1e30c26411503878185bd82728c6193e4ff4f000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100200000000000000000000000000288480976500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c00d3916fb92997fc6d11ceac7618482759bbdee5134e9d90baf116ba3519c9ac003ddc52962996f3fba4559612dab2325a5b0955dcea7b47acca0cf09ec11077715d0c7554341e472f609caae810b38873fe00309bb2d45ec9a832d3495e4036a2522e15d49a09c52652fef43746de58ec7b1fd7b184c865c83e1388e094271b409ba20579e2d04accd56eb8e8a491ab9b4d34f99bfc72cd440617da672eed9051ee6ceeeeb8a777900d022714aff12d1226c32ce7878959335314ce025fcc1cd2e67c2299cf9706fe81e750b7169ac0997b670a655c3141cc3848a6c36262aa1268cc791f070169f6130083246044546114360f7717fc47a4038c470c2b0eb71000000000000000000000000100200000000000000000000000000288480976509f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000e9ed316946d3d98dfcd829a53ec9822e000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02d53f40dfd231e94db1a1d5759818fb65788cc5a586dd52a87086c6ef52c2ea5067f9e6672e0fad253a4fe3884a9474a86f76c452ffb70ce828f49ff271c157a212abb5dd8ad3ebe98c1df40799e224a0b6a91af68f97531f8987abd58abc3a10f93cb8848bbe50947bbc22b5c97b388ba7998cd532c20da56567f476b1e76a31105d06e1f880f4048a98a4df35b275375f27e6044dbb2cf04ccacdbe07b823e28afe9c052d68931c22f0e0fa54431072857eab1835faa2d675021facea397ca28d2278d4aa71184d6240498c2b30cad7270f561f8322338e7b93259560e7b6a1560ee42f01bc475cc1f4791f9cabd2c9061e1f4545030271fe81b0c076cb4e4000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d8521004f81599b826fa9b715033e76e5b2fdda881352a9b61360022e30ee33ddccad90744e9b92802056c722ac4b31612e1b1de544d5b99481386b162a0b59862e0850000000000000000000000000000000000000000000000000000000000000001285bf79dc20d58e71b9712cb38c420b9cb91d3438c8e3dbaf07829b03ffffffc0000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000002d241fdb9d4330c564ffc0a36af05f6000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c005b949d85f762a54b7400547132026c5d0995d671297872ebfb3dbac1917659f2755fb3f4599b1be254b810f9c973d8d539e56fb599f9d024508b5940a4334ab2368727d07b8fbaa568f5fa27a4cda0c0160243a010f1efcc0db7a6973b247620569ef4735403a355f762108a4d140aa0dc4b2333b8542438953e6f72dc57cce10c14af2d6f21dbcfe917df6e872277a928e5bc2760f3fc4e6a59466089cb23b2b1ecda73e41abed5fe373923efc6a5724a8a865f829d600afc22ad5a846b02a203c58db94f189f5e9d0805f37c30de93e0af2dc930fc138d20cc4b0655df11f0ef8a2c8bbec2d701c5ebb5caf18a04847748c43ef52efd9422effa8b23651fd000000000000000000000000000000000000000000000000000000000000000009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852100f1d1d7e673892c9109c8b536253aa86d1d9dbd317ee37e71f22391e3a9fa5b3138cc656a4ed3352a074f68b57d684b33506d71ef40054fa928402c4897d14b8000000000000000000000000000000000000000000000000000000000000000102d241fdb9d4330c564ffc0a36af05f66c6174657374000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + } + + function getResponseWithGitHubAuth() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Auth memory auth = AuthBuilder.build({authType: AuthType.GITHUB}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + auth: auth, + proofData: hex"0dac2cbf2a79fbf0685feb4decc19d488741ab490e3a1d9bc7f188b117650cd81acd802e6ed6a5c7d1b82b43238e6c6b9ccc5ba466aa7a2edcf11916374b410f06acfd9ce499c4798e90170cd4ae34163e98f57c011b96ee4cab4a48e2bf276c01431be40bbdfa36bea2306300b12b33d5848b3ac2d537697b7bb49d20eadb09222be62294cfe98a8d9fc397d96a3d76b1baf55644ebcad35c9b29be6a0a6c542bb5308742a9bea4ff29f1732cfc0b1ac496dd7e2ab7f2f6f4e7760700cab6e4166218b204613db523550412311a5f58d3090138c70c38ba402c61bedd4fcaf1202bc490be5cab53595dc1359743004bc48c6db6fa7a9bb80c65cdc3d28fea54000000000000000000000000100100000000000000000000000000009999037009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: abi.encode(0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE), + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000007def1d6d28d6bda49e69fa89ad75d160becba3ae0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100100000000000000000000000000009999037000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c00dac2cbf2a79fbf0685feb4decc19d488741ab490e3a1d9bc7f188b117650cd81acd802e6ed6a5c7d1b82b43238e6c6b9ccc5ba466aa7a2edcf11916374b410f06acfd9ce499c4798e90170cd4ae34163e98f57c011b96ee4cab4a48e2bf276c01431be40bbdfa36bea2306300b12b33d5848b3ac2d537697b7bb49d20eadb09222be62294cfe98a8d9fc397d96a3d76b1baf55644ebcad35c9b29be6a0a6c542bb5308742a9bea4ff29f1732cfc0b1ac496dd7e2ab7f2f6f4e7760700cab6e4166218b204613db523550412311a5f58d3090138c70c38ba402c61bedd4fcaf1202bc490be5cab53595dc1359743004bc48c6db6fa7a9bb80c65cdc3d28fea54000000000000000000000000100100000000000000000000000000009999037009f60d972df499264335faccfc437669a97ea2b6c97a1a7ddf3f0105eda34b1d07f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + ); + } + + function getResponseWithGitHubAuthWithoutSignature() + external + pure + returns (SismoConnectResponse memory response, bytes memory responseAsBytes) + { + Auth memory auth = AuthBuilder.build({authType: AuthType.GITHUB}); + + SismoConnectProof[] memory proofs = new SismoConnectProof[](1); + proofs[0] = ProofBuilder.build({ + auth: auth, + proofData: hex"14aa96fb34414b749bb4610bace69a3d3e9ed4b1af6137f7d1a3270590c696bb0074dc54bfd774a3185b445f2b1013bcefb8d8d1b98b186611829ae9ac59a44407b6fa1abaafa92b207d2bed2139ff1a6cd05f56ac2167f89a6b3a3180eceebb107f09ef3f109f1ac13560ed255b5605e340964f5fd6b96ae9e62634cd219d51233f679d2011810af86b8da940f2e3b8ba38716d0ab63a8aa6944c13dd6ec40d0c36d09c76572cc1dfffd527ca60c1828642782322a49ef6df921f0a57ecc65f2706ff429747a7b1dd72643a24dc9be189b0461f155fe5479bde1f78609fece82331e429f79401e878e826c36ada7d85053e00226dd49e6e76fb76ff7b2e43490000000000000000000000001001000000000000000000000000000099990370000000000000000000000000000000000000000000000000000000000000000007f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + }); + + return ( + SismoConnectResponse({ + appId: 0x11b1de449c6c4adb0b5775b3868b28b3, + namespace: bytes16(keccak256("main")), + version: bytes32("sismo-connect-v1.1"), + signedMessage: "", + proofs: proofs + }), + // response as bytes + hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100100000000000000000000000000009999037000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c014aa96fb34414b749bb4610bace69a3d3e9ed4b1af6137f7d1a3270590c696bb0074dc54bfd774a3185b445f2b1013bcefb8d8d1b98b186611829ae9ac59a44407b6fa1abaafa92b207d2bed2139ff1a6cd05f56ac2167f89a6b3a3180eceebb107f09ef3f109f1ac13560ed255b5605e340964f5fd6b96ae9e62634cd219d51233f679d2011810af86b8da940f2e3b8ba38716d0ab63a8aa6944c13dd6ec40d0c36d09c76572cc1dfffd527ca60c1828642782322a49ef6df921f0a57ecc65f2706ff429747a7b1dd72643a24dc9be189b0461f155fe5479bde1f78609fece82331e429f79401e878e826c36ada7d85053e00226dd49e6e76fb76ff7b2e43490000000000000000000000001001000000000000000000000000000099990370000000000000000000000000000000000000000000000000000000000000000007f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + ); + } + + function getCheatSheetResponse() external pure returns (bytes memory) { + return + hex"000000000000000000000000000000000000000000000000000000000000002032403ced4b65f2079eda77c84e7d2be600000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d49206c6f7665205369736d6f2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000ac00000000000000000000000000000000000000000000000000000000000000f80000000000000000000000000000000000000000000000000000000000000144000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001de000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000027a00000000000000000000000000000000000000000000000000000000000002c8000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02ee756e8d291546c67b5573b9b751b5bd5a0dbcede35464ef2a6e2c14f11b033151164d686f667393f18dcd27584954f2126998bcbed6ed9b9982cd99069bb830d2e1f84055faad2b66fd81c5db45b47356df5f8a3e3c3f852b63ffb83579b25221a09032e42863c6847ff2dd1ad2843628b7cae34ce0eee41c2c95829526ba611abc4b47a83f51174c44304a3ec7fc5e0a4d2661c6e0516f1f932c5258d788a14165f2fac0ff540383b5d74113f799dc98b5e6bc9cad1d8c1706b8606ff7d400877d9fc97b985ab302afe17621dd1ede1379dc2671aeb791d104097ce7a2b7c2d27c3487bda0b24a491c70c021aee29840c77400e3612e6959cd78c1d29e55000000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008ab1760889f26cbbf33a75fd2cf1696bfccdc9e600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c024d4b21c846468fc5e45041225279dbaf181db1d30c0ca47ba531e2139d9eaf7280d33b782823298589f29aaba714eea5acb96ebe2826de93f633d7f3c0a008f2f32d3204f8911a2bcfa70a0ef4e197b1807f8cfbb23f8e5686d79ccce4a40a10d7cf559488b27861bd1cc1b63275ccdceb49daaf8639ee099df558ceec868ed0edc00ae97888c6e213a4922f25c33e2e9de1d9a84f65101e071ac07297799eb2ca5e5cc67ee3d6c3a747ee9f0da812d8cbcb477a162dcabc40860092b8e4985049dded4313ca1c7fd8c2bb2341dc239b4c0b7db930ecc7e2b849e5dcdfe9317247dc2c6229691441432bffb6228a40d4096290a347bed1a215bf4203b6932a80000000000000000000000008ab1760889f26cbbf33a75fd2cf1696bfccdc9e61304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4c94a6091545e40fc9c3e0982aec8942e282f3800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c005e9a85d4b9401511669228989a3ff0c30b5b9f459e900fc75d4ab9a70c49ef80e46b75f5cf3bccbf05d7af71f87fe8d132b7f85a1607b0bfd6e4feaa8213f9f1063f2f84a7ce96e52f5e43003dfab677a74c1ec96a1d626225a4033cde26ebc0e54e534d6de2002f1a08033821a7fd348fd0f9dae7e85e0796f76319ff8c8e5251c6201cecdbd21885dd4d341227cdbf8f7f5693146166d99192c0ada581d5924b9ebe2e3dd193f95bbfc462a64bddcce25b799936a919452a704138a60c35d1534cb185dc6762a446321ad3b0ac40720cde123c86d8ada6ed050b0c106adc81ee271099e4702a5925e134d668eea626c19b220a2c39dd16d0400168d99d791000000000000000000000000a4c94a6091545e40fc9c3e0982aec8942e282f381304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100100000000000000000000000000003577409700000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0137081498c847bdc10ace33d22949bfc73b674d4812b66a8f53e878ddffc190f0cda340c783fd25566dfd14394dcc8fc9e7af60237bbec04d70b097721f7e6e70e0998b7010de2546274bb5c03238e5ffd2340c319ba85327f11e8dd0279f1f217e1c040a49739304d4025d7c42d97f2b41102d4b504b49693666d6fffae1ea5279e58b6b2a415acd5db0706921a85985d348386637463751a7de73448ac35fd215517307d716502bc580dff5ba4c8f484eeb7a1f2f9cc69f49052a09f6887b70803efb5635d81e2f07eb7ae6024bcd4ffd2b927209865e183747523f7d274c51464ceea457eb61b7c2a132177ec531842ceb568a51fe6a4e145a0f9a564a0ee00000000000000000000000010010000000000000000000000000000357740971304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100300000000000000000000000000087560811000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c01cab87335090f31f2c858c45dbe40ac1e3fd5eda4b584bbc8b8784991a5c9f91041986364178d5d6a6a9cfbe96e6679111feff038be558c436df97c113d8f10e25b99ceb0082c9df5bb7e90739e1c1f4d4588bae1169c88c5422356294e86b7e0b43cb521b0b664462993aea9666d18a84e6684afeed6ba49b0b42402b67685e0b82bfa1c7724f214cd6fd624e7300ab4372f955ebfd9b489aa935ed5e074eb2239b65a6f9f51888891d69f57ce2d4a6fd1a1594d77090edf526d16242feb4a2157bec5129edd6e86f43d73f12b2561250a8835cfa5eb1533f1a15d5d1513ca11129beec3cd8288b1beb42352734cb93173f72679402a51db226dbe1a01ce49900000000000000000000000010030000000000000000000000000008756081101304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000fae674b6cba3ff2f8ce2114defb200b1000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0068a54cba7e80eea17652e5399bac0f373a37289e19e4990f03b14f5304ba97b0e86c7b9ff626dad18a91068c36cfaca3b4bba8c23ccbd8aa89a50478632bb3808dac983625c650c8ee73594fd9b6cc609696db35f213f4efa3c7355436c61d9273d66565e35cd47df9763521fcb24813b0070b920aa7d13206d3f541540a4542ff6e85db5be75a22c067551f70000275568339f0e67155907ce6aaacdd9c35120e1c6f0752cb5565b7324847eadc5b568b60b356976f6194b59cddd32f72bcd0c60c6907df2d4e1dfc7fd7cafb77170d74deed3b60f4565d8814ad3345c489d2073030d081ad0615e2898c77db05842544e08d1909daffd4b1f51af41d0c1a600000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d85210223889be50de6309c4a51edd039aa1fb882c9964a746581ff319bbe982debcf82efc4cc7c03398856dbf08377861fb15549f5a9137456a615d4da264e7d69cd4000000000000000000000000000000000000000000000000000000000000000108f0ec7865abde5ef350b4bd682b46dfa35deafb12d4cd29ac96341c4ffffffb000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001cde61966decb8600dfd0749bd371f12000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02c7c25b4657897bdb2bc62112bdac39f1fcb4fd090b44a73b9e17125754d0f9a26321b26cb19ac752eb7f7557ef0b868d9e1c0cb22a6f3354d8bf1eae8efb02f2ea24f5c4265ed8439dfa93a3742164e91bad77e6fee1b2f88ecd7c58fbe802027f44df7403fb133ce8cc8c5fd23b458c4bc53c455727e28d753bfea20f1445d2182c405df59bec7da832b42cfa3edbbd48bdf42dbfb073950d13ee7b0a55f1c1d4eb48a63d9d4f67c61a932a830101e76b501cd1145ffc755d8d5450b554bbd2fbd2b04120d8ef1e5bd290b00ff4a25a917bccfa03f13da4f70e7d30ac792932e716a0f4c76aa9a197419c2125257cfcfd36fd4e7c7de28c145ec429e3c5a1700000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852101e7a3215d4d02e734fa653c5ca96357521ac260e6ba94a1f05c413b0143e15bd2113caea8c11ac1bdcde3d297ebd9f24df376b1ae881a18e62e49c81b5db8267000000000000000000000000000000000000000000000000000000000000000f1cde61966decb8600dfd0749bd371f126c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002fae674b6cba3ff2f8ce2114defb200b1000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c0107ecc33ddbb094a870b4f300a5fff992ce214effaf8e441b1d3de2d2b9ae0a012842d6a54fd89bc48444701e99eb26114f4bf767490bb13d0446f214c55ce7603ecc0efc47b9d2fe6683d856ddc141d234da6e80845263c4bcc1e823443da430c50c00649710842967c9755f99bafc7219a19fad38cce29f1bcf1316c1469061c0b6468c29704188ddece490bd2723cc392b4ca7b1f6501c6469236cb535bf61df114f50ba48448088c440823c7cf811003b2c1707f124d8ab2b262c7400c982b14db09cfabca6f7fd817457ae68a882cbd72c01839cc326408e938e3deb0140323af36a396c8b906ecfda2d92e82383e4693cef14d94a2b2b77f4b61b3859000000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d85210223889be50de6309c4a51edd039aa1fb882c9964a746581ff319bbe982debcf82efc4cc7c03398856dbf08377861fb15549f5a9137456a615d4da264e7d69cd4000000000000000000000000000000000000000000000000000000000000000a08f0ec7865abde5ef350b4bd682b46dfa35deafb12d4cd29ac96341c4ffffffb000000000000000000000000000000000000000000000000000000000000000110915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000fae674b6cba3ff2f8ce2114defb200b1000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c02699914aaa5bb1b11b49261603cd894aee490c39b8ca5ea5c1625f05c60c3e2e2e4bef13a3cc0df3f3dc1bf5d601b699f4c2d94b1ca2b62622f91874f3a600832f057ff2148e63bc50db8c9f049e33929d195610f8b8a826d75941d2ef7c46ef1a108ab29c16b6498990fa5767f4e3594648c444a71dd16924366d03e1f31a9813f954aaf7916663320a9baa8de31cb14f3e4ce8fb7fc88d7ae2356f8d91404f1c21b77322002fdfcea7df847cf31f4dc7c4485d535392f4583aa67eb63bfcd214ca04a230eca28910992acf54cb9682f8b7a4240b193ccdd7ac081181e9ee3f1fbfc685affa356338b832c8c49dc2d33cafb950af2377e2ea73e53cc101020400000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d85210223889be50de6309c4a51edd039aa1fb882c9964a746581ff319bbe982debcf82efc4cc7c03398856dbf08377861fb15549f5a9137456a615d4da264e7d69cd4000000000000000000000000000000000000000000000000000000000000000108f0ec7865abde5ef350b4bd682b46dfa35deafb12d4cd29ac96341c4ffffffb000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001cde61966decb8600dfd0749bd371f12000000000000000000000000000000006c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001900000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c01376d89c862093d8af4faece2845d584a7f5adbce6415f91185445053066db272b55dfb2d1f4d34239c3dde1e396bec29e5a1398dc9cc589a1c4a01dc6b5a190038bbde989bdaa41ae06c00e806e8b05698557a1ee2b7bcba05173cb72e5a22b2b4b2be01439457de5fbee80ca58c442b0a98239810cd611ab1db95e2806d81a194d33e4750fa3d1dc0417bc8c620935c888ad3a5af607fc4ccf21af83b539980c8017f171ea205708d7d16dd2d6968682c92a4f6aa60c4a2b397849c064f1d71f2c626c4108ab3566301144a75f0964791e8770d014da3c6b986cadc296763d19d3935c9924bd88b558920f376f4cd31833d1f69dcaa8b747bd8fab8a83305300000000000000000000000000000000000000000000000000000000000000001304dc6e4c90bc43f257c55a1c5ec90070d73f4356bca95b502a7bbc28d13a071801b584700a740f9576cc7e83745895452edc518a9ce60b430e1272fc4eb93b057cf80de4f8dd3e4c56f948f40c28c3acbeca71ef9f825597bf8cc059f1238b0d4f2a0d3c9c82fbdb9f118c948baa9d8c0b2f467855c6b4cb43a95631d852101e7a3215d4d02e734fa653c5ca96357521ac260e6ba94a1f05c413b0143e15bd2113caea8c11ac1bdcde3d297ebd9f24df376b1ae881a18e62e49c81b5db826700000000000000000000000000000000000000000000000000000000000000191cde61966decb8600dfd0749bd371f126c617465737400000000000000000000000000000000000000000000000000000000000000000000000000000000000010915e40a7c9ce7f97e81541c24893b4f714de4794fc4a3c71898cb9f25bb55f0fe61c3a8c717465050c08081b2efe7d66020da96e00293df4c354c783d06b6b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + } +} diff --git a/test/verifiers/hydra-s3/HydraS3Verifier.t.sol b/test/verifiers/hydra-s3/HydraS3Verifier.t.sol new file mode 100644 index 0000000..e8a7bfa --- /dev/null +++ b/test/verifiers/hydra-s3/HydraS3Verifier.t.sol @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import "forge-std/console.sol"; +import {HydraS3BaseTest} from "./HydraS3BaseTest.t.sol"; +import {SismoConnectHarness} from "test/harness/SismoConnectHarness.sol"; +import "src/SismoConnectLib.sol"; +import {HydraS3ProofData, HydraS3Lib, HydraS3ProofInput} from "src/verifiers/HydraS3Lib.sol"; + +contract HydraS3VerifierTest is HydraS3BaseTest { + using HydraS3Lib for HydraS3ProofData; + + SismoConnectHarness sismoConnect; + address user = 0x7def1d6D28D6bDa49E69fa89aD75d160BEcBa3AE; + bytes16 constant appId = 0x11b1de449c6c4adb0b5775b3868b28b3; + bytes16 constant groupId = 0xe9ed316946d3d98dfcd829a53ec9822e; + + bool public DEFAULT_IS_IMPERSONATION_MODE = false; + + ClaimRequest claimRequest; + AuthRequest authRequest; + SignatureRequest signature; + + HydraS3ProofData snarkProof; + + function setUp() public virtual override { + super.setUp(); + sismoConnect = new SismoConnectHarness(appId, DEFAULT_IS_IMPERSONATION_MODE); + claimRequest = sismoConnect.exposed_buildClaim({groupId: groupId}); + authRequest = sismoConnect.exposed_buildAuth({authType: AuthType.VAULT}); + signature = sismoConnect.exposed_buildSignature({message: abi.encode(user)}); + } + + function test_RevertWith_InvalidVersionOfProvingScheme() public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + invalidResponse.proofs[0].provingScheme = bytes32("fake-proving-scheme"); + // register the fake proving scheme to the HydraS3Verifier address i the SismoConnectVerifier contract + // if the proving scheme is not registered, it will revert without an error since the SismoConnectVerifier will not be able to find the verifier when routing + vm.prank(owner); + sismoConnectVerifier.registerVerifier(bytes32("fake-proving-scheme"), address(hydraS3Verifier)); + vm.expectRevert( + abi.encodeWithSignature("InvalidVersion(bytes32)", bytes32("fake-proving-scheme")) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_VaultNamespaceMismatch(uint256 invalidVaultNamespace) public { + // we force the invalidVaultNamespace to be different from the correct one + // while being a valid uint128 + vm.assume(invalidVaultNamespace < 2 ** 128 - 1); + vm.assume( + invalidVaultNamespace != + uint256(keccak256(abi.encodePacked(appId, bytes16(0)))) % HydraS3Lib.SNARK_FIELD + ); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOnlyOneAuthAndMessage(); + // we change the vaultNamespace to be equal to a random one instead of the coorect appId + // vaultNamespace is at index 11 is in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 11, + invalidVaultNamespace + ); + vm.expectRevert( + abi.encodeWithSignature( + "VaultNamespaceMismatch(uint256,uint256)", + snarkProof._getVaultNamespace(), + uint256(keccak256(abi.encodePacked(appId, bytes16(0)))) % HydraS3Lib.SNARK_FIELD + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: authRequest, + signature: signature + }); + } + + function test_RevertWith_DestinationVerificationNotEnabled() public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOnlyOneAuthAndMessage(); + // we change the authType to be equal to GITHUB instead of ANON + invalidResponse.proofs[0].auths[0] = Auth({ + authType: AuthType.GITHUB, + isAnon: false, + isSelectableByUser: true, + userId: 0, + extraData: "" + }); + + // we change the authType to be equal to GITHUB instead of ANON, so it is the same as in the response and we can test the revert of the destinationVerificationEnabled + AuthRequest memory githubAuthRequest = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB + }); + + // this should revert because the destinationVerificationEnabled is false and the AuthType is different from ANON + vm.expectRevert(abi.encodeWithSignature("DestinationVerificationNotEnabled()")); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: githubAuthRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_CommitmentMapperPubKeyXMismatchWithAuth( + uint256 incorrectCommitmentMapperPubKeyX + ) public { + // we assume that the incorrectCommitmentMapperPubKeyX is different from the correct commitmentMapperPubKeyX when fuzzing + vm.assume(incorrectCommitmentMapperPubKeyX != hydraS3Proofs.getEdDSAPubKey()[0]); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOnlyOneAuthAndMessage(); + // we change the authType to be equal to GITHUB instead of ANON to be able to check the public key + invalidResponse.proofs[0].auths[0] = Auth({ + authType: AuthType.GITHUB, + isAnon: false, + isSelectableByUser: true, + userId: 0, + extraData: "" + }); + // we change the commitmentMapperPubKeyX to be equal to a random uint256 instead of the correct commitmentMapperPubKeyX + // commitmentMapperPubKeyX is at index 2 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 2, + incorrectCommitmentMapperPubKeyX + ); + // we change the destinationVerificationEnabled to be equal to true instead of false + // with an AuthType different from ANON, the destinationVerificationEnabled should be true + // destinationVerificationEnabled at index 13 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse(invalidResponse, 13, uint256(1)); // true + + // we change the authType to be equal to GITHUB instead of ANON, so it is the same as in the response and we can test the revert of the destinationVerificationEnabled + AuthRequest memory githubAuthRequest = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB + }); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getEdDSAPubKey()[1]), + bytes32(incorrectCommitmentMapperPubKeyX), + bytes32(snarkProof._getCommitmentMapperPubKey()[1]) + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: githubAuthRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_CommitmentMapperPubKeyYMismatchWithAuth( + uint256 incorrectCommitmentMapperPubKeyY + ) public { + // we assume that the incorrectCommitmentMapperPubKeyY is different from the correct commitmentMapperPubKeyY when fuzzing + vm.assume(incorrectCommitmentMapperPubKeyY != hydraS3Proofs.getEdDSAPubKey()[1]); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOnlyOneAuthAndMessage(); + // we change the authType to be equal to GITHUB instead of ANON to be able to check the public key + invalidResponse.proofs[0].auths[0] = Auth({ + authType: AuthType.GITHUB, + isAnon: false, + isSelectableByUser: true, + userId: 0, + extraData: "" + }); + // we change the commitmentMapperPubKeyY to be equal to a random uint256 instead of the correct commitmentMapperPubKeyY + // commitmentMapperPubKeyY is at index 3 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 3, + incorrectCommitmentMapperPubKeyY + ); + // we change the destinationVerificationEnabled to be equal to true instead of false + // with an AuthType different from ANON, the destinationVerificationEnabled should be true + invalidResponse = _changeProofDataInSismoConnectResponse(invalidResponse, 13, uint256(1)); // destinationVerificationEnabled at index 13 is equal to true + + // we change the authType to be equal to GITHUB instead of ANON, so it is the same as in the response and we can test the revert of the destinationVerificationEnabled + AuthRequest memory githubAuthRequest = sismoConnect.exposed_buildAuth({ + authType: AuthType.GITHUB + }); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getEdDSAPubKey()[1]), + bytes32(snarkProof._getCommitmentMapperPubKey()[0]), + bytes32(incorrectCommitmentMapperPubKeyY) + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + auth: githubAuthRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_ClaimValueMismatch(uint256 invalidClaimValue) public { + // we force that the invalidClaimValue is different from the correct claimValue when fuzzing + vm.assume(invalidClaimValue != 1); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // claimValue is at index 7 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse(invalidResponse, 7, invalidClaimValue); + vm.expectRevert(abi.encodeWithSignature("ClaimValueMismatch()")); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_RequestIdentifierMismatch( + uint256 incorrectRequestIdentifier + ) public { + uint256 correctRequestIdentifier = _encodeRequestIdentifier( + groupId, + bytes16("latest"), + appId, + bytes16(keccak256("main")) + ); + // we force that the incorrectRequestIdentifier is different from the correct requestIdentifier when fuzzing + vm.assume( + incorrectRequestIdentifier != + _encodeRequestIdentifier(groupId, bytes16("latest"), appId, bytes16(keccak256("main"))) + ); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // requestIdentifier is at index 5 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 5, + incorrectRequestIdentifier + ); + vm.expectRevert( + abi.encodeWithSignature( + "RequestIdentifierMismatch(uint256,uint256)", + incorrectRequestIdentifier, + correctRequestIdentifier + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_CommitmentMapperPubKeyXMismatchWithClaim( + uint256 incorrectCommitmentMapperPubKeyX + ) public { + // we assume that the incorrectCommitmentMapperPubKeyX is different from the correct commitmentMapperPubKeyX when fuzzing + vm.assume(incorrectCommitmentMapperPubKeyX != hydraS3Proofs.getEdDSAPubKey()[0]); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // commitmentMapperPubKeyX is at index 2 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 2, + incorrectCommitmentMapperPubKeyX + ); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getEdDSAPubKey()[1]), + bytes32(incorrectCommitmentMapperPubKeyX), + bytes32(snarkProof._getCommitmentMapperPubKey()[1]) + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + + // it should also revert whe in impersonation mode + SismoConnectHarness impersonationSismoConnect = new SismoConnectHarness(appId, true); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getImpersonationEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getImpersonationEdDSAPubKey()[1]), + bytes32(incorrectCommitmentMapperPubKeyX), + bytes32(snarkProof._getCommitmentMapperPubKey()[1]) + ) + ); + impersonationSismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_CommitmentMapperPubKeyYMismatchWithClaim( + uint256 incorrectCommitmentMapperPubKeyY + ) public { + // we assume that the incorrectCommitmentMapperPubKeyY is different from the correct commitmentMapperPubKeyY when fuzzing + vm.assume(incorrectCommitmentMapperPubKeyY != hydraS3Proofs.getEdDSAPubKey()[1]); + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // commitmentMapperPubKeyY is at index 3 in the snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 3, + incorrectCommitmentMapperPubKeyY + ); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getEdDSAPubKey()[1]), + bytes32(snarkProof._getCommitmentMapperPubKey()[0]), + bytes32(incorrectCommitmentMapperPubKeyY) + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + + // it should also revert whe in impersonation mode + SismoConnectHarness impersonationSismoConnect = new SismoConnectHarness(appId, true); + vm.expectRevert( + abi.encodeWithSignature( + "CommitmentMapperPubKeyMismatch(bytes32,bytes32,bytes32,bytes32)", + bytes32(hydraS3Proofs.getImpersonationEdDSAPubKey()[0]), + bytes32(hydraS3Proofs.getImpersonationEdDSAPubKey()[1]), + bytes32(snarkProof._getCommitmentMapperPubKey()[0]), + bytes32(incorrectCommitmentMapperPubKeyY) + ) + ); + impersonationSismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_SourceVerificationNotEnabled() public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // we change the sourceVerificationEnabled to be equal to false instead of true + // sourceVerificationEnabled is at index 12 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse(invalidResponse, 12, uint256(0)); + vm.expectRevert(abi.encodeWithSignature("SourceVerificationNotEnabled()")); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_RegistryTreeRootNotAvailable( + uint256 invalidRegistryTreeRoot + ) public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + + // we shift the return of the mocked AvailableRootsregistry contract to be always false + availableRootsRegistry.switchIsRootAvailable(); + // registryTreeRoot is at index 4 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 4, + invalidRegistryTreeRoot + ); + vm.expectRevert( + abi.encodeWithSignature("RegistryRootNotAvailable(uint256)", invalidRegistryTreeRoot) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_AccountsTreeValueMismatch( + uint256 incorrectAccountsTreeValue + ) public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + uint256 correctAccountsTreeValue = abi + .decode(invalidResponse.proofs[0].proofData, (HydraS3ProofData)) + ._getAccountsTreeValue(); + // we assume that the incorrectAccountsTreeValue is different from the correct accountsTreeValue when fuzzing + vm.assume(incorrectAccountsTreeValue != correctAccountsTreeValue); + // accountsTreeValue is at index 8 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 8, + incorrectAccountsTreeValue + ); + vm.expectRevert( + abi.encodeWithSignature( + "AccountsTreeValueMismatch(uint256,uint256)", + incorrectAccountsTreeValue, + correctAccountsTreeValue + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function test_RevertWith_ClaimTypeMismatch() public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + // we change the claimComparator to be equal to 1, the claimType should be EQ to not revert + // but we keep the claimType of GTE in the claimRequest + uint256 incorrectClaimComparator = 1; + // claimComparator is at index 9 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 9, + incorrectClaimComparator + ); + vm.expectRevert( + abi.encodeWithSignature( + "ClaimTypeMismatch(uint256,uint256)", + incorrectClaimComparator, + claimRequest.claimType + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_InvalidExtraData(uint256 incorrectExtraData) public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + uint256 correctExtraData = abi + .decode(invalidResponse.proofs[0].proofData, (HydraS3ProofData)) + ._getExtraData(); + // we assume that the incorrectExtraData is different from the correct extraData when fuzzing + vm.assume(incorrectExtraData != correctExtraData); + // extraData is at index 1 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 1, + incorrectExtraData + ); + vm.expectRevert( + abi.encodeWithSignature( + "InvalidExtraData(uint256,uint256)", + incorrectExtraData, + correctExtraData + ) + ); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + function testFuzz_RevertWith_InvalidProof(uint256 incorrectProofIdentifier) public { + (SismoConnectResponse memory invalidResponse, ) = hydraS3Proofs + .getResponseWithOneClaimAndSignature(); + uint256 correctProofIdentifier = abi + .decode(invalidResponse.proofs[0].proofData, (HydraS3ProofData)) + ._getProofIdentifier(); + vm.assume(incorrectProofIdentifier != correctProofIdentifier); + // we force the incorrectProofIdentifier to be less than the SNARK_FIELD + vm.assume(incorrectProofIdentifier < HydraS3Lib.SNARK_FIELD); + // proofIdentifier is at index 6 in snarkProof's inputs + invalidResponse = _changeProofDataInSismoConnectResponse( + invalidResponse, + 6, + incorrectProofIdentifier + ); + vm.expectRevert(abi.encodeWithSignature("InvalidProof()")); + sismoConnect.exposed_verify({ + responseBytes: abi.encode(invalidResponse), + claim: claimRequest, + signature: signature + }); + } + + /////////////////////////// + // Helper functions + /////////////////////////// + + // this helper function is used to change the input at the specified index of the snark proof in the response + // the value is the new value of the input at the specified index + function _changeProofDataInSismoConnectResponse( + SismoConnectResponse memory response, + uint256 index, + uint256 value + ) internal returns (SismoConnectResponse memory) { + // Decode the snark proof from the sismoConnectProof + // This snark proof is specify to this proving scheme + snarkProof = abi.decode(response.proofs[0].proofData, (HydraS3ProofData)); + // we change the input at the specified index to be different + snarkProof.input[index] = value; + response.proofs[0].proofData = abi.encode(snarkProof); + return response; + } + + function _encodeRequestIdentifier( + bytes16 _groupId, + bytes16 groupTimestamp, + bytes16 _appId, + bytes16 namespace + ) internal pure returns (uint256) { + bytes32 groupSnapshotId = bytes32(abi.encodePacked(_groupId, groupTimestamp)); + bytes32 serviceId = bytes32(abi.encodePacked(_appId, namespace)); + return + uint256(keccak256(abi.encodePacked(serviceId, groupSnapshotId))) % HydraS3Lib.SNARK_FIELD; + } +} diff --git a/test/verifiers/mocks/VerifierMockBaseTest.t.sol b/test/verifiers/mocks/VerifierMockBaseTest.t.sol new file mode 100644 index 0000000..413a790 --- /dev/null +++ b/test/verifiers/mocks/VerifierMockBaseTest.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.17; + +import {BaseTest} from "test/BaseTest.t.sol"; +import {VerifierMock} from "test/mocks/VerifierMock.sol"; + +contract VerifierMockBaseTest is BaseTest { + VerifierMock verifierMock; + + function setUp() public virtual override { + super.setUp(); + + verifierMock = new VerifierMock(); + + vm.startPrank(owner); + sismoConnectVerifier.registerVerifier(verifierMock.VERSION(), address(verifierMock)); + vm.stopPrank(); + } +}