"content":"//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport \"../interfaces/ISemaphoreCore.sol\";\nimport \"../interfaces/IVerifier.sol\";\n\n/// @title Semaphore core contract.\n/// @notice Minimal code to allow users to signal their endorsement of an arbitrary string.\n/// @dev The following code verifies that the proof is correct and saves the hash of the\n/// nullifier to prevent double-signaling. External nullifier and Merkle trees (i.e. groups) must be\n/// managed externally.\ncontract SemaphoreCore is ISemaphoreCore {\n /// @dev Gets a nullifier hash and returns true or false.\n /// It is used to prevent double-signaling.\n mapping(uint256 => bool) internal nullifierHashes;\n\n /// @dev Asserts that no nullifier already exists and if the zero-knowledge proof is valid.\n /// Otherwise it reverts.\n /// @param signal: Semaphore signal.\n /// @param root: Root of the Merkle tree.\n /// @param nullifierHash: Nullifier hash.\n /// @param externalNullifier: External nullifier.\n /// @param proof: Zero-knowledge proof.\n /// @param verifier: Verifier address.\n function _verifyProof(\n bytes32 signal,\n uint256 root,\n uint256 nullifierHash,\n uint256 externalNullifier,\n uint256[8] calldata proof,\n IVerifier verifier\n ) internal view {\n require(!nullifierHashes[nullifierHash], \"SemaphoreCore: you cannot use the same nullifier twice\");\n\n uint256 signalHash = _hashSignal(signal);\n\n verifier.verifyProof(\n [proof[0], proof[1]],\n [[proof[2], proof[3]], [proof[4], proof[5]]],\n [proof[6], proof[7]],\n [root, nullifierHash, signalHash, externalNullifier]\n );\n }\n\n /// @dev Stores the nullifier hash to prevent double-signaling.\n /// Attention! Remember to call it when you verify a proof if you\n /// need to prevent double-signaling.\n /// @param nullifierHash: Semaphore nullifier hash.\n function _saveNullifierHash(uint256 nullifierHash) internal {\n nullifierHashes[nullifierHash] = true;\n }\n\n /// @dev Creates a keccak256 hash of the signal.\n /// @param signal: Semaphore signal.\n /// @return Hash of the signal.\n function _hashSignal(bytes32 signal) private pure returns (uint256) {\n return uint256(keccak256(abi.encodePacked(signal))) >> 8;\n }\n}\n"
"content":"//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @title SemaphoreCore interface.\n/// @dev Interface of SemaphoreCore contract.\ninterface ISemaphoreCore {\n /// @notice Emitted when a proof is verified correctly and a new nullifier hash is added.\n /// @param nullifierHash: Hash of external and identity nullifiers.\n event NullifierHashAdded(uint256 nullifierHash);\n}\n"
"content":"//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @title Interep interface.\n/// @dev Interface of a Interep contract.\ninterface IInterep {\n struct Verifier {\n address contractAddress;\n uint8 merkleTreeDepth;\n }\n\n struct Group {\n bytes32 provider;\n bytes32 name;\n uint256 root;\n uint8 depth;\n }\n\n /// @dev Emitted when a Semaphore proof is verified.\n /// @param groupId: Id of the group.\n /// @param signal: Semaphore signal.\n event ProofVerified(uint256 indexed groupId, bytes32 signal);\n\n /// @dev Emitted when an Interep group is updated.\n /// @param groupId: Id of the group.\n /// @param provider: Provider of the group.\n /// @param name: Name of the group.\n /// @param root: Root hash of the tree.\n /// @param depth: Depth of the tree.\n event GroupUpdated(\n uint256 groupId,\n bytes32 indexed provider,\n bytes32 indexed name,\n uint256 root,\n uint8 indexed depth\n );\n\n /// @dev Updates the Interep groups.\n /// @param groups: List of Interep groups.\n function updateGroups(Group[] calldata groups) external;\n\n /// @dev Saves the nullifier hash to avoid double signaling and emits an event\n /// if the zero-knowledge proof is valid.\n /// @param groupId: Id of the group.\n /// @param signal: Semaphore signal.\n /// @param nullifierHash: Nullifier hash.\n /// @param externalNullifier: External nullifier.\n /// @param proof: Zero-knowledge proof.\n function verifyProof(\n uint256 groupId,\n bytes32 signal,\n uint256 nullifierHash,\n uint256 externalNullifier,\n uint256[8] calldata proof\n ) external;\n\n /// @dev Returns the root hash of an Interep group.\n /// @param groupId: Id of the group.\n /// @return Root hash of the group.\n function getRoot(uint256 groupId) external view returns (uint256);\n\n /// @dev Returns the tree depth of an Interep group.\n /// @param groupId: Id of the group.\n /// @return Tree depth of the group.\n function getDepth(uint256 groupId) external view returns (uint8);\n}\n"
},
"@interep/contracts/Interep.sol":{
"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport \"./IInterep.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@appliedzkp/semaphore-contracts/interfaces/IVerifier.sol\";\nimport \"@appliedzkp/semaphore-contracts/base/SemaphoreCore.sol\";\nimport \"@appliedzkp/semaphore-contracts/base/SemaphoreConstants.sol\";\n\n/// @title Interep\n/// @dev Interep is a collection of reputation Semaphore groups in which members\n/// can prove their Web2 reputation (or their membership in a group) without revealing their identity.\n/// Each Interep group is actually a Merkle tree, whose leaves represent the members of the group.\n/// Interep groups are saved off-chain but the Merkle tree roots of those groups are saved on-chain\n/// at regular intervals, so that users can verify their Semaphore ZK proof on-chain with this contract.\ncontract Interep is IInterep, Ownable, SemaphoreCore {\n /// @dev Gets a tree depth and returns its verifier address.\n mapping(uint8 => IVerifier) public verifiers;\n\n /// @dev Gets a group id and returns the group data.\n mapping(uint256 => Group) public groups;\n\n /// @dev Checks if there is a verifier for the given tree depth.\n /// @param depth: Depth of the tree.\n modifier onlySupportedDepth(uint8 depth) {\n require(address(verifiers[depth]) != address(0), \"Interep: tree depth is not supported\");\n _;\n }\n\n /// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.\n /// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).\n constructor(Verifier[] memory _verifiers) {\n for (uint8 i = 0; i < _verifiers.length; i++) {\n verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);\n }\n }\n\n /// @dev See {IInterep-updateGroups}.\n function updateGroups(Group[] calldata _groups) external override onlyOwner {\n for (uint8 i = 0; i < _groups.length; i++) {\n uint256 groupId = uint256(keccak256(abi.encodePacked(_groups[i].provider, _groups[i].name))) %\n SNARK_SCALAR_FIELD;\n\n _updateGroup(groupId, _groups[i]);\n }\n }\n\n /// @dev See {IInterep-verifyProof}.\n function verifyProof(\n uint256 groupId,\n bytes32 signal,\n uint256 nullifierHash,\n uint256 externalNullifier,\n uint256[8] calldata proof\n ) external override {\n uint256 root = getRoot(groupId);\n uint8 depth = getDepth(groupId);\n\n require(depth != 0, \"Interep: group does not exist\");\n\n IVerifier verifier = verifiers[depth];\n\n _verifyProof(signal, root, nullifierHash, externalNullifier, proof, verifier);\n\n _saveNullifierHash(nullifierHash);\n\n emit ProofVerified(groupId, signal);\n }\n\n /// @dev See {IInterep-getRoot}.\n function getRoot(uint256 groupId) public view override returns (uint256) {\n return groups[groupId].root;\n }\n\n /// @dev See {IInterep-getDepth}.\n function getDepth(uint256 groupId) public view override returns (uint8) {\n return groups[groupId].depth;\n }\n\n /// @dev Updates an Interep group.\n /// @param groupId: Id of the group.\n /// @param group: Group data.\n function _updateGroup(uint256 groupId, Group calldata group) private onlySupportedDepth(group.depth) {\n groups[groupId] = group;\n\n emit GroupUpdated(groupId, group.provider, group.name, group.root, group.depth);\n }\n}\n"
},
"@openzeppelin/contracts/access/Ownable.sol":{
"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"
},
"@openzeppelin/contracts/utils/Context.sol":{
"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"