Base Sepolia Testnet

Contract

0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Add Member373663182026-02-07 21:48:446 hrs ago1770500924IN
0x8A1fd199...AC83c693D
0 ETH0.000000170.00120044
Add Members373546812026-02-07 15:20:5013 hrs ago1770477650IN
0x8A1fd199...AC83c693D
0 ETH0.000000270.0012
Create Group373545702026-02-07 15:17:0813 hrs ago1770477428IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Add Members369308562026-01-28 19:53:2010 days ago1769630000IN
0x8A1fd199...AC83c693D
0 ETH0.000000270.0012
Create Group369308532026-01-28 19:53:1410 days ago1769629994IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Add Members369296072026-01-28 19:11:4210 days ago1769627502IN
0x8A1fd199...AC83c693D
0 ETH0.000000270.0012
Create Group369296042026-01-28 19:11:3610 days ago1769627496IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Add Members369294552026-01-28 19:06:3810 days ago1769627198IN
0x8A1fd199...AC83c693D
0 ETH0.000000270.0012
Create Group369294522026-01-28 19:06:3210 days ago1769627192IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Create Group369288332026-01-28 18:45:5410 days ago1769625954IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Create Group369287312026-01-28 18:42:3010 days ago1769625750IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.00117092
Create Group369285722026-01-28 18:37:1210 days ago1769625432IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.00120278
Create Group369282882026-01-28 18:27:4410 days ago1769624864IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Create Group369282372026-01-28 18:26:0210 days ago1769624762IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Create Group369275322026-01-28 18:02:3210 days ago1769623352IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Create Group369272592026-01-28 17:53:2610 days ago1769622806IN
0x8A1fd199...AC83c693D
0 ETH0.000000090.0012
Accept Group Adm...367307672026-01-24 4:43:4214 days ago1769229822IN
0x8A1fd199...AC83c693D
0 ETH0.000000030.00117
Accept Group Adm...367307332026-01-24 4:42:3414 days ago1769229754IN
0x8A1fd199...AC83c693D
0 ETH0.000000030.00117
Update Group Adm...367306982026-01-24 4:41:2414 days ago1769229684IN
0x8A1fd199...AC83c693D
0 ETH0.000000060.00117
Add Member367303582026-01-24 4:30:0414 days ago1769229004IN
0x8A1fd199...AC83c693D
0 ETH0.000000180.00117
Add Members367303442026-01-24 4:29:3614 days ago1769228976IN
0x8A1fd199...AC83c693D
0 ETH0.000000140.00117
Add Member366191922026-01-21 14:44:3217 days ago1769006672IN
0x8A1fd199...AC83c693D
0 ETH0.000000210.00117
Add Members366191712026-01-21 14:43:5017 days ago1769006630IN
0x8A1fd199...AC83c693D
0 ETH0.000000170.00117
Add Member366185372026-01-21 14:22:4217 days ago1769005362IN
0x8A1fd199...AC83c693D
0 ETH0.000000180.00117
Add Members366184962026-01-21 14:21:2017 days ago1769005280IN
0x8A1fd199...AC83c693D
0 ETH0.000000140.00117
View all transactions

Latest 1 internal transaction

Parent Transaction Hash Block From To Amount
305261952025-09-02 13:44:38158 days ago1756820678  Contract Creation0 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Semaphore

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

import {ISemaphore} from "./interfaces/ISemaphore.sol";
import {ISemaphoreVerifier} from "./interfaces/ISemaphoreVerifier.sol";
import {SemaphoreGroups} from "./base/SemaphoreGroups.sol";
import {MIN_DEPTH, MAX_DEPTH} from "./base/Constants.sol";

/// @title Semaphore
/// @dev This contract uses the Semaphore base contracts to provide a complete service
/// to allow admins to create and manage groups and their members to verify Semaphore proofs
/// Group admins can add, update or remove group members, and can be an Ethereum account or a smart contract.
/// This contract also assigns each new Merkle tree generated with a new root a duration (or an expiry)
/// within which the proofs generated with that root can be validated.
contract Semaphore is ISemaphore, SemaphoreGroups {
    ISemaphoreVerifier public verifier;

    /// @dev Gets a group id and returns the group parameters.
    mapping(uint256 => Group) public groups;

    /// @dev Counter to assign an incremental id to the groups.
    /// This counter is used to keep track of the number of groups created.
    uint256 public groupCounter;

    /// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
    /// @param _verifier: Semaphore verifier addresse.
    constructor(ISemaphoreVerifier _verifier) {
        verifier = _verifier;
    }

    /// @dev See {SemaphoreGroups-_createGroup}.
    function createGroup() external override returns (uint256 groupId) {
        groupId = groupCounter++;
        _createGroup(groupId, msg.sender);

        groups[groupId].merkleTreeDuration = 1 hours;
    }

    /// @dev See {SemaphoreGroups-_createGroup}.
    function createGroup(address admin) external override returns (uint256 groupId) {
        groupId = groupCounter++;
        _createGroup(groupId, admin);

        groups[groupId].merkleTreeDuration = 1 hours;
    }

    /// @dev See {ISemaphore-createGroup}.
    function createGroup(address admin, uint256 merkleTreeDuration) external override returns (uint256 groupId) {
        groupId = groupCounter++;
        _createGroup(groupId, admin);

        groups[groupId].merkleTreeDuration = merkleTreeDuration;
    }

    /// @dev See {SemaphoreGroups-_updateGroupAdmin}.
    function updateGroupAdmin(uint256 groupId, address newAdmin) external override {
        _updateGroupAdmin(groupId, newAdmin);
    }

    /// @dev See {SemaphoreGroups- acceptGroupAdmin}.
    function acceptGroupAdmin(uint256 groupId) external override {
        _acceptGroupAdmin(groupId);
    }

    /// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
    function updateGroupMerkleTreeDuration(
        uint256 groupId,
        uint256 newMerkleTreeDuration
    ) external override onlyGroupAdmin(groupId) {
        uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;

        groups[groupId].merkleTreeDuration = newMerkleTreeDuration;

        emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
    }

    /// @dev See {SemaphoreGroups-_addMember}.
    function addMember(uint256 groupId, uint256 identityCommitment) external override {
        uint256 merkleTreeRoot = _addMember(groupId, identityCommitment);

        groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
    }

    /// @dev See {SemaphoreGroups-_addMembers}.
    function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external override {
        uint256 merkleTreeRoot = _addMembers(groupId, identityCommitments);

        groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
    }

    /// @dev See {SemaphoreGroups-_updateMember}.
    function updateMember(
        uint256 groupId,
        uint256 identityCommitment,
        uint256 newIdentityCommitment,
        uint256[] calldata merkleProofSiblings
    ) external override {
        uint256 merkleTreeRoot = _updateMember(groupId, identityCommitment, newIdentityCommitment, merkleProofSiblings);

        groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
    }

    /// @dev See {SemaphoreGroups-_removeMember}.
    function removeMember(
        uint256 groupId,
        uint256 identityCommitment,
        uint256[] calldata merkleProofSiblings
    ) external override {
        uint256 merkleTreeRoot = _removeMember(groupId, identityCommitment, merkleProofSiblings);

        groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
    }

    /// @dev See {ISemaphore-validateProof}.
    function validateProof(uint256 groupId, SemaphoreProof calldata proof) external override {
        // The function will revert if the nullifier that is part of the proof,
        // was already used inside the group with id groupId.
        if (groups[groupId].nullifiers[proof.nullifier]) {
            revert Semaphore__YouAreUsingTheSameNullifierTwice();
        }

        // The function will revert if the proof is not verified successfully.
        if (!verifyProof(groupId, proof)) {
            revert Semaphore__InvalidProof();
        }

        // Saves the nullifier so that it cannot be used again to successfully verify a proof
        // that is part of the group with id groupId.
        groups[groupId].nullifiers[proof.nullifier] = true;

        emit ProofValidated(
            groupId,
            proof.merkleTreeDepth,
            proof.merkleTreeRoot,
            proof.nullifier,
            proof.message,
            proof.scope,
            proof.points
        );
    }

    /// @dev See {ISemaphore-verifyProof}.
    function verifyProof(
        uint256 groupId,
        SemaphoreProof calldata proof
    ) public view override onlyExistingGroup(groupId) returns (bool) {
        // The function will revert if the Merkle tree depth is not supported.
        if (proof.merkleTreeDepth < MIN_DEPTH || proof.merkleTreeDepth > MAX_DEPTH) {
            revert Semaphore__MerkleTreeDepthIsNotSupported();
        }

        // Gets the number of leaves in the Incremental Merkle Tree that represents the group
        // with id groupId which is the same as the number of members in the group groupId.
        uint256 merkleTreeSize = getMerkleTreeSize(groupId);

        // The function will revert if there are no members in the group.
        if (merkleTreeSize == 0) {
            revert Semaphore__GroupHasNoMembers();
        }

        // Gets the Merkle root of the Incremental Merkle Tree that represents the group with id groupId.
        uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);

        // A proof could have used an old Merkle tree root.
        // https://github.com/semaphore-protocol/semaphore/issues/98
        if (proof.merkleTreeRoot != currentMerkleTreeRoot) {
            uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[proof.merkleTreeRoot];
            uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;

            if (merkleRootCreationDate == 0) {
                revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
            }

            if (block.timestamp > merkleRootCreationDate + merkleTreeDuration) {
                revert Semaphore__MerkleTreeRootIsExpired();
            }
        }

        return
            verifier.verifyProof(
                [proof.points[0], proof.points[1]],
                [[proof.points[2], proof.points[3]], [proof.points[4], proof.points[5]]],
                [proof.points[6], proof.points[7]],
                [proof.merkleTreeRoot, proof.nullifier, _hash(proof.message), _hash(proof.scope)],
                proof.merkleTreeDepth
            );
    }

    /// @dev Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
    /// @param message: Message to be hashed.
    /// @return Message digest.
    function _hash(uint256 message) private pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(message))) >> 8;
    }
}

File 2 of 9 : Constants.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {PoseidonT3} from "poseidon-solidity/PoseidonT3.sol";
import {SNARK_SCALAR_FIELD} from "./Constants.sol";

struct LeanIMTData {
    // Tracks the current number of leaves in the tree.
    uint256 size;
    // Represents the current depth of the tree, which can increase as new leaves are inserted.
    uint256 depth;
    // A mapping from each level of the tree to the node value of the last even position at that level.
    // Used for efficient inserts, updates and root calculations.
    mapping(uint256 => uint256) sideNodes;
    // A mapping from leaf values to their respective indices in the tree.
    // This facilitates checks for leaf existence and retrieval of leaf positions.
    mapping(uint256 => uint256) leaves;
}

error WrongSiblingNodes();
error LeafGreaterThanSnarkScalarField();
error LeafCannotBeZero();
error LeafAlreadyExists();
error LeafDoesNotExist();

/// @title Lean Incremental binary Merkle tree.
/// @dev The LeanIMT is an optimized version of the BinaryIMT.
/// This implementation eliminates the use of zeroes, and make the tree depth dynamic.
/// When a node doesn't have the right child, instead of using a zero hash as in the BinaryIMT,
/// the node's value becomes that of its left child. Furthermore, rather than utilizing a static tree depth,
/// it is updated based on the number of leaves in the tree. This approach
/// results in the calculation of significantly fewer hashes, making the tree more efficient.
library InternalLeanIMT {
    /// @dev Inserts a new leaf into the incremental merkle tree.
    /// The function ensures that the leaf is valid according to the
    /// constraints of the tree and then updates the tree's structure accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the new leaf to be inserted into the tree.
    /// @return The new hash of the node after the leaf has been inserted.
    function _insert(LeanIMTData storage self, uint256 leaf) internal returns (uint256) {
        if (leaf >= SNARK_SCALAR_FIELD) {
            revert LeafGreaterThanSnarkScalarField();
        } else if (leaf == 0) {
            revert LeafCannotBeZero();
        } else if (_has(self, leaf)) {
            revert LeafAlreadyExists();
        }

        uint256 index = self.size;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        // A new insertion can increase a tree's depth by at most 1,
        // and only if the number of leaves supported by the current
        // depth is less than the number of leaves to be supported after insertion.
        if (2 ** treeDepth < index + 1) {
            ++treeDepth;
        }

        self.depth = treeDepth;

        uint256 node = leaf;

        for (uint256 level = 0; level < treeDepth; ) {
            if ((index >> level) & 1 == 1) {
                node = PoseidonT3.hash([self.sideNodes[level], node]);
            } else {
                self.sideNodes[level] = node;
            }

            unchecked {
                ++level;
            }
        }

        self.size = ++index;

        self.sideNodes[treeDepth] = node;
        self.leaves[leaf] = index;

        return node;
    }

    /// @dev Inserts many leaves into the incremental merkle tree.
    /// The function ensures that the leaves are valid according to the
    /// constraints of the tree and then updates the tree's structure accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaves: The values of the new leaves to be inserted into the tree.
    /// @return The root after the leaves have been inserted.
    function _insertMany(LeanIMTData storage self, uint256[] calldata leaves) internal returns (uint256) {
        // Cache tree size to optimize gas
        uint256 treeSize = self.size;

        // Check that all the new values are correct to be added.
        for (uint256 i = 0; i < leaves.length; ) {
            if (leaves[i] >= SNARK_SCALAR_FIELD) {
                revert LeafGreaterThanSnarkScalarField();
            } else if (leaves[i] == 0) {
                revert LeafCannotBeZero();
            } else if (_has(self, leaves[i])) {
                revert LeafAlreadyExists();
            }

            self.leaves[leaves[i]] = treeSize + 1 + i;

            unchecked {
                ++i;
            }
        }

        // Array to save the nodes that will be used to create the next level of the tree.
        uint256[] memory currentLevelNewNodes;

        currentLevelNewNodes = leaves;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        // Calculate the depth of the tree after adding the new values.
        // Unlike the 'insert' function, we need a while here as
        // N insertions can increase the tree's depth more than once.
        while (2 ** treeDepth < treeSize + leaves.length) {
            ++treeDepth;
        }

        self.depth = treeDepth;

        // First index to change in every level.
        uint256 currentLevelStartIndex = treeSize;

        // Size of the level used to create the next level.
        uint256 currentLevelSize = treeSize + leaves.length;

        // The index where changes begin at the next level.
        uint256 nextLevelStartIndex = currentLevelStartIndex >> 1;

        // The size of the next level.
        uint256 nextLevelSize = ((currentLevelSize - 1) >> 1) + 1;

        for (uint256 level = 0; level < treeDepth; ) {
            // The number of nodes for the new level that will be created,
            // only the new values, not the entire level.
            uint256 numberOfNewNodes = nextLevelSize - nextLevelStartIndex;
            uint256[] memory nextLevelNewNodes = new uint256[](numberOfNewNodes);
            for (uint256 i = 0; i < numberOfNewNodes; ) {
                uint256 leftNode;

                // Assign the left node using the saved path or the position in the array.
                if ((i + nextLevelStartIndex) * 2 < currentLevelStartIndex) {
                    leftNode = self.sideNodes[level];
                } else {
                    leftNode = currentLevelNewNodes[(i + nextLevelStartIndex) * 2 - currentLevelStartIndex];
                }

                uint256 rightNode;

                // Assign the right node if the value exists.
                if ((i + nextLevelStartIndex) * 2 + 1 < currentLevelSize) {
                    rightNode = currentLevelNewNodes[(i + nextLevelStartIndex) * 2 + 1 - currentLevelStartIndex];
                }

                uint256 parentNode;

                // Assign the parent node.
                // If it has a right child the result will be the hash(leftNode, rightNode) if not,
                // it will be the leftNode.
                if (rightNode != 0) {
                    parentNode = PoseidonT3.hash([leftNode, rightNode]);
                } else {
                    parentNode = leftNode;
                }

                nextLevelNewNodes[i] = parentNode;

                unchecked {
                    ++i;
                }
            }

            // Update the `sideNodes` variable.
            // If `currentLevelSize` is odd, the saved value will be the last value of the array
            // if it is even and there are more than 1 element in `currentLevelNewNodes`, the saved value
            // will be the value before the last one.
            // If it is even and there is only one element, there is no need to save anything because
            // the correct value for this level was already saved before.
            if (currentLevelSize & 1 == 1) {
                self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 1];
            } else if (currentLevelNewNodes.length > 1) {
                self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 2];
            }

            currentLevelStartIndex = nextLevelStartIndex;

            // Calculate the next level startIndex value.
            // It is the position of the parent node which is pos/2.
            nextLevelStartIndex >>= 1;

            // Update the next array that will be used to calculate the next level.
            currentLevelNewNodes = nextLevelNewNodes;

            currentLevelSize = nextLevelSize;

            // Calculate the size of the next level.
            // The size of the next level is (currentLevelSize - 1) / 2 + 1.
            nextLevelSize = ((nextLevelSize - 1) >> 1) + 1;

            unchecked {
                ++level;
            }
        }

        // Update tree size
        self.size = treeSize + leaves.length;

        // Update tree root
        self.sideNodes[treeDepth] = currentLevelNewNodes[0];

        return currentLevelNewNodes[0];
    }

    /// @dev Updates the value of an existing leaf and recalculates hashes
    /// to maintain tree integrity.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param oldLeaf: The value of the leaf that is to be updated.
    /// @param newLeaf: The new value that will replace the oldLeaf in the tree.
    /// @param siblingNodes: An array of sibling nodes that are necessary to recalculate the path to the root.
    /// @return The new hash of the updated node after the leaf has been updated.
    function _update(
        LeanIMTData storage self,
        uint256 oldLeaf,
        uint256 newLeaf,
        uint256[] calldata siblingNodes
    ) internal returns (uint256) {
        if (newLeaf >= SNARK_SCALAR_FIELD) {
            revert LeafGreaterThanSnarkScalarField();
        } else if (!_has(self, oldLeaf)) {
            revert LeafDoesNotExist();
        } else if (_has(self, newLeaf)) {
            revert LeafAlreadyExists();
        }

        uint256 index = _indexOf(self, oldLeaf);
        uint256 node = newLeaf;
        uint256 oldRoot = oldLeaf;

        uint256 lastIndex = self.size - 1;
        uint256 i = 0;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        for (uint256 level = 0; level < treeDepth; ) {
            if ((index >> level) & 1 == 1) {
                if (siblingNodes[i] >= SNARK_SCALAR_FIELD) {
                    revert LeafGreaterThanSnarkScalarField();
                }

                node = PoseidonT3.hash([siblingNodes[i], node]);
                oldRoot = PoseidonT3.hash([siblingNodes[i], oldRoot]);

                unchecked {
                    ++i;
                }
            } else {
                if (index >> level != lastIndex >> level) {
                    if (siblingNodes[i] >= SNARK_SCALAR_FIELD) {
                        revert LeafGreaterThanSnarkScalarField();
                    }

                    if (self.sideNodes[level] == oldRoot) {
                        self.sideNodes[level] = node;
                    }

                    node = PoseidonT3.hash([node, siblingNodes[i]]);
                    oldRoot = PoseidonT3.hash([oldRoot, siblingNodes[i]]);

                    unchecked {
                        ++i;
                    }
                } else {
                    self.sideNodes[level] = node;
                }
            }

            unchecked {
                ++level;
            }
        }

        if (oldRoot != _root(self)) {
            revert WrongSiblingNodes();
        }

        self.sideNodes[treeDepth] = node;

        if (newLeaf != 0) {
            self.leaves[newLeaf] = self.leaves[oldLeaf];
        }

        self.leaves[oldLeaf] = 0;

        return node;
    }

    /// @dev Removes a leaf from the tree by setting its value to zero.
    /// This function utilizes the update function to set the leaf's value
    /// to zero and update the tree's state accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param oldLeaf: The value of the leaf to be removed.
    /// @param siblingNodes: An array of sibling nodes required for updating the path to the root after removal.
    /// @return The new root hash of the tree after the leaf has been removed.
    function _remove(
        LeanIMTData storage self,
        uint256 oldLeaf,
        uint256[] calldata siblingNodes
    ) internal returns (uint256) {
        return _update(self, oldLeaf, 0, siblingNodes);
    }

    /// @dev Checks if a leaf exists in the tree.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the leaf to check for existence.
    /// @return A boolean value indicating whether the leaf exists in the tree.
    function _has(LeanIMTData storage self, uint256 leaf) internal view returns (bool) {
        return self.leaves[leaf] != 0;
    }

    /// @dev Retrieves the index of a given leaf in the tree.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the leaf whose index is to be found.
    /// @return The index of the specified leaf within the tree. If the leaf is not present, the function
    /// reverts with a custom error.
    function _indexOf(LeanIMTData storage self, uint256 leaf) internal view returns (uint256) {
        if (self.leaves[leaf] == 0) {
            revert LeafDoesNotExist();
        }

        return self.leaves[leaf] - 1;
    }

    /// @dev Retrieves the root of the tree from the 'sideNodes' mapping using the
    /// current tree depth.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @return The root hash of the tree.
    function _root(LeanIMTData storage self) internal view returns (uint256) {
        return self.sideNodes[self.depth];
    }
}

File 4 of 9 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

/// @dev Minimum supported tree depth.
uint8 constant MIN_DEPTH = 1;

/// @dev Maximum supported tree depth.
uint8 constant MAX_DEPTH = 32;

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

import {ISemaphoreGroups} from "../interfaces/ISemaphoreGroups.sol";
import {InternalLeanIMT, LeanIMTData} from "@zk-kit/lean-imt.sol/InternalLeanIMT.sol";

/// @title Semaphore groups contract.
/// @dev This contract allows you to create groups, add, remove and update members.
/// You can use getters to obtain informations about groups (root, depth, number of leaves).
abstract contract SemaphoreGroups is ISemaphoreGroups {
    using InternalLeanIMT for LeanIMTData;

    /// @dev Gets a group id and returns its tree data.
    /// The tree is an Incremental Merkle Tree
    /// which is called Lean Incremental Merkle Tree.
    mapping(uint256 => LeanIMTData) internal merkleTrees;

    /// @dev Gets a group id and returns its admin.
    /// The admin can be an Ethereum account or a smart contract.
    mapping(uint256 => address) internal admins;

    /// @dev Gets a group id and returns any pending admin.
    /// The pending admin can be an Ethereum account or a smart contract.
    mapping(uint256 => address) internal pendingAdmins;

    /// @dev Checks if the group admin is the transaction sender.
    /// @param groupId: Id of the group.
    modifier onlyGroupAdmin(uint256 groupId) {
        if (admins[groupId] != msg.sender) {
            revert Semaphore__CallerIsNotTheGroupAdmin();
        }
        _;
    }

    /// @dev Checks if the group exists.
    /// @param groupId: Id of the group.
    modifier onlyExistingGroup(uint256 groupId) {
        if (admins[groupId] == address(0)) {
            revert Semaphore__GroupDoesNotExist();
        }

        _;
    }

    /// @dev Creates a new group. Only the admin will be able to add or remove members.
    /// @param groupId: Id of the group.
    /// @param admin: Admin of the group.
    function _createGroup(uint256 groupId, address admin) internal virtual {
        admins[groupId] = admin;

        emit GroupCreated(groupId);
        emit GroupAdminUpdated(groupId, address(0), admin);
    }

    /// @dev Updates the group admin. In order for the new admin to actually be updated,
    /// they must explicitly accept by calling `_acceptGroupAdmin`.
    /// @param groupId: Id of the group.
    /// @param newAdmin: New admin of the group.
    function _updateGroupAdmin(uint256 groupId, address newAdmin) internal virtual onlyGroupAdmin(groupId) {
        pendingAdmins[groupId] = newAdmin;

        emit GroupAdminPending(groupId, msg.sender, newAdmin);
    }

    /// @dev Allows the new admin to accept to update the group admin with their address.
    /// @param groupId: Id of the group.
    function _acceptGroupAdmin(uint256 groupId) internal virtual {
        if (pendingAdmins[groupId] != msg.sender) {
            revert Semaphore__CallerIsNotThePendingGroupAdmin();
        }

        address oldAdmin = admins[groupId];

        admins[groupId] = msg.sender;

        delete pendingAdmins[groupId];

        emit GroupAdminUpdated(groupId, oldAdmin, msg.sender);
    }

    /// @dev Adds an identity commitment to an existing group.
    /// @param groupId: Id of the group.
    /// @param identityCommitment: New identity commitment.
    /// @return merkleTreeRoot New root hash of the tree.
    function _addMember(
        uint256 groupId,
        uint256 identityCommitment
    ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
        uint256 index = getMerkleTreeSize(groupId);
        merkleTreeRoot = merkleTrees[groupId]._insert(identityCommitment);

        emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
    }

    /// @dev Adds new members to an existing group.
    /// @param groupId: Id of the group.
    /// @param identityCommitments: New identity commitments.
    /// @return merkleTreeRoot New root hash of the tree.
    function _addMembers(
        uint256 groupId,
        uint256[] calldata identityCommitments
    ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
        uint256 startIndex = getMerkleTreeSize(groupId);
        merkleTreeRoot = merkleTrees[groupId]._insertMany(identityCommitments);

        emit MembersAdded(groupId, startIndex, identityCommitments, merkleTreeRoot);
    }

    /// @dev Updates an identity commitment of an existing group. A proof of membership is
    /// needed to check if the node to be updated is part of the tree.
    /// @param groupId: Id of the group.
    /// @param oldIdentityCommitment: Existing identity commitment to be updated.
    /// @param newIdentityCommitment: New identity commitment.
    /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
    /// @return merkleTreeRoot New root hash of the tree.
    function _updateMember(
        uint256 groupId,
        uint256 oldIdentityCommitment,
        uint256 newIdentityCommitment,
        uint256[] calldata merkleProofSiblings
    ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
        uint256 index = merkleTrees[groupId]._indexOf(oldIdentityCommitment);
        merkleTreeRoot = merkleTrees[groupId]._update(
            oldIdentityCommitment,
            newIdentityCommitment,
            merkleProofSiblings
        );

        emit MemberUpdated(groupId, index, oldIdentityCommitment, newIdentityCommitment, merkleTreeRoot);
    }

    /// @dev Removes an identity commitment from an existing group. A proof of membership is
    /// needed to check if the node to be deleted is part of the tree.
    /// @param groupId: Id of the group.
    /// @param identityCommitment: Existing identity commitment to be removed.
    /// @param merkleProofSiblings: Array of the sibling nodes of the proof of membership.
    /// @return merkleTreeRoot New root hash of the tree.
    function _removeMember(
        uint256 groupId,
        uint256 identityCommitment,
        uint256[] calldata merkleProofSiblings
    ) internal virtual onlyGroupAdmin(groupId) returns (uint256 merkleTreeRoot) {
        uint256 index = merkleTrees[groupId]._indexOf(identityCommitment);

        merkleTreeRoot = merkleTrees[groupId]._remove(identityCommitment, merkleProofSiblings);

        emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
    }

    /// @dev See {ISemaphoreGroups-getGroupAdmin}.
    function getGroupAdmin(uint256 groupId) public view virtual override returns (address) {
        return admins[groupId];
    }

    /// @dev See {ISemaphoreGroups-hasMember}.
    function hasMember(uint256 groupId, uint256 identityCommitment) public view virtual override returns (bool) {
        return merkleTrees[groupId]._has(identityCommitment);
    }

    /// @dev See {ISemaphoreGroups-indexOf}.
    function indexOf(uint256 groupId, uint256 identityCommitment) public view virtual override returns (uint256) {
        return merkleTrees[groupId]._indexOf(identityCommitment);
    }

    /// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
    function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
        return merkleTrees[groupId]._root();
    }

    /// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
    function getMerkleTreeDepth(uint256 groupId) public view virtual override returns (uint256) {
        return merkleTrees[groupId].depth;
    }

    /// @dev See {ISemaphoreGroups-getMerkleTreeSize}.
    function getMerkleTreeSize(uint256 groupId) public view virtual override returns (uint256) {
        return merkleTrees[groupId].size;
    }
}

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

/// @title Semaphore contract interface.
interface ISemaphore {
    error Semaphore__GroupHasNoMembers();
    error Semaphore__MerkleTreeDepthIsNotSupported();
    error Semaphore__MerkleTreeRootIsExpired();
    error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
    error Semaphore__YouAreUsingTheSameNullifierTwice();
    error Semaphore__InvalidProof();

    /// It defines all the group parameters used by Semaphore.sol.
    struct Group {
        uint256 merkleTreeDuration;
        mapping(uint256 => uint256) merkleRootCreationDates;
        mapping(uint256 => bool) nullifiers;
    }

    /// It defines all the Semaphore proof parameters used by Semaphore.sol.
    struct SemaphoreProof {
        uint256 merkleTreeDepth;
        uint256 merkleTreeRoot;
        uint256 nullifier;
        uint256 message;
        uint256 scope;
        uint256[8] points;
    }

    /// @dev Event emitted when the Merkle tree duration of a group is updated.
    /// @param groupId: Id of the group.
    /// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
    /// @param newMerkleTreeDuration: New Merkle tree duration of the group.
    event GroupMerkleTreeDurationUpdated(
        uint256 indexed groupId,
        uint256 oldMerkleTreeDuration,
        uint256 newMerkleTreeDuration
    );

    /// @dev Event emitted when a Semaphore proof is validated.
    /// @param groupId: Id of the group.
    /// @param merkleTreeDepth: Depth of the Merkle tree.
    /// @param merkleTreeRoot: Root of the Merkle tree.
    /// @param nullifier: Nullifier.
    /// @param message: Semaphore message.
    /// @param scope: Scope.
    /// @param points: Zero-knowledge points.
    event ProofValidated(
        uint256 indexed groupId,
        uint256 merkleTreeDepth,
        uint256 indexed merkleTreeRoot,
        uint256 nullifier,
        uint256 message,
        uint256 indexed scope,
        uint256[8] points
    );

    /// @dev Returns the current value of the group counter.
    /// @return The current group counter value.
    function groupCounter() external view returns (uint256);

    /// @dev See {SemaphoreGroups-_createGroup}.
    function createGroup() external returns (uint256);

    /// @dev See {SemaphoreGroups-_createGroup}.
    function createGroup(address admin) external returns (uint256);

    /// @dev It creates a group with a custom Merkle tree duration.
    /// @param admin: Admin of the group. It can be an Ethereum account or a smart contract.
    /// @param merkleTreeDuration: Merkle tree duration.
    /// @return Id of the group.
    function createGroup(address admin, uint256 merkleTreeDuration) external returns (uint256);

    /// @dev See {SemaphoreGroups-_updateGroupAdmin}.
    function updateGroupAdmin(uint256 groupId, address newAdmin) external;

    /// @dev See {SemaphoreGroups-_acceptGroupAdmin}.
    function acceptGroupAdmin(uint256 groupId) external;

    /// @dev Updates the group Merkle tree duration.
    /// @param groupId: Id of the group.
    /// @param newMerkleTreeDuration: New Merkle tree duration.
    function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;

    /// @dev See {SemaphoreGroups-_addMember}.
    function addMember(uint256 groupId, uint256 identityCommitment) external;

    /// @dev See {SemaphoreGroups-_addMembers}.
    function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external;

    /// @dev See {SemaphoreGroups-_updateMember}.
    function updateMember(
        uint256 groupId,
        uint256 oldIdentityCommitment,
        uint256 newIdentityCommitment,
        uint256[] calldata merkleProofSiblings
    ) external;

    /// @dev See {SemaphoreGroups-_removeMember}.
    function removeMember(uint256 groupId, uint256 identityCommitment, uint256[] calldata merkleProofSiblings) external;

    /// @dev Saves the nullifier hash to prevent double signaling and emits an event
    /// if the zero-knowledge proof is valid.
    /// @param groupId: Id of the group.
    /// @param proof: Semaphore zero-knowledge proof.
    function validateProof(uint256 groupId, SemaphoreProof calldata proof) external;

    /// @dev Verifies a zero-knowledge proof by returning true or false.
    /// @param groupId: Id of the group.
    /// @param proof: Semaphore zero-knowledge proof.
    function verifyProof(uint256 groupId, SemaphoreProof calldata proof) external view returns (bool);
}

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

/// @title SemaphoreGroups contract interface.
interface ISemaphoreGroups {
    error Semaphore__GroupDoesNotExist();
    error Semaphore__CallerIsNotTheGroupAdmin();
    error Semaphore__CallerIsNotThePendingGroupAdmin();

    /// @dev Event emitted when a new group is created.
    /// @param groupId: Id of the group.
    event GroupCreated(uint256 indexed groupId);

    /// @dev Event emitted when a new admin is assigned to a group.
    /// @param groupId: Id of the group.
    /// @param oldAdmin: Old admin of the group.
    /// @param newAdmin: New admin of the group.
    event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);

    /// @dev Event emitted when a group admin is being updated.
    /// @param groupId: Id of the group.
    /// @param oldAdmin: Old admin of the group.
    /// @param newAdmin: New admin of the group.
    event GroupAdminPending(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);

    /// @dev Event emitted when a new identity commitment is added.
    /// @param groupId: Group id of the group.
    /// @param index: Merkle tree leaf index.
    /// @param identityCommitment: New identity commitment.
    /// @param merkleTreeRoot: New root hash of the tree.
    event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);

    /// @dev Event emitted when many identity commitments are added at the same time.
    /// @param groupId: Group id of the group.
    /// @param startIndex: Index of the first element of the new identity commitments in the merkle tree.
    /// @param identityCommitments: The new identity commitments.
    /// @param merkleTreeRoot: New root hash of the tree.
    event MembersAdded(
        uint256 indexed groupId,
        uint256 startIndex,
        uint256[] identityCommitments,
        uint256 merkleTreeRoot
    );

    /// @dev Event emitted when an identity commitment is updated.
    /// @param groupId: Group id of the group.
    /// @param index: Identity commitment index.
    /// @param identityCommitment: Existing identity commitment to be updated.
    /// @param newIdentityCommitment: New identity commitment.
    /// @param merkleTreeRoot: New root hash of the tree.
    event MemberUpdated(
        uint256 indexed groupId,
        uint256 index,
        uint256 identityCommitment,
        uint256 newIdentityCommitment,
        uint256 merkleTreeRoot
    );

    /// @dev Event emitted when a new identity commitment is removed.
    /// @param groupId: Group id of the group.
    /// @param index: Identity commitment index.
    /// @param identityCommitment: Existing identity commitment to be removed.
    /// @param merkleTreeRoot: New root hash of the tree.
    event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);

    /// @dev Returns the address of the group admin. The group admin can be an Ethereum account or a smart contract.
    /// @param groupId: Id of the group.
    /// @return Address of the group admin.
    function getGroupAdmin(uint256 groupId) external view returns (address);

    /// @dev Returns true if a member exists in a group.
    /// @param groupId: Id of the group.
    /// @param identityCommitment: Identity commitment.
    /// @return True if the member exists, false otherwise.
    function hasMember(uint256 groupId, uint256 identityCommitment) external view returns (bool);

    /// @dev Returns the index of a member.
    /// @param groupId: Id of the group.
    /// @param identityCommitment: Identity commitment.
    /// @return Index of member.
    function indexOf(uint256 groupId, uint256 identityCommitment) external view returns (uint256);

    /// @dev Returns the last root hash of a group.
    /// @param groupId: Id of the group.
    /// @return Root hash of the group.
    function getMerkleTreeRoot(uint256 groupId) external view returns (uint256);

    /// @dev Returns the depth of the tree of a group.
    /// @param groupId: Id of the group.
    /// @return Depth of the group tree.
    function getMerkleTreeDepth(uint256 groupId) external view returns (uint256);

    /// @dev Returns the number of tree leaves of a group.
    /// @param groupId: Id of the group.
    /// @return Number of tree leaves.
    function getMerkleTreeSize(uint256 groupId) external view returns (uint256);
}

File 8 of 9 : ISemaphoreVerifier.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.23 <0.9.0;

/// @title SemaphoreVerifier contract interface.
interface ISemaphoreVerifier {
    /// @dev Returns true if the proof was successfully verified.
    /// @param _pA: Point A.
    /// @param _pB: Point B.
    /// @param _pC: Point C.
    /// @param _pubSignals: Public signals.
    /// @param merkleTreeDepth: Merkle tree depth.
    /// @return True if the proof was successfully verified, false otherwise.
    function verifyProof(
        uint[2] calldata _pA,
        uint[2][2] calldata _pB,
        uint[2] calldata _pC,
        uint[4] calldata _pubSignals,
        uint merkleTreeDepth
    ) external view returns (bool);
}

/// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;

library PoseidonT3 {
  uint constant M00 = 0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b;
  uint constant M01 = 0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771;
  uint constant M02 = 0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7;
  uint constant M10 = 0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0;
  uint constant M11 = 0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23;
  uint constant M12 = 0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911;

  // See here for a simplified implementation: https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol#L40
  // Inspired by: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js
  function hash(uint[2] memory) public pure returns (uint) {
    assembly {
      let F := 21888242871839275222246405745257275088548364400416034343698204186575808495617
      let M20 := 0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d
      let M21 := 0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa
      let M22 := 0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0

      // load the inputs from memory
      let state1 := add(mod(mload(0x80), F), 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864)
      let state2 := add(mod(mload(0xa0), F), 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5)
      let scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(
        0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0,
        add(add(15452833169820924772166449970675545095234312153403844297388521437673434406763, mulmod(state1, M10, F)), mulmod(state2, M20, F))
      )
      let scratch1 := add(
        0x2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf2,
        add(add(18674271267752038776579386132900109523609358935013267566297499497165104279117, mulmod(state1, M11, F)), mulmod(state2, M21, F))
      )
      let scratch2 := add(
        0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa,
        add(add(14817777843080276494683266178512808687156649753153012854386334860566696099579, mulmod(state1, M12, F)), mulmod(state2, M22, F))
      )
      let state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(0x15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(0x0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)

      mstore(0x0, mod(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), F))

      return(0, 0x20)
    }
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/Semaphore.sol": {
      "PoseidonT3": "0xb43122ecb241dd50062641f089876679fd06599a"
    }
  }
}

Contract ABI

API
[{"inputs":[{"internalType":"contract ISemaphoreVerifier","name":"_verifier","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LeafAlreadyExists","type":"error"},{"inputs":[],"name":"LeafCannotBeZero","type":"error"},{"inputs":[],"name":"LeafDoesNotExist","type":"error"},{"inputs":[],"name":"LeafGreaterThanSnarkScalarField","type":"error"},{"inputs":[],"name":"Semaphore__CallerIsNotTheGroupAdmin","type":"error"},{"inputs":[],"name":"Semaphore__CallerIsNotThePendingGroupAdmin","type":"error"},{"inputs":[],"name":"Semaphore__GroupDoesNotExist","type":"error"},{"inputs":[],"name":"Semaphore__GroupHasNoMembers","type":"error"},{"inputs":[],"name":"Semaphore__InvalidProof","type":"error"},{"inputs":[],"name":"Semaphore__MerkleTreeDepthIsNotSupported","type":"error"},{"inputs":[],"name":"Semaphore__MerkleTreeRootIsExpired","type":"error"},{"inputs":[],"name":"Semaphore__MerkleTreeRootIsNotPartOfTheGroup","type":"error"},{"inputs":[],"name":"Semaphore__YouAreUsingTheSameNullifierTwice","type":"error"},{"inputs":[],"name":"WrongSiblingNodes","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"GroupAdminPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"GroupAdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"GroupCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldMerkleTreeDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMerkleTreeDuration","type":"uint256"}],"name":"GroupMerkleTreeDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"identityCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"}],"name":"MemberAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"identityCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"}],"name":"MemberRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"identityCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newIdentityCommitment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"}],"name":"MemberUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startIndex","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"identityCommitments","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"}],"name":"MembersAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"merkleTreeDepth","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nullifier","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"message","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"scope","type":"uint256"},{"indexed":false,"internalType":"uint256[8]","name":"points","type":"uint256[8]"}],"name":"ProofValidated","type":"event"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"acceptGroupAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"identityCommitment","type":"uint256"}],"name":"addMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256[]","name":"identityCommitments","type":"uint256[]"}],"name":"addMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint256","name":"merkleTreeDuration","type":"uint256"}],"name":"createGroup","outputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createGroup","outputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"createGroup","outputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"getGroupAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"getMerkleTreeDepth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"getMerkleTreeRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"}],"name":"getMerkleTreeSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"groupCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"groups","outputs":[{"internalType":"uint256","name":"merkleTreeDuration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"identityCommitment","type":"uint256"}],"name":"hasMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"identityCommitment","type":"uint256"}],"name":"indexOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"identityCommitment","type":"uint256"},{"internalType":"uint256[]","name":"merkleProofSiblings","type":"uint256[]"}],"name":"removeMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"updateGroupAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"newMerkleTreeDuration","type":"uint256"}],"name":"updateGroupMerkleTreeDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"internalType":"uint256","name":"identityCommitment","type":"uint256"},{"internalType":"uint256","name":"newIdentityCommitment","type":"uint256"},{"internalType":"uint256[]","name":"merkleProofSiblings","type":"uint256[]"}],"name":"updateMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint256","name":"merkleTreeDepth","type":"uint256"},{"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"},{"internalType":"uint256","name":"nullifier","type":"uint256"},{"internalType":"uint256","name":"message","type":"uint256"},{"internalType":"uint256","name":"scope","type":"uint256"},{"internalType":"uint256[8]","name":"points","type":"uint256[8]"}],"internalType":"struct ISemaphore.SemaphoreProof","name":"proof","type":"tuple"}],"name":"validateProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"contract ISemaphoreVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupId","type":"uint256"},{"components":[{"internalType":"uint256","name":"merkleTreeDepth","type":"uint256"},{"internalType":"uint256","name":"merkleTreeRoot","type":"uint256"},{"internalType":"uint256","name":"nullifier","type":"uint256"},{"internalType":"uint256","name":"message","type":"uint256"},{"internalType":"uint256","name":"scope","type":"uint256"},{"internalType":"uint256[8]","name":"points","type":"uint256[8]"}],"internalType":"struct ISemaphore.SemaphoreProof","name":"proof","type":"tuple"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b5060405161204138038061204183398101604081905261002f91610054565b600380546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611fae806100936000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80636389e107116100b8578063a9961c941161007c578063a9961c94146102b5578063d0d898dd146102de578063d24924fe146102f1578063da3cda52146102fa578063dabc4d511461030d578063fcf0b6ec1461032057600080fd5b80636389e1071461022c5780636cdd32fe1461024f5780637ee35a0c1461026257806390509d441461028257806396324bd41461029557600080fd5b80634178c4d5116100ff5780634178c4d5146101c8578063456f4188146101db578063568ee826146101fe578063575185ed146102115780635c3f3b601461021957600080fd5b8063042453711461013c57806306dd8485146101515780631783efc3146101775780632b7ac3f31461018a5780632c880363146101b5575b600080fd5b61014f61014a366004611a0e565b610333565b005b61016461015f366004611a5a565b610366565b6040519081526020015b60405180910390f35b61014f610185366004611a5a565b610387565b60035461019d906001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b6101646101c3366004611a98565b6103b8565b61014f6101d6366004611ac2565b6103f0565b6101ee6101e9366004611b23565b610427565b604051901515815260200161016e565b61014f61020c366004611b5d565b61068c565b61016461069a565b610164610227366004611b89565b6106d1565b61016461023a366004611ba4565b60009081526020819052604090206001015490565b61014f61025d366004611bbd565b61070a565b610164610270366004611ba4565b60009081526020819052604090205490565b6101ee610290366004611a5a565b61073f565b6101646102a3366004611ba4565b60046020526000908152604090205481565b61019d6102c3366004611ba4565b6000908152600160205260409020546001600160a01b031690565b61014f6102ec366004611b23565b610761565b61016460055481565b61014f610308366004611ba4565b61084b565b61016461031b366004611ba4565b610857565b61014f61032e366004611a5a565b61087b565b600061034084848461090b565b600094855260046020908152604080872092875260019092019052909320429055505050565b600082815260208190526040812061037e90836109a9565b90505b92915050565b600061039383836109f6565b6000938452600460209081526040808620928652600190920190529092204290555050565b60058054600091826103c983611c26565b9190505590506103d98184610a98565b600081815260046020526040902091909155919050565b60006103ff8686868686610b22565b6000968752600460209081526040808920928952600190920190529095204290555050505050565b60008281526001602052604081205483906001600160a01b031661045e5760405163029f057960e01b815260040160405180910390fd5b60018335108061046f575060208335115b1561048d5760405163767b278960e11b815260040160405180910390fd5b600084815260208190526040812054908190036104bd5760405163c8b02e0160e01b815260040160405180910390fd5b60006104c886610857565b90508085602001351461054d576000868152600460208181526040808420898301358552600181018352908420548a855292909152549091829003610520576040516326994ac360e11b815260040160405180910390fd5b61052a8183611c3f565b42111561054a576040516309581a9960e41b815260040160405180910390fd5b50505b60035460408051808201825260a0880135815260c088013560208083019190915282516080808201855260e08b01358286019081526101008c0135606080850191909152908352855180870187526101208d013581526101408d01358186015283850152855180870187526101608d013581526101808d01358186015286519283018752848d013583528c870135948301949094526001600160a01b039096169563a23f019995929392820190610606908d0135610be9565b81526020016106188c60800135610be9565b90526040516001600160e01b031960e087901b16815261064194939291908c3590600401611cb4565b602060405180830381865afa15801561065e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106829190611d47565b9695505050505050565b6106968282610c20565b5050565b60058054600091826106ab83611c26565b9190505590506106bb8133610a98565b6000818152600460205260409020610e10905590565b60058054600091826106e283611c26565b9190505590506106f28183610a98565b6000818152600460205260409020610e109055919050565b600061071885858585610cb4565b60009586526004602090815260408088209288526001909201905290942042905550505050565b600082815260208181526040808320848452600301909152812054151561037e565b600082815260046020908152604080832084820135845260020190915290205460ff16156107a25760405163041162bd60e31b815260040160405180910390fd5b6107ac8282610427565b6107c95760405163012a9af160e61b815260040160405180910390fd5b6000828152600460209081526040808320848201358085526002909101835292819020805460ff1916600117905551608084013592918401359185917f0c32e14cfe81a05d371c248d22de6b7ae849e981b76a1f8842e7b6da73fc405a9161083f918735919060608901359060a08a0190611d70565b60405180910390a45050565b61085481610d72565b50565b60008181526020818152604080832060018101548452600201909152812054610381565b60008281526001602052604090205482906001600160a01b031633146108b4576040516317737e4f60e31b815260040160405180910390fd5b60008381526004602090815260409182902080549085905582518181529182018590529185917f264b2a8f6763c084235fe832ba903482b2ef1a521336881fc75b987c2dfd29c5910160405180910390a250505050565b60008381526001602052604081205484906001600160a01b03163314610944576040516317737e4f60e31b815260040160405180910390fd5b6000858152602081905260409020805490610960908686610e17565b9250857f61e5e8054e3daf084a0c6c646c065e8bf5e7ca4d5567bda942309bd1652f349d828787876040516109989493929190611d98565b60405180910390a250509392505050565b600081815260038301602052604081205481036109d957604051631c811d5b60e21b815260040160405180910390fd5b600082815260038401602052604090205461037e90600190611dde565b60008281526001602052604081205483906001600160a01b03163314610a2f576040516317737e4f60e31b815260040160405180910390fd5b6000848152602081905260409020805490610a4a9085611344565b604080518381526020810187905290810182905290935085907f19239b3f93cd10558aaf11423af70c77763bf54f52bcc75bfa74d4d13548cde99060600160405180910390a2505092915050565b60008281526001602052604080822080546001600160a01b0319166001600160a01b0385161790555183917ff0adfb94eab6daf835deb69c5738fe636150c3dfd08094a76f39b963dc8cb05a91a26040516001600160a01b0382169060009084907f0ba83579a0e79193ef649b9f5a8759d35af086ba62a3e207b52e4a8ae30d49e3908390a45050565b60008581526001602052604081205486906001600160a01b03163314610b5b576040516317737e4f60e31b815260040160405180910390fd5b6000878152602081905260408120610b7390886109a9565b6000898152602081905260409020909150610b91908888888861150d565b60408051838152602081018a90529081018890526060810182905290935088907fea3588e4a2a0c93d6a0e69dfeaf7496f43ccccf02ad9ce0a5b7627cbca4b61b19060800160405180910390a2505095945050505050565b6000600882604051602001610c0091815260200190565b60408051601f198184030181529190528051602090910120901c92915050565b60008281526001602052604090205482906001600160a01b03163314610c59576040516317737e4f60e31b815260040160405180910390fd5b60008381526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519091339186917f1018365553cce55d9cb02ef73e18cc9311894f3fe1d1eafd235ac2d26cd8ba5891a4505050565b60008481526001602052604081205485906001600160a01b03163314610ced576040516317737e4f60e31b815260040160405180910390fd5b6000868152602081905260408120610d0590876109a9565b6000888152602081905260409020909150610d22908787876119a9565b604080518381526020810189905290810182905290935087907f3108849c053c77b8073a11256dffb5ffd5b55e93e105a355e1c9061db890d8719060600160405180910390a25050949350505050565b6000818152600260205260409020546001600160a01b03163314610da9576040516334c4245d60e01b815260040160405180910390fd5b60008181526001602090815260408083208054336001600160a01b031980831682179093556002909452828520805490921690915590516001600160a01b0390911692839185917f0ba83579a0e79193ef649b9f5a8759d35af086ba62a3e207b52e4a8ae30d49e391a45050565b8254600090815b83811015610f4857600080516020611f59833981519152858583818110610e4757610e47611c52565b9050602002013510610e6c576040516361c0541760e11b815260040160405180910390fd5b848482818110610e7e57610e7e611c52565b90506020020135600003610ea5576040516314b48df160e11b815260040160405180910390fd5b610eda86868684818110610ebb57610ebb611c52565b9050602002013560009081526003919091016020526040902054151590565b15610ef8576040516312c50cad60e11b815260040160405180910390fd5b80610f04836001611c3f565b610f0e9190611c3f565b866003016000878785818110610f2657610f26611c52565b6020908102929092013583525081019190915260400160002055600101610e1e565b50606084848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050506001880154919250505b610f918584611c3f565b610f9c826002611ed5565b1015610fb257610fab81611c26565b9050610f87565b60018701819055826000610fc68783611c3f565b9050600182811c90600090610fdb8185611dde565b610fe7911c6001611c3f565b905060005b858110156112d85760006110008484611dde565b905060008167ffffffffffffffff81111561101d5761101d611ee1565b604051908082528060200260200182016040528015611046578160200160208202803683370190505b50905060005b82811015611203576000886110618884611c3f565b61106c906002611ef7565b101561108f578f60020160008681526020019081526020016000205490506110cb565b8a8961109b8985611c3f565b6110a6906002611ef7565b6110b09190611dde565b815181106110c0576110c0611c52565b602002602001015190505b6000886110d88985611c3f565b6110e3906002611ef7565b6110ee906001611c3f565b101561113b578b8a6111008a86611c3f565b61110b906002611ef7565b611116906001611c3f565b6111209190611dde565b8151811061113057611130611c52565b602002602001015190505b600081156111d357604080518082018252848152602081018490529051632b0aac7f60e11b815273b43122ecb241dd50062641f089876679fd06599a9163561558fe9161118b9190600401611f0e565b602060405180830381865af41580156111a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cc9190611f3f565b90506111d6565b50815b808585815181106111e9576111e9611c52565b60200260200101818152505083600101935050505061104c565b5085600116600103611254578860018a5161121e9190611dde565b8151811061122e5761122e611c52565b60200260200101518e60020160008581526020019081526020016000208190555061129f565b60018951111561129f578860028a5161126d9190611dde565b8151811061127d5761127d611c52565b60200260200101518e6002016000858152602001908152602001600020819055505b849650600185901c9450809850839550600180856112bd9190611dde565b6112c9911c6001611c3f565b93508260010192505050610fec565b506112e38988611c3f565b8b55855186906000906112f8576112f8611c52565b60200260200101518b6002016000878152602001908152602001600020819055508560008151811061132c5761132c611c52565b60200260200101519750505050505050509392505050565b6000600080516020611f598339815191528210611374576040516361c0541760e11b815260040160405180910390fd5b81600003611395576040516314b48df160e11b815260040160405180910390fd5b6000828152600384016020526040902054156113c4576040516312c50cad60e11b815260040160405180910390fd5b8254600180850154906113d8908390611c3f565b6113e3826002611ed5565b10156113f5576113f281611c26565b90505b600185018190558360005b828110156114d2578084901c6001166001036114b657604080518082018252600083815260028a0160209081529083902054825281018490529051632b0aac7f60e11b815273b43122ecb241dd50062641f089876679fd06599a9163561558fe9161146e9190600401611f0e565b602060405180830381865af415801561148b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114af9190611f3f565b91506114ca565b600081815260028801602052604090208290555b600101611400565b506114dc83611c26565b8087556000928352600287016020908152604080852084905596845260039097019096529390209390935550919050565b6000600080516020611f59833981519152841061153d576040516361c0541760e11b815260040160405180910390fd5b600085815260038701602052604090205461156b57604051631c811d5b60e21b815260040160405180910390fd5b60008481526003870160205260409020541561159a576040516312c50cad60e11b815260040160405180910390fd5b60006115a687876109a9565b8754909150859087906000906115be90600190611dde565b60018b0154909150600090815b81811015611920578087901c60011660010361177e57600080516020611f598339815191528a8a8581811061160257611602611c52565b9050602002013510611627576040516361c0541760e11b815260040160405180910390fd5b73b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808d8d8881811061165e5761165e611c52565b905060200201358152602001898152506040518263ffffffff1660e01b815260040161168a9190611f0e565b602060405180830381865af41580156116a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116cb9190611f3f565b955073b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808d8d8881811061170457611704611c52565b905060200201358152602001888152506040518263ffffffff1660e01b81526004016117309190611f0e565b602060405180830381865af415801561174d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117719190611f3f565b9450826001019250611918565b86811c84821c1461190457600080516020611f598339815191528a8a858181106117aa576117aa611c52565b90506020020135106117cf576040516361c0541760e11b815260040160405180910390fd5b600081815260028e0160205260409020548590036117fb57600081815260028e01602052604090208690555b73b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808981526020018d8d8881811061183857611838611c52565b905060200201358152506040518263ffffffff1660e01b815260040161185e9190611f0e565b602060405180830381865af415801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190611f3f565b955073b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808881526020018d8d888181106118de576118de611c52565b905060200201358152506040518263ffffffff1660e01b81526004016117309190611f0e565b600081815260028e01602052604090208690555b6001016115cb565b5060018c0154600090815260028d016020526040902054841461195657604051631fd4986360e11b815260040160405180910390fd5b600081815260028d016020526040902085905589156119885760008b815260038d016020526040808220548c83529120555b505050600088815260038a0160205260408120555091505095945050505050565b60006119b985856000868661150d565b95945050505050565b60008083601f8401126119d457600080fd5b50813567ffffffffffffffff8111156119ec57600080fd5b6020830191508360208260051b8501011115611a0757600080fd5b9250929050565b600080600060408486031215611a2357600080fd5b83359250602084013567ffffffffffffffff811115611a4157600080fd5b611a4d868287016119c2565b9497909650939450505050565b60008060408385031215611a6d57600080fd5b50508035926020909101359150565b80356001600160a01b0381168114611a9357600080fd5b919050565b60008060408385031215611aab57600080fd5b611ab483611a7c565b946020939093013593505050565b600080600080600060808688031215611ada57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115611b0657600080fd5b611b12888289016119c2565b969995985093965092949392505050565b6000808284036101c0811215611b3857600080fd5b833592506101a0601f1982011215611b4f57600080fd5b506020830190509250929050565b60008060408385031215611b7057600080fd5b82359150611b8060208401611a7c565b90509250929050565b600060208284031215611b9b57600080fd5b61037e82611a7c565b600060208284031215611bb657600080fd5b5035919050565b60008060008060608587031215611bd357600080fd5b8435935060208501359250604085013567ffffffffffffffff811115611bf857600080fd5b611c04878288016119c2565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600060018201611c3857611c38611c10565b5060010190565b8082018082111561038157610381611c10565b634e487b7160e01b600052603260045260246000fd5b8060005b6002811015611c8b578151845260209384019390910190600101611c6c565b50505050565b8060005b6004811015611c8b578151845260209384019390910190600101611c95565b6101a08101611cc38288611c68565b6040808301876000805b6002808210611cdc5750611d16565b835185845b83811015611cff578251825260209283019290910190600101611ce1565b505050938501935060209290920191600101611ccd565b5050505050611d2860c0830186611c68565b611d36610100830185611c91565b826101808301529695505050505050565b600060208284031215611d5957600080fd5b81518015158114611d6957600080fd5b9392505050565b8481526020810184905260408101839052610160810161010083606084013795945050505050565b848152606060208201819052810183905260006001600160fb1b03841115611dbf57600080fd5b8360051b80866080850137604083019390935250016080019392505050565b8181038181111561038157610381611c10565b600181815b80851115611e2c578160001904821115611e1257611e12611c10565b80851615611e1f57918102915b93841c9390800290611df6565b509250929050565b600082611e4357506001610381565b81611e5057506000610381565b8160018114611e665760028114611e7057611e8c565b6001915050610381565b60ff841115611e8157611e81611c10565b50506001821b610381565b5060208310610133831016604e8410600b8410161715611eaf575081810a610381565b611eb98383611df1565b8060001904821115611ecd57611ecd611c10565b029392505050565b600061037e8383611e34565b634e487b7160e01b600052604160045260246000fd5b808202811582820484141761038157610381611c10565b60408101818360005b6002811015611f36578151835260209283019290910190600101611f17565b50505092915050565b600060208284031215611f5157600080fd5b505191905056fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122084e705462004ac3836e73fc250636bb9e4adb10992b32ba2998bce788eb1639f64736f6c634300081700330000000000000000000000004dec9e3784ecc1ee002001bfe91deef4a48931f8

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101375760003560e01c80636389e107116100b8578063a9961c941161007c578063a9961c94146102b5578063d0d898dd146102de578063d24924fe146102f1578063da3cda52146102fa578063dabc4d511461030d578063fcf0b6ec1461032057600080fd5b80636389e1071461022c5780636cdd32fe1461024f5780637ee35a0c1461026257806390509d441461028257806396324bd41461029557600080fd5b80634178c4d5116100ff5780634178c4d5146101c8578063456f4188146101db578063568ee826146101fe578063575185ed146102115780635c3f3b601461021957600080fd5b8063042453711461013c57806306dd8485146101515780631783efc3146101775780632b7ac3f31461018a5780632c880363146101b5575b600080fd5b61014f61014a366004611a0e565b610333565b005b61016461015f366004611a5a565b610366565b6040519081526020015b60405180910390f35b61014f610185366004611a5a565b610387565b60035461019d906001600160a01b031681565b6040516001600160a01b03909116815260200161016e565b6101646101c3366004611a98565b6103b8565b61014f6101d6366004611ac2565b6103f0565b6101ee6101e9366004611b23565b610427565b604051901515815260200161016e565b61014f61020c366004611b5d565b61068c565b61016461069a565b610164610227366004611b89565b6106d1565b61016461023a366004611ba4565b60009081526020819052604090206001015490565b61014f61025d366004611bbd565b61070a565b610164610270366004611ba4565b60009081526020819052604090205490565b6101ee610290366004611a5a565b61073f565b6101646102a3366004611ba4565b60046020526000908152604090205481565b61019d6102c3366004611ba4565b6000908152600160205260409020546001600160a01b031690565b61014f6102ec366004611b23565b610761565b61016460055481565b61014f610308366004611ba4565b61084b565b61016461031b366004611ba4565b610857565b61014f61032e366004611a5a565b61087b565b600061034084848461090b565b600094855260046020908152604080872092875260019092019052909320429055505050565b600082815260208190526040812061037e90836109a9565b90505b92915050565b600061039383836109f6565b6000938452600460209081526040808620928652600190920190529092204290555050565b60058054600091826103c983611c26565b9190505590506103d98184610a98565b600081815260046020526040902091909155919050565b60006103ff8686868686610b22565b6000968752600460209081526040808920928952600190920190529095204290555050505050565b60008281526001602052604081205483906001600160a01b031661045e5760405163029f057960e01b815260040160405180910390fd5b60018335108061046f575060208335115b1561048d5760405163767b278960e11b815260040160405180910390fd5b600084815260208190526040812054908190036104bd5760405163c8b02e0160e01b815260040160405180910390fd5b60006104c886610857565b90508085602001351461054d576000868152600460208181526040808420898301358552600181018352908420548a855292909152549091829003610520576040516326994ac360e11b815260040160405180910390fd5b61052a8183611c3f565b42111561054a576040516309581a9960e41b815260040160405180910390fd5b50505b60035460408051808201825260a0880135815260c088013560208083019190915282516080808201855260e08b01358286019081526101008c0135606080850191909152908352855180870187526101208d013581526101408d01358186015283850152855180870187526101608d013581526101808d01358186015286519283018752848d013583528c870135948301949094526001600160a01b039096169563a23f019995929392820190610606908d0135610be9565b81526020016106188c60800135610be9565b90526040516001600160e01b031960e087901b16815261064194939291908c3590600401611cb4565b602060405180830381865afa15801561065e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106829190611d47565b9695505050505050565b6106968282610c20565b5050565b60058054600091826106ab83611c26565b9190505590506106bb8133610a98565b6000818152600460205260409020610e10905590565b60058054600091826106e283611c26565b9190505590506106f28183610a98565b6000818152600460205260409020610e109055919050565b600061071885858585610cb4565b60009586526004602090815260408088209288526001909201905290942042905550505050565b600082815260208181526040808320848452600301909152812054151561037e565b600082815260046020908152604080832084820135845260020190915290205460ff16156107a25760405163041162bd60e31b815260040160405180910390fd5b6107ac8282610427565b6107c95760405163012a9af160e61b815260040160405180910390fd5b6000828152600460209081526040808320848201358085526002909101835292819020805460ff1916600117905551608084013592918401359185917f0c32e14cfe81a05d371c248d22de6b7ae849e981b76a1f8842e7b6da73fc405a9161083f918735919060608901359060a08a0190611d70565b60405180910390a45050565b61085481610d72565b50565b60008181526020818152604080832060018101548452600201909152812054610381565b60008281526001602052604090205482906001600160a01b031633146108b4576040516317737e4f60e31b815260040160405180910390fd5b60008381526004602090815260409182902080549085905582518181529182018590529185917f264b2a8f6763c084235fe832ba903482b2ef1a521336881fc75b987c2dfd29c5910160405180910390a250505050565b60008381526001602052604081205484906001600160a01b03163314610944576040516317737e4f60e31b815260040160405180910390fd5b6000858152602081905260409020805490610960908686610e17565b9250857f61e5e8054e3daf084a0c6c646c065e8bf5e7ca4d5567bda942309bd1652f349d828787876040516109989493929190611d98565b60405180910390a250509392505050565b600081815260038301602052604081205481036109d957604051631c811d5b60e21b815260040160405180910390fd5b600082815260038401602052604090205461037e90600190611dde565b60008281526001602052604081205483906001600160a01b03163314610a2f576040516317737e4f60e31b815260040160405180910390fd5b6000848152602081905260409020805490610a4a9085611344565b604080518381526020810187905290810182905290935085907f19239b3f93cd10558aaf11423af70c77763bf54f52bcc75bfa74d4d13548cde99060600160405180910390a2505092915050565b60008281526001602052604080822080546001600160a01b0319166001600160a01b0385161790555183917ff0adfb94eab6daf835deb69c5738fe636150c3dfd08094a76f39b963dc8cb05a91a26040516001600160a01b0382169060009084907f0ba83579a0e79193ef649b9f5a8759d35af086ba62a3e207b52e4a8ae30d49e3908390a45050565b60008581526001602052604081205486906001600160a01b03163314610b5b576040516317737e4f60e31b815260040160405180910390fd5b6000878152602081905260408120610b7390886109a9565b6000898152602081905260409020909150610b91908888888861150d565b60408051838152602081018a90529081018890526060810182905290935088907fea3588e4a2a0c93d6a0e69dfeaf7496f43ccccf02ad9ce0a5b7627cbca4b61b19060800160405180910390a2505095945050505050565b6000600882604051602001610c0091815260200190565b60408051601f198184030181529190528051602090910120901c92915050565b60008281526001602052604090205482906001600160a01b03163314610c59576040516317737e4f60e31b815260040160405180910390fd5b60008381526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590519091339186917f1018365553cce55d9cb02ef73e18cc9311894f3fe1d1eafd235ac2d26cd8ba5891a4505050565b60008481526001602052604081205485906001600160a01b03163314610ced576040516317737e4f60e31b815260040160405180910390fd5b6000868152602081905260408120610d0590876109a9565b6000888152602081905260409020909150610d22908787876119a9565b604080518381526020810189905290810182905290935087907f3108849c053c77b8073a11256dffb5ffd5b55e93e105a355e1c9061db890d8719060600160405180910390a25050949350505050565b6000818152600260205260409020546001600160a01b03163314610da9576040516334c4245d60e01b815260040160405180910390fd5b60008181526001602090815260408083208054336001600160a01b031980831682179093556002909452828520805490921690915590516001600160a01b0390911692839185917f0ba83579a0e79193ef649b9f5a8759d35af086ba62a3e207b52e4a8ae30d49e391a45050565b8254600090815b83811015610f4857600080516020611f59833981519152858583818110610e4757610e47611c52565b9050602002013510610e6c576040516361c0541760e11b815260040160405180910390fd5b848482818110610e7e57610e7e611c52565b90506020020135600003610ea5576040516314b48df160e11b815260040160405180910390fd5b610eda86868684818110610ebb57610ebb611c52565b9050602002013560009081526003919091016020526040902054151590565b15610ef8576040516312c50cad60e11b815260040160405180910390fd5b80610f04836001611c3f565b610f0e9190611c3f565b866003016000878785818110610f2657610f26611c52565b6020908102929092013583525081019190915260400160002055600101610e1e565b50606084848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050506001880154919250505b610f918584611c3f565b610f9c826002611ed5565b1015610fb257610fab81611c26565b9050610f87565b60018701819055826000610fc68783611c3f565b9050600182811c90600090610fdb8185611dde565b610fe7911c6001611c3f565b905060005b858110156112d85760006110008484611dde565b905060008167ffffffffffffffff81111561101d5761101d611ee1565b604051908082528060200260200182016040528015611046578160200160208202803683370190505b50905060005b82811015611203576000886110618884611c3f565b61106c906002611ef7565b101561108f578f60020160008681526020019081526020016000205490506110cb565b8a8961109b8985611c3f565b6110a6906002611ef7565b6110b09190611dde565b815181106110c0576110c0611c52565b602002602001015190505b6000886110d88985611c3f565b6110e3906002611ef7565b6110ee906001611c3f565b101561113b578b8a6111008a86611c3f565b61110b906002611ef7565b611116906001611c3f565b6111209190611dde565b8151811061113057611130611c52565b602002602001015190505b600081156111d357604080518082018252848152602081018490529051632b0aac7f60e11b815273b43122ecb241dd50062641f089876679fd06599a9163561558fe9161118b9190600401611f0e565b602060405180830381865af41580156111a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cc9190611f3f565b90506111d6565b50815b808585815181106111e9576111e9611c52565b60200260200101818152505083600101935050505061104c565b5085600116600103611254578860018a5161121e9190611dde565b8151811061122e5761122e611c52565b60200260200101518e60020160008581526020019081526020016000208190555061129f565b60018951111561129f578860028a5161126d9190611dde565b8151811061127d5761127d611c52565b60200260200101518e6002016000858152602001908152602001600020819055505b849650600185901c9450809850839550600180856112bd9190611dde565b6112c9911c6001611c3f565b93508260010192505050610fec565b506112e38988611c3f565b8b55855186906000906112f8576112f8611c52565b60200260200101518b6002016000878152602001908152602001600020819055508560008151811061132c5761132c611c52565b60200260200101519750505050505050509392505050565b6000600080516020611f598339815191528210611374576040516361c0541760e11b815260040160405180910390fd5b81600003611395576040516314b48df160e11b815260040160405180910390fd5b6000828152600384016020526040902054156113c4576040516312c50cad60e11b815260040160405180910390fd5b8254600180850154906113d8908390611c3f565b6113e3826002611ed5565b10156113f5576113f281611c26565b90505b600185018190558360005b828110156114d2578084901c6001166001036114b657604080518082018252600083815260028a0160209081529083902054825281018490529051632b0aac7f60e11b815273b43122ecb241dd50062641f089876679fd06599a9163561558fe9161146e9190600401611f0e565b602060405180830381865af415801561148b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114af9190611f3f565b91506114ca565b600081815260028801602052604090208290555b600101611400565b506114dc83611c26565b8087556000928352600287016020908152604080852084905596845260039097019096529390209390935550919050565b6000600080516020611f59833981519152841061153d576040516361c0541760e11b815260040160405180910390fd5b600085815260038701602052604090205461156b57604051631c811d5b60e21b815260040160405180910390fd5b60008481526003870160205260409020541561159a576040516312c50cad60e11b815260040160405180910390fd5b60006115a687876109a9565b8754909150859087906000906115be90600190611dde565b60018b0154909150600090815b81811015611920578087901c60011660010361177e57600080516020611f598339815191528a8a8581811061160257611602611c52565b9050602002013510611627576040516361c0541760e11b815260040160405180910390fd5b73b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808d8d8881811061165e5761165e611c52565b905060200201358152602001898152506040518263ffffffff1660e01b815260040161168a9190611f0e565b602060405180830381865af41580156116a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116cb9190611f3f565b955073b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808d8d8881811061170457611704611c52565b905060200201358152602001888152506040518263ffffffff1660e01b81526004016117309190611f0e565b602060405180830381865af415801561174d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117719190611f3f565b9450826001019250611918565b86811c84821c1461190457600080516020611f598339815191528a8a858181106117aa576117aa611c52565b90506020020135106117cf576040516361c0541760e11b815260040160405180910390fd5b600081815260028e0160205260409020548590036117fb57600081815260028e01602052604090208690555b73b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808981526020018d8d8881811061183857611838611c52565b905060200201358152506040518263ffffffff1660e01b815260040161185e9190611f0e565b602060405180830381865af415801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190611f3f565b955073b43122ecb241dd50062641f089876679fd06599a63561558fe60405180604001604052808881526020018d8d888181106118de576118de611c52565b905060200201358152506040518263ffffffff1660e01b81526004016117309190611f0e565b600081815260028e01602052604090208690555b6001016115cb565b5060018c0154600090815260028d016020526040902054841461195657604051631fd4986360e11b815260040160405180910390fd5b600081815260028d016020526040902085905589156119885760008b815260038d016020526040808220548c83529120555b505050600088815260038a0160205260408120555091505095945050505050565b60006119b985856000868661150d565b95945050505050565b60008083601f8401126119d457600080fd5b50813567ffffffffffffffff8111156119ec57600080fd5b6020830191508360208260051b8501011115611a0757600080fd5b9250929050565b600080600060408486031215611a2357600080fd5b83359250602084013567ffffffffffffffff811115611a4157600080fd5b611a4d868287016119c2565b9497909650939450505050565b60008060408385031215611a6d57600080fd5b50508035926020909101359150565b80356001600160a01b0381168114611a9357600080fd5b919050565b60008060408385031215611aab57600080fd5b611ab483611a7c565b946020939093013593505050565b600080600080600060808688031215611ada57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115611b0657600080fd5b611b12888289016119c2565b969995985093965092949392505050565b6000808284036101c0811215611b3857600080fd5b833592506101a0601f1982011215611b4f57600080fd5b506020830190509250929050565b60008060408385031215611b7057600080fd5b82359150611b8060208401611a7c565b90509250929050565b600060208284031215611b9b57600080fd5b61037e82611a7c565b600060208284031215611bb657600080fd5b5035919050565b60008060008060608587031215611bd357600080fd5b8435935060208501359250604085013567ffffffffffffffff811115611bf857600080fd5b611c04878288016119c2565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b600060018201611c3857611c38611c10565b5060010190565b8082018082111561038157610381611c10565b634e487b7160e01b600052603260045260246000fd5b8060005b6002811015611c8b578151845260209384019390910190600101611c6c565b50505050565b8060005b6004811015611c8b578151845260209384019390910190600101611c95565b6101a08101611cc38288611c68565b6040808301876000805b6002808210611cdc5750611d16565b835185845b83811015611cff578251825260209283019290910190600101611ce1565b505050938501935060209290920191600101611ccd565b5050505050611d2860c0830186611c68565b611d36610100830185611c91565b826101808301529695505050505050565b600060208284031215611d5957600080fd5b81518015158114611d6957600080fd5b9392505050565b8481526020810184905260408101839052610160810161010083606084013795945050505050565b848152606060208201819052810183905260006001600160fb1b03841115611dbf57600080fd5b8360051b80866080850137604083019390935250016080019392505050565b8181038181111561038157610381611c10565b600181815b80851115611e2c578160001904821115611e1257611e12611c10565b80851615611e1f57918102915b93841c9390800290611df6565b509250929050565b600082611e4357506001610381565b81611e5057506000610381565b8160018114611e665760028114611e7057611e8c565b6001915050610381565b60ff841115611e8157611e81611c10565b50506001821b610381565b5060208310610133831016604e8410600b8410161715611eaf575081810a610381565b611eb98383611df1565b8060001904821115611ecd57611ecd611c10565b029392505050565b600061037e8383611e34565b634e487b7160e01b600052604160045260246000fd5b808202811582820484141761038157610381611c10565b60408101818360005b6002811015611f36578151835260209283019290910190600101611f17565b50505092915050565b600060208284031215611f5157600080fd5b505191905056fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122084e705462004ac3836e73fc250636bb9e4adb10992b32ba2998bce788eb1639f64736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000004dec9e3784ecc1ee002001bfe91deef4a48931f8

-----Decoded View---------------
Arg [0] : _verifier (address): 0x4DeC9E3784EcC1eE002001BfE91deEf4A48931f8

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004dec9e3784ecc1ee002001bfe91deef4a48931f8


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.