diff --git a/.solhintignore b/.solhintignore
index 821516fc..7c569c83 100644
--- a/.solhintignore
+++ b/.solhintignore
@@ -7,11 +7,6 @@
**/lib/VerifierStateTransition.sol
**/lib/VerifierV3.sol
**/lib/VerifierV3Wrapper.sol
-**/lib/groth16-verifiers/Groth16VerifierMTP.sol
-**/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol
-**/lib/groth16-verifiers/Groth16VerifierSig.sol
-**/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol
-**/lib/groth16-verifiers/Groth16VerifierStateTransition.sol
-**/lib/groth16-verifiers/Groth16VerifierV3.sol
-**/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol
+**/lib/groth16-verifiers
**/node_modules
+
diff --git a/contracts/AlwaysRevert.sol b/contracts/AlwaysRevert.sol
index 7f9bf943..93c57422 100644
--- a/contracts/AlwaysRevert.sol
+++ b/contracts/AlwaysRevert.sol
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
+error TheContractIsDisabled();
+
/// @title This contract as a dummy implementation for Proxy contract if we need to revert all calls
// This can be applied to disable all methods of a proxy contract with explicit error message
contract AlwaysRevert {
fallback() external payable {
- revert("The contract is disabled");
+ revert TheContractIsDisabled();
}
}
diff --git a/contracts/Create2AddressAnchor.sol b/contracts/Create2AddressAnchor.sol
index 4913ffc1..e43d8108 100644
--- a/contracts/Create2AddressAnchor.sol
+++ b/contracts/Create2AddressAnchor.sol
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
+/* solhint-disable no-empty-blocks */
contract Create2AddressAnchor {}
+/* solhint-enable no-empty-blocks */
diff --git a/contracts/cross-chain/CrossChainProofValidator.sol b/contracts/cross-chain/CrossChainProofValidator.sol
index 09f271f2..b88a3518 100644
--- a/contracts/cross-chain/CrossChainProofValidator.sol
+++ b/contracts/cross-chain/CrossChainProofValidator.sol
@@ -6,6 +6,13 @@ import {ICrossChainProofValidator} from "../interfaces/ICrossChainProofValidator
import {IState} from "../interfaces/IState.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+error IdentityStateProofInvalid();
+error GlobalStateProofInvalid();
+error GlobalStateProofSigningAddressInvalid(address recovered);
+error IdentityStateProofSigningAddressInvalid(address recovered);
+error OracleTimestampCannotBeInThePast();
+error OracleReplacedAtTimestampCannotBeInTheFuture();
+
/**
* @dev Contract which provides proof validation from identity state
* and global state proofs from trusted oracle with signature from any network.
@@ -83,11 +90,12 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator
gsu.globalStateMsg,
gsu.signature
);
- require(isValid, "Global state proof is not valid");
- require(
- recovered == _oracleSigningAddress,
- "Global state proof signing address is not valid"
- );
+ if (!isValid) {
+ revert GlobalStateProofInvalid();
+ }
+ if (recovered != _oracleSigningAddress) {
+ revert GlobalStateProofSigningAddressInvalid(recovered);
+ }
return
IState.GlobalStateProcessResult({
@@ -117,11 +125,12 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator
isu.idStateMsg,
isu.signature
);
- require(isValid, "Identity state proof is not valid");
- require(
- recovered == _oracleSigningAddress,
- "Identity state proof signing address is not valid"
- );
+ if (!isValid) {
+ revert IdentityStateProofInvalid();
+ }
+ if (recovered != _oracleSigningAddress) {
+ revert IdentityStateProofSigningAddressInvalid(recovered);
+ }
return
IState.IdentityStateProcessResult({
@@ -213,13 +222,13 @@ contract CrossChainProofValidator is Ownable, EIP712, ICrossChainProofValidator
uint256 replacedAtTimestamp
) internal view returns (uint256 replacedAt) {
if (oracleTimestamp < block.timestamp - MAX_TIMESTAMP_LAG) {
- revert("Oracle timestamp cannot be in the past");
+ revert OracleTimestampCannotBeInThePast();
}
replacedAt = replacedAtTimestamp == 0 ? oracleTimestamp : replacedAtTimestamp;
if (replacedAt > block.timestamp + MAX_REPLACED_AT_AHEAD_OF_TIME) {
- revert("Oracle replacedAtTimestamp or oracle timestamp cannot be in the future");
+ revert OracleReplacedAtTimestampCannotBeInTheFuture();
}
// this should never happen as block.timestamp is always greater than 0
diff --git a/contracts/identitytreestore/IdentityTreeStore.sol b/contracts/identitytreestore/IdentityTreeStore.sol
index fa636c7d..a2a4eaef 100644
--- a/contracts/identitytreestore/IdentityTreeStore.sol
+++ b/contracts/identitytreestore/IdentityTreeStore.sol
@@ -8,6 +8,11 @@ import {IOnchainCredentialStatusResolver} from "../interfaces/IOnchainCredential
import {IRHSStorage} from "../interfaces/IRHSStorage.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
+error NodeNotFound();
+error InvalidStateNode();
+error InvalidNodeType();
+error UnsupportedLength();
+
/**
* @dev Contract which provides onchain Reverse Hash Service (RHS)
* for checking revocation status of claims.
@@ -40,10 +45,12 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
// keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityTreeStore.ReverseHashLibData")) - 1)) &
// ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant ReverseHashLibDataStorageLocation =
0x0f7e3bdc6cc0e880d509aa1f6b8d1a88e5fcb7274e18dfba772424a36fe9b400;
function _getReverseHashLibDataStorage() private pure returns (ReverseHashLib.Data storage $) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := ReverseHashLibDataStorageLocation
}
@@ -55,6 +62,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
}
// keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityTreeStore.Main")) - 1)) & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant IdentityTreeStoreMainStorageLocation =
0x95ca427007e091a13a7ccfcb233b8a2ed19d987330a248c445b1b483a35bb800;
@@ -64,6 +72,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
pure
returns (IdentityTreeStoreMainStorage storage $)
{
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := IdentityTreeStoreMainStorageLocation
}
@@ -96,7 +105,9 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
*/
function getNode(uint256 key) public view returns (uint256[] memory) {
uint256[] memory preim = _getReverseHashLibDataStorage().getPreimage(key);
- require(preim.length > 0, "Node not found");
+ if (preim.length == 0) {
+ revert NodeNotFound();
+ }
return preim;
}
@@ -122,6 +133,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
* @return CredentialStatus
*/
function getRevocationStatusByIdAndState(
+ // solhint-disable-next-line no-unused-vars
uint256 id,
uint256 state,
uint64 nonce
@@ -134,7 +146,9 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
uint64 nonce
) internal view returns (CredentialStatus memory) {
uint256[] memory roots = getNode(state);
- require(_nodeType(roots) == NodeType.State, "Invalid state node");
+ if (_nodeType(roots) != NodeType.State) {
+ revert InvalidStateNode();
+ }
CredentialStatus memory status = CredentialStatus({
issuer: IdentityStateRoots({
@@ -200,7 +214,7 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
proof.siblings[i] = children[1];
}
} else {
- revert("Invalid node type");
+ revert InvalidNodeType();
}
}
@@ -234,6 +248,6 @@ contract IdentityTreeStore is Initializable, IOnchainCredentialStatusResolver, I
if (preimage.length == 3) {
return PoseidonUnit3L.poseidon([preimage[0], preimage[1], preimage[2]]);
}
- revert("Unsupported length");
+ revert UnsupportedLength();
}
}
diff --git a/contracts/imports.sol b/contracts/imports.sol
index 4cdc83cf..61554a96 100644
--- a/contracts/imports.sol
+++ b/contracts/imports.sol
@@ -1,7 +1,9 @@
-// SPDX-License-Identifier: UNLICENSED
+// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
// We import these here to force Hardhat to compile them.
// This ensures that their artifacts are available for Hardhat Ignition to use.
+/* solhint-disable no-unused-import */
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
+/* solhint-enable no-unused-import */
diff --git a/contracts/interfaces/IAuthValidator.sol b/contracts/interfaces/IAuthValidator.sol
new file mode 100644
index 00000000..56413787
--- /dev/null
+++ b/contracts/interfaces/IAuthValidator.sol
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+/**
+ * @dev IAuthValidator. Interface for verification of auth data.
+ */
+interface IAuthValidator {
+ /**
+ * @dev AuthResponseField. Information about response fields from verification. Used in verify function.
+ * @param name Name of the response field
+ * @param value Value of the response field
+ */
+ struct AuthResponseField {
+ string name;
+ uint256 value;
+ }
+
+ /**
+ * @dev Get version of the contract
+ */
+ function version() external view returns (string memory);
+
+ /**
+ * @dev Verify the proof with the supported method informed in the auth query data
+ * packed as bytes and that the proof was generated by the sender.
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return userID User Id for the auth proof verified and response fields.
+ * @return authResponseFields Additional response fields.
+ */
+ function verify(
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) external returns (uint256 userID, AuthResponseField[] memory authResponseFields);
+}
diff --git a/contracts/interfaces/ICircuitValidator.sol b/contracts/interfaces/ICircuitValidator.sol
deleted file mode 100644
index 273172af..00000000
--- a/contracts/interfaces/ICircuitValidator.sol
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {IState} from "./IState.sol";
-
-/**
- * @dev ICircuitValidator. Interface for circuit verification.
- */
-interface ICircuitValidator {
- /**
- * @dev KeyToInputIndex. Information about public inputs of the circuit verification. Used in verify function.
- * @param key Name of the public input
- * @param inputIndex Index of the public input
- *
- * Note: Kept for backward compatibility. Now it's replaced by Signal struct for verifyV2 function.
- */
- struct KeyToInputIndex {
- string key;
- uint256 inputIndex;
- }
-
- /**
- * @dev Signal. Information about public signals of the circuit verification. Used in verifyV2 function.
- * @param name Name of the public signal
- * @param value Value of the public signal
- */
- struct Signal {
- string name;
- uint256 value;
- }
-
- /**
- * @dev Get version of the contract
- */
- function version() external view returns (string memory);
-
- /**
- * @dev Verify with the supported circuit informed in the request query data the groth16 proof
- * π=([πa]1,[πb]2,[πc]1) and that the proof was generated by the sender.
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @return Array of key to public input index as result.
- */
- function verify(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
- address sender
- ) external returns (ICircuitValidator.KeyToInputIndex[] memory);
-
- /**
- * @dev Verify with the supported circuit informed in the request query data the groth16 proof
- * packed as bytes and that the proof was generated by the sender.
- * @param zkProof Proof packed as bytes to verify.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param state State contract to get identities and gist states to check.
- * @return Array of public signals as result.
- */
- function verifyV2(
- bytes calldata zkProof,
- bytes calldata data,
- address sender,
- IState state
- ) external returns (ICircuitValidator.Signal[] memory);
-
- /**
- * @dev Get supported circuit ids.
- * @return ids Array of circuit ids supported.
- */
- function getSupportedCircuitIds() external view returns (string[] memory ids);
-
- /**
- * @dev Get the index of the public input of the circuit by name.
- * @param name Name of the public input.
- * @return Index of the public input.
- */
- function inputIndexOf(string memory name) external view returns (uint256);
-}
diff --git a/contracts/interfaces/IGroth16Verifier.sol b/contracts/interfaces/IGroth16Verifier.sol
new file mode 100644
index 00000000..e41c4196
--- /dev/null
+++ b/contracts/interfaces/IGroth16Verifier.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+/**
+ * @dev IGroth16Verifier. Interface for verification of groth16 proofs.
+ */
+interface IGroth16Verifier {
+ /**
+ * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
+ * @param a πa element of the groth16 proof.
+ * @param b πb element of the groth16 proof.
+ * @param c πc element of the groth16 proof.
+ * @param signals Public inputs and outputs of the circuit.
+ * @return r true if the proof is verified.
+ */
+ function verify(
+ uint256[2] calldata a,
+ uint256[2][2] calldata b,
+ uint256[2] calldata c,
+ uint256[] calldata signals
+ ) external view returns (bool r);
+}
diff --git a/contracts/interfaces/IRequestValidator.sol b/contracts/interfaces/IRequestValidator.sol
new file mode 100644
index 00000000..2d921eb9
--- /dev/null
+++ b/contracts/interfaces/IRequestValidator.sol
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+/**
+ * @dev IRequestValidator. Interface for verification of request query data.
+ */
+interface IRequestValidator {
+ /**
+ * @dev ResponseField. Information about response fields from verification. Used in verify function.
+ * @param name Name of the response field
+ * @param value Value of the response field
+ */
+ struct ResponseField {
+ string name;
+ uint256 value;
+ }
+
+ /**
+ * @dev RequestParam. Information about request param from request query data.
+ * @param name Name of the request query param
+ * @param value Value of the request query param
+ */
+ struct RequestParam {
+ string name;
+ uint256 value;
+ }
+
+ /**
+ * @dev Get version of the contract
+ */
+ function version() external view returns (string memory);
+
+ /**
+ * @dev Verify the proof with the supported method informed in the request query data
+ * packed as bytes and that the proof was generated by the sender.
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of response fields as result.
+ */
+ function verify(
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) external returns (ResponseField[] memory);
+
+ /**
+ * @dev Get the request params of the request query data.
+ * @param params Request query data of the credential to verify.
+ * @return RequestParams of the request query data.
+ */
+ function getRequestParams(bytes calldata params) external view returns (RequestParam[] memory);
+
+ /**
+ * @dev Get the index of the request param by name
+ * @param name Name of the request param
+ * @return Index of the request param
+ */
+ function requestParamIndexOf(string memory name) external view returns (uint256);
+}
diff --git a/contracts/interfaces/IVerifier.sol b/contracts/interfaces/IVerifier.sol
index b7ba452f..fe8d9a52 100644
--- a/contracts/interfaces/IVerifier.sol
+++ b/contracts/interfaces/IVerifier.sol
@@ -1,22 +1,266 @@
// SPDX-License-Identifier: GPL-3.0
+
pragma solidity 0.8.27;
+import {IAuthValidator} from "./IAuthValidator.sol";
+import {IRequestValidator} from "./IRequestValidator.sol";
+
/**
- * @dev IVerifier. Interface for verification of groth16 proofs.
+ * @dev IVerifier. Interface for creating requests and verifying request responses through validators circuits.
*/
interface IVerifier {
/**
- * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param input Public inputs of the circuit.
- * @return r true if the proof is verified.
- */
- function verify(
- uint256[2] calldata a,
- uint256[2][2] calldata b,
- uint256[2] calldata c,
- uint256[] calldata input
- ) external view returns (bool r);
+ * @dev Request. Structure for request.
+ * @param requestId Request id.
+ * @param metadata Metadata of the request.
+ * @param validator Validator to verify the response.
+ * @param params Parameters data of the request.
+ */
+ struct Request {
+ uint256 requestId;
+ string metadata;
+ IRequestValidator validator;
+ bytes params;
+ }
+
+ /**
+ * @dev Request. Structure for request for storage.
+ * @param metadata Metadata of the request.
+ * @param validator Validator circuit.
+ * @param params Params of the request. Proof parameters could be ZK groth16, plonk, ESDSA, EIP712, etc.
+ */
+ struct RequestData {
+ string metadata;
+ IRequestValidator validator;
+ bytes params;
+ address creator;
+ }
+
+ /**
+ * @dev RequestInfo. Structure for request info.
+ * @param requestId Request id.
+ * @param metadata Metadata of the request.
+ * @param validator Validator to verify the response.
+ * @param params Parameters data of the request.
+ * @param creator Creator of the request.
+ * @param verifierId Verifier id.
+ */
+ struct RequestInfo {
+ uint256 requestId;
+ string metadata;
+ IRequestValidator validator;
+ bytes params;
+ address creator;
+ }
+
+ /**
+ * @dev Response. Structure for response.
+ * @param requestId Request id of the request.
+ * @param proof proof to verify.
+ * @param metadata Metadata of the request.
+ */
+ struct Response {
+ uint256 requestId;
+ bytes proof;
+ bytes metadata;
+ }
+
+ /**
+ * @dev AuthResponse. Structure for auth response.
+ * @param authMethod Auth type of the proof response.
+ * @param proof proof to verify.
+ */
+ struct AuthResponse {
+ string authMethod;
+ bytes proof;
+ }
+
+ /**
+ * @dev RequestProofStatus. Structure for request proof status.
+ * @param requestId Request id of the proof.
+ * @param isVerified True if the proof is verified.
+ * @param validatorVersion Version of the validator.
+ * @param timestamp Timestamp of the proof.
+ */
+ struct RequestProofStatus {
+ uint256 requestId;
+ bool isVerified;
+ string validatorVersion;
+ uint256 timestamp;
+ }
+
+ /**
+ * @dev AuthMethod. Structure for auth type for auth proofs.
+ * @param authMethod Auth type of the auth proof.
+ * @param validator Validator to verify the auth.
+ * @param params Parameters data of the auth.
+ */
+ struct AuthMethod {
+ string authMethod;
+ IAuthValidator validator;
+ bytes params;
+ }
+
+ /**
+ * @dev MultiRequest. Structure for multiRequest.
+ * @param multiRequestId MultiRequest id.
+ * @param requestIds Request ids for this multi multiRequest (without groupId. Single requests).
+ * @param groupIds Group ids for this multi multiRequest (all the requests included in the group. Grouped requests).
+ * @param metadata Metadata for the multiRequest. Empty in first version.
+ */
+ struct MultiRequest {
+ uint256 multiRequestId;
+ uint256[] requestIds;
+ uint256[] groupIds;
+ bytes metadata;
+ }
+
+ /**
+ * @dev Submits an array of responses and updates proofs status
+ * @param authResponse Auth response including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This
+ * includes identities and global states.
+ */
+ function submitResponse(
+ AuthResponse memory authResponse,
+ Response[] memory responses,
+ bytes memory crossChainProofs
+ ) external;
+
+ /**
+ * @dev Sets different requests
+ * @param requests List of requests
+ */
+ function setRequests(Request[] calldata requests) external;
+
+ /**
+ * @dev Gets a specific request by ID
+ * @param requestId The ID of the request
+ * @return request The request info
+ */
+ function getRequest(uint256 requestId) external view returns (RequestInfo memory request);
+
+ /**
+ * @dev Get the requests count.
+ * @return Requests count.
+ */
+ function getRequestsCount() external view returns (uint256);
+
+ /**
+ * @dev Get the group of requests count.
+ * @return Group of requests count.
+ */
+ function getGroupsCount() external view returns (uint256);
+
+ /**
+ * @dev Get the group of requests.
+ * @return Group of requests.
+ */
+ function getGroupedRequests(uint256 groupID) external view returns (RequestInfo[] memory);
+
+ /**
+ * @dev Checks if a request ID exists
+ * @param requestId The ID of the request
+ * @return Whether the request ID exists
+ */
+ function requestIdExists(uint256 requestId) external view returns (bool);
+
+ /**
+ * @dev Checks if a group ID exists
+ * @param groupId The ID of the group
+ * @return Whether the group ID exists
+ */
+ function groupIdExists(uint256 groupId) external view returns (bool);
+
+ /**
+ * @dev Checks if a multiRequest ID exists
+ * @param multiRequestId The ID of the multiRequest
+ * @return Whether the multiRequest ID exists
+ */
+ function multiRequestIdExists(uint256 multiRequestId) external view returns (bool);
+
+ /**
+ * @dev Gets the status of the multiRequest verification
+ * @param multiRequestId The ID of the MultiRequest
+ * @param userAddress The address of the user
+ * @return status The status of the MultiRequest. "True" if all requests are verified, "false" otherwise
+ */
+ function getMultiRequestProofsStatus(
+ uint256 multiRequestId,
+ address userAddress
+ ) external view returns (RequestProofStatus[] memory);
+
+ /**
+ * @dev Checks if the proofs from a Multirequest submitted for a given sender and request ID are verified
+ * @param multiRequestId The ID of the MultiRequest
+ * @param userAddress The address of the user
+ * @return Wether the multiRequest is verified.
+ */
+ function areMultiRequestProofsVerified(
+ uint256 multiRequestId,
+ address userAddress
+ ) external view returns (bool);
+
+ /**
+ * @dev Gets proof storage response field value
+ * @param requestId Id of the request
+ * @param sender Address of the user
+ * @param responseFieldName Name of the proof storage response field to get
+ */
+ function getResponseFieldValue(
+ uint256 requestId,
+ address sender,
+ string memory responseFieldName
+ ) external view returns (uint256);
+
+ /**
+ * @dev Gets proof storage response fields
+ * @param requestId Id of the request
+ * @param sender Address of the user
+ */
+ function getResponseFields(
+ uint256 requestId,
+ address sender
+ ) external view returns (IRequestValidator.ResponseField[] memory);
+
+ /**
+ * @dev Checks if a proof from a request submitted for a given sender and request ID is verified
+ * @param sender Sender of the proof.
+ * @param requestId Request id of the Request to verify.
+ * @return True if proof is verified for the sender and request id.
+ */
+ function isRequestProofVerified(address sender, uint256 requestId) external view returns (bool);
+
+ /**
+ * @dev Sets an auth method
+ * @param authMethod The auth method to add
+ */
+ function setAuthMethod(AuthMethod calldata authMethod) external;
+
+ /**
+ * @dev Sets a multiRequest
+ * @param multiRequest The multiRequest data
+ */
+ function setMultiRequest(MultiRequest calldata multiRequest) external;
+
+ /**
+ * @dev Gets a specific multiRequest by ID
+ * @param multiRequestId The ID of the multiRequest
+ * @return multiRequest The multiRequest data
+ */
+ function getMultiRequest(
+ uint256 multiRequestId
+ ) external view returns (MultiRequest memory multiRequest);
+
+ /**
+ * @dev Get the proof status for the sender and request with requestId.
+ * @param sender Sender of the proof.
+ * @param requestId Request id of the proof.
+ * @return Proof status.
+ */
+ function getRequestProofStatus(
+ address sender,
+ uint256 requestId
+ ) external view returns (RequestProofStatus memory);
}
diff --git a/contracts/interfaces/IZKPVerifier.sol b/contracts/interfaces/IZKPVerifier.sol
deleted file mode 100644
index 585dd43c..00000000
--- a/contracts/interfaces/IZKPVerifier.sol
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-
-pragma solidity 0.8.27;
-
-import {ICircuitValidator} from "./ICircuitValidator.sol";
-
-/**
- * @dev IZKPVerifier. Interface for verification of groth16 proofs for validators circuits.
- */
-interface IZKPVerifier {
- /**
- * @dev ZKPRequest. Structure for ZKP request.
- * @param metadata Metadata of the request.
- * @param validator Validator circuit.
- * @param data Data of the request.
- */
- struct ZKPRequest {
- string metadata;
- ICircuitValidator validator;
- bytes data;
- }
- /**
- * @dev ProofStatus. Structure for proof status.
- * @param isVerified True if the proof is verified.
- * @param validatorVersion Version of the validator.
- * @param blockNumber Block number of the proof.
- * @param blockTimestamp Block timestamp of the proof.
- */
- struct ProofStatus {
- bool isVerified;
- string validatorVersion;
- uint256 blockNumber;
- uint256 blockTimestamp;
- }
-
- /**
- * @dev ZKPResponse. Structure for ZKP response.
- * @param requestId Request id of the ZKP request.
- * @param zkProof ZKP proof to verify.
- * @param data Metadata of the request.
- */
- struct ZKPResponse {
- uint64 requestId;
- bytes zkProof;
- bytes data;
- }
-
- /**
- * @dev Submit the groth16 proof π=([πa]1,[πb]2,[πc]1) for the ZKP request requestId.
- * @param requestId Request id of the ZKP request.
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- */
- function submitZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) external;
-
- /**
- * @dev Submit the groth16 proof π=([πa]1,[πb]2,[πc]1) for the ZKP request requestId.
- * @param responses The list of responses including ZKP request ID, ZK proof and metadata.
- * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle).
- */
- function submitZKPResponseV2(
- ZKPResponse[] memory responses,
- bytes memory crossChainProofs
- ) external;
-
- /**
- * @dev Set the ZKP request for the requestId.
- * @param requestId Request id of the ZKP request.
- * @param request ZKP request to set.
- */
- function setZKPRequest(uint64 requestId, ZKPRequest calldata request) external;
-
- /**
- * @dev Get the ZKP request for the requestId.
- * @param requestId Request id of the ZKP request.
- * @return ZKP request.
- */
- function getZKPRequest(uint64 requestId) external view returns (ZKPRequest memory);
-
- /**
- * @dev Get the ZKP request count.
- * @return ZKP request count.
- */
- function getZKPRequestsCount() external view returns (uint256);
-
- /**
- * @dev Check if the requestId exists.
- * @param requestId Request id of the ZKP request.
- * @return True if the requestId exists.
- */
- function requestIdExists(uint64 requestId) external view returns (bool);
-
- /**
- * @dev Get the ZKP requests.
- * @param startIndex Start index of the ZKP requests.
- * @param length Length of the ZKP requests.
- * @return Array of the ZKP requests.
- */
- function getZKPRequests(
- uint256 startIndex,
- uint256 length
- ) external view returns (ZKPRequest[] memory);
-
- /**
- * @dev Get if proof is verified for the sender and ZKP request with requestId.
- * @param sender Sender of the proof.
- * @param requestId Request id of the ZKP Request to verify.
- * @return True if proof is verified for the sender and request id.
- */
- function isProofVerified(address sender, uint64 requestId) external view returns (bool);
-
- /**
- * @dev Get the proof status for the sender and ZKP request with requestId.
- * @param sender Sender of the proof.
- * @param requestId Request id of the proof.
- * @return Proof status.
- */
- function getProofStatus(
- address sender,
- uint64 requestId
- ) external view returns (ProofStatus memory);
-
- /**
- * @dev Get the proof storage field for the user, requestId and key.
- * @param user User address.
- * @param requestId Request id of the proof.
- * @param key Key of the proof storage field.
- * @return Proof storage field.
- */
- function getProofStorageField(
- address user,
- uint64 requestId,
- string memory key
- ) external view returns (uint256);
-}
diff --git a/contracts/lib/ArrayUtils.sol b/contracts/lib/ArrayUtils.sol
index cb148fbb..60c6802b 100644
--- a/contracts/lib/ArrayUtils.sol
+++ b/contracts/lib/ArrayUtils.sol
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
+error LenghtShouldBeGreaterThanZero();
+error LengthLimitExceeded(uint256 limit);
+error StartIndexOutOfBounds(uint256 arrLength);
+
/// @title A common functions for arrays.
library ArrayUtils {
/**
@@ -17,9 +21,15 @@ library ArrayUtils {
uint256 length,
uint256 limit
) internal pure returns (uint256, uint256) {
- require(length > 0, "Length should be greater than 0");
- require(length <= limit, "Length limit exceeded");
- require(start < arrLength, "Start index out of bounds");
+ if (length == 0) {
+ revert LenghtShouldBeGreaterThanZero();
+ }
+ if (length > limit) {
+ revert LengthLimitExceeded(limit);
+ }
+ if (start >= arrLength) {
+ revert StartIndexOutOfBounds(arrLength);
+ }
uint256 end = start + length;
if (end > arrLength) {
diff --git a/contracts/lib/ClaimBuilder.sol b/contracts/lib/ClaimBuilder.sol
index bf8f5d31..bbb42773 100644
--- a/contracts/lib/ClaimBuilder.sol
+++ b/contracts/lib/ClaimBuilder.sol
@@ -3,6 +3,15 @@ pragma solidity 0.8.27;
import {PrimitiveTypeUtils} from "../lib/PrimitiveTypeUtils.sol";
+error IdShouldBeEmpty();
+error IdShouldBeNotEmpty();
+error InvalidIdPosition();
+error RevocationNonceShouldBeZeroForNonExpirableClaim();
+error ExpirationDateShouldBeZeroForNonExpirableClaim();
+error VersionShouldBeZeroForNonUpdatableClaim();
+error DataSlotsShouldBeEmpty();
+error MerklizedRootShouldBeZeroForNonMerklizedClaim();
+
library ClaimBuilder {
// ID_POSITION_NONE means ID value not located in claim.
uint8 public constant ID_POSITION_NONE = 0;
@@ -50,6 +59,8 @@ library ClaimBuilder {
uint256 valueDataSlotB;
}
+ /* solhint-disable code-complexity */
+
// RULE: each uint we convert to bytes has to be reversed (in go Little ending, solidity - big ending).
//
// Final result reverted bytes to get valid uint256
@@ -72,56 +83,64 @@ library ClaimBuilder {
// ID
if (c.idPosition == ID_POSITION_NONE) {
- require(c.id == 0, "id should be empty");
+ if (c.id != 0) {
+ revert IdShouldBeEmpty();
+ }
} else if (c.idPosition == ID_POSITION_INDEX) {
- require(c.id != 0, "id should be not empty");
+ if (c.id == 0) {
+ revert IdShouldBeNotEmpty();
+ }
flags |= SUBJECT_FLAG_OTHER_IDEN_INDEX;
claim[1] = c.id;
} else if (c.idPosition == ID_POSITION_VALUE) {
- require(c.id != 0, "id should be not empty");
+ if (c.id == 0) {
+ revert IdShouldBeNotEmpty();
+ }
flags |= SUBJECT_FLAG_OTHER_IDEN_VALUE;
claim[5] = c.id;
} else {
- require(false, "invalid id position");
+ revert InvalidIdPosition();
}
// Expirable
if (c.expirable) {
flags |= EXPIRABLE_FLAG_YES;
- } else {
- require(c.expirationDate == 0, "expirationDate should be 0 for non expirable claim");
+ } else if (c.expirationDate != 0) {
+ revert ExpirationDateShouldBeZeroForNonExpirableClaim();
}
// Updatable
if (c.updatable) {
flags |= UPDATABLE_FLAG_YES;
- } else {
- require(c.version == 0, "version should be 0 for non updatable claim");
+ } else if (c.version != 0) {
+ revert VersionShouldBeZeroForNonUpdatableClaim();
}
// Merklized Root
if (c.merklizedRootPosition == MERKLIZED_ROOT_POSITION_INDEX) {
- require(
- c.indexDataSlotA == 0 &&
- c.indexDataSlotB == 0 &&
- c.valueDataSlotA == 0 &&
- c.indexDataSlotB == 0,
- "data slots should be empty"
- );
+ if (
+ c.indexDataSlotA != 0 ||
+ c.indexDataSlotB != 0 ||
+ c.valueDataSlotA != 0 ||
+ c.valueDataSlotB != 0
+ ) {
+ revert DataSlotsShouldBeEmpty();
+ }
flags |= MERKLIZED_FLAG_INDEX;
claim[2] = c.merklizedRoot;
} else if (c.merklizedRootPosition == MERKLIZED_ROOT_POSITION_VALUE) {
- require(
- c.indexDataSlotA == 0 &&
- c.indexDataSlotB == 0 &&
- c.valueDataSlotA == 0 &&
- c.indexDataSlotB == 0,
- "data slots should be empty"
- );
+ if (
+ c.indexDataSlotA != 0 ||
+ c.indexDataSlotB != 0 ||
+ c.valueDataSlotA != 0 ||
+ c.valueDataSlotB != 0
+ ) {
+ revert DataSlotsShouldBeEmpty();
+ }
flags |= MERKLIZED_FLAG_VALUE;
claim[6] = c.merklizedRoot;
- } else {
- require(c.merklizedRoot == 0, "merklizedRoot should be 0 for non merklized claim");
+ } else if (c.merklizedRoot != 0) {
+ revert MerklizedRootShouldBeZeroForNonMerklizedClaim();
}
bytes memory claim0 = PrimitiveTypeUtils.concat(
@@ -153,4 +172,5 @@ library ClaimBuilder {
return claim;
}
+ /* solhint-enable code-complexity */
}
diff --git a/contracts/lib/GenesisUtils.sol b/contracts/lib/GenesisUtils.sol
index 8be58af7..888dc0f7 100644
--- a/contracts/lib/GenesisUtils.sol
+++ b/contracts/lib/GenesisUtils.sol
@@ -3,12 +3,15 @@ pragma solidity 0.8.27;
import {PrimitiveTypeUtils} from "./PrimitiveTypeUtils.sol";
+error ChecksumLengthRequired(uint256 length);
+error IdBytesLengthRequired(uint256 length);
+
library GenesisUtils {
/**
* @dev sum
*/
function sum(bytes memory array) internal pure returns (uint16 s) {
- require(array.length == 29, "Checksum requires 29 length array");
+ if (array.length != 29) revert ChecksumLengthRequired(29);
for (uint256 i = 0; i < array.length; ++i) {
s += uint16(uint8(array[i]));
@@ -49,7 +52,7 @@ library GenesisUtils {
bytes memory checkSumBytes = abi.encodePacked(checksum);
bytes memory idBytes = PrimitiveTypeUtils.concat(beforeChecksum, checkSumBytes);
- require(idBytes.length == 31, "idBytes requires 31 length array");
+ if (idBytes.length != 31) revert IdBytesLengthRequired(31);
return PrimitiveTypeUtils.reverseUint256(PrimitiveTypeUtils.padRightToUint256(idBytes));
}
diff --git a/contracts/lib/IdentityBase.sol b/contracts/lib/IdentityBase.sol
index 0ba9527f..3c5c8887 100644
--- a/contracts/lib/IdentityBase.sol
+++ b/contracts/lib/IdentityBase.sol
@@ -7,6 +7,8 @@ import {IdentityLib} from "../lib/IdentityLib.sol";
import {SmtLib} from "../lib/SmtLib.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+error IdentityIdMismatch();
+
// /**
// * @dev Contract managing onchain identity
// */
@@ -20,11 +22,13 @@ abstract contract IdentityBase is IIdentifiable, IOnchainCredentialStatusResolve
// keccak256(abi.encode(uint256(keccak256("iden3.storage.IdentityBase")) - 1))
// & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant IdentityBaseStorageLocation =
0x3018a310c36c4f8228f09bf3b1822685cf0971daa8265a58ca807c4a4daba400;
/// @dev Get the main storage using assembly to ensure specific storage location
function _getIdentityBaseStorage() internal pure returns (IdentityBaseStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := IdentityBaseStorageLocation
}
@@ -262,7 +266,9 @@ abstract contract IdentityBase is IIdentifiable, IOnchainCredentialStatusResolve
uint256 state,
uint64 nonce
) public view returns (CredentialStatus memory) {
- require(id == _getIdentityBaseStorage().identity.id, "Identity id mismatch");
+ if (id != _getIdentityBaseStorage().identity.id) {
+ revert IdentityIdMismatch();
+ }
IdentityLib.Roots memory historicalStates = _getIdentityBaseStorage()
.identity
.getRootsByState(state);
diff --git a/contracts/lib/IdentityLib.sol b/contracts/lib/IdentityLib.sol
index 1c4a2180..43774c1b 100644
--- a/contracts/lib/IdentityLib.sol
+++ b/contracts/lib/IdentityLib.sol
@@ -6,6 +6,12 @@ import {SmtLib} from "../lib/SmtLib.sol";
import {PoseidonUnit3L, PoseidonUnit4L} from "../lib/Poseidon.sol";
import {GenesisUtils} from "../lib/GenesisUtils.sol";
+error SMTDepthIsGreaterThanMaxAllowed();
+error IdTypeNotSupported();
+error IdentityTreesHaventChanged();
+error RootsForThisStateDoesntExist();
+error RootsForThisStateAlreadyExist();
+
// /**
// * @dev Contract managing onchain identity
// */
@@ -81,9 +87,13 @@ library IdentityLib {
uint256 depth,
bytes2 idType
) external {
- require(depth <= IDENTITY_MAX_SMT_DEPTH, "SMT depth is greater than max allowed depth");
+ if (depth > IDENTITY_MAX_SMT_DEPTH) {
+ revert SMTDepthIsGreaterThanMaxAllowed();
+ }
self.stateContract = IState(_stateContractAddr);
- require(self.stateContract.isIdTypeSupported(idType), "id type is not supported");
+ if (!self.stateContract.isIdTypeSupported(idType)) {
+ revert IdTypeNotSupported();
+ }
self.isOldStateGenesis = true;
self.trees.claimsTree.initialize(depth);
self.trees.revocationsTree.initialize(depth);
@@ -133,12 +143,13 @@ library IdentityLib {
uint256 currentRevocationsTreeRoot = self.trees.revocationsTree.getRoot();
uint256 currentRootsTreeRoot = self.trees.rootsTree.getRoot();
- require(
- (self.latestPublishedTreeRoots.claimsRoot != currentClaimsTreeRoot) ||
- (self.latestPublishedTreeRoots.revocationsRoot != currentRevocationsTreeRoot) ||
- (self.latestPublishedTreeRoots.rootsRoot != currentRootsTreeRoot),
- "Identity trees haven't changed"
- );
+ if (
+ (self.latestPublishedTreeRoots.claimsRoot == currentClaimsTreeRoot) &&
+ (self.latestPublishedTreeRoots.revocationsRoot == currentRevocationsTreeRoot) &&
+ (self.latestPublishedTreeRoots.rootsRoot == currentRootsTreeRoot)
+ ) {
+ revert IdentityTreesHaventChanged();
+ }
// if claimsTreeRoot changed, then add it to rootsTree
if (self.latestPublishedTreeRoots.claimsRoot != currentClaimsTreeRoot) {
@@ -384,22 +395,6 @@ library IdentityLib {
return self.trees.rootsTree.getRoot();
}
- /**
- * @dev write roots to history by state
- * @param self identity
- * @param state identity state
- * @param roots set of roots
- */
- function writeHistory(Data storage self, uint256 state, Roots memory roots) internal {
- require(
- self.rootsByState[state].claimsRoot == 0 &&
- self.rootsByState[state].revocationsRoot == 0 &&
- self.rootsByState[state].rootsRoot == 0,
- "Roots for this state already exist"
- );
- self.rootsByState[state] = roots;
- }
-
/**
* @dev returns historical claimsTree roots, revocationsTree roots, rootsTree roots
* by state
@@ -410,12 +405,30 @@ library IdentityLib {
Data storage self,
uint256 state
) external view returns (Roots memory) {
- require(
- self.rootsByState[state].claimsRoot != 0 ||
- self.rootsByState[state].revocationsRoot != 0 ||
- self.rootsByState[state].rootsRoot != 0,
- "Roots for this state doesn't exist"
- );
+ if (
+ self.rootsByState[state].claimsRoot == 0 &&
+ self.rootsByState[state].revocationsRoot == 0 &&
+ self.rootsByState[state].rootsRoot == 0
+ ) {
+ revert RootsForThisStateDoesntExist();
+ }
return self.rootsByState[state];
}
+
+ /**
+ * @dev write roots to history by state
+ * @param self identity
+ * @param state identity state
+ * @param roots set of roots
+ */
+ function writeHistory(Data storage self, uint256 state, Roots memory roots) internal {
+ if (
+ self.rootsByState[state].claimsRoot != 0 ||
+ self.rootsByState[state].revocationsRoot != 0 ||
+ self.rootsByState[state].rootsRoot != 0
+ ) {
+ revert RootsForThisStateAlreadyExist();
+ }
+ self.rootsByState[state] = roots;
+ }
}
diff --git a/contracts/lib/Poseidon.sol b/contracts/lib/Poseidon.sol
index c4b8f83c..2d26b964 100644
--- a/contracts/lib/Poseidon.sol
+++ b/contracts/lib/Poseidon.sol
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
+/* solhint-disable no-empty-blocks */
library PoseidonUnit1L {
function poseidon(uint256[1] calldata) public pure returns (uint256) {}
}
@@ -24,6 +25,7 @@ library PoseidonUnit5L {
library PoseidonUnit6L {
function poseidon(uint256[6] calldata) public pure returns (uint256) {}
}
+/* solhint-enable no-empty-blocks */
library SpongePoseidon {
uint32 internal constant BATCH_SIZE = 6;
diff --git a/contracts/lib/PrimitiveTypeUtils.sol b/contracts/lib/PrimitiveTypeUtils.sol
index 929077b9..f5c543a4 100644
--- a/contracts/lib/PrimitiveTypeUtils.sol
+++ b/contracts/lib/PrimitiveTypeUtils.sol
@@ -3,12 +3,15 @@ pragma solidity 0.8.27;
import {BytesLib} from "solidity-bytes-utils/contracts/BytesLib.sol";
+error GivenInputNotAnAddressRepresentation(uint256 input);
+
library PrimitiveTypeUtils {
/**
* @dev uint256ToBytes
*/
function uint256ToBytes(uint256 x) internal pure returns (bytes memory b) {
b = new bytes(32);
+ // solhint-disable-next-line no-inline-assembly
assembly {
mstore(add(b, 32), x)
}
@@ -90,6 +93,7 @@ library PrimitiveTypeUtils {
* @dev bytesToAddress
*/
function bytesToAddress(bytes memory bys) internal pure returns (address addr) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
addr := mload(add(bys, 20))
}
@@ -135,10 +139,9 @@ library PrimitiveTypeUtils {
* @return address representation of uint256 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
*/
function uint256ToAddress(uint256 input) internal pure returns (address) {
- require(
- input == uint256(uint160(input)),
- "given input is not a representation of address, 12 most significant bytes should be zero"
- );
+ if (input != uint256(uint160(input))) {
+ revert GivenInputNotAnAddressRepresentation(input);
+ }
return address(uint160(input));
}
@@ -166,10 +169,9 @@ library PrimitiveTypeUtils {
* @return address - 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
*/
function uint256LEToAddress(uint256 input) internal pure returns (address) {
- require(
- input == uint256(uint160(input)),
- "given uint256 is not a representation of an address, 12 most significant bytes should be zero"
- );
+ if (input != uint256(uint160(input))) {
+ revert GivenInputNotAnAddressRepresentation(input);
+ }
return bytesToAddress(uint256ToBytes(reverseUint256(input)));
}
diff --git a/contracts/lib/SmtLib.sol b/contracts/lib/SmtLib.sol
index 809fb86c..048b2af1 100644
--- a/contracts/lib/SmtLib.sol
+++ b/contracts/lib/SmtLib.sol
@@ -4,6 +4,18 @@ pragma solidity 0.8.27;
import {PoseidonUnit2L, PoseidonUnit3L} from "./Poseidon.sol";
import {ArrayUtils} from "./ArrayUtils.sol";
+error RootDoesNotExist();
+error InvalidNodeType();
+error NoFutureTimestampsAllowed();
+error NoFutureBlocksAllowed();
+error MaxDepthMustBeGreaterThanZero();
+error MaxDepthCanOnlyBeIncreased();
+error MaxDepthIsGreaterThanHardCap();
+error SmtAlreadyInitialized();
+error SmtNotInitialized();
+error MaxDepthReached();
+error InvalidSearchType();
+
/// @title A sparse merkle tree implementation, which keeps tree history.
// Note that this SMT implementation can manage duplicated roots in the history,
// which may happen when some leaf change its value and then changes it back to the original value.
@@ -132,7 +144,9 @@ library SmtLib {
* @param root SMT root.
*/
modifier onlyExistingRoot(Data storage self, uint256 root) {
- require(rootExists(self, root), "Root does not exist");
+ if (!rootExists(self, root)) {
+ revert RootDoesNotExist();
+ }
_;
}
@@ -264,7 +278,7 @@ library SmtLib {
proof.siblings[i] = node.childRight;
}
} else {
- revert("Invalid node type");
+ revert InvalidNodeType();
}
}
return proof;
@@ -313,7 +327,9 @@ library SmtLib {
Data storage self,
uint256 timestamp
) public view returns (RootEntryInfo memory) {
- require(timestamp <= block.timestamp, "No future timestamps allowed");
+ if (timestamp > block.timestamp) {
+ revert NoFutureTimestampsAllowed();
+ }
return
_getRootInfoByTimestampOrBlock(
@@ -332,7 +348,9 @@ library SmtLib {
Data storage self,
uint256 blockN
) public view returns (RootEntryInfo memory) {
- require(blockN <= block.number, "No future blocks allowed");
+ if (blockN > block.number) {
+ revert NoFutureBlocksAllowed();
+ }
return _getRootInfoByTimestampOrBlock(self, blockN, BinarySearchSmtRoots.SearchType.BLOCK);
}
@@ -408,9 +426,15 @@ library SmtLib {
* @param maxDepth max depth
*/
function setMaxDepth(Data storage self, uint256 maxDepth) public {
- require(maxDepth > 0, "Max depth must be greater than zero");
- require(maxDepth > self.maxDepth, "Max depth can only be increased");
- require(maxDepth <= MAX_DEPTH_HARD_CAP, "Max depth is greater than hard cap");
+ if (maxDepth == 0) {
+ revert MaxDepthMustBeGreaterThanZero();
+ }
+ if (maxDepth <= self.maxDepth) {
+ revert MaxDepthCanOnlyBeIncreased();
+ }
+ if (maxDepth > MAX_DEPTH_HARD_CAP) {
+ revert MaxDepthIsGreaterThanHardCap();
+ }
self.maxDepth = maxDepth;
}
@@ -427,14 +451,18 @@ library SmtLib {
* @param maxDepth Max depth of the SMT.
*/
function initialize(Data storage self, uint256 maxDepth) external {
- require(!isInitialized(self), "Smt is already initialized");
+ if (isInitialized(self)) {
+ revert SmtAlreadyInitialized();
+ }
setMaxDepth(self, maxDepth);
_addEntry(self, 0, 0, 0);
self.initialized = true;
}
modifier onlyInitialized(Data storage self) {
- require(isInitialized(self), "Smt is not initialized");
+ if (!isInitialized(self)) {
+ revert SmtNotInitialized();
+ }
_;
}
@@ -449,7 +477,7 @@ library SmtLib {
uint256 depth
) internal returns (uint256) {
if (depth > self.maxDepth) {
- revert("Max depth reached");
+ revert MaxDepthReached();
}
Node memory node = self.nodes[nodeHash];
@@ -502,7 +530,7 @@ library SmtLib {
// no reason to continue if we are at max possible depth
// as, anyway, we exceed the depth going down the tree
if (depth >= self.maxDepth) {
- revert("Max depth reached");
+ revert MaxDepthReached();
}
Node memory newNodeMiddle;
@@ -696,7 +724,7 @@ library BinarySearchSmtRoots {
} else if (st == SearchType.TIMESTAMP) {
return rti.createdAtTimestamp;
} else {
- revert("Invalid search type");
+ revert InvalidSearchType();
}
}
}
diff --git a/contracts/lib/StateCrossChainLib.sol b/contracts/lib/StateCrossChainLib.sol
deleted file mode 100644
index 4292ab0f..00000000
--- a/contracts/lib/StateCrossChainLib.sol
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {IState} from "../interfaces/IState.sol";
-import {State} from "../state/State.sol";
-
-/**
- * @title StateCrossChainLib
- * @dev The library provides functions to process cross chain proofs.
- */
-library StateCrossChainLib {
- bytes32 private constant GLOBAL_STATE_PROOF_TYPE = keccak256(bytes("globalStateProof"));
-
- bytes32 private constant STATE_PROOF_TYPE = keccak256(bytes("stateProof"));
-
- /**
- * @dev Processes cross chain proofs.
- * @param self The StateCrossChainStorage storage pointer.
- * @param crossChainProofs The cross chain proofs.
- */
- function processCrossChainProofs(
- State.StateCrossChainStorage storage self,
- bytes calldata crossChainProofs
- ) public {
- if (crossChainProofs.length == 0) {
- return;
- }
-
- IState.CrossChainProof[] memory proofs = abi.decode(
- crossChainProofs,
- (IState.CrossChainProof[])
- );
-
- for (uint256 i = 0; i < proofs.length; i++) {
- if (keccak256(bytes(proofs[i].proofType)) == GLOBAL_STATE_PROOF_TYPE) {
- IState.GlobalStateProcessResult memory gsp = self
- ._crossChainProofValidator
- .processGlobalStateProof(proofs[i].proof);
- self._rootToGistRootReplacedAt[gsp.idType][gsp.root] = gsp.replacedAtTimestamp;
- } else if (keccak256(bytes(proofs[i].proofType)) == STATE_PROOF_TYPE) {
- IState.IdentityStateProcessResult memory isu = self
- ._crossChainProofValidator
- .processIdentityStateProof(proofs[i].proof);
- self._idToStateReplacedAt[isu.id][isu.state] = isu.replacedAtTimestamp;
- } else {
- revert("Unknown proof type");
- }
- }
- }
-}
diff --git a/contracts/lib/StateLib.sol b/contracts/lib/StateLib.sol
index cf64be95..6434df99 100644
--- a/contracts/lib/StateLib.sol
+++ b/contracts/lib/StateLib.sol
@@ -3,6 +3,10 @@ pragma solidity 0.8.27;
import {ArrayUtils} from "../lib/ArrayUtils.sol";
+error IdentityDoesNotExist();
+error StateDoesNotExist();
+error IdentityAlreadyExists();
+
/// @title Library for state data management.
// It's purpose is to keep records of identity states along with their metadata and history.
library StateLib {
@@ -91,7 +95,9 @@ library StateLib {
* @param id Identity
*/
modifier onlyExistingId(Data storage self, uint256 id) {
- require(idExists(self, id), "Identity does not exist");
+ if (!idExists(self, id)) {
+ revert IdentityDoesNotExist();
+ }
_;
}
@@ -101,7 +107,9 @@ library StateLib {
* @param state State
*/
modifier onlyExistingState(Data storage self, uint256 id, uint256 state) {
- require(stateExists(self, id, state), "State does not exist");
+ if (!stateExists(self, id, state)) {
+ revert StateDoesNotExist();
+ }
_;
}
@@ -120,10 +128,9 @@ library StateLib {
* @param state State
*/
function addGenesisState(Data storage self, uint256 id, uint256 state) external {
- require(
- !idExists(self, id),
- "Zero timestamp and block should be only in the first identity state"
- );
+ if (idExists(self, id)) {
+ revert IdentityAlreadyExists();
+ }
_addState(self, id, state, 0, 0);
}
diff --git a/contracts/lib/VerifierLib.sol b/contracts/lib/VerifierLib.sol
deleted file mode 100644
index a47ad53d..00000000
--- a/contracts/lib/VerifierLib.sol
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {ZKPVerifierBase} from "../verifiers/ZKPVerifierBase.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-
-/**
- * @title VerifierLib
- * @dev A library for writing proof results.
- */
-library VerifierLib {
- /// @dev Struct to store ZKP proof and associated data
- struct Proof {
- bool isVerified;
- mapping(string key => uint256 inputValue) storageFields;
- string validatorVersion;
- uint256 blockNumber;
- uint256 blockTimestamp;
- mapping(string key => bytes) metadata;
- }
-
- /**
- * @dev Writes proof results.
- * @param self The ZKPVerifierStorage storage pointer
- * @param sender The sender of the proof
- * @param requestId The request ID
- * @param keyToInpIdxs The array of key to public inputs index mapping
- * @param inputs The array of public inputs
- */
- function writeProofResults(
- ZKPVerifierBase.ZKPVerifierStorage storage self,
- address sender,
- uint64 requestId,
- ICircuitValidator.KeyToInputIndex[] memory keyToInpIdxs,
- uint256[] memory inputs
- ) public {
- Proof storage proof = self._proofs[sender][requestId];
- for (uint256 i = 0; i < keyToInpIdxs.length; i++) {
- proof.storageFields[keyToInpIdxs[i].key] = inputs[keyToInpIdxs[i].inputIndex];
- }
-
- proof.isVerified = true;
- proof.validatorVersion = self._requests[requestId].validator.version();
- proof.blockNumber = block.number;
- proof.blockTimestamp = block.timestamp;
- }
-
- /**
- * @dev Writes proof results.
- * @param self The ZKPVerifierStorage storage pointer
- * @param sender The sender of the proof
- * @param requestId The request ID of the proof
- * @param signals The array of public signals of the proof
- */
- function writeProofResultsV2(
- ZKPVerifierBase.ZKPVerifierStorage storage self,
- address sender,
- uint64 requestId,
- ICircuitValidator.Signal[] memory signals
- ) public {
- Proof storage proof = self._proofs[sender][requestId];
- for (uint256 i = 0; i < signals.length; i++) {
- proof.storageFields[signals[i].name] = signals[i].value;
- }
-
- proof.isVerified = true;
- proof.validatorVersion = self._requests[requestId].validator.version();
- proof.blockNumber = block.number;
- proof.blockTimestamp = block.timestamp;
- }
-}
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol
index c97d1e64..89d092f8 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol
@@ -1,32 +1,12 @@
-//
-// Copyright 2017 Christian Reitwiessner
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom
-// the Software is furnished to do so, subject to the following conditions:
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-// 2019 OKIMS
-// ported to solidity 0.6
-// fixed linter warnings
-// added requiere error messages
-//
-//
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
import {Groth16VerifierAuthV2} from "./Groth16VerifierAuthV2.sol";
-import {IVerifier} from "../../interfaces/IVerifier.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
-contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IVerifier {
+error ExpectedArrayLenght(uint256 expected, uint256 actual);
+
+contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IGroth16Verifier {
/**
* @dev Number of public signals for atomic mtp circuit
*/
@@ -37,21 +17,23 @@ contract Groth16VerifierAuthV2Wrapper is Groth16VerifierAuthV2, IVerifier {
* @param a πa element of the groth16 proof.
* @param b πb element of the groth16 proof.
* @param c πc element of the groth16 proof.
- * @param input Public inputs of the circuit.
+ * @param signals Public inputs and outputs of the circuit.
* @return r true if the proof is valid.
*/
function verify(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
- uint256[] calldata input
+ uint256[] calldata signals
) public view returns (bool r) {
uint[PUBSIGNALS_LENGTH] memory pubSignals;
- require(input.length == PUBSIGNALS_LENGTH, "expected array length is 3");
+ if (signals.length != PUBSIGNALS_LENGTH) {
+ revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length);
+ }
for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) {
- pubSignals[i] = input[i];
+ pubSignals[i] = signals[i];
}
return this.verifyProof(a, b, c, pubSignals);
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol
new file mode 100644
index 00000000..e2dba6a7
--- /dev/null
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10.sol
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-3.0
+/*
+ Copyright 2021 0KIMS association.
+
+ This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
+
+ snarkJS is a free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ snarkJS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with snarkJS. If not, see .
+*/
+
+pragma solidity >=0.8.4 <0.9.0;
+
+contract Groth16VerifierLinkedMultiQuery10 {
+ // Scalar field size
+ uint256 constant r =
+ 21888242871839275222246405745257275088548364400416034343698204186575808495617;
+ // Base field size
+ uint256 constant q =
+ 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+
+ // Verification Key data
+ uint256 constant alphax =
+ 20491192805390485299153009773594534940189261866228447918068658471970481763042;
+ uint256 constant alphay =
+ 9383485363053290200918347156157836566562967994039712273449902621266178545958;
+ uint256 constant betax1 =
+ 4252822878758300859123897981450591353533073413197771768651442665752259397132;
+ uint256 constant betax2 =
+ 6375614351688725206403948262868962793625744043794305715222011528459656738731;
+ uint256 constant betay1 =
+ 21847035105528745403288232691147584728191162732299865338377159692350059136679;
+ uint256 constant betay2 =
+ 10505242626370262277552901082094356697409835680220590971873171140371331206856;
+ uint256 constant gammax1 =
+ 11559732032986387107991004021392285783925812861821192530917403151452391805634;
+ uint256 constant gammax2 =
+ 10857046999023057135944570762232829481370756359578518086990519993285655852781;
+ uint256 constant gammay1 =
+ 4082367875863433681332203403145435568316851327593401208105741076214120093531;
+ uint256 constant gammay2 =
+ 8495653923123431417604973247489272438418190587263600148770280649306958101930;
+ uint256 constant deltax1 =
+ 4767756989901781990548811495555254021246964220885607355087778530306964004185;
+ uint256 constant deltax2 =
+ 13574129252125202270158307841999632289188481698271261939235393046564697547323;
+ uint256 constant deltay1 =
+ 11765493019200775638510616767809212227835759957683292721283970143875449362878;
+ uint256 constant deltay2 =
+ 20994491963918641855107870498261517959074286551785099903933200630273567734342;
+
+ uint256 constant IC0x =
+ 12449886944142661472251059230965936349361235560943050777171852750972268056009;
+ uint256 constant IC0y =
+ 5508789765348348011558576931625983265119736287691184278767289209256184182152;
+
+ uint256 constant IC1x =
+ 11354840822823409678846005531170154810223893374328536931571598076429246168962;
+ uint256 constant IC1y =
+ 10243618321308788660349859395450060514823490518996600371300209313988271557806;
+
+ uint256 constant IC2x =
+ 7688841796121824588147585218713985820690021917094358723669767856390683928034;
+ uint256 constant IC2y =
+ 15304029843415543132293541704424359450862448668530347048215672038580045683481;
+
+ uint256 constant IC3x =
+ 15990615657429515286876718277658019436828926204319889565777537283744068146700;
+ uint256 constant IC3y =
+ 20265128390631794181627612941990068143695235211256419586038084564697570772459;
+
+ uint256 constant IC4x =
+ 16744634382041772612761056860980716914432614100602561913600347639646803828867;
+ uint256 constant IC4y =
+ 9587909504738762931618416803620503763808524690654300610728307244650105345649;
+
+ uint256 constant IC5x =
+ 14498281259442737211687928465501452644380043044531604747511002130574576040500;
+ uint256 constant IC5y =
+ 15178480169883279183083105005735414370343021495727319036601387862295433592890;
+
+ uint256 constant IC6x =
+ 181238700928172282344680236185737466543303371505875966182504955165221550787;
+ uint256 constant IC6y =
+ 21622111637396317730948136644302630767714713068723532481132071344883159478317;
+
+ uint256 constant IC7x =
+ 8334117149439267478794081283986502998659211363774660979410854038645857015106;
+ uint256 constant IC7y =
+ 3525586056545466424550069059261704178677653029630068235241952571550605630653;
+
+ uint256 constant IC8x =
+ 16676389244152071637547895889424069474191043909363062157910970100503924284824;
+ uint256 constant IC8y =
+ 6293986690744783536251466348123663316687870380690807594123241364218706730246;
+
+ uint256 constant IC9x =
+ 12745671365224662776594194440156600675329812876347548121369698185420569095439;
+ uint256 constant IC9y =
+ 11273088596548493444123027464142605382437970433270231501917065525393005894036;
+
+ uint256 constant IC10x =
+ 7732485931307476787148144929824683305147104743163709148772223736952704050567;
+ uint256 constant IC10y =
+ 14991775678419768558530779568394256066852823412993601432448554479361118463299;
+
+ uint256 constant IC11x =
+ 13954475229491875183185146721491133006576631796979640931033593718558384269206;
+ uint256 constant IC11y =
+ 20143678799568261548345812147552378448221261337943896478291695109662795302646;
+
+ uint256 constant IC12x =
+ 1588536655220107824895151554872386730171641945783207210783928981583577082720;
+ uint256 constant IC12y =
+ 13908530648827733472139197820866316501402019214593222521521102979981263265396;
+
+ uint256 constant IC13x =
+ 12678767645933368864421466910761496605084347784517452696623065956846509548782;
+ uint256 constant IC13y =
+ 21381570127686765465000169852593021495333227087229864265691446720659272361152;
+
+ uint256 constant IC14x =
+ 17922265673268483320025865036589139344955822363275373430719168065953761526520;
+ uint256 constant IC14y =
+ 9242324301503892823219332201525279187476010610994752688104429744801597668285;
+
+ uint256 constant IC15x =
+ 19367539127735956732148435844861647320899694335953718141209016532640873590140;
+ uint256 constant IC15y =
+ 12701104584447112200166345844417732176637947754547635778619790266357846083284;
+
+ uint256 constant IC16x =
+ 14931750548482966130586321361300230947899794584196248761236252137274123990811;
+ uint256 constant IC16y =
+ 18907870831743031028168656813690968152456035625888662633278498386598866738708;
+
+ uint256 constant IC17x =
+ 21078326524345796712273699205406122410330437647297400186087773951320605894880;
+ uint256 constant IC17y =
+ 6471701510558433137588469036231611931381433511837825536013781894924055589201;
+
+ uint256 constant IC18x =
+ 11616604898621091236885062107603844843578912315924240360909152763967953411071;
+ uint256 constant IC18y =
+ 15567597962932438133376009485279673723080736998791665521084155531250437535832;
+
+ uint256 constant IC19x =
+ 16814378820042549514945932350142180953549065761435730844701764513083012014298;
+ uint256 constant IC19y =
+ 9577851565990440995137571478255586121135591079059958395444685890902579770570;
+
+ uint256 constant IC20x =
+ 1093702848180480792269642835164492672016092778979951861285096707497432193760;
+ uint256 constant IC20y =
+ 4063334433551442475817332481927046015343707417264061346417488535608502495218;
+
+ uint256 constant IC21x =
+ 7214731470556020664921656204545020072837783006969685612760693537299230135333;
+ uint256 constant IC21y =
+ 8891562787830667150144624187125115054175583159717508708300614390764766181778;
+
+ uint256 constant IC22x =
+ 4041991063957841891847968885939221032895793579852508335899469034278358488695;
+ uint256 constant IC22y =
+ 12929528695870206289536816082066059156374288392417066761527212742555189041207;
+
+ // Memory data
+ uint16 constant pVk = 0;
+ uint16 constant pPairing = 128;
+
+ uint16 constant pLastMem = 896;
+
+ function verifyProof(
+ uint[2] calldata _pA,
+ uint[2][2] calldata _pB,
+ uint[2] calldata _pC,
+ uint[22] calldata _pubSignals
+ ) public view returns (bool) {
+ assembly {
+ function checkField(v) {
+ if iszero(lt(v, r)) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ // G1 function to multiply a G1 value(x,y) to value in an address
+ function g1_mulAccC(pR, x, y, s) {
+ let success
+ let mIn := mload(0x40)
+ mstore(mIn, x)
+ mstore(add(mIn, 32), y)
+ mstore(add(mIn, 64), s)
+
+ success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+
+ mstore(add(mIn, 64), mload(pR))
+ mstore(add(mIn, 96), mload(add(pR, 32)))
+
+ success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
+
+ if iszero(success) {
+ mstore(0, 0)
+ return(0, 0x20)
+ }
+ }
+
+ function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
+ let _pPairing := add(pMem, pPairing)
+ let _pVk := add(pMem, pVk)
+
+ mstore(_pVk, IC0x)
+ mstore(add(_pVk, 32), IC0y)
+
+ // Compute the linear combination vk_x
+
+ g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
+
+ g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
+
+ g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
+
+ g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
+
+ g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128)))
+
+ g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160)))
+
+ g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192)))
+
+ g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224)))
+
+ g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256)))
+
+ g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288)))
+
+ g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320)))
+
+ g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352)))
+
+ g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384)))
+
+ g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416)))
+
+ g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448)))
+
+ g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480)))
+
+ g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512)))
+
+ g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544)))
+
+ g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576)))
+
+ g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608)))
+
+ g1_mulAccC(_pVk, IC21x, IC21y, calldataload(add(pubSignals, 640)))
+
+ g1_mulAccC(_pVk, IC22x, IC22y, calldataload(add(pubSignals, 672)))
+
+ // -A
+ mstore(_pPairing, calldataload(pA))
+ mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
+
+ // B
+ mstore(add(_pPairing, 64), calldataload(pB))
+ mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
+ mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
+ mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
+
+ // alpha1
+ mstore(add(_pPairing, 192), alphax)
+ mstore(add(_pPairing, 224), alphay)
+
+ // beta2
+ mstore(add(_pPairing, 256), betax1)
+ mstore(add(_pPairing, 288), betax2)
+ mstore(add(_pPairing, 320), betay1)
+ mstore(add(_pPairing, 352), betay2)
+
+ // vk_x
+ mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
+ mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
+
+ // gamma2
+ mstore(add(_pPairing, 448), gammax1)
+ mstore(add(_pPairing, 480), gammax2)
+ mstore(add(_pPairing, 512), gammay1)
+ mstore(add(_pPairing, 544), gammay2)
+
+ // C
+ mstore(add(_pPairing, 576), calldataload(pC))
+ mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
+
+ // delta2
+ mstore(add(_pPairing, 640), deltax1)
+ mstore(add(_pPairing, 672), deltax2)
+ mstore(add(_pPairing, 704), deltay1)
+ mstore(add(_pPairing, 736), deltay2)
+
+ let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
+
+ isOk := and(success, mload(_pPairing))
+ }
+
+ let pMem := mload(0x40)
+ mstore(0x40, add(pMem, pLastMem))
+
+ // Validate that all evaluations ∈ F
+
+ checkField(calldataload(add(_pubSignals, 0)))
+
+ checkField(calldataload(add(_pubSignals, 32)))
+
+ checkField(calldataload(add(_pubSignals, 64)))
+
+ checkField(calldataload(add(_pubSignals, 96)))
+
+ checkField(calldataload(add(_pubSignals, 128)))
+
+ checkField(calldataload(add(_pubSignals, 160)))
+
+ checkField(calldataload(add(_pubSignals, 192)))
+
+ checkField(calldataload(add(_pubSignals, 224)))
+
+ checkField(calldataload(add(_pubSignals, 256)))
+
+ checkField(calldataload(add(_pubSignals, 288)))
+
+ checkField(calldataload(add(_pubSignals, 320)))
+
+ checkField(calldataload(add(_pubSignals, 352)))
+
+ checkField(calldataload(add(_pubSignals, 384)))
+
+ checkField(calldataload(add(_pubSignals, 416)))
+
+ checkField(calldataload(add(_pubSignals, 448)))
+
+ checkField(calldataload(add(_pubSignals, 480)))
+
+ checkField(calldataload(add(_pubSignals, 512)))
+
+ checkField(calldataload(add(_pubSignals, 544)))
+
+ checkField(calldataload(add(_pubSignals, 576)))
+
+ checkField(calldataload(add(_pubSignals, 608)))
+
+ checkField(calldataload(add(_pubSignals, 640)))
+
+ checkField(calldataload(add(_pubSignals, 672)))
+
+ // Validate all evaluations
+ let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
+
+ mstore(0, isValid)
+ return(0, 0x20)
+ }
+ }
+}
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol
new file mode 100644
index 00000000..0c611638
--- /dev/null
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {Groth16VerifierLinkedMultiQuery10} from "./Groth16VerifierLinkedMultiQuery10.sol";
+
+error ExpectedArrayLenght(uint256 expected, uint256 actual);
+
+contract Groth16VerifierLinkedMultiQuery10Wrapper is
+ Groth16VerifierLinkedMultiQuery10,
+ IGroth16Verifier
+{
+ /**
+ * @dev Number of public signals for atomic mtp circuit
+ */
+ uint256 constant PUBSIGNALS_LENGTH = 22;
+
+ /**
+ * @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
+ * @param a πa element of the groth16 proof.
+ * @param b πb element of the groth16 proof.
+ * @param c πc element of the groth16 proof.
+ * @param signals Public inputs and outputs of the circuit.
+ * @return r true if the proof is valid.
+ */
+ function verify(
+ uint256[2] calldata a,
+ uint256[2][2] calldata b,
+ uint256[2] calldata c,
+ uint256[] calldata signals
+ ) public view returns (bool r) {
+ uint[PUBSIGNALS_LENGTH] memory pubSignals;
+
+ if (signals.length != PUBSIGNALS_LENGTH) {
+ revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length);
+ }
+
+ for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) {
+ pubSignals[i] = signals[i];
+ }
+
+ return this.verifyProof(a, b, c, pubSignals);
+ }
+}
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol b/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol
index de520abf..5c3568f0 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierMTP.sol
@@ -18,7 +18,7 @@
along with snarkJS. If not, see .
*/
-pragma solidity >=0.7.0 <0.9.0;
+pragma solidity >=0.8.4 <0.9.0;
contract Groth16VerifierMTP {
// Scalar field size
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol
index 19b268de..8868f176 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierMTPWrapper.sol
@@ -14,34 +14,38 @@
pragma solidity 0.8.27;
import "./Groth16VerifierMTP.sol";
-import "../../interfaces/IVerifier.sol";
+import "../../interfaces/IGroth16Verifier.sol";
-contract Groth16VerifierMTPWrapper is Groth16VerifierMTP, IVerifier {
+error ExpectedArrayLenght(uint256 expected, uint256 actual);
+
+contract Groth16VerifierMTPWrapper is Groth16VerifierMTP, IGroth16Verifier {
/**
* @dev Number of public signals for atomic mtp circuit
*/
- uint constant PUBSIGNALS_LENGTH = 11;
+ uint256 constant PUBSIGNALS_LENGTH = 11;
/**
* @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
* @param a πa element of the groth16 proof.
* @param b πb element of the groth16 proof.
* @param c πc element of the groth16 proof.
- * @param input Public inputs of the circuit.
+ * @param signals Public inputs and outputs of the circuit.
* @return r true if the proof is valid.
*/
function verify(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
- uint256[] calldata input
+ uint256[] calldata signals
) public view returns (bool r) {
uint[PUBSIGNALS_LENGTH] memory pubSignals;
- require(input.length == PUBSIGNALS_LENGTH, "expected array length is 11");
+ if (signals.length != PUBSIGNALS_LENGTH) {
+ revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length);
+ }
for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) {
- pubSignals[i] = input[i];
+ pubSignals[i] = signals[i];
}
return this.verifyProof(a, b, c, pubSignals);
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol b/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol
index 36aea424..da97c6eb 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierSig.sol
@@ -18,7 +18,7 @@
along with snarkJS. If not, see .
*/
-pragma solidity >=0.7.0 <0.9.0;
+pragma solidity >=0.8.4 <0.9.0;
contract Groth16VerifierSig {
// Scalar field size
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol
index efd6665a..f65cbae7 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierSigWrapper.sol
@@ -14,35 +14,39 @@
pragma solidity 0.8.27;
import "./Groth16VerifierSig.sol";
-import "../../interfaces/IVerifier.sol";
+import "../../interfaces/IGroth16Verifier.sol";
-contract Groth16VerifierSigWrapper is Groth16VerifierSig, IVerifier {
+error ExpectedArrayLenght(uint256 expected, uint256 actual);
+
+contract Groth16VerifierSigWrapper is Groth16VerifierSig, IGroth16Verifier {
/**
* @dev Number of public signals for atomic sig circuit
*/
- uint constant PUBSIGNALS_LENGTH = 11;
+ uint256 constant PUBSIGNALS_LENGTH = 11;
/**
* @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
* @param a πa element of the groth16 proof.
* @param b πb element of the groth16 proof.
* @param c πc element of the groth16 proof.
- * @param input Public inputs of the circuit.
+ * @param signals Public inputs and outputs of the circuit.
* @return r true if the proof is valid.
*/
function verify(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
- uint256[] calldata input
+ uint256[] calldata signals
) public view returns (bool r) {
// slither-disable-next-line uninitialized-local
uint[PUBSIGNALS_LENGTH] memory pubSignals;
- require(input.length == PUBSIGNALS_LENGTH, "expected array length is 11");
+ if (signals.length != PUBSIGNALS_LENGTH) {
+ revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length);
+ }
for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) {
- pubSignals[i] = input[i];
+ pubSignals[i] = signals[i];
}
return this.verifyProof(a, b, c, pubSignals);
}
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol b/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol
index 6bfdd28a..52d567b6 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierStateTransition.sol
@@ -18,7 +18,7 @@
along with snarkJS. If not, see .
*/
-pragma solidity >=0.7.0 <0.9.0;
+pragma solidity >=0.8.4 <0.9.0;
import "../../interfaces/IStateTransitionVerifier.sol";
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol b/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol
index 1b6d8b6f..48a9571f 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierV3.sol
@@ -18,7 +18,7 @@
along with snarkJS. If not, see .
*/
-pragma solidity >=0.7.0 <0.9.0;
+pragma solidity >=0.8.4 <0.9.0;
contract Groth16VerifierV3 {
// Scalar field size
diff --git a/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol b/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol
index 9f963726..e256652b 100644
--- a/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol
+++ b/contracts/lib/groth16-verifiers/Groth16VerifierV3Wrapper.sol
@@ -14,35 +14,39 @@
pragma solidity 0.8.27;
import "./Groth16VerifierV3.sol";
-import "../../interfaces/IVerifier.sol";
+import "../../interfaces/IGroth16Verifier.sol";
-contract Groth16VerifierV3Wrapper is Groth16VerifierV3, IVerifier {
+error ExpectedArrayLenght(uint256 expected, uint256 actual);
+
+contract Groth16VerifierV3Wrapper is Groth16VerifierV3, IGroth16Verifier {
/**
* @dev Number of public signals for atomic V3 circuit
*/
- uint constant PUBSIGNALS_LENGTH = 14;
+ uint256 constant PUBSIGNALS_LENGTH = 14;
/**
* @dev Verify the circuit with the groth16 proof π=([πa]1,[πb]2,[πc]1).
* @param a πa element of the groth16 proof.
* @param b πb element of the groth16 proof.
* @param c πc element of the groth16 proof.
- * @param input Public inputs of the circuit.
+ * @param signals Public inputs and outputs of the circuit.
* @return r true if the proof is valid.
*/
function verify(
uint256[2] calldata a,
uint256[2][2] calldata b,
uint256[2] calldata c,
- uint256[] calldata input
+ uint256[] calldata signals
) public view returns (bool r) {
// slither-disable-next-line uninitialized-local
uint[PUBSIGNALS_LENGTH] memory pubSignals;
- require(input.length == PUBSIGNALS_LENGTH, "expected array length is 14");
+ if (signals.length != PUBSIGNALS_LENGTH) {
+ revert ExpectedArrayLenght(PUBSIGNALS_LENGTH, signals.length);
+ }
for (uint256 i = 0; i < PUBSIGNALS_LENGTH; i++) {
- pubSignals[i] = input[i];
+ pubSignals[i] = signals[i];
}
return this.verifyProof(a, b, c, pubSignals);
}
diff --git a/contracts/package.json b/contracts/package.json
index dfbf225c..f785351e 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,7 +1,7 @@
{
"name": "@iden3/contracts",
"description": "Smart Contract library for Solidity",
- "version": "2.5.7",
+ "version": "3.0.0",
"files": [
"**/*.sol",
"/build/contracts/*.json",
diff --git a/contracts/payment/MCPayment.sol b/contracts/payment/MCPayment.sol
index 5c079efc..2eecb127 100644
--- a/contracts/payment/MCPayment.sol
+++ b/contracts/payment/MCPayment.sol
@@ -70,10 +70,12 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable {
// keccak256(abi.encode(uint256(keccak256("iden3.storage.MCPayment")) - 1)) &
// ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant MCPaymentStorageLocation =
0x843c93f996398391e581389b674681e6ea27a4f9a96390a9d8ecb41cf0226300;
function _getMCPaymentStorage() private pure returns (MCPaymentStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := MCPaymentStorageLocation
}
@@ -222,6 +224,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable {
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
+ // solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(permitSignature, 0x20))
s := mload(add(permitSignature, 0x40))
@@ -358,7 +361,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable {
* @dev Withdraw ERC-20 balance to owner
*/
function ownerERC20Withdraw(address token) public onlyOwner {
- uint amount = IERC20(token).balanceOf(address(this));
+ uint256 amount = IERC20(token).balanceOf(address(this));
if (amount == 0) {
revert WithdrawErrorNoBalance();
}
@@ -424,7 +427,7 @@ contract MCPayment is Ownable2StepUpgradeable, EIP712Upgradeable {
_withdraw(amount, issuer);
}
- function _withdraw(uint amount, address to) internal {
+ function _withdraw(uint256 amount, address to) internal {
if (to == address(0)) {
revert WithdrawErrorInvalidAddress();
}
diff --git a/contracts/payment/VCPayment.sol b/contracts/payment/VCPayment.sol
index c645e0f3..5922f9a7 100644
--- a/contracts/payment/VCPayment.sol
+++ b/contracts/payment/VCPayment.sol
@@ -47,10 +47,12 @@ contract VCPayment is Ownable2StepUpgradeable {
// keccak256(abi.encode(uint256(keccak256("iden3.storage.VCPayment")) - 1)) &
// ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant VCPaymentStorageLocation =
0xbb49acb92ce91902600caabfefad66ed7ac2a150edbd631ab48a5501402b3300;
function _getVCPaymentStorage() private pure returns (VCPaymentStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := VCPaymentStorageLocation
}
@@ -245,7 +247,7 @@ contract VCPayment is Ownable2StepUpgradeable {
_withdraw(amount, issuer);
}
- function _withdraw(uint amount, address to) internal {
+ function _withdraw(uint256 amount, address to) internal {
if (amount == 0) {
revert WithdrawError("There is no balance to withdraw");
}
diff --git a/contracts/state/State.sol b/contracts/state/State.sol
index dbb6f653..3017b1c9 100644
--- a/contracts/state/State.sol
+++ b/contracts/state/State.sol
@@ -7,16 +7,43 @@ import {IStateTransitionVerifier} from "../interfaces/IStateTransitionVerifier.s
import {SmtLib} from "../lib/SmtLib.sol";
import {PoseidonUnit1L} from "../lib/Poseidon.sol";
import {StateLib} from "../lib/StateLib.sol";
-import {StateCrossChainLib} from "../lib/StateCrossChainLib.sol";
import {GenesisUtils} from "../lib/GenesisUtils.sol";
import {ICrossChainProofValidator} from "../interfaces/ICrossChainProofValidator.sol";
+error VerifierContractAddressShouldNotBeZero();
+error UnknownProofType();
+error DefaultIdTypeNotInitialized();
+error ZeroKnowledgeProofOfStateTransitionIsNotValid();
+error SenderIsNotIdentityOwner();
+error MethodParamsShouldBeEmpty();
+error OldStateShouldBeZero();
+error UnknownStateTransitionMethodId();
+error StateEntryNotFound();
+error CrossChainStateNotFound();
+error GistRootEntryNotFound();
+error CrossChainGistRootNotFound();
+error IdTypeNotSupported();
+error IdShouldNotBeZero();
+error NewStateShouldNotBeZero();
+error OldStateIsGenesisButIdentityAlreadyExists();
+error OldStateIsNotGenesisButIdentityDoesNotExist();
+error OldStateDoesNotMatchTheLatestState();
+error NewStateAlreadyExists();
+
/// @title Set and get states for each identity
contract State is Ownable2StepUpgradeable, IState {
/**
* @dev Version of contract
*/
- string public constant VERSION = "2.6.1";
+ string public constant VERSION = "2.6.2";
+ /**
+ * @dev Global state proof type
+ */
+ bytes32 private constant GLOBAL_STATE_PROOF_TYPE = keccak256(bytes("globalStateProof"));
+ /**
+ * @dev State proof type
+ */
+ bytes32 private constant STATE_PROOF_TYPE = keccak256(bytes("stateProof"));
// This empty reserved space is put in place to allow future versions
// of the State contract to inherit from other contracts without a risk of
@@ -53,34 +80,34 @@ contract State is Ownable2StepUpgradeable, IState {
*/
bool internal _defaultIdTypeInitialized;
- // keccak256(abi.encode(uint256(keccak256("iden3.storage.StateCrossChain")) - 1))
- // & ~bytes32(uint256(0xff));
- bytes32 private constant StateCrossChainStorageLocation =
- 0xfe6de916382846695d2555237dc6c0ef6555f4c949d4ba263e03532600778100;
-
/// @custom:storage-location erc7201:iden3.storage.StateCrossChain
struct StateCrossChainStorage {
mapping(uint256 id => mapping(uint256 state => uint256 replacedAt)) _idToStateReplacedAt;
mapping(bytes2 idType => mapping(uint256 root => uint256 replacedAt)) _rootToGistRootReplacedAt;
ICrossChainProofValidator _crossChainProofValidator;
- IState _state;
+ }
+
+ // keccak256(abi.encode(uint256(keccak256("iden3.storage.StateCrossChain")) - 1))
+ // & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
+ bytes32 private constant StateCrossChainStorageLocation =
+ 0xfe6de916382846695d2555237dc6c0ef6555f4c949d4ba263e03532600778100;
+
+ function _getStateCrossChainStorage() private pure returns (StateCrossChainStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ $.slot := StateCrossChainStorageLocation
+ }
}
using SmtLib for SmtLib.Data;
using StateLib for StateLib.Data;
- using StateCrossChainLib for StateCrossChainStorage;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
- function _getStateCrossChainStorage() private pure returns (StateCrossChainStorage storage $) {
- assembly {
- $.slot := StateCrossChainStorageLocation
- }
- }
-
/**
* @dev Initialize the contract
* @param verifierContractAddr Verifier address
@@ -99,7 +126,7 @@ contract State is Ownable2StepUpgradeable, IState {
}
if (address(verifierContractAddr) == address(0)) {
- revert("Verifier contract address should not be zero");
+ revert VerifierContractAddressShouldNotBeZero();
}
verifier = verifierContractAddr;
@@ -119,12 +146,35 @@ contract State is Ownable2StepUpgradeable, IState {
}
/**
- * @dev Process cross chain proofs with identity and global state proofs
- * @param proofs Cross chain proofs to be processed
+ * @dev Processes cross chain proofs.
+ * @param crossChainProofs The cross chain proofs.
*/
- function processCrossChainProofs(bytes calldata proofs) public {
+ function processCrossChainProofs(bytes calldata crossChainProofs) public {
+ if (crossChainProofs.length == 0) {
+ return;
+ }
+
+ IState.CrossChainProof[] memory proofs = abi.decode(
+ crossChainProofs,
+ (IState.CrossChainProof[])
+ );
+
StateCrossChainStorage storage $ = _getStateCrossChainStorage();
- $.processCrossChainProofs(proofs);
+ for (uint256 i = 0; i < proofs.length; i++) {
+ if (keccak256(bytes(proofs[i].proofType)) == GLOBAL_STATE_PROOF_TYPE) {
+ IState.GlobalStateProcessResult memory gsp = $
+ ._crossChainProofValidator
+ .processGlobalStateProof(proofs[i].proof);
+ $._rootToGistRootReplacedAt[gsp.idType][gsp.root] = gsp.replacedAtTimestamp;
+ } else if (keccak256(bytes(proofs[i].proofType)) == STATE_PROOF_TYPE) {
+ IState.IdentityStateProcessResult memory isu = $
+ ._crossChainProofValidator
+ .processIdentityStateProof(proofs[i].proof);
+ $._idToStateReplacedAt[isu.id][isu.state] = isu.replacedAtTimestamp;
+ } else {
+ revert UnknownProofType();
+ }
+ }
}
/**
@@ -140,7 +190,9 @@ contract State is Ownable2StepUpgradeable, IState {
* @return defaultIdType
*/
function getDefaultIdType() public view returns (bytes2) {
- require(_defaultIdTypeInitialized, "Default Id Type is not initialized");
+ if (!_defaultIdTypeInitialized) {
+ revert DefaultIdTypeNotInitialized();
+ }
return _defaultIdType;
}
@@ -174,10 +226,9 @@ contract State is Ownable2StepUpgradeable, IState {
// Check if the id type is supported
getIdTypeIfSupported(id);
uint256[4] memory input = [id, oldState, newState, uint256(isOldStateGenesis ? 1 : 0)];
- require(
- verifier.verifyProof(a, b, c, input),
- "Zero-knowledge proof of state transition is not valid"
- );
+ if (!verifier.verifyProof(a, b, c, input)) {
+ revert ZeroKnowledgeProofOfStateTransitionIsNotValid();
+ }
_transitState(id, oldState, newState, isOldStateGenesis);
}
@@ -202,16 +253,22 @@ contract State is Ownable2StepUpgradeable, IState {
bytes2 idType = getIdTypeIfSupported(id);
if (methodId == 1) {
uint256 calcId = GenesisUtils.calcIdFromEthAddress(idType, msg.sender);
- require(calcId == id, "msg.sender is not owner of the identity");
- require(methodParams.length == 0, "methodParams should be empty");
+ if (calcId != id) {
+ revert SenderIsNotIdentityOwner();
+ }
+ if (methodParams.length != 0) {
+ revert MethodParamsShouldBeEmpty();
+ }
if (isOldStateGenesis) {
- require(oldState == 0, "Old state should be zero");
+ if (oldState != 0) {
+ revert OldStateShouldBeZero();
+ }
}
_transitState(id, oldState, newState, isOldStateGenesis);
} else {
- revert("Unknown state transition method id");
+ revert UnknownStateTransitionMethodId();
}
}
@@ -446,14 +503,14 @@ contract State is Ownable2StepUpgradeable, IState {
} else if (GenesisUtils.isGenesisState(id, state)) {
return 0;
}
- revert("State entry not found");
+ revert StateEntryNotFound();
} else {
StateCrossChainStorage storage $ = _getStateCrossChainStorage();
uint256 replacedAt = $._idToStateReplacedAt[id][state];
if (replacedAt != 0) {
return replacedAt;
}
- revert("Cross-chain state not found");
+ revert CrossChainStateNotFound();
}
}
@@ -468,17 +525,39 @@ contract State is Ownable2StepUpgradeable, IState {
if (_gistData.rootExists(root)) {
return _gistData.getRootInfo(root).replacedAtTimestamp;
}
- revert("GIST root entry not found");
+ revert GistRootEntryNotFound();
} else {
StateCrossChainStorage storage $ = _getStateCrossChainStorage();
uint256 replacedAt = $._rootToGistRootReplacedAt[idType][root];
if (replacedAt != 0) {
return replacedAt;
}
- revert("Cross-chain GIST root not found");
+ revert CrossChainGistRootNotFound();
}
}
+ /**
+ * @dev Check if the id type is supported and return the id type
+ * @param id Identity
+ * trows if id type is not supported
+ */
+ function getIdTypeIfSupported(uint256 id) public view returns (bytes2) {
+ bytes2 idType = GenesisUtils.getIdType(id);
+ if (!_stateData.isIdTypeSupported[idType]) {
+ revert IdTypeNotSupported();
+ }
+ return idType;
+ }
+
+ /**
+ * @dev Set supported IdType setter
+ * @param idType id type
+ * @param supported ability to enable or disable id type support
+ */
+ function setSupportedIdType(bytes2 idType, bool supported) public onlyOwner {
+ _stateData.isIdTypeSupported[idType] = supported;
+ }
+
/**
* @dev Change the state of an identity (transit to the new state) with ZKP ownership check.
* @param id Identity
@@ -492,23 +571,35 @@ contract State is Ownable2StepUpgradeable, IState {
uint256 newState,
bool isOldStateGenesis
) internal {
- require(id != 0, "ID should not be zero");
- require(newState != 0, "New state should not be zero");
+ if (id == 0) {
+ revert IdShouldNotBeZero();
+ }
+ if (newState == 0) {
+ revert NewStateShouldNotBeZero();
+ }
if (isOldStateGenesis) {
- require(!idExists(id), "Old state is genesis but identity already exists");
+ if (idExists(id)) {
+ revert OldStateIsGenesisButIdentityAlreadyExists();
+ }
// Push old state to state entries, with zero timestamp and block
_stateData.addGenesisState(id, oldState);
} else {
- require(idExists(id), "Old state is not genesis but identity does not yet exist");
+ if (!idExists(id)) {
+ revert OldStateIsNotGenesisButIdentityDoesNotExist();
+ }
StateLib.EntryInfo memory prevStateInfo = _stateData.getStateInfoById(id);
- require(prevStateInfo.state == oldState, "Old state does not match the latest state");
+ if (prevStateInfo.state != oldState) {
+ revert OldStateDoesNotMatchTheLatestState();
+ }
}
// this checks that oldState != newState as well
- require(!stateExists(id, newState), "New state already exists");
+ if (stateExists(id, newState)) {
+ revert NewStateAlreadyExists();
+ }
_stateData.addState(id, newState);
_gistData.addLeaf(PoseidonUnit1L.poseidon([id]), newState);
}
@@ -574,24 +665,4 @@ contract State is Ownable2StepUpgradeable, IState {
_defaultIdTypeInitialized = true;
_stateData.isIdTypeSupported[defaultIdType] = true;
}
-
- /**
- * @dev Check if the id type is supported and return the id type
- * @param id Identity
- * trows if id type is not supported
- */
- function getIdTypeIfSupported(uint256 id) public view returns (bytes2) {
- bytes2 idType = GenesisUtils.getIdType(id);
- require(_stateData.isIdTypeSupported[idType], "id type is not supported");
- return idType;
- }
-
- /**
- * @dev Set supported IdType setter
- * @param idType id type
- * @param supported ability to enable or disable id type support
- */
- function setSupportedIdType(bytes2 idType, bool supported) public onlyOwner {
- _stateData.isIdTypeSupported[idType] = supported;
- }
}
diff --git a/contracts/test-helpers/AuthValidatorStub.sol b/contracts/test-helpers/AuthValidatorStub.sol
new file mode 100644
index 00000000..7e89122f
--- /dev/null
+++ b/contracts/test-helpers/AuthValidatorStub.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+import {IAuthValidator} from "../interfaces/IAuthValidator.sol";
+
+/**
+ * @dev AuthValidatorStub validator
+ */
+contract AuthValidatorStub is IAuthValidator, ERC165 {
+ string public constant VERSION = "1.0.0-stub";
+
+ uint256 private userID;
+
+ function version() public pure override returns (string memory) {
+ return VERSION;
+ }
+
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return
+ interfaceId == type(IAuthValidator).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ function verify(
+ address,
+ bytes calldata,
+ bytes calldata
+ ) external view override returns (uint256, AuthResponseField[] memory) {
+ AuthResponseField[] memory authResponseFields = new AuthResponseField[](1);
+ authResponseFields[0] = AuthResponseField("challenge", 1);
+ return (userID, authResponseFields);
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function stub_setVerifyResults(uint256 _userID) external {
+ userID = _userID;
+ }
+}
diff --git a/contracts/test-helpers/ERC20PermitToken.sol b/contracts/test-helpers/ERC20PermitToken.sol
index 209de571..a1a8395a 100644
--- a/contracts/test-helpers/ERC20PermitToken.sol
+++ b/contracts/test-helpers/ERC20PermitToken.sol
@@ -1,6 +1,6 @@
pragma solidity ^0.8.27;
-import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
+import {ERC20, ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
contract ERC20PermitToken is ERC20Permit {
constructor(uint256 initialSupply) ERC20Permit("TEST") ERC20("EIP-2612 TEST", "EIP2612-TST") {
diff --git a/contracts/test-helpers/ERC20Token.sol b/contracts/test-helpers/ERC20Token.sol
index 69028fb8..fd326c6e 100644
--- a/contracts/test-helpers/ERC20Token.sol
+++ b/contracts/test-helpers/ERC20Token.sol
@@ -1,6 +1,6 @@
pragma solidity ^0.8.27;
-import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ERC20Token is ERC20 {
constructor(uint256 initialSupply) ERC20("ERC20Token", "TST") {
diff --git a/contracts/test-helpers/EmbeddedVerifierWrapper.sol b/contracts/test-helpers/EmbeddedVerifierWrapper.sol
new file mode 100644
index 00000000..38c2f153
--- /dev/null
+++ b/contracts/test-helpers/EmbeddedVerifierWrapper.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {EmbeddedVerifier} from "../verifiers/EmbeddedVerifier.sol";
+import {IState} from "../interfaces/IState.sol";
+
+contract EmbeddedVerifierWrapper is EmbeddedVerifier {
+ event BeforeProofSubmit(AuthResponse authResponse, Response[] responses);
+ event AfterProofSubmit(AuthResponse authResponse, Response[] responses);
+
+ function initialize(address initialOwner, IState state) public initializer {
+ super.__EmbeddedVerifier_init(initialOwner, state);
+ }
+
+ function _beforeProofSubmit(
+ AuthResponse memory authResponse,
+ Response[] memory responses
+ ) internal override {
+ emit BeforeProofSubmit(authResponse, responses);
+ }
+
+ function _afterProofSubmit(
+ AuthResponse memory authResponse,
+ Response[] memory responses
+ ) internal override {
+ emit AfterProofSubmit(authResponse, responses);
+ }
+}
diff --git a/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol b/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol
deleted file mode 100644
index eb3ae3d4..00000000
--- a/contracts/test-helpers/EmbeddedZKPVerifierWrapper.sol
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {EmbeddedZKPVerifier} from "../verifiers/EmbeddedZKPVerifier.sol";
-import {IState} from "../interfaces/IState.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
-
-contract EmbeddedZKPVerifierWrapper is EmbeddedZKPVerifier {
- event BeforeProofSubmit(uint64 requestId, uint256[] inputs, ICircuitValidator validator);
- event AfterProofSubmit(uint64 requestId, uint256[] inputs, ICircuitValidator validator);
- event BeforeProofSubmitV2(IZKPVerifier.ZKPResponse[] responses);
- event AfterProofSubmitV2(IZKPVerifier.ZKPResponse[] responses);
-
- function initialize(address initialOwner, IState state) public initializer {
- super.__EmbeddedZKPVerifier_init(initialOwner, state);
- }
-
- function _beforeProofSubmit(
- uint64 requestId,
- uint256[] memory inputs,
- ICircuitValidator validator
- ) internal override {
- emit BeforeProofSubmit(requestId, inputs, validator);
- }
-
- function _afterProofSubmit(
- uint64 requestId,
- uint256[] memory inputs,
- ICircuitValidator validator
- ) internal override {
- emit AfterProofSubmit(requestId, inputs, validator);
- }
-
- function _beforeProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal override {
- emit BeforeProofSubmitV2(responses);
- }
-
- function _afterProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal override {
- emit AfterProofSubmitV2(responses);
- }
-}
diff --git a/contracts/test-helpers/Groth16VerifierValidatorStub.sol b/contracts/test-helpers/Groth16VerifierValidatorStub.sol
index 91f1200d..e5c39edd 100644
--- a/contracts/test-helpers/Groth16VerifierValidatorStub.sol
+++ b/contracts/test-helpers/Groth16VerifierValidatorStub.sol
@@ -1,15 +1,26 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
-import {IVerifier} from "../interfaces/IVerifier.sol";
+import {IGroth16Verifier} from "../interfaces/IGroth16Verifier.sol";
+
+contract Groth16VerifierValidatorStub is IGroth16Verifier {
+ bool private verifyResult;
+
+ constructor() {
+ verifyResult = true;
+ }
-contract Groth16VerifierValidatorStub is IVerifier {
function verify(
uint256[2] calldata,
uint256[2][2] calldata,
uint256[2] calldata,
uint256[] calldata
- ) external pure returns (bool r) {
- return true;
+ ) external view returns (bool r) {
+ return verifyResult;
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function stub_setVerifyResult(bool result) external {
+ verifyResult = result;
}
}
diff --git a/contracts/test-helpers/RequestDisableableTestWrapper.sol b/contracts/test-helpers/RequestDisableableTestWrapper.sol
new file mode 100644
index 00000000..1fc17ec7
--- /dev/null
+++ b/contracts/test-helpers/RequestDisableableTestWrapper.sol
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {RequestDisableable} from "../verifiers/RequestDisableable.sol";
+import {IState} from "../interfaces/IState.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
+
+contract RequestDisableableTestWrapper is RequestDisableable {
+ function initialize(IState state) public initializer {
+ __Verifier_init(state);
+ }
+
+ function disableRequest(uint256 requestId) public {
+ _disableRequest(requestId);
+ }
+
+ function enableRequest(uint256 requestId) public {
+ _enableRequest(requestId);
+ }
+
+ /* solhint-disable no-empty-blocks */
+ function testModifier(uint256 requestId) public view onlyEnabledRequest(requestId) {}
+ /* solhint-enable no-empty-blocks */
+
+ function getRequestIfCanBeVerified(
+ uint256 requestId
+ ) public view returns (IVerifier.RequestData memory) {
+ return _getRequestIfCanBeVerified(requestId);
+ }
+}
diff --git a/contracts/test-helpers/RequestOwnershipTestWrapper.sol b/contracts/test-helpers/RequestOwnershipTestWrapper.sol
new file mode 100644
index 00000000..36fd588b
--- /dev/null
+++ b/contracts/test-helpers/RequestOwnershipTestWrapper.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {RequestOwnership} from "../verifiers/RequestOwnership.sol";
+import {IState} from "../interfaces/IState.sol";
+
+contract RequestOwnershipTestWrapper is RequestOwnership {
+ function initialize(IState state) public initializer {
+ __Verifier_init(state);
+ }
+
+ function setRequestOwner(uint256 requestId, address requestOwner) public {
+ _setRequestOwner(requestId, requestOwner);
+ }
+}
diff --git a/contracts/test-helpers/RequestValidatorStub.sol b/contracts/test-helpers/RequestValidatorStub.sol
new file mode 100644
index 00000000..6bd7ce26
--- /dev/null
+++ b/contracts/test-helpers/RequestValidatorStub.sol
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+import {IRequestValidator} from "../interfaces/IRequestValidator.sol";
+
+error RequestParamNameNotFound();
+
+/**
+ * @dev RequestValidatorStub validator
+ */
+contract RequestValidatorStub is IRequestValidator, ERC165 {
+ string public constant VERSION = "1.0.0-stub";
+
+ mapping(bytes32 hashParams => IRequestValidator.RequestParam[] requestParams)
+ private requestParams;
+ IRequestValidator.ResponseField[] private responseFields;
+ mapping(string => uint256) private _requestParamNameToIndex;
+
+ function version() public pure override returns (string memory) {
+ return VERSION;
+ }
+
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return
+ interfaceId == type(IRequestValidator).interfaceId ||
+ super.supportsInterface(interfaceId);
+ }
+
+ function verify(
+ address,
+ bytes calldata,
+ bytes calldata
+ ) external view returns (IRequestValidator.ResponseField[] memory) {
+ return responseFields;
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function stub_setVerifyResults(
+ IRequestValidator.ResponseField[] calldata _responseFields
+ ) external {
+ delete responseFields;
+ for (uint256 i = 0; i < _responseFields.length; i++) {
+ responseFields.push(_responseFields[i]);
+ }
+ }
+
+ function getRequestParams(
+ bytes calldata params
+ ) external view returns (IRequestValidator.RequestParam[] memory) {
+ return requestParams[keccak256(params)];
+ }
+
+ function requestParamIndexOf(string memory name) public view override returns (uint256) {
+ uint256 index = _requestParamNameToIndex[name];
+ if (index == 0) revert RequestParamNameNotFound();
+ return --index; // we save 1-based index, but return 0-based
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function stub_setRequestParams(
+ bytes[] calldata _params,
+ IRequestValidator.RequestParam[][] calldata _requestParams
+ ) external {
+ for (uint256 i = 0; i < _params.length; i++) {
+ delete requestParams[keccak256(_params[i])];
+
+ for (uint256 j = 0; j < _requestParams[i].length; j++) {
+ requestParams[keccak256(_params[i])].push(_requestParams[i][j]);
+ _setRequestParamToIndex(_requestParams[i][j].name, j);
+ }
+ }
+ }
+
+ function _setRequestParamToIndex(string memory requestParamName, uint256 index) internal {
+ // increment index to avoid 0
+ _requestParamNameToIndex[requestParamName] = ++index;
+ }
+}
diff --git a/contracts/test-helpers/ReverseHashWrapper.sol b/contracts/test-helpers/ReverseHashWrapper.sol
index 6e6c223f..d4f6228b 100644
--- a/contracts/test-helpers/ReverseHashWrapper.sol
+++ b/contracts/test-helpers/ReverseHashWrapper.sol
@@ -4,6 +4,8 @@ pragma solidity 0.8.27;
import {ReverseHashLib} from "../lib/ReverseHashLib.sol";
import {PoseidonUnit2L, PoseidonUnit3L} from "../lib/Poseidon.sol";
+error UnsupportedLength();
+
contract ReverseHashWrapper {
using ReverseHashLib for ReverseHashLib.Data;
@@ -28,6 +30,6 @@ contract ReverseHashWrapper {
if (preimage.length == 3) {
return PoseidonUnit3L.poseidon([preimage[0], preimage[1], preimage[2]]);
}
- revert("Unsupported length");
+ revert UnsupportedLength();
}
}
diff --git a/contracts/test-helpers/ValidatorStub.sol b/contracts/test-helpers/ValidatorStub.sol
deleted file mode 100644
index 5a4136b4..00000000
--- a/contracts/test-helpers/ValidatorStub.sol
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IState} from "../interfaces/IState.sol";
-
-/**
- * @dev ValidatorStub validator
- */
-contract ValidatorStub is ICircuitValidator, ERC165 {
- string public constant VERSION = "2.0.2-mock";
-
- string internal constant CIRCUIT_ID = "mock-stub";
-
- string[] circuitIds = [CIRCUIT_ID];
-
- function version() public pure override returns (string memory) {
- return VERSION;
- }
-
- function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
- return
- interfaceId == type(ICircuitValidator).interfaceId ||
- super.supportsInterface(interfaceId);
- }
-
- function verify(
- uint256[] calldata,
- uint256[2] calldata,
- uint256[2][2] calldata,
- uint256[2] calldata,
- bytes calldata,
- address
- ) external pure override returns (ICircuitValidator.KeyToInputIndex[] memory) {
- ICircuitValidator.KeyToInputIndex[]
- memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](2);
- keyToInputIndexes[0].key = "userID";
- keyToInputIndexes[0].inputIndex = 1;
- keyToInputIndexes[1].key = "issuerID";
- keyToInputIndexes[1].inputIndex = 2;
- return keyToInputIndexes;
- }
-
- function verifyV2(
- bytes calldata,
- bytes calldata,
- address,
- IState
- ) external pure override returns (ICircuitValidator.Signal[] memory) {
- ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](2);
- signals[0].name = "userID";
- signals[0].value = 1;
- signals[1].name = "issuerID";
- signals[1].value = 2;
- return signals;
- }
-
- function inputIndexOf(string memory /*name*/) external pure returns (uint256) {
- return 0;
- }
-
- function getSupportedCircuitIds() external view returns (string[] memory ids) {
- return circuitIds;
- }
-}
diff --git a/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol b/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol
new file mode 100644
index 00000000..c32d4513
--- /dev/null
+++ b/contracts/test-helpers/ValidatorWhitelistTestWrapper.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {ValidatorWhitelist} from "../verifiers/ValidatorWhitelist.sol";
+import {IState} from "../interfaces/IState.sol";
+import {IRequestValidator} from "../interfaces/IRequestValidator.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
+
+contract ValidatorWhitelistTestWrapper is ValidatorWhitelist {
+ function initialize(IState state) public initializer {
+ __Verifier_init(state);
+ }
+
+ function addValidatorToWhitelist(IRequestValidator validator) public {
+ _addValidatorToWhitelist(validator);
+ }
+
+ function removeValidatorFromWhitelist(IRequestValidator validator) public {
+ _removeValidatorFromWhitelist(validator);
+ }
+
+ /* solhint-disable no-empty-blocks */
+ function testModifier(
+ IRequestValidator validator
+ ) public view onlyWhitelistedValidator(validator) {}
+ /* solhint-enable no-empty-blocks */
+
+ function getRequestIfCanBeVerified(
+ uint256 requestId
+ ) public view returns (IVerifier.RequestData memory) {
+ return _getRequestIfCanBeVerified(requestId);
+ }
+}
diff --git a/contracts/test-helpers/VerifierTestWrapper.sol b/contracts/test-helpers/VerifierTestWrapper.sol
new file mode 100644
index 00000000..7509db25
--- /dev/null
+++ b/contracts/test-helpers/VerifierTestWrapper.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {Verifier} from "../verifiers/Verifier.sol";
+import {IState} from "../interfaces/IState.sol";
+
+contract VerifierTestWrapper is Verifier {
+ function initialize(IState state) public initializer {
+ __Verifier_init(state);
+ }
+
+ function setVerifierID(uint256 verifierID) public {
+ _setVerifierID(verifierID);
+ }
+}
diff --git a/contracts/validators/AuthV2Validator.sol b/contracts/validators/AuthV2Validator.sol
deleted file mode 100644
index 46ecdf0b..00000000
--- a/contracts/validators/AuthV2Validator.sol
+++ /dev/null
@@ -1,138 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol";
-import {IVerifier} from "../interfaces/IVerifier.sol";
-import {GenesisUtils} from "../lib/GenesisUtils.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IState} from "../interfaces/IState.sol";
-
-/**
- * @dev AuthV2Validator validator
- */
-contract AuthV2Validator is CredentialAtomicQueryValidatorBase {
- struct PubSignals {
- uint256 userID;
- uint256 challenge;
- uint256 gistRoot;
- }
-
- /**
- * @dev Version of contract
- */
- string public constant VERSION = "1.0.0";
-
- string internal constant CIRCUIT_ID = "authV2";
-
- /**
- * @dev Initialize the contract
- * @param _verifierContractAddr Address of the verifier contract
- * @param _stateContractAddr Address of the state contract
- * @param owner Owner of the contract
- */
- function initialize(
- address _verifierContractAddr,
- address _stateContractAddr,
- address owner
- ) public initializer {
- _setInputToIndex("userID", 0);
- _setInputToIndex("challenge", 1);
- _setInputToIndex("gistRoot", 2);
-
- _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner);
- }
-
- /**
- * @dev Get the version of the contract
- * @return Version of the contract
- */
- function version() public pure override returns (string memory) {
- return VERSION;
- }
-
- /**
- * @dev Parse the public signals
- * @param inputs Array of public inputs
- * @return Parsed public signals
- */
- function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) {
- PubSignals memory pubSignals = PubSignals({
- userID: inputs[0],
- challenge: inputs[1],
- gistRoot: inputs[2]
- });
-
- return pubSignals;
- }
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @return Array of key to public input index as result.
- */
- function verify(
- // solhint-disable-next-line no-unused-vars
- uint256[] memory inputs,
- // solhint-disable-next-line no-unused-vars
- uint256[2] memory a,
- // solhint-disable-next-line no-unused-vars
- uint256[2][2] memory b,
- // solhint-disable-next-line no-unused-vars
- uint256[2] memory c,
- // solhint-disable-next-line no-unused-vars
- bytes calldata data,
- // solhint-disable-next-line no-unused-vars
- address sender
- ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) {
- revert("function not supported in this contract");
- }
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param zkProof Proof packed as bytes to verify.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param stateContract State contract to get identities and gist states to check.
- * @return Array of public signals as result.
- */
- function verifyV2(
- bytes calldata zkProof,
- // solhint-disable-next-line no-unused-vars
- bytes calldata data,
- address sender,
- IState stateContract
- ) public view override returns (ICircuitValidator.Signal[] memory) {
- (
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
-
- PubSignals memory pubSignals = parsePubSignals(inputs);
- _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, stateContract);
- _checkChallenge(pubSignals.challenge, sender);
- _verifyZKP(inputs, a, b, c);
- ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](1);
- signals[0] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID});
- return signals;
- }
-
- function _verifyZKP(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) internal view {
- IVerifier verifier = getVerifierByCircuitId(CIRCUIT_ID);
- require(verifier != IVerifier(address(0)), "Verifier address should not be zero");
-
- // verify that zkp is valid
- require(verifier.verify(a, b, c, inputs), "Proof is not valid");
- }
-}
diff --git a/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol b/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol
deleted file mode 100644
index a307062b..00000000
--- a/contracts/validators/CredentialAtomicQueryV2ValidatorBase.sol
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol";
-import {IVerifier} from "../interfaces/IVerifier.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IState} from "../interfaces/IState.sol";
-
-/**
- * @dev Base contract for credential atomic query v2 validators circuits.
- */
-abstract contract CredentialAtomicQueryV2ValidatorBase is CredentialAtomicQueryValidatorBase {
- /**
- * @dev Version of contract
- */
-
- struct CredentialAtomicQuery {
- uint256 schema;
- uint256 claimPathKey;
- uint256 operator;
- uint256 slotIndex;
- uint256[] value;
- uint256 queryHash;
- uint256[] allowedIssuers;
- string[] circuitIds;
- bool skipClaimRevocationCheck;
- // 0 for inclusion in merklized credentials, 1 for non-inclusion and for non-merklized credentials
- uint256 claimPathNotExists;
- }
-
- struct PubSignals {
- uint256 merklized;
- uint256 userID;
- uint256 issuerState;
- uint256 circuitQueryHash;
- uint256 requestID;
- uint256 challenge;
- uint256 gistRoot;
- uint256 issuerID;
- uint256 isRevocationChecked;
- uint256 issuerClaimNonRevState;
- uint256 timestamp;
- }
-
- /**
- * @dev Get the version of the contract
- * @return Version of the contract
- */
- function version() public pure virtual override returns (string memory);
-
- /**
- * @dev Parse the public signals
- * @param inputs Array of public inputs
- * @return Parsed public signals
- */
- function parsePubSignals(
- uint256[] memory inputs
- ) public pure virtual returns (PubSignals memory);
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @return Array of key to public input index as result.
- */
- function verify(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
- address sender
- ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) {
- _verifyMain(inputs, a, b, c, data, sender, IState(getStateAddress()));
-
- return _getSpecialInputIndexes();
- }
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param zkProof Proof packed as bytes to verify.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param stateContract State contract to get identities and gist states to check.
- * @return Array of public signals as result.
- */
- function verifyV2(
- bytes calldata zkProof,
- bytes calldata data,
- address sender,
- IState stateContract
- ) public view override returns (ICircuitValidator.Signal[] memory) {
- (
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
-
- PubSignals memory pubSignals = _verifyMain(inputs, a, b, c, data, sender, stateContract);
- return _getSpecialSignals(pubSignals);
- }
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param state State contract to get identities and gist states to check.
- */
- function _verifyMain(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
- address sender,
- IState state
- ) internal view returns (PubSignals memory) {
- CredentialAtomicQuery memory credAtomicQuery = abi.decode(data, (CredentialAtomicQuery));
-
- require(credAtomicQuery.circuitIds.length == 1, "circuitIds length is not equal to 1");
-
- IVerifier verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]);
-
- require(verifier != IVerifier(address(0)), "Verifier address should not be zero");
-
- // verify that zkp is valid
- require(verifier.verify(a, b, c, inputs), "Proof is not valid");
-
- PubSignals memory pubSignals = parsePubSignals(inputs);
-
- // check circuitQueryHash
- require(
- pubSignals.circuitQueryHash == credAtomicQuery.queryHash,
- "Query hash does not match the requested one"
- );
-
- // TODO: add support for query to specific userID and then verifying it
-
- _checkMerklized(pubSignals.merklized, credAtomicQuery.claimPathKey);
- _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers);
- _checkProofExpiration(pubSignals.timestamp);
- _checkIsRevocationChecked(
- pubSignals.isRevocationChecked,
- credAtomicQuery.skipClaimRevocationCheck
- );
-
- // Checking challenge to prevent replay attacks from other addresses
- _checkChallenge(pubSignals.challenge, sender);
-
- // GIST root and state checks
- _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, state);
- _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState, state);
- _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState, state);
-
- return pubSignals;
- }
-
- function _checkMerklized(uint256 merklized, uint256 queryClaimPathKey) internal pure {
- uint256 shouldBeMerklized = queryClaimPathKey != 0 ? 1 : 0;
- require(merklized == shouldBeMerklized, "Merklized value is not correct");
- }
-
- function _checkIsRevocationChecked(
- uint256 isRevocationChecked,
- bool skipClaimRevocationCheck
- ) internal pure {
- uint256 expectedIsRevocationChecked = 1;
- if (skipClaimRevocationCheck) {
- expectedIsRevocationChecked = 0;
- }
- require(
- isRevocationChecked == expectedIsRevocationChecked,
- "Revocation check should match the query"
- );
- }
-
- function _getSpecialSignals(
- PubSignals memory pubSignals
- ) internal pure returns (ICircuitValidator.Signal[] memory) {
- ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](3);
- signals[0] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID});
- signals[1] = ICircuitValidator.Signal({name: "timestamp", value: pubSignals.timestamp});
- signals[2] = ICircuitValidator.Signal({name: "issuerID", value: pubSignals.issuerID});
- return signals;
- }
-
- function _getSpecialInputIndexes()
- internal
- view
- returns (ICircuitValidator.KeyToInputIndex[] memory)
- {
- ICircuitValidator.KeyToInputIndex[]
- memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](3);
- keyToInputIndexes[0] = ICircuitValidator.KeyToInputIndex({
- key: "userID",
- inputIndex: inputIndexOf("userID")
- });
- keyToInputIndexes[1] = ICircuitValidator.KeyToInputIndex({
- key: "timestamp",
- inputIndex: inputIndexOf("timestamp")
- });
- keyToInputIndexes[2] = ICircuitValidator.KeyToInputIndex({
- key: "issuerID",
- inputIndex: inputIndexOf("issuerID")
- });
- return keyToInputIndexes;
- }
-}
diff --git a/contracts/validators/auth/AuthV2Validator.sol b/contracts/validators/auth/AuthV2Validator.sol
new file mode 100644
index 00000000..25ea1d87
--- /dev/null
+++ b/contracts/validators/auth/AuthV2Validator.sol
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
+import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {GenesisUtils} from "../../lib/GenesisUtils.sol";
+import {IAuthValidator} from "../../interfaces/IAuthValidator.sol";
+import {IState} from "../../interfaces/IState.sol";
+
+error VerifierAddressShouldNotBeZero();
+error ProofIsNotValid();
+error GistRootIsExpired();
+
+/**
+ * @dev AuthV2 validator for auth
+ */
+contract AuthV2Validator is Ownable2StepUpgradeable, IAuthValidator, ERC165 {
+ struct PubSignals {
+ uint256 userID;
+ uint256 challenge;
+ uint256 gistRoot;
+ }
+
+ /**
+ * @dev Version of contract
+ */
+ string public constant VERSION = "1.0.0";
+
+ string internal constant CIRCUIT_ID = "authV2";
+
+ /// @dev Main storage structure for the contract
+ /// @custom:storage-location iden3.storage.AuthV2Validator
+ struct AuthV2ValidatorStorage {
+ mapping(string => IGroth16Verifier) _circuitIdToVerifier;
+ string[] _supportedCircuitIds;
+ IState state;
+ uint256 revocationStateExpirationTimeout;
+ uint256 proofExpirationTimeout;
+ uint256 gistRootExpirationTimeout;
+ mapping(string => uint256) _inputNameToIndex;
+ }
+
+ // keccak256(abi.encode(uint256(keccak256("iden3.storage.AuthV2Validator")) - 1))
+ // & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
+ bytes32 private constant AuthV2ValidatorStorageLocation =
+ 0x5212d71c1540b1d75013e45246a2b44f2ee9363a102ea02fac1792932b691600;
+
+ /// @dev Get the main storage using assembly to ensure specific storage location
+ function _getAuthV2ValidatorStorage() private pure returns (AuthV2ValidatorStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ $.slot := AuthV2ValidatorStorageLocation
+ }
+ }
+
+ /**
+ * @dev Initialize the contract
+ * @param _stateContractAddr Address of the state contract
+ * @param _verifierContractAddr Address of the verifier contract
+ * @param owner Owner of the contract
+ */
+ function initialize(
+ address _stateContractAddr,
+ address _verifierContractAddr,
+ address owner
+ ) public initializer {
+ _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner);
+ }
+
+ /**
+ * @dev Get the version of the contract
+ * @return Version of the contract
+ */
+ function version() public pure override returns (string memory) {
+ return VERSION;
+ }
+
+ /**
+ * @dev Parse the public signals
+ * @param inputs Array of public inputs
+ * @return Parsed public signals
+ */
+ function parsePubSignals(uint256[] memory inputs) public pure returns (PubSignals memory) {
+ PubSignals memory pubSignals = PubSignals({
+ userID: inputs[0],
+ challenge: inputs[1],
+ gistRoot: inputs[2]
+ });
+
+ return pubSignals;
+ }
+
+ /**
+ * @dev Verify the groth16 proof and check the request query data
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return userID user ID of public signals as result.
+ */
+ function verify(
+ // solhint-disable-next-line no-unused-vars
+ address sender,
+ bytes calldata proof,
+ // solhint-disable-next-line no-unused-vars
+ bytes calldata params
+ ) public view override returns (uint256 userID, AuthResponseField[] memory) {
+ (
+ uint256[] memory inputs,
+ uint256[2] memory a,
+ uint256[2][2] memory b,
+ uint256[2] memory c
+ ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
+
+ PubSignals memory pubSignals = parsePubSignals(inputs);
+ _checkGistRoot(pubSignals.userID, pubSignals.gistRoot);
+ _verifyZKP(inputs, a, b, c);
+
+ AuthResponseField[] memory authResponseFields = new AuthResponseField[](1);
+ authResponseFields[0] = AuthResponseField("challenge", pubSignals.challenge);
+ return (pubSignals.userID, authResponseFields);
+ }
+
+ /**
+ * @dev Get the verifier by circuit id
+ * @param circuitId Circuit id
+ * @return The verifier
+ */
+ function getVerifierByCircuitId(
+ string memory circuitId
+ ) public view virtual returns (IGroth16Verifier) {
+ return _getAuthV2ValidatorStorage()._circuitIdToVerifier[circuitId];
+ }
+
+ /**
+ * @dev Set the expiration timeout for the revocation state
+ * @param expirationTimeout The expiration timeout for the revocation state
+ */
+ function setRevocationStateExpirationTimeout(
+ uint256 expirationTimeout
+ ) public virtual onlyOwner {
+ _getAuthV2ValidatorStorage().revocationStateExpirationTimeout = expirationTimeout;
+ }
+
+ /**
+ * @dev Get the expiration timeout for the revocation state
+ * @return The expiration timeout for the revocation state
+ */
+ function getRevocationStateExpirationTimeout() public view virtual returns (uint256) {
+ return _getAuthV2ValidatorStorage().revocationStateExpirationTimeout;
+ }
+
+ /**
+ * @dev Set the expiration timeout for the proof
+ * @param expirationTimeout The expiration timeout for the proof
+ */
+ function setProofExpirationTimeout(uint256 expirationTimeout) public virtual onlyOwner {
+ _getAuthV2ValidatorStorage().proofExpirationTimeout = expirationTimeout;
+ }
+
+ /**
+ * @dev Get the expiration timeout for the proof
+ * @return The expiration timeout for the proof
+ */
+ function getProofExpirationTimeout() public view virtual returns (uint256) {
+ return _getAuthV2ValidatorStorage().proofExpirationTimeout;
+ }
+
+ /**
+ * @dev Set the expiration timeout for the gist root
+ * @param expirationTimeout The expiration timeout for the gist root
+ */
+ function setGISTRootExpirationTimeout(uint256 expirationTimeout) public virtual onlyOwner {
+ _getAuthV2ValidatorStorage().gistRootExpirationTimeout = expirationTimeout;
+ }
+
+ /**
+ * @dev Get the expiration timeout for the gist root
+ * @return The expiration timeout for the gist root
+ */
+ function getGISTRootExpirationTimeout() public view virtual returns (uint256) {
+ return _getAuthV2ValidatorStorage().gistRootExpirationTimeout;
+ }
+
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return
+ interfaceId == type(IAuthValidator).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ function _initDefaultStateVariables(
+ address _stateContractAddr,
+ address _verifierContractAddr,
+ string memory circuitId,
+ address owner
+ ) internal {
+ AuthV2ValidatorStorage storage s = _getAuthV2ValidatorStorage();
+
+ s.revocationStateExpirationTimeout = 1 hours;
+ s.proofExpirationTimeout = 1 hours;
+ s.gistRootExpirationTimeout = 1 hours;
+ s._supportedCircuitIds = [circuitId];
+ s._circuitIdToVerifier[circuitId] = IGroth16Verifier(_verifierContractAddr);
+ s.state = IState(_stateContractAddr);
+ __Ownable_init(owner);
+ }
+
+ function _getState() internal view returns (IState) {
+ return _getAuthV2ValidatorStorage().state;
+ }
+
+ function _checkGistRoot(uint256 _id, uint256 _gistRoot) internal view {
+ AuthV2ValidatorStorage storage $ = _getAuthV2ValidatorStorage();
+ bytes2 idType = GenesisUtils.getIdType(_id);
+ uint256 replacedAt = _getState().getGistRootReplacedAt(idType, _gistRoot);
+
+ if (replacedAt != 0 && block.timestamp > $.gistRootExpirationTimeout + replacedAt) {
+ revert GistRootIsExpired();
+ }
+ }
+
+ function _verifyZKP(
+ uint256[] memory inputs,
+ uint256[2] memory a,
+ uint256[2][2] memory b,
+ uint256[2] memory c
+ ) internal view {
+ IGroth16Verifier g16Verifier = getVerifierByCircuitId(CIRCUIT_ID);
+ if (g16Verifier == IGroth16Verifier(address(0))) {
+ revert VerifierAddressShouldNotBeZero();
+ }
+
+ // verify that zkp is valid
+ if (!g16Verifier.verify(a, b, c, inputs)) {
+ revert ProofIsNotValid();
+ }
+ }
+}
diff --git a/contracts/validators/auth/EthIdentityValidator.sol b/contracts/validators/auth/EthIdentityValidator.sol
new file mode 100644
index 00000000..4f513155
--- /dev/null
+++ b/contracts/validators/auth/EthIdentityValidator.sol
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
+import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+import {GenesisUtils} from "../../lib/GenesisUtils.sol";
+import {IAuthValidator} from "../../interfaces/IAuthValidator.sol";
+import {IState} from "../../interfaces/IState.sol";
+
+error SenderIsNotIdentityOwner();
+
+/**
+ * @dev EthIdentityValidator validator
+ */
+contract EthIdentityValidator is Ownable2StepUpgradeable, IAuthValidator, ERC165 {
+ struct PubSignals {
+ uint256 userID;
+ }
+
+ /**
+ * @dev Version of contract
+ */
+ string public constant VERSION = "1.0.0";
+
+ /// @dev Main storage structure for the contract
+ /// @custom:storage-location iden3.storage.EthIdentityValidator
+ struct EthIdentityValidatorBaseStorage {
+ IState state;
+ }
+
+ // keccak256(abi.encode(uint256(keccak256("iden3.storage.EthIdentityValidator")) - 1))
+ // & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
+ bytes32 private constant EthIdentityValidatorBaseStorageLocation =
+ 0x1816cff28d525c2e505742319020369d0e29e8fafd5168e127e29766cf2be1fb;
+
+ /// @dev Get the main storage using assembly to ensure specific storage location
+ function _getEthIdentityValidatorBaseStorage()
+ private
+ pure
+ returns (EthIdentityValidatorBaseStorage storage $)
+ {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ $.slot := EthIdentityValidatorBaseStorageLocation
+ }
+ }
+
+ /**
+ * @dev Initialize the contract
+ * @param _stateContractAddr Address of the state contract
+ * @param owner Owner of the contract
+ */
+ function initialize(address _stateContractAddr, address owner) public initializer {
+ _initDefaultStateVariables(_stateContractAddr, owner);
+ }
+
+ /**
+ * @dev Get the version of the contract
+ * @return Version of the contract
+ */
+ function version() public pure override returns (string memory) {
+ return VERSION;
+ }
+
+ /**
+ * @dev Verify the proof and check the request query data
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of signals as result.
+ */
+ function verify(
+ address sender,
+ bytes calldata proof,
+ // solhint-disable-next-line no-unused-vars
+ bytes calldata params
+ ) public view override returns (uint256, AuthResponseField[] memory) {
+ uint256 userID = abi.decode(proof, (uint256));
+
+ _verifyEthIdentity(userID, sender);
+ return (userID, new AuthResponseField[](0));
+ }
+
+ function _getState() internal view returns (IState) {
+ return _getEthIdentityValidatorBaseStorage().state;
+ }
+
+ function _initDefaultStateVariables(address _stateContractAddr, address owner) internal {
+ EthIdentityValidatorBaseStorage storage s = _getEthIdentityValidatorBaseStorage();
+
+ s.state = IState(_stateContractAddr);
+ __Ownable_init(owner);
+ }
+
+ function _verifyEthIdentity(uint256 id, address sender) internal view {
+ bytes2 idType = _getState().getIdTypeIfSupported(id);
+ uint256 calcId = GenesisUtils.calcIdFromEthAddress(idType, sender);
+ if (calcId != id) {
+ revert SenderIsNotIdentityOwner();
+ }
+ }
+}
diff --git a/contracts/validators/CredentialAtomicQueryMTPV2Validator.sol b/contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol
similarity index 94%
rename from contracts/validators/CredentialAtomicQueryMTPV2Validator.sol
rename to contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol
index 03dd5334..726dd57c 100644
--- a/contracts/validators/CredentialAtomicQueryMTPV2Validator.sol
+++ b/contracts/validators/request/CredentialAtomicQueryMTPV2Validator.sol
@@ -16,13 +16,13 @@ contract CredentialAtomicQueryMTPV2Validator is CredentialAtomicQueryV2Validator
/**
* @dev Initialize the contract
- * @param _verifierContractAddr Address of the verifier contract
* @param _stateContractAddr Address of the state contract
+ * @param _verifierContractAddr Address of the verifier contract
* @param owner Owner of the contract
*/
function initialize(
- address _verifierContractAddr,
address _stateContractAddr,
+ address _verifierContractAddr,
address owner
) public initializer {
_setInputToIndex("merklized", 0);
@@ -37,6 +37,10 @@ contract CredentialAtomicQueryMTPV2Validator is CredentialAtomicQueryV2Validator
_setInputToIndex("issuerClaimNonRevState", 9);
_setInputToIndex("timestamp", 10);
+ _setRequestParamToIndex("groupID", 0);
+ _setRequestParamToIndex("verifierID", 1);
+ _setRequestParamToIndex("nullifierSessionID", 2);
+
_initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner);
}
diff --git a/contracts/validators/CredentialAtomicQuerySigV2Validator.sol b/contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol
similarity index 86%
rename from contracts/validators/CredentialAtomicQuerySigV2Validator.sol
rename to contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol
index 97f69ba4..7c600789 100644
--- a/contracts/validators/CredentialAtomicQuerySigV2Validator.sol
+++ b/contracts/validators/request/CredentialAtomicQuerySigV2Validator.sol
@@ -16,13 +16,13 @@ contract CredentialAtomicQuerySigV2Validator is CredentialAtomicQueryV2Validator
/**
* @dev Initialize the contract
+ * @param _stateContractAddress Address of the state contract
* @param _verifierContractAddr Address of the verifier contract
- * @param _stateContractAddr Address of the state contract
* @param owner Owner of the contract
*/
function initialize(
+ address _stateContractAddress,
address _verifierContractAddr,
- address _stateContractAddr,
address owner
) public initializer {
_setInputToIndex("merklized", 0);
@@ -37,7 +37,11 @@ contract CredentialAtomicQuerySigV2Validator is CredentialAtomicQueryV2Validator
_setInputToIndex("issuerClaimNonRevState", 9);
_setInputToIndex("timestamp", 10);
- _initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner);
+ _setRequestParamToIndex("groupID", 0);
+ _setRequestParamToIndex("verifierID", 1);
+ _setRequestParamToIndex("nullifierSessionID", 2);
+
+ _initDefaultStateVariables(_stateContractAddress, _verifierContractAddr, CIRCUIT_ID, owner);
}
/**
diff --git a/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol b/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol
new file mode 100644
index 00000000..8316e557
--- /dev/null
+++ b/contracts/validators/request/CredentialAtomicQueryV2ValidatorBase.sol
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {IRequestValidator} from "../../interfaces/IRequestValidator.sol";
+
+error CircuitsLengthShouldBeOne();
+error VerifierAddressShouldNotBeZero();
+error ProofIsNotValid();
+error QueryHashDoesNotMatchTheRequestedOne(uint256 expected, uint256 actual);
+error MerklizedValueIsNotCorrect();
+error RevocationCheckShouldMatchTheQuery(uint256 expected, uint256 actual);
+
+/**
+ * @dev Base contract for credential atomic query v2 validators circuits.
+ */
+abstract contract CredentialAtomicQueryV2ValidatorBase is CredentialAtomicQueryValidatorBase {
+ /**
+ * @dev Version of contract
+ */
+
+ struct CredentialAtomicQuery {
+ uint256 schema;
+ uint256 claimPathKey;
+ uint256 operator;
+ uint256 slotIndex;
+ uint256[] value;
+ uint256 queryHash;
+ uint256[] allowedIssuers;
+ string[] circuitIds;
+ bool skipClaimRevocationCheck;
+ // 0 for inclusion in merklized credentials, 1 for non-inclusion and for non-merklized credentials
+ uint256 claimPathNotExists;
+ }
+
+ struct PubSignals {
+ uint256 merklized;
+ uint256 userID;
+ uint256 issuerState;
+ uint256 circuitQueryHash;
+ uint256 requestID;
+ uint256 challenge;
+ uint256 gistRoot;
+ uint256 issuerID;
+ uint256 isRevocationChecked;
+ uint256 issuerClaimNonRevState;
+ uint256 timestamp;
+ }
+
+ /**
+ * @dev Get the version of the contract
+ * @return Version of the contract
+ */
+ function version() public pure virtual override returns (string memory);
+
+ /**
+ * @dev Parse the public signals
+ * @param inputs Array of public inputs
+ * @return Parsed public signals
+ */
+ function parsePubSignals(
+ uint256[] memory inputs
+ ) public pure virtual returns (PubSignals memory);
+
+ /**
+ * @dev Verify the groth16 proof and check the request query data
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of public signals as result.
+ */
+ function verify(
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) public view override returns (IRequestValidator.ResponseField[] memory) {
+ PubSignals memory pubSignals = _verifyMain(sender, proof, params);
+ return _getResponseFields(pubSignals);
+ }
+
+ /**
+ * @dev Get the request params for V2 circuit validator.
+ * @return RequestParams for V2 circuit validator.
+ */
+ function getRequestParams(
+ bytes calldata
+ ) external pure override returns (IRequestValidator.RequestParam[] memory) {
+ IRequestValidator.RequestParam[]
+ memory requestParams = new IRequestValidator.RequestParam[](3);
+ requestParams[0] = IRequestValidator.RequestParam({name: "groupID", value: 0});
+ requestParams[1] = IRequestValidator.RequestParam({name: "verifierID", value: 0});
+ requestParams[2] = IRequestValidator.RequestParam({name: "nullifierSessionID", value: 0});
+ return requestParams;
+ }
+
+ /**
+ * @dev Verify the groth16 proof and check the request query data
+ * @param sender Sender of the proof.
+ * @param proof the groth16 proof.
+ * @param params Request query data of the credential to verify.
+ */
+ function _verifyMain(
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) internal view returns (PubSignals memory) {
+ (
+ uint256[] memory inputs,
+ uint256[2] memory a,
+ uint256[2][2] memory b,
+ uint256[2] memory c
+ ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
+
+ CredentialAtomicQuery memory credAtomicQuery = abi.decode(params, (CredentialAtomicQuery));
+
+ if (credAtomicQuery.circuitIds.length != 1) {
+ revert CircuitsLengthShouldBeOne();
+ }
+
+ IGroth16Verifier g16Verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]);
+
+ if (g16Verifier == IGroth16Verifier(address(0))) {
+ revert VerifierAddressShouldNotBeZero();
+ }
+
+ // verify that zkp is valid
+ if (!g16Verifier.verify(a, b, c, inputs)) {
+ revert ProofIsNotValid();
+ }
+
+ PubSignals memory pubSignals = parsePubSignals(inputs);
+
+ // check circuitQueryHash
+ if (pubSignals.circuitQueryHash != credAtomicQuery.queryHash) {
+ revert QueryHashDoesNotMatchTheRequestedOne(
+ credAtomicQuery.queryHash,
+ pubSignals.circuitQueryHash
+ );
+ }
+
+ // TODO: add support for query to specific userID and then verifying it
+
+ _checkMerklized(pubSignals.merklized, credAtomicQuery.claimPathKey);
+ _checkAllowedIssuers(pubSignals.issuerID, credAtomicQuery.allowedIssuers);
+ _checkProofExpiration(pubSignals.timestamp);
+ _checkIsRevocationChecked(
+ pubSignals.isRevocationChecked,
+ credAtomicQuery.skipClaimRevocationCheck
+ );
+
+ // Checking challenge to prevent replay attacks from other addresses
+ _checkChallenge(pubSignals.challenge, sender);
+
+ // GIST root and state checks
+ _checkGistRoot(pubSignals.userID, pubSignals.gistRoot);
+ _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState);
+ _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState);
+
+ return pubSignals;
+ }
+
+ function _checkMerklized(uint256 merklized, uint256 queryClaimPathKey) internal pure {
+ uint256 shouldBeMerklized = queryClaimPathKey != 0 ? 1 : 0;
+ if (merklized != shouldBeMerklized) {
+ revert MerklizedValueIsNotCorrect();
+ }
+ }
+
+ function _checkIsRevocationChecked(
+ uint256 isRevocationChecked,
+ bool skipClaimRevocationCheck
+ ) internal pure {
+ uint256 expectedIsRevocationChecked = 1;
+ if (skipClaimRevocationCheck) {
+ expectedIsRevocationChecked = 0;
+ }
+ if (isRevocationChecked != expectedIsRevocationChecked) {
+ revert RevocationCheckShouldMatchTheQuery(
+ expectedIsRevocationChecked,
+ isRevocationChecked
+ );
+ }
+ }
+
+ function _getResponseFields(
+ PubSignals memory pubSignals
+ ) internal pure returns (IRequestValidator.ResponseField[] memory) {
+ IRequestValidator.ResponseField[]
+ memory responseFields = new IRequestValidator.ResponseField[](3);
+ responseFields[0] = IRequestValidator.ResponseField({
+ name: "userID",
+ value: pubSignals.userID
+ });
+ responseFields[1] = IRequestValidator.ResponseField({
+ name: "timestamp",
+ value: pubSignals.timestamp
+ });
+ responseFields[2] = IRequestValidator.ResponseField({
+ name: "issuerID",
+ value: pubSignals.issuerID
+ });
+ return responseFields;
+ }
+}
diff --git a/contracts/validators/CredentialAtomicQueryV3Validator.sol b/contracts/validators/request/CredentialAtomicQueryV3Validator.sol
similarity index 53%
rename from contracts/validators/CredentialAtomicQueryV3Validator.sol
rename to contracts/validators/request/CredentialAtomicQueryV3Validator.sol
index c704ee2b..3bb9f901 100644
--- a/contracts/validators/CredentialAtomicQueryV3Validator.sol
+++ b/contracts/validators/request/CredentialAtomicQueryV3Validator.sol
@@ -2,10 +2,19 @@
pragma solidity 0.8.27;
import {CredentialAtomicQueryValidatorBase} from "./CredentialAtomicQueryValidatorBase.sol";
-import {IVerifier} from "../interfaces/IVerifier.sol";
-import {GenesisUtils} from "../lib/GenesisUtils.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IState} from "../interfaces/IState.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {GenesisUtils} from "../../lib/GenesisUtils.sol";
+import {IRequestValidator} from "../../interfaces/IRequestValidator.sol";
+
+error VerifierIDNotSet();
+error QueryHashDoesNotMatchTheRequestedOne(uint256 expected, uint256 actual);
+error VerifierAddressShouldNotBeZero();
+error CircuitsLengthShouldBeOne();
+error ProofIsNotValid();
+error InvalidLinkIDPubSignal();
+error ProofTypeShouldMatchTheRequestedOneInQuery();
+error InvalidNullifyPubSignal();
+error UserIDDoesNotCorrespondToTheSender();
/**
* @dev CredentialAtomicQueryV3 validator
@@ -53,13 +62,13 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
/**
* @dev Initialize the contract
- * @param _verifierContractAddr Address of the verifier contract
* @param _stateContractAddr Address of the state contract
+ * @param _verifierContractAddr Address of the verifier contract
* @param owner Owner of the contract
*/
function initialize(
- address _verifierContractAddr,
address _stateContractAddr,
+ address _verifierContractAddr,
address owner
) public initializer {
_setInputToIndex("userID", 0);
@@ -77,6 +86,10 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
_setInputToIndex("timestamp", 12);
_setInputToIndex("isBJJAuthEnabled", 13);
+ _setRequestParamToIndex("groupID", 0);
+ _setRequestParamToIndex("verifierID", 1);
+ _setRequestParamToIndex("nullifierSessionID", 2);
+
_initDefaultStateVariables(_stateContractAddr, _verifierContractAddr, CIRCUIT_ID, owner);
}
@@ -116,83 +129,72 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
/**
* @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
* @param sender Sender of the proof.
- * @return Array of key to public input index as result.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of public signals as result.
*/
function verify(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
- address sender
- ) public view override returns (ICircuitValidator.KeyToInputIndex[] memory) {
- (, bool hasSD) = _verifyMain(inputs, a, b, c, data, sender, IState(getStateAddress()));
-
- return _getSpecialInputIndexes(hasSD);
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) public view override returns (IRequestValidator.ResponseField[] memory) {
+ (PubSignals memory pubSignals, bool hasSD) = _verifyMain(sender, proof, params);
+ return _getResponseFields(pubSignals, hasSD);
}
/**
- * @dev Verify the groth16 proof and check the request query data
- * @param zkProof Proof packed as bytes to verify.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param stateContract State contract to get identities and gist states to check.
- * @return Array of public signals as result.
+ * @dev Get the request params of the request query data.
+ * @param params Request query data of the credential to verify.
+ * @return RequestParams of the request query data.
*/
- function verifyV2(
- bytes calldata zkProof,
- bytes calldata data,
- address sender,
- IState stateContract
- ) public view override returns (ICircuitValidator.Signal[] memory) {
- (
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) = abi.decode(zkProof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
-
- (PubSignals memory pubSignals, bool hasSD) = _verifyMain(
- inputs,
- a,
- b,
- c,
- data,
- sender,
- stateContract
+ function getRequestParams(
+ bytes calldata params
+ ) external pure override returns (IRequestValidator.RequestParam[] memory) {
+ CredentialAtomicQueryV3 memory credAtomicQuery = abi.decode(
+ params,
+ (CredentialAtomicQueryV3)
);
- return _getSpecialSignals(pubSignals, hasSD);
+
+ if (credAtomicQuery.verifierID == 0) revert VerifierIDNotSet();
+ IRequestValidator.RequestParam[]
+ memory requestParams = new IRequestValidator.RequestParam[](3);
+ requestParams[0] = IRequestValidator.RequestParam({
+ name: "groupID",
+ value: credAtomicQuery.groupID
+ });
+ requestParams[1] = IRequestValidator.RequestParam({
+ name: "verifierID",
+ value: credAtomicQuery.verifierID
+ });
+ requestParams[2] = IRequestValidator.RequestParam({
+ name: "nullifierSessionID",
+ value: credAtomicQuery.nullifierSessionID
+ });
+ return requestParams;
}
/**
* @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
* @param sender Sender of the proof.
- * @param state State contract to get identities and gist states to check.
+ * @param proof the groth16 proof.
+ * @param params Request query data of the credential to verify.
*/
function _verifyMain(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
address sender,
- IState state
+ bytes calldata proof,
+ bytes calldata params
) internal view returns (PubSignals memory, bool) {
CredentialAtomicQueryV3 memory credAtomicQuery = abi.decode(
- data,
+ params,
(CredentialAtomicQueryV3)
);
+ (
+ uint256[] memory inputs,
+ uint256[2] memory a,
+ uint256[2][2] memory b,
+ uint256[2] memory c
+ ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
_verifyZKP(inputs, a, b, c, credAtomicQuery);
@@ -206,10 +208,10 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
_checkNullify(pubSignals.nullifier, credAtomicQuery.nullifierSessionID);
// GIST root and state checks
- _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState, state);
- _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState, state);
+ _checkClaimIssuanceState(pubSignals.issuerID, pubSignals.issuerState);
+ _checkClaimNonRevState(pubSignals.issuerID, pubSignals.issuerClaimNonRevState);
if (pubSignals.isBJJAuthEnabled == 1) {
- _checkGistRoot(pubSignals.userID, pubSignals.gistRoot, state);
+ _checkGistRoot(pubSignals.userID, pubSignals.gistRoot);
} else {
_checkAuth(pubSignals.userID, sender);
}
@@ -218,10 +220,12 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
_checkChallenge(pubSignals.challenge, sender);
// check circuitQueryHash
- require(
- pubSignals.circuitQueryHash == credAtomicQuery.queryHash,
- "Query hash does not match the requested one"
- );
+ if (pubSignals.circuitQueryHash != credAtomicQuery.queryHash) {
+ revert QueryHashDoesNotMatchTheRequestedOne(
+ credAtomicQuery.queryHash,
+ pubSignals.circuitQueryHash
+ );
+ }
// if operator == 16 then we have selective disclosure
return (pubSignals, credAtomicQuery.operator == 16);
@@ -234,102 +238,86 @@ contract CredentialAtomicQueryV3Validator is CredentialAtomicQueryValidatorBase
uint256[2] memory c,
CredentialAtomicQueryV3 memory credAtomicQuery
) internal view {
- require(credAtomicQuery.circuitIds.length == 1, "circuitIds length is not equal to 1");
+ if (credAtomicQuery.circuitIds.length != 1) {
+ revert CircuitsLengthShouldBeOne();
+ }
- IVerifier verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]);
- require(verifier != IVerifier(address(0)), "Verifier address should not be zero");
+ IGroth16Verifier g16Verifier = getVerifierByCircuitId(credAtomicQuery.circuitIds[0]);
+ if (g16Verifier == IGroth16Verifier(address(0))) {
+ revert VerifierAddressShouldNotBeZero();
+ }
// verify that zkp is valid
- require(verifier.verify(a, b, c, inputs), "Proof is not valid");
+ if (!g16Verifier.verify(a, b, c, inputs)) {
+ revert ProofIsNotValid();
+ }
}
function _checkLinkID(uint256 groupID, uint256 linkID) internal pure {
- require(
- (groupID == 0 && linkID == 0) || (groupID != 0 && linkID != 0),
- "Invalid Link ID pub signal"
- );
+ if (!((groupID == 0 && linkID == 0) || (groupID != 0 && linkID != 0))) {
+ revert InvalidLinkIDPubSignal();
+ }
}
function _checkProofType(uint256 queryProofType, uint256 pubSignalProofType) internal pure {
- require(
- queryProofType == 0 || queryProofType == pubSignalProofType,
- "Proof type should match the requested one in query"
- );
+ if (queryProofType != 0 && queryProofType != pubSignalProofType) {
+ revert ProofTypeShouldMatchTheRequestedOneInQuery();
+ }
}
function _checkNullify(uint256 nullifier, uint256 nullifierSessionID) internal pure {
- require(nullifierSessionID == 0 || nullifier != 0, "Invalid nullify pub signal");
+ if (nullifierSessionID != 0 && nullifier == 0) {
+ revert InvalidNullifyPubSignal();
+ }
}
function _checkAuth(uint256 userID, address ethIdentityOwner) internal view {
- require(
- userID ==
- GenesisUtils.calcIdFromEthAddress(
- _getState().getIdTypeIfSupported(userID),
- ethIdentityOwner
- ),
- "UserID does not correspond to the sender"
- );
- }
-
- function _getSpecialSignals(
- PubSignals memory pubSignals,
- bool hasSelectiveDisclosure
- ) internal pure returns (ICircuitValidator.Signal[] memory) {
- uint256 numSignals = hasSelectiveDisclosure ? 6 : 5;
- ICircuitValidator.Signal[] memory signals = new ICircuitValidator.Signal[](numSignals);
-
- uint i = 0;
- signals[i++] = ICircuitValidator.Signal({name: "userID", value: pubSignals.userID});
- signals[i++] = ICircuitValidator.Signal({name: "linkID", value: pubSignals.linkID});
- signals[i++] = ICircuitValidator.Signal({name: "nullifier", value: pubSignals.nullifier});
- if (hasSelectiveDisclosure) {
- signals[i++] = ICircuitValidator.Signal({
- name: "operatorOutput",
- value: pubSignals.operatorOutput
- });
+ if (
+ userID !=
+ GenesisUtils.calcIdFromEthAddress(
+ _getState().getIdTypeIfSupported(userID),
+ ethIdentityOwner
+ )
+ ) {
+ revert UserIDDoesNotCorrespondToTheSender();
}
- signals[i++] = ICircuitValidator.Signal({name: "timestamp", value: pubSignals.timestamp});
- signals[i++] = ICircuitValidator.Signal({name: "issuerID", value: pubSignals.issuerID});
-
- return signals;
}
- function _getSpecialInputIndexes(
+ function _getResponseFields(
+ PubSignals memory pubSignals,
bool hasSelectiveDisclosure
- ) internal view returns (ICircuitValidator.KeyToInputIndex[] memory) {
+ ) internal pure returns (IRequestValidator.ResponseField[] memory) {
uint256 numSignals = hasSelectiveDisclosure ? 6 : 5;
- ICircuitValidator.KeyToInputIndex[]
- memory keyToInputIndexes = new ICircuitValidator.KeyToInputIndex[](numSignals);
+ IRequestValidator.ResponseField[]
+ memory responseFields = new IRequestValidator.ResponseField[](numSignals);
- uint i = 0;
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "userID",
- inputIndex: inputIndexOf("userID")
+ uint256 i = 0;
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "userID",
+ value: pubSignals.userID
+ });
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "linkID",
+ value: pubSignals.linkID
});
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "linkID",
- inputIndex: inputIndexOf("linkID")
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "nullifier",
+ value: pubSignals.nullifier
});
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "nullifier",
- inputIndex: inputIndexOf("nullifier")
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "timestamp",
+ value: pubSignals.timestamp
+ });
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "issuerID",
+ value: pubSignals.issuerID
});
if (hasSelectiveDisclosure) {
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "operatorOutput",
- inputIndex: inputIndexOf("operatorOutput")
+ responseFields[i++] = IRequestValidator.ResponseField({
+ name: "operatorOutput",
+ value: pubSignals.operatorOutput
});
}
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "timestamp",
- inputIndex: inputIndexOf("timestamp")
- });
- keyToInputIndexes[i++] = ICircuitValidator.KeyToInputIndex({
- key: "issuerID",
- inputIndex: inputIndexOf("issuerID")
- });
-
- return keyToInputIndexes;
+ return responseFields;
}
}
diff --git a/contracts/validators/CredentialAtomicQueryValidatorBase.sol b/contracts/validators/request/CredentialAtomicQueryValidatorBase.sol
similarity index 71%
rename from contracts/validators/CredentialAtomicQueryValidatorBase.sol
rename to contracts/validators/request/CredentialAtomicQueryValidatorBase.sol
index a972a12e..1255b437 100644
--- a/contracts/validators/CredentialAtomicQueryValidatorBase.sol
+++ b/contracts/validators/request/CredentialAtomicQueryValidatorBase.sol
@@ -3,34 +3,45 @@ pragma solidity 0.8.27;
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
-import {GenesisUtils} from "../lib/GenesisUtils.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IVerifier} from "../interfaces/IVerifier.sol";
-import {IState} from "../interfaces/IState.sol";
-import {PrimitiveTypeUtils} from "../lib/PrimitiveTypeUtils.sol";
+import {GenesisUtils} from "../../lib/GenesisUtils.sol";
+import {IRequestValidator} from "../../interfaces/IRequestValidator.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {IState} from "../../interfaces/IState.sol";
+import {PrimitiveTypeUtils} from "../../lib/PrimitiveTypeUtils.sol";
+
+error InputNameNotFound();
+error RequestParamNameNotFound();
+error ChallengeShouldMatchTheSender();
+error GistRootIsExpired();
+error NonRevocationStateOfIssuerIsExpired();
+error ProofGeneratedInTheFutureIsNotValid();
+error GeneratedProofIsOutdated();
+error IssuerIsNotOnTheAllowedIssuersList();
/**
* @dev Base contract for credential atomic query validators circuits.
*/
abstract contract CredentialAtomicQueryValidatorBase is
Ownable2StepUpgradeable,
- ICircuitValidator,
+ IRequestValidator,
ERC165
{
/// @dev Main storage structure for the contract
/// @custom:storage-location iden3.storage.CredentialAtomicQueryValidator
struct CredentialAtomicQueryValidatorBaseStorage {
- mapping(string => IVerifier) _circuitIdToVerifier;
+ mapping(string => IGroth16Verifier) _circuitIdToVerifier;
string[] _supportedCircuitIds;
IState state;
uint256 revocationStateExpirationTimeout;
uint256 proofExpirationTimeout;
uint256 gistRootExpirationTimeout;
mapping(string => uint256) _inputNameToIndex;
+ mapping(string => uint256) _requestParamNameToIndex;
}
// keccak256(abi.encode(uint256(keccak256("iden3.storage.CredentialAtomicQueryValidator")) - 1))
// & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant CredentialAtomicQueryValidatorBaseStorageLocation =
0x28c92975a30f1f2f7970a65953987652034d896ba2d3b7a4961ada9e18287500;
@@ -40,29 +51,12 @@ abstract contract CredentialAtomicQueryValidatorBase is
pure
returns (CredentialAtomicQueryValidatorBaseStorage storage $)
{
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := CredentialAtomicQueryValidatorBaseStorageLocation
}
}
- function _initDefaultStateVariables(
- address _stateContractAddr,
- address _verifierContractAddr,
- string memory circuitId,
- address owner
- ) internal {
- CredentialAtomicQueryValidatorBaseStorage
- storage s = _getCredentialAtomicQueryValidatorBaseStorage();
-
- s.revocationStateExpirationTimeout = 1 hours;
- s.proofExpirationTimeout = 1 hours;
- s.gistRootExpirationTimeout = 1 hours;
- s._supportedCircuitIds = [circuitId];
- s._circuitIdToVerifier[circuitId] = IVerifier(_verifierContractAddr);
- s.state = IState(_stateContractAddr);
- __Ownable_init(owner);
- }
-
/**
* @dev Returns the version of the contract
* @return The version of the contract
@@ -138,38 +132,18 @@ abstract contract CredentialAtomicQueryValidatorBase is
}
/**
- * @dev Verify the groth16 proof and check the request query data
- * @param inputs Public inputs of the circuit.
- * @param a πa element of the groth16 proof.
- * @param b πb element of the groth16 proof.
- * @param c πc element of the groth16 proof.
- * @param data Request query data of the credential to verify.
+ * @dev Verify the proof with the supported method informed in the request query data
+ * packed as bytes and that the proof was generated by the sender.
* @param sender Sender of the proof.
- * @return Array of key to public input index as result.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of response fields as result.
*/
function verify(
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- bytes calldata data,
- address sender
- ) external view virtual returns (ICircuitValidator.KeyToInputIndex[] memory);
-
- /**
- * @dev Verify the groth16 proof and check the request query data
- * @param zkProof Proof packed as bytes to verify.
- * @param data Request query data of the credential to verify.
- * @param sender Sender of the proof.
- * @param stateContract State contract to get identities and gist states to check.
- * @return Array of public signals as result.
- */
- function verifyV2(
- bytes calldata zkProof,
- bytes calldata data,
address sender,
- IState stateContract
- ) external view virtual returns (ICircuitValidator.Signal[] memory);
+ bytes calldata proof,
+ bytes calldata params
+ ) external view virtual returns (ResponseField[] memory);
/**
* @dev Get supported circuit ids
@@ -186,14 +160,10 @@ abstract contract CredentialAtomicQueryValidatorBase is
*/
function getVerifierByCircuitId(
string memory circuitId
- ) public view virtual returns (IVerifier) {
+ ) public view virtual returns (IGroth16Verifier) {
return _getCredentialAtomicQueryValidatorBaseStorage()._circuitIdToVerifier[circuitId];
}
- function _getState() internal view returns (IState) {
- return _getCredentialAtomicQueryValidatorBaseStorage().state;
- }
-
/**
* @dev Get the index of the public input of the circuit by name
* @param name Name of the public input
@@ -201,7 +171,24 @@ abstract contract CredentialAtomicQueryValidatorBase is
*/
function inputIndexOf(string memory name) public view virtual returns (uint256) {
uint256 index = _getCredentialAtomicQueryValidatorBaseStorage()._inputNameToIndex[name];
- require(index != 0, "Input name not found");
+ if (index == 0) {
+ revert InputNameNotFound();
+ }
+ return --index; // we save 1-based index, but return 0-based
+ }
+
+ /**
+ * @dev Get the index of the request param by name
+ * @param name Name of the request param
+ * @return Index of the request param
+ */
+ function requestParamIndexOf(string memory name) public view override returns (uint256) {
+ uint256 index = _getCredentialAtomicQueryValidatorBaseStorage()._requestParamNameToIndex[
+ name
+ ];
+ if (index == 0) {
+ revert RequestParamNameNotFound();
+ }
return --index; // we save 1-based index, but return 0-based
}
@@ -210,40 +197,54 @@ abstract contract CredentialAtomicQueryValidatorBase is
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
- interfaceId == type(ICircuitValidator).interfaceId ||
+ interfaceId == type(IRequestValidator).interfaceId ||
super.supportsInterface(interfaceId);
}
- function _checkGistRoot(uint256 _id, uint256 _gistRoot, IState _stateContract) internal view {
+ function _initDefaultStateVariables(
+ address _stateContractAddr,
+ address _verifierContractAddr,
+ string memory circuitId,
+ address owner
+ ) internal {
+ CredentialAtomicQueryValidatorBaseStorage
+ storage s = _getCredentialAtomicQueryValidatorBaseStorage();
+
+ s.revocationStateExpirationTimeout = 1 hours;
+ s.proofExpirationTimeout = 1 hours;
+ s.gistRootExpirationTimeout = 1 hours;
+ s._supportedCircuitIds = [circuitId];
+ s._circuitIdToVerifier[circuitId] = IGroth16Verifier(_verifierContractAddr);
+ s.state = IState(_stateContractAddr);
+ __Ownable_init(owner);
+ }
+
+ function _checkGistRoot(uint256 _id, uint256 _gistRoot) internal view {
CredentialAtomicQueryValidatorBaseStorage
storage $ = _getCredentialAtomicQueryValidatorBaseStorage();
bytes2 idType = GenesisUtils.getIdType(_id);
- uint256 replacedAt = _stateContract.getGistRootReplacedAt(idType, _gistRoot);
+ uint256 replacedAt = $.state.getGistRootReplacedAt(idType, _gistRoot);
if (replacedAt != 0 && block.timestamp > $.gistRootExpirationTimeout + replacedAt) {
- revert("Gist root is expired");
+ revert GistRootIsExpired();
}
}
- function _checkClaimIssuanceState(
- uint256 _id,
- uint256 _state,
- IState _stateContract
- ) internal view {
- _stateContract.getStateReplacedAt(_id, _state);
+ function _getState() internal view returns (IState) {
+ return _getCredentialAtomicQueryValidatorBaseStorage().state;
+ }
+
+ function _checkClaimIssuanceState(uint256 _id, uint256 _state) internal view {
+ _getState().getStateReplacedAt(_id, _state);
}
- function _checkClaimNonRevState(
- uint256 _id,
- uint256 _claimNonRevState,
- IState _stateContract
- ) internal view {
+ function _checkClaimNonRevState(uint256 _id, uint256 _claimNonRevState) internal view {
CredentialAtomicQueryValidatorBaseStorage
storage $ = _getCredentialAtomicQueryValidatorBaseStorage();
- uint256 replacedAt = _stateContract.getStateReplacedAt(_id, _claimNonRevState);
+ uint256 replacedAt = _getState().getStateReplacedAt(_id, _claimNonRevState);
if (replacedAt != 0 && block.timestamp > $.revocationStateExpirationTimeout + replacedAt) {
- revert("Non-Revocation state of Issuer expired");
+ revert NonRevocationStateOfIssuerIsExpired();
}
}
@@ -254,14 +255,14 @@ abstract contract CredentialAtomicQueryValidatorBase is
https://github.com/ethereum/go-ethereum/issues/24152
*/
if (_proofGenerationTimestamp > (block.timestamp + 5 minutes)) {
- revert("Proof generated in the future is not valid");
+ revert ProofGeneratedInTheFutureIsNotValid();
}
if (
block.timestamp >
_getCredentialAtomicQueryValidatorBaseStorage().proofExpirationTimeout +
_proofGenerationTimestamp
) {
- revert("Generated proof is outdated");
+ revert GeneratedProofIsOutdated();
}
}
@@ -271,24 +272,30 @@ abstract contract CredentialAtomicQueryValidatorBase is
return;
}
- for (uint i = 0; i < allowedIssuers.length; i++) {
+ for (uint256 i = 0; i < allowedIssuers.length; i++) {
if (issuerId == allowedIssuers[i]) {
return;
}
}
- revert("Issuer is not on the Allowed Issuers list");
+ revert IssuerIsNotOnTheAllowedIssuersList();
}
function _checkChallenge(uint256 challenge, address sender) internal pure {
- require(
- PrimitiveTypeUtils.uint256LEToAddress(challenge) == sender,
- "Challenge should match the sender"
- );
+ if (PrimitiveTypeUtils.uint256LEToAddress(challenge) != sender) {
+ revert ChallengeShouldMatchTheSender();
+ }
}
function _setInputToIndex(string memory inputName, uint256 index) internal {
// increment index to avoid 0
_getCredentialAtomicQueryValidatorBaseStorage()._inputNameToIndex[inputName] = ++index;
}
+
+ function _setRequestParamToIndex(string memory requestParamName, uint256 index) internal {
+ // increment index to avoid 0
+ _getCredentialAtomicQueryValidatorBaseStorage()._requestParamNameToIndex[
+ requestParamName
+ ] = ++index;
+ }
}
diff --git a/contracts/validators/request/LinkedMultiQueryValidator.sol b/contracts/validators/request/LinkedMultiQueryValidator.sol
new file mode 100644
index 00000000..60e0b5d3
--- /dev/null
+++ b/contracts/validators/request/LinkedMultiQueryValidator.sol
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.10;
+
+import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
+import {IGroth16Verifier} from "../../interfaces/IGroth16Verifier.sol";
+import {IRequestValidator} from "../../interfaces/IRequestValidator.sol";
+import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
+import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
+
+error WrongCircuitID(string circuitID);
+error InvalidQueryHash(uint256 expectedQueryHash, uint256 actualQueryHash);
+error InvalidGroupID(uint256 groupID);
+error TooManyQueries(uint256 operatorCount);
+error InvalidGroth16Proof();
+error RequestParamNameNotFound();
+
+contract LinkedMultiQueryValidator is Ownable2StepUpgradeable, IRequestValidator, ERC165 {
+ // This should be limited to the real number of queries in which operator != 0
+ struct Query {
+ uint256[] claimPathKey;
+ uint256[] operator; // when checking SD take operator from here
+ uint256[] slotIndex;
+ uint256[][] value;
+ uint256[] queryHash;
+ string[] circuitIds;
+ uint256 groupID;
+ uint256 verifierID;
+ }
+
+ /// @dev Main storage structure for the contract
+ /// @custom:storage-location iden3.storage.LinkedMultiQueryValidatorStorage
+ struct LinkedMultiQueryValidatorStorage {
+ mapping(string circuitName => IGroth16Verifier) _supportedCircuits;
+ string[] _supportedCircuitIds;
+ mapping(string => uint256) _requestParamNameToIndex;
+ }
+
+ // keccak256(abi.encode(uint256(keccak256("iden3.storage.LinkedMultiQueryValidator")) - 1))
+ // & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
+ bytes32 private constant LinkedMultiQueryValidatorStorageLocation =
+ 0x85875fc21d0742149175681df1689e48bce1484a73b475e15e5042650a2d7800;
+
+ /// @dev Get the main storage using assembly to ensure specific storage location
+ function _getLinkedMultiQueryValidatorStorage()
+ private
+ pure
+ returns (LinkedMultiQueryValidatorStorage storage $)
+ {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ $.slot := LinkedMultiQueryValidatorStorageLocation
+ }
+ }
+
+ struct PubSignals {
+ uint256 linkID;
+ uint256 merklized;
+ uint256[10] operatorOutput;
+ uint256[10] circuitQueryHash;
+ }
+
+ string public constant VERSION = "1.0.0-beta.1";
+ string internal constant CIRCUIT_ID = "linkedMultiQuery10-beta.1";
+ uint256 internal constant QUERIES_COUNT = 10;
+
+ /**
+ * @dev Returns the version of the contract
+ * @return The version of the contract
+ */
+ function version() external pure override returns (string memory) {
+ return VERSION;
+ }
+
+ /**
+ * @dev Initialize the contract
+ * @param _groth16VerifierContractAddr Address of the verifier contract
+ * @param owner Owner of the contract
+ */
+ function initialize(address _groth16VerifierContractAddr, address owner) public initializer {
+ LinkedMultiQueryValidatorStorage storage $ = _getLinkedMultiQueryValidatorStorage();
+ $._supportedCircuits[CIRCUIT_ID] = IGroth16Verifier(_groth16VerifierContractAddr);
+ $._supportedCircuitIds.push(CIRCUIT_ID);
+
+ _setRequestParamToIndex("groupID", 0);
+ _setRequestParamToIndex("verifierID", 1);
+ _setRequestParamToIndex("nullifierSessionID", 2);
+
+ __Ownable_init(owner);
+ }
+
+ /**
+ * @dev Verify the proof with the supported method informed in the request query data
+ * packed as bytes and that the proof was generated by the sender.
+ * @param sender Sender of the proof.
+ * @param proof Proof packed as bytes to verify.
+ * @param params Request query data of the credential to verify.
+ * @return Array of response fields as result.
+ */
+ function verify(
+ // solhint-disable-next-line no-unused-vars
+ address sender,
+ bytes calldata proof,
+ bytes calldata params
+ ) external view returns (IRequestValidator.ResponseField[] memory) {
+ LinkedMultiQueryValidatorStorage storage $ = _getLinkedMultiQueryValidatorStorage();
+
+ Query memory query = abi.decode(params, (Query));
+ (
+ uint256[] memory inputs,
+ uint256[2] memory a,
+ uint256[2][2] memory b,
+ uint256[2] memory c
+ ) = abi.decode(proof, (uint256[], uint256[2], uint256[2][2], uint256[2]));
+ PubSignals memory pubSignals = _parsePubSignals(inputs);
+
+ _checkQueryHash(query, pubSignals);
+ _checkGroupId(query.groupID);
+
+ if (keccak256(bytes(query.circuitIds[0])) != keccak256(bytes(CIRCUIT_ID))) {
+ revert WrongCircuitID(query.circuitIds[0]);
+ }
+ if (!$._supportedCircuits[CIRCUIT_ID].verify(a, b, c, inputs)) {
+ revert InvalidGroth16Proof();
+ }
+
+ return _getResponseFields(pubSignals, query);
+ }
+
+ /**
+ * @dev Decodes special request parameters from the request params
+ * do be used by upper level clients of this contract.
+ * @param params Request parameters packed as bytes.
+ * @return Special request parameters extracted from the request data.
+ */
+ function getRequestParams(
+ bytes calldata params
+ ) external pure override returns (IRequestValidator.RequestParam[] memory) {
+ Query memory query = abi.decode(params, (Query));
+ IRequestValidator.RequestParam[]
+ memory requestParams = new IRequestValidator.RequestParam[](3);
+ requestParams[0] = IRequestValidator.RequestParam({name: "groupID", value: query.groupID});
+ requestParams[1] = IRequestValidator.RequestParam({
+ name: "verifierID",
+ value: query.verifierID
+ });
+ requestParams[2] = IRequestValidator.RequestParam({name: "nullifierSessionID", value: 0});
+ return requestParams;
+ }
+
+ /**
+ * @dev Get the index of the request param by name
+ * @param name Name of the request param
+ * @return Index of the request param
+ */
+ function requestParamIndexOf(
+ string memory name
+ ) public view virtual override returns (uint256) {
+ uint256 index = _getLinkedMultiQueryValidatorStorage()._requestParamNameToIndex[name];
+ if (index == 0) {
+ revert RequestParamNameNotFound();
+ }
+ return --index; // we save 1-based index, but return 0-based
+ }
+
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return
+ interfaceId == type(IRequestValidator).interfaceId ||
+ super.supportsInterface(interfaceId);
+ }
+
+ function _checkGroupId(uint256 groupID) internal pure {
+ if (groupID == 0) {
+ revert InvalidGroupID(groupID);
+ }
+ }
+
+ function _checkQueryHash(Query memory query, PubSignals memory pubSignals) internal pure {
+ if (query.queryHash.length > QUERIES_COUNT) {
+ revert TooManyQueries(query.queryHash.length);
+ }
+ for (uint256 i = 0; i < query.queryHash.length; i++) {
+ if (query.queryHash[i] != pubSignals.circuitQueryHash[i]) {
+ revert InvalidQueryHash(query.queryHash[i], pubSignals.circuitQueryHash[i]);
+ }
+ }
+ }
+
+ function _parsePubSignals(uint256[] memory inputs) internal pure returns (PubSignals memory) {
+ uint256[QUERIES_COUNT] memory opsOutput;
+ uint256[QUERIES_COUNT] memory queryHashes;
+ PubSignals memory pubSignals = PubSignals({
+ linkID: 0,
+ merklized: 0,
+ operatorOutput: opsOutput,
+ circuitQueryHash: queryHashes
+ });
+
+ pubSignals.linkID = inputs[0];
+ pubSignals.merklized = inputs[1];
+ for (uint256 i = 0; i < QUERIES_COUNT; i++) {
+ pubSignals.operatorOutput[i] = inputs[2 + i];
+ pubSignals.circuitQueryHash[i] = inputs[2 + QUERIES_COUNT + i];
+ }
+ return pubSignals;
+ }
+
+ function _getResponseFields(
+ PubSignals memory pubSignals,
+ Query memory query
+ ) internal pure returns (ResponseField[] memory) {
+ uint256 operatorCount = 0;
+ for (uint256 i = 0; i < query.operator.length; i++) {
+ if (query.operator[i] == 16) {
+ operatorCount++;
+ }
+ }
+
+ uint256 n = 1;
+ ResponseField[] memory rfs = new ResponseField[](n + operatorCount);
+ rfs[0] = ResponseField("linkID", pubSignals.linkID);
+
+ uint256 m = 1;
+ for (uint256 i = 0; i < query.operator.length; i++) {
+ // TODO consider if can be more gas efficient. Check via gasleft() first
+ if (query.operator[i] == 16) {
+ rfs[m++] = ResponseField(
+ string(abi.encodePacked("operatorOutput", Strings.toString(i))),
+ pubSignals.operatorOutput[i]
+ );
+ }
+ }
+
+ return rfs;
+ }
+
+ function _setRequestParamToIndex(string memory requestParamName, uint256 index) internal {
+ // increment index to avoid 0
+ _getLinkedMultiQueryValidatorStorage()._requestParamNameToIndex[requestParamName] = ++index;
+ }
+}
diff --git a/contracts/verifiers/EmbeddedVerifier.sol b/contracts/verifiers/EmbeddedVerifier.sol
new file mode 100644
index 00000000..95fea945
--- /dev/null
+++ b/contracts/verifiers/EmbeddedVerifier.sol
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
+import {Verifier} from "./Verifier.sol";
+import {IState} from "../interfaces/IState.sol";
+
+abstract contract EmbeddedVerifier is Ownable2StepUpgradeable, Verifier {
+ /// @dev Sets the state contract linked to this verifier
+ /// @param state The state contract address
+ function setState(IState state) public onlyOwner {
+ _setState(state);
+ }
+
+ /**
+ * @dev Submits an array of responses and updates proofs status
+ * @param authResponse Auth response including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This
+ * includes identities and global states.
+ */
+ function submitResponse(
+ AuthResponse memory authResponse,
+ Response[] memory responses,
+ bytes memory crossChainProofs
+ ) public virtual override {
+ _beforeProofSubmit(authResponse, responses);
+ super.submitResponse(authResponse, responses, crossChainProofs);
+ _afterProofSubmit(authResponse, responses);
+ }
+
+ /**
+ * @dev Sets the value for Owner
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function __EmbeddedVerifier_init(address initialOwner, IState state) internal onlyInitializing {
+ __Ownable_init(initialOwner);
+ ___EmbeddedVerifier_init_unchained(initialOwner);
+ __Verifier_init(state);
+ }
+
+ /* solhint-disable no-empty-blocks */
+ // solhint-disable-next-line func-name-mixedcase
+ function ___EmbeddedVerifier_init_unchained(address initialOwner) internal onlyInitializing {}
+
+ /**
+ * @dev Hook that is called before any proof response submit
+ * @param authResponse Auth response including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ */
+ function _beforeProofSubmit(
+ AuthResponse memory authResponse,
+ Response[] memory responses
+ ) internal virtual {}
+
+ /**
+ * @dev Hook that is called after any proof response submit
+ * @param authResponse The list of auth responses including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ */
+ function _afterProofSubmit(
+ AuthResponse memory authResponse,
+ Response[] memory responses
+ ) internal virtual {}
+ /* solhint-enable no-empty-blocks */
+}
diff --git a/contracts/verifiers/EmbeddedZKPVerifier.sol b/contracts/verifiers/EmbeddedZKPVerifier.sol
deleted file mode 100644
index 64268afa..00000000
--- a/contracts/verifiers/EmbeddedZKPVerifier.sol
+++ /dev/null
@@ -1,118 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
-import {ZKPVerifierBase} from "./ZKPVerifierBase.sol";
-import {IState} from "../interfaces/IState.sol";
-
-abstract contract EmbeddedZKPVerifier is Ownable2StepUpgradeable, ZKPVerifierBase {
- /**
- * @dev Sets the value for Owner
- */
- function __EmbeddedZKPVerifier_init(
- address initialOwner,
- IState state
- ) internal onlyInitializing {
- __Ownable_init(initialOwner);
- ___EmbeddedZKPVerifier_init_unchained(initialOwner);
- __ZKPVerifierBase_init(state);
- }
-
- function ___EmbeddedZKPVerifier_init_unchained(
- address initialOwner
- ) internal onlyInitializing {}
-
- /// @dev Sets the state contract linked to this verifier
- /// @param state The state contract address
- function setState(IState state) public onlyOwner {
- _setState(state);
- }
-
- /// @dev Sets a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function setZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public virtual override onlyOwner {
- super.setZKPRequest(requestId, request);
- }
-
- /**
- * @dev Set the list of ZKP requests for the list of requestIds in the same order.
- * @param requestIds Request ids of the ZKP requests.
- * @param requests ZKP requests to set.
- */
- function setZKPRequests(
- uint64[] calldata requestIds,
- ZKPRequest[] calldata requests
- ) public virtual override onlyOwner {
- super.setZKPRequests(requestIds, requests);
- }
-
- /// @dev Submits a ZKP response and updates proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The input data for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- function submitZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) public virtual override {
- IZKPVerifier.ZKPRequest memory request = getZKPRequest(requestId);
- _beforeProofSubmit(requestId, inputs, request.validator);
- super.submitZKPResponse(requestId, inputs, a, b, c);
- _afterProofSubmit(requestId, inputs, request.validator);
- }
-
- /**
- * @dev Submits an array of ZKP responses and updates proofs status
- * @param responses The list of responses including ZKP request ID, ZK proof and metadata
- * @param crossChainProof The list of cross chain proofs from universal resolver (oracle). This
- * includes identities and global states.
- */
- function submitZKPResponseV2(
- IZKPVerifier.ZKPResponse[] memory responses,
- bytes memory crossChainProof
- ) public override {
- _beforeProofSubmitV2(responses);
- super.submitZKPResponseV2(responses, crossChainProof);
- _afterProofSubmitV2(responses);
- }
-
- /**
- * @dev Hook that is called before any proof response submit
- */
- function _beforeProofSubmit(
- uint64 requestId,
- uint256[] memory inputs,
- ICircuitValidator validator
- ) internal virtual {}
-
- /**
- * @dev Hook that is called after any proof response submit
- */
- function _afterProofSubmit(
- uint64 requestId,
- uint256[] memory inputs,
- ICircuitValidator validator
- ) internal virtual {}
-
- /**
- * @dev Hook that is called before any proof response submit V2
- * @param responses The list of responses including ZKP request ID, ZK proof and metadata
- */
- function _beforeProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal virtual {}
-
- /**
- * @dev Hook that is called after any proof response submit V2
- * @param responses The list of responses including ZKP request ID, ZK proof and metadata
- */
- function _afterProofSubmitV2(IZKPVerifier.ZKPResponse[] memory responses) internal virtual {}
-}
diff --git a/contracts/verifiers/RequestDisableable.sol b/contracts/verifiers/RequestDisableable.sol
index 7ff1dfa0..988a8f49 100644
--- a/contracts/verifiers/RequestDisableable.sol
+++ b/contracts/verifiers/RequestDisableable.sol
@@ -1,82 +1,65 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
-import {ZKPVerifierBase} from "./ZKPVerifierBase.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
+import {Verifier} from "./Verifier.sol";
-contract RequestDisableable is ZKPVerifierBase {
+error RequestIsDisabled(uint256 requestId);
+
+contract RequestDisableable is Verifier {
/// @custom:storage-location erc7201:iden3.storage.RequestDisableable
struct RequestDisableStorage {
- mapping(uint64 requestId => bool isDisabled) _requestDisabling;
+ mapping(uint256 requestId => bool isDisabled) _requestDisabling;
}
// keccak256(abi.encode(uint256(keccak256("iden3.storage.RequestDisableable")) - 1)) & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant RequestDisableStorageLocation =
0x70325635d67d74932012fa921ccb2f335d3b1d69e3a487f50d001cc65f531600;
function _getRequestDisableStorage() private pure returns (RequestDisableStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := RequestDisableStorageLocation
}
}
- /// @dev Modifier to check if the ZKP request is enabled
- modifier onlyEnabledRequest(uint64 requestId) {
- require(isZKPRequestEnabled(requestId), "Request is disabled");
+ /// @dev Modifier to check if the request is enabled
+ modifier onlyEnabledRequest(uint256 requestId) {
+ if (!isRequestEnabled(requestId)) {
+ revert RequestIsDisabled(requestId);
+ }
_;
}
- /// @dev Verifies a ZKP response without updating any proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The public inputs for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- /// @param sender The sender on behalf of which the proof is done
- function verifyZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- address sender
- )
- public
- virtual
- override
- onlyEnabledRequest(requestId)
- returns (ICircuitValidator.KeyToInputIndex[] memory)
- {
- return super.verifyZKPResponse(requestId, inputs, a, b, c, sender);
- }
-
- /// @dev Checks if ZKP Request is enabled
- /// @param requestId The ID of the ZKP request
- /// @return True if ZKP Request enabled, otherwise returns false
- function isZKPRequestEnabled(
- uint64 requestId
+ /**
+ * @dev Checks if a request is enabled
+ * @param requestId The ID of the request
+ * @return True if the request enabled, otherwise returns false
+ */
+ function isRequestEnabled(
+ uint256 requestId
) public view virtual checkRequestExistence(requestId, true) returns (bool) {
return !_getRequestDisableStorage()._requestDisabling[requestId];
}
- function _disableZKPRequest(uint64 requestId) internal checkRequestExistence(requestId, true) {
+ function _disableRequest(uint256 requestId) internal checkRequestExistence(requestId, true) {
_getRequestDisableStorage()._requestDisabling[requestId] = true;
}
- function _enableZKPRequest(uint64 requestId) internal checkRequestExistence(requestId, true) {
+ function _enableRequest(uint256 requestId) internal checkRequestExistence(requestId, true) {
_getRequestDisableStorage()._requestDisabling[requestId] = false;
}
function _getRequestIfCanBeVerified(
- uint64 requestId
+ uint256 requestId
)
internal
view
virtual
override
onlyEnabledRequest(requestId)
- returns (IZKPVerifier.ZKPRequest storage)
+ returns (IVerifier.RequestData storage)
{
return super._getRequestIfCanBeVerified(requestId);
}
diff --git a/contracts/verifiers/RequestOwnership.sol b/contracts/verifiers/RequestOwnership.sol
index 194c83d6..397d4ad1 100644
--- a/contracts/verifiers/RequestOwnership.sol
+++ b/contracts/verifiers/RequestOwnership.sol
@@ -1,16 +1,17 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
-import {ZKPVerifierBase} from "./ZKPVerifierBase.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
+import {Verifier} from "./Verifier.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
-abstract contract RequestOwnership is ZKPVerifierBase {
+abstract contract RequestOwnership is Verifier {
/// @custom:storage-location erc7201:iden3.storage.RequestOwnership
struct RequestOwnershipStorage {
- mapping(uint64 requestId => address requestOwner) _requestOwners;
+ mapping(uint256 requestId => address requestOwner) _requestOwners;
}
// keccak256(abi.encode(uint256(keccak256("iden3.storage.RequestOwnership")) - 1)) & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant RequestOwnershipStorageLocation =
0x6209bdc3799f5201408f7a7d4d471bb2a0100353e618451674b93f730b006a00;
@@ -19,53 +20,30 @@ abstract contract RequestOwnership is ZKPVerifierBase {
pure
returns (RequestOwnershipStorage storage $)
{
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := RequestOwnershipStorageLocation
}
}
- /// @dev Modifier to check if the caller is ZKP Request owner
- modifier onlyRequestOwner(uint64 requestId) virtual {
- require(getRequestOwner(requestId) == _msgSender(), "Not a request owner");
- _;
- }
-
- /// @dev Sets a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function setZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public virtual override {
- super.setZKPRequest(requestId, request);
- _setRequestOwner(requestId, _msgSender());
- }
-
/**
- * @dev Set the list of ZKP requests for the list of requestIds in the same order.
- * @param requestIds Request ids of the ZKP requests.
- * @param requests ZKP requests to set.
+ * @dev Get a request owner address
+ * @param requestId The ID of a request
+ * @return The request owner address
*/
- function setZKPRequests(
- uint64[] calldata requestIds,
- ZKPRequest[] calldata requests
- ) public virtual override {
- for (uint256 i = 0; i < requestIds.length; i++) {
- setZKPRequest(requestIds[i], requests[i]);
- }
- }
-
- /// @dev Get a ZKP Request Owner address
- /// @param requestId The ID of a ZKP Request
- /// @return The ZKP Request Owner address
function getRequestOwner(
- uint64 requestId
+ uint256 requestId
) public view virtual checkRequestExistence(requestId, true) returns (address) {
return _getRequestOwnershipStorage()._requestOwners[requestId];
}
+ function _setRequest(IVerifier.Request calldata request) internal virtual override {
+ super._setRequest(request);
+ _setRequestOwner(request.requestId, _msgSender());
+ }
+
function _setRequestOwner(
- uint64 requestId,
+ uint256 requestId,
address requestOwner
) internal checkRequestExistence(requestId, true) {
RequestOwnershipStorage storage $ = _getRequestOwnershipStorage();
diff --git a/contracts/verifiers/UniversalVerifier.sol b/contracts/verifiers/UniversalVerifier.sol
index 6d5882c3..2cdf229b 100644
--- a/contracts/verifiers/UniversalVerifier.sol
+++ b/contracts/verifiers/UniversalVerifier.sol
@@ -2,14 +2,16 @@
pragma solidity 0.8.27;
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
+import {IRequestValidator} from "../interfaces/IRequestValidator.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
import {RequestOwnership} from "./RequestOwnership.sol";
import {RequestDisableable} from "./RequestDisableable.sol";
import {ValidatorWhitelist} from "./ValidatorWhitelist.sol";
-import {ZKPVerifierBase} from "./ZKPVerifierBase.sol";
+import {Verifier} from "./Verifier.sol";
import {IState} from "../interfaces/IState.sol";
+error NotAnOwnerOrRequestOwner(address);
+
/// @title Universal Verifier Contract
/// @notice A contract to manage ZKP (Zero-Knowledge Proof) requests and proofs.
contract UniversalVerifier is
@@ -21,43 +23,63 @@ contract UniversalVerifier is
/**
* @dev Version of contract
*/
- string public constant VERSION = "1.1.5";
+ string public constant VERSION = "2.0.0";
- /// @dev Event emitted upon submitting a ZKP request
- event ZKPResponseSubmitted(uint64 indexed requestId, address indexed caller);
+ /**
+ * @dev Event emitted upon submitting a request
+ */
+ event ResponseSubmitted(uint256 indexed requestId, address indexed caller);
- /// @dev Event emitted upon adding a ZKP request
- event ZKPRequestSet(
- uint64 indexed requestId,
+ /**
+ * @dev Event emitted upon submitting an auth response
+ */
+ event AuthResponseSubmitted(string indexed authMethod, address indexed caller);
+
+ /**
+ * @dev Event emitted upon adding a request
+ */
+ event RequestSet(
+ uint256 indexed requestId,
address indexed requestOwner,
string metadata,
address validator,
- bytes data
+ bytes params
);
- /// @dev Event emitted upon updating a ZKP request
- event ZKPRequestUpdate(
- uint64 indexed requestId,
+ /**
+ * @dev Event emitted upon adding an auth method by the owner
+ */
+ event AuthMethodSet(string indexed authMethod, address validator, bytes params);
+
+ /**
+ * @dev Event emitted upon updating a request
+ */
+ event RequestUpdate(
+ uint256 indexed requestId,
address indexed requestOwner,
string metadata,
address validator,
- bytes data
+ bytes params
);
+ /**
+ * @dev Event emitted upon adding a multiRequest
+ */
+ event MultiRequestSet(uint256 indexed multiRequestId, uint256[] requestIds, uint256[] groupIds);
+
/// @dev Modifier to check if the caller is the contract Owner or ZKP Request Owner
- modifier onlyOwnerOrRequestOwner(uint64 requestId) {
+ modifier onlyOwnerOrRequestOwner(uint256 requestId) {
address sender = _msgSender();
- require(
- sender == getRequestOwner(requestId) || sender == owner(),
- "Not an owner or request owner"
- );
+ if (sender != getRequestOwner(requestId) && sender != owner()) {
+ revert NotAnOwnerOrRequestOwner(sender);
+ }
_;
}
/// @dev Initializes the contract
function initialize(IState state, address owner) public initializer {
__Ownable_init(owner);
- __ZKPVerifierBase_init(state);
+ __Verifier_init(state);
}
/// @dev Version of contract getter
@@ -65,111 +87,66 @@ contract UniversalVerifier is
return VERSION;
}
- /// @dev Sets a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function setZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public override(RequestOwnership, ValidatorWhitelist, ZKPVerifierBase) {
- super.setZKPRequest(requestId, request);
-
- emit ZKPRequestSet(
- requestId,
- _msgSender(),
- request.metadata,
- address(request.validator),
- request.data
- );
- }
-
/**
- * @dev Set the list of ZKP requests for the list of requestIds in the same order.
- * @param requestIds Request ids of the ZKP requests.
- * @param requests ZKP requests to set.
+ * @dev Sets an auth type
+ * @param authMethod The auth type to add
*/
- function setZKPRequests(
- uint64[] calldata requestIds,
- ZKPRequest[] calldata requests
- ) public override(RequestOwnership, ValidatorWhitelist, ZKPVerifierBase) {
- for (uint256 i = 0; i < requestIds.length; i++) {
- setZKPRequest(requestIds[i], requests[i]);
- }
+ function setAuthMethod(IVerifier.AuthMethod calldata authMethod) public override onlyOwner {
+ super.setAuthMethod(authMethod);
+ emit AuthMethodSet(authMethod.authMethod, address(authMethod.validator), authMethod.params);
}
- /// @dev Update a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function updateZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public onlyOwner {
- super._updateZKPRequest(requestId, request);
+ /**
+ * @dev Updates a request
+ * @param request The request data
+ */
+ function updateRequest(IVerifier.Request calldata request) public onlyOwner {
+ super._updateRequest(request);
- emit ZKPRequestUpdate(
- requestId,
+ emit RequestUpdate(
+ request.requestId,
_msgSender(),
request.metadata,
address(request.validator),
- request.data
+ request.params
);
}
- /// @dev Submits a ZKP response and updates proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The input data for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- function submitZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) public override {
- super.submitZKPResponse(requestId, inputs, a, b, c);
- emit ZKPResponseSubmitted(requestId, _msgSender());
+ /**
+ * @dev Sets a multiRequest
+ * @param multiRequest The multiRequest data
+ */
+ function setMultiRequest(
+ IVerifier.MultiRequest calldata multiRequest
+ ) public override checkMultiRequestExistence(multiRequest.multiRequestId, false) {
+ super.setMultiRequest(multiRequest);
+ emit MultiRequestSet(
+ multiRequest.multiRequestId,
+ multiRequest.requestIds,
+ multiRequest.groupIds
+ );
}
/**
- * @dev Submits an array of ZKP responses and updates proofs status
- * @param responses The list of responses including ZKP request ID, ZK proof and metadata
- * @param crossChainProof The list of cross chain proofs from universal resolver (oracle). This
+ * @dev Submits an array of responses and updates proofs status
+ * @param authResponse Auth responses including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This
* includes identities and global states.
*/
- function submitZKPResponseV2(
- IZKPVerifier.ZKPResponse[] memory responses,
- bytes memory crossChainProof
+ function submitResponse(
+ AuthResponse memory authResponse,
+ Response[] memory responses,
+ bytes memory crossChainProofs
) public override {
- super.submitZKPResponseV2(responses, crossChainProof);
+ super.submitResponse(authResponse, responses, crossChainProofs);
+ emit AuthResponseSubmitted(authResponse.authMethod, _msgSender());
+
for (uint256 i = 0; i < responses.length; i++) {
- emit ZKPResponseSubmitted(responses[i].requestId, _msgSender());
+ emit ResponseSubmitted(responses[i].requestId, _msgSender());
}
}
- /// @dev Verifies a ZKP response without updating any proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The public inputs for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- /// @param sender The sender on behalf of which the proof is done
- function verifyZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- address sender
- )
- public
- override(RequestDisableable, ValidatorWhitelist, ZKPVerifierBase)
- returns (ICircuitValidator.KeyToInputIndex[] memory)
- {
- return super.verifyZKPResponse(requestId, inputs, a, b, c, sender);
- }
-
/**
* @dev Sets the state contract address
*/
@@ -177,60 +154,78 @@ contract UniversalVerifier is
_setState(state);
}
- /// @dev Gets multiple ZKP requests within a range (disabled in this contract)
- /// @param startIndex The starting index of the range
- /// @param length The length of the range
- /// @return An array of ZKP requests within the specified range
- function getZKPRequests(
- uint256 startIndex,
- uint256 length
- ) public view override returns (IZKPVerifier.ZKPRequest[] memory) {
- revert("Not implemented in this version");
+ /**
+ * @dev Sets the verifier ID
+ */
+ function setVerifierID(uint256 verifierID) public onlyOwner {
+ _setVerifierID(verifierID);
}
- /// @dev Sets ZKP Request Owner address
- /// @param requestId The ID of the ZKP request
- /// @param requestOwner ZKP Request Owner address
+ /**
+ * @dev Sets the request owner address
+ * @param requestId The ID of the request
+ * @param requestOwner The address of the request owner
+ */
function setRequestOwner(
- uint64 requestId,
+ uint256 requestId,
address requestOwner
) public onlyOwnerOrRequestOwner(requestId) {
_setRequestOwner(requestId, requestOwner);
}
- /// @dev Disables ZKP Request
- /// @param requestId The ID of the ZKP request
- function disableZKPRequest(uint64 requestId) public onlyOwnerOrRequestOwner(requestId) {
- _disableZKPRequest(requestId);
+ /**
+ * @dev Disables Request
+ * @param requestId The ID of the request
+ */
+ function disableRequest(uint256 requestId) public onlyOwnerOrRequestOwner(requestId) {
+ _disableRequest(requestId);
}
- /// @dev Enables ZKP Request
- /// @param requestId The ID of the ZKP request
- function enableZKPRequest(uint64 requestId) public onlyOwnerOrRequestOwner(requestId) {
- _enableZKPRequest(requestId);
+ /**
+ * @dev Enables Request
+ * @param requestId The ID of the request
+ */
+ function enableRequest(uint256 requestId) public onlyOwnerOrRequestOwner(requestId) {
+ _enableRequest(requestId);
}
- /// @dev Add new validator to the whitelist
- /// @param validator Validator address
- function addValidatorToWhitelist(ICircuitValidator validator) public onlyOwner {
+ /**
+ * @dev Adds a validator to the whitelist
+ * @param validator The address of the validator
+ */
+ function addValidatorToWhitelist(IRequestValidator validator) public onlyOwner {
_addValidatorToWhitelist(validator);
}
- /// @dev Remove validator from the whitelist
- /// @param validator Validator address
- function removeValidatorFromWhitelist(ICircuitValidator validator) public onlyOwner {
+ /**
+ * @dev Removes a validator from the whitelist
+ * @param validator The address of the validator
+ */
+ function removeValidatorFromWhitelist(IRequestValidator validator) public onlyOwner {
_removeValidatorFromWhitelist(validator);
}
function _getRequestIfCanBeVerified(
- uint64 requestId
+ uint256 requestId
)
internal
view
- override(RequestDisableable, ValidatorWhitelist, ZKPVerifierBase)
- onlyEnabledRequest(requestId)
- returns (IZKPVerifier.ZKPRequest storage)
+ override(RequestDisableable, ValidatorWhitelist, Verifier)
+ returns (IVerifier.RequestData storage)
{
return super._getRequestIfCanBeVerified(requestId);
}
+
+ function _setRequest(
+ Request calldata request
+ ) internal virtual override(RequestOwnership, ValidatorWhitelist, Verifier) {
+ super._setRequest(request);
+ emit RequestSet(
+ request.requestId,
+ _msgSender(),
+ request.metadata,
+ address(request.validator),
+ request.params
+ );
+ }
}
diff --git a/contracts/verifiers/ValidatorWhitelist.sol b/contracts/verifiers/ValidatorWhitelist.sol
index 49b619d0..5d2dc09c 100644
--- a/contracts/verifiers/ValidatorWhitelist.sol
+++ b/contracts/verifiers/ValidatorWhitelist.sol
@@ -2,17 +2,21 @@
pragma solidity 0.8.27;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {ZKPVerifierBase} from "./ZKPVerifierBase.sol";
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
+import {IRequestValidator} from "../interfaces/IRequestValidator.sol";
+import {Verifier} from "./Verifier.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
-contract ValidatorWhitelist is ZKPVerifierBase {
+error ValidatorIsNotWhitelisted(address validator);
+error ValidatorNotSupportInterface(address validator);
+
+contract ValidatorWhitelist is Verifier {
/// @custom:storage-location erc7201:iden3.storage.ValidatorWhitelist
struct ValidatorWhitelistStorage {
- mapping(ICircuitValidator => bool isApproved) _validatorWhitelist;
+ mapping(IRequestValidator => bool isApproved) _validatorWhitelist;
}
// keccak256(abi.encode(uint256(keccak256("iden3.storage.ValidatorWhitelist")) - 1)) & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
bytes32 private constant ValidatorWhitelistStorageLocation =
0x76aa24e3538905838cc74060b2aa4c054b1e474aacf44741879e1850715e9300;
@@ -21,93 +25,61 @@ contract ValidatorWhitelist is ZKPVerifierBase {
pure
returns (ValidatorWhitelistStorage storage $)
{
+ // solhint-disable-next-line no-inline-assembly
assembly {
$.slot := ValidatorWhitelistStorageLocation
}
}
/// @dev Modifier to check if the validator is whitelisted
- modifier onlyWhitelistedValidator(ICircuitValidator validator) {
- require(isWhitelistedValidator(validator), "Validator is not whitelisted");
+ modifier onlyWhitelistedValidator(IRequestValidator validator) {
+ if (!isWhitelistedValidator(validator)) {
+ revert ValidatorIsNotWhitelisted(address(validator));
+ }
_;
}
- /// @dev Sets a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function setZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public virtual override onlyWhitelistedValidator(request.validator) {
- super.setZKPRequest(requestId, request);
- }
-
/**
- * @dev Set the list of ZKP requests for the list of requestIds in the same order.
- * @param requestIds Request ids of the ZKP requests.
- * @param requests ZKP requests to set.
+ * @dev Checks if validator is whitelisted
+ * @param validator The validator address
+ * @return True if validator is whitelisted, otherwise returns false
*/
- function setZKPRequests(
- uint64[] calldata requestIds,
- ZKPRequest[] calldata requests
- ) public virtual override {
- for (uint256 i = 0; i < requestIds.length; i++) {
- setZKPRequest(requestIds[i], requests[i]);
- }
- }
-
- /// @dev Verifies a ZKP response without updating any proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The public inputs for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- /// @param sender The sender on behalf of which the proof is done
- function verifyZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- address sender
- ) public virtual override returns (ICircuitValidator.KeyToInputIndex[] memory) {
- ICircuitValidator validator = getZKPRequest(requestId).validator;
- require(isWhitelistedValidator(validator), "Validator is not whitelisted");
- return super.verifyZKPResponse(requestId, inputs, a, b, c, sender);
- }
-
- /// @dev Checks if validator is whitelisted
- /// @param validator The validator address
- /// @return True if validator is whitelisted, otherwise returns false
function isWhitelistedValidator(
- ICircuitValidator validator
+ IRequestValidator validator
) public view virtual returns (bool) {
return _getValidatorWhitelistStorage()._validatorWhitelist[validator];
}
- function _addValidatorToWhitelist(ICircuitValidator validator) internal {
- require(
- IERC165(address(validator)).supportsInterface(type(ICircuitValidator).interfaceId),
- "Validator doesn't support relevant interface"
- );
+ function _addValidatorToWhitelist(IRequestValidator validator) internal {
+ if (!IERC165(address(validator)).supportsInterface(type(IRequestValidator).interfaceId)) {
+ revert ValidatorNotSupportInterface(address(validator));
+ }
_getValidatorWhitelistStorage()._validatorWhitelist[validator] = true;
}
- function _removeValidatorFromWhitelist(ICircuitValidator validator) internal {
+ function _removeValidatorFromWhitelist(IRequestValidator validator) internal {
_getValidatorWhitelistStorage()._validatorWhitelist[validator] = false;
}
function _getRequestIfCanBeVerified(
- uint64 requestId
+ uint256 requestId
)
internal
view
virtual
override
- onlyWhitelistedValidator(getZKPRequest(requestId).validator)
- returns (IZKPVerifier.ZKPRequest storage)
+ onlyWhitelistedValidator(getRequest(requestId).validator)
+ returns (IVerifier.RequestData storage)
{
return super._getRequestIfCanBeVerified(requestId);
}
+
+ function _setRequest(Request calldata request) internal virtual override {
+ IRequestValidator validator = request.validator;
+ if (!isWhitelistedValidator(validator)) {
+ revert ValidatorIsNotWhitelisted(address(validator));
+ }
+ super._setRequest(request);
+ }
}
diff --git a/contracts/verifiers/Verifier.sol b/contracts/verifiers/Verifier.sol
new file mode 100644
index 00000000..217d9d37
--- /dev/null
+++ b/contracts/verifiers/Verifier.sol
@@ -0,0 +1,976 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity 0.8.27;
+
+import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
+import {IRequestValidator} from "../interfaces/IRequestValidator.sol";
+import {IAuthValidator} from "../interfaces/IAuthValidator.sol";
+import {IState} from "../interfaces/IState.sol";
+import {IVerifier} from "../interfaces/IVerifier.sol";
+import {GenesisUtils} from "../lib/GenesisUtils.sol";
+
+error AuthMethodNotFound(string authMethod);
+error AuthMethodAlreadyExists(string authMethod);
+error GroupIdNotFound(uint256 groupId);
+error GroupIdAlreadyExists(uint256 groupId);
+error GroupMustHaveAtLeastTwoRequests(uint256 groupID);
+error LinkIDNotTheSameForGroupedRequests();
+error MetadataNotSupportedYet();
+error MultiRequestIdAlreadyExists(uint256 multiRequestId);
+error MultiRequestIdNotFound(uint256 multiRequestId);
+error NullifierSessionIDAlreadyExists(uint256 nullifierSessionID);
+error ResponseFieldAlreadyExists(string responseFieldName);
+error RequestIdAlreadyExists(uint256 requestId);
+error RequestIdNotFound(uint256 requestId);
+error RequestIdNotValid();
+error RequestIdUsesReservedBytes();
+error RequestIdTypeNotValid();
+error RequestShouldNotHaveAGroup(uint256 requestId);
+error UserIDMismatch(uint256 userIDFromAuth, uint256 userIDFromResponse);
+error UserIDNotFound(uint256 userID);
+error UserIDNotLinkedToAddress(uint256 userID, address userAddress);
+error UserNotAuthenticated();
+error ValidatorNotWhitelisted(address validator);
+error VerifierIDIsNotValid(uint256 requestVerifierID, uint256 expectedVerifierID);
+error ChallengeIsInvalid();
+
+abstract contract Verifier is IVerifier, ContextUpgradeable {
+ /// @dev Key to retrieve the linkID from the proof storage
+ string private constant LINKED_PROOF_KEY = "linkID";
+ // keccak256(abi.encodePacked("authV2"))
+ bytes32 private constant AUTHV2_NAME =
+ 0x380ee2d21c7a4607d113dad9e76a0bc90f5325a136d5f0e14b6ccf849d948e25;
+ // keccak256(abi.encodePacked("challenge"))
+ bytes32 private constant CHALLENGE_NAME =
+ 0x62357b294ca756256b576c5da68950c49d0d1823063551ffdcc1dad9d65a07a6;
+
+ struct AuthMethodData {
+ IAuthValidator validator;
+ bytes params;
+ bool isActive;
+ }
+
+ /// @custom:storage-location erc7201:iden3.storage.Verifier
+ struct VerifierStorage {
+ // Information about requests
+ // solhint-disable-next-line
+ mapping(uint256 requestId => mapping(address sender => Proof)) _proofs;
+ mapping(uint256 requestId => IVerifier.RequestData) _requests;
+ uint256[] _requestIds;
+ IState _state;
+ mapping(uint256 groupId => uint256[] requestIds) _groupedRequests;
+ uint256[] _groupIds;
+ // Information about multiRequests
+ mapping(uint256 multiRequestId => IVerifier.MultiRequest) _multiRequests;
+ uint256[] _multiRequestIds;
+ // Information about auth methods and validators
+ string[] _authMethodsNames;
+ mapping(string authMethod => AuthMethodData) _authMethods;
+ mapping(uint256 nullifierSessionID => uint256 requestId) _nullifierSessionIDs;
+ // verifierID to check in requests
+ uint256 _verifierID;
+ }
+
+ /**
+ * @dev Struct to store proof and associated data
+ */
+ struct Proof {
+ bool isVerified;
+ mapping(string key => uint256 inputValue) storageFields;
+ string validatorVersion;
+ uint256 blockTimestamp;
+ string[] storageFieldNames;
+ // introduce artificial shift + 1 to avoid 0 index
+ mapping(string key => uint256 keyIndex) storageFieldIndexes;
+ uint256[44] __gap;
+ }
+
+ // keccak256(abi.encode(uint256(keccak256("iden3.storage.Verifier")) -1 )) & ~bytes32(uint256(0xff));
+ // solhint-disable-next-line const-name-snakecase
+ bytes32 internal constant VerifierStorageLocation =
+ 0x11369addde4aae8af30dcf56fa25ad3d864848d3201d1e9197f8b4da18a51a00;
+
+ function _getVerifierStorage() private pure returns (VerifierStorage storage $) {
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ $.slot := VerifierStorageLocation
+ }
+ }
+
+ bytes2 internal constant VERIFIER_ID_TYPE = 0x01A1;
+
+ /**
+ * @dev Modifier to check if the request exists
+ */
+ modifier checkRequestExistence(uint256 requestId, bool existence) {
+ if (existence) {
+ if (!requestIdExists(requestId)) {
+ revert RequestIdNotFound(requestId);
+ }
+ } else {
+ if (requestIdExists(requestId)) {
+ revert RequestIdAlreadyExists(requestId);
+ }
+ }
+ _;
+ }
+
+ /**
+ * @dev Modifier to check if the multiRequest exists
+ */
+ modifier checkMultiRequestExistence(uint256 multiRequestId, bool existence) {
+ if (existence) {
+ if (!multiRequestIdExists(multiRequestId)) {
+ revert MultiRequestIdNotFound(multiRequestId);
+ }
+ } else {
+ if (multiRequestIdExists(multiRequestId)) {
+ revert MultiRequestIdAlreadyExists(multiRequestId);
+ }
+ }
+ _;
+ }
+
+ /**
+ * @dev Modifier to check if the auth type exists
+ */
+ modifier checkAuthMethodExistence(string memory authMethod, bool existence) {
+ if (existence) {
+ if (!authMethodExists(authMethod)) {
+ revert AuthMethodNotFound(authMethod);
+ }
+ } else {
+ if (authMethodExists(authMethod)) {
+ revert AuthMethodAlreadyExists(authMethod);
+ }
+ }
+ _;
+ }
+
+ /**
+ * @dev Checks if a request ID exists
+ * @param requestId The ID of the request
+ * @return Whether the request ID exists
+ */
+ function requestIdExists(uint256 requestId) public view returns (bool) {
+ return
+ _getVerifierStorage()._requests[requestId].validator != IRequestValidator(address(0));
+ }
+
+ /**
+ * @dev Checks if a group ID exists
+ * @param groupId The ID of the group
+ * @return Whether the group ID exists
+ */
+ function groupIdExists(uint256 groupId) public view returns (bool) {
+ return _getVerifierStorage()._groupedRequests[groupId].length != 0;
+ }
+
+ /**
+ * @dev Checks if a multiRequest ID exists
+ * @param multiRequestId The ID of the multiRequest
+ * @return Whether the multiRequest ID exists
+ */
+ function multiRequestIdExists(uint256 multiRequestId) public view returns (bool) {
+ return
+ _getVerifierStorage()._multiRequests[multiRequestId].multiRequestId == multiRequestId;
+ }
+
+ /**
+ * @dev Checks if an auth method exists
+ * @param authMethod The auth method
+ * @return Whether the auth type exists
+ */
+ function authMethodExists(string memory authMethod) public view returns (bool) {
+ return
+ _getVerifierStorage()._authMethods[authMethod].validator != IAuthValidator(address(0));
+ }
+
+ /**
+ * @dev Sets different requests
+ * @param requests The list of requests
+ */
+ function setRequests(IVerifier.Request[] calldata requests) public {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ uint256 newGroupsCount = 0;
+ uint256[] memory newGroupsGroupID = new uint256[](requests.length);
+ uint256[] memory newGroupsRequestCount = new uint256[](requests.length);
+
+ // 1. Check first that groupIds don't exist and keep the number of requests per group.
+ for (uint256 i = 0; i < requests.length; i++) {
+ uint256 groupID = requests[i]
+ .validator
+ .getRequestParams(requests[i].params)[
+ requests[i].validator.requestParamIndexOf("groupID")
+ ].value;
+
+ if (groupID != 0) {
+ if (groupIdExists(groupID)) {
+ revert GroupIdAlreadyExists(groupID);
+ }
+
+ (bool exists, uint256 groupIDIndex) = _getGroupIDIndex(
+ groupID,
+ newGroupsGroupID,
+ newGroupsCount
+ );
+
+ if (!exists) {
+ newGroupsGroupID[newGroupsCount] = groupID;
+ newGroupsRequestCount[newGroupsCount]++;
+ newGroupsCount++;
+ } else {
+ newGroupsRequestCount[groupIDIndex]++;
+ }
+ }
+ }
+
+ _checkGroupsRequestsCount(newGroupsGroupID, newGroupsRequestCount, newGroupsCount);
+
+ // 2. Set requests checking groups and nullifierSessionID uniqueness
+ for (uint256 i = 0; i < requests.length; i++) {
+ _checkRequestIdCorrectness(requests[i].requestId, requests[i].params);
+
+ _checkNullifierSessionIdUniqueness(requests[i]);
+ _checkVerifierID(requests[i]);
+
+ uint256 groupID = requests[i]
+ .validator
+ .getRequestParams(requests[i].params)[
+ requests[i].validator.requestParamIndexOf("groupID")
+ ].value;
+ _setRequest(requests[i]);
+
+ // request with group
+ if (groupID != 0) {
+ // request with group
+ if (!groupIdExists(groupID)) {
+ s._groupIds.push(groupID);
+ }
+
+ s._groupedRequests[groupID].push(requests[i].requestId);
+ }
+ }
+ }
+
+ /**
+ * @dev Gets a specific request by ID
+ * @param requestId The ID of the request
+ * @return request The request info
+ */
+ function getRequest(
+ uint256 requestId
+ ) public view checkRequestExistence(requestId, true) returns (RequestInfo memory request) {
+ VerifierStorage storage $ = _getVerifierStorage();
+ IVerifier.RequestData storage rd = $._requests[requestId];
+ return
+ IVerifier.RequestInfo({
+ requestId: requestId,
+ metadata: rd.metadata,
+ validator: rd.validator,
+ params: rd.params,
+ creator: rd.creator
+ });
+ }
+
+ /**
+ * @dev Sets a multiRequest
+ * @param multiRequest The multiRequest data
+ */
+ function setMultiRequest(
+ IVerifier.MultiRequest calldata multiRequest
+ ) public virtual checkMultiRequestExistence(multiRequest.multiRequestId, false) {
+ VerifierStorage storage s = _getVerifierStorage();
+ s._multiRequests[multiRequest.multiRequestId] = multiRequest;
+ s._multiRequestIds.push(multiRequest.multiRequestId);
+
+ // checks for all the requests in this multiRequest
+ _checkRequestsInMultiRequest(multiRequest.multiRequestId);
+ }
+
+ /**
+ * @dev Gets a specific multiRequest by ID
+ * @param multiRequestId The ID of the multiRequest
+ * @return multiRequest The multiRequest data
+ */
+ function getMultiRequest(
+ uint256 multiRequestId
+ )
+ public
+ view
+ checkMultiRequestExistence(multiRequestId, true)
+ returns (IVerifier.MultiRequest memory multiRequest)
+ {
+ return _getVerifierStorage()._multiRequests[multiRequestId];
+ }
+
+ /**
+ * @dev Submits an array of responses and updates proofs status
+ * @param authResponse Auth response including auth type and proof
+ * @param responses The list of responses including request ID, proof and metadata for requests
+ * @param crossChainProofs The list of cross chain proofs from universal resolver (oracle). This
+ * includes identities and global states.
+ */
+ function submitResponse(
+ AuthResponse memory authResponse,
+ Response[] memory responses,
+ bytes memory crossChainProofs
+ ) public virtual {
+ VerifierStorage storage $ = _getVerifierStorage();
+ address sender = _msgSender();
+
+ // 1. Process crossChainProofs
+ $._state.processCrossChainProofs(crossChainProofs);
+
+ uint256 userIDFromAuthResponse;
+ AuthMethodData storage authMethodData = $._authMethods[authResponse.authMethod];
+
+ // 2. Authenticate user and get userID
+ IAuthValidator.AuthResponseField[] memory authResponseFields;
+ (userIDFromAuthResponse, authResponseFields) = authMethodData.validator.verify(
+ sender,
+ authResponse.proof,
+ authMethodData.params
+ );
+
+ if (keccak256(abi.encodePacked(authResponse.authMethod)) == AUTHV2_NAME) {
+ if (
+ authResponseFields.length > 0 &&
+ keccak256(abi.encodePacked(authResponseFields[0].name)) == CHALLENGE_NAME
+ ) {
+ bytes32 expectedNonce = keccak256(abi.encode(sender, responses)) &
+ 0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
+ if (expectedNonce != bytes32(authResponseFields[0].value)) {
+ revert ChallengeIsInvalid();
+ }
+ }
+ }
+
+ if (userIDFromAuthResponse == 0) {
+ revert UserNotAuthenticated();
+ }
+
+ // 3. Verify all the responses, check userID from signals and write proof results,
+ // emit events (existing logic)
+ for (uint256 i = 0; i < responses.length; i++) {
+ IVerifier.Response memory response = responses[i];
+ IVerifier.RequestData storage request = _getRequestIfCanBeVerified(response.requestId);
+
+ IRequestValidator.ResponseField[] memory signals = request.validator.verify(
+ sender,
+ response.proof,
+ request.params
+ );
+
+ // Check if userID from authResponse is the same as the one in the signals
+ _checkUserIDMatch(userIDFromAuthResponse, signals);
+
+ _writeProofResults(response.requestId, sender, signals);
+
+ if (response.metadata.length > 0) {
+ revert MetadataNotSupportedYet();
+ }
+ }
+ }
+
+ /**
+ * @dev Sets an auth method
+ * @param authMethod The auth method to add
+ */
+ function setAuthMethod(
+ IVerifier.AuthMethod calldata authMethod
+ ) public virtual checkAuthMethodExistence(authMethod.authMethod, false) {
+ VerifierStorage storage s = _getVerifierStorage();
+ s._authMethodsNames.push(authMethod.authMethod);
+ s._authMethods[authMethod.authMethod] = AuthMethodData({
+ validator: authMethod.validator,
+ params: authMethod.params,
+ isActive: true
+ });
+ }
+
+ /**
+ * @dev Disables an auth method
+ * @param authMethod The auth method to disable
+ */
+ function disableAuthMethod(
+ string calldata authMethod
+ ) public checkAuthMethodExistence(authMethod, true) {
+ VerifierStorage storage s = _getVerifierStorage();
+ s._authMethods[authMethod].isActive = false;
+ }
+
+ /**
+ * @dev Enables an auth type
+ * @param authMethod The auth type to enable
+ */
+ function enableAuthMethod(
+ string calldata authMethod
+ ) public checkAuthMethodExistence(authMethod, true) {
+ VerifierStorage storage s = _getVerifierStorage();
+ s._authMethods[authMethod].isActive = true;
+ }
+
+ /**
+ * @dev Gets an auth type
+ * @param authMethod The Id of the auth type to get
+ * @return authMethodData The auth type data
+ */
+ function getAuthMethod(
+ string calldata authMethod
+ )
+ public
+ view
+ checkAuthMethodExistence(authMethod, true)
+ returns (AuthMethodData memory authMethodData)
+ {
+ return _getVerifierStorage()._authMethods[authMethod];
+ }
+
+ /**
+ * @dev Gets response field value
+ * @param requestId Id of the request
+ * @param sender Address of the user
+ * @param responseFieldName Name of the response field to get
+ */
+ function getResponseFieldValue(
+ uint256 requestId,
+ address sender,
+ string memory responseFieldName
+ ) public view checkRequestExistence(requestId, true) returns (uint256) {
+ VerifierStorage storage s = _getVerifierStorage();
+ return s._proofs[requestId][sender].storageFields[responseFieldName];
+ }
+
+ /**
+ * @dev Gets proof storage response fields
+ * @param requestId Id of the request
+ * @param sender Address of the user
+ */
+ function getResponseFields(
+ uint256 requestId,
+ address sender
+ ) public view returns (IRequestValidator.ResponseField[] memory) {
+ VerifierStorage storage s = _getVerifierStorage();
+ Proof storage proof = s._proofs[requestId][sender];
+
+ IRequestValidator.ResponseField[]
+ memory responseFields = new IRequestValidator.ResponseField[](
+ proof.storageFieldNames.length
+ );
+
+ for (uint256 i = 0; i < proof.storageFieldNames.length; i++) {
+ responseFields[i] = IRequestValidator.ResponseField({
+ name: proof.storageFieldNames[i],
+ value: proof.storageFields[proof.storageFieldNames[i]]
+ });
+ }
+
+ return responseFields;
+ }
+
+ /**
+ * @dev Gets the status of the multiRequest verification
+ * @param multiRequestId The ID of the multiRequest
+ * @param userAddress The address of the user
+ * @return status The status of the multiRequest. "True" if all requests are verified, "false" otherwise
+ */
+ function getMultiRequestProofsStatus(
+ uint256 multiRequestId,
+ address userAddress
+ )
+ public
+ view
+ checkMultiRequestExistence(multiRequestId, true)
+ returns (IVerifier.RequestProofStatus[] memory)
+ {
+ // 1. Check if all requests statuses are true for the userAddress
+ IVerifier.RequestProofStatus[] memory requestProofStatus = _getMultiRequestProofsStatus(
+ multiRequestId,
+ userAddress
+ );
+
+ // 2. Check if all linked response fields are the same
+ bool linkedResponsesOK = _checkLinkedResponseFields(multiRequestId, userAddress);
+
+ if (!linkedResponsesOK) {
+ revert LinkIDNotTheSameForGroupedRequests();
+ }
+
+ return requestProofStatus;
+ }
+
+ /**
+ * @dev Checks if the proofs from a Multirequest submitted for a given sender and request ID are verified
+ * @param multiRequestId The ID of the multiRequest
+ * @param userAddress The address of the user
+ * @return status The status of the multiRequest. "True" if all requests are verified, "false" otherwise
+ */
+ function areMultiRequestProofsVerified(
+ uint256 multiRequestId,
+ address userAddress
+ ) public view checkMultiRequestExistence(multiRequestId, true) returns (bool) {
+ // 1. Check if all requests are verified for the userAddress
+ bool verified = _areMultiRequestProofsVerified(multiRequestId, userAddress);
+
+ if (verified) {
+ // 2. Check if all linked response fields are the same
+ bool linkedResponsesOK = _checkLinkedResponseFields(multiRequestId, userAddress);
+
+ if (!linkedResponsesOK) {
+ verified = false;
+ }
+ }
+
+ return verified;
+ }
+
+ /**
+ * @dev Checks if a proof from a request submitted for a given sender and request ID is verified
+ * @param sender The sender's address
+ * @param requestId The ID of the request
+ * @return True if proof is verified
+ */
+ function isRequestProofVerified(
+ address sender,
+ uint256 requestId
+ ) public view checkRequestExistence(requestId, true) returns (bool) {
+ VerifierStorage storage s = _getVerifierStorage();
+ return s._proofs[requestId][sender].isVerified;
+ }
+
+ /**
+ * @dev Get the requests count.
+ * @return Requests count.
+ */
+ function getRequestsCount() public view returns (uint256) {
+ return _getVerifierStorage()._requestIds.length;
+ }
+
+ /**
+ * @dev Get the group of requests count.
+ * @return Group of requests count.
+ */
+ function getGroupsCount() public view returns (uint256) {
+ return _getVerifierStorage()._groupIds.length;
+ }
+
+ /**
+ * @dev Get the group of requests.
+ * @return Group of requests.
+ */
+ function getGroupedRequests(
+ uint256 groupID
+ ) public view returns (IVerifier.RequestInfo[] memory) {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ IVerifier.RequestInfo[] memory requests = new IVerifier.RequestInfo[](
+ s._groupedRequests[groupID].length
+ );
+
+ for (uint256 i = 0; i < s._groupedRequests[groupID].length; i++) {
+ uint256 requestId = s._groupedRequests[groupID][i];
+ IVerifier.RequestData storage rd = s._requests[requestId];
+
+ requests[i] = IVerifier.RequestInfo({
+ requestId: requestId,
+ metadata: rd.metadata,
+ validator: rd.validator,
+ params: rd.params,
+ creator: rd.creator
+ });
+ }
+
+ return requests;
+ }
+
+ /**
+ * @dev Gets the address of the state contract linked to the verifier
+ * @return address State contract address
+ */
+ function getStateAddress() public view virtual returns (address) {
+ return address(_getVerifierStorage()._state);
+ }
+
+ /**
+ * @dev Gets the verifierID of the verifier contract
+ * @return uint256 verifierID of the verifier contract
+ */
+ function getVerifierID() public view virtual returns (uint256) {
+ return _getVerifierStorage()._verifierID;
+ }
+
+ /**
+ * @dev Checks the proof status for a given user and request ID
+ * @param sender The sender's address
+ * @param requestId The ID of the ZKP request
+ * @return The proof status structure
+ */
+ function getRequestProofStatus(
+ address sender,
+ uint256 requestId
+ )
+ public
+ view
+ checkRequestExistence(requestId, true)
+ returns (IVerifier.RequestProofStatus memory)
+ {
+ VerifierStorage storage s = _getVerifierStorage();
+ Proof storage proof = s._proofs[requestId][sender];
+
+ return
+ IVerifier.RequestProofStatus(
+ requestId,
+ proof.isVerified,
+ proof.validatorVersion,
+ proof.blockTimestamp
+ );
+ }
+
+ function _setState(IState state) internal {
+ _getVerifierStorage()._state = state;
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function __Verifier_init(IState state) internal onlyInitializing {
+ __Verifier_init_unchained(state);
+ }
+
+ // solhint-disable-next-line func-name-mixedcase
+ function __Verifier_init_unchained(IState state) internal onlyInitializing {
+ _setState(state);
+ // initial calculation of verifierID from contract address and verifier id type defined
+ uint256 calculatedVerifierID = GenesisUtils.calcIdFromEthAddress(
+ VERIFIER_ID_TYPE,
+ address(this)
+ );
+ _setVerifierID(calculatedVerifierID);
+ }
+
+ function _setVerifierID(uint256 verifierID) internal {
+ VerifierStorage storage s = _getVerifierStorage();
+ s._verifierID = verifierID;
+ }
+
+ function _setRequest(
+ Request calldata request
+ ) internal virtual checkRequestExistence(request.requestId, false) {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ s._requests[request.requestId] = IVerifier.RequestData({
+ metadata: request.metadata,
+ validator: request.validator,
+ params: request.params,
+ creator: _msgSender()
+ });
+ s._requestIds.push(request.requestId);
+ }
+
+ function _checkVerifierID(IVerifier.Request calldata request) internal view {
+ VerifierStorage storage s = _getVerifierStorage();
+ uint256 requestVerifierID = request
+ .validator
+ .getRequestParams(request.params)[request.validator.requestParamIndexOf("verifierID")]
+ .value;
+
+ if (requestVerifierID != 0) {
+ if (requestVerifierID != s._verifierID) {
+ revert VerifierIDIsNotValid(requestVerifierID, s._verifierID);
+ }
+ }
+ }
+
+ function _getRequestType(uint256 requestId) internal pure returns (uint16) {
+ // 0x0000000000000000 - prefix for old uint64 requests
+ // 0x0001000000000000 - prefix for keccak256 cut to fit in the remaining 192 bits
+ return uint16(requestId >> 240);
+ }
+
+ function _checkRequestIdCorrectness(
+ uint256 requestId,
+ bytes calldata requestParams
+ ) internal pure {
+ // 1. Check prefix
+ uint16 requestType = _getRequestType(requestId);
+ if (requestType >= 2) {
+ revert RequestIdTypeNotValid();
+ }
+ // 2. Check reserved bytes
+ if (((requestId << 16) >> 216) > 0) {
+ revert RequestIdUsesReservedBytes();
+ }
+ // 3. Check if requestId matches the hash of the requestParams
+ // 0x0000000000000000FFFF...FF. Reserved first 8 bytes for the request Id type and future use
+ // 0x00010000000000000000...00. First 2 bytes for the request Id type
+ // - 0x0000... for old request Ids with uint64
+ // - 0x0001... for new request Ids with uint256
+ if (requestType == 1) {
+ uint256 hashValue = uint256(keccak256(requestParams));
+ if (
+ requestId !=
+ (hashValue & 0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) +
+ 0x0001000000000000000000000000000000000000000000000000000000000000
+ ) {
+ revert RequestIdNotValid();
+ }
+ }
+ }
+
+ function _checkNullifierSessionIdUniqueness(IVerifier.Request calldata request) internal {
+ VerifierStorage storage s = _getVerifierStorage();
+ uint256 nullifierSessionID = request
+ .validator
+ .getRequestParams(request.params)[
+ request.validator.requestParamIndexOf("nullifierSessionID")
+ ].value;
+ if (nullifierSessionID != 0) {
+ if (s._nullifierSessionIDs[nullifierSessionID] != 0) {
+ revert NullifierSessionIDAlreadyExists(nullifierSessionID);
+ }
+ s._nullifierSessionIDs[nullifierSessionID] = nullifierSessionID;
+ }
+ }
+
+ function _getGroupIDIndex(
+ uint256 groupID,
+ uint256[] memory groupList,
+ uint256 listCount
+ ) internal pure returns (bool, uint256) {
+ for (uint256 j = 0; j < listCount; j++) {
+ if (groupList[j] == groupID) {
+ return (true, j);
+ }
+ }
+
+ return (false, 0);
+ }
+
+ function _checkGroupsRequestsCount(
+ uint256[] memory groupList,
+ uint256[] memory groupRequestsList,
+ uint256 groupsCount
+ ) internal pure {
+ for (uint256 i = 0; i < groupsCount; i++) {
+ if (groupRequestsList[i] < 2) {
+ revert GroupMustHaveAtLeastTwoRequests(groupList[i]);
+ }
+ }
+ }
+
+ function _checkRequestsInMultiRequest(uint256 multiRequestId) internal view {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ uint256[] memory requestIds = s._multiRequests[multiRequestId].requestIds;
+ uint256[] memory groupIds = s._multiRequests[multiRequestId].groupIds;
+
+ // check that all the single requests doesn't have group
+ for (uint256 i = 0; i < requestIds.length; i++) {
+ if (!requestIdExists(requestIds[i])) {
+ revert RequestIdNotFound(requestIds[i]);
+ }
+ uint256 groupID = s
+ ._requests[requestIds[i]]
+ .validator
+ .getRequestParams(s._requests[requestIds[i]].params)[
+ s._requests[requestIds[i]].validator.requestParamIndexOf("groupID")
+ ].value;
+
+ if (groupID != 0) {
+ revert RequestShouldNotHaveAGroup(requestIds[i]);
+ }
+ }
+
+ for (uint256 i = 0; i < groupIds.length; i++) {
+ if (!groupIdExists(groupIds[i])) {
+ revert GroupIdNotFound(groupIds[i]);
+ }
+ }
+ }
+
+ function _checkUserIDMatch(
+ uint256 userIDFromAuthResponse,
+ IRequestValidator.ResponseField[] memory signals
+ ) internal pure {
+ for (uint256 j = 0; j < signals.length; j++) {
+ if (
+ keccak256(abi.encodePacked(signals[j].name)) ==
+ keccak256(abi.encodePacked("userID"))
+ ) {
+ if (userIDFromAuthResponse != signals[j].value) {
+ revert UserIDMismatch(userIDFromAuthResponse, signals[j].value);
+ }
+ }
+ }
+ }
+
+ /**
+ * @dev Updates a request
+ * @param request The request data
+ */
+ function _updateRequest(
+ IVerifier.Request calldata request
+ ) internal checkRequestExistence(request.requestId, true) {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ s._requests[request.requestId] = IVerifier.RequestData({
+ metadata: request.metadata,
+ validator: request.validator,
+ params: request.params,
+ creator: _msgSender()
+ });
+ }
+
+ function _checkLinkedResponseFields(
+ uint256 multiRequestId,
+ address sender
+ ) internal view returns (bool) {
+ VerifierStorage storage s = _getVerifierStorage();
+
+ for (uint256 i = 0; i < s._multiRequests[multiRequestId].groupIds.length; i++) {
+ uint256 groupId = s._multiRequests[multiRequestId].groupIds[i];
+
+ // Check linkID in the same group or requests is the same
+ uint256 requestLinkID = getResponseFieldValue(
+ s._groupedRequests[groupId][0],
+ sender,
+ LINKED_PROOF_KEY
+ );
+ for (uint256 j = 1; j < s._groupedRequests[groupId].length; j++) {
+ uint256 requestLinkIDToCompare = getResponseFieldValue(
+ s._groupedRequests[groupId][j],
+ sender,
+ LINKED_PROOF_KEY
+ );
+ if (requestLinkID != requestLinkIDToCompare) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function _getMultiRequestProofsStatus(
+ uint256 multiRequestId,
+ address userAddress
+ ) internal view returns (IVerifier.RequestProofStatus[] memory) {
+ VerifierStorage storage s = _getVerifierStorage();
+ IVerifier.MultiRequest storage multiRequest = s._multiRequests[multiRequestId];
+
+ uint256 lengthGroupIds;
+
+ if (multiRequest.groupIds.length > 0) {
+ for (uint256 i = 0; i < multiRequest.groupIds.length; i++) {
+ uint256 groupId = multiRequest.groupIds[i];
+ lengthGroupIds += s._groupedRequests[groupId].length;
+ }
+ }
+
+ IVerifier.RequestProofStatus[]
+ memory requestProofStatus = new IVerifier.RequestProofStatus[](
+ multiRequest.requestIds.length + lengthGroupIds
+ );
+
+ for (uint256 i = 0; i < multiRequest.requestIds.length; i++) {
+ uint256 requestId = multiRequest.requestIds[i];
+
+ requestProofStatus[i] = IVerifier.RequestProofStatus({
+ requestId: requestId,
+ isVerified: s._proofs[requestId][userAddress].isVerified,
+ validatorVersion: s._proofs[requestId][userAddress].validatorVersion,
+ timestamp: s._proofs[requestId][userAddress].blockTimestamp
+ });
+ }
+
+ for (uint256 i = 0; i < multiRequest.groupIds.length; i++) {
+ uint256 groupId = multiRequest.groupIds[i];
+
+ for (uint256 j = 0; j < s._groupedRequests[groupId].length; j++) {
+ uint256 requestId = s._groupedRequests[groupId][j];
+
+ requestProofStatus[multiRequest.requestIds.length + j] = IVerifier
+ .RequestProofStatus({
+ requestId: requestId,
+ isVerified: s._proofs[requestId][userAddress].isVerified,
+ validatorVersion: s._proofs[requestId][userAddress].validatorVersion,
+ timestamp: s._proofs[requestId][userAddress].blockTimestamp
+ });
+ }
+ }
+
+ return requestProofStatus;
+ }
+
+ function _areMultiRequestProofsVerified(
+ uint256 multiRequestId,
+ address userAddress
+ ) internal view returns (bool) {
+ VerifierStorage storage s = _getVerifierStorage();
+ IVerifier.MultiRequest storage multiRequest = s._multiRequests[multiRequestId];
+
+ for (uint256 i = 0; i < multiRequest.requestIds.length; i++) {
+ uint256 requestId = multiRequest.requestIds[i];
+
+ if (!s._proofs[requestId][userAddress].isVerified) {
+ return false;
+ }
+ }
+
+ for (uint256 i = 0; i < multiRequest.groupIds.length; i++) {
+ uint256 groupId = multiRequest.groupIds[i];
+
+ for (uint256 j = 0; j < s._groupedRequests[groupId].length; j++) {
+ uint256 requestId = s._groupedRequests[groupId][j];
+
+ if (!s._proofs[requestId][userAddress].isVerified) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function _getRequestIfCanBeVerified(
+ uint256 requestId
+ )
+ internal
+ view
+ virtual
+ checkRequestExistence(requestId, true)
+ returns (IVerifier.RequestData storage)
+ {
+ VerifierStorage storage $ = _getVerifierStorage();
+ return $._requests[requestId];
+ }
+
+ /**
+ * @dev Writes proof results.
+ * @param requestId The request ID of the proof
+ * @param sender The address of the sender of the proof
+ * @param responseFields The array of response fields of the proof
+ */
+ function _writeProofResults(
+ uint256 requestId,
+ address sender,
+ IRequestValidator.ResponseField[] memory responseFields
+ ) internal {
+ VerifierStorage storage s = _getVerifierStorage();
+ Proof storage proof = s._proofs[requestId][sender];
+
+ // We only keep only 1 proof now without history. Prepared for the future if needed.
+ for (uint256 i = 0; i < responseFields.length; i++) {
+ proof.storageFields[responseFields[i].name] = responseFields[i].value;
+ if (proof.storageFieldIndexes[responseFields[i].name] == 0) {
+ proof.storageFieldNames.push(responseFields[i].name);
+ proof.storageFieldIndexes[responseFields[i].name] = proof.storageFieldNames.length;
+ } else {
+ revert ResponseFieldAlreadyExists(responseFields[i].name);
+ }
+ }
+
+ proof.isVerified = true;
+ proof.validatorVersion = s._requests[requestId].validator.version();
+ proof.blockTimestamp = block.timestamp;
+ }
+}
diff --git a/contracts/verifiers/ZKPVerifier.sol b/contracts/verifiers/ZKPVerifier.sol
deleted file mode 100644
index e440d23c..00000000
--- a/contracts/verifiers/ZKPVerifier.sol
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {EmbeddedZKPVerifier} from "./EmbeddedZKPVerifier.sol";
-
-/**
- * @dev The ZKPVerifier is deprecated and will be removed in the future major versions
- * Please use EmbeddedZKPVerifier instead
- */
-contract ZKPVerifier is EmbeddedZKPVerifier {}
diff --git a/contracts/verifiers/ZKPVerifierBase.sol b/contracts/verifiers/ZKPVerifierBase.sol
deleted file mode 100644
index a128d172..00000000
--- a/contracts/verifiers/ZKPVerifierBase.sol
+++ /dev/null
@@ -1,344 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-pragma solidity 0.8.27;
-
-import {IZKPVerifier} from "../interfaces/IZKPVerifier.sol";
-import {ICircuitValidator} from "../interfaces/ICircuitValidator.sol";
-import {ArrayUtils} from "../lib/ArrayUtils.sol";
-import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
-import {IState} from "../interfaces/IState.sol";
-import {VerifierLib} from "../lib/VerifierLib.sol";
-
-abstract contract ZKPVerifierBase is IZKPVerifier, ContextUpgradeable {
- struct Metadata {
- string key;
- bytes value;
- }
-
- /// @custom:storage-location erc7201:iden3.storage.ZKPVerifier
- struct ZKPVerifierStorage {
- mapping(address user => mapping(uint64 requestId => VerifierLib.Proof)) _proofs;
- mapping(uint64 requestId => IZKPVerifier.ZKPRequest) _requests;
- uint64[] _requestIds;
- IState _state;
- }
-
- // keccak256(abi.encode(uint256(keccak256("iden3.storage.ZKPVerifier")) - 1)) & ~bytes32(uint256(0xff));
- bytes32 internal constant ZKPVerifierStorageLocation =
- 0x512d18c55869273fec77e70d8a8586e3fb133e90f1db24c6bcf4ff3506ef6a00;
-
- /// @dev Get the main storage using assembly to ensure specific storage location
- function _getZKPVerifierStorage() private pure returns (ZKPVerifierStorage storage $) {
- assembly {
- $.slot := ZKPVerifierStorageLocation
- }
- }
-
- function _setState(IState state) internal {
- _getZKPVerifierStorage()._state = state;
- }
-
- using VerifierLib for ZKPVerifierStorage;
-
- function __ZKPVerifierBase_init(IState state) internal onlyInitializing {
- __ZKPVerifierBase_init_unchained(state);
- }
-
- function __ZKPVerifierBase_init_unchained(IState state) internal onlyInitializing {
- _setState(state);
- }
-
- /**
- * @dev Max return array length for request queries
- */
- uint256 public constant REQUESTS_RETURN_LIMIT = 1000;
-
- /// @dev Key to retrieve the linkID from the proof storage
- string constant LINKED_PROOF_KEY = "linkID";
-
- /// @dev Linked proof custom error
- error LinkedProofError(
- string message,
- uint64 requestId,
- uint256 linkID,
- uint64 requestIdToCompare,
- uint256 linkIdToCompare
- );
-
- /// @dev Modifier to check if the validator is set for the request
- modifier checkRequestExistence(uint64 requestId, bool existence) {
- if (existence) {
- require(requestIdExists(requestId), "request id doesn't exist");
- } else {
- require(!requestIdExists(requestId), "request id already exists");
- }
- _;
- }
-
- /// @dev Sets a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function setZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) public virtual checkRequestExistence(requestId, false) {
- ZKPVerifierStorage storage s = _getZKPVerifierStorage();
- s._requests[requestId] = request;
- s._requestIds.push(requestId);
- }
-
- /**
- * @dev Set the ZKP request for the requestId.
- * @param requestIds Request ids of the ZKP requests.
- * @param requests ZKP requests to set.
- */
- function setZKPRequests(
- uint64[] calldata requestIds,
- ZKPRequest[] calldata requests
- ) public virtual {
- require(requestIds.length == requests.length, "Request IDs and requests length mismatch");
-
- for (uint256 i = 0; i < requestIds.length; i++) {
- setZKPRequest(requestIds[i], requests[i]);
- }
- }
-
- /// @notice Submits a ZKP response and updates proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The input data for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- function submitZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c
- ) public virtual {
- address sender = _msgSender();
- ZKPVerifierStorage storage $ = _getZKPVerifierStorage();
-
- IZKPVerifier.ZKPRequest storage request = _getRequestIfCanBeVerified(requestId);
- ICircuitValidator.KeyToInputIndex[] memory keyToInpIdxs = request.validator.verify(
- inputs,
- a,
- b,
- c,
- request.data,
- sender
- );
-
- $.writeProofResults(sender, requestId, keyToInpIdxs, inputs);
- }
-
- /// @notice Submits a ZKP response V2 and updates proof status
- /// @param responses The list of responses including ZKP request ID, ZK proof and metadata
- /// @param crossChainProofs The list of cross chain proofs from universal resolver (oracle)
- function submitZKPResponseV2(
- IZKPVerifier.ZKPResponse[] memory responses,
- bytes memory crossChainProofs
- ) public virtual {
- ZKPVerifierStorage storage $ = _getZKPVerifierStorage();
-
- $._state.processCrossChainProofs(crossChainProofs);
-
- for (uint256 i = 0; i < responses.length; i++) {
- IZKPVerifier.ZKPResponse memory response = responses[i];
-
- address sender = _msgSender();
-
- IZKPVerifier.ZKPRequest storage request = _getRequestIfCanBeVerified(
- response.requestId
- );
- ICircuitValidator.Signal[] memory signals = request.validator.verifyV2(
- response.zkProof,
- request.data,
- sender,
- $._state
- );
-
- $.writeProofResultsV2(sender, response.requestId, signals);
-
- if (response.data.length > 0) {
- revert("Metadata not supported yet");
- }
- }
- }
-
- /// @dev Verifies a ZKP response without updating any proof status
- /// @param requestId The ID of the ZKP request
- /// @param inputs The public inputs for the proof
- /// @param a The first component of the proof
- /// @param b The second component of the proof
- /// @param c The third component of the proof
- /// @param sender The sender on behalf of which the proof is done
- function verifyZKPResponse(
- uint64 requestId,
- uint256[] memory inputs,
- uint256[2] memory a,
- uint256[2][2] memory b,
- uint256[2] memory c,
- address sender
- )
- public
- virtual
- checkRequestExistence(requestId, true)
- returns (ICircuitValidator.KeyToInputIndex[] memory)
- {
- IZKPVerifier.ZKPRequest storage request = _getZKPVerifierStorage()._requests[requestId];
- return request.validator.verify(inputs, a, b, c, request.data, sender);
- }
-
- /// @dev Gets the list of request IDs and verifies the proofs are linked
- /// @param sender the user's address
- /// @param requestIds the list of request IDs
- /// Throws if the proofs are not linked
- function verifyLinkedProofs(address sender, uint64[] calldata requestIds) public view virtual {
- require(requestIds.length > 1, "Linked proof verification needs more than 1 request");
-
- uint256 expectedLinkID = getProofStorageField(sender, requestIds[0], LINKED_PROOF_KEY);
-
- if (expectedLinkID == 0) {
- revert("Can't find linkID for given request Ids and user address");
- }
-
- for (uint256 i = 1; i < requestIds.length; i++) {
- uint256 actualLinkID = getProofStorageField(sender, requestIds[i], LINKED_PROOF_KEY);
-
- if (expectedLinkID != actualLinkID) {
- revert LinkedProofError(
- "Proofs are not linked",
- requestIds[0],
- expectedLinkID,
- requestIds[i],
- actualLinkID
- );
- }
- }
- }
-
- /// @dev Gets a specific ZKP request by ID
- /// @param requestId The ID of the ZKP request
- /// @return zkpRequest The ZKP request data
- function getZKPRequest(
- uint64 requestId
- )
- public
- view
- checkRequestExistence(requestId, true)
- returns (IZKPVerifier.ZKPRequest memory zkpRequest)
- {
- return _getZKPVerifierStorage()._requests[requestId];
- }
-
- /// @dev Gets the count of ZKP requests
- /// @return The count of ZKP requests
- function getZKPRequestsCount() public view returns (uint256) {
- return _getZKPVerifierStorage()._requestIds.length;
- }
-
- /// @dev Checks if a ZKP request ID exists
- /// @param requestId The ID of the ZKP request
- /// @return Whether the request ID exists
- function requestIdExists(uint64 requestId) public view override returns (bool) {
- return
- _getZKPVerifierStorage()._requests[requestId].validator !=
- ICircuitValidator(address(0));
- }
-
- /// @dev Gets multiple ZKP requests within a range
- /// @param startIndex The starting index of the range
- /// @param length The length of the range
- /// @return An array of ZKP requests within the specified range
- function getZKPRequests(
- uint256 startIndex,
- uint256 length
- ) public view virtual returns (IZKPVerifier.ZKPRequest[] memory) {
- ZKPVerifierStorage storage s = _getZKPVerifierStorage();
- (uint256 start, uint256 end) = ArrayUtils.calculateBounds(
- s._requestIds.length,
- startIndex,
- length,
- REQUESTS_RETURN_LIMIT
- );
-
- IZKPVerifier.ZKPRequest[] memory result = new IZKPVerifier.ZKPRequest[](end - start);
-
- for (uint256 i = start; i < end; i++) {
- result[i - start] = s._requests[s._requestIds[i]];
- }
-
- return result;
- }
-
- /// @dev Checks if proof submitted for a given sender and request ID
- /// @param sender The sender's address
- /// @param requestId The ID of the ZKP request
- /// @return true if proof submitted
- function isProofVerified(
- address sender,
- uint64 requestId
- ) public view checkRequestExistence(requestId, true) returns (bool) {
- return _getZKPVerifierStorage()._proofs[sender][requestId].isVerified;
- }
-
- /// @dev Checks the proof status for a given user and request ID
- /// @param sender The sender's address
- /// @param requestId The ID of the ZKP request
- /// @return The proof status structure
- function getProofStatus(
- address sender,
- uint64 requestId
- ) public view checkRequestExistence(requestId, true) returns (IZKPVerifier.ProofStatus memory) {
- VerifierLib.Proof storage proof = _getZKPVerifierStorage()._proofs[sender][requestId];
-
- return
- IZKPVerifier.ProofStatus(
- proof.isVerified,
- proof.validatorVersion,
- proof.blockNumber,
- proof.blockTimestamp
- );
- }
-
- /// @dev Gets the proof storage item for a given user, request ID and key
- /// @param user The user's address
- /// @param requestId The ID of the ZKP request
- /// @return The proof
- function getProofStorageField(
- address user,
- uint64 requestId,
- string memory key
- ) public view checkRequestExistence(requestId, true) returns (uint256) {
- return _getZKPVerifierStorage()._proofs[user][requestId].storageFields[key];
- }
-
- /// @dev Gets the address of the state contract linked to the verifier
- /// @return address of the state contract
- function getStateAddress() public view virtual returns (address) {
- return address(_getZKPVerifierStorage()._state);
- }
-
- /// @dev Update a ZKP request
- /// @param requestId The ID of the ZKP request
- /// @param request The ZKP request data
- function _updateZKPRequest(
- uint64 requestId,
- IZKPVerifier.ZKPRequest calldata request
- ) internal checkRequestExistence(requestId, true) {
- ZKPVerifierStorage storage s = _getZKPVerifierStorage();
- s._requests[requestId] = request;
- }
-
- function _getRequestIfCanBeVerified(
- uint64 requestId
- )
- internal
- view
- virtual
- checkRequestExistence(requestId, true)
- returns (IZKPVerifier.ZKPRequest storage)
- {
- return _getZKPVerifierStorage()._requests[requestId];
- }
-}
diff --git a/hardhat.config.ts b/hardhat.config.ts
index 28646e36..798baa9e 100644
--- a/hardhat.config.ts
+++ b/hardhat.config.ts
@@ -41,6 +41,71 @@ const config: HardhatUserConfig = {
version: "0.8.27",
},
],
+ overrides: {
+ "contracts/verifiers/UniversalVerifier.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/test-helpers/VerifierTestWrapper.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/test-helpers/EmbeddedVerifierWrapper.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/test-helpers/RequestDisableableTestWrapper.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/test-helpers/RequestOwnershipTestWrapper.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/test-helpers/ValidatorWhitelistTestWrapper.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ "contracts/state/State.sol": {
+ version: "0.8.27",
+ settings: {
+ optimizer: {
+ enabled: true,
+ runs: 200,
+ },
+ },
+ },
+ },
},
networks: {
"privado-main": {
diff --git a/helpers/DeployHelper.ts b/helpers/DeployHelper.ts
index 670d4303..f2a74ce3 100644
--- a/helpers/DeployHelper.ts
+++ b/helpers/DeployHelper.ts
@@ -23,11 +23,12 @@ import {
waitNotToInterfereWithHardhatIgnition,
} from "./helperUtils";
import { MCPaymentProxyModule } from "../ignition/modules/mcPayment";
+import { LinkedMultiQueryProxyModule } from "../ignition/modules/linkedMultiQuery";
const SMT_MAX_DEPTH = 64;
-export type Groth16VerifierType = "mtpV2" | "sigV2" | "v3" | "authV2";
-export type ValidatorType = "mtpV2" | "sigV2" | "v3" | "authV2";
+export type Groth16VerifierType = "mtpV2" | "sigV2" | "v3" | "authV2" | "lmk10";
+export type ValidatorType = "mtpV2" | "sigV2" | "v3" | "authV2" | "lmk";
export class DeployHelper {
constructor(
@@ -57,7 +58,6 @@ export class DeployHelper {
): Promise<{
state: Contract;
stateLib: Contract;
- stateCrossChainLib: Contract;
crossChainProofValidator: Contract;
smtLib: Contract;
poseidon1: Contract;
@@ -81,7 +81,6 @@ export class DeployHelper {
const {
state,
stateLib,
- stateCrossChainLib,
crossChainProofValidator,
groth16VerifierStateTransition,
defaultIdType,
@@ -96,7 +95,6 @@ export class DeployHelper {
return {
state,
stateLib: stateLib!,
- stateCrossChainLib: stateCrossChainLib!,
crossChainProofValidator: crossChainProofValidator!,
defaultIdType,
smtLib,
@@ -118,7 +116,6 @@ export class DeployHelper {
): Promise<{
state: Contract;
stateLib: Contract | null;
- stateCrossChainLib: Contract | null;
crossChainProofValidator: Contract | null;
groth16VerifierStateTransition: Contract | null;
defaultIdType;
@@ -158,7 +155,6 @@ export class DeployHelper {
return {
state,
stateLib: null,
- stateCrossChainLib: null,
crossChainProofValidator: null,
groth16VerifierStateTransition: null,
defaultIdType,
@@ -182,23 +178,6 @@ export class DeployHelper {
tmpContractDeployments.addContract(contractsInfo.STATE_LIB.name, await stateLib.getAddress());
}
- let stateCrossChainLib;
- stateCrossChainLib = await tmpContractDeployments.getContract(
- contractsInfo.STATE_CROSS_CHAIN_LIB.name,
- );
- if (stateCrossChainLib) {
- Logger.warning(
- `${contractsInfo.STATE_CROSS_CHAIN_LIB.name} found already deployed to: ${await stateCrossChainLib?.getAddress()}`,
- );
- } else {
- this.log("deploying StateCrossChainLib...");
- stateCrossChainLib = await this.deployStateCrossChainLib("StateCrossChainLib");
- tmpContractDeployments.addContract(
- contractsInfo.STATE_CROSS_CHAIN_LIB.name,
- await stateCrossChainLib.getAddress(),
- );
- }
-
let crossChainProofValidator;
crossChainProofValidator = await tmpContractDeployments.getContract(
contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.name,
@@ -223,7 +202,6 @@ export class DeployHelper {
StateLib: await stateLib.getAddress(),
SmtLib: smtLibAddress,
PoseidonUnit1L: poseidon1Address,
- StateCrossChainLib: await stateCrossChainLib.getAddress(),
},
});
@@ -302,7 +280,6 @@ export class DeployHelper {
return {
state,
stateLib,
- stateCrossChainLib,
crossChainProofValidator,
groth16VerifierStateTransition,
defaultIdType,
@@ -319,7 +296,6 @@ export class DeployHelper {
): Promise<{
state: Contract;
stateLib: Contract;
- stateCrossChainLib: Contract;
crossChainProofValidator: Contract;
}> {
this.log("======== State: upgrade started ========");
@@ -330,9 +306,6 @@ export class DeployHelper {
this.log("deploying StateLib...");
const stateLib = await this.deployStateLib();
- this.log("deploying StateCrossChainLib...");
- const stateCrossChainLib = await this.deployStateCrossChainLib();
-
this.log("upgrading state...");
/*
@@ -349,7 +322,6 @@ export class DeployHelper {
StateLib: await stateLib.getAddress(),
SmtLib: smtLibAddress,
PoseidonUnit1L: poseidon1Address,
- StateCrossChainLib: await stateCrossChainLib.getAddress(),
},
});
@@ -385,7 +357,6 @@ export class DeployHelper {
state: stateContract,
crossChainProofValidator: opvContract,
stateLib,
- stateCrossChainLib,
};
}
@@ -440,14 +411,6 @@ export class DeployHelper {
return stateLib;
}
- async deployStateCrossChainLib(StateCrossChainLibName = "StateCrossChainLib"): Promise {
- const stateCrossChainLib = await ethers.deployContract(StateCrossChainLibName);
- await stateCrossChainLib.waitForDeployment();
- Logger.success(`StateCrossChainLib deployed to: ${await stateCrossChainLib.getAddress()}`);
-
- return stateCrossChainLib;
- }
-
async deploySmtLibTestWrapper(maxDepth: number = SMT_MAX_DEPTH): Promise {
const contractName = "SmtLibTestWrapper";
@@ -488,17 +451,6 @@ export class DeployHelper {
return stateLibWrapper;
}
- async deployVerifierLib(): Promise {
- const contractName = "VerifierLib";
-
- const verifierLib = await ethers.deployContract(contractName);
- await verifierLib.waitForDeployment();
-
- Logger.success(`${contractName} deployed to: ${await verifierLib.getAddress()}`);
-
- return verifierLib;
- }
-
async deployBinarySearchTestWrapper(): Promise {
this.log("deploying poseidons...");
const [poseidon2Elements, poseidon3Elements] = await deployPoseidons([2, 3]);
@@ -565,6 +517,28 @@ export class DeployHelper {
return g16Verifier;
}
+ getGroth16VerifierTypeFromValidatorType(validatorType: ValidatorType): Groth16VerifierType {
+ let groth16VerifierType;
+ switch (validatorType) {
+ case "mtpV2":
+ groth16VerifierType = "mtpV2";
+ break;
+ case "sigV2":
+ groth16VerifierType = "sigV2";
+ break;
+ case "v3":
+ groth16VerifierType = "v3";
+ break;
+ case "authV2":
+ groth16VerifierType = "authV2";
+ break;
+ case "lmk":
+ groth16VerifierType = "lmk10";
+ break;
+ }
+ return groth16VerifierType;
+ }
+
getGroth16VerifierWrapperName(groth16VerifierType: Groth16VerifierType): string {
let g16VerifierContractWrapperName;
switch (groth16VerifierType) {
@@ -580,6 +554,9 @@ export class DeployHelper {
case "authV2":
g16VerifierContractWrapperName = contractsInfo.GROTH16_VERIFIER_AUTH_V2.name;
break;
+ case "lmk10":
+ g16VerifierContractWrapperName = contractsInfo.GROTH16_VERIFIER_LINKED_MULTI_QUERY10.name;
+ break;
}
return g16VerifierContractWrapperName;
}
@@ -601,9 +578,12 @@ export class DeployHelper {
break;
case "v3":
verification = contractsInfo.GROTH16_VERIFIER_V3.verificationOpts;
+ break;
case "authV2":
verification = contractsInfo.GROTH16_VERIFIER_AUTH_V2.verificationOpts;
break;
+ case "lmk10":
+ verification = contractsInfo.GROTH16_VERIFIER_LINKED_MULTI_QUERY10.verificationOpts;
}
return verification;
}
@@ -625,6 +605,10 @@ export class DeployHelper {
break;
case "v3":
verification = contractsInfo.VALIDATOR_V3.verificationOpts;
+ break;
+ case "lmk":
+ verification = contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.verificationOpts;
+ break;
case "authV2":
verification = contractsInfo.VALIDATOR_AUTH_V2.verificationOpts;
break;
@@ -647,33 +631,32 @@ export class DeployHelper {
async deployValidatorContractsWithVerifiers(
validatorType: ValidatorType,
- stateAddress: string,
+ stateContractAddress: string,
deployStrategy: "basic" | "create2" = "basic",
+ groth16VerifierWrapperAddress?: string,
): Promise<{
- state: any;
groth16VerifierWrapper: any;
validator: any;
}> {
const contracts = await this.deployValidatorContracts(
validatorType,
- stateAddress,
+ stateContractAddress,
deployStrategy,
+ groth16VerifierWrapperAddress,
);
- const state = await ethers.getContractAt("State", stateAddress);
return {
validator: contracts.validator,
groth16VerifierWrapper: contracts.groth16VerifierWrapper,
- state,
};
}
async deployValidatorContracts(
validatorType: ValidatorType,
- stateAddress: string,
+ stateContractAddress: string,
deployStrategy: "basic" | "create2" = "basic",
+ groth16VerifierWrapperAddress?: string,
): Promise<{
- state: any;
validator: any;
groth16VerifierWrapper: Contract | null;
}> {
@@ -693,6 +676,8 @@ export class DeployHelper {
case "authV2":
validatorContractName = "AuthV2Validator";
break;
+ case "lmk":
+ validatorContractName = "LinkedMultiQueryValidator";
}
let validator;
@@ -713,6 +698,9 @@ export class DeployHelper {
case "authV2":
validatorModule = AuthV2ValidatorProxyModule;
break;
+ case "lmk":
+ validatorModule = LinkedMultiQueryProxyModule;
+ break;
}
await waitNotToInterfereWithHardhatIgnition(undefined);
@@ -735,14 +723,25 @@ export class DeployHelper {
);
return {
validator,
- state: await ethers.getContractAt("State", stateAddress),
groth16VerifierWrapper: null,
};
}
}
}
- const groth16VerifierWrapper = await this.deployGroth16VerifierWrapper(validatorType);
+ let groth16VerifierWrapper;
+ if (!groth16VerifierWrapperAddress) {
+ groth16VerifierWrapper = await this.deployGroth16VerifierWrapper(
+ this.getGroth16VerifierTypeFromValidatorType(validatorType),
+ );
+ } else {
+ groth16VerifierWrapper = await ethers.getContractAt(
+ this.getGroth16VerifierWrapperName(
+ this.getGroth16VerifierTypeFromValidatorType(validatorType),
+ ),
+ groth16VerifierWrapperAddress,
+ );
+ }
const ValidatorFactory = await ethers.getContractFactory(validatorContractName);
const Create2AddressAnchorFactory = await ethers.getContractFactory(
@@ -772,36 +771,46 @@ export class DeployHelper {
redeployImplementation: "always",
call: {
fn: "initialize",
- args: [await groth16VerifierWrapper.getAddress(), stateAddress, await owner.getAddress()],
+ args:
+ validatorType != "lmk"
+ ? [
+ stateContractAddress,
+ await groth16VerifierWrapper.getAddress(),
+ await owner.getAddress(),
+ ]
+ : [await groth16VerifierWrapper.getAddress(), await owner.getAddress()],
},
});
} else {
this.log("deploying with BASIC strategy...");
- validator = await upgrades.deployProxy(ValidatorFactory, [
- await groth16VerifierWrapper.getAddress(),
- stateAddress,
- await owner.getAddress(),
- ]);
+ validator = await upgrades.deployProxy(
+ ValidatorFactory,
+ validatorType != "lmk"
+ ? [
+ stateContractAddress,
+ await groth16VerifierWrapper.getAddress(),
+ await owner.getAddress(),
+ ]
+ : [await groth16VerifierWrapper.getAddress(), await owner.getAddress()],
+ );
}
validator.waitForDeployment();
Logger.success(`${validatorContractName} deployed to: ${await validator.getAddress()}`);
- const state = await ethers.getContractAt("State", stateAddress);
return {
validator,
- state,
groth16VerifierWrapper,
};
}
- async deployValidatorStub(): Promise {
- const stub = await ethers.getContractFactory("ValidatorStub");
+ async deployValidatorStub(validatorName: string = "RequestValidatorStub"): Promise {
+ const stub = await ethers.getContractFactory(validatorName);
const stubInstance = await stub.deploy();
await stubInstance.waitForDeployment();
- console.log("Validator stub deployed to:", await stubInstance.getAddress());
+ console.log(`${validatorName} stub deployed to:`, await stubInstance.getAddress());
return stubInstance;
}
@@ -856,7 +865,6 @@ export class DeployHelper {
async upgradeUniversalVerifier(
verifierAddress: string,
- verifierLibAddr: string,
verifierContractName = contractsInfo.UNIVERSAL_VERIFIER.name,
): Promise {
this.log("======== Verifier: upgrade started ========");
@@ -865,9 +873,6 @@ export class DeployHelper {
this.log("upgrading verifier...");
const VerifierFactory = await ethers.getContractFactory(verifierContractName, {
signer: proxyAdminOwner,
- libraries: {
- VerifierLib: verifierLibAddr,
- },
});
this.log("upgrading proxy...");
@@ -908,29 +913,9 @@ export class DeployHelper {
return primitiveTypeUtilsWrapper;
}
- async deployEmbeddedZKPVerifierWrapper(
- owner: SignerWithAddress | undefined,
- stateAddr: string,
- verifierLibAddr: string,
- ): Promise {
- const Verifier = await ethers.getContractFactory("EmbeddedZKPVerifierWrapper", {
- libraries: {
- VerifierLib: verifierLibAddr,
- },
- });
- // const zkpVerifier = await ZKPVerifier.deploy(await owner.getAddress());
- const verifier = await upgrades.deployProxy(Verifier, [await owner.getAddress(), stateAddr], {
- unsafeAllow: ["external-library-linking"],
- });
- await verifier.waitForDeployment();
- console.log("EmbeddedZKPVerifierWrapper deployed to:", await verifier.getAddress());
- return verifier;
- }
-
async deployUniversalVerifier(
owner: SignerWithAddress | undefined,
stateAddr: string,
- verifierLibAddr: string,
deployStrategy: "basic" | "create2" = "basic",
): Promise {
if (!owner) {
@@ -940,9 +925,6 @@ export class DeployHelper {
contractsInfo.UNIVERSAL_VERIFIER.name,
{
signer: owner,
- libraries: {
- VerifierLib: verifierLibAddr,
- },
},
);
const Create2AddressAnchorFactory = await ethers.getContractFactory(
diff --git a/helpers/UniversalVerifierContractMigrationHelper.ts b/helpers/UniversalVerifierContractMigrationHelper.ts
index aab0623a..3bec09d3 100644
--- a/helpers/UniversalVerifierContractMigrationHelper.ts
+++ b/helpers/UniversalVerifierContractMigrationHelper.ts
@@ -104,13 +104,9 @@ export class UniversalVerifierContractMigrationHelper extends ContractMigrationS
}
@log
- async upgradeContract(
- universalVerifierContract: Contract,
- opts: { verifierLibAddress: string },
- ): Promise {
+ async upgradeContract(universalVerifierContract: Contract): Promise {
return await this._universalVerifierDeployHelper.upgradeUniversalVerifier(
await universalVerifierContract.getAddress(),
- opts.verifierLibAddress,
);
}
}
diff --git a/helpers/constants.ts b/helpers/constants.ts
index 354845dc..43c4c4df 100644
--- a/helpers/constants.ts
+++ b/helpers/constants.ts
@@ -108,9 +108,9 @@ export const contractsInfo = Object.freeze({
},
UNIVERSAL_VERIFIER: {
name: "UniversalVerifier",
- version: "1.1.5",
- unifiedAddress: "0xfcc86A79fCb057A8e55C6B853dff9479C3cf607c",
- create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.UniversalVerifier")),
+ version: "2.0.0",
+ unifiedAddress: "0xfcc86A79fCb057A8e55C6B853dff9479C3cf607c", // TODO: Recalculate new address
+ create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.UniversalVerifier.v2")),
verificationOpts: {
// For verifying the different contracts with proxy we need verification with different constructor arguments
constructorArgsImplementation: [],
@@ -125,7 +125,7 @@ export const contractsInfo = Object.freeze({
},
STATE: {
name: "State",
- version: "2.6.1",
+ version: "2.6.2",
unifiedAddress: "0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896",
create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.State")),
verificationOpts: {
@@ -193,10 +193,26 @@ export const contractsInfo = Object.freeze({
libraries: {},
},
},
+ VALIDATOR_LINKED_MULTI_QUERY: {
+ name: "LinkedMultiQueryValidator",
+ version: "1.0.0-beta.1",
+ unifiedAddress: "0xfA622418d7aBF33868545732CaD2C2E7ce9B16C8",
+ create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.LinkedMultiQueryValidator")),
+ verificationOpts: {
+ constructorArgsImplementation: [],
+ constructorArgsProxy: [
+ "0x56fF81aBB5cdaC478bF236db717e4976b2ff841e",
+ "0xae15d2023a76174a940cbb2b7f44012c728b9d74",
+ "0x6964656e332e637265617465322e556e6976657273616c5665726966696572",
+ ],
+ constructorArgsProxyAdmin: ["0xAe15d2023A76174a940cbb2b7f44012c728b9d74"],
+ libraries: {},
+ },
+ },
VALIDATOR_AUTH_V2: {
name: "AuthV2Validator",
version: "1.0.0",
- unifiedAddress: "0x49ebdC163fa014F310CeDBc8e4a0b15C738D8073",
+ unifiedAddress: "0x535F6a1B30533616CE4bD44081ea7A17CF2042B8",
create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.AuthV2Validator")),
verificationOpts: {
constructorArgsImplementation: [],
@@ -228,7 +244,7 @@ export const contractsInfo = Object.freeze({
VC_PAYMENT: {
name: "VCPayment",
version: "1.0.0",
- unifiedAddress: "",
+ unifiedAddress: "0xba83D99c87358Ef9B6f7c4a5A94021A58d870704",
create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.VCPayment")),
verificationOpts: {
constructorArgsImplementation: [],
@@ -238,7 +254,7 @@ export const contractsInfo = Object.freeze({
MC_PAYMENT: {
name: "MCPayment",
version: "1.0.0",
- unifiedAddress: "",
+ unifiedAddress: "0xe317A4f1450116b2fD381446DEaB41c882D6136D",
create2Calldata: ethers.hexlify(ethers.toUtf8Bytes("iden3.create2.MCPayment")),
verificationOpts: {
constructorArgsImplementation: [],
@@ -327,46 +343,40 @@ export const contractsInfo = Object.freeze({
libraries: {},
},
},
- GROTH16_VERIFIER_AUTH_V2: {
- name: "Groth16VerifierAuthV2Wrapper",
+ GROTH16_VERIFIER_LINKED_MULTI_QUERY10: {
+ name: "Groth16VerifierLinkedMultiQuery10Wrapper",
unifiedAddress: "",
create2Calldata: "",
verificationOpts: {
contract:
- "contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol:Groth16VerifierAuthV2Wrapper",
- constructorArgsImplementation: [],
- libraries: {},
- },
- },
- STATE_LIB: {
- name: "StateLib",
- unifiedAddress: "",
- create2Address: "",
- verificationOpts: {
+ "contracts/lib/groth16-verifiers/Groth16VerifierLinkedMultiQuery10Wrapper.sol:Groth16VerifierLinkedMultiQuery10Wrapper",
constructorArgsImplementation: [],
libraries: {},
},
},
- STATE_CROSS_CHAIN_LIB: {
- name: "StateCrossChainLib",
+ GROTH16_VERIFIER_AUTH_V2: {
+ name: "Groth16VerifierAuthV2Wrapper",
unifiedAddress: "",
- create2Address: "",
+ create2Calldata: "",
verificationOpts: {
+ contract:
+ "contracts/lib/groth16-verifiers/Groth16VerifierAuthV2Wrapper.sol:Groth16VerifierAuthV2Wrapper",
constructorArgsImplementation: [],
libraries: {},
},
},
- VERIFIER_LIB: {
- name: "VerifierLib",
+ STATE_LIB: {
+ name: "StateLib",
unifiedAddress: "",
- create2Address: "",
+ create2Calldata: "",
verificationOpts: {
constructorArgsImplementation: [],
libraries: {},
},
},
- EMBEDDED_ZKP_VERIFIER_WRAPPER: {
- name: "EmbeddedZKPVerifierWrapper",
+
+ EMBEDDED_VERIFIER_WRAPPER: {
+ name: "EmbeddedVerifierWrapper",
unifiedAddress: "",
create2Calldata: "",
},
diff --git a/ignition/modules/libraries.ts b/ignition/modules/libraries.ts
index e6225aac..ddb26aab 100644
--- a/ignition/modules/libraries.ts
+++ b/ignition/modules/libraries.ts
@@ -125,8 +125,3 @@ export const SpongePoseidonModule = buildModule("SpongePoseidonModule", (m) => {
});
return { spongePoseidon };
});
-
-export const VerifierLibModule = buildModule("VerifierLibModule", (m) => {
- const verifierLib = m.contract("VerifierLib");
- return { verifierLib };
-});
diff --git a/ignition/modules/linkedMultiQuery.ts b/ignition/modules/linkedMultiQuery.ts
new file mode 100644
index 00000000..f838f8a3
--- /dev/null
+++ b/ignition/modules/linkedMultiQuery.ts
@@ -0,0 +1,22 @@
+import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
+import { contractsInfo } from "../../helpers/constants";
+
+export const LinkedMultiQueryProxyModule = buildModule("LinkedMultiQueryModule", (m) => {
+ const proxyAdminOwner = m.getAccount(0);
+
+ // This contract is supposed to be deployed to the same address across many networks,
+ // so the first implementation address is a dummy contract that does nothing but accepts any calldata.
+ // Therefore, it is a mechanism to deploy TransparentUpgradeableProxy contract
+ // with constant constructor arguments, so predictable init bytecode and predictable CREATE2 address.
+ // Subsequent upgrades are supposed to switch this proxy to the real implementation.
+
+ const proxy = m.contract("TransparentUpgradeableProxy", [
+ contractsInfo.CREATE2_ADDRESS_ANCHOR.unifiedAddress,
+ proxyAdminOwner,
+ contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.create2Calldata,
+ ]);
+
+ const proxyAdminAddress = m.readEventArgument(proxy, "AdminChanged", "newAdmin");
+ const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress);
+ return { proxyAdmin, proxy };
+});
diff --git a/scripts/deploy/deployCrossChainVerifierWithRequests.ts b/scripts/deploy/deployCrossChainVerifierWithRequests.ts
index 834a0030..0921d6bb 100644
--- a/scripts/deploy/deployCrossChainVerifierWithRequests.ts
+++ b/scripts/deploy/deployCrossChainVerifierWithRequests.ts
@@ -39,7 +39,7 @@ async function main() {
console.log("Removing previous ignition files for chain: ", chainId);
fs.rmSync(`./ignition/deployments/chain-${chainId}`, { recursive: true, force: true });
}
- // ##################### State with StateCrossChainLib deploy #####################
+ // ##################### State deploy #####################
const { state, crossChainProofValidator } = await deployHelper.deployStateWithLibraries();
@@ -60,15 +60,8 @@ async function main() {
await state.getAddress(),
);
- // ##################### VerifierLib deploy #####################
- const verifierLib = await deployHelper.deployVerifierLib();
-
// ##################### Universal Verifier deploy #####################
- const verifier = await deployHelper.deployUniversalVerifier(
- undefined,
- await state.getAddress(),
- await verifierLib.getAddress(),
- );
+ const verifier = await deployHelper.deployUniversalVerifier(undefined, await state.getAddress());
const addToWhiteList1 = await verifier.addValidatorToWhitelist(await validatorSig.getAddress());
await addToWhiteList1.wait();
diff --git a/scripts/deploy/deployState.ts b/scripts/deploy/deployState.ts
index 7c71c34c..d8ad13ed 100644
--- a/scripts/deploy/deployState.ts
+++ b/scripts/deploy/deployState.ts
@@ -40,22 +40,13 @@ async function main() {
// if the state contract already exists we won't have new contracts deployed
// to verify and to save the output
- if (
- groth16VerifierStateTransition &&
- stateLib &&
- stateCrossChainLib &&
- crossChainProofValidator
- ) {
+ if (groth16VerifierStateTransition && stateLib && crossChainProofValidator) {
await verifyContract(await state.getAddress(), contractsInfo.STATE.verificationOpts);
await verifyContract(
await groth16VerifierStateTransition.getAddress(),
contractsInfo.GROTH16_VERIFIER_STATE_TRANSITION.verificationOpts,
);
await verifyContract(await stateLib.getAddress(), contractsInfo.STATE_LIB.verificationOpts);
- await verifyContract(
- await stateCrossChainLib.getAddress(),
- contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts,
- );
await verifyContract(
await crossChainProofValidator.getAddress(),
contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.verificationOpts,
@@ -69,7 +60,6 @@ async function main() {
proxyAdminOwnerAddress: await signer.getAddress(),
state: await state.getAddress(),
stateLib: await stateLib?.getAddress(),
- stateCrossChainLib: await stateCrossChainLib?.getAddress(),
crossChainProofValidator: await crossChainProofValidator?.getAddress(),
network: networkName,
chainId,
diff --git a/scripts/deploy/deployUniversalVerifier.ts b/scripts/deploy/deployUniversalVerifier.ts
index 1e1188b8..391d2754 100644
--- a/scripts/deploy/deployUniversalVerifier.ts
+++ b/scripts/deploy/deployUniversalVerifier.ts
@@ -28,29 +28,9 @@ async function main() {
"./scripts/deployments_output/temp_deployments_output.json",
);
- let verifierLib = await tmpContractDeployments.getContract(contractsInfo.VERIFIER_LIB.name);
- if (verifierLib) {
- Logger.warning(
- `${contractsInfo.VERIFIER_LIB.name} found already deployed to: ${await verifierLib?.getAddress()}`,
- );
- } else {
- verifierLib = await deployHelper.deployVerifierLib();
- const tx = await verifierLib.deploymentTransaction();
- await waitNotToInterfereWithHardhatIgnition(tx);
- tmpContractDeployments.addContract(
- contractsInfo.VERIFIER_LIB.name,
- await verifierLib.getAddress(),
- );
- await verifyContract(
- await verifierLib.getAddress(),
- contractsInfo.VERIFIER_LIB.verificationOpts,
- );
- }
-
const universalVerifier = await deployHelper.deployUniversalVerifier(
undefined,
stateContractAddress,
- await verifierLib.getAddress(),
deployStrategy,
);
tmpContractDeployments.remove();
@@ -68,7 +48,6 @@ async function main() {
const outputJson = {
proxyAdminOwnerAddress: await signer.getAddress(),
universalVerifier: await universalVerifier.getAddress(),
- verifierLib: await verifierLib.getAddress(),
state: stateContractAddress,
network: networkName,
chainId,
diff --git a/scripts/deploy/deployValidators.ts b/scripts/deploy/deployValidators.ts
index b3f5b3c1..6e23fd40 100644
--- a/scripts/deploy/deployValidators.ts
+++ b/scripts/deploy/deployValidators.ts
@@ -13,14 +13,14 @@ async function main() {
const config = getConfig();
const chainId = await getChainId();
- const stateContractAddress = await getStateContractAddress();
- const validators: ValidatorType[] = ["mtpV2", "sigV2", "v3", "authV2"];
+ const validators: ValidatorType[] = ["mtpV2", "sigV2", "v3", "lmk"];
const deployStrategy: "basic" | "create2" =
config.deployStrategy == "create2" ? "create2" : "basic";
const [signer] = await hre.ethers.getSigners();
const deployHelper = await DeployHelper.initialize(null, true);
+ const stateContractAddress = getStateContractAddress();
const validatorsInfo: any = [];
for (const v of validators) {
diff --git a/scripts/maintenance/checkContractsVerificationManually.ts b/scripts/maintenance/checkContractsVerificationManually.ts
index 6a35c530..04a218df 100644
--- a/scripts/maintenance/checkContractsVerificationManually.ts
+++ b/scripts/maintenance/checkContractsVerificationManually.ts
@@ -2,29 +2,16 @@ import { verifyContract } from "../../helpers/helperUtils";
import { contractsInfo } from "../../helpers/constants";
async function main() {
- const StateCrossChainLibAddress: string = "";
const StateLibAddress: string = "";
- const VerifierLibAddress: string = "";
const StateAddress: string = "";
if (StateAddress.includes("0x")) {
await verifyContract(StateAddress, contractsInfo.STATE.verificationOpts);
}
- if (StateCrossChainLibAddress.includes("0x")) {
- await verifyContract(
- StateCrossChainLibAddress,
- contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts,
- );
- }
-
if (StateLibAddress.includes("0x")) {
await verifyContract(StateLibAddress, contractsInfo.STATE_LIB.verificationOpts);
}
-
- if (VerifierLibAddress.includes("0x")) {
- await verifyContract(VerifierLibAddress, contractsInfo.VERIFIER_LIB.verificationOpts);
- }
}
main()
diff --git a/scripts/maintenance/checkEmbeddedZKPVerifier.ts b/scripts/maintenance/checkEmbeddedZKPVerifier.ts
index e919726c..e69de29b 100644
--- a/scripts/maintenance/checkEmbeddedZKPVerifier.ts
+++ b/scripts/maintenance/checkEmbeddedZKPVerifier.ts
@@ -1,70 +0,0 @@
-import { getStateContractAddress, Logger } from "../../helpers/helperUtils";
-import { contractsInfo } from "../../helpers/constants";
-import hre, { ethers } from "hardhat";
-import {
- setZKPRequest_KYCAgeCredential,
- submitZKPResponses_KYCAgeCredential,
-} from "../upgrade/verifiers/helpers/testVerifier";
-import { Contract } from "ethers";
-
-// Replace these addresses with the ones you want to test
-const embeddedZKPVerifierAddress = "";
-const validatorSigV2Address = "";
-const validatorMTPV2Address = "";
-const validatorV3Address = "";
-
-async function testVerification(verifier: Contract) {
- const requestId_V3 = 7254189;
- await setZKPRequest_KYCAgeCredential(requestId_V3, verifier, validatorV3Address, "v3");
- await submitZKPResponses_KYCAgeCredential(requestId_V3, verifier, "v3", {
- stateContractAddress: await getStateContractAddress(),
- verifierContractAddress: await verifier.getAddress(),
- checkSubmitZKResponseV2: false,
- });
-
- const requestId_SigV2 = 7254190;
- await setZKPRequest_KYCAgeCredential(requestId_SigV2, verifier, validatorSigV2Address, "sigV2");
- await submitZKPResponses_KYCAgeCredential(requestId_SigV2, verifier, "sigV2", {
- stateContractAddress: await getStateContractAddress(),
- verifierContractAddress: await verifier.getAddress(),
- checkSubmitZKResponseV2: false,
- });
-
- const requestId_MTPV2 = 7254191;
- await setZKPRequest_KYCAgeCredential(requestId_MTPV2, verifier, validatorMTPV2Address, "mtpV2");
- await submitZKPResponses_KYCAgeCredential(requestId_MTPV2, verifier, "mtpV2", {
- stateContractAddress: await getStateContractAddress(),
- verifierContractAddress: await verifier.getAddress(),
- checkSubmitZKResponseV2: false,
- });
-}
-
-async function main() {
- console.log(
- `\nChecking EmbeddedZKPVerifier verification on ${hre.network.name} with address ${embeddedZKPVerifierAddress}...`,
- );
-
- const embeddedZKPVerifier = await ethers.getContractAt(
- contractsInfo.EMBEDDED_ZKP_VERIFIER_WRAPPER.name,
- embeddedZKPVerifierAddress,
- );
-
- try {
- await testVerification(embeddedZKPVerifier);
- Logger.success(
- `${hre.network.name} embedded ZKP Verifier onchain ${embeddedZKPVerifierAddress} verified`,
- );
- } catch (error) {
- console.error(error);
- Logger.error(
- `${hre.network.name} embedded ZKP Verifier onchain ${embeddedZKPVerifierAddress} not verified`,
- );
- }
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error);
- process.exit(1);
- });
diff --git a/scripts/maintenance/disableProxyContract.ts b/scripts/maintenance/disableProxyContract.ts
index 3a271e49..a04a0bd5 100644
--- a/scripts/maintenance/disableProxyContract.ts
+++ b/scripts/maintenance/disableProxyContract.ts
@@ -21,7 +21,10 @@ async function main() {
await new Promise((resolve) => setTimeout(resolve, 20000));
// !!!!! Put proper function name here to make some check, e.g. getDefaultIdType() for State contract !!!!!
- await expect(contract.getDefaultIdType()).to.be.revertedWith("The contract is disabled");
+ await expect(contract.getDefaultIdType()).to.be.revertedWithCustomError(
+ contract,
+ "TheContractIsDisabled",
+ );
const network = hre.network.name;
console.log(
diff --git a/scripts/upgrade/state/state-upgrade.ts b/scripts/upgrade/state/state-upgrade.ts
index c9bdb7e5..b812c51e 100644
--- a/scripts/upgrade/state/state-upgrade.ts
+++ b/scripts/upgrade/state/state-upgrade.ts
@@ -79,22 +79,17 @@ async function main() {
const defaultIdTypeBefore = await stateContract.getDefaultIdType();
const stateOwnerAddressBefore = await stateContract.owner();
- const { state, stateLib, stateCrossChainLib, crossChainProofValidator } =
- await stateDeployHelper.upgradeState(
- await stateContract.getAddress(),
- true,
- contractsInfo.SMT_LIB.unifiedAddress,
- contractsInfo.POSEIDON_1.unifiedAddress,
- );
+ const { state, stateLib, crossChainProofValidator } = await stateDeployHelper.upgradeState(
+ await stateContract.getAddress(),
+ true,
+ contractsInfo.SMT_LIB.unifiedAddress,
+ contractsInfo.POSEIDON_1.unifiedAddress,
+ );
console.log("Version after: ", await state.VERSION());
await verifyContract(await state.getAddress(), contractsInfo.STATE.verificationOpts);
await verifyContract(await stateLib.getAddress(), contractsInfo.STATE_LIB.verificationOpts);
- await verifyContract(
- await stateCrossChainLib.getAddress(),
- contractsInfo.STATE_CROSS_CHAIN_LIB.verificationOpts,
- );
await verifyContract(
await crossChainProofValidator.getAddress(),
contractsInfo.CROSS_CHAIN_PROOF_VALIDATOR.verificationOpts,
@@ -149,7 +144,6 @@ async function main() {
verifier: contractsInfo.GROTH16_VERIFIER_STATE_TRANSITION.unifiedAddress,
stateLib: await stateLib.getAddress(),
smtLib: contractsInfo.SMT_LIB.unifiedAddress,
- stateCrossChainLib: await stateCrossChainLib.getAddress(),
crossChainProofValidator: await crossChainProofValidator.getAddress(),
poseidon1: contractsInfo.POSEIDON_1.unifiedAddress,
poseidon2: contractsInfo.POSEIDON_2.unifiedAddress,
diff --git a/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts b/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts
index f3009b21..ef7fb600 100644
--- a/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts
+++ b/scripts/upgrade/verifiers/embedded-verifier-upgrade.ts
@@ -17,11 +17,11 @@ async function main() {
const chainId = await getChainId();
const network = hre.network.name;
- // EmbeddedZKPVerifer is abstract contract
+ // EmbeddedVerifer is abstract contract
// In real upgrade, you should use THE NAME as THE ADDRESS
- // of your custom contract, which inherits EmbeddedZKPVerifer
+ // of your custom contract, which inherits EmbeddedVerifer
let verifierContract = await ethers.getContractAt(
- "", // EmbeddedZKPVerifierWrapper
+ "", // EmbeddedVerifierWrapper
"",
);
@@ -42,14 +42,10 @@ async function main() {
const verifierRequestsCountBeforeUpgrade = await verifierContract.getZKPRequestsCount();
console.log("Owner Address Before Upgrade: ", verifierOwnerAddressBeforeUpgrade);
- const verifierLib = await deployerHelper.deployVerifierLib();
-
// **** Upgrade Embedded Verifier ****
- const verifierFactory = await ethers.getContractFactory("EmbeddedZKPVerifierWrapper", {
- libraries: {
- VerifierLib: await verifierLib.getAddress(),
- },
- });
+ const verifierFactory = await ethers.getContractFactory(
+ contractsInfo.EMBEDDED_VERIFIER_WRAPPER.name,
+ );
try {
verifierContract = await upgrades.upgradeProxy(
@@ -98,7 +94,6 @@ async function main() {
const outputJson = {
proxyAdminOwnerAddress: await signer.getAddress(),
verifierContract: await verifierContract.getAddress(),
- verifierLib: await verifierLib.getAddress(),
state: stateContractAddress,
network: network,
chainId,
diff --git a/scripts/upgrade/verifiers/universal-verifier-upgrade.ts b/scripts/upgrade/verifiers/universal-verifier-upgrade.ts
index ed73ab80..000f2df1 100644
--- a/scripts/upgrade/verifiers/universal-verifier-upgrade.ts
+++ b/scripts/upgrade/verifiers/universal-verifier-upgrade.ts
@@ -123,16 +123,8 @@ async function main() {
expect(await universalVerifierContract.isWhitelistedValidator(validator)).to.equal(true);
}
- const verifierLib = await deployerHelper.deployVerifierLib();
- const txVerifLib = await verifierLib.deploymentTransaction();
- await waitNotToInterfereWithHardhatIgnition(txVerifLib);
-
- await verifyContract(await verifierLib.getAddress(), contractsInfo.VERIFIER_LIB.verificationOpts);
-
// **** Upgrade Universal Verifier ****
- await universalVerifierMigrationHelper.upgradeContract(universalVerifierContract, {
- verifierLibAddress: await verifierLib.getAddress(),
- });
+ await universalVerifierMigrationHelper.upgradeContract(universalVerifierContract);
// ************************
console.log("Checking data after upgrade");
@@ -217,7 +209,6 @@ async function main() {
const outputJson = {
proxyAdminOwnerAddress: await proxyAdminOwnerSigner.getAddress(),
universalVerifier: await universalVerifierContract.getAddress(),
- verifierLib: await verifierLib.getAddress(),
state: stateContractAddress,
network: network,
chainId,
diff --git a/test/IdentityTreeStore/IdentityTreeStore.test.ts b/test/IdentityTreeStore/IdentityTreeStore.test.ts
index 230db1a0..f6096d66 100644
--- a/test/IdentityTreeStore/IdentityTreeStore.test.ts
+++ b/test/IdentityTreeStore/IdentityTreeStore.test.ts
@@ -295,10 +295,11 @@ describe("IdentityTreeStore", function () {
await expect(
identityTreeStore.getRevocationStatusByIdAndState(id, state, nonce),
- ).to.be.rejectedWith("Invalid state node");
+ ).to.be.revertedWithCustomError(identityTreeStore, "InvalidStateNode");
- await expect(identityTreeStore.getRevocationStatus(id, nonce)).to.be.rejectedWith(
- "Invalid state node",
+ await expect(identityTreeStore.getRevocationStatus(id, nonce)).to.be.revertedWithCustomError(
+ identityTreeStore,
+ "InvalidStateNode",
);
});
});
diff --git a/test/check-unified-addresses.test.ts b/test/check-unified-addresses.test.ts
new file mode 100644
index 00000000..75b9f833
--- /dev/null
+++ b/test/check-unified-addresses.test.ts
@@ -0,0 +1,72 @@
+import { buildModule } from "@nomicfoundation/ignition-core";
+import { contractsInfo } from "../helpers/constants";
+import hre, { ethers, ignition } from "hardhat";
+import { Logger } from "../helpers/helperUtils";
+
+// Replace here with your own proxy admin owner address
+const proxyAdminOwnerAddress = "0xAe15d2023A76174a940cbb2b7F44012C728B9d74";
+
+const Create2AddressAnchorModule = buildModule("Create2AddressAnchorModule", (m) => {
+ const create2AddressAnchor = m.contract(contractsInfo.CREATE2_ADDRESS_ANCHOR.name, {
+ abi: [],
+ contractName: contractsInfo.CREATE2_ADDRESS_ANCHOR.name,
+ bytecode: "0x6005600C60003960056000F360006000F3",
+ sourceName: "",
+ linkReferences: {},
+ });
+
+ return { create2AddressAnchor };
+});
+
+const GeneralProxyModule = buildModule("GeneralProxyModule", (m) => {
+ const create2Calldata = m.getParameter("create2Calldata", 0);
+
+ const proxy = m.contract("TransparentUpgradeableProxy", [
+ contractsInfo.CREATE2_ADDRESS_ANCHOR.unifiedAddress,
+ proxyAdminOwnerAddress,
+ create2Calldata,
+ ]);
+ const proxyAdminAddress = m.readEventArgument(proxy, "AdminChanged", "newAdmin");
+ const proxyAdmin = m.contractAt("ProxyAdmin", proxyAdminAddress);
+
+ return { proxyAdmin, proxy };
+});
+
+it("Calculate and check unified addresses for proxy contracts", async () => {
+ await hre.network.provider.request({
+ method: "hardhat_impersonateAccount",
+ params: [proxyAdminOwnerAddress],
+ });
+
+ (await ethers.getSigners())[0].sendTransaction({
+ to: proxyAdminOwnerAddress,
+ value: ethers.parseEther("1.0"), // Sends exactly 1.0 ether
+ });
+
+ await ignition.deploy(Create2AddressAnchorModule, { strategy: "create2" });
+
+ for (const property in contractsInfo) {
+ if (contractsInfo[property].create2Calldata !== "") {
+ const proxyDeployed = (
+ await ignition.deploy(GeneralProxyModule, {
+ strategy: "create2",
+ parameters: {
+ GeneralProxyModule: {
+ create2Calldata: contractsInfo[property].create2Calldata,
+ },
+ },
+ })
+ ).proxy;
+ await proxyDeployed.waitForDeployment();
+ if ((await proxyDeployed.getAddress()) !== contractsInfo[property].unifiedAddress) {
+ Logger.error(
+ `${contractsInfo[property].name} deployed with unified address: ${await proxyDeployed.getAddress()} (expected: ${contractsInfo[property].unifiedAddress})`,
+ );
+ } else {
+ Logger.success(
+ `${contractsInfo[property].name} deployed with unified address: ${await proxyDeployed.getAddress()}`,
+ );
+ }
+ }
+ }
+});
diff --git a/test/cross-chain/cross-chain-proof-validator.test.ts b/test/cross-chain/cross-chain-proof-validator.test.ts
index 7f66f0ba..9940ecec 100644
--- a/test/cross-chain/cross-chain-proof-validator.test.ts
+++ b/test/cross-chain/cross-chain-proof-validator.test.ts
@@ -91,9 +91,9 @@ describe("State Cross Chain", function () {
};
const proof = await packIdentityStateUpdateWithSignature(ism, signer);
- await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith(
- "Oracle timestamp cannot be in the past",
- );
+ await expect(
+ crossChainProofValidator.processIdentityStateProof(proof),
+ ).to.be.revertedWithCustomError(crossChainProofValidator, "OracleTimestampCannotBeInThePast");
});
it("Oracle replacedAtTimestamp or oracle timestamp cannot be in the future", async function () {
@@ -107,8 +107,11 @@ describe("State Cross Chain", function () {
};
let proof = await packGlobalStateUpdateWithSignature(gsm, signer);
- await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith(
- "Oracle replacedAtTimestamp or oracle timestamp cannot be in the future",
+ await expect(
+ crossChainProofValidator.processGlobalStateProof(proof),
+ ).to.be.revertedWithCustomError(
+ crossChainProofValidator,
+ "OracleReplacedAtTimestampCannotBeInTheFuture",
);
const ism: IdentityStateMessage = {
@@ -119,8 +122,11 @@ describe("State Cross Chain", function () {
};
proof = await packIdentityStateUpdateWithSignature(ism, signer);
- await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith(
- "Oracle replacedAtTimestamp or oracle timestamp cannot be in the future",
+ await expect(
+ crossChainProofValidator.processIdentityStateProof(proof),
+ ).to.be.revertedWithCustomError(
+ crossChainProofValidator,
+ "OracleReplacedAtTimestampCannotBeInTheFuture",
);
});
@@ -135,8 +141,11 @@ describe("State Cross Chain", function () {
};
let proof = await packGlobalStateUpdateWithSignature(gsm, signer, true);
- await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith(
- "Global state proof signing address is not valid",
+ await expect(
+ crossChainProofValidator.processGlobalStateProof(proof),
+ ).to.be.revertedWithCustomError(
+ crossChainProofValidator,
+ "GlobalStateProofSigningAddressInvalid",
);
const ism: IdentityStateMessage = {
@@ -147,8 +156,11 @@ describe("State Cross Chain", function () {
};
proof = await packIdentityStateUpdateWithSignature(ism, signer, true);
- await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith(
- "Identity state proof signing address is not valid",
+ await expect(
+ crossChainProofValidator.processIdentityStateProof(proof),
+ ).to.be.revertedWithCustomError(
+ crossChainProofValidator,
+ "IdentityStateProofSigningAddressInvalid",
);
});
@@ -163,9 +175,9 @@ describe("State Cross Chain", function () {
};
let proof = await packGlobalStateUpdateWithSignature(gsm, signer, false, true);
- await expect(crossChainProofValidator.processGlobalStateProof(proof)).to.be.rejectedWith(
- "Global state proof is not valid",
- );
+ await expect(
+ crossChainProofValidator.processGlobalStateProof(proof),
+ ).to.be.revertedWithCustomError(crossChainProofValidator, "GlobalStateProofInvalid");
const ism: IdentityStateMessage = {
timestamp: currentTimestamp,
@@ -175,8 +187,8 @@ describe("State Cross Chain", function () {
};
proof = await packIdentityStateUpdateWithSignature(ism, signer, false, true);
- await expect(crossChainProofValidator.processIdentityStateProof(proof)).to.be.rejectedWith(
- "Identity state proof is not valid",
- );
+ await expect(
+ crossChainProofValidator.processIdentityStateProof(proof),
+ ).to.be.revertedWithCustomError(crossChainProofValidator, "IdentityStateProofInvalid");
});
});
diff --git a/test/disable-proxy.test.ts b/test/disable-proxy.test.ts
index 37a7edb5..ae87ea7d 100644
--- a/test/disable-proxy.test.ts
+++ b/test/disable-proxy.test.ts
@@ -20,8 +20,8 @@ describe("Disable Proxy Contract test", async () => {
const alwaysRevertFactory = await ethers.getContractFactory("AlwaysRevert");
await upgrades.upgradeProxy(await verifier.getAddress(), alwaysRevertFactory);
- await expect(verifier.verifyProof(d[0], d[1], d[2], d[3])).to.be.revertedWith(
- "The contract is disabled",
+ await expect(verifier.verifyProof(d[0], d[1], d[2], d[3])).to.be.rejectedWith(
+ "TheContractIsDisabled()",
);
await upgrades.upgradeProxy(await verifier.getAddress(), verifierStubFactory);
diff --git a/test/integration-tests/data/user_claim_issued_on_userid_v3.json b/test/integration-tests/data/user_claim_issued_on_userid_v3.json
new file mode 100644
index 00000000..1752523d
--- /dev/null
+++ b/test/integration-tests/data/user_claim_issued_on_userid_v3.json
@@ -0,0 +1,43 @@
+{
+ "pub_signals": [
+ "23273167900576580892722615617815475823351560716009055944677723144398443009",
+ "5163501582380794606957519356304223666405959765481558471633650858228490409290",
+ "2943483356559152311923412925436024635269538717812859789851139200242297094",
+ "20336008450539684768013573494073798243349685857640613070314041678185349736439",
+ "0",
+ "0",
+ "1",
+ "41",
+ "583091486781463398742321306787801699791102451699",
+ "0",
+ "22057981499787921734624217749308316644136637822444794206796063681866502657",
+ "2943483356559152311923412925436024635269538717812859789851139200242297094",
+ "1642074362",
+ "1"
+ ],
+ "proof": {
+ "pi_a": [
+ "19669163552065605232226440325758625657636624385583277995594891950486344866508",
+ "10711637643378840554760385822550851249555527485204302585948254974040755477609",
+ "1"
+ ],
+ "pi_b": [
+ [
+ "2876377569478858706516978096403208510392181149089058781420525859804877516279",
+ "9515133907790273150201355935211769526767866212205498667361695701553682353137"
+ ],
+ [
+ "14869390077573764384106112054362589649141652233556283316748964628563711405904",
+ "1151936578002145346443589143139936031757296603439509995084143527963932212544"
+ ],
+ ["1", "0"]
+ ],
+ "pi_c": [
+ "18589419753357207419833045626873608018236514226418635490877679898608141092303",
+ "4377014052512563002949775596611087745477480197663974829547855257127755207594",
+ "1"
+ ],
+ "protocol": "groth16",
+ "curve": "bn128"
+ }
+}
diff --git a/test/integration-tests/data/user_genesis_auth.json b/test/integration-tests/data/user_genesis_auth.json
new file mode 100644
index 00000000..68afce0f
--- /dev/null
+++ b/test/integration-tests/data/user_genesis_auth.json
@@ -0,0 +1,32 @@
+{
+ "pub_signals": [
+ "23273167900576580892722615617815475823351560716009055944677723144398443009",
+ "5212973139745638668633720237501954966656555739014896868936311397139229290378",
+ "0"
+ ],
+ "proof": {
+ "pi_a": [
+ "1238064536595227341390695164336084541847939190316067358993916901940214723234",
+ "15799255647621631452959766830308132916683864863600158271743280920118665788588",
+ "1"
+ ],
+ "pi_b": [
+ [
+ "17670400722045843961660874132388709522679013234267198690084857080641983583843",
+ "5287730570087617132913682200031155642104951958077715792787827776465000719881"
+ ],
+ [
+ "6075263630519803963226139789246602077914731950499703659787166643095603330195",
+ "7938053062178962435112746593441459158641110827412215757397151271877979765565"
+ ],
+ ["1", "0"]
+ ],
+ "pi_c": [
+ "21010592776578764547907351859929622777512296832984420047235514552228625464856",
+ "18192765798069122918377413910327891618012999130269311083464781452775699686570",
+ "1"
+ ],
+ "protocol": "groth16",
+ "curve": "bn128"
+ }
+}
diff --git a/test/integration-tests/data/user_genesis_auth_challenge_invalid.json b/test/integration-tests/data/user_genesis_auth_challenge_invalid.json
new file mode 100644
index 00000000..890bb82c
--- /dev/null
+++ b/test/integration-tests/data/user_genesis_auth_challenge_invalid.json
@@ -0,0 +1,32 @@
+{
+ "pub_signals": [
+ "23273167900576580892722615617815475823351560716009055944677723144398443009",
+ "2378043419791432977129888049610162411300945363341716024701363947598560258096",
+ "0"
+ ],
+ "proof": {
+ "pi_a": [
+ "9541867327348938145541193982123992297208138293358805560483945427733735306124",
+ "13833819619741404300235158867440476234063725794567625680704749737959767863116",
+ "1"
+ ],
+ "pi_b": [
+ [
+ "20359745551134549335223867766905772056177316525265757287933840985984292914937",
+ "1780864031735933858234307839702997430255911747389589653941781093680324195492"
+ ],
+ [
+ "12080937648102594742202930954953883943640192768810066345568670629167309979739",
+ "13280726496624428913315243268401447342745276267258692974299666120924393078428"
+ ],
+ ["1", "0"]
+ ],
+ "pi_c": [
+ "12131738695386235649587882341686961353232752515854843634252155993701923991681",
+ "18949649035566368476284982950769667836111086011759734792131512893325609072891",
+ "1"
+ ],
+ "protocol": "groth16",
+ "curve": "bn128"
+ }
+}
diff --git a/test/integration-tests/data/user_linked_multi_query.json b/test/integration-tests/data/user_linked_multi_query.json
new file mode 100644
index 00000000..9bb0c3d1
--- /dev/null
+++ b/test/integration-tests/data/user_linked_multi_query.json
@@ -0,0 +1,51 @@
+{
+ "pub_signals": [
+ "20336008450539684768013573494073798243349685857640613070314041678185349736439",
+ "1",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "3326382892536126749483088946048689911243394580824744244053752370464747528203",
+ "9907132056133666096701539062450765284880813426582692863734448403438789333698",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442",
+ "13362042977965885903820557513534065802896288300017199700677633721405805677442"
+ ],
+ "proof": {
+ "pi_a": [
+ "10541909102768476058347747538132221338909944796214430823937430621918433820572",
+ "12998271972533338175505729586393778918022420191938730276405884463074788961369",
+ "1"
+ ],
+ "pi_b": [
+ [
+ "21786734761872104002981387083471529709973058267263166350818620656227477577301",
+ "6784160731236418180364992784613101482914038854158831514386379008042983363743"
+ ],
+ [
+ "17941889499361474971416705471447893349857158046615762117348229875623276791888",
+ "5989944269623828035204132704907772907469171386995335116029892218132563943912"
+ ],
+ ["1", "0"]
+ ],
+ "pi_c": [
+ "17192623970124500187048482626581622763069786710232775241298788913349580516363",
+ "17848067197475549139335038191779648120820902475170770311958006870826316291138",
+ "1"
+ ],
+ "protocol": "groth16",
+ "curve": "bn128"
+ }
+}
diff --git a/test/integration-tests/integration-verifier.test.ts b/test/integration-tests/integration-verifier.test.ts
new file mode 100644
index 00000000..8b44478b
--- /dev/null
+++ b/test/integration-tests/integration-verifier.test.ts
@@ -0,0 +1,259 @@
+import { ethers } from "hardhat";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
+import { prepareInputs } from "../utils/state-utils";
+import authProofJson from "./data/user_genesis_auth.json";
+import authInvalidChallengeProofJson from "./data/user_genesis_auth_challenge_invalid.json";
+import v3ProofJson from "./data/user_claim_issued_on_userid_v3.json";
+import linkedProofJson from "./data/user_linked_multi_query.json";
+import { packZKProof } from "../utils/packData";
+import { expect } from "chai";
+import {
+ packLinkedMultiQueryValidatorParams,
+ packV3ValidatorParams,
+} from "../utils/validator-pack-utils";
+import { CircuitId } from "@0xpolygonid/js-sdk";
+import { calculateQueryHashV3 } from "../utils/query-hash-utils";
+import { TEN_YEARS } from "../../helpers/constants";
+
+describe("Verifier Integration test", function () {
+ let verifier, authValidator, v3Validator, lmkValidator;
+ let signer;
+
+ const requestIdV3 = 32;
+ const requestIdLMK = 33;
+ const groupID = 1;
+
+ const value = ["20020101", ...new Array(63).fill("0")];
+
+ const schema = "267831521922558027206082390043321796944";
+ const slotIndex = 0; // 0 for signature
+ const operator = 7;
+ const claimPathKey =
+ "20376033832371109177683048456014525905119173674985843915445634726167450989630";
+ const [merklized, isRevocationChecked, valueArrSize] = [1, 1, 1];
+ const nullifierSessionId = "0";
+ const verifierId = "21929109382993718606847853573861987353620810345503358891473103689157378049";
+ const queryHash = calculateQueryHashV3(
+ value,
+ schema,
+ slotIndex,
+ operator,
+ claimPathKey,
+ valueArrSize,
+ merklized,
+ isRevocationChecked,
+ verifierId,
+ nullifierSessionId,
+ );
+
+ const query = {
+ schema,
+ claimPathKey,
+ operator,
+ slotIndex,
+ value,
+ circuitIds: [CircuitId.AtomicQueryV3OnChain],
+ skipClaimRevocationCheck: false,
+ queryHash,
+ groupID: groupID,
+ nullifierSessionID: nullifierSessionId, // for ethereum based user
+ proofType: 1, // 1 for BJJ
+ verifierID: verifierId,
+ };
+
+ const crossChainProofs = "0x";
+ const metadatas = "0x";
+ const authMethod = "authV2";
+
+ const v3Params = packV3ValidatorParams(query);
+
+ const twoQueries = {
+ claimPathKey: [
+ 20376033832371109177683048456014525905119173674985843915445634726167450989630n,
+ 20376033832371109177683048456014525905119173674985843915445634726167450989630n,
+ ],
+ operator: [2, 6],
+ slotIndex: [0, 0],
+ value: [
+ [20020101, ...new Array(63).fill(0)],
+ [20030101, ...new Array(63).fill(0)],
+ ],
+ queryHash: [
+ 3326382892536126749483088946048689911243394580824744244053752370464747528203n,
+ 9907132056133666096701539062450765284880813426582692863734448403438789333698n,
+ ],
+ circuitIds: ["linkedMultiQuery10-beta.1"],
+ groupID: groupID,
+ verifierID: verifierId,
+ };
+
+ const twoQueriesParams = packLinkedMultiQueryValidatorParams(twoQueries);
+
+ const v3Proof = getProof(v3ProofJson);
+ const lmqProof = getProof(linkedProofJson);
+
+ function getProof(proofJson: any) {
+ const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
+ const proof = packZKProof(inputs, pi_a, pi_b, pi_c);
+ return proof;
+ }
+
+ async function deployContractsFixture() {
+ [signer] = await ethers.getSigners();
+
+ const verifier = await ethers.deployContract("VerifierTestWrapper", []);
+
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const { state } = await deployHelper.deployStateWithLibraries(["0x0212"]);
+ await verifier.initialize(await state.getAddress());
+
+ const { validator: authValidator } = await deployHelper.deployValidatorContractsWithVerifiers(
+ "authV2",
+ await state.getAddress(),
+ );
+ await authValidator.setProofExpirationTimeout(TEN_YEARS);
+ await authValidator.setGISTRootExpirationTimeout(TEN_YEARS);
+
+ const authMethod = {
+ authMethod: "authV2",
+ validator: await authValidator.getAddress(),
+ params: "0x",
+ };
+ await verifier.setAuthMethod(authMethod);
+
+ const { validator: v3Validator } = await deployHelper.deployValidatorContractsWithVerifiers(
+ "v3",
+ await state.getAddress(),
+ );
+ await v3Validator.setProofExpirationTimeout(TEN_YEARS);
+ await v3Validator.setGISTRootExpirationTimeout(TEN_YEARS);
+
+ const { validator: lmkValidator } = await deployHelper.deployValidatorContractsWithVerifiers(
+ "lmk",
+ await state.getAddress(),
+ );
+
+ return { state, verifier, authValidator, v3Validator, lmkValidator };
+ }
+
+ beforeEach(async () => {
+ ({ verifier, authValidator, v3Validator, lmkValidator } =
+ await loadFixture(deployContractsFixture));
+
+ await verifier.setVerifierID(query.verifierID);
+ });
+
+ it("Should revert with ChallengeIsInvalid for auth proof", async function () {
+ const authInvalidChallengeProof = getProof(authInvalidChallengeProofJson);
+
+ await verifier.setRequests([
+ {
+ requestId: requestIdV3,
+ metadata: "metadata",
+ validator: await v3Validator.getAddress(),
+ params: v3Params,
+ },
+ {
+ requestId: requestIdLMK,
+ metadata: "metadata",
+ validator: await lmkValidator.getAddress(),
+ params: twoQueriesParams,
+ },
+ ]);
+
+ await expect(
+ verifier.submitResponse(
+ {
+ authMethod: authMethod,
+ proof: authInvalidChallengeProof,
+ },
+ [
+ {
+ requestId: requestIdV3,
+ proof: v3Proof,
+ metadata: metadatas,
+ },
+ {
+ requestId: requestIdLMK,
+ proof: lmqProof,
+ metadata: metadatas,
+ },
+ ],
+ crossChainProofs,
+ ),
+ ).to.be.revertedWithCustomError(verifier, "ChallengeIsInvalid");
+ });
+
+ it("Should verify", async function () {
+ const authProof = getProof(authProofJson);
+
+ // 1. Create the requests
+ await verifier.setRequests([
+ {
+ requestId: requestIdV3,
+ metadata: "metadata",
+ validator: await v3Validator.getAddress(),
+ params: v3Params,
+ },
+ {
+ requestId: requestIdLMK,
+ metadata: "metadata",
+ validator: await lmkValidator.getAddress(),
+ params: twoQueriesParams,
+ },
+ ]);
+
+ const multiRequest = {
+ multiRequestId: 1,
+ requestIds: [],
+ groupIds: [groupID],
+ metadata: "0x",
+ };
+
+ // 2. Create the multi-request
+ await expect(verifier.setMultiRequest(multiRequest)).not.to.be.reverted;
+ const multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId);
+ expect(multiRequestIdExists).to.be.true;
+
+ let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest.multiRequestId,
+ await signer.getAddress(),
+ );
+ expect(areMultiRequestProofsVerified).to.be.false;
+
+ // 3. Submitting a response with valid proofs
+ await expect(
+ verifier.submitResponse(
+ {
+ authMethod: authMethod,
+ proof: authProof,
+ },
+ [
+ {
+ requestId: requestIdV3,
+ proof: v3Proof,
+ metadata: metadatas,
+ },
+ {
+ requestId: requestIdLMK,
+ proof: lmqProof,
+ metadata: metadatas,
+ },
+ ],
+ crossChainProofs,
+ ),
+ ).not.to.be.reverted;
+
+ areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest.multiRequestId,
+ await signer.getAddress(),
+ );
+ expect(areMultiRequestProofsVerified).to.be.true;
+ });
+
+ // An integration test with a MultiRequest
+ // The multiRequest has a single group with two requests inside
+ // One request is based on V3 validator
+ // Another one is based on LinkedMultiQuery validator
+});
diff --git a/test/onchain-identity/claim-builder.test.ts b/test/onchain-identity/claim-builder.test.ts
index 374c9fd5..dde6c256 100644
--- a/test/onchain-identity/claim-builder.test.ts
+++ b/test/onchain-identity/claim-builder.test.ts
@@ -2,7 +2,7 @@ import { expect } from "chai";
import { OnchainIdentityDeployHelper } from "../../helpers/OnchainIdentityDeployHelper";
import fs from "fs";
-describe("Claim builder tests", function() {
+describe("Claim builder tests", function () {
let identity;
before(async () => {
@@ -12,118 +12,512 @@ describe("Claim builder tests", function() {
it("validate buildClaim", async function () {
const inputs = [
- { // schemaHash
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- expectedClaims: ['75118319212313495155413841331241344325', '0', '0', '0', '0', '0', '0', '0']
- },
- { // id index
- contractInput: ['75118319212313495155413841331241344325', 1, false, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 0, 0, 0, 0, 0, 0],
- expectedClaims: ['755683053054190422082163056194777767237', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0', '0', '0', '0', '0']
- },
- { // id value
- contractInput: ['75118319212313495155413841331241344325', 2, false, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 0, 0, 0, 0, 0, 0],
- expectedClaims: ['1095965419975128885545537663626545978693', '0', '0', '0', '0', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0']
- },
- { // expirationDate
- contractInput: ['75118319212313495155413841331241344325', 2, true, false, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, 0, 0, 0, 0, 0],
- expectedClaims: ['3818224355342636593252534523080691670341', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0']
- },
- { // updatableFlag
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 0, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, 0, 0, 0, 0, 0],
- expectedClaims: ['9262742226077652008666528241988983053637', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0']
- },
- { // merklized index
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 1, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0],
- expectedClaims: ['20151777967547682839494515679805565820229', '0', '93352129123234552352342342353456456452342343456345234121567843345', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '0', '0']
- },
- { // merklized value
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 0, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0],
- expectedClaims: ['31040813709017713670322503117622148586821', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0']
- },
- { // version
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 0, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0],
- expectedClaims: ['130395355847364581104005408845894865439016836786170092869', '0', '0', '0', '34268264483206187164568125440', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0']
- },
- { // revocation nonce
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 2, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 3312445, 1857686340, '93352129123234552352342342353456456452342343456345234121567843345', 0, 0, 0, 0],
- expectedClaims: ['130395355847364581104005408845894865439016836786170092869', '0', '0', '0', '34268264483206187164571437885', '25425363284463910957419549722021124450832239517990785975889689633068548096', '93352129123234552352342342353456456452342343456345234121567843345', '0']
- },
- { // data slots
- contractInput: ['75118319212313495155413841331241344325', 2, true, true, 0, 89220123, '25425363284463910957419549722021124450832239517990785975889689633068548096', 3312445, 1857686340, '0', '16243864111864693853212588481963275789994876191154110553066821559749894481761', '7078462697308959301666117070269719819629678436794910510259518359026273676830', '12448278679517811784508557734102986855579744384337338465055621486538311281772', '9260608685281348956030279125705000716237952776955782848598673606545494194823'],
- expectedClaims: ['130395355847364559325933925905833203783041961153004559685', '0', '16243864111864693853212588481963275789994876191154110553066821559749894481761', '7078462697308959301666117070269719819629678436794910510259518359026273676830', '34268264483206187164571437885', '25425363284463910957419549722021124450832239517990785975889689633068548096', '12448278679517811784508557734102986855579744384337338465055621486538311281772', '9260608685281348956030279125705000716237952776955782848598673606545494194823']
- },
+ {
+ // schemaHash
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "75118319212313495155413841331241344325",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // id index
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 1,
+ false,
+ false,
+ 0,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "755683053054190422082163056194777767237",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // id value
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ false,
+ false,
+ 0,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "1095965419975128885545537663626545978693",
+ "0",
+ "0",
+ "0",
+ "0",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // expirationDate
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ false,
+ 0,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 1857686340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "3818224355342636593252534523080691670341",
+ "0",
+ "0",
+ "0",
+ "34268264483206187164568125440",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // updatableFlag
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 0,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 1857686340,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "9262742226077652008666528241988983053637",
+ "0",
+ "0",
+ "0",
+ "34268264483206187164568125440",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // merklized index
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 1,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 1857686340,
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "20151777967547682839494515679805565820229",
+ "0",
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ "0",
+ "34268264483206187164568125440",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "0",
+ "0",
+ ],
+ },
+ {
+ // merklized value
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 2,
+ 0,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 1857686340,
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "31040813709017713670322503117622148586821",
+ "0",
+ "0",
+ "0",
+ "34268264483206187164568125440",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ "0",
+ ],
+ },
+ {
+ // version
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 2,
+ 89220123,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 0,
+ 1857686340,
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "130395355847364581104005408845894865439016836786170092869",
+ "0",
+ "0",
+ "0",
+ "34268264483206187164568125440",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ "0",
+ ],
+ },
+ {
+ // revocation nonce
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 2,
+ 89220123,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 3312445,
+ 1857686340,
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedClaims: [
+ "130395355847364581104005408845894865439016836786170092869",
+ "0",
+ "0",
+ "0",
+ "34268264483206187164571437885",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "93352129123234552352342342353456456452342343456345234121567843345",
+ "0",
+ ],
+ },
+ {
+ // data slots
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ true,
+ true,
+ 0,
+ 89220123,
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ 3312445,
+ 1857686340,
+ "0",
+ "16243864111864693853212588481963275789994876191154110553066821559749894481761",
+ "7078462697308959301666117070269719819629678436794910510259518359026273676830",
+ "12448278679517811784508557734102986855579744384337338465055621486538311281772",
+ "9260608685281348956030279125705000716237952776955782848598673606545494194823",
+ ],
+ expectedClaims: [
+ "130395355847364559325933925905833203783041961153004559685",
+ "0",
+ "16243864111864693853212588481963275789994876191154110553066821559749894481761",
+ "7078462697308959301666117070269719819629678436794910510259518359026273676830",
+ "34268264483206187164571437885",
+ "25425363284463910957419549722021124450832239517990785975889689633068548096",
+ "12448278679517811784508557734102986855579744384337338465055621486538311281772",
+ "9260608685281348956030279125705000716237952776955782848598673606545494194823",
+ ],
+ },
];
for (let i = 0; i < inputs.length; i++) {
- const input = inputs[i];
- const claims = await identity.buildClaim(input.contractInput);
- // console.log(claims);
- claims.forEach((c, cIndex) => {
- expect(c == input.expectedClaims[cIndex]).to.be.true;
- });
+ const input = inputs[i];
+ const claims = await identity.buildClaim(input.contractInput);
+ // console.log(claims);
+ claims.forEach((c, cIndex) => {
+ expect(c == input.expectedClaims[cIndex]).to.be.true;
+ });
}
});
it("validate buildClaim errors", async function () {
const inputs = [
- { // idPosition = 0 & id not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, '8764639037689384765', 0, 0, 0, 0, 0, 0, 0],
- expectedErr: 'id should be empty'
- },
- { // idPosition = 1 & id null
- contractInput: ['75118319212313495155413841331241344325', 1, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- expectedErr: 'id should be not empty'
- },
- { // idPosition = 2 & id null
- contractInput: ['75118319212313495155413841331241344325', 2, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- expectedErr: 'id should be not empty'
- },
- { // idPosition = 3 - invalid position
- contractInput: ['75118319212313495155413841331241344325', 3, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- expectedErr: 'invalid id position'
- },
- { // expirable = false & expiration date not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 89220123, 0, 0, 0, 0, 0],
- expectedErr: 'expirationDate should be 0 for non expirable claim'
- },
- { // updatable = false & version not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 12133, 0, 0, 0, 0, 0, 0, 0, 0],
- expectedErr: 'version should be 0 for non updatable claim'
- },
- { // merklizedRootPosition = 1 & indx data slot not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 1, 0, 0, 0, 0, 0, 1234421, 0, 0, 0],
- expectedErr: 'data slots should be empty'
- },
- { // merklizedRootPosition = 2 & value data slot not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 1, 0, 0, 0, 0, 0, 0, 0, 123445, 0],
- expectedErr: 'data slots should be empty'
- },
- { // merklizedRootPosition = 0 & merklizedRoot not null
- contractInput: ['75118319212313495155413841331241344325', 0, false, false, 0, 0, 0, 0, 0, '972355817823445311', 0, 0, 0, 0],
- expectedErr: 'merklizedRoot should be 0 for non merklized claim'
- },
+ {
+ // idPosition = 0 & id not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 0,
+ 0,
+ "8764639037689384765",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "IdShouldBeEmpty",
+ },
+ {
+ // idPosition = 1 & id null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 1,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "IdShouldBeNotEmpty",
+ },
+ {
+ // idPosition = 2 & id null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 2,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "IdShouldBeNotEmpty",
+ },
+ {
+ // idPosition = 3 - invalid position
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 3,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "InvalidIdPosition",
+ },
+ {
+ // expirable = false & expiration date not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 89220123,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "ExpirationDateShouldBeZeroForNonExpirableClaim",
+ },
+ {
+ // updatable = false & version not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 0,
+ 12133,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "VersionShouldBeZeroForNonUpdatableClaim",
+ },
+ {
+ // merklizedRootPosition = 1 & indx data slot not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1234421,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "DataSlotsShouldBeEmpty",
+ },
+ {
+ // merklizedRootPosition = 2 & value data slot not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 123445,
+ 0,
+ ],
+ expectedErr: "DataSlotsShouldBeEmpty",
+ },
+ {
+ // merklizedRootPosition = 0 & merklizedRoot not null
+ contractInput: [
+ "75118319212313495155413841331241344325",
+ 0,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "972355817823445311",
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ expectedErr: "MerklizedRootShouldBeZeroForNonMerklizedClaim",
+ },
];
for (let i = 0; i < inputs.length; i++) {
- const input = inputs[i];
- try {
- await identity.buildClaim(input.contractInput);
- expect.fail('The transaction should have thrown an error');
- } catch (err: any) {
- expect(err.message).to.include(input.expectedErr);
- }
+ const input = inputs[i];
+ try {
+ await identity.buildClaim(input.contractInput);
+ expect.fail("The transaction should have thrown an error");
+ } catch (err: any) {
+ expect(err.message).to.include(input.expectedErr);
+ }
}
-
});
it("validate buildClaim from file", async function () {
- var inputs: any[] = JSON.parse(fs.readFileSync(require.resolve('./vectorsGen/data/claimBuilderData.json'), 'utf-8'))
- console.log(inputs.length)
+ var inputs: any[] = JSON.parse(
+ fs.readFileSync(require.resolve("./vectorsGen/data/claimBuilderData.json"), "utf-8"),
+ );
+ console.log(inputs.length);
for (let i = 0; i < inputs.length; i++) {
- const input = inputs[i];
- const claims = await identity.buildClaim(input.contractInput);
- claims.forEach((c, cIndex) => {
- expect(c == input.expectedClaims[cIndex]).to.be.true;
- });
+ const input = inputs[i];
+ const claims = await identity.buildClaim(input.contractInput);
+ claims.forEach((c, cIndex) => {
+ expect(c == input.expectedClaims[cIndex]).to.be.true;
+ });
}
});
-
});
diff --git a/test/onchain-identity/onchain-identity.test.ts b/test/onchain-identity/onchain-identity.test.ts
index d9fc000e..b8bee4a2 100644
--- a/test/onchain-identity/onchain-identity.test.ts
+++ b/test/onchain-identity/onchain-identity.test.ts
@@ -616,7 +616,7 @@ describe("Genesis state doens't have history of states", () => {
await identity.getRootsByState(latestState);
expect.fail("The transaction should have thrown an error");
} catch (err: any) {
- expect(err.message).to.include("Roots for this state doesn't exist");
+ expect(err.message).to.include("RootsForThisStateDoesntExist");
}
});
});
diff --git a/test/primitiveUtils/primitiveUtils.test.ts b/test/primitiveUtils/primitiveUtils.test.ts
index 9bad04c6..57817f11 100644
--- a/test/primitiveUtils/primitiveUtils.test.ts
+++ b/test/primitiveUtils/primitiveUtils.test.ts
@@ -1,6 +1,5 @@
import { DeployHelper } from "../../helpers/DeployHelper";
import { expect } from "chai";
-import { ethers } from "hardhat";
let utilsWrapper;
@@ -38,10 +37,9 @@ describe("uint conversions", function () {
});
it("invalid challenge (uint256 LE address) must produce error", async () => {
- const address = "0x3930000000000000000000000000000000000000";
const uint256 = "5010846606798320903600395684540411235907858077292797642081699116";
await expect(utilsWrapper.uint256LEToAddress(uint256)).to.be.rejectedWith(
- "given uint256 is not a representation of an address, 12 most significant bytes should be zero",
+ "GivenInputNotAnAddressRepresentation(5010846606798320903600395684540411235907858077292797642081699116)",
);
});
diff --git a/test/smtLib/smtLib.test.ts b/test/smtLib/smtLib.test.ts
index be6181ec..e750f8b2 100644
--- a/test/smtLib/smtLib.test.ts
+++ b/test/smtLib/smtLib.test.ts
@@ -982,7 +982,7 @@ describe("Merkle tree proofs of SMT", () => {
description: "Negative: add two leaves with maximum depth + 1 (less significant bits SET)",
leavesToInsert: [
{ i: genMaxBinaryNumber(64), v: 100 }, //1111111111111111111111111111111111111111111111111111111111111111
- { i: genMaxBinaryNumber(65), v: 100, error: "Max depth reached" }, //11111111111111111111111111111111111111111111111111111111111111111
+ { i: genMaxBinaryNumber(65), v: 100, error: "MaxDepthReached()" }, //11111111111111111111111111111111111111111111111111111111111111111
],
},
{
@@ -990,7 +990,7 @@ describe("Merkle tree proofs of SMT", () => {
"Negative: add two leaves with maximum depth + 1 (less significant bits NOT SET)",
leavesToInsert: [
{ i: 0, v: 100 },
- { i: genMaxBinaryNumber(64) + BigInt(1), v: 100, error: "Max depth reached" }, // 10000000000000000000000000000000000000000000000000000000000000000
+ { i: genMaxBinaryNumber(64) + BigInt(1), v: 100, error: "MaxDepthReached()" }, // 10000000000000000000000000000000000000000000000000000000000000000
],
},
{
@@ -998,7 +998,7 @@ describe("Merkle tree proofs of SMT", () => {
"Negative: add two leaves with maximum depth + 1 (less significant bits are both SET and NOT SET",
leavesToInsert: [
{ i: "17713686966169915918", v: 100 }, //1111010111010011101010000111000111010001000001100101001000001110
- { i: "36160431039879467534", v: 100, error: "Max depth reached" }, //11111010111010011101010000111000111010001000001100101001000001110
+ { i: "36160431039879467534", v: 100, error: "MaxDepthReached()" }, //11111010111010011101010000111000111010001000001100101001000001110
],
},
];
@@ -1061,16 +1061,16 @@ describe("Root history requests", function () {
});
it("should revert if length is zero", async () => {
- await expect(smt.getRootHistory(0, 0)).to.be.rejectedWith("Length should be greater than 0");
+ await expect(smt.getRootHistory(0, 0)).to.be.rejectedWith("LenghtShouldBeGreaterThanZero()");
});
it("should revert if length limit exceeded", async () => {
- await expect(smt.getRootHistory(0, 10 ** 6)).to.be.rejectedWith("Length limit exceeded");
+ await expect(smt.getRootHistory(0, 10 ** 6)).to.be.rejectedWith("LengthLimitExceeded(1000)");
});
it("should revert if out of bounds", async () => {
await expect(smt.getRootHistory(historyLength, 100)).to.be.rejectedWith(
- "Start index out of bounds",
+ "StartIndexOutOfBounds(3)",
);
});
@@ -1126,7 +1126,7 @@ describe("Root history duplicates", function () {
const riDoubleRoot = await smt.getRootInfoListByRoot(doubleRoot, 0, 100);
const riTripleRoot = await smt.getRootInfoListByRoot(tripleRoot, 0, 100);
await expect(smt.getRootInfoListByRoot(nonExistingRoot, 0, 100)).to.be.rejectedWith(
- "Root does not exist",
+ "RootDoesNotExist()",
);
expect(riSingleRoot.length).to.be.equal(1);
@@ -1158,7 +1158,7 @@ describe("Root history duplicates", function () {
await smt.add(1, 1);
const root = await smt.getRoot();
await expect(smt.getRootInfoListByRoot(root, 0, 0)).to.be.rejectedWith(
- "Length should be greater than 0",
+ "LenghtShouldBeGreaterThanZero()",
);
});
@@ -1166,7 +1166,7 @@ describe("Root history duplicates", function () {
await smt.add(1, 1);
const root = await smt.getRoot();
await expect(smt.getRootInfoListByRoot(root, 0, 10 ** 6)).to.be.rejectedWith(
- "Length limit exceeded",
+ "LengthLimitExceeded(1000)",
);
});
@@ -1176,7 +1176,7 @@ describe("Root history duplicates", function () {
await smt.add(1, 1);
const root = await smt.getRoot();
await expect(smt.getRootInfoListByRoot(root, 3, 100)).to.be.rejectedWith(
- "Start index out of bounds",
+ "StartIndexOutOfBounds(2)",
);
});
@@ -1769,14 +1769,14 @@ describe("Edge cases with exceptions", () => {
await smt.add(1, 1);
const root = await smt.getRoot();
await expect(smt.getRootInfo(root)).not.to.be.rejected;
- await expect(smt.getRootInfo(root + 1n)).to.be.rejectedWith("Root does not exist");
+ await expect(smt.getRootInfo(root + 1n)).to.be.rejectedWith("RootDoesNotExist()");
});
it("getProofByRoot() should throw when root does not exist", async () => {
await smt.add(1, 1);
const root = await smt.getRoot();
await expect(smt.getProofByRoot(1, root)).not.to.be.rejected;
- await expect(smt.getProofByRoot(1, root + 1n)).to.be.rejectedWith("Root does not exist");
+ await expect(smt.getProofByRoot(1, root + 1n)).to.be.rejectedWith("RootDoesNotExist()");
});
});
@@ -1804,22 +1804,20 @@ describe("maxDepth setting tests", () => {
});
it("Should throw when decrease max depth", async () => {
- await expect(smt.setMaxDepth(127)).to.be.rejectedWith("Max depth can only be increased");
+ await expect(smt.setMaxDepth(127)).to.be.rejectedWith("MaxDepthCanOnlyBeIncreased()");
});
it("Should throw when max depth is set to the same value", async () => {
- await expect(smt.setMaxDepth(128)).to.be.rejectedWith("Max depth can only be increased");
+ await expect(smt.setMaxDepth(128)).to.be.rejectedWith("MaxDepthCanOnlyBeIncreased()");
});
it("Should throw when max depth is set to 0", async () => {
- await expect(smt.setMaxDepth(0)).to.be.rejectedWith("Max depth must be greater than zero");
+ await expect(smt.setMaxDepth(0)).to.be.rejectedWith("MaxDepthMustBeGreaterThanZero()");
});
it("Should throw when max depth is set to greater than hard cap", async () => {
- await expect(smt.setMaxDepth(257)).to.be.rejectedWith("Max depth is greater than hard cap");
- await expect(smt.setMaxDepth(1000000000)).to.be.rejectedWith(
- "Max depth is greater than hard cap",
- );
+ await expect(smt.setMaxDepth(257)).to.be.rejectedWith("MaxDepthIsGreaterThanHardCap()");
+ await expect(smt.setMaxDepth(1000000000)).to.be.rejectedWith("MaxDepthIsGreaterThanHardCap()");
});
});
diff --git a/test/state/state.test.ts b/test/state/state.test.ts
index 51e30f98..8d591174 100644
--- a/test/state/state.test.ts
+++ b/test/state/state.test.ts
@@ -44,8 +44,9 @@ describe("State transition with real groth16 verifier", () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithProofs[0]));
modifiedStateTransition.pub_signals[2] = "100"; // change state to make zk proof invalid
- await expect(publishState(state, modifiedStateTransition)).to.be.rejectedWith(
- "Zero-knowledge proof of state transition is not valid",
+ await expect(publishState(state, modifiedStateTransition)).to.be.revertedWithCustomError(
+ state,
+ "ZeroKnowledgeProofOfStateTransitionIsNotValid",
);
});
@@ -136,9 +137,9 @@ describe("State transition negative cases", () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[1]));
modifiedStateTransition.oldState = 10;
- await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith(
- "Old state does not match the latest state",
- );
+ await expect(
+ publishStateWithStubProof(state, modifiedStateTransition),
+ ).to.be.revertedWithCustomError(state, "OldStateDoesNotMatchTheLatestState");
});
it("Old state is genesis but identity already exists", async () => {
@@ -147,36 +148,36 @@ describe("State transition negative cases", () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[1]));
modifiedStateTransition.isOldStateGenesis = true;
- await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith(
- "Old state is genesis but identity already exists",
- );
+ await expect(
+ publishStateWithStubProof(state, modifiedStateTransition),
+ ).to.be.revertedWithCustomError(state, "OldStateIsGenesisButIdentityAlreadyExists");
});
it("Old state is not genesis but identity does not yet exist", async () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0]));
modifiedStateTransition.isOldStateGenesis = false;
- await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith(
- "Old state is not genesis but identity does not yet exist",
- );
+ await expect(
+ publishStateWithStubProof(state, modifiedStateTransition),
+ ).to.be.revertedWithCustomError(state, "OldStateIsNotGenesisButIdentityDoesNotExist");
});
it("ID should not be zero", async () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0]));
modifiedStateTransition.id = 0;
- await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith(
- "ID should not be zero",
- );
+ await expect(
+ publishStateWithStubProof(state, modifiedStateTransition),
+ ).to.be.revertedWithCustomError(state, "IdShouldNotBeZero");
});
it("New state should not be zero", async () => {
const modifiedStateTransition = JSON.parse(JSON.stringify(stateTransitionsWithNoProofs[0]));
modifiedStateTransition.newState = 0;
- await expect(publishStateWithStubProof(state, modifiedStateTransition)).to.be.rejectedWith(
- "New state should not be zero",
- );
+ await expect(
+ publishStateWithStubProof(state, modifiedStateTransition),
+ ).to.be.revertedWithCustomError(state, "NewStateShouldNotBeZero");
});
it("Should allow only one unique state per identity", async () => {
@@ -190,8 +191,9 @@ describe("State transition negative cases", () => {
isOldStateGenesis: false,
};
- await expect(publishStateWithStubProof(state, stateTransition)).to.be.rejectedWith(
- "New state already exists",
+ await expect(publishStateWithStubProof(state, stateTransition)).to.be.revertedWithCustomError(
+ state,
+ "NewStateAlreadyExists",
);
});
});
@@ -433,12 +435,14 @@ describe("Check replacedAt timestamp expirations", () => {
expect(await state.getGistRootReplacedAt("0x0112", 0)).to.be.equal(0);
- await expect(state.getGistRootReplacedAt("0x0112", 10)).to.be.rejectedWith(
- "GIST root entry not found",
+ await expect(state.getGistRootReplacedAt("0x0112", 10)).to.be.revertedWithCustomError(
+ state,
+ "GistRootEntryNotFound",
);
- await expect(state.getGistRootReplacedAt("0x0212", 10)).to.be.rejectedWith(
- "Cross-chain GIST root not found",
+ await expect(state.getGistRootReplacedAt("0x0212", 10)).to.be.revertedWithCustomError(
+ state,
+ "CrossChainGistRootNotFound",
);
expect(
@@ -453,13 +457,13 @@ describe("Check replacedAt timestamp expirations", () => {
BigInt("0xD9C10A0BFB514F30B64E115D7EEB3D547C240C104E03D4548375669FE1201"),
0,
),
- ).to.be.rejectedWith("State entry not found");
+ ).to.be.revertedWithCustomError(state, "StateEntryNotFound");
await expect(
state.getStateReplacedAt(
BigInt("0xD9C10A0BFB514F30B64E115D7EEB3D547C240C104E03D4548375669FE1202"),
0,
),
- ).to.be.rejectedWith("Cross-chain state not found");
+ ).to.be.revertedWithCustomError(state, "CrossChainStateNotFound");
});
});
diff --git a/test/state/stateV2_v3_migration.test.ts b/test/state/stateV2_v3_migration.test.ts
deleted file mode 100644
index eae3a7b2..00000000
--- a/test/state/stateV2_v3_migration.test.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { expect } from "chai";
-import { ethers, network} from "hardhat";
-import { publishState } from "../utils/state-utils";
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { StateContractMigrationHelper } from "../../helpers/StateContractMigrationHelper";
-
-const stateTransitionsWithProofs = [
- require("./data/user_state_genesis_transition.json"),
- require("./data/user_state_next_transition.json"),
- ];
-
- const stateTransitionsWithNoProofs = [
- {
- id: '6901746346790563787434755862277025452451108972170386555162524223864832',
- oldState: '1099511627776',
- newState: '2199023255552',
- isOldStateGenesis: true,
- },
- {
- id: '6901746346790563787434755862277025452451108972170386555162524223864832',
- oldState: '2199023255552',
- newState: '3298534883328',
- isOldStateGenesis: false,
- },
- ];
-
-describe.skip("Get State old Contract and migrate to latest version", () => {
- let guWrpr;
- let deployHelper;
- let signers;
-
- before(async function () {
- signers = await ethers.getSigners();
- deployHelper = await DeployHelper.initialize();
- guWrpr = await deployHelper.deployGenesisUtilsWrapper();
- });
-
- it("Check migration", async () => {
- // 1. init old contract by abi & address
- const stateContractMigrationHelper = new StateContractMigrationHelper(deployHelper, signers[0]);
- const oldContractABI = []; // abi of contract that will be upgraded
- const stateContractAddress = ''; // address of contract that will be upgraded
- const stateContractInstance = await stateContractMigrationHelper.getInitContract({
- contractNameOrAbi: oldContractABI,
- address: stateContractAddress,
- });
-
- // 2. publish first state
- const params1 = await publishState(stateContractInstance, stateTransitionsWithProofs[0]);
- const res1 = await stateContractInstance.getStateInfoById(params1.id);
- expect(res1.state).to.be.equal(BigInt(params1.newState).toString());
-
- // 3. migrate
- const { state: stateV3 } = await stateContractMigrationHelper.upgradeContract(stateContractInstance);
-
- // 4. publish second state
- const params2 = await publishState(stateV3, stateTransitionsWithProofs[1]);
- const res2 = await stateV3.getStateInfoById(params2.id);
- expect(res2.state).to.be.equal(BigInt(params2.newState).toString());
-
- // 5. check _defaultIdType is not initialized
- await expect(stateV3.getDefaultIdType()).to.be.rejectedWith(
- "Default Id Type is not initialized",
- );
- // 6. initialize _defaultIdType
- const { defaultIdType } = await deployHelper.getDefaultIdType();
- await stateV3.setDefaultIdType(defaultIdType);
- const defIdTypeValue = await stateV3.getDefaultIdType();
- expect(defaultIdType).to.be.equal(defIdTypeValue);
-
- // 7. run new 'transitStateGeneric' method
- const onchainId = await guWrpr.calcOnchainIdFromAddress(
- defaultIdType,
- await signers[0].getAddress(),
- );
- await stateV3.transitStateGeneric(
- onchainId,
- stateTransitionsWithNoProofs[0].oldState,
- stateTransitionsWithNoProofs[0].newState,
- stateTransitionsWithNoProofs[0].isOldStateGenesis,
- 1,
- []
- );
-
- const res3 = await stateV3.getStateInfoById(onchainId);
- expect(res3.state).to.be.equal(bigInt(stateTransitionsWithNoProofs[0].newState).toString());
-
- });
-});
diff --git a/test/stateLib/stateLib.test.ts b/test/stateLib/stateLib.test.ts
index d23cc8f7..0600ff00 100644
--- a/test/stateLib/stateLib.test.ts
+++ b/test/stateLib/stateLib.test.ts
@@ -27,24 +27,24 @@ describe("Negative tests", function () {
it("getStateInfoByID: should be reverted if identity does not exist", async () => {
const missingID = 777;
- await expect(stateLibWrpr.getStateInfoById(missingID)).to.be.revertedWith(
- "Identity does not exist",
+ await expect(stateLibWrpr.getStateInfoById(missingID)).to.be.rejectedWith(
+ "IdentityDoesNotExist()",
);
});
it("getStateInfoHistoryById: should be reverted if identity does not exist", async () => {
const missingID = 777;
- await expect(stateLibWrpr.getStateInfoHistoryById(missingID, 0, 1)).to.be.revertedWith(
- "Identity does not exist",
+ await expect(stateLibWrpr.getStateInfoHistoryById(missingID, 0, 1)).to.be.rejectedWith(
+ "IdentityDoesNotExist()",
);
});
it("getStateInfoHistoryLengthById: should be reverted if identity does not exist", async () => {
const missingID = 777;
- await expect(stateLibWrpr.getStateInfoHistoryLengthById(missingID)).to.be.revertedWith(
- "Identity does not exist",
+ await expect(stateLibWrpr.getStateInfoHistoryLengthById(missingID)).to.be.rejectedWith(
+ "IdentityDoesNotExist()",
);
});
@@ -52,21 +52,17 @@ describe("Negative tests", function () {
const id = id1Inputs[0].id;
const missingState = 888;
- await expect(stateLibWrpr.getStateInfoByIdAndState(id, missingState)).to.be.revertedWith(
- "State does not exist",
+ await expect(stateLibWrpr.getStateInfoByIdAndState(id, missingState)).to.be.rejectedWith(
+ "StateDoesNotExist()",
);
});
it("Zero timestamp and block should be only in the first identity state", async () => {
await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.not.reverted;
- await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.revertedWith(
- "Zero timestamp and block should be only in the first identity state",
- );
+ await expect(stateLibWrpr.addGenesisState(2, 20)).to.be.rejectedWith("IdentityAlreadyExists()");
await expect(stateLibWrpr.addState(3, 30)).to.be.not.reverted;
- await expect(stateLibWrpr.addGenesisState(3, 30)).to.be.revertedWith(
- "Zero timestamp and block should be only in the first identity state",
- );
+ await expect(stateLibWrpr.addGenesisState(3, 30)).to.be.rejectedWith("IdentityAlreadyExists()");
});
});
@@ -117,21 +113,21 @@ describe("StateInfo history", function () {
});
it("should be reverted if length is zero", async () => {
- await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 0)).to.be.revertedWith(
- "Length should be greater than 0",
+ await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 0)).to.be.rejectedWith(
+ "LenghtShouldBeGreaterThanZero()",
);
});
it("should be reverted if length limit exceeded", async () => {
- await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 10 ** 6)).to.be.revertedWith(
- "Length limit exceeded",
+ await expect(stateLibWrpr.getStateInfoHistoryById(id1, 0, 10 ** 6)).to.be.rejectedWith(
+ "LengthLimitExceeded(1000)",
);
});
it("should be reverted if startIndex is out of bounds", async () => {
await expect(
stateLibWrpr.getStateInfoHistoryById(id1, id1HistoryLength, 100),
- ).to.be.revertedWith("Start index out of bounds");
+ ).to.be.rejectedWith("StartIndexOutOfBounds(2)");
});
it("should not revert if startIndex + length >= historyLength", async () => {
@@ -252,7 +248,7 @@ describe("State history duplicates", function () {
const state = 1;
await stateLibWrpr.addState(id, state);
await expect(stateLibWrpr.getStateInfoListByIdAndState(id, state, 0, 0)).to.be.rejectedWith(
- "Length should be greater than 0",
+ "LenghtShouldBeGreaterThanZero()",
);
});
@@ -262,7 +258,7 @@ describe("State history duplicates", function () {
await stateLibWrpr.addState(id, state);
await expect(
stateLibWrpr.getStateInfoListByIdAndState(id, state, 0, 10 ** 6),
- ).to.be.revertedWith("Length limit exceeded");
+ ).to.be.rejectedWith("LengthLimitExceeded(1000)");
});
it("should revert if out of bounds", async () => {
@@ -271,8 +267,8 @@ describe("State history duplicates", function () {
await stateLibWrpr.addState(id, state);
await stateLibWrpr.addState(id, state);
await stateLibWrpr.addState(id, state);
- await expect(stateLibWrpr.getStateInfoListByIdAndState(id, state, 3, 100)).to.be.revertedWith(
- "Start index out of bounds",
+ await expect(stateLibWrpr.getStateInfoListByIdAndState(id, state, 3, 100)).to.be.rejectedWith(
+ "StartIndexOutOfBounds(3)",
);
it("should NOT revert if startIndex + length >= historyLength", async () => {
diff --git a/test/utils/validator-pack-utils.ts b/test/utils/validator-pack-utils.ts
index 68cde7af..900c6386 100644
--- a/test/utils/validator-pack-utils.ts
+++ b/test/utils/validator-pack-utils.ts
@@ -15,7 +15,7 @@ export function packValidatorParams(query: any, allowedIssuers: any[] = []): str
"uint256[] allowedIssuers," +
"string[] circuitIds," +
"bool skipClaimRevocationCheck," +
- "uint256 claimPathNotExists" +
+ "uint256 claimPathNotExists," +
")",
],
[
@@ -31,7 +31,7 @@ export function packValidatorParams(query: any, allowedIssuers: any[] = []): str
skipClaimRevocationCheck: query.skipClaimRevocationCheck,
claimPathNotExists: query.claimPathNotExists,
},
- ]
+ ],
);
}
@@ -70,6 +70,35 @@ export function packV3ValidatorParams(query: any, allowedIssuers: any[] = []): s
proofType: query.proofType,
verifierID: query.verifierID,
},
- ]
+ ],
+ );
+}
+
+export function packLinkedMultiQueryValidatorParams(query: any): string {
+ return abiCoder.encode(
+ [
+ "tuple(" +
+ "uint256[] claimPathKey," +
+ "uint256[] operator," +
+ "uint256[] slotIndex," +
+ "uint256[][] value," +
+ "uint256[] queryHash," +
+ "string[] circuitIds," +
+ "uint256 groupID," +
+ "uint256 verifierID," +
+ ")",
+ ],
+ [
+ {
+ claimPathKey: query.claimPathKey,
+ operator: query.operator,
+ slotIndex: query.slotIndex,
+ value: query.value,
+ queryHash: query.queryHash,
+ circuitIds: query.circuitIds,
+ groupID: query.groupID,
+ verifierID: query.verifierID,
+ },
+ ],
);
}
diff --git a/test/validators/authv2/index.ts b/test/validators/authv2/index.ts
new file mode 100644
index 00000000..091f99c9
--- /dev/null
+++ b/test/validators/authv2/index.ts
@@ -0,0 +1,113 @@
+import { expect } from "chai";
+import { prepareInputs, publishState } from "../../utils/state-utils";
+import { DeployHelper } from "../../../helpers/DeployHelper";
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
+import { packZKProof } from "../../utils/packData";
+import { time } from "@nomicfoundation/hardhat-network-helpers";
+import { contractsInfo } from "../../../helpers/constants";
+
+const testCases: any[] = [
+ {
+ name: "Validate AuthV2",
+ sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ stateTransitions: [
+ require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"),
+ ],
+ userID: 23273167900576580892722615617815475823351560716009055944677723144398443009n,
+ },
+ {
+ name: "Validation of Gist root not found",
+ sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ stateTransitions: [
+ require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"),
+ ],
+ userID: 23273167900576580892722615617815475823351560716009055944677723144398443009n,
+ gistRoot: 2n,
+ errorMessage: "GistRootEntryNotFound()",
+ },
+];
+
+describe("Auth V2 Validator", function () {
+ let state: any, authV2validator;
+
+ async function deployContractsFixture() {
+ const deployHelper = await DeployHelper.initialize(null, true);
+
+ const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0212"]);
+
+ const verifierStub = await deployHelper.deployGroth16VerifierValidatorStub();
+
+ const contracts = await deployHelper.deployValidatorContractsWithVerifiers(
+ "authV2",
+ await stateContract.getAddress(),
+ "basic",
+ await verifierStub.getAddress(),
+ );
+ const validator = contracts.validator;
+
+ return {
+ stateContract,
+ validator,
+ };
+ }
+
+ beforeEach(async () => {
+ ({ stateContract: state, validator: authV2validator } =
+ await loadFixture(deployContractsFixture));
+ });
+
+ for (const test of testCases) {
+ it(test.name, async function () {
+ this.timeout(50000);
+
+ for (let i = 0; i < test.stateTransitions.length; i++) {
+ if (test.stateTransitionDelayMs) {
+ await time.increase(test.stateTransitionDelayMs);
+ }
+ await publishState(state, test.stateTransitions[i]);
+ }
+
+ const challenge =
+ test.challenge || "0x0000000000000000000000000000000000000000000000000000000000000001";
+
+ const proof = {
+ pub_signals: [test.userID, challenge, test.gistRoot || "0"],
+ proof: {
+ pi_a: ["0", "0", "0"],
+ pi_b: [
+ ["0", "0"],
+ ["0", "0"],
+ ["0", "0"],
+ ],
+ pi_c: ["0", "0", "0"],
+ protocol: "groth16",
+ curve: "bn128",
+ },
+ };
+
+ const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proof);
+
+ const data = "0x00";
+
+ // Check verify function
+ const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
+
+ if (test.errorMessage) {
+ await expect(authV2validator.verify(test.sender, zkProof, data)).to.be.rejectedWith(
+ test.errorMessage,
+ );
+ } else if (test.errorMessage === "") {
+ await expect(authV2validator.verify(test.sender, zkProof, data)).to.be.reverted;
+ } else {
+ const result = await authV2validator.verify(test.sender, zkProof, data);
+
+ expect(result[0]).to.be.equal(test.userID);
+ }
+ });
+ }
+
+ it("check version", async () => {
+ const version = await authV2validator.version();
+ expect(version).to.be.equal(contractsInfo.VALIDATOR_AUTH_V2.version);
+ });
+});
diff --git a/test/validators/linked-multi-query/linked-multi-query.test.ts b/test/validators/linked-multi-query/linked-multi-query.test.ts
new file mode 100644
index 00000000..794b7d2c
--- /dev/null
+++ b/test/validators/linked-multi-query/linked-multi-query.test.ts
@@ -0,0 +1,194 @@
+import { ethers } from "hardhat";
+import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
+import { packZKProof } from "../../utils/packData";
+import { packLinkedMultiQueryValidatorParams } from "../../utils/validator-pack-utils";
+import { expect } from "chai";
+import { contractsInfo } from "../../../helpers/constants";
+
+describe("Test linkedMultiQuery10.circom", function () {
+ let validator, groth16Verifier;
+ let signer;
+
+ const stateAddress = ethers.ZeroAddress;
+
+ const linkId = "1";
+ const merklized = "1";
+ const operator1 = "1";
+ const operator2 = "16";
+ const operatorOutput1 = "0";
+ const operatorOutput2 = "777";
+ const queryHash1 = "100";
+ const queryHash2 = "200";
+
+ const dummyZKProof = [
+ ["0", "0"],
+ [
+ ["0", "0"],
+ ["0", "0"],
+ ],
+ ["0", "0"],
+ ];
+
+ const proofForOneQuery = packZKProof(
+ [linkId, merklized]
+ .concat([operatorOutput1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+ .concat([queryHash1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
+ ...dummyZKProof,
+ );
+
+ const proofForTwoQueries = packZKProof(
+ [linkId, merklized]
+ .concat([operatorOutput1, operatorOutput2, 0, 0, 0, 0, 0, 0, 0, 0])
+ .concat([queryHash1, queryHash2, 0, 0, 0, 0, 0, 0, 0, 0]),
+ ...dummyZKProof,
+ );
+
+ const oneQuery = {
+ claimPathKey: [0, 0],
+ operator: [operator1],
+ slotIndex: [0, 0],
+ value: [
+ [0, 0],
+ [0, 0],
+ ],
+ queryHash: [queryHash1],
+ circuitIds: ["linkedMultiQuery10-beta.1"],
+ groupID: 1,
+ verifierID: 1,
+ };
+
+ const oneQueryParams = packLinkedMultiQueryValidatorParams(oneQuery);
+
+ const twoQueries = {
+ claimPathKey: [0, 0],
+ operator: [operator1, operator2],
+ slotIndex: [0, 0],
+ value: [
+ [0, 0],
+ [0, 0],
+ ],
+ queryHash: [queryHash1, queryHash2],
+ circuitIds: ["linkedMultiQuery10-beta.1"],
+ groupID: 1,
+ verifierID: 1,
+ };
+
+ const twoQueriesParams = packLinkedMultiQueryValidatorParams(twoQueries);
+
+ async function deployContractsFixture() {
+ [signer] = await ethers.getSigners();
+ const groth16Verifier = await ethers.deployContract("Groth16VerifierValidatorStub");
+ const validator = await ethers.deployContract("LinkedMultiQueryValidator");
+ await validator.initialize(await groth16Verifier.getAddress(), signer);
+ return { validator, groth16Verifier };
+ }
+
+ beforeEach(async () => {
+ ({ validator, groth16Verifier } = await loadFixture(deployContractsFixture));
+ });
+
+ it("Should verify", async function () {
+ const result = await validator.verify(signer.address, proofForTwoQueries, twoQueriesParams);
+ expect(result).to.deep.equal([
+ ["linkID", linkId],
+ ["operatorOutput1", 777n],
+ ]);
+
+ // have more than one operator output
+ });
+
+ it("Should throw if circuitId is not linkedMultiQuery10-beta.1", async function () {
+ const params = packLinkedMultiQueryValidatorParams({
+ ...oneQuery,
+ circuitIds: ["someWrongCircuitId"],
+ });
+
+ await expect(validator.verify(signer.address, proofForOneQuery, params))
+ .to.be.revertedWithCustomError(validator, "WrongCircuitID")
+ .withArgs("someWrongCircuitId");
+ });
+
+ it("More than 10 queries in request params should throw", async function () {
+ const params = packLinkedMultiQueryValidatorParams({
+ ...oneQuery,
+ queryHash: Array(11).fill(queryHash1),
+ });
+
+ await expect(validator.verify(signer.address, proofForOneQuery, params))
+ .to.be.revertedWithCustomError(validator, "TooManyQueries")
+ .withArgs(11);
+ });
+
+ it("Should throw if wrong query hash", async function () {
+ const params = packLinkedMultiQueryValidatorParams({
+ ...oneQuery,
+ queryHash: [queryHash2],
+ });
+
+ await expect(validator.verify(signer.address, proofForOneQuery, params))
+ .to.be.revertedWithCustomError(validator, "InvalidQueryHash")
+ .withArgs(queryHash2, queryHash1);
+ });
+
+ it("Should throw if groupID is 0", async function () {
+ const params = packLinkedMultiQueryValidatorParams({
+ ...oneQuery,
+ groupID: 0,
+ });
+
+ await expect(validator.verify(signer.address, proofForOneQuery, params))
+ .to.be.revertedWithCustomError(validator, "InvalidGroupID")
+ .withArgs(0);
+ });
+
+ it("getRequestParams should return the correct values", async function () {
+ const result = await validator.getRequestParams(oneQueryParams);
+ expect(result).to.deep.equal([
+ ["groupID", oneQuery.groupID],
+ ["verifierID", oneQuery.verifierID],
+ ["nullifierSessionID", 0],
+ ]);
+ });
+
+ it("Should throw if failed ZK verification", async function () {
+ await groth16Verifier.stub_setVerifyResult(false);
+
+ await expect(
+ validator.verify(signer.address, proofForOneQuery, oneQueryParams),
+ ).to.be.revertedWithCustomError(validator, "InvalidGroth16Proof");
+ });
+
+ it("Contract version should be 1.0.0-beta.1", async function () {
+ expect(await validator.VERSION()).to.equal("1.0.0-beta.1");
+ expect(await validator.version()).to.equal("1.0.0-beta.1");
+ });
+
+ it("check version", async () => {
+ const version = await validator.version();
+ expect(version).to.be.equal(contractsInfo.VALIDATOR_LINKED_MULTI_QUERY.version);
+ });
+
+ it("check getRequestParams", async () => {
+ const query: any = {
+ claimPathKey: [1, 2],
+ operator: [2, 3],
+ slotIndex: [0],
+ value: [
+ [20020101, ...new Array(63).fill(0)],
+ [20030101, ...new Array(63).fill(0)],
+ ],
+ queryHash: [3, 4],
+ circuitIds: ["circuitName"],
+ groupID: 4,
+ verifierID: 5,
+ };
+
+ const params = packLinkedMultiQueryValidatorParams(query);
+ const requestParams = await validator.getRequestParams(params);
+ expect(requestParams[await validator.requestParamIndexOf("groupID")][1]).to.be.equal(4);
+ expect(requestParams[await validator.requestParamIndexOf("verifierID")][1]).to.be.equal(5);
+ expect(requestParams[await validator.requestParamIndexOf("nullifierSessionID")][1]).to.be.equal(
+ 0,
+ );
+ });
+});
diff --git a/test/validators/mtp/index.ts b/test/validators/mtp/index.ts
index 4e341f8e..a2a67a54 100644
--- a/test/validators/mtp/index.ts
+++ b/test/validators/mtp/index.ts
@@ -5,8 +5,9 @@ import { packValidatorParams } from "../../utils/validator-pack-utils";
import { CircuitId } from "@0xpolygonid/js-sdk";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { time } from "@nomicfoundation/hardhat-network-helpers";
-import { TEN_YEARS } from "../../../helpers/constants";
+import { contractsInfo, TEN_YEARS } from "../../../helpers/constants";
import { packZKProof } from "../../utils/packData";
+import { ethers } from "hardhat";
const tenYears = TEN_YEARS;
const testCases: any[] = [
@@ -86,7 +87,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_mtp_user_non_genesis.json"),
setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Non-Revocation state of Issuer expired",
+ errorMessage: "NonRevocationStateOfIssuerIsExpired()",
setProofExpiration: tenYears,
},
{
@@ -100,7 +101,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_mtp_user_non_genesis.json"), // generated on step 2
setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Gist root is expired",
+ errorMessage: "GistRootIsExpired()",
setProofExpiration: tenYears,
},
{
@@ -111,7 +112,7 @@ const testCases: any[] = [
require("../common-data/issuer_next_state_transition.json"),
],
proofJson: require("./data/valid_mtp_user_non_genesis.json"),
- errorMessage: "Generated proof is outdated",
+ errorMessage: "GeneratedProofIsOutdated()",
},
{
name: "Validate Genesis User State. Issuer Claim IdenState is in Chain. Revocation State is in Chain",
@@ -119,7 +120,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_mtp_user_genesis.json"),
setProofExpiration: tenYears,
allowedIssuers: [123n],
- errorMessage: "Issuer is not on the Allowed Issuers list",
+ errorMessage: "IssuerIsNotOnTheAllowedIssuersList()",
},
];
@@ -206,39 +207,15 @@ describe("Atomic MTP Validator", function () {
const data = packValidatorParams(query, test.allowedIssuers);
// Check verify function
- if (test.errorMessage) {
- await expect(
- mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress),
- ).to.be.rejectedWith(test.errorMessage);
- } else if (test.errorMessage === "") {
- await expect(mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress)).to.be
- .reverted;
- } else {
- const signals = await mtpValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress);
- const signalValues: any[] = [];
- // Replace index with value to check instead of signal index
- for (let i = 0; i < signals.length; i++) {
- signalValues.push([signals[i][0], inputs[signals[i][1]]]);
- }
- checkSignals(signalValues, test.signalValues);
- }
-
- // Check verifyV2 function
const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
if (test.errorMessage) {
- await expect(
- mtpValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()),
- ).to.be.rejectedWith(test.errorMessage);
+ await expect(mtpValidator.verify(senderAddress, zkProof, data)).to.be.rejectedWith(
+ test.errorMessage,
+ );
} else if (test.errorMessage === "") {
- await expect(mtpValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()))
- .to.be.reverted;
+ await expect(mtpValidator.verify(senderAddress, zkProof, data)).to.be.reverted;
} else {
- const signals = await mtpValidator.verifyV2(
- zkProof,
- data,
- senderAddress,
- await state.getAddress(),
- );
+ const signals = await mtpValidator.verify(senderAddress, zkProof, data);
checkSignals(signals, test.signalValues);
}
});
@@ -248,4 +225,49 @@ describe("Atomic MTP Validator", function () {
const challengeIndx = await mtpValidator.inputIndexOf("challenge");
expect(challengeIndx).to.be.equal(4);
});
+
+ it("check version", async () => {
+ const version = await mtpValidator.version();
+ expect(version).to.be.equal(contractsInfo.VALIDATOR_MTP.version);
+ });
+
+ it("check getRequestParams", async () => {
+ const query: any = {
+ requestId: 1,
+ schema: 2,
+ claimPathKey: 3,
+ operator: 4,
+ slotIndex: 0,
+ queryHash: 5,
+ value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters
+ circuitIds: ["circuitName"],
+ skipClaimRevocationCheck: false,
+ claimPathNotExists: 0,
+ };
+
+ const params = packValidatorParams(query);
+ const requestParams = await mtpValidator.getRequestParams(params);
+ expect(requestParams[await mtpValidator.requestParamIndexOf("groupID")][1]).to.be.equal(0);
+ expect(requestParams[await mtpValidator.requestParamIndexOf("verifierID")][1]).to.be.equal(0);
+ expect(
+ requestParams[await mtpValidator.requestParamIndexOf("nullifierSessionID")][1],
+ ).to.be.equal(0);
+ });
+
+ it("Test get config params", async () => {
+ const oneHour = 3600;
+ const expirationTimeout = await mtpValidator.getProofExpirationTimeout();
+ const revocationStateExpirationTimeout =
+ await mtpValidator.getRevocationStateExpirationTimeout();
+ const gistRootExpirationTimeout = await mtpValidator.getGISTRootExpirationTimeout();
+ expect(expirationTimeout).to.be.equal(oneHour);
+ expect(revocationStateExpirationTimeout).to.be.equal(oneHour);
+ expect(gistRootExpirationTimeout).to.be.equal(oneHour);
+ });
+
+ it("Test supported circuits", async () => {
+ const supportedCircuitIds = await mtpValidator.getSupportedCircuitIds();
+ expect(supportedCircuitIds.length).to.be.equal(1);
+ expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQueryMTPV2OnChain);
+ });
});
diff --git a/test/validators/sig/index.ts b/test/validators/sig/index.ts
index 08d83bdf..0e756690 100644
--- a/test/validators/sig/index.ts
+++ b/test/validators/sig/index.ts
@@ -5,8 +5,9 @@ import { packValidatorParams } from "../../utils/validator-pack-utils";
import { CircuitId } from "@0xpolygonid/js-sdk";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { time } from "@nomicfoundation/hardhat-network-helpers";
-import { TEN_YEARS } from "../../../helpers/constants";
+import { contractsInfo, TEN_YEARS } from "../../../helpers/constants";
import { packZKProof } from "../../utils/packData";
+import { ethers } from "hardhat";
const tenYears = TEN_YEARS;
const testCases: any[] = [
@@ -86,7 +87,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_sig_user_non_genesis.json"),
setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Non-Revocation state of Issuer expired",
+ errorMessage: "NonRevocationStateOfIssuerIsExpired()",
setProofExpiration: tenYears,
},
{
@@ -100,7 +101,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_sig_user_non_genesis.json"), // generated on step 2
setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Gist root is expired",
+ errorMessage: "GistRootIsExpired()",
setProofExpiration: tenYears,
},
{
@@ -111,7 +112,7 @@ const testCases: any[] = [
require("../common-data/issuer_next_state_transition.json"),
],
proofJson: require("./data/valid_sig_user_non_genesis.json"),
- errorMessage: "Generated proof is outdated",
+ errorMessage: "GeneratedProofIsOutdated()",
},
{
name: "Validate Genesis User State. Issuer Claim IdenState is in Chain. Revocation State is in Chain",
@@ -119,7 +120,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_sig_user_genesis.json"),
setProofExpiration: tenYears,
allowedIssuers: [123n],
- errorMessage: "Issuer is not on the Allowed Issuers list",
+ errorMessage: "IssuerIsNotOnTheAllowedIssuersList()",
},
];
@@ -202,39 +203,15 @@ describe("Atomic Sig Validator", function () {
const data = packValidatorParams(query, test.allowedIssuers);
// Check verify function
- if (test.errorMessage) {
- await expect(
- sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress),
- ).to.be.rejectedWith(test.errorMessage);
- } else if (test.errorMessage === "") {
- await expect(sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress)).to.be
- .reverted;
- } else {
- const signals = await sigValidator.verify(inputs, pi_a, pi_b, pi_c, data, senderAddress);
- const signalValues: any[] = [];
- // Replace index with value to check instead of signal index
- for (let i = 0; i < signals.length; i++) {
- signalValues.push([signals[i][0], inputs[signals[i][1]]]);
- }
- checkSignals(signalValues, test.signalValues);
- }
-
- // Check verifyV2 function
const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
if (test.errorMessage) {
- await expect(
- sigValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()),
- ).to.be.rejectedWith(test.errorMessage);
+ await expect(sigValidator.verify(senderAddress, zkProof, data)).to.be.rejectedWith(
+ test.errorMessage,
+ );
} else if (test.errorMessage === "") {
- await expect(sigValidator.verifyV2(zkProof, data, senderAddress, await state.getAddress()))
- .to.be.reverted;
+ await expect(sigValidator.verify(senderAddress, zkProof, data)).to.be.reverted;
} else {
- const signals = await sigValidator.verifyV2(
- zkProof,
- data,
- senderAddress,
- await state.getAddress(),
- );
+ const signals = await sigValidator.verify(senderAddress, zkProof, data);
checkSignals(signals, test.signalValues);
}
});
@@ -244,4 +221,49 @@ describe("Atomic Sig Validator", function () {
const challengeIndx = await sigValidator.inputIndexOf("challenge");
expect(challengeIndx).to.be.equal(5);
});
+
+ it("check version", async () => {
+ const version = await sigValidator.version();
+ expect(version).to.be.equal(contractsInfo.VALIDATOR_SIG.version);
+ });
+
+ it("check getRequestParams", async () => {
+ const query: any = {
+ requestId: 1,
+ schema: 2,
+ claimPathKey: 3,
+ operator: 4,
+ slotIndex: 0,
+ queryHash: 5,
+ value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters
+ circuitIds: ["circuitName"],
+ skipClaimRevocationCheck: false,
+ claimPathNotExists: 0,
+ };
+
+ const params = packValidatorParams(query);
+ const requestParams = await sigValidator.getRequestParams(params);
+ expect(requestParams[await sigValidator.requestParamIndexOf("groupID")][1]).to.be.equal(0);
+ expect(requestParams[await sigValidator.requestParamIndexOf("verifierID")][1]).to.be.equal(0);
+ expect(
+ requestParams[await sigValidator.requestParamIndexOf("nullifierSessionID")][1],
+ ).to.be.equal(0);
+ });
+
+ it("Test get config params", async () => {
+ const oneHour = 3600;
+ const expirationTimeout = await sigValidator.getProofExpirationTimeout();
+ const revocationStateExpirationTimeout =
+ await sigValidator.getRevocationStateExpirationTimeout();
+ const gistRootExpirationTimeout = await sigValidator.getGISTRootExpirationTimeout();
+ expect(expirationTimeout).to.be.equal(oneHour);
+ expect(revocationStateExpirationTimeout).to.be.equal(oneHour);
+ expect(gistRootExpirationTimeout).to.be.equal(oneHour);
+ });
+
+ it("Test supported circuits", async () => {
+ const supportedCircuitIds = await sigValidator.getSupportedCircuitIds();
+ expect(supportedCircuitIds.length).to.be.equal(1);
+ expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQuerySigV2OnChain);
+ });
});
diff --git a/test/validators/v3/index.ts b/test/validators/v3/index.ts
index 1d7f39a2..87635cf9 100644
--- a/test/validators/v3/index.ts
+++ b/test/validators/v3/index.ts
@@ -6,8 +6,9 @@ import { calculateQueryHashV3 } from "../../utils/query-hash-utils";
import { CircuitId } from "@0xpolygonid/js-sdk";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { time } from "@nomicfoundation/hardhat-network-helpers";
-import { TEN_YEARS } from "../../../helpers/constants";
+import { contractsInfo, TEN_YEARS } from "../../../helpers/constants";
import { packZKProof } from "../../utils/packData";
+import { ethers } from "hardhat";
const tenYears = TEN_YEARS;
const testCases: any[] = [
@@ -45,7 +46,7 @@ const testCases: any[] = [
require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"),
],
proofJson: require("./data/invalid_bjj_user_genesis_v3.json"),
- errorMessage: "Proof is not valid",
+ errorMessage: "ProofIsNotValid()",
setProofExpiration: tenYears,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
@@ -120,7 +121,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_bjj_user_second_issuer_first_v3"),
setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Non-Revocation state of Issuer expired",
+ errorMessage: "NonRevocationStateOfIssuerIsExpired()",
setProofExpiration: tenYears,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
@@ -136,7 +137,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Gist root is expired",
+ errorMessage: "GistRootIsExpired()",
setProofExpiration: tenYears,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
@@ -148,7 +149,7 @@ const testCases: any[] = [
require("../common-data/issuer_from_first_state_to_second_transition_v3.json"),
],
proofJson: require("./data/valid_bjj_user_first_v3.json"),
- errorMessage: "Generated proof is outdated",
+ errorMessage: "GeneratedProofIsOutdated()",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
{
@@ -159,7 +160,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_bjj_user_genesis_v3.json"),
setProofExpiration: tenYears,
allowedIssuers: [123n],
- errorMessage: "Issuer is not on the Allowed Issuers list",
+ errorMessage: "IssuerIsNotOnTheAllowedIssuersList()",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
{
@@ -227,7 +228,7 @@ const testCases: any[] = [
require("../common-data/issuer_from_genesis_state_to_first_transition_v3.json"),
],
proofJson: require("./data/invalid_mtp_user_genesis_v3.json"),
- errorMessage: "Proof is not valid",
+ errorMessage: "ProofIsNotValid()",
setProofExpiration: tenYears,
isMtpProof: true,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
@@ -304,7 +305,7 @@ const testCases: any[] = [
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
proofJson: require("./data/valid_mtp_user_second_issuer_first_v3.json"),
setRevStateExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Non-Revocation state of Issuer expired",
+ errorMessage: "NonRevocationStateOfIssuerIsExpired()",
setProofExpiration: tenYears,
isMtpProof: true,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
@@ -320,7 +321,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_mtp_user_first_v3"),
stateTransitionDelayMs: 2000, // [1....][2....][3....][4....] - each block is 2 seconds long
setGISTRootExpiration: 3, // [1....][2....][3..*.][4....] <-- (*) - marks where the expiration threshold is
- errorMessage: "Gist root is expired",
+ errorMessage: "GistRootIsExpired()",
setProofExpiration: tenYears,
isMtpProof: true,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
@@ -333,7 +334,7 @@ const testCases: any[] = [
require("../common-data/issuer_from_first_state_to_second_transition_v3.json"),
],
proofJson: require("./data/valid_mtp_user_first_v3.json"),
- errorMessage: "Generated proof is outdated",
+ errorMessage: "GeneratedProofIsOutdated()",
isMtpProof: true,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
@@ -345,7 +346,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_mtp_user_genesis_v3.json"),
setProofExpiration: tenYears,
allowedIssuers: [123n],
- errorMessage: "Issuer is not on the Allowed Issuers list",
+ errorMessage: "IssuerIsNotOnTheAllowedIssuersList()",
isMtpProof: true,
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
},
@@ -387,7 +388,7 @@ const testCases: any[] = [
],
proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3_wrong_id.json"),
setProofExpiration: tenYears,
- errorMessage: "UserID does not correspond to the sender",
+ errorMessage: "UserIDDoesNotCorrespondToTheSender()",
ethereumBasedUser: true,
sender: "0x6edFa588aFd58803F728AbC91984c69528C00854",
},
@@ -398,7 +399,7 @@ const testCases: any[] = [
],
proofJson: require("./data/valid_mtp_user_genesis_auth_disabled_v3_wrong_id.json"),
setProofExpiration: tenYears,
- errorMessage: "UserID does not correspond to the sender",
+ errorMessage: "UserIDDoesNotCorrespondToTheSender()",
ethereumBasedUser: true,
isMtpProof: true,
sender: "0x6edFa588aFd58803F728AbC91984c69528C00854",
@@ -439,7 +440,7 @@ const testCases: any[] = [
require("../common-data/user_from_genesis_state_to_first_transition_v3.json"),
],
proofJson: require("./data/valid_bjj_user_first_issuer_genesis_v3.json"),
- errorMessage: "Challenge should match the sender",
+ errorMessage: "ChallengeShouldMatchTheSender()",
setProofExpiration: tenYears,
sender: "0x0000000000000000000000000000000000000000",
},
@@ -452,7 +453,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"),
setProofExpiration: tenYears,
ethereumBasedUser: true,
- errorMessage: "Invalid Link ID pub signal",
+ errorMessage: "InvalidLinkIDPubSignal()",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
groupID: 0,
},
@@ -465,7 +466,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"),
setProofExpiration: tenYears,
ethereumBasedUser: true,
- errorMessage: "Proof type should match the requested one in query",
+ errorMessage: "ProofTypeShouldMatchTheRequestedOneInQuery()",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
isMtpProof: true,
},
@@ -478,7 +479,7 @@ const testCases: any[] = [
proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"),
setProofExpiration: tenYears,
ethereumBasedUser: true,
- errorMessage: "Invalid nullify pub signal",
+ errorMessage: "InvalidNullifyPubSignal()",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
nullifierSessionId: "2",
},
@@ -491,14 +492,15 @@ const testCases: any[] = [
proofJson: require("./data/valid_bjj_user_genesis_auth_disabled_v3.json"),
setProofExpiration: tenYears,
ethereumBasedUser: true,
- errorMessage: "Query hash does not match the requested one",
+ errorMessage:
+ "QueryHashDoesNotMatchTheRequestedOne(0, 19185468473610285815446195195707572856383167010831244369191309337886545428382)",
sender: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
queryHash: BigInt(0),
},
];
describe("Atomic V3 Validator", function () {
- let state: any, v3validator;
+ let state: any, v3Validator;
async function deployContractsFixture() {
const deployHelper = await DeployHelper.initialize(null, true);
@@ -527,7 +529,7 @@ describe("Atomic V3 Validator", function () {
}
beforeEach(async () => {
- ({ stateContract: state, validator: v3validator } = await loadFixture(deployContractsFixture));
+ ({ stateContract: state, validator: v3Validator } = await loadFixture(deployContractsFixture));
});
for (const test of testCases) {
@@ -582,57 +584,80 @@ describe("Atomic V3 Validator", function () {
const { inputs, pi_a, pi_b, pi_c } = prepareInputs(test.proofJson);
if (test.setProofExpiration) {
- await v3validator.setProofExpirationTimeout(test.setProofExpiration);
+ await v3Validator.setProofExpirationTimeout(test.setProofExpiration);
}
if (test.setRevStateExpiration) {
- await v3validator.setRevocationStateExpirationTimeout(test.setRevStateExpiration);
+ await v3Validator.setRevocationStateExpirationTimeout(test.setRevStateExpiration);
}
if (test.setGISTRootExpiration) {
- await v3validator.setGISTRootExpirationTimeout(test.setGISTRootExpiration);
+ await v3Validator.setGISTRootExpirationTimeout(test.setGISTRootExpiration);
}
const data = packV3ValidatorParams(query, test.allowedIssuers);
// Check verify function
- if (test.errorMessage) {
- await expect(
- v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender),
- ).to.be.rejectedWith(test.errorMessage);
- } else if (test.errorMessage === "") {
- await expect(v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender)).to.be
- .reverted;
- } else {
- const signals = await v3validator.verify(inputs, pi_a, pi_b, pi_c, data, test.sender);
-
- const signalValues: any[] = [];
- // Replace index with value to check instead of signal index
- for (let i = 0; i < signals.length; i++) {
- signalValues.push([signals[i][0], inputs[signals[i][1]]]);
- }
-
- // Check if the number signals are correct. "operatorOutput" for selective disclosure is optional
- checkSignals(signalValues, test.signalValues);
- }
-
- // Check verifyV2 function
const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
if (test.errorMessage) {
- await expect(
- v3validator.verifyV2(zkProof, data, test.sender, await state.getAddress()),
- ).to.be.rejectedWith(test.errorMessage);
+ await expect(v3Validator.verify(test.sender, zkProof, data)).to.be.rejectedWith(
+ test.errorMessage,
+ );
} else if (test.errorMessage === "") {
- await expect(v3validator.verifyV2(zkProof, data, test.sender, await state.getAddress())).to
- .be.reverted;
+ await expect(v3Validator.verify(test.sender, zkProof, data)).to.be.reverted;
} else {
- const signals = await v3validator.verifyV2(
- zkProof,
- data,
- test.sender,
- await state.getAddress(),
- );
+ const signals = await v3Validator.verify(test.sender, zkProof, data);
checkSignals(signals, test.signalValues);
}
});
}
+
+ it("check version", async () => {
+ const version = await v3Validator.version();
+ expect(version).to.be.equal(contractsInfo.VALIDATOR_V3.version);
+ });
+
+ it("check getRequestParams", async () => {
+ const query: any = {
+ requestId: 1,
+ schema: 2,
+ claimPathKey: 3,
+ operator: 4,
+ slotIndex: 0,
+ queryHash: 5,
+ value: [20020101, ...new Array(63).fill(0)], // for operators 1-3 only first value matters
+ circuitIds: ["circuitName"],
+ skipClaimRevocationCheck: false,
+ claimPathNotExists: 0,
+ allowedIssuers: [],
+ verifierID: 7,
+ nullifierSessionID: 8,
+ groupID: 9,
+ proofType: 0,
+ };
+
+ const params = packV3ValidatorParams(query);
+ const requestParams = await v3Validator.getRequestParams(params);
+ expect(requestParams[await v3Validator.requestParamIndexOf("groupID")][1]).to.be.equal(9);
+ expect(requestParams[await v3Validator.requestParamIndexOf("verifierID")][1]).to.be.equal(7);
+ expect(
+ requestParams[await v3Validator.requestParamIndexOf("nullifierSessionID")][1],
+ ).to.be.equal(8);
+ });
+
+ it("Test get config params", async () => {
+ const oneHour = 3600;
+ const expirationTimeout = await v3Validator.getProofExpirationTimeout();
+ const revocationStateExpirationTimeout =
+ await v3Validator.getRevocationStateExpirationTimeout();
+ const gistRootExpirationTimeout = await v3Validator.getGISTRootExpirationTimeout();
+ expect(expirationTimeout).to.be.equal(oneHour);
+ expect(revocationStateExpirationTimeout).to.be.equal(oneHour);
+ expect(gistRootExpirationTimeout).to.be.equal(oneHour);
+ });
+
+ it("Test supported circuits", async () => {
+ const supportedCircuitIds = await v3Validator.getSupportedCircuitIds();
+ expect(supportedCircuitIds.length).to.be.equal(1);
+ expect(supportedCircuitIds[0]).to.be.equal(CircuitId.AtomicQueryV3OnChain);
+ });
});
diff --git a/test/verifier/embedded-verifier.test.ts b/test/verifier/embedded-verifier.test.ts
new file mode 100644
index 00000000..adb5decd
--- /dev/null
+++ b/test/verifier/embedded-verifier.test.ts
@@ -0,0 +1,96 @@
+import { ethers } from "hardhat";
+import { beforeEach } from "mocha";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { expect } from "chai";
+
+describe("EmbeddedVerifier tests", function () {
+ let verifier, state, validator, signer: any;
+ let request, paramsFromValidator, authResponse, response, crossChainProofs: any;
+
+ async function deployContractsFixture() {
+ [signer] = await ethers.getSigners();
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const verifier = await ethers.deployContract("EmbeddedVerifierWrapper", []);
+
+ const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub");
+ await verifier.initialize(await signer.getAddress(), await state.getAddress());
+
+ const validator = await ethers.deployContract("RequestValidatorStub");
+
+ const authValidator = await deployHelper.deployValidatorStub("AuthValidatorStub");
+ await authValidator.stub_setVerifyResults(1);
+
+ const authMethod = {
+ authMethod: "stubAuth",
+ validator: await authValidator.getAddress(),
+ params: "0x",
+ };
+ await verifier.setAuthMethod(authMethod);
+
+ return { state, verifier, validator };
+ }
+
+ beforeEach(async function () {
+ ({ state, verifier, validator } = await deployContractsFixture());
+
+ request = {
+ requestId: 0,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ response = {
+ requestId: 0,
+ proof: "0x",
+ metadata: "0x",
+ };
+
+ crossChainProofs = "0x";
+ });
+
+ it("Test get state address", async () => {
+ let stateAddr = await verifier.getStateAddress();
+ expect(stateAddr).to.be.equal(await state.getAddress());
+
+ await verifier.setState(await signer.getAddress());
+
+ stateAddr = await verifier.getStateAddress();
+ expect(stateAddr).to.be.equal(await signer.getAddress());
+
+ await verifier.setState(await state.getAddress());
+ });
+
+ it("beforeProofSubmit/afterProofSubmit when submitting response", async function () {
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await verifier.setRequests([request]);
+
+ await expect(verifier.submitResponse(authResponse, [response], crossChainProofs)).to.emit(
+ verifier,
+ "BeforeProofSubmit",
+ );
+
+ let filter = verifier.filters.BeforeProofSubmit;
+ let events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("BeforeProofSubmit");
+ expect(events[0].args.authResponse).to.deep.equal(Object.values(authResponse));
+ expect(events[0].args.responses).to.deep.equal([Object.values(response)]);
+
+ filter = verifier.filters.AfterProofSubmit;
+ events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("AfterProofSubmit");
+ expect(events[0].args.authResponse).to.deep.equal(Object.values(authResponse));
+ expect(events[0].args.responses).to.deep.equal([Object.values(response)]);
+ });
+});
diff --git a/test/verifier/embedded-zkp-verifier.test.ts b/test/verifier/embedded-zkp-verifier.test.ts
deleted file mode 100644
index 418b608c..00000000
--- a/test/verifier/embedded-zkp-verifier.test.ts
+++ /dev/null
@@ -1,258 +0,0 @@
-import { expect } from "chai";
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { ethers } from "hardhat";
-import { packValidatorParams } from "../utils/validator-pack-utils";
-import { prepareInputs } from "../utils/state-utils";
-import { Block, Signer } from "ethers";
-import { buildCrossChainProofs, packCrossChainProofs, packZKProof } from "../utils/packData";
-import proofJson from "../validators/sig/data/valid_sig_user_genesis.json";
-import { CircuitId } from "@0xpolygonid/js-sdk";
-import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
-
-describe("Embedded ZKP Verifier", function () {
- let verifier: any, validator: any;
- let owner: Signer;
-
- const query = {
- schema: BigInt("180410020913331409885634153623124536270"),
- claimPathKey: BigInt(
- "8566939875427719562376598811066985304309117528846759529734201066483458512800",
- ),
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- claimPathNotExists: 0,
- };
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
- const metadatas = "0x";
-
- async function deployContractsFixture() {
- const deployHelper = await DeployHelper.initialize(null, true);
- [owner] = await ethers.getSigners();
-
- const { state } = await deployHelper.deployStateWithLibraries(["0x0112"]);
-
- const verifierLib = await deployHelper.deployVerifierLib();
-
- verifier = await deployHelper.deployEmbeddedZKPVerifierWrapper(
- owner,
- await state.getAddress(),
- await verifierLib.getAddress(),
- );
-
- validator = await deployHelper.deployValidatorStub();
- }
-
- async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) {
- for (const field of storageFields) {
- const value = await verifier.getProofStorageField(
- await owner.getAddress(),
- requestId,
- field.name,
- );
- expect(value).to.be.equal(field.value);
- }
- }
-
- beforeEach(async () => {
- await loadFixture(deployContractsFixture);
- });
-
- it("test submit response", async () => {
- await verifier.setZKPRequest(0, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: packValidatorParams(query),
- });
-
- const tx = await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c);
- const txRes = await tx.wait();
- const storageFields = [
- {
- name: "userID",
- value: inputs[1],
- },
- {
- name: "issuerID",
- value: inputs[2],
- },
- ];
-
- await checkStorageFields(verifier, 0, storageFields);
- const receipt = await ethers.provider.getTransactionReceipt(txRes.hash);
-
- // 2 events are emitted
- expect(receipt?.logs.length).to.equal(2);
-
- const interfaceEventBeforeProofSubmit = new ethers.Interface([
- "event BeforeProofSubmit(uint64 requestId, uint256[] inputs, address validator)",
- ]);
- const eventBeforeProofSubmit = interfaceEventBeforeProofSubmit.decodeEventLog(
- "BeforeProofSubmit",
- receipt?.logs[0].data || "",
- receipt?.logs[0].topics,
- );
- expect(eventBeforeProofSubmit[0]).to.equal(0);
- expect(eventBeforeProofSubmit[1]).to.deep.equal(inputs.map((x) => BigInt(x)));
- expect(eventBeforeProofSubmit[2]).to.equal(await validator.getAddress());
-
- const interfaceEventAfterProofSubmit = new ethers.Interface([
- "event AfterProofSubmit(uint64 requestId, uint256[] inputs, address validator)",
- ]);
- const eventAfterProofSubmit = interfaceEventAfterProofSubmit.decodeEventLog(
- "AfterProofSubmit",
- receipt?.logs[1].data || "",
- receipt?.logs[1].topics,
- );
- expect(eventAfterProofSubmit[0]).to.equal(0);
- expect(eventAfterProofSubmit[1]).to.deep.equal(inputs.map((x) => BigInt(x)));
- expect(eventAfterProofSubmit[2]).to.equal(await validator.getAddress());
-
- const ownerAddress = await owner.getAddress();
- const requestID = 0;
- const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
- txRes.blockNumber,
- )) as Block;
-
- const isProofVerified = await verifier.isProofVerified(ownerAddress, requestID);
- expect(isProofVerified).to.be.equal(true);
- const proofStatus = await verifier.getProofStatus(ownerAddress, requestID);
- expect(proofStatus.isVerified).to.be.equal(true);
- expect(proofStatus.validatorVersion).to.be.equal("2.0.2-mock");
- expect(proofStatus.blockNumber).to.be.equal(txRes.blockNumber);
- expect(proofStatus.blockTimestamp).to.be.equal(txResTimestamp);
- });
-
- it("test submit response v2", async () => {
- const globalStateMessage = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- idType: "0x01A1",
- root: 0n,
- replacedAtTimestamp: 0n,
- };
-
- const identityStateMessage1 = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- id: 25530185136167283063987925153802803371825564143650291260157676786685420033n,
- state: 4595702004868323299100310062178085028712435650290319955390778053863052230284n,
- replacedAtTimestamp: 0n,
- };
-
- const identityStateUpdate2 = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- id: 25530185136167283063987925153802803371825564143650291260157676786685420033n,
- state: 16775015541053109108201708100382933592407720757224325883910784163897594100403n,
- replacedAtTimestamp: 1724858009n,
- };
-
- await verifier.setZKPRequest(0, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: packValidatorParams(query),
- });
-
- const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
- const [signer] = await ethers.getSigners();
-
- const crossChainProofs = packCrossChainProofs(
- await buildCrossChainProofs(
- [globalStateMessage, identityStateMessage1, identityStateUpdate2],
- signer,
- ),
- );
-
- const tx = await verifier.submitZKPResponseV2(
- [
- {
- requestId: 0,
- zkProof: zkProof,
- data: metadatas,
- },
- ],
- crossChainProofs,
- );
-
- const txRes = await tx.wait();
-
- const storageFields = [
- {
- name: "userID",
- value: 1n,
- },
- {
- name: "issuerID",
- value: 2n,
- },
- ];
- await checkStorageFields(verifier, 0, storageFields);
-
- const receipt = await ethers.provider.getTransactionReceipt(txRes.hash);
-
- // 2 events are emitted
- expect(receipt?.logs.length).to.equal(2);
-
- const interfaceEventBeforeProofSubmitV2 = new ethers.Interface([
- "event BeforeProofSubmitV2(tuple(uint64 requestId,bytes zkProof,bytes data)[])",
- ]);
- const eventBeforeProofSubmitV2 = interfaceEventBeforeProofSubmitV2.decodeEventLog(
- "BeforeProofSubmitV2",
- receipt?.logs[0].data || "",
- receipt?.logs[0].topics,
- );
- expect(eventBeforeProofSubmitV2[0][0][0]).to.equal(0);
- expect(eventBeforeProofSubmitV2[0][0][1]).to.deep.equal(zkProof);
- expect(eventBeforeProofSubmitV2[0][0][2]).to.equal(metadatas);
-
- const interfaceEventAfterProofSubmitV2 = new ethers.Interface([
- "event AfterProofSubmitV2(tuple(uint64 requestId,bytes zkProof,bytes data)[])",
- ]);
- const eventAfterProofSubmitV2 = interfaceEventAfterProofSubmitV2.decodeEventLog(
- "AfterProofSubmitV2",
- receipt?.logs[1].data || "",
- receipt?.logs[1].topics,
- );
- expect(eventAfterProofSubmitV2[0][0][0]).to.equal(0);
- expect(eventAfterProofSubmitV2[0][0][1]).to.deep.equal(zkProof);
- expect(eventAfterProofSubmitV2[0][0][2]).to.equal(metadatas);
-
- const ownerAddress = await owner.getAddress();
- const requestID = 0;
- const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
- txRes.blockNumber,
- )) as Block;
-
- const isProofVerified = await verifier.isProofVerified(ownerAddress, requestID);
- expect(isProofVerified).to.be.equal(true);
- const proofStatus = await verifier.getProofStatus(ownerAddress, requestID);
- expect(proofStatus.isVerified).to.be.equal(true);
- expect(proofStatus.validatorVersion).to.be.equal("2.0.2-mock");
- expect(proofStatus.blockNumber).to.be.equal(txRes.blockNumber);
- expect(proofStatus.blockTimestamp).to.be.equal(txResTimestamp);
- });
-
- it("test getZKPRequest and request id exists", async () => {
- const requestsCount = 3;
- for (let i = 0; i < requestsCount; i++) {
- await verifier.setZKPRequest(i, {
- metadata: "metadataN" + i,
- validator: await validator.getAddress(),
- data: "0x00",
- });
- const reqeustIdExists = await verifier.requestIdExists(i);
- expect(reqeustIdExists).to.be.true;
- const reqeustIdDoesntExists = await verifier.requestIdExists(i + 1);
- expect(reqeustIdDoesntExists).to.be.false;
-
- const request = await verifier.getZKPRequest(i);
- expect(request.metadata).to.be.equal("metadataN" + i);
- await expect(verifier.getZKPRequest(i + 1)).to.be.rejectedWith("request id doesn't exist");
- }
- const count = await verifier.getZKPRequestsCount();
- expect(count).to.be.equal(requestsCount);
- });
-});
diff --git a/test/verifier/requestDisableable.test.ts b/test/verifier/requestDisableable.test.ts
new file mode 100644
index 00000000..89b7a148
--- /dev/null
+++ b/test/verifier/requestDisableable.test.ts
@@ -0,0 +1,69 @@
+import { ethers } from "hardhat";
+import { beforeEach } from "mocha";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { expect } from "chai";
+
+describe("RequestDisableable tests", function () {
+ let verifier, validator: any;
+ let request, paramsFromValidator: any;
+
+ async function deployContractsFixture() {
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const verifier = await ethers.deployContract("RequestDisableableTestWrapper", []);
+
+ const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub");
+ await verifier.initialize(await state.getAddress());
+
+ const validator = await ethers.deployContract("RequestValidatorStub");
+ return { verifier, validator };
+ }
+
+ beforeEach(async function () {
+ ({ verifier, validator } = await deployContractsFixture());
+
+ request = {
+ requestId: 1,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ });
+
+ it("disable/enable request and onlyEnabledRequest modifier", async function () {
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await verifier.setRequests([request]);
+
+ let isRequestEnabled = await verifier.isRequestEnabled(request.requestId);
+ expect(isRequestEnabled).to.be.true;
+
+ await expect(verifier.testModifier(request.requestId)).not.to.be.reverted;
+ await expect(verifier.getRequestIfCanBeVerified(request.requestId)).not.to.be.reverted;
+
+ await verifier.disableRequest(request.requestId);
+
+ isRequestEnabled = await verifier.isRequestEnabled(request.requestId);
+ expect(isRequestEnabled).to.be.false;
+
+ await expect(verifier.testModifier(request.requestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIsDisabled")
+ .withArgs(request.requestId);
+
+ await expect(verifier.getRequestIfCanBeVerified(request.requestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIsDisabled")
+ .withArgs(request.requestId);
+
+ await verifier.enableRequest(request.requestId);
+
+ isRequestEnabled = await verifier.isRequestEnabled(request.requestId);
+ expect(isRequestEnabled).to.be.true;
+
+ await expect(verifier.testModifier(request.requestId)).not.to.be.reverted;
+ });
+});
diff --git a/test/verifier/requestOwnership.test.ts b/test/verifier/requestOwnership.test.ts
new file mode 100644
index 00000000..79d20cd8
--- /dev/null
+++ b/test/verifier/requestOwnership.test.ts
@@ -0,0 +1,53 @@
+import { ethers } from "hardhat";
+import { beforeEach } from "mocha";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { expect } from "chai";
+
+describe("RequestOwnership tests", function () {
+ let verifier, validator: any;
+ let request, paramsFromValidator: any;
+ let signer1, signer2: any;
+
+ async function deployContractsFixture() {
+ [signer1, signer2] = await ethers.getSigners();
+
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const verifier = await ethers.deployContract("RequestOwnershipTestWrapper", []);
+
+ const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub");
+ await verifier.initialize(await state.getAddress());
+
+ const validator = await ethers.deployContract("RequestValidatorStub");
+ return { verifier, validator, signer1, signer2 };
+ }
+
+ beforeEach(async function () {
+ ({ verifier, validator, signer1, signer2 } = await deployContractsFixture());
+
+ request = {
+ requestId: 1,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ });
+
+ it("setRequestOwner: change request ownership", async function () {
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+
+ let owner = await verifier.getRequestOwner(request.requestId);
+ expect(owner).to.be.equal(await signer1.getAddress());
+
+ await verifier.setRequestOwner(request.requestId, await signer2.getAddress());
+
+ owner = await verifier.getRequestOwner(request.requestId);
+ expect(owner).to.be.equal(await signer2.getAddress());
+ });
+});
diff --git a/test/verifier/universal-verifier-linked-proofs.test.ts b/test/verifier/universal-verifier-linked-proofs.test.ts
deleted file mode 100644
index 8edad40c..00000000
--- a/test/verifier/universal-verifier-linked-proofs.test.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { ethers } from "hardhat";
-import { packV3ValidatorParams } from "../utils/validator-pack-utils";
-import { prepareInputs, publishState } from "../utils/state-utils";
-import { expect } from "chai";
-import testData from "./linked-proofs-data.json";
-import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
-import { TEN_YEARS } from "../../helpers/constants";
-
-describe("Universal Verifier Linked proofs", function () {
- let verifier: any, v3: any, state: any;
- let signer, signer2;
- let signerAddress: string;
- let deployHelper: DeployHelper;
-
- async function deployContractsFixture() {
- [signer, signer2] = await ethers.getSigners();
- signerAddress = await signer.getAddress();
-
- deployHelper = await DeployHelper.initialize(null, true);
- ({ state } = await deployHelper.deployStateWithLibraries(["0x0112"]));
-
- const verifierLib = await deployHelper.deployVerifierLib();
-
- verifier = await deployHelper.deployUniversalVerifier(
- signer,
- await state.getAddress(),
- await verifierLib.getAddress(),
- );
-
- const contracts = await deployHelper.deployValidatorContractsWithVerifiers(
- "v3",
- await state.getAddress(),
- );
- v3 = contracts.validator;
- await verifier.addValidatorToWhitelist(await v3.getAddress());
- await verifier.connect();
-
- await publishState(state, testData.state as unknown as { [key: string]: string });
- await v3.setProofExpirationTimeout(TEN_YEARS);
- for (let i = 0; i < testData.queryData.zkpRequests.length; i++) {
- await verifier.setZKPRequest(100 + i, {
- metadata: "linkedProofN" + i,
- validator: await v3.getAddress(),
- data: packV3ValidatorParams(testData.queryData.zkpRequests[i].request),
- });
- }
-
- for (let i = 0; i < testData.queryData.zkpResponses.length; i++) {
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(testData.queryData.zkpResponses[i]);
- await verifier.submitZKPResponse(100 + i, inputs, pi_a, pi_b, pi_c);
- }
- }
-
- beforeEach(async () => {
- await loadFixture(deployContractsFixture);
- });
-
- it("should linked proof validation pass", async () => {
- expect(await verifier.verifyLinkedProofs(signerAddress, [101, 102])).not.to.throw;
- expect(await verifier.verifyLinkedProofs(signerAddress, [100, 103])).not.to.throw;
- });
-
- it("should linked proof validation fail", async () => {
- await expect(verifier.verifyLinkedProofs(signerAddress, [100, 101])).to.be.rejectedWith(
- "LinkedProofError",
- );
- await expect(verifier.verifyLinkedProofs(signerAddress, [102, 103])).to.be.rejectedWith(
- "LinkedProofError",
- );
-
- await expect(verifier.verifyLinkedProofs(signerAddress, [102])).to.be.rejectedWith(
- "Linked proof verification needs more than 1 request",
- );
- await expect(
- verifier.verifyLinkedProofs(await signer2.getAddress(), [101, 102]),
- ).to.be.rejectedWith(`Can't find linkID for given request Ids and user address`);
- });
-});
diff --git a/test/verifier/universal-verifier-submit-V2.test.ts b/test/verifier/universal-verifier-submit-V2.test.ts
deleted file mode 100644
index a4117be9..00000000
--- a/test/verifier/universal-verifier-submit-V2.test.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-import { expect } from "chai";
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { ethers } from "hardhat";
-import { packValidatorParams } from "../utils/validator-pack-utils";
-import { prepareInputs } from "../utils/state-utils";
-import { Block, Contract } from "ethers";
-import proofJson from "../validators/sig/data/valid_sig_user_genesis.json";
-import { buildCrossChainProofs, packCrossChainProofs, packZKProof } from "../utils/packData";
-import { CircuitId } from "@0xpolygonid/js-sdk";
-import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
-
-describe("Universal Verifier submitZKPResponseV2 SigV2 validators", function () {
- let verifier: any, sig: any;
- let signer;
- let signerAddress: string;
- let deployHelper: DeployHelper;
- let stateCrossChainStub, crossChainProofValidatorStub, validatorStub: Contract;
-
- const globalStateMessage = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- idType: "0x01A1",
- root: 0n,
- replacedAtTimestamp: 0n,
- };
-
- const identityStateMessage1 = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- id: 25530185136167283063987925153802803371825564143650291260157676786685420033n,
- state: 4595702004868323299100310062178085028712435650290319955390778053863052230284n,
- replacedAtTimestamp: 0n,
- };
-
- const identityStateUpdate2 = {
- timestamp: BigInt(Math.floor(Date.now() / 1000)),
- id: 25530185136167283063987925153802803371825564143650291260157676786685420033n,
- state: 16775015541053109108201708100382933592407720757224325883910784163897594100403n,
- replacedAtTimestamp: 1724858009n,
- };
-
- const query = {
- schema: BigInt("180410020913331409885634153623124536270"),
- claimPathKey: BigInt(
- "8566939875427719562376598811066985304309117528846759529734201066483458512800",
- ),
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- claimPathNotExists: 0,
- };
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
- const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
- const metadatas = "0x";
- const data = packValidatorParams(query);
-
- const requestIds = [0, 1, 2];
- const nonExistingRequestId = 3;
-
- const singleProof = [
- {
- requestId: 0,
- zkProof: zkProof,
- data: metadatas,
- },
- ];
-
- const multiProof = [
- {
- requestId: 1,
- zkProof: zkProof,
- data: metadatas,
- },
- {
- requestId: 2,
- zkProof: zkProof,
- data: metadatas,
- },
- ];
-
- let crossChainProofs;
-
- async function deployContractsFixture() {
- [signer] = await ethers.getSigners();
- signerAddress = await signer.getAddress();
-
- deployHelper = await DeployHelper.initialize(null, true);
- crossChainProofValidatorStub = await deployHelper.deployCrossChainProofValidator();
-
- const { state } = await deployHelper.deployStateWithLibraries(["0x01A1", "0x0102"]);
- await state.setCrossChainProofValidator(crossChainProofValidatorStub);
- stateCrossChainStub = state;
-
- const verifierLib = await deployHelper.deployVerifierLib();
-
- verifier = await deployHelper.deployUniversalVerifier(
- signer,
- await stateCrossChainStub.getAddress(),
- await verifierLib.getAddress(),
- );
-
- validatorStub = await deployHelper.deployValidatorStub();
-
- sig = validatorStub;
- await verifier.addValidatorToWhitelist(await sig.getAddress());
- await verifier.connect();
-
- for (const requestId of requestIds) {
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await sig.getAddress(),
- data: data,
- });
- }
- }
-
- const storageFields = [
- {
- name: "userID",
- value: 1n,
- },
- {
- name: "issuerID",
- value: 2n,
- },
- ];
-
- async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) {
- for (const field of storageFields) {
- const value = await verifier.getProofStorageField(
- await signer.getAddress(),
- requestId,
- field.name,
- );
- expect(value).to.be.equal(field.value);
- }
- }
-
- beforeEach(async () => {
- await loadFixture(deployContractsFixture);
- crossChainProofs = packCrossChainProofs(
- await buildCrossChainProofs(
- [globalStateMessage, identityStateMessage1, identityStateUpdate2],
- signer,
- ),
- );
- });
-
- it("Test submit response V2", async () => {
- const requestId = 0;
- const tx = await verifier.submitZKPResponseV2(singleProof, crossChainProofs);
-
- const txRes = await tx.wait();
- await checkStorageFields(verifier, requestId, storageFields);
- const filter = verifier.filters.ZKPResponseSubmitted;
-
- const events = await verifier.queryFilter(filter, -1);
- expect(events[0].eventName).to.be.equal("ZKPResponseSubmitted");
- expect(events[0].args.requestId).to.be.equal(0);
- expect(events[0].args.caller).to.be.equal(signerAddress);
-
- const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
- txRes.blockNumber,
- )) as Block;
-
- const status = await verifier.getProofStatus(signerAddress, requestId);
- expect(status.isVerified).to.be.true;
- expect(status.validatorVersion).to.be.equal("2.0.2-mock");
- expect(status.blockNumber).to.be.equal(txRes.blockNumber);
- expect(status.blockTimestamp).to.be.equal(txResTimestamp);
-
- await expect(verifier.getProofStatus(signerAddress, nonExistingRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
-
- const requestIdsMulti = requestIds.slice(1, 3);
- const txMulti = await verifier.submitZKPResponseV2(multiProof, crossChainProofs);
-
- const txResMulti = await txMulti.wait();
-
- const eventsMulti = await verifier.queryFilter(filter, txRes.blockNumber + 1);
- expect(eventsMulti[0].eventName).to.be.equal("ZKPResponseSubmitted");
- expect(eventsMulti[0].args.requestId).to.be.equal(1);
- expect(eventsMulti[0].args.caller).to.be.equal(signerAddress);
-
- const { timestamp: txResTimestampMuti } = (await ethers.provider.getBlock(
- txResMulti.blockNumber,
- )) as Block;
-
- for (const requestId of requestIdsMulti) {
- const status = await verifier.getProofStatus(signerAddress, requestId);
- expect(status.isVerified).to.be.true;
- expect(status.validatorVersion).to.be.equal("2.0.2-mock");
- expect(status.blockNumber).to.be.equal(txResMulti.blockNumber);
- expect(status.blockTimestamp).to.be.equal(txResTimestampMuti);
- await checkStorageFields(verifier, requestId, storageFields);
- }
- });
-
- it("Test submit response V2 with disable/enable functionality", async () => {
- await verifier.disableZKPRequest(0);
- await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).to.be.rejectedWith(
- "Request is disabled",
- );
-
- await verifier.disableZKPRequest(1);
- await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).to.be.rejectedWith(
- "Request is disabled",
- );
-
- await verifier.enableZKPRequest(0);
- await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).not.to.be.rejected;
-
- await verifier.enableZKPRequest(1);
- await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).not.to.be.rejected;
- });
-
- it("Test submit response V2 check whitelisted functionality", async () => {
- await verifier.removeValidatorFromWhitelist(await sig.getAddress());
- await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).to.be.rejectedWith(
- "Validator is not whitelisted",
- );
- await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).to.be.rejectedWith(
- "Validator is not whitelisted",
- );
-
- await verifier.addValidatorToWhitelist(await sig.getAddress());
- await expect(verifier.submitZKPResponseV2(singleProof, crossChainProofs)).not.to.be.rejected;
- await expect(verifier.submitZKPResponseV2(multiProof, crossChainProofs)).not.to.be.rejected;
- });
-});
diff --git a/test/verifier/universal-verifier.events.test.ts b/test/verifier/universal-verifier.events.test.ts
deleted file mode 100644
index fa5441e9..00000000
--- a/test/verifier/universal-verifier.events.test.ts
+++ /dev/null
@@ -1,175 +0,0 @@
-import { expect } from "chai";
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { ethers } from "hardhat";
-import { packValidatorParams } from "../utils/validator-pack-utils";
-import { AbiCoder } from "ethers";
-import { CircuitId } from "@0xpolygonid/js-sdk";
-
-describe("Universal Verifier events", function () {
- let verifier: any, sig: any;
- let signer;
-
- const queries = [
- {
- schema: 111n,
- claimPathKey: 8566939875427719562376598811066985304309117528846759529734201066483458512800n,
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- skipClaimRevocationCheck: false,
- claimPathNotExists: 0n,
- },
- {
- schema: BigInt("222"),
- claimPathKey: BigInt(
- "8566939875427719562376598811066985304309117528846759529734201066483458512800",
- ),
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- skipClaimRevocationCheck: true,
- claimPathNotExists: 0n,
- },
- {
- schema: 333n,
- claimPathKey: BigInt(
- "8566939875427719562376598811066985304309117528846759529734201066483458512800",
- ),
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- skipClaimRevocationCheck: false,
- claimPathNotExists: 0n,
- },
- ];
-
- const encodedDataAbi = [
- {
- components: [
- { name: "schema", type: "uint256" },
- { name: "claimPathKey", type: "uint256" },
- { name: "operator", type: "uint256" },
- { name: "slotIndex", type: "uint256" },
- { name: "value", type: "uint256[]" },
- { name: "queryHash", type: "uint256" },
- { name: "allowedIssuers", type: "uint256[]" },
- { name: "circuitIds", type: "string[]" },
- { name: "skipClaimRevocationCheck", type: "bool" },
- { name: "claimPathNotExists", type: "uint256" },
- ],
- name: "",
- type: "tuple",
- },
- ];
-
- beforeEach(async () => {
- [signer] = await ethers.getSigners();
-
- const deployHelper = await DeployHelper.initialize(null, true);
- const { state } = await deployHelper.deployStateWithLibraries(["0x0112"]);
-
- const verifierLib = await deployHelper.deployVerifierLib();
- verifier = await deployHelper.deployUniversalVerifier(
- signer,
- await state.getAddress(),
- await verifierLib.getAddress(),
- );
-
- const contracts = await deployHelper.deployValidatorContractsWithVerifiers(
- "sigV2",
- await state.getAddress(),
- );
- sig = contracts.validator;
- await verifier.addValidatorToWhitelist(await sig.getAddress());
- await verifier.connect();
- });
-
- it("Check ZKPRequestSet event", async () => {
- const requestsCount = 3;
- const data = [
- packValidatorParams(queries[0]),
- packValidatorParams(queries[1]),
- packValidatorParams(queries[2]),
- ];
-
- for (let i = 0; i < requestsCount; i++) {
- await verifier.setZKPRequest(i, {
- metadata: "metadataN" + i,
- validator: await sig.getAddress(),
- data: data[i],
- });
- }
- const filter = verifier.filters.ZKPRequestSet(null, null);
- const logs = await verifier.queryFilter(filter, 0, "latest");
-
- const coder = AbiCoder.defaultAbiCoder();
- logs.map((log, index) => {
- const [decodedData] = coder.decode(encodedDataAbi as any, log.args.data);
- expect(decodedData.schema).to.equal(queries[index].schema);
- expect(decodedData.claimPathKey).to.equal(queries[index].claimPathKey);
- expect(decodedData.operator).to.equal(queries[index].operator);
- expect(decodedData.slotIndex).to.equal(queries[index].slotIndex);
- decodedData.value.forEach((v, i) => {
- expect(v).to.equal(queries[index].value[i]);
- });
- expect(decodedData.queryHash).to.equal(queries[index].queryHash);
- decodedData.circuitIds.forEach((circuitId, i) => {
- expect(circuitId).to.equal(queries[index].circuitIds[i]);
- });
- expect(decodedData.skipClaimRevocationCheck).to.equal(
- queries[index].skipClaimRevocationCheck,
- );
- expect(decodedData.claimPathNotExists).to.equal(queries[index].claimPathNotExists);
- });
- });
-
- it("Check ZKPRequestUpdate event", async () => {
- const originalRequestData = packValidatorParams(queries[0]);
- const updatedRequestData = packValidatorParams(queries[1]);
-
- await verifier.setZKPRequest(0, {
- metadata: "metadataN0",
- validator: await sig.getAddress(),
- data: originalRequestData,
- });
-
- await verifier.updateZKPRequest(0, {
- metadata: "metadataN1",
- validator: await sig.getAddress(),
- data: updatedRequestData,
- });
-
- const filter = verifier.filters.ZKPRequestUpdate(null, null);
- const logs = await verifier.queryFilter(filter, 0, "latest");
-
- const coder = AbiCoder.defaultAbiCoder();
- logs.map((log) => {
- const [decodedData] = coder.decode(encodedDataAbi as any, log.args.data);
- expect(decodedData.schema).to.equal(queries[1].schema);
- expect(decodedData.claimPathKey).to.equal(queries[1].claimPathKey);
- expect(decodedData.operator).to.equal(queries[1].operator);
- expect(decodedData.slotIndex).to.equal(queries[1].slotIndex);
- decodedData.value.forEach((v, i) => {
- expect(v).to.equal(queries[1].value[i]);
- });
- expect(decodedData.queryHash).to.equal(queries[1].queryHash);
- decodedData.circuitIds.forEach((circuitId, i) => {
- expect(circuitId).to.equal(queries[1].circuitIds[i]);
- });
- expect(decodedData.skipClaimRevocationCheck).to.equal(queries[1].skipClaimRevocationCheck);
- expect(decodedData.claimPathNotExists).to.equal(queries[1].claimPathNotExists);
- });
- });
-});
diff --git a/test/verifier/universal-verifier.test.ts b/test/verifier/universal-verifier.test.ts
index 4918f494..9fddda8b 100644
--- a/test/verifier/universal-verifier.test.ts
+++ b/test/verifier/universal-verifier.test.ts
@@ -2,411 +2,657 @@ import { expect } from "chai";
import { DeployHelper } from "../../helpers/DeployHelper";
import { ethers } from "hardhat";
import { packValidatorParams } from "../utils/validator-pack-utils";
-import { prepareInputs } from "../utils/state-utils";
-import { Block } from "ethers";
-import proofJson from "../validators/mtp/data/valid_mtp_user_genesis.json";
-import { CircuitId } from "@0xpolygonid/js-sdk";
+import { AbiCoder, Block } from "ethers";
+import { byteEncoder, CircuitId } from "@0xpolygonid/js-sdk";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
+import { contractsInfo } from "../../helpers/constants";
-describe("Universal Verifier MTP & SIG validators", function () {
- let verifier: any, validator: any, state: any;
+describe("Universal Verifier tests", function () {
+ let request, paramsFromValidator, multiRequest, authResponse, response: any;
+ let verifier: any, validator: any, authValidator: any, state: any;
let signer, signer2, signer3;
let signerAddress: string;
let deployHelper: DeployHelper;
- const query = {
- schema: BigInt("180410020913331409885634153623124536270"),
- claimPathKey: BigInt(
- "8566939875427719562376598811066985304309117528846759529734201066483458512800",
- ),
- operator: 1n,
- slotIndex: 0n,
- value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
- queryHash: BigInt(
- "1496222740463292783938163206931059379817846775593932664024082849882751356658",
- ),
- circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
- claimPathNotExists: 0,
- };
+ const storageFields = [
+ {
+ name: "userID",
+ value: 1n,
+ },
+ {
+ name: "issuerID",
+ value: 2n,
+ },
+ ];
+
+ const crossChainProofs = "0x";
async function deployContractsFixture() {
const [ethSigner, ethSigner2, ethSigner3] = await ethers.getSigners();
deployHelper = await DeployHelper.initialize(null, true);
const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0112"]);
- const verifierLib = await deployHelper.deployVerifierLib();
- const verifier: any = await deployHelper.deployUniversalVerifier(
+ const validator = await deployHelper.deployValidatorStub("RequestValidatorStub");
+ await validator.stub_setVerifyResults([
+ { name: "userID", value: 1 },
+ { name: "issuerID", value: 2 },
+ ]);
+
+ const universalVerifier: any = await deployHelper.deployUniversalVerifier(
ethSigner,
await stateContract.getAddress(),
- await verifierLib.getAddress(),
);
- const validator = await deployHelper.deployValidatorStub();
- await verifier.addValidatorToWhitelist(await validator.getAddress());
- await verifier.connect();
+ await universalVerifier.addValidatorToWhitelist(await validator.getAddress());
+ await universalVerifier.connect();
+
+ const authValidator = await deployHelper.deployValidatorStub("AuthValidatorStub");
+ await authValidator.stub_setVerifyResults(1);
+
+ const authMethod = {
+ authMethod: "stubAuth",
+ validator: await authValidator.getAddress(),
+ params: "0x",
+ };
+ await universalVerifier.setAuthMethod(authMethod);
- return { ethSigner, ethSigner2, ethSigner3, stateContract, verifier, validator };
+ return {
+ ethSigner,
+ ethSigner2,
+ ethSigner3,
+ stateContract,
+ universalVerifier,
+ validator,
+ authValidator,
+ };
}
- async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) {
+ async function checkStorageFields(verifier: any, requestId: bigint, storageFields: any[]) {
for (const field of storageFields) {
- const value = await verifier.getProofStorageField(
- await signer.getAddress(),
+ const value = await verifier.getResponseFieldValue(
requestId,
+ await signer.getAddress(),
field.name,
);
expect(value).to.be.equal(field.value);
}
}
- beforeEach(async () => {
- ({
- ethSigner: signer,
- ethSigner2: signer2,
- ethSigner3: signer3,
- stateContract: state,
- verifier,
- validator,
- } = await loadFixture(deployContractsFixture));
- signerAddress = await signer.getAddress();
- });
+ describe("Methods", function () {
+ beforeEach(async () => {
+ ({
+ ethSigner: signer,
+ ethSigner2: signer2,
+ ethSigner3: signer3,
+ stateContract: state,
+ universalVerifier: verifier,
+ validator: validator,
+ } = await loadFixture(deployContractsFixture));
+ request = {
+ requestId: 0,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+
+ authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ response = {
+ requestId: 0,
+ proof: "0x",
+ metadata: "0x",
+ };
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ multiRequest = {
+ multiRequestId: 1,
+ requestIds: [request.requestId],
+ groupIds: [],
+ metadata: "0x",
+ };
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ signerAddress = await signer.getAddress();
+ });
- it("Test get state address", async () => {
- const stateAddr = await verifier.getStateAddress();
- expect(stateAddr).to.be.equal(await state.getAddress());
- });
+ it("Test get version", async () => {
+ const version = await verifier.version();
+ expect(version).to.be.equal(contractsInfo.UNIVERSAL_VERIFIER.version);
+ });
- it("Test add, get ZKPRequest, requestIdExists, getZKPRequestsCount", async () => {
- const requestsCount = 3;
- const validatorAddr = await validator.getAddress();
+ it("Test get state address", async () => {
+ let stateAddr = await verifier.getStateAddress();
+ expect(stateAddr).to.be.equal(await state.getAddress());
- for (let i = 0; i < requestsCount; i++) {
- await expect(
- verifier.setZKPRequest(i, {
- metadata: "metadataN" + i,
- validator: validatorAddr,
- data: "0x0" + i,
- }),
- )
- .to.emit(verifier, "ZKPRequestSet")
- .withArgs(i, signerAddress, "metadataN" + i, validatorAddr, "0x0" + i);
- const request = await verifier.getZKPRequest(i);
- expect(request.metadata).to.be.equal("metadataN" + i);
- expect(request.validator).to.be.equal(validatorAddr);
- expect(request.data).to.be.equal("0x0" + i);
-
- const requestIdExists = await verifier.requestIdExists(i);
- expect(requestIdExists).to.be.true;
- const requestIdDoesntExists = await verifier.requestIdExists(i + 1);
- expect(requestIdDoesntExists).to.be.false;
-
- await expect(verifier.getZKPRequest(i + 1)).to.be.rejectedWith("request id doesn't exist");
- }
+ await verifier.setState(await signer.getAddress());
- const count = await verifier.getZKPRequestsCount();
- expect(count).to.be.equal(requestsCount);
- });
+ stateAddr = await verifier.getStateAddress();
+ expect(stateAddr).to.be.equal(await signer.getAddress());
- it("Test add, get ZKPRequest, requestIdExists, getZKPRequestsCount with multiple set", async () => {
- const requestsCount = 3;
- const validatorAddr = await validator.getAddress();
-
- const requestIds: number[] = [];
- const requests: any[] = [];
- for (let i = 0; i < requestsCount; i++) {
- requestIds.push(i);
- requests.push({
- metadata: "metadataN" + i,
- validator: validatorAddr,
- data: "0x0" + i,
- });
- }
+ await verifier.setState(await state.getAddress());
+ });
- await expect(verifier.setZKPRequests(requestIds, requests))
- .to.emit(verifier, "ZKPRequestSet")
- .withArgs(0, signerAddress, "metadataN" + 0, validatorAddr, "0x0" + 0);
+ it("Test add, getRequest, requestIdExists, getRequestsCount", async () => {
+ const requestsCount = 3;
+ for (let i = 0; i < requestsCount; i++) {
+ request.requestId = i;
+ request.metadata = "metadataN" + i;
+ request.params = "0x0" + i;
+
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await expect(verifier.setRequests([request]))
+ .to.emit(verifier, "RequestSet")
+ .withArgs(i, signerAddress, "metadataN" + i, request.validator, "0x0" + i);
+ const requestFromContract = await verifier.getRequest(i);
+ expect(requestFromContract.metadata).to.be.equal("metadataN" + i);
+ expect(requestFromContract.validator).to.be.equal(request.validator);
+ expect(requestFromContract.params).to.be.equal("0x0" + i);
+
+ const requestIdExists = await verifier.requestIdExists(i);
+ expect(requestIdExists).to.be.true;
+ const requestIdDoesntExists = await verifier.requestIdExists(i + 1);
+ expect(requestIdDoesntExists).to.be.false;
+
+ await expect(verifier.getRequest(i + 1))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(i + 1);
+ }
+
+ const count = await verifier.getRequestsCount();
+ expect(count).to.be.equal(requestsCount);
+ });
- for (let i = 1; i < requestsCount; i++) {
- const request = await verifier.getZKPRequest(i);
- expect(request.metadata).to.be.equal("metadataN" + i);
- expect(request.validator).to.be.equal(validatorAddr);
- expect(request.data).to.be.equal("0x0" + i);
+ it("Test submit response single request", async () => {
+ const nonExistingRequestId = 1;
+ await verifier.setRequests([request]);
- const requestIdExists = await verifier.requestIdExists(i);
- expect(requestIdExists).to.be.true;
- }
+ const tx = await verifier.submitResponse(authResponse, [response], crossChainProofs);
- const count = await verifier.getZKPRequestsCount();
- expect(count).to.be.equal(requestsCount);
- });
+ const txRes = await tx.wait();
+ await checkStorageFields(verifier, BigInt(request.requestId), storageFields);
- it("Test submit response", async () => {
- const requestId = 0;
- const nonExistingRequestId = 1;
- const data = packValidatorParams(query);
+ let filter = verifier.filters.ResponseSubmitted;
+ let events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("ResponseSubmitted");
+ expect(events[0].args.requestId).to.be.equal(request.requestId);
+ expect(events[0].args.caller).to.be.equal(signerAddress);
- await verifier.setZKPRequest(0, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: data,
+ filter = verifier.filters.AuthResponseSubmitted;
+ events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("AuthResponseSubmitted");
+ expect(events[0].args.authMethod.hash).to.be.equal(
+ ethers.keccak256(byteEncoder.encode(authResponse.authMethod)),
+ );
+ expect(events[0].args.caller).to.be.equal(signerAddress);
+
+ const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
+ txRes.blockNumber,
+ )) as Block;
+
+ const status = await verifier.getRequestProofStatus(signerAddress, request.requestId);
+ expect(status.isVerified).to.be.true;
+ expect(status.validatorVersion).to.be.equal("1.0.0-stub");
+ expect(status.timestamp).to.be.equal(txResTimestamp);
+
+ await expect(verifier.getRequestProofStatus(signerAddress, nonExistingRequestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(nonExistingRequestId);
});
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
- const tx = await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c);
- const txRes = await tx.wait();
- const storageFields = [
- {
- name: "userID",
- value: inputs[1],
- },
- {
- name: "issuerID",
- value: inputs[2],
- },
- ];
- await checkStorageFields(verifier, requestId, storageFields);
- const filter = verifier.filters.ZKPResponseSubmitted;
-
- const events = await verifier.queryFilter(filter, -1);
- expect(events[0].eventName).to.be.equal("ZKPResponseSubmitted");
- expect(events[0].args.requestId).to.be.equal(0);
- expect(events[0].args.caller).to.be.equal(signerAddress);
-
- const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
- txRes.blockNumber,
- )) as Block;
-
- await expect(
- verifier.verifyZKPResponse(
- 0,
- inputs,
- pi_a,
- pi_b,
- pi_c,
- "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
- ),
- ).not.to.be.rejected;
-
- const status = await verifier.getProofStatus(signerAddress, requestId);
- expect(status.isVerified).to.be.true;
- expect(status.validatorVersion).to.be.equal("2.0.2-mock");
- expect(status.blockNumber).to.be.equal(txRes.blockNumber);
- expect(status.blockTimestamp).to.be.equal(txResTimestamp);
-
- await expect(verifier.getProofStatus(signerAddress, nonExistingRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
- });
+ it("Test submit response multiple request", async () => {
+ const requestIds = [1, 2];
+ await verifier.setRequests([
+ {
+ ...request,
+ requestId: requestIds[0],
+ },
+ {
+ ...request,
+ requestId: requestIds[1],
+ },
+ ]);
+
+ const tx = await verifier.submitResponse(
+ authResponse,
+ [
+ {
+ ...response,
+ requestId: requestIds[0],
+ },
+ {
+ ...response,
+ requestId: requestIds[1],
+ },
+ ],
+ crossChainProofs,
+ );
- it("Check access control", async () => {
- const owner = signer;
- const requestOwner = signer2;
- const someSigner = signer3;
- const requestId = 0;
- const nonExistentRequestId = 1;
- const requestOwnerAddr = await requestOwner.getAddress();
- const someSignerAddress = await someSigner.getAddress();
-
- await expect(verifier.getRequestOwner(requestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
- await verifier.connect(requestOwner).setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: packValidatorParams(query),
+ const txRes = await tx.wait();
+
+ for (const requestId of requestIds) {
+ await checkStorageFields(verifier, BigInt(requestId), storageFields);
+ }
+
+ let filter = verifier.filters.ResponseSubmitted;
+ let events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("ResponseSubmitted");
+ expect(events[0].args.requestId).to.be.equal(requestIds[0]);
+ expect(events[0].args.caller).to.be.equal(signerAddress);
+
+ filter = verifier.filters.AuthResponseSubmitted;
+ events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("AuthResponseSubmitted");
+ expect(events[0].args.authMethod.hash).to.be.equal(
+ ethers.keccak256(byteEncoder.encode(authResponse.authMethod)),
+ );
+ expect(events[0].args.caller).to.be.equal(signerAddress);
+
+ const { timestamp: txResTimestamp } = (await ethers.provider.getBlock(
+ txRes.blockNumber,
+ )) as Block;
+
+ for (const requestId of requestIds) {
+ const status = await verifier.getRequestProofStatus(signerAddress, requestId);
+ expect(status.isVerified).to.be.true;
+ expect(status.validatorVersion).to.be.equal("1.0.0-stub");
+ expect(status.timestamp).to.be.equal(txResTimestamp);
+ }
});
- expect(await verifier.getRequestOwner(requestId)).to.be.equal(requestOwnerAddr);
- await expect(
- verifier.connect(someSigner).setRequestOwner(requestId, someSigner),
- ).to.be.rejectedWith("Not an owner or request owner");
+ it("Check access control", async () => {
+ const owner = signer;
+ const requestOwner = signer2;
+ const someSigner = signer3;
+ const nonExistentRequestId = 1;
+ const requestOwnerAddr = await requestOwner.getAddress();
+ const someSignerAddress = await someSigner.getAddress();
- await verifier.connect(requestOwner).setRequestOwner(requestId, someSigner);
- expect(await verifier.getRequestOwner(requestId)).to.be.equal(someSignerAddress);
+ await expect(verifier.getRequestOwner(request.requestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(request.requestId);
- await expect(
- verifier.connect(requestOwner).setRequestOwner(requestId, requestOwnerAddr),
- ).to.be.rejectedWith("Not an owner or request owner");
- await verifier.connect(owner).setRequestOwner(requestId, requestOwnerAddr);
- expect(await verifier.getRequestOwner(requestId)).to.be.equal(requestOwnerAddr);
+ await verifier.connect(requestOwner).setRequests([request]);
- await expect(verifier.getRequestOwner(nonExistentRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
- await expect(
- verifier.setRequestOwner(nonExistentRequestId, someSignerAddress),
- ).to.be.rejectedWith("request id doesn't exist");
- });
+ expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(requestOwnerAddr);
+ await expect(verifier.connect(someSigner).setRequestOwner(request.requestId, someSigner))
+ .to.be.revertedWithCustomError(verifier, "NotAnOwnerOrRequestOwner")
+ .withArgs(someSigner);
- it("Check disable/enable functionality", async () => {
- const owner = signer;
- const requestOwner = signer2;
- const someSigner = signer3;
- const requestId = 0;
- const nonExistentRequestId = 1;
+ await verifier.connect(requestOwner).setRequestOwner(request.requestId, someSigner);
+ expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(someSignerAddress);
- await expect(verifier.isZKPRequestEnabled(requestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
+ await expect(
+ verifier.connect(requestOwner).setRequestOwner(request.requestId, requestOwnerAddr),
+ )
+ .to.be.revertedWithCustomError(verifier, "NotAnOwnerOrRequestOwner")
+ .withArgs(requestOwner);
+
+ await verifier.connect(owner).setRequestOwner(request.requestId, requestOwnerAddr);
+ expect(await verifier.getRequestOwner(request.requestId)).to.be.equal(requestOwnerAddr);
+
+ await expect(verifier.getRequestOwner(nonExistentRequestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(nonExistentRequestId);
+ await expect(verifier.setRequestOwner(nonExistentRequestId, someSignerAddress))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(nonExistentRequestId);
+ });
- await verifier.connect(requestOwner).setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: packValidatorParams(query),
+ it("Test submit response with disable/enable functionality", async () => {
+ const requestIds = [0, 1, 2];
+
+ const singleResponse = [response];
+
+ const multiResponses = [
+ {
+ ...response,
+ requestId: 1,
+ },
+ {
+ ...response,
+ requestId: 2,
+ },
+ ];
+
+ for (const requestId of requestIds) {
+ await verifier.setRequests([
+ {
+ ...request,
+ requestId: requestId,
+ },
+ ]);
+ }
+
+ await verifier.disableRequest(singleResponse[0].requestId);
+ await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs))
+ .to.be.revertedWithCustomError(verifier, "RequestIsDisabled")
+ .withArgs(singleResponse[0].requestId);
+
+ await verifier.disableRequest(multiResponses[0].requestId);
+ await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs))
+ .to.be.revertedWithCustomError(verifier, "RequestIsDisabled")
+ .withArgs(multiResponses[0].requestId);
+
+ await verifier.enableRequest(singleResponse[0].requestId);
+ await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)).not.to
+ .be.rejected;
+
+ await verifier.enableRequest(multiResponses[0].requestId);
+ await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)).not.to
+ .be.rejected;
});
- expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true;
- await expect(verifier.connect(someSigner).disableZKPRequest(requestId)).to.be.rejectedWith(
- "Not an owner or request owner",
- );
- expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true;
+ it("Test submit response check whitelisted functionality", async () => {
+ const requestIds = [0, 1, 2];
+ const singleResponse = [response];
+
+ const multiResponses = [
+ {
+ ...response,
+ requestId: 1,
+ },
+ {
+ ...response,
+ requestId: 2,
+ },
+ ];
+
+ for (const requestId of requestIds) {
+ await verifier.setRequests([
+ {
+ ...request,
+ requestId: requestId,
+ },
+ ]);
+ }
+
+ await verifier.removeValidatorFromWhitelist(await validator.getAddress());
+ await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs))
+ .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted")
+ .withArgs(await validator.getAddress());
+ await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs))
+ .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted")
+ .withArgs(await validator.getAddress());
+
+ await verifier.addValidatorToWhitelist(await validator.getAddress());
+ await expect(verifier.submitResponse(authResponse, singleResponse, crossChainProofs)).not.to
+ .be.rejected;
+ await expect(verifier.submitResponse(authResponse, multiResponses, crossChainProofs)).not.to
+ .be.rejected;
+ });
- await verifier.connect(owner).disableZKPRequest(requestId);
- expect(await verifier.isZKPRequestEnabled(requestId)).to.be.false;
+ it("Check updateRequest", async () => {
+ const owner = signer;
+ const requestOwner = signer2;
+ const requestId = 0;
- await expect(verifier.connect(someSigner).enableZKPRequest(requestId)).to.be.rejectedWith(
- "Not an owner or request owner",
- );
- await verifier.connect(requestOwner).enableZKPRequest(requestId);
- expect(await verifier.isZKPRequestEnabled(requestId)).to.be.true;
+ await verifier.connect(requestOwner).setRequests([request]);
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
- await verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c);
+ let requestStored = await verifier.getRequest(requestId);
+ expect(requestStored.metadata).to.be.equal(request.metadata);
+ await expect(
+ verifier.connect(requestOwner).updateRequest(request),
+ ).to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount");
- await verifier.connect(requestOwner).disableZKPRequest(requestId);
- await expect(verifier.submitZKPResponse(0, inputs, pi_a, pi_b, pi_c)).to.be.rejectedWith(
- "Request is disabled",
- );
- await expect(
- verifier.verifyZKPResponse(
- 0,
- inputs,
- pi_a,
- pi_b,
- pi_c,
- "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
- ),
- ).to.be.rejectedWith("Request is disabled");
-
- await expect(verifier.isZKPRequestEnabled(nonExistentRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
- await expect(verifier.disableZKPRequest(nonExistentRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
- await expect(verifier.enableZKPRequest(nonExistentRequestId)).to.be.rejectedWith(
- "request id doesn't exist",
- );
+ await verifier.connect(owner).updateRequest({
+ ...request,
+ metadata: "metadata2",
+ });
+
+ requestStored = await verifier.getRequest(requestId);
+ expect(requestStored.metadata).to.be.equal("metadata2");
+ });
+
+ it("updateRequest - not existed request", async () => {
+ const owner = signer;
+ const requestId = 0;
+
+ await expect(verifier.connect(owner).updateRequest(request))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(requestId);
+ });
+
+ it("Test set request fails with VerifierIDIsNotValid", async () => {
+ ({
+ ethSigner: signer,
+ ethSigner2: signer2,
+ stateContract: state,
+ validator: validator,
+ universalVerifier: verifier,
+ } = await loadFixture(deployContractsFixture));
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 2 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ const requestId = 40;
+
+ const request = {
+ requestId: requestId,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await verifier.setVerifierID(1);
+
+ await expect(verifier.setRequests([request]))
+ .to.be.revertedWithCustomError(verifier, "VerifierIDIsNotValid")
+ .withArgs(2, 1);
+ });
});
- it("Check whitelisted validators", async () => {
- const owner = signer;
- const someAddress = signer2;
- const requestId = 1;
- const otherRequestId = 2;
- const { validator: mtp } = await deployHelper.deployValidatorContractsWithVerifiers(
- "mtpV2",
- await state.getAddress(),
- );
- const mtpValAddr = await mtp.getAddress();
- expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.false;
-
- await expect(
- verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: mtpValAddr,
- data: "0x00",
- }),
- ).to.be.rejectedWith("Validator is not whitelisted");
-
- await expect(verifier.connect(someAddress).addValidatorToWhitelist(mtpValAddr))
- .to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount")
- .withArgs(someAddress);
- expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.false;
-
- await verifier.connect(owner).addValidatorToWhitelist(mtpValAddr);
- expect(await verifier.isWhitelistedValidator(mtpValAddr)).to.be.true;
-
- await expect(
- verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: mtpValAddr,
- data: "0x00",
- }),
- ).not.to.be.rejected;
-
- // can't whitelist validator, which does not support ICircuitValidator interface
- await expect(verifier.addValidatorToWhitelist(someAddress)).to.be.rejected;
-
- await expect(
- verifier.setZKPRequest(otherRequestId, {
- metadata: "metadata",
- validator: someAddress,
- data: "0x00",
- }),
- ).to.be.rejectedWith("Validator is not whitelisted");
-
- await verifier.removeValidatorFromWhitelist(mtpValAddr);
-
- await expect(
- verifier.submitZKPResponse(
- requestId,
- [],
- [0, 0],
- [
- [0, 0],
- [0, 0],
+ describe("Events", function () {
+ const queries = [
+ {
+ schema: 111n,
+ claimPathKey: 8566939875427719562376598811066985304309117528846759529734201066483458512800n,
+ operator: 1n,
+ slotIndex: 0n,
+ value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
+ queryHash: BigInt(
+ "1496222740463292783938163206931059379817846775593932664024082849882751356658",
+ ),
+ circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
+ skipClaimRevocationCheck: false,
+ claimPathNotExists: 0n,
+ },
+ {
+ schema: 222n,
+ claimPathKey: BigInt(
+ "8566939875427719562376598811066985304309117528846759529734201066483458512800",
+ ),
+ operator: 1n,
+ slotIndex: 0n,
+ value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
+ queryHash: BigInt(
+ "1496222740463292783938163206931059379817846775593932664024082849882751356658",
+ ),
+ circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
+ skipClaimRevocationCheck: true,
+ claimPathNotExists: 0n,
+ },
+ {
+ schema: 333n,
+ claimPathKey: BigInt(
+ "8566939875427719562376598811066985304309117528846759529734201066483458512800",
+ ),
+ operator: 1n,
+ slotIndex: 0n,
+ value: [1420070400000000000n, ...new Array(63).fill("0").map((x) => BigInt(x))],
+ queryHash: BigInt(
+ "1496222740463292783938163206931059379817846775593932664024082849882751356658",
+ ),
+ circuitIds: [CircuitId.AtomicQuerySigV2OnChain],
+ skipClaimRevocationCheck: false,
+ claimPathNotExists: 0n,
+ },
+ ];
+
+ const encodedDataAbi = [
+ {
+ components: [
+ { name: "schema", type: "uint256" },
+ { name: "claimPathKey", type: "uint256" },
+ { name: "operator", type: "uint256" },
+ { name: "slotIndex", type: "uint256" },
+ { name: "value", type: "uint256[]" },
+ { name: "queryHash", type: "uint256" },
+ { name: "allowedIssuers", type: "uint256[]" },
+ { name: "circuitIds", type: "string[]" },
+ { name: "skipClaimRevocationCheck", type: "bool" },
+ { name: "claimPathNotExists", type: "uint256" },
],
- [0, 0],
- ),
- ).to.be.rejectedWith("Validator is not whitelisted");
- });
+ name: "",
+ type: "tuple",
+ },
+ ];
- it("Check updateZKPRequest", async () => {
- const owner = signer;
- const requestOwner = signer2;
- const requestId = 0;
- const data = packValidatorParams(query);
+ beforeEach(async () => {
+ ({
+ ethSigner: signer,
+ ethSigner2: signer2,
+ ethSigner3: signer3,
+ stateContract: state,
+ universalVerifier: verifier,
+ validator: validator,
+ authValidator: authValidator,
+ } = await loadFixture(deployContractsFixture));
+ signerAddress = await signer.getAddress();
+ });
- await verifier.connect(requestOwner).setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: data,
+ it("Check RequestSet event", async () => {
+ const requestsCount = 3;
+ const params = [
+ packValidatorParams(queries[0]),
+ packValidatorParams(queries[1]),
+ packValidatorParams(queries[2]),
+ ];
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ for (let i = 0; i < requestsCount; i++) {
+ await validator.stub_setRequestParams([params[i]], [paramsFromValidator]);
+ await expect(
+ verifier.setRequests([
+ {
+ ...request,
+ requestId: i,
+ params: params[i],
+ },
+ ]),
+ ).to.emit(verifier, "RequestSet");
+ }
+ const filter = verifier.filters.RequestSet(null, null);
+ const logs = await verifier.queryFilter(filter, 0, "latest");
+
+ const coder = AbiCoder.defaultAbiCoder();
+ logs.map((log, index) => {
+ const [decodedData] = coder.decode(encodedDataAbi as any, log.args.params);
+ expect(decodedData.schema).to.equal(queries[index].schema);
+ expect(decodedData.claimPathKey).to.equal(queries[index].claimPathKey);
+ expect(decodedData.operator).to.equal(queries[index].operator);
+ expect(decodedData.slotIndex).to.equal(queries[index].slotIndex);
+ decodedData.value.forEach((v, i) => {
+ expect(v).to.equal(queries[index].value[i]);
+ });
+ expect(decodedData.queryHash).to.equal(queries[index].queryHash);
+ decodedData.circuitIds.forEach((circuitId, i) => {
+ expect(circuitId).to.equal(queries[index].circuitIds[i]);
+ });
+ expect(decodedData.skipClaimRevocationCheck).to.equal(
+ queries[index].skipClaimRevocationCheck,
+ );
+ expect(decodedData.claimPathNotExists).to.equal(queries[index].claimPathNotExists);
+ });
});
- let request = await verifier.getZKPRequest(requestId);
- expect(request.metadata).to.be.equal("metadata");
+ it("Check RequestUpdate event", async () => {
+ const originalRequestData = packValidatorParams(queries[0]);
+ const updatedRequestData = packValidatorParams(queries[1]);
- await expect(
- verifier.connect(requestOwner).updateZKPRequest(requestId, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: data,
- }),
- ).to.be.revertedWithCustomError(verifier, "OwnableUnauthorizedAccount");
-
- await verifier.connect(owner).updateZKPRequest(requestId, {
- metadata: "metadata2",
- validator: await validator.getAddress(),
- data: data,
+ await validator.stub_setRequestParams([originalRequestData], [paramsFromValidator]);
+ await validator.stub_setRequestParams([updatedRequestData], [paramsFromValidator]);
+
+ await verifier.setRequests([
+ {
+ ...request,
+ params: originalRequestData,
+ },
+ ]);
+
+ await verifier.updateRequest({
+ ...request,
+ metadata: "metadataN1",
+ params: updatedRequestData,
+ });
+
+ const filter = verifier.filters.RequestUpdate(null, null);
+ const logs = await verifier.queryFilter(filter, 0, "latest");
+
+ const coder = AbiCoder.defaultAbiCoder();
+ logs.map((log) => {
+ const [decodedData] = coder.decode(encodedDataAbi as any, log.args.params);
+ expect(decodedData.schema).to.equal(queries[1].schema);
+ expect(decodedData.claimPathKey).to.equal(queries[1].claimPathKey);
+ expect(decodedData.operator).to.equal(queries[1].operator);
+ expect(decodedData.slotIndex).to.equal(queries[1].slotIndex);
+ decodedData.value.forEach((v, i) => {
+ expect(v).to.equal(queries[1].value[i]);
+ });
+ expect(decodedData.queryHash).to.equal(queries[1].queryHash);
+ decodedData.circuitIds.forEach((circuitId, i) => {
+ expect(circuitId).to.equal(queries[1].circuitIds[i]);
+ });
+ expect(decodedData.skipClaimRevocationCheck).to.equal(queries[1].skipClaimRevocationCheck);
+ expect(decodedData.claimPathNotExists).to.equal(queries[1].claimPathNotExists);
+ });
});
- request = await verifier.getZKPRequest(requestId);
- expect(request.metadata).to.be.equal("metadata2");
- });
+ it("Check AuthMethodSet event", async () => {
+ const nonExistingAuthMethod = {
+ authMethod: "stubAuth2",
+ validator: await authValidator.getAddress(),
+ params: "0x",
+ };
+ const tx = await verifier.setAuthMethod(nonExistingAuthMethod);
+
+ const filter = verifier.filters.AuthMethodSet;
+ const events = await verifier.queryFilter(filter, tx.blockNumber);
+ expect(events[0].eventName).to.be.equal("AuthMethodSet");
+ expect(events[0].args.authMethod.hash).to.be.equal(
+ ethers.keccak256(byteEncoder.encode(nonExistingAuthMethod.authMethod)),
+ );
+ expect(events[0].args.validator).to.be.equal(nonExistingAuthMethod.validator);
+ expect(events[0].args.params).to.be.equal(nonExistingAuthMethod.params);
+ });
- it("updateZKPRequest - not existed request", async () => {
- const owner = signer;
- const requestId = 0;
- const data = packValidatorParams(query);
+ it("Check MultiRequestSet event", async function () {
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
- await expect(
- verifier.connect(owner).updateZKPRequest(requestId, {
- metadata: "metadata",
- validator: await validator.getAddress(),
- data: data,
- }),
- ).to.be.rejectedWith("equest id doesn't exis");
+ await expect(verifier.setMultiRequest(multiRequest)).to.emit(verifier, "MultiRequestSet");
+
+ const filter = verifier.filters.MultiRequestSet;
+ const events = await verifier.queryFilter(filter, -1);
+ expect(events[0].eventName).to.be.equal("MultiRequestSet");
+ expect(events[0].args.multiRequestId).to.be.equal(multiRequest.multiRequestId);
+ expect(events[0].args.requestIds).to.deep.equal(multiRequest.requestIds);
+ expect(events[0].args.groupIds).to.deep.equal(multiRequest.groupIds);
+ });
});
});
diff --git a/test/verifier/universal-verifier.v3.test.ts b/test/verifier/universal-verifier.v3.test.ts
deleted file mode 100644
index 08c840c5..00000000
--- a/test/verifier/universal-verifier.v3.test.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-import { DeployHelper } from "../../helpers/DeployHelper";
-import { ethers } from "hardhat";
-import { packV3ValidatorParams } from "../utils/validator-pack-utils";
-import { prepareInputs, publishState } from "../utils/state-utils";
-import { calculateQueryHashV3 } from "../utils/query-hash-utils";
-import { expect } from "chai";
-import { CircuitId } from "@0xpolygonid/js-sdk";
-import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
-import proofJson from "../validators/v3/data/valid_bjj_user_genesis_auth_disabled_v3.json";
-import stateTransition1 from "../validators/common-data/issuer_from_genesis_state_to_first_auth_disabled_transition_v3.json";
-import stateTransition11 from "../validators/common-data/issuer_from_genesis_state_to_first_transition_v3.json";
-import stateTransition12 from "../validators/common-data/user_from_genesis_state_to_first_transition_v3.json";
-import stateTransition13 from "../validators/common-data/issuer_from_first_state_to_second_transition_v3.json";
-import { packZKProof } from "../utils/packData";
-import { TEN_YEARS } from "../../helpers/constants";
-
-const storageFields = [
- {
- name: "issuerID",
- value: 22057981499787921734624217749308316644136637822444794206796063681866502657n,
- },
- {
- name: "userID",
- value: 23013175891893363078841232968022302880776034013620341061794940968520126978n,
- },
- { name: "timestamp", value: 1642074362n },
- {
- name: "linkID",
- value: 19823993270096139446564592922993947503208333537792611306066620392561342309875n,
- },
- { name: "nullifier", value: 0 },
-];
-
-describe("Universal Verifier V3 validator", function () {
- let verifier: any, v3Validator: any, state: any;
- let signer, signer2;
- let deployHelper: DeployHelper;
-
- const value = ["20010101", ...new Array(63).fill("0")];
-
- const schema = "267831521922558027206082390043321796944";
- const slotIndex = 0; // 0 for signature
- const operator = 2;
- const claimPathKey =
- "20376033832371109177683048456014525905119173674985843915445634726167450989630";
- const [merklized, isRevocationChecked, valueArrSize] = [1, 1, 1];
- const nullifierSessionId = "0";
- const verifierId = "21929109382993718606847853573861987353620810345503358891473103689157378049";
- const queryHash = calculateQueryHashV3(
- value,
- schema,
- slotIndex,
- operator,
- claimPathKey,
- valueArrSize,
- merklized,
- isRevocationChecked,
- verifierId,
- nullifierSessionId,
- );
-
- const query = {
- schema,
- claimPathKey,
- operator,
- slotIndex,
- value,
- circuitIds: [CircuitId.AtomicQueryV3OnChain],
- skipClaimRevocationCheck: false,
- queryHash,
- groupID: 1,
- nullifierSessionID: nullifierSessionId, // for ethereum based user
- proofType: 1, // 1 for BJJ
- verifierID: verifierId,
- };
-
- const initializeState = async () => {
- deployHelper = await DeployHelper.initialize(null, true);
-
- const { state: stateContract } = await deployHelper.deployStateWithLibraries(["0x0212"]);
- const verifierLib = await deployHelper.deployVerifierLib();
- const contracts = await deployHelper.deployValidatorContractsWithVerifiers(
- "v3",
- await stateContract.getAddress(),
- );
- const validator = contracts.validator;
- const universalVerifier: any = await deployHelper.deployUniversalVerifier(
- signer,
- await stateContract.getAddress(),
- await verifierLib.getAddress(),
- );
- await universalVerifier.addValidatorToWhitelist(await validator.getAddress());
- await universalVerifier.connect();
-
- return { stateContract, validator, universalVerifier };
- };
-
- async function deployContractsFixture() {
- const [ethSigner, ethSigner2] = await ethers.getSigners();
- const { stateContract, validator, universalVerifier } = await initializeState();
- return { ethSigner, ethSigner2, stateContract, universalVerifier, validator };
- }
-
- async function checkStorageFields(verifier: any, requestId: number, storageFields: any[]) {
- for (const field of storageFields) {
- const value = await verifier.getProofStorageField(
- await signer.getAddress(),
- requestId,
- field.name,
- );
- expect(value).to.be.equal(field.value);
- }
- }
-
- before(async () => {
- ({
- ethSigner: signer,
- ethSigner2: signer2,
- stateContract: state,
- validator: v3Validator,
- universalVerifier: verifier,
- } = await loadFixture(deployContractsFixture));
- await v3Validator.setProofExpirationTimeout(TEN_YEARS);
- });
-
- it("Test submit response", async () => {
- await publishState(state, stateTransition1 as any);
- const data = packV3ValidatorParams(query);
- const requestId = 32;
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
- await v3Validator.setProofExpirationTimeout(TEN_YEARS);
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await verifier.verifyZKPResponse(
- requestId,
- inputs,
- pi_a,
- pi_b,
- pi_c,
- "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
- );
-
- await expect(verifier.submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c)).not.to.be
- .rejected;
-
- await checkStorageFields(verifier, requestId, storageFields);
- });
-
- it("Test submit response V2", async () => {
- const requestId = 32;
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- const zkProof = packZKProof(inputs, pi_a, pi_b, pi_c);
-
- const crossChainProofs = "0x";
-
- const metadatas = "0x";
-
- await expect(
- verifier.submitZKPResponseV2(
- [
- {
- requestId,
- zkProof: zkProof,
- data: metadatas,
- },
- ],
- crossChainProofs,
- ),
- ).not.to.be.rejected;
-
- await checkStorageFields(verifier, requestId, storageFields);
- });
-
- it("Test submit response fails with UserID does not correspond to the sender", async () => {
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
- const requestId = 32;
- await expect(
- verifier.connect(signer2).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("UserID does not correspond to the sender");
- });
-
- it("Test submit response fails with Issuer is not on the Allowed Issuers list", async () => {
- const data = packV3ValidatorParams(query, ["1"]);
- const requestId = 33;
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Issuer is not on the Allowed Issuers list");
- });
-
- it("Test submit response fails with Invalid Link ID pub signal", async () => {
- const query2 = {
- ...query,
- };
- query2.groupID = 0;
- const requestId = 34;
- const data = packV3ValidatorParams(query2);
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Invalid Link ID pub signal");
- });
-
- it("Test submit response fails with Proof type should match the requested one in query", async () => {
- const query2 = {
- ...query,
- };
- query2.proofType = 2;
- const requestId = 35;
- const data = packV3ValidatorParams(query2);
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Proof type should match the requested one in query");
- });
-
- it("Test submit response fails with Invalid nullify pub signal", async () => {
- const query2 = {
- ...query,
- };
- query2.nullifierSessionID = "2";
- const requestId = 36;
- const data = packV3ValidatorParams(query2);
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Invalid nullify pub signal");
- });
-
- it("Test submit response fails with Query hash does not match the requested one", async () => {
- const query2 = {
- ...query,
- };
- query2.queryHash = BigInt(0);
- const requestId = 37;
- const data = packV3ValidatorParams(query2);
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Query hash does not match the requested one");
- });
-
- it("Test submit response fails with Generated proof is outdated", async () => {
- ({
- ethSigner: signer,
- ethSigner2: signer2,
- stateContract: state,
- validator: v3Validator,
- universalVerifier: verifier,
- } = await loadFixture(deployContractsFixture));
-
- await publishState(state, stateTransition11 as any);
- await publishState(state, stateTransition12 as any);
- await publishState(state, stateTransition13 as any);
-
- const data = packV3ValidatorParams(query);
- const requestId = 37;
- await verifier.setZKPRequest(requestId, {
- metadata: "metadata",
- validator: await v3Validator.getAddress(),
- data: data,
- });
-
- const { inputs, pi_a, pi_b, pi_c } = prepareInputs(proofJson);
-
- await expect(
- verifier.connect(signer).submitZKPResponse(requestId, inputs, pi_a, pi_b, pi_c),
- ).to.be.rejectedWith("Generated proof is outdated");
- });
-});
diff --git a/test/verifier/validatorWhitelist.test.ts b/test/verifier/validatorWhitelist.test.ts
new file mode 100644
index 00000000..1eef3957
--- /dev/null
+++ b/test/verifier/validatorWhitelist.test.ts
@@ -0,0 +1,75 @@
+import { ethers } from "hardhat";
+import { beforeEach } from "mocha";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { expect } from "chai";
+
+describe("ValidatorWhitelist tests", function () {
+ let verifier, validator: any;
+ let signer1, signer2: any;
+ let request, paramsFromValidator: any;
+
+ async function deployContractsFixture() {
+ [signer1, signer2] = await ethers.getSigners();
+
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const verifier = await ethers.deployContract("ValidatorWhitelistTestWrapper", []);
+
+ const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub");
+ await verifier.initialize(await state.getAddress());
+
+ const validator = await ethers.deployContract("RequestValidatorStub");
+ return { verifier, validator, signer1, signer2 };
+ }
+
+ beforeEach(async function () {
+ ({ verifier, validator, signer1, signer2 } = await deployContractsFixture());
+
+ request = {
+ requestId: 1,
+ metadata: "0x",
+ validator: await validator.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ });
+
+ it("whitelist/remove Validators and modifier onlyWhitelistedValidator", async function () {
+ let isWhitelistedValidator = await verifier.isWhitelistedValidator(
+ await validator.getAddress(),
+ );
+ expect(isWhitelistedValidator).to.be.false;
+
+ await expect(verifier.testModifier(await validator.getAddress())).to.be.revertedWithCustomError(
+ verifier,
+ "ValidatorIsNotWhitelisted",
+ );
+
+ await verifier.addValidatorToWhitelist(await validator.getAddress());
+
+ await validator.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+
+ await expect(verifier.testModifier(await validator.getAddress())).not.to.be.reverted;
+ await expect(verifier.getRequestIfCanBeVerified(request.requestId)).not.to.be.reverted;
+
+ isWhitelistedValidator = await verifier.isWhitelistedValidator(await validator.getAddress());
+ expect(isWhitelistedValidator).to.be.true;
+
+ await verifier.removeValidatorFromWhitelist(await validator.getAddress());
+
+ await expect(verifier.testModifier(await validator.getAddress()))
+ .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted")
+ .withArgs(await validator.getAddress());
+ await expect(verifier.getRequestIfCanBeVerified(request.requestId))
+ .to.be.revertedWithCustomError(verifier, "ValidatorIsNotWhitelisted")
+ .withArgs(await validator.getAddress());
+
+ isWhitelistedValidator = await verifier.isWhitelistedValidator(await validator.getAddress());
+ expect(isWhitelistedValidator).to.be.false;
+ });
+});
diff --git a/test/verifier/verifer.test.ts b/test/verifier/verifer.test.ts
new file mode 100644
index 00000000..6fff36aa
--- /dev/null
+++ b/test/verifier/verifer.test.ts
@@ -0,0 +1,660 @@
+import { ethers } from "hardhat";
+import { beforeEach } from "mocha";
+import { DeployHelper } from "../../helpers/DeployHelper";
+import { expect } from "chai";
+
+describe("Verifer tests", function () {
+ let sender: any;
+ let verifier, validator1, validator2: any;
+ let request, paramsFromValidator, authMethod: any;
+ let multiRequest: any;
+ let signer: any;
+ let signerAddress: string;
+ let verifierId: any;
+
+ async function deployContractsFixture() {
+ [signer] = await ethers.getSigners();
+ signerAddress = await signer.getAddress();
+
+ const deployHelper = await DeployHelper.initialize(null, true);
+ const verifier = await ethers.deployContract("VerifierTestWrapper", []);
+
+ const { state } = await deployHelper.deployStateWithLibraries([], "Groth16VerifierStub");
+ await verifier.initialize(await state.getAddress());
+
+ const authValidatorStub = await ethers.deployContract("AuthValidatorStub");
+ await authValidatorStub.stub_setVerifyResults(1);
+
+ authMethod = {
+ authMethod: "stubAuth",
+ validator: await authValidatorStub.getAddress(),
+ params: "0x",
+ };
+
+ await verifier.setAuthMethod(authMethod);
+
+ const validator1 = await ethers.deployContract("RequestValidatorStub");
+ const validator2 = await ethers.deployContract("RequestValidatorStub");
+ return { verifier, validator1, validator2 };
+ }
+
+ describe("Single request tests", function () {
+ beforeEach(async function () {
+ [sender] = await ethers.getSigners();
+ ({ verifier, validator1, validator2 } = await deployContractsFixture());
+
+ verifierId = await verifier.getVerifierID();
+
+ request = {
+ requestId: 1,
+ metadata: "0x",
+ validator: await validator1.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ multiRequest = {
+ multiRequestId: 1,
+ requestIds: [request.requestId],
+ groupIds: [],
+ metadata: "0x",
+ };
+ });
+
+ it("setRequests: should not exist when creating", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ let requestIdExists = await verifier.requestIdExists(request.requestId);
+ expect(requestIdExists).to.be.false;
+ let requestsCount = await verifier.getRequestsCount();
+ expect(requestsCount).to.be.equal(0);
+
+ await expect(verifier.setRequests([request])).not.to.be.rejected;
+ await expect(verifier.setRequests([request]))
+ .to.be.revertedWithCustomError(verifier, "RequestIdAlreadyExists")
+ .withArgs(request.requestId);
+
+ requestIdExists = await verifier.requestIdExists(request.requestId);
+ expect(requestIdExists).to.be.true;
+ requestsCount = await verifier.getRequestsCount();
+ expect(requestsCount).to.be.equal(1);
+ });
+
+ it("setRequests: nullifierSessionID may be not unique if EQUAL to 0", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await verifier.setRequests([request]);
+ request.requestId = 2;
+ await verifier.setRequests([request]);
+ });
+
+ it("setRequests: nullifierSessionID must be unique if NOT EQUAL to 0", async function () {
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 1 },
+ ];
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ await verifier.setRequests([request]);
+ request.requestId = 2;
+ await expect(verifier.setRequests([request]))
+ .to.be.revertedWithCustomError(verifier, "NullifierSessionIDAlreadyExists")
+ .withArgs(1);
+ });
+
+ it("setRequests: requestId should be valid", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+
+ request.requestId = BigInt(
+ "0x0002000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ ); // requestId without valid prefix 0x00000000000000_00 or 0x00000000000000_01 (eigth byte)
+
+ await expect(verifier.setRequests([request])).to.be.revertedWithCustomError(
+ verifier,
+ "RequestIdTypeNotValid",
+ );
+
+ request.requestId = BigInt(
+ "0x0000000001000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ ); // requestId uses reserved bytes (firt to seventh byte) 0x00000000000000
+ await expect(verifier.setRequests([request])).to.be.revertedWithCustomError(
+ verifier,
+ "RequestIdUsesReservedBytes",
+ );
+
+ request.requestId = BigInt(
+ "0x0001000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ ); // requestId idType is valid but calculation from hash params is not valid
+ await expect(verifier.setRequests([request])).to.be.revertedWithCustomError(
+ verifier,
+ "RequestIdNotValid",
+ );
+
+ request.requestId =
+ (BigInt(ethers.keccak256(request.params)) &
+ BigInt("0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")) +
+ BigInt("0x0001000000000000000000000000000000000000000000000000000000000000"); // requestId is valid;
+ await expect(verifier.setRequests([request])).not.to.be.rejected;
+ });
+
+ it("setRequests: a group should be formed by the groupID encoded in requests params", async function () {
+ const groupID = 1;
+ const groupRequest1 = { ...request, groupID };
+ const groupRequest2 = { ...request, requestId: 2, groupID };
+ paramsFromValidator = [
+ { name: "groupID", value: 1 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ await validator1.stub_setRequestParams([groupRequest1.params], [paramsFromValidator]);
+ await validator1.stub_setRequestParams([groupRequest2.params], [paramsFromValidator]);
+
+ let groupExists = await verifier.groupIdExists(groupID);
+ expect(groupExists).to.be.false;
+ let groupsCount = await verifier.getGroupsCount();
+ expect(groupsCount).to.be.equal(0);
+
+ await verifier.setRequests([groupRequest1, groupRequest2]);
+
+ groupExists = await verifier.groupIdExists(groupID);
+ expect(groupExists).to.be.true;
+ groupsCount = await verifier.getGroupsCount();
+ expect(groupsCount).to.be.equal(1);
+
+ const groupedRequests = await verifier.getGroupedRequests(groupID);
+ expect(groupedRequests.length).to.be.equal(2);
+ expect(groupedRequests[0].requestId).to.be.equal(groupRequest1.requestId);
+ expect(groupedRequests[1].requestId).to.be.equal(groupRequest2.requestId);
+ });
+
+ it("setRequests: a group should not exist previously", async function () {
+ const groupID = 1;
+ const groupRequest1 = { ...request, groupID };
+ const groupRequest2 = { ...request, requestId: 2, groupID };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 1 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ await validator1.stub_setRequestParams([groupRequest1.params], [paramsFromValidator]);
+ await validator1.stub_setRequestParams([groupRequest2.params], [paramsFromValidator]);
+
+ await verifier.setRequests([groupRequest1, groupRequest2]);
+
+ await expect(verifier.setRequests([groupRequest1, groupRequest2]))
+ .to.be.revertedWithCustomError(verifier, "GroupIdAlreadyExists")
+ .withArgs(groupID);
+ });
+
+ it("getRequest: requestId should exist", async function () {
+ await expect(verifier.getRequest(request.requestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(request.requestId);
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: verifierId },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+
+ const requestObject = await verifier.getRequest(request.requestId);
+
+ expect(requestObject.requestId).to.be.equal(request.requestId);
+ expect(requestObject.metadata).to.be.equal(request.metadata);
+ expect(requestObject.validator).to.be.equal(request.validator);
+ expect(requestObject.params).to.be.equal(request.params);
+ expect(requestObject.creator).to.be.equal(await signer.getAddress());
+ });
+
+ it("getRequestProofStatus: requestId should exist", async function () {
+ const nonExistingRequestId = 2;
+
+ await expect(verifier.getRequestProofStatus(signerAddress, nonExistingRequestId))
+ .to.be.revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(nonExistingRequestId);
+ });
+
+ it("getAuthMethod: authMethod should exist", async function () {
+ const authMethod2 = { ...authMethod, authMethod: "stubAuth2" };
+
+ await expect(verifier.getAuthMethod(authMethod2.authMethod))
+ .to.be.revertedWithCustomError(verifier, "AuthMethodNotFound")
+ .withArgs(authMethod2.authMethod);
+
+ await expect(verifier.setAuthMethod(authMethod))
+ .to.be.revertedWithCustomError(verifier, "AuthMethodAlreadyExists")
+ .withArgs(authMethod.authMethod);
+
+ await expect(verifier.setAuthMethod(authMethod2)).not.to.be.reverted;
+
+ const authMethodObject = await verifier.getAuthMethod(authMethod.authMethod);
+ expect(authMethodObject.validator).to.be.equal(authMethod2.validator);
+ expect(authMethodObject.params).to.be.equal(authMethod2.params);
+ });
+
+ it("enableAuthMethod/disableAuthMethod", async function () {
+ let authMethodObject = await verifier.getAuthMethod(authMethod.authMethod);
+ expect(authMethodObject.isActive).to.be.true;
+
+ await verifier.disableAuthMethod(authMethod.authMethod);
+
+ authMethodObject = await verifier.getAuthMethod(authMethod.authMethod);
+ expect(authMethodObject.isActive).to.be.false;
+
+ await verifier.enableAuthMethod(authMethod.authMethod);
+
+ authMethodObject = await verifier.getAuthMethod(authMethod.authMethod);
+ expect(authMethodObject.isActive).to.be.true;
+ });
+
+ it("submitResponse: not repeated responseFields from validator", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+ await validator1.stub_setVerifyResults([
+ {
+ name: "someFieldName1",
+ value: 1,
+ },
+ {
+ name: "someFieldName2",
+ value: 2,
+ },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response = {
+ requestId: request.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+
+ let isRequestProofVerified = await verifier.isRequestProofVerified(sender, request.requestId);
+ expect(isRequestProofVerified).to.be.false;
+
+ await verifier.submitResponse(authResponse, [response], crossChainProofs);
+
+ isRequestProofVerified = await verifier.isRequestProofVerified(sender, request.requestId);
+ expect(isRequestProofVerified).to.be.true;
+
+ const responseField1 = await verifier.getResponseFieldValue(
+ request.requestId,
+ sender,
+ "someFieldName1",
+ );
+ expect(responseField1).to.be.equal(1);
+ const resonseField2 = await verifier.getResponseFieldValue(
+ request.requestId,
+ sender,
+ "someFieldName2",
+ );
+ expect(resonseField2).to.be.equal(2);
+
+ const responseFields = await verifier.getResponseFields(request.requestId, sender);
+ expect(responseFields.length).to.be.equal(2);
+ expect(responseFields[0].name).to.be.equal("someFieldName1");
+ expect(responseFields[0].value).to.be.equal(1);
+ expect(responseFields[1].name).to.be.equal("someFieldName2");
+ expect(responseFields[1].value).to.be.equal(2);
+ });
+
+ it("submitResponse: should throw if repeated responseFields from validator", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+ await validator1.stub_setVerifyResults([
+ {
+ name: "someFieldName1",
+ value: 1,
+ },
+ {
+ name: "someFieldName1",
+ value: 1,
+ },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response = {
+ requestId: request.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+ await expect(verifier.submitResponse(authResponse, [response], crossChainProofs))
+ .to.revertedWithCustomError(verifier, "ResponseFieldAlreadyExists")
+ .withArgs("someFieldName1");
+ });
+
+ it("submitResponse: userID in response fields should match auth userID", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+
+ let userID = 1; // we assume that userID is hardcoded to 1 in the auth stub contract
+ await validator1.stub_setVerifyResults([
+ {
+ name: "userID",
+ value: userID,
+ },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response = {
+ requestId: request.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+
+ await verifier.submitResponse(authResponse, [response], crossChainProofs);
+
+ userID = 2;
+ await validator1.stub_setVerifyResults([
+ {
+ name: "userID",
+ value: userID,
+ },
+ ]);
+
+ await expect(verifier.submitResponse(authResponse, [response], crossChainProofs))
+ .to.revertedWithCustomError(verifier, "UserIDMismatch")
+ .withArgs(1, 2);
+ });
+ });
+
+ describe("Multi request tests", function () {
+ before(async function () {
+ [sender] = await ethers.getSigners();
+ ({ verifier, validator1, validator2 } = await deployContractsFixture());
+
+ request = {
+ requestId: 1,
+ metadata: "0x",
+ validator: await validator1.getAddress(),
+ params: "0x",
+ };
+
+ paramsFromValidator = [
+ { name: "groupID", value: 0 },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+
+ multiRequest = {
+ multiRequestId: 1,
+ requestIds: [request.requestId],
+ groupIds: [],
+ metadata: "0x",
+ };
+ });
+
+ it("setMultiRequest: should not exist when creating", async function () {
+ await validator1.stub_setRequestParams([request.params], [paramsFromValidator]);
+ await verifier.setRequests([request]);
+
+ let multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId);
+ expect(multiRequestIdExists).to.be.false;
+ await expect(verifier.setMultiRequest(multiRequest)).not.to.be.rejected;
+ await expect(verifier.setMultiRequest(multiRequest))
+ .revertedWithCustomError(verifier, "MultiRequestIdAlreadyExists")
+ .withArgs(multiRequest.multiRequestId);
+ multiRequestIdExists = await verifier.multiRequestIdExists(multiRequest.multiRequestId);
+ expect(multiRequestIdExists).to.be.true;
+ });
+
+ it("setMultiRequest: requestIds and groupIds should exist", async function () {
+ const multiRequest2 = {
+ multiRequestId: 2,
+ requestIds: [2],
+ groupIds: [],
+ metadata: "0x",
+ };
+
+ await expect(verifier.setMultiRequest(multiRequest2))
+ .revertedWithCustomError(verifier, "RequestIdNotFound")
+ .withArgs(multiRequest2.requestIds[0]);
+
+ const multiRequest3 = {
+ multiRequestId: 3,
+ requestIds: [],
+ groupIds: [2],
+ metadata: "0x",
+ };
+
+ await expect(verifier.setMultiRequest(multiRequest3))
+ .revertedWithCustomError(verifier, "GroupIdNotFound")
+ .withArgs(multiRequest3.groupIds[0]);
+ });
+
+ it("getMultiRequest: multiRequestId should exist", async function () {
+ const nonExistingMultiRequestId = 5;
+ await expect(verifier.getMultiRequest(nonExistingMultiRequestId))
+ .to.be.revertedWithCustomError(verifier, "MultiRequestIdNotFound")
+ .withArgs(nonExistingMultiRequestId);
+ const multiRequestObject = await verifier.getMultiRequest(multiRequest.multiRequestId);
+ expect(multiRequestObject.multiRequestId).to.be.equal(multiRequest.multiRequestId);
+ expect(multiRequestObject.metadata).to.be.equal(multiRequest.metadata);
+ expect(multiRequestObject.requestIds.length).to.be.equal(multiRequest.requestIds.length);
+ expect(multiRequestObject.groupIds.length).to.be.equal(multiRequest.groupIds.length);
+ });
+
+ it("setMultiRequest: check statuses of two different multiRequests pointing to the same requests", async function () {
+ const multiRequest2 = { ...multiRequest, multiRequestId: 2 };
+ await verifier.setMultiRequest(multiRequest2);
+
+ let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest.multiRequestId,
+ signerAddress,
+ );
+ expect(areMultiRequestProofsVerified).to.be.false;
+
+ let isMultiRequest2Verified = await verifier.areMultiRequestProofsVerified(
+ multiRequest2.multiRequestId,
+ signerAddress,
+ );
+ expect(isMultiRequest2Verified).to.be.false;
+
+ const userID = 1; // we assume that userID is hardcoded to 1 in the auth stub contract
+ await validator1.stub_setVerifyResults([
+ {
+ name: "userID",
+ value: userID,
+ },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response = {
+ requestId: request.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+
+ await verifier.submitResponse(authResponse, [response], crossChainProofs);
+
+ //check statuses of two different multiRequests pointing to the same requests after response
+ areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest.multiRequestId,
+ signerAddress,
+ );
+ expect(areMultiRequestProofsVerified).to.be.true;
+
+ isMultiRequest2Verified = await verifier.areMultiRequestProofsVerified(
+ multiRequest2.multiRequestId,
+ signerAddress,
+ );
+ expect(isMultiRequest2Verified).to.be.true;
+ });
+
+ it("getMultiRequestProofsStatus: multi request should exist", async function () {
+ const nonExistingMultiRequestId = 5;
+ await expect(verifier.getMultiRequestProofsStatus(nonExistingMultiRequestId, signerAddress))
+ .to.be.revertedWithCustomError(verifier, "MultiRequestIdNotFound")
+ .withArgs(nonExistingMultiRequestId);
+ await expect(verifier.getMultiRequestProofsStatus(multiRequest.multiRequestId, signerAddress))
+ .not.to.be.rejected;
+ });
+
+ it("getMultiRequestProofsStatus: linkID should be equal to all requests in a group, otherwise multiRequest pointing to it returns false", async function () {
+ const groupID = 1;
+ const groupRequest1 = { ...request, requestId: 5, groupID };
+ const groupRequest2 = {
+ ...request,
+ validator: await validator2.getAddress(),
+ requestId: 6,
+ groupID,
+ };
+ paramsFromValidator = [
+ { name: "groupID", value: groupID },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ await validator1.stub_setRequestParams([groupRequest1.params], [paramsFromValidator]);
+ await validator2.stub_setRequestParams([groupRequest2.params], [paramsFromValidator]);
+
+ await verifier.setRequests([groupRequest1, groupRequest2]);
+
+ const multiRequest3 = {
+ multiRequestId: 3,
+ requestIds: [],
+ groupIds: [groupID],
+ metadata: "0x",
+ };
+ await verifier.setMultiRequest(multiRequest3);
+
+ const userID = 1;
+ await validator1.stub_setVerifyResults([
+ { name: "userID", value: userID },
+ { name: "issuerID", value: 2 },
+ { name: "linkID", value: 3 },
+ ]);
+ await validator2.stub_setVerifyResults([
+ { name: "userID", value: userID },
+ { name: "issuerID", value: 2 },
+ { name: "linkID", value: 4 },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response1 = {
+ requestId: groupRequest1.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const response2 = {
+ requestId: groupRequest2.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+
+ await verifier.submitResponse(authResponse, [response1, response2], crossChainProofs);
+ await expect(
+ verifier.getMultiRequestProofsStatus(multiRequest3.multiRequestId, signerAddress),
+ ).to.be.revertedWithCustomError(verifier, "LinkIDNotTheSameForGroupedRequests");
+
+ const areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest3.multiRequestId,
+ signerAddress,
+ );
+ expect(areMultiRequestProofsVerified).to.be.false;
+ });
+
+ it("getMultiRequestProofsStatus: all request with same linkID in a group already verified returns true", async function () {
+ const groupID = 2;
+ const groupRequest1 = { ...request, requestId: 10, groupID };
+ const groupRequest2 = {
+ ...request,
+ requestId: 11,
+ groupID,
+ };
+ paramsFromValidator = [
+ { name: "groupID", value: groupID },
+ { name: "verifierID", value: 0 },
+ { name: "nullifierSessionID", value: 0 },
+ ];
+ await validator1.stub_setRequestParams([groupRequest1.params], [paramsFromValidator]);
+
+ await verifier.setRequests([groupRequest1, groupRequest2]);
+
+ const multiRequest4 = {
+ multiRequestId: 4,
+ requestIds: [],
+ groupIds: [groupID],
+ metadata: "0x",
+ };
+ await verifier.setMultiRequest(multiRequest4);
+
+ const userID = 1;
+ await validator1.stub_setVerifyResults([
+ { name: "userID", value: userID },
+ { name: "issuerID", value: 2 },
+ { name: "linkID", value: 3 },
+ ]);
+
+ const authResponse = {
+ authMethod: "stubAuth",
+ proof: "0x",
+ };
+ const response1 = {
+ requestId: groupRequest1.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const response2 = {
+ requestId: groupRequest2.requestId,
+ proof: "0x",
+ metadata: "0x",
+ };
+ const crossChainProofs = "0x";
+
+ // partial responses of the multiRequest group
+ await verifier.submitResponse(authResponse, [response1], crossChainProofs);
+
+ await expect(
+ verifier.getMultiRequestProofsStatus(multiRequest4.multiRequestId, signerAddress),
+ ).to.be.revertedWithCustomError(verifier, "LinkIDNotTheSameForGroupedRequests");
+
+ let areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest4.multiRequestId,
+ signerAddress,
+ );
+ expect(areMultiRequestProofsVerified).to.be.false;
+
+ // all responses of the multiRequest group completed
+ await verifier.submitResponse(authResponse, [response2], crossChainProofs);
+
+ await expect(
+ verifier.getMultiRequestProofsStatus(multiRequest4.multiRequestId, signerAddress),
+ ).not.to.be.rejected;
+
+ areMultiRequestProofsVerified = await verifier.areMultiRequestProofsVerified(
+ multiRequest4.multiRequestId,
+ signerAddress,
+ );
+ expect(areMultiRequestProofsVerified).to.be.true;
+ });
+ });
+});