diff --git a/foundry.toml b/foundry.toml index 49a3eae..773eb1d 100644 --- a/foundry.toml +++ b/foundry.toml @@ -5,6 +5,7 @@ libs = ["lib"] fs_permissions = [{ access = "read-write", path = "./"}] bytecode_hash="none" +solc_version="0.8.19" [rpc_endpoints] arbitrum_one = "https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}" diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 2501af3..d87b906 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.17; import {Test} from "forge-std/Test.sol"; import {IAddressesProvider} from "src/interfaces/IAddressesProvider.sol"; import {AddressesProviderMock} from "test/mocks/AddressesProviderMock.sol"; -// import {SismoConnectVerifierMock} from "test/mocks/SismoConnectVerifierMock.sol"; +import {SismoConnectVerifierMock} from "test/mocks/SismoConnectVerifierMock.sol"; import {AuthRequestBuilder} from "src/utils/AuthRequestBuilder.sol"; import {ClaimRequestBuilder} from "src/utils/ClaimRequestBuilder.sol"; import {SignatureBuilder} from "src/utils/SignatureBuilder.sol"; @@ -16,7 +16,7 @@ contract BaseTest is Test { address immutable owner = vm.addr(3); address immutable sismoAddressProviderV2 = 0x3Cd5334eB64ebBd4003b72022CC25465f1BFcEe6; - //SismoConnectVerifierMock sismoConnectVerifier; + SismoConnectVerifierMock sismoConnectVerifier; // external libraries AuthRequestBuilder authRequestBuilder; @@ -26,7 +26,7 @@ contract BaseTest is Test { function setUp() public virtual { AddressesProviderMock addressesProviderMock = new AddressesProviderMock(); - // sismoConnectVerifier = new SismoConnectVerifierMock(); + sismoConnectVerifier = new SismoConnectVerifierMock(); // external libraries authRequestBuilder = new AuthRequestBuilder(); @@ -36,10 +36,10 @@ contract BaseTest is Test { vm.etch(sismoAddressProviderV2, address(addressesProviderMock).code); - // IAddressesProvider(sismoAddressProviderV2).set( - // address(sismoConnectVerifier), - // string("sismoConnectVerifier-v1.2") - // ); + IAddressesProvider(sismoAddressProviderV2).set( + address(sismoConnectVerifier), + string("sismoConnectVerifier-v1.2") + ); IAddressesProvider(sismoAddressProviderV2).set( address(authRequestBuilder), string("authRequestBuilder-v1.1") diff --git a/test/mocks/SismoConnectVerifierMock.sol b/test/mocks/SismoConnectVerifierMock.sol index 5635a1c..a60ae0c 100644 --- a/test/mocks/SismoConnectVerifierMock.sol +++ b/test/mocks/SismoConnectVerifierMock.sol @@ -1,158 +1,125 @@ -// // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.17; +// SPDX-License-Identifier: MIT -// import "../../src/interfaces/ISismoConnectVerifier.sol"; -// import "../../src/utils/Structs.sol"; +pragma solidity ^0.8.17; -// // this contract is supposed to implement the interface from SismoConnectVerifier contract -// // we dont specify the interface here because for some reason we encounter a stack too deep error up to a local variable -// // when implementing the `verify` function -// // TO replicate the error, try adding the `config` and `request` argument to the verify function -// // it compiles with one of them (+ response) but not with the three arguments -// contract SismoConnectVerifierMock is ISismoConnectVerifier { -// // 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 -// VerifiedAuth[] auths; -// VerifiedClaim[] claims; -// } +import "../../src/interfaces/ISismoConnectVerifier.sol"; -// bytes32 public immutable SISMO_CONNECT_VERSION = "sismo-connect-v1.1"; +contract SismoConnectVerifierMock is ISismoConnectVerifier { + uint8 public constant IMPLEMENTATION_VERSION = 1; + bytes32 public immutable SISMO_CONNECT_VERSION = "sismo-connect-v1.1"; -// function _check(SismoConnectRequest memory request) internal pure { -// if (request.auths.length == 0 && request.claims.length == 0) { -// revert("SismoConnectVerifierMock: no auths or claims"); -// } -// } + // 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 + } -// function verify( -// SismoConnectResponse memory response, -// SismoConnectRequest memory, // request, -// SismoConnectConfig memory // config -// ) external pure returns (SismoConnectVerifiedResult memory) { -// VerifiedArraysInfos memory infos = VerifiedArraysInfos({ -// nbOfAuths: 0, -// nbOfClaims: 0, -// authsIndex: 0, -// claimsIndex: 0, -// auths: new VerifiedAuth[](0), -// claims: new VerifiedClaim[](0) -// }); + // 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; + } -// infos = _getVerifiedArrayInfos(infos, response); + function verify( + SismoConnectResponse memory response, + SismoConnectRequest memory, // request + SismoConnectConfig memory // config + ) external view override returns (SismoConnectVerifiedResult memory) { + uint256 responseProofsArrayLength = response.proofs.length; + VerifiedArraysInfos memory infos = VerifiedArraysInfos({ + nbOfAuths: 0, + nbOfClaims: 0, + authsIndex: 0, + claimsIndex: 0 + }); -// infos = _saveVerifiedAuthAndClaim(infos, response); + // 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; + } -// return -// SismoConnectVerifiedResult({ -// appId: response.appId, -// namespace: response.namespace, -// version: response.version, -// auths: infos.auths, -// claims: infos.claims, -// signedMessage: response.signedMessage -// }); -// } + VerifiedProofs memory verifiedProofs = VerifiedProofs({ + auths: new VerifiedAuth[](infos.nbOfAuths), + claims: new VerifiedClaim[](infos.nbOfClaims) + }); -// function _getVerifiedArrayInfos( -// VerifiedArraysInfos memory infos, -// SismoConnectResponse memory response -// ) private pure returns (VerifiedArraysInfos memory) { -// // Count the number of auths and claims in the response -// for (uint256 i = 0; i < response.proofs.length; i++) { -// infos.nbOfAuths += response.proofs[i].auths.length; -// infos.nbOfClaims += response.proofs[i].claims.length; -// } + for (uint256 i = 0; i < responseProofsArrayLength; i++) { + // we use an external call to getVerifiedAuthAndClaim to avoid stack too deep error (the caller stack is not known by the callee contract) + // in the prod implementation, an external call to a verifier contract is done + // it explains why we don't encounter the stack too deep error in the prod implementation + (VerifiedAuth memory verifiedAuth, VerifiedClaim memory verifiedClaim) = this + .getVerifiedAuthAndClaim({ + appId: response.appId, + namespace: response.namespace, + proof: response.proofs[i] + }); -// return -// VerifiedArraysInfos({ -// nbOfAuths: infos.nbOfAuths, -// nbOfClaims: infos.nbOfClaims, -// authsIndex: infos.authsIndex, -// claimsIndex: infos.claimsIndex, -// auths: new VerifiedAuth[](infos.nbOfAuths), -// claims: new VerifiedClaim[](infos.nbOfClaims) -// }); -// } + // 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++; + } + } -// function _saveVerifiedAuthAndClaim( -// VerifiedArraysInfos memory infos, -// SismoConnectResponse memory response -// ) internal pure returns (VerifiedArraysInfos memory) { -// for (uint256 i = 0; i < response.proofs.length; i++) { -// ( -// VerifiedAuth memory verifiedAuth, -// VerifiedClaim memory verifiedClaim -// ) = _getVerifiedAuthAndClaim(response); -// if (verifiedAuth.proofData.length != 0) { -// infos.auths[infos.authsIndex] = verifiedAuth; -// infos.authsIndex++; -// } -// if (verifiedClaim.proofData.length != 0) { -// infos.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 + }); + } -// return infos; -// } + function getVerifiedAuthAndClaim( + bytes16 appId, + bytes16 namespace, + SismoConnectProof memory proof + ) external pure returns (VerifiedAuth memory, VerifiedClaim memory) { + VerifiedAuth memory verifiedAuth; + VerifiedClaim memory verifiedClaim; -// function _getVerifiedAuthAndClaim( -// SismoConnectResponse memory response -// ) private pure returns (VerifiedAuth memory, VerifiedClaim memory) { -// VerifiedAuth memory verifiedAuth; -// VerifiedClaim memory verifiedClaim; - -// if (response.proofs[0].auths.length != 0) { -// verifiedAuth = VerifiedAuth({ -// authType: response.proofs[0].auths[0].authType, -// isAnon: response.proofs[0].auths[0].isAnon, -// userId: response.proofs[0].auths[0].userId, -// proofData: response.proofs[0].proofData, -// extraData: response.proofs[0].auths[0].extraData -// }); -// // verifiedAuth = VerifiedAuth({ -// // authType: AuthType.VAULT, -// // isAnon: false, -// // userId: 0, -// // proofData: "123", -// // extraData: "" -// // }); -// } -// if (response.proofs[0].claims.length != 0) { -// verifiedClaim = VerifiedClaim({ -// claimType: response.proofs[0].claims[0].claimType, -// groupId: response.proofs[0].claims[0].groupId, -// groupTimestamp: response.proofs[0].claims[0].groupTimestamp, -// value: response.proofs[0].claims[0].value, -// proofId: uint256( -// keccak256( -// abi.encodePacked( -// response.proofs[0].claims[0].groupId, -// response.proofs[0].claims[0].groupTimestamp, -// response.appId, -// response.namespace -// ) -// ) -// ), -// proofData: response.proofs[0].proofData, -// extraData: response.proofs[0].claims[0].extraData -// }); -// // verifiedClaim = VerifiedClaim({ -// // claimType: ClaimType.GTE, -// // groupId: bytes16("groupId"), -// // groupTimestamp: bytes16("latest"), -// // value: 1, -// // proofId: 1, -// // proofData: "123", -// // extraData: "" -// // }); -// } -// return (verifiedAuth, verifiedClaim); -// } -// } + if (proof.auths.length != 0) { + verifiedAuth = VerifiedAuth({ + authType: proof.auths[0].authType, + isAnon: proof.auths[0].isAnon, + userId: proof.auths[0].userId, + proofData: proof.proofData, + extraData: proof.auths[0].extraData + }); + } + if (proof.claims.length != 0) { + verifiedClaim = VerifiedClaim({ + claimType: proof.claims[0].claimType, + groupId: proof.claims[0].groupId, + groupTimestamp: proof.claims[0].groupTimestamp, + value: proof.claims[0].value, + proofId: uint256( + keccak256( + abi.encodePacked( + proof.claims[0].groupId, + proof.claims[0].groupTimestamp, + appId, + namespace + ) + ) + ), + proofData: proof.proofData, + extraData: proof.claims[0].extraData + }); + } + return (verifiedAuth, verifiedClaim); + } +} diff --git a/test/unit/SismoConnect.t.sol b/test/unit/SismoConnect.t.sol index d2332d5..8759c11 100644 --- a/test/unit/SismoConnect.t.sol +++ b/test/unit/SismoConnect.t.sol @@ -64,4 +64,13 @@ contract SismoConnectTest is BaseTest { userId: uint256(bytes32("wrong-id")) }); } + + function test_verifyProof() public view { + bytes + memory responseBytes = hex"000000000000000000000000000000000000000000000000000000000000002011b1de449c6c4adb0b5775b3868b28b300000000000000000000000000000000b8e2054f8a912367e38a22ce773328ff000000000000000000000000000000007369736d6f2d636f6e6e6563742d76312e31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a068796472612d73332e310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100100000000000000000000000000009999037000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c014aa96fb34414b749bb4610bace69a3d3e9ed4b1af6137f7d1a3270590c696bb0074dc54bfd774a3185b445f2b1013bcefb8d8d1b98b186611829ae9ac59a44407b6fa1abaafa92b207d2bed2139ff1a6cd05f56ac2167f89a6b3a3180eceebb107f09ef3f109f1ac13560ed255b5605e340964f5fd6b96ae9e62634cd219d51233f679d2011810af86b8da940f2e3b8ba38716d0ab63a8aa6944c13dd6ec40d0c36d09c76572cc1dfffd527ca60c1828642782322a49ef6df921f0a57ecc65f2706ff429747a7b1dd72643a24dc9be189b0461f155fe5479bde1f78609fece82331e429f79401e878e826c36ada7d85053e00226dd49e6e76fb76ff7b2e43490000000000000000000000001001000000000000000000000000000099990370000000000000000000000000000000000000000000000000000000000000000007f6c5612eb579788478789deccb06cf0eb168e457eea490af754922939ebdb920706798455f90ed993f8dac8075fc1538738a25f0c928da905c0dffd81869fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086297004382ede0550866e3e15fdce4b5b9fa843f0c12fece0fa11cf69ba5ff01935d4d418952220ae0332606f61de2894d8b84c3076e6097ef3746a1ba04a5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"; + ClaimRequest memory claimRequest = claimRequestBuilder.build({groupId: bytes16("group-id")}); + // by default, the sismoConnectVerifier contract is mocked + // the mock will return true for any proof well encoded in the response + sismoConnect.exposed_verify({responseBytes: responseBytes, claim: claimRequest}); + } }