ETH Price: $1,973.20 (+0.17%)

Transaction Decoder

Block:
24491456 at Feb-19-2026 02:21:23 PM +UTC
Transaction Fee:
0.000497595241060568 ETH $0.98
Gas Used:
536,662 Gas / 0.927204164 Gwei

Emitted Events:

106 PrivacyPoolSimple.LeafInserted( _index=6436, _leaf=14427098225722791103383761893914039086184269871286508174225338623126798861935, _root=11291644896449219142321039166168260722728385813384072757046381165914752487564 )
107 PrivacyPoolSimple.Withdrawn( _processooor=[Sender] 0x1c0aa8ccd568d90d61659f060d1bfb1e6f855a20, _value=12104366638582180, _spentNullifier=14203731547262537187081300687537091399428870819355629012011221609048027650018, _newCommitment=14427098225722791103383761893914039086184269871286508174225338623126798861935 )

Account State Difference:

  Address   Before After State Difference Code
0x1C0Aa8cC...e6f855A20
0.2429953914848571 Eth
Nonce: 11000
0.254602162882378712 Eth
Nonce: 11001
0.011606771397521612
(quasarbuilder)
18.684052313534349614 Eth18.684465543274349614 Eth0.00041322974
0xF241d57C...3C9A9C9fB
(Privacy Pools: Simple)
768.587223487509939485 Eth768.575119120871357305 Eth0.01210436663858218

Execution Trace

PrivacyPoolSimple.withdraw( _withdrawal=[{name:processooor, type:address, order:1, indexed:false, value:0x1C0Aa8cCD568d90d61659F060D1bFb1e6f855A20, valueString:0x1C0Aa8cCD568d90d61659F060D1bFb1e6f855A20}, {name:data, type:bytes, order:2, indexed:false, value:0x, valueString:0x}], _proof=[{name:pA, type:uint256[2], order:1, indexed:false, value:[20804231941469380128368118537220134616921248518024544109839814544976012650061, 10481111530726227529778374598066443149698864733483100428788183433736384947255], valueString:[20804231941469380128368118537220134616921248518024544109839814544976012650061, 10481111530726227529778374598066443149698864733483100428788183433736384947255]}, {name:pB, type:uint256[2][2], order:2, indexed:false, value:[[1337440397102773182332555238734784386707935452055279069461370163449861963511, 9347648628314825766820237144062191745012366161488371558304805491092882692197], [14598806907698567800412625693058414419644234039486230490085540195456655813383, 15000750963550359101623606697771269918891242623466219089057920904266986809150]], valueString:[[1337440397102773182332555238734784386707935452055279069461370163449861963511, 9347648628314825766820237144062191745012366161488371558304805491092882692197], [14598806907698567800412625693058414419644234039486230490085540195456655813383, 15000750963550359101623606697771269918891242623466219089057920904266986809150]]}, {name:pC, type:uint256[2], order:3, indexed:false, value:[3851992875510279388504930560063560898599230916282792781207758757743182540947, 10601615664997608311560764908083958253162831881812325230078735887303439536502], valueString:[3851992875510279388504930560063560898599230916282792781207758757743182540947, 10601615664997608311560764908083958253162831881812325230078735887303439536502]}, {name:pubSignals, type:uint256[8], order:4, indexed:false, value:[14427098225722791103383761893914039086184269871286508174225338623126798861935, 14203731547262537187081300687537091399428870819355629012011221609048027650018, 12104366638582180, 21718798747096879037536112249731562046478202975801073929259756480878743916930, 13, 17477784785483335011099164176803519009190152515117027057162507389763058753158, 12, 4746703211438369118988581413217703215990259778395998672519096540397980875542], valueString:[14427098225722791103383761893914039086184269871286508174225338623126798861935, 14203731547262537187081300687537091399428870819355629012011221609048027650018, 12104366638582180, 21718798747096879037536112249731562046478202975801073929259756480878743916930, 13, 17477784785483335011099164176803519009190152515117027057162507389763058753158, 12, 4746703211438369118988581413217703215990259778395998672519096540397980875542]}] )
  • ERC1967Proxy.STATICCALL( )
    • 0x15e355024de1cdc74addea7ebdf98418ba5b1a2c.DELEGATECALL( )
    • WithdrawalVerifier.verifyProof( _pA=[20804231941469380128368118537220134616921248518024544109839814544976012650061, 10481111530726227529778374598066443149698864733483100428788183433736384947255], _pB=[[1337440397102773182332555238734784386707935452055279069461370163449861963511, 9347648628314825766820237144062191745012366161488371558304805491092882692197], [14598806907698567800412625693058414419644234039486230490085540195456655813383, 15000750963550359101623606697771269918891242623466219089057920904266986809150]], _pC=[3851992875510279388504930560063560898599230916282792781207758757743182540947, 10601615664997608311560764908083958253162831881812325230078735887303439536502], _pubSignals=[14427098225722791103383761893914039086184269871286508174225338623126798861935, 14203731547262537187081300687537091399428870819355629012011221609048027650018, 12104366638582180, 21718798747096879037536112249731562046478202975801073929259756480878743916930, 13, 17477784785483335011099164176803519009190152515117027057162507389763058753158, 12, 4746703211438369118988581413217703215990259778395998672519096540397980875542] ) => ( True )
      • Null: 0x000...007.08d93b65( )
      • Null: 0x000...006.07ddde4e( )
      • Null: 0x000...007.0967bfab( )
      • Null: 0x000...006.0591a1a6( )
      • Null: 0x000...007.1c5d0a9e( )
      • Null: 0x000...006.267c830d( )
      • Null: 0x000...007.2112c9ae( )
      • Null: 0x000...006.03aa230c( )
      • Null: 0x000...007.00dacdcb( )
      • Null: 0x000...006.060810a1( )
      • Null: 0x000...007.1fd92166( )
      • Null: 0x000...006.290bfc8b( )
      • Null: 0x000...007.0e93b09b( )
      • Null: 0x000...006.1e448740( )
      • Null: 0x000...007.1e9512a8( )
      • Null: 0x000...006.042bc80a( )
      • Null: 0x000...008.2dfec72a( )
      • PoseidonT3.hash( [3022522466274883762828132357086749669457801772366167123962477526849152330137, 14427098225722791103383761893914039086184269871286508174225338623126798861935] ) => ( 6394851689870418952288945715969722537133237658067603471507245482424259255331 )
      • PoseidonT3.hash( [5826290596741791645917236773753936903279183471885050185112158681716529179146, 6394851689870418952288945715969722537133237658067603471507245482424259255331] ) => ( 982609783254892135723161509979783200572926174184446114220477889314459386719 )
      • PoseidonT3.hash( [21699724539860160655490730906955452287454927081467592946909415783941906638706, 982609783254892135723161509979783200572926174184446114220477889314459386719] ) => ( 10791231936314776957360498107992902928780690376756023594798757297702275648572 )
      • PoseidonT3.hash( [20585668880175658321423066309643434389538508395643062922762207983865683214071, 10791231936314776957360498107992902928780690376756023594798757297702275648572] ) => ( 19963114009471484446476790614477473064838118130361937395748273986986237531290 )
      • PoseidonT3.hash( [539395349417630230701926304750909054139246781937216729942754870265716007378, 19963114009471484446476790614477473064838118130361937395748273986986237531290] ) => ( 20490653987936656144461144165445201672294360466613317105624164555492744596186 )
      • PoseidonT3.hash( [21432130453059805491954728035861440066570085622297540185399655939896726318815, 20490653987936656144461144165445201672294360466613317105624164555492744596186] ) => ( 11291644896449219142321039166168260722728385813384072757046381165914752487564 )
      • ETH 0.01210436663858218 SushiSwap: Deployer 1.CALL( )
        File 1 of 4: PrivacyPoolSimple
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        /*
        Made with ♥ for 0xBow by
        ░██╗░░░░░░░██╗░█████╗░███╗░░██╗██████╗░███████╗██████╗░██╗░░░░░░█████╗░███╗░░██╗██████╗░
        ░██║░░██╗░░██║██╔══██╗████╗░██║██╔══██╗██╔════╝██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔══██╗
        ░╚██╗████╗██╔╝██║░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██║░░░░░███████║██╔██╗██║██║░░██║
        ░░████╔═████║░██║░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██║░░░░░██╔══██║██║╚████║██║░░██║
        ░░╚██╔╝░╚██╔╝░╚█████╔╝██║░╚███║██████╔╝███████╗██║░░██║███████╗██║░░██║██║░╚███║██████╔╝
        ░░░╚═╝░░░╚═╝░░░╚════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░
        https://defi.sucks/
        */
        import {Constants} from 'contracts/lib/Constants.sol';
        import {PrivacyPool} from 'contracts/PrivacyPool.sol';
        import {IPrivacyPoolSimple} from 'interfaces/IPrivacyPool.sol';
        /**
         * @title PrivacyPoolSimple
         * @notice Native asset implementation of Privacy Pool.
         */
        contract PrivacyPoolSimple is PrivacyPool, IPrivacyPoolSimple {
          // @notice Initializes the state addresses
          constructor(
            address _entrypoint,
            address _withdrawalVerifier,
            address _ragequitVerifier
          ) PrivacyPool(_entrypoint, _withdrawalVerifier, _ragequitVerifier, Constants.NATIVE_ASSET) {}
          /**
           * @notice Handle receiving native asset asset
           * @param _amount The amount of asset receiving
           * @inheritdoc PrivacyPool
           */
          function _pull(address, uint256 _amount) internal override(PrivacyPool) {
            // Check the amount matches the value sent
            if (msg.value != _amount) revert InsufficientValue();
          }
          /**
           * @notice Handle sending native asset
           * @param _recipient The address of the user receiving the asset
           * @param _amount The amount of native asset being sent
           * @inheritdoc PrivacyPool
           */
          function _push(address _recipient, uint256 _amount) internal override(PrivacyPool) {
            /// Try to send native asset to recipient
            (bool _success,) = _recipient.call{value: _amount}('');
            if (!_success) revert FailedToSendNativeAsset();
          }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        library Constants {
          uint256 constant SNARK_SCALAR_FIELD =
            21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
          address constant NATIVE_ASSET = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        /*
        Made with ♥ for 0xBow by
        ░██╗░░░░░░░██╗░█████╗░███╗░░██╗██████╗░███████╗██████╗░██╗░░░░░░█████╗░███╗░░██╗██████╗░
        ░██║░░██╗░░██║██╔══██╗████╗░██║██╔══██╗██╔════╝██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔══██╗
        ░╚██╗████╗██╔╝██║░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██║░░░░░███████║██╔██╗██║██║░░██║
        ░░████╔═████║░██║░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██║░░░░░██╔══██║██║╚████║██║░░██║
        ░░╚██╔╝░╚██╔╝░╚█████╔╝██║░╚███║██████╔╝███████╗██║░░██║███████╗██║░░██║██║░╚███║██████╔╝
        ░░░╚═╝░░░╚═╝░░░╚════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░
        https://defi.sucks/
        */
        import {PoseidonT4} from 'poseidon/PoseidonT4.sol';
        import {Constants} from './lib/Constants.sol';
        import {ProofLib} from './lib/ProofLib.sol';
        import {IPrivacyPool} from 'interfaces/IPrivacyPool.sol';
        import {State} from './State.sol';
        /**
         * @title PrivacyPool
         * @notice Allows publicly depositing and privately withdrawing funds.
         * @dev Withdrawals require a valid proof of being approved by an ASP.
         * @dev Deposits can be irreversibly suspended by the Entrypoint, while withdrawals can't.
         */
        abstract contract PrivacyPool is State, IPrivacyPool {
          using ProofLib for ProofLib.WithdrawProof;
          using ProofLib for ProofLib.RagequitProof;
          /**
           * @notice Does a series of sanity checks on the proof public signals
           * @param _withdrawal The withdrawal data structure containing withdrawal details
           * @param _proof The withdrawal proof data structure containing proof details
           */
          modifier validWithdrawal(Withdrawal memory _withdrawal, ProofLib.WithdrawProof memory _proof) {
            // Check caller is the allowed processooor
            if (msg.sender != _withdrawal.processooor) revert InvalidProcessooor();
            // Check the context matches to ensure its integrity
            if (_proof.context() != uint256(keccak256(abi.encode(_withdrawal, SCOPE))) % Constants.SNARK_SCALAR_FIELD) {
              revert ContextMismatch();
            }
            // Check the tree depth signals are less than the max tree depth
            if (_proof.stateTreeDepth() > MAX_TREE_DEPTH || _proof.ASPTreeDepth() > MAX_TREE_DEPTH) revert InvalidTreeDepth();
            // Check the state root is known
            if (!_isKnownRoot(_proof.stateRoot())) revert UnknownStateRoot();
            // Check the ASP root is the latest
            if (_proof.ASPRoot() != ENTRYPOINT.latestRoot()) revert IncorrectASPRoot();
            _;
          }
          /**
           * @notice Initializes the contract state addresses
           * @param _entrypoint Address of the Entrypoint that operates this pool
           * @param _withdrawalVerifier Address of the Groth16 verifier for withdrawal proofs
           * @param _ragequitVerifier Address of the Groth16 verifier for ragequit proofs
           * @param _asset Address of the pool asset
           */
          constructor(
            address _entrypoint,
            address _withdrawalVerifier,
            address _ragequitVerifier,
            address _asset
          ) State(_asset, _entrypoint, _withdrawalVerifier, _ragequitVerifier) {}
          /*///////////////////////////////////////////////////////////////
                                     USER METHODS 
          //////////////////////////////////////////////////////////////*/
          /// @inheritdoc IPrivacyPool
          function deposit(
            address _depositor,
            uint256 _value,
            uint256 _precommitmentHash
          ) external payable onlyEntrypoint returns (uint256 _commitment) {
            // Check deposits are enabled
            if (dead) revert PoolIsDead();
            if (_value >= type(uint128).max) revert InvalidDepositValue();
            // Compute label
            uint256 _label = uint256(keccak256(abi.encodePacked(SCOPE, ++nonce))) % Constants.SNARK_SCALAR_FIELD;
            // Store depositor
            depositors[_label] = _depositor;
            // Compute commitment hash
            _commitment = PoseidonT4.hash([_value, _label, _precommitmentHash]);
            // Insert commitment in state (revert if already present)
            _insert(_commitment);
            // Pull funds from caller
            _pull(msg.sender, _value);
            emit Deposited(_depositor, _commitment, _label, _value, _precommitmentHash);
          }
          /// @inheritdoc IPrivacyPool
          function withdraw(
            Withdrawal memory _withdrawal,
            ProofLib.WithdrawProof memory _proof
          ) external validWithdrawal(_withdrawal, _proof) {
            // Verify proof with Groth16 verifier
            if (!WITHDRAWAL_VERIFIER.verifyProof(_proof.pA, _proof.pB, _proof.pC, _proof.pubSignals)) revert InvalidProof();
            // Mark existing commitment nullifier as spent
            _spend(_proof.existingNullifierHash());
            // Insert new commitment in state
            _insert(_proof.newCommitmentHash());
            // Transfer out funds to procesooor
            _push(_withdrawal.processooor, _proof.withdrawnValue());
            emit Withdrawn(
              _withdrawal.processooor, _proof.withdrawnValue(), _proof.existingNullifierHash(), _proof.newCommitmentHash()
            );
          }
          /// @inheritdoc IPrivacyPool
          function ragequit(ProofLib.RagequitProof memory _proof) external {
            // Check if caller is original depositor
            uint256 _label = _proof.label();
            if (depositors[_label] != msg.sender) revert OnlyOriginalDepositor();
            // Verify proof with Groth16 verifier
            if (!RAGEQUIT_VERIFIER.verifyProof(_proof.pA, _proof.pB, _proof.pC, _proof.pubSignals)) revert InvalidProof();
            // Check commitment exists in state
            if (!_isInState(_proof.commitmentHash())) revert InvalidCommitment();
            // Mark existing commitment nullifier as spent
            _spend(_proof.nullifierHash());
            // Transfer out funds to ragequitter
            _push(msg.sender, _proof.value());
            emit Ragequit(msg.sender, _proof.commitmentHash(), _proof.label(), _proof.value());
          }
          /*///////////////////////////////////////////////////////////////
                                     WIND DOWN
          //////////////////////////////////////////////////////////////*/
          /// @inheritdoc IPrivacyPool
          function windDown() external onlyEntrypoint {
            // Check pool is still alive
            if (dead) revert PoolIsDead();
            // Die
            dead = true;
            emit PoolDied();
          }
          /*///////////////////////////////////////////////////////////////
                                  ASSET OVERRIDES
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Handle receiving an asset
           * @dev To be implemented by an asset specific contract
           * @param _sender The address of the user sending funds
           * @param _value The amount of asset being received
           */
          function _pull(address _sender, uint256 _value) internal virtual;
          /**
           * @notice Handle sending an asset
           * @dev To be implemented by an asset specific contract
           * @param _recipient The address of the user receiving funds
           * @param _value The amount of asset being sent
           */
          function _push(address _recipient, uint256 _value) internal virtual;
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        import {ProofLib} from '../contracts/lib/ProofLib.sol';
        import {IState} from 'interfaces/IState.sol';
        /**
         * @title IPrivacyPool
         * @notice Interface for the PrivacyPool contract
         */
        interface IPrivacyPool is IState {
          /*///////////////////////////////////////////////////////////////
                                      STRUCTS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Struct for the withdrawal request
           * @dev The integrity of this data is ensured by the `context` signal in the proof
           * @param processooor The allowed address to process the withdrawal
           * @param data Encoded arbitrary data used by the Entrypoint
           */
          struct Withdrawal {
            address processooor;
            bytes data;
          }
          /*///////////////////////////////////////////////////////////////
                                      EVENTS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Emitted when making a user deposit
           * @param _depositor The address of the depositor
           * @param _commitment The commitment hash
           * @param _label The deposit generated label
           * @param _value The deposited amount
           * @param _precommitmentHash The deposit precommitment hash
           */
          event Deposited(
            address indexed _depositor, uint256 _commitment, uint256 _label, uint256 _value, uint256 _precommitmentHash
          );
          /**
           * @notice Emitted when processing a withdrawal
           * @param _processooor The address which processed the withdrawal
           * @param _value The withdrawn amount
           * @param _spentNullifier The spent nullifier
           * @param _newCommitment The new commitment hash
           */
          event Withdrawn(address indexed _processooor, uint256 _value, uint256 _spentNullifier, uint256 _newCommitment);
          /**
           * @notice Emitted when ragequitting a commitment
           * @param _ragequitter The address who ragequit
           * @param _commitment The ragequit commitment
           * @param _label The commitment label
           * @param _value The ragequit amount
           */
          event Ragequit(address indexed _ragequitter, uint256 _commitment, uint256 _label, uint256 _value);
          /**
           * @notice Emitted irreversibly suspending deposits
           */
          event PoolDied();
          /*///////////////////////////////////////////////////////////////
                                      ERRORS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Thrown when failing to verify a withdrawal proof through the Groth16 verifier
           */
          error InvalidProof();
          /**
           * @notice Thrown when trying to spend a commitment that does not exist in the state
           */
          error InvalidCommitment();
          /**
           * @notice Thrown when calling `withdraw` while not being the allowed processooor
           */
          error InvalidProcessooor();
          /**
           * @notice Thrown when calling `withdraw` with a ASP or state tree depth greater or equal than the max tree depth
           */
          error InvalidTreeDepth();
          /**
           * @notice Thrown when trying to deposit an amount higher than 2**128
           */
          error InvalidDepositValue();
          /**
           * @notice Thrown when providing an invalid scope for this pool
           */
          error ScopeMismatch();
          /**
           * @notice Thrown when providing an invalid context for the pool and withdrawal
           */
          error ContextMismatch();
          /**
           * @notice Thrown when providing an unknown or outdated state root
           */
          error UnknownStateRoot();
          /**
           * @notice Thrown when providing an unknown or outdated ASP root
           */
          error IncorrectASPRoot();
          /**
           * @notice Thrown when trying to ragequit while not being the original depositor
           */
          error OnlyOriginalDepositor();
          /*///////////////////////////////////////////////////////////////
                                      LOGIC
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Deposit funds into the Privacy Pool
           * @dev Only callable by the Entrypoint
           * @param _depositor The depositor address
           * @param _value The value being deposited
           * @param _precommitment The precommitment hash
           * @return _commitment The commitment hash
           */
          function deposit(
            address _depositor,
            uint256 _value,
            uint256 _precommitment
          ) external payable returns (uint256 _commitment);
          /**
           * @notice Privately withdraw funds by spending an existing commitment
           * @param _w The `Withdrawal` struct
           * @param _p The `WithdrawProof` struct
           */
          function withdraw(Withdrawal memory _w, ProofLib.WithdrawProof memory _p) external;
          /**
           * @notice Publicly withdraw funds to original depositor without exposing secrets
           * @dev Only callable by the original depositor
           * @param _p the `RagequitProof` struct
           */
          function ragequit(ProofLib.RagequitProof memory _p) external;
          /**
           * @notice Irreversibly suspends deposits
           * @dev Withdrawals can never be disabled
           * @dev Only callable by the Entrypoint
           */
          function windDown() external;
        }
        /**
         * @title IPrivacyPoolSimple
         * @notice Interface for the PrivacyPool native asset implementation
         */
        interface IPrivacyPoolSimple is IPrivacyPool {
          /*///////////////////////////////////////////////////////////////
                                      ERRORS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Thrown when sending less amount of native asset than required
           */
          error InsufficientValue();
          /**
           * @notice Thrown when failing to send native asset to an account
           */
          error FailedToSendNativeAsset();
        }
        /**
         * @title IPrivacyPoolComplex
         * @notice Interface for the PrivacyPool ERC20 implementation
         */
        interface IPrivacyPoolComplex is IPrivacyPool {
          /*///////////////////////////////////////////////////////////////
                                      ERRORS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Thrown when sending sending any amount of native asset
           */
          error NativeAssetNotAccepted();
          /**
           * @notice Thrown when trying to set up a complex pool with the native asset
           */
          error NativeAssetNotSupported();
        }
        /// SPDX-License-Identifier: MIT
        pragma solidity >=0.7.0;
        library PoseidonT4 {
          uint constant F = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
          uint constant M00 = 0x236d13393ef85cc48a351dd786dd7a1de5e39942296127fd87947223ae5108ad;
          uint constant M01 = 0x2a75a171563b807db525be259699ab28fe9bc7fb1f70943ff049bc970e841a0c;
          uint constant M02 = 0x2070679e798782ef592a52ca9cef820d497ad2eecbaa7e42f366b3e521c4ed42;
          uint constant M03 = 0x2f545e578202c9732488540e41f783b68ff0613fd79375f8ba8b3d30958e7677;
          uint constant M10 = 0x277686494f7644bbc4a9b194e10724eb967f1dc58718e59e3cedc821b2a7ae19;
          uint constant M11 = 0x083abff5e10051f078e2827d092e1ae808b4dd3e15ccc3706f38ce4157b6770e;
          uint constant M12 = 0x2e18c8570d20bf5df800739a53da75d906ece318cd224ab6b3a2be979e2d7eab;
          uint constant M13 = 0x23810bf82877fc19bff7eefeae3faf4bb8104c32ba4cd701596a15623d01476e;
          uint constant M20 = 0x023db68784e3f0cc0b85618826a9b3505129c16479973b0a84a4529e66b09c62;
          uint constant M21 = 0x1a5ad71bbbecd8a97dc49cfdbae303ad24d5c4741eab8b7568a9ff8253a1eb6f;
          uint constant M22 = 0x0fa86f0f27e4d3dd7f3367ce86f684f1f2e4386d3e5b9f38fa283c6aa723b608;
          uint constant M23 = 0x014fcd5eb0be6d5beeafc4944034cf321c068ef930f10be2207ed58d2a34cdd6;
          uint constant M30 = 0x1d359d245f286c12d50d663bae733f978af08cdbd63017c57b3a75646ff382c1;
          uint constant M31 = 0x0d745fd00dd167fb86772133640f02ce945004a7bc2c59e8790f725c5d84f0af;
          uint constant M32 = 0x03f3e6fab791f16628168e4b14dbaeb657035ee3da6b2ca83f0c2491e0b403eb;
          uint constant M33 = 0x00c15fc3a1d5733dd835eae0823e377f8ba4a8b627627cc2bb661c25d20fb52a;
          // 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[3] memory) public pure returns (uint) {
            assembly {
              // memory 0x00 to 0x3f (64 bytes) is scratch space for hash algos
              // we can use it in inline assembly because we're not calling e.g. keccak
              //
              // memory 0x80 is the default offset for free memory
              // we take inputs as a memory argument so we simply write over
              // that memory after loading it
              // we have the following variables at memory offsets
              // state0 - 0x00
              // state1 - 0x20
              // state2 - 0x80
              // state3 - 0xa0
              // state4 - ...
              function pRound(c0, c1, c2, c3) {
                let state0 := add(mload(0x0), c0)
                let state1 := add(mload(0x20), c1)
                let state2 := add(mload(0x80), c2)
                let state3 := add(mload(0xa0), c3)
                let p := mulmod(state0, state0, F)
                state0 := mulmod(mulmod(p, p, F), state0, F)
                mstore(0x0, mod(add(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), mulmod(state3, M30, F)), F))
                mstore(0x20, mod(add(add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)), mulmod(state3, M31, F)), F))
                mstore(0x80, mod(add(add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)), mulmod(state3, M32, F)), F))
                mstore(0xa0, mod(add(add(add(mulmod(state0, M03, F), mulmod(state1, M13, F)), mulmod(state2, M23, F)), mulmod(state3, M33, F)), F))
              }
              function fRound(c0, c1, c2, c3) {
                let state0 := add(mload(0x0), c0)
                let state1 := add(mload(0x20), c1)
                let state2 := add(mload(0x80), c2)
                let state3 := add(mload(0xa0), c3)
                let p := mulmod(state0, state0, F)
                state0 := mulmod(mulmod(p, p, F), state0, F)
                p := mulmod(state1, state1, F)
                state1 := mulmod(mulmod(p, p, F), state1, F)
                p := mulmod(state2, state2, F)
                state2 := mulmod(mulmod(p, p, F), state2, F)
                p := mulmod(state3, state3, F)
                state3 := mulmod(mulmod(p, p, F), state3, F)
                mstore(0x0, mod(add(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), mulmod(state3, M30, F)), F))
                mstore(0x20, mod(add(add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)), mulmod(state3, M31, F)), F))
                mstore(0x80, mod(add(add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)), mulmod(state3, M32, F)), F))
                mstore(0xa0, mod(add(add(add(mulmod(state0, M03, F), mulmod(state1, M13, F)), mulmod(state2, M23, F)), mulmod(state3, M33, F)), F))
              }
              // scratch variable for exponentiation
              let p
              {
                // load the inputs from memory
                let state1 := add(mod(mload(0x80), F), 0x265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d6)
                let state2 := add(mod(mload(0xa0), F), 0x199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aa)
                let state3 := add(mod(mload(0xc0), F), 0x157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf8)
                p := mulmod(state1, state1, F)
                state1 := mulmod(mulmod(p, p, F), state1, F)
                p := mulmod(state2, state2, F)
                state2 := mulmod(mulmod(p, p, F), state2, F)
                p := mulmod(state3, state3, F)
                state3 := mulmod(mulmod(p, p, F), state3, F)
                // state0 pow5mod and M[] multiplications are pre-calculated
                mstore(
                  0x0,
                  mod(add(add(add(0x211184aac7468125da9b5527788aed6331caa8335774fe66f16acc6c66c456d7, mulmod(state1, M10, F)), mulmod(state2, M20, F)), mulmod(state3, M30, F)), F)
                )
                mstore(
                  0x20,
                  mod(add(add(add(0x19764435729b98150ca53b559b7b1bdd91692d645e831f4a30d30d510792687a, mulmod(state1, M11, F)), mulmod(state2, M21, F)), mulmod(state3, M31, F)), F)
                )
                mstore(
                  0x80,
                  mod(add(add(add(0x21f642c132b82c867835f1753eecedd4679085e8c78f6a0ae4a8cd81e9834bdf, mulmod(state1, M12, F)), mulmod(state2, M22, F)), mulmod(state3, M32, F)), F)
                )
                mstore(
                  0xa0,
                  mod(add(add(add(0x26bc2b5c607af61196105d955bd3d9b2cf795edcf9e39d1e508c542ca85d6be3, mulmod(state1, M13, F)), mulmod(state2, M23, F)), mulmod(state3, M33, F)), F)
                )
              }
              fRound(
                0x2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac94902,
                0x0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1e,
                0x251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b996,
                0x13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4e
              )
              fRound(
                0x0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd4738,
                0x011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca06,
                0x0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f367549,
                0x04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789b
              )
              fRound(
                0x0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e8,
                0x259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323f,
                0x28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a1,
                0x0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd6941432447
              )
              pRound(
                0x0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cf,
                0x123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf811,
                0x26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee75,
                0x1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c5
              )
              pRound(
                0x1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d0,
                0x011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e5574,
                0x2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8c,
                0x2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a5
              )
              pRound(
                0x0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951d,
                0x192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527b,
                0x1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d85,
                0x179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfb
              )
              pRound(
                0x29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1c,
                0x225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e08,
                0x064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd59,
                0x10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b87
              )
              pRound(
                0x0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471c,
                0x1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fb,
                0x1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070b,
                0x2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17db
              )
              pRound(
                0x2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd83517926,
                0x062100eb485db06269655cf186a68532985275428450359adc99cec6960711b8,
                0x0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59b,
                0x20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0d
              )
              pRound(
                0x25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5a,
                0x23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4b,
                0x22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e0,
                0x26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce5
              )
              pRound(
                0x070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad9,
                0x12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250da,
                0x248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d729,
                0x1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaa
              )
              pRound(
                0x28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cf,
                0x0094975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7e,
                0x04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d65,
                0x2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde187
              )
              pRound(
                0x2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f3,
                0x03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b0,
                0x00b7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b64,
                0x159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9a
              )
              pRound(
                0x1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431f,
                0x1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30d,
                0x2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33f,
                0x0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb173
              )
              pRound(
                0x02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad16,
                0x0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed705,
                0x0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53a,
                0x22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea9
              )
              pRound(
                0x25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f16,
                0x1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d0,
                0x2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e5,
                0x2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d83505
              )
              pRound(
                0x044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43d,
                0x227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a5319025,
                0x02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a6800355,
                0x0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befac
              )
              pRound(
                0x1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d38,
                0x0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e5,
                0x1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5c,
                0x25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5f
              )
              pRound(
                0x0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75a,
                0x13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a96,
                0x2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391ce,
                0x21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f959
              )
              pRound(
                0x05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185b,
                0x0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a4,
                0x0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bf,
                0x09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f1455
              )
              pRound(
                0x0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd4335,
                0x2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34b,
                0x1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412df,
                0x176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c404
              )
              pRound(
                0x2ef1e0fad9f08e87a3bb5e47d7e33538ca964d2b7d1083d4fb0225035bd3f8db,
                0x226c9b1af95babcf17b2b1f57c7310179c1803dec5ae8f0a1779ed36c817ae2a,
                0x14bce3549cc3db7428126b4c3a15ae0ff8148c89f13fb35d35734eb5d4ad0def,
                0x2debff156e276bb5742c3373f2635b48b8e923d301f372f8e550cfd4034212c7
              )
              pRound(
                0x2d4083cf5a87f5b6fc2395b22e356b6441afe1b6b29c47add7d0432d1d4760c7,
                0x0c225b7bcd04bf9c34b911262fdc9c1b91bf79a10c0184d89c317c53d7161c29,
                0x03152169d4f3d06ec33a79bfac91a02c99aa0200db66d5aa7b835265f9c9c8f3,
                0x0b61811a9210be78b05974587486d58bddc8f51bfdfebbb87afe8b7aa7d3199c
              )
              pRound(
                0x203e000cad298daaf7eba6a5c5921878b8ae48acf7048f16046d637a533b6f78,
                0x1a44bf0937c722d1376672b69f6c9655ba7ee386fda1112c0757143d1bfa9146,
                0x0376b4fae08cb03d3500afec1a1f56acb8e0fde75a2106d7002f59c5611d4daa,
                0x00780af2ca1cad6465a2171250fdfc32d6fc241d3214177f3d553ef363182185
              )
              pRound(
                0x10774d9ab80c25bdeb808bedfd72a8d9b75dbe18d5221c87e9d857079bdc31d5,
                0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e8,
                0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac16,
                0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428c
              )
              pRound(
                0x2840d045e9bc22b259cfb8811b1e0f45b77f7bdb7f7e2b46151a1430f608e3c5,
                0x062752f86eebe11a009c937e468c335b04554574c2990196508e01fa5860186b,
                0x06041bdac48205ac87adb87c20a478a71c9950c12a80bc0a55a8e83eaaf04746,
                0x04a533f236c422d1ff900a368949b0022c7a2ae092f308d82b1dcbbf51f5000d
              )
              pRound(
                0x13e31d7a67232fd811d6a955b3d4f25dfe066d1e7dc33df04bde50a2b2d05b2a,
                0x011c2683ae91eb4dfbc13d6357e8599a9279d1648ff2c95d2f79905bb13920f1,
                0x0b0d219346b8574525b1a270e0b4cba5d56c928e3e2c2bd0a1ecaed015aaf6ae,
                0x14abdec8db9c6dc970291ee638690209b65080781ef9fd13d84c7a726b5f1364
              )
              pRound(
                0x1a0b70b4b26fdc28fcd32aa3d266478801eb12202ef47ced988d0376610be106,
                0x278543721f96d1307b6943f9804e7fe56401deb2ef99c4d12704882e7278b607,
                0x16eb59494a9776cf57866214dbd1473f3f0738a325638d8ba36535e011d58259,
                0x2567a658a81ffb444f240088fa5524c69a9e53eeab6b7f8c41c3479dcf8c644a
              )
              pRound(
                0x29aa1d7c151e9ad0a7ab39f1abd9cf77ab78e0215a5715a6b882ade840bb13d8,
                0x15c091233e60efe0d4bbfce2b36415006a4f017f9a85388ce206b91f99f2c984,
                0x16bd7d22ff858e5e0882c2c999558d77e7673ad5f1915f9feb679a8115f014cf,
                0x02db50480a07be0eb2c2e13ed6ef4074c0182d9b668b8e08ffe6769250042025
              )
              pRound(
                0x05e4a220e6a3bc9f7b6806ec9d6cdba186330ef2bf7adb4c13ba866343b73119,
                0x1dda05ebc30170bc98cbf2a5ee3b50e8b5f70bc424d39fa4104d37f1cbcf7a42,
                0x0184bef721888187f645b6fee3667f3c91da214414d89ba5cd301f22b0de8990,
                0x1498a307e68900065f5e8276f62aef1c37414b84494e1577ad1a6d64341b78ec
              )
              pRound(
                0x25f40f82b31dacc4f4939800b9d2c3eacef737b8fab1f864fe33548ad46bd49d,
                0x09d317cc670251943f6f5862a30d2ea9e83056ce4907bfbbcb1ff31ce5bb9650,
                0x2f77d77786d979b23ba4ce4a4c1b3bd0a41132cd467a86ab29b913b6cf3149d0,
                0x0f53dafd535a9f4473dc266b6fccc6841bbd336963f254c152f89e785f729bbf
              )
              pRound(
                0x25c1fd72e223045265c3a099e17526fa0e6976e1c00baf16de96de85deef2fa2,
                0x2a902c8980c17faae368d385d52d16be41af95c84eaea3cf893e65d6ce4a8f62,
                0x1ce1580a3452ecf302878c8976b82be96676dd114d1dc8d25527405762f83529,
                0x24a6073f91addc33a49a1fa306df008801c5ec569609034d2fc50f7f0f4d0056
              )
              pRound(
                0x25e52dbd6124530d9fc27fe306d71d4583e07ca554b5d1577f256c68b0be2b74,
                0x23dffae3c423fa7a93468dbccfb029855974be4d0a7b29946796e5b6cd70f15d,
                0x06342da370cc0d8c49b77594f6b027c480615d50be36243a99591bc9924ed6f5,
                0x2754114281286546b75f09f115fc751b4778303d0405c1b4cc7df0d8e9f63925
              )
              pRound(
                0x15c19e8534c5c1a8862c2bc1d119eddeabf214153833d7bdb59ee197f8187cf5,
                0x265fe062766d08fab4c78d0d9ef3cabe366f3be0a821061679b4b3d2d77d5f3e,
                0x13ccf689d67a3ec9f22cb7cd0ac3a327d377ac5cd0146f048debfd098d3ec7be,
                0x17662f7456789739f81cd3974827a887d92a5e05bdf3fe6b9fbccca4524aaebd
              )
              pRound(
                0x21b29c76329b31c8ef18631e515f7f2f82ca6a5cca70cee4e809fd624be7ad5d,
                0x18137478382aadba441eb97fe27901989c06738165215319939eb17b01fa975c,
                0x2bc07ea2bfad68e8dc724f5fef2b37c2d34f761935ffd3b739ceec4668f37e88,
                0x2ddb2e376f54d64a563840480df993feb4173203c2bd94ad0e602077aef9a03e
              )
              pRound(
                0x277eb50f2baa706106b41cb24c602609e8a20f8d72f613708adb25373596c3f7,
                0x0d4de47e1aba34269d0c620904f01a56b33fc4b450c0db50bb7f87734c9a1fe5,
                0x0b8442bfe9e4a1b4428673b6bd3eea6f9f445697058f134aae908d0279a29f0c,
                0x11fe5b18fbbea1a86e06930cb89f7d4a26e186a65945e96574247fddb720f8f5
              )
              pRound(
                0x224026f6dfaf71e24d25d8f6d9f90021df5b774dcad4d883170e4ad89c33a0d6,
                0x0b2ca6a999fe6887e0704dad58d03465a96bc9e37d1091f61bc9f9c62bbeb824,
                0x221b63d66f0b45f9d40c54053a28a06b1d0a4ce41d364797a1a7e0c96529f421,
                0x30185c48b7b2f1d53d4120801b047d087493bce64d4d24aedce2f4836bb84ad4
              )
              pRound(
                0x23f5d372a3f0e3cba989e223056227d3533356f0faa48f27f8267318632a61f0,
                0x2716683b32c755fd1bf8235ea162b1f388e1e0090d06162e8e6dfbe4328f3e3b,
                0x0977545836866fa204ca1d853ec0909e3d140770c80ac67dc930c69748d5d4bc,
                0x1444e8f592bdbfd8025d91ab4982dd425f51682d31472b05e81c43c0f9434b31
              )
              pRound(
                0x26e04b65e9ca8270beb74a1c5cb8fee8be3ffbfe583f7012a00f874e7718fbe3,
                0x22a5c2fa860d11fe34ee47a5cd9f869800f48f4febe29ad6df69816fb1a914d2,
                0x174b54d9907d8f5c6afd672a738f42737ec338f3a0964c629f7474dd44c5c8d7,
                0x1db1db8aa45283f31168fa66694cf2808d2189b87c8c8143d56c871907b39b87
              )
              pRound(
                0x1530bf0f46527e889030b8c7b7dfde126f65faf8cce0ab66387341d813d1bfd1,
                0x0b73f613993229f59f01c1cec8760e9936ead9edc8f2814889330a2f2bade457,
                0x29c25a22fe2164604552aaea377f448d587ab977fc8227787bd2dc0f36bcf41e,
                0x2b30d53ed1759bfb8503da66c92cf4077abe82795dc272b377df57d77c875526
              )
              pRound(
                0x12f6d703b5702aab7b7b7e69359d53a2756c08c85ede7227cf5f0a2916787cd2,
                0x2520e18300afda3f61a40a0b8837293a55ad01071028d4841ffa9ac706364113,
                0x1ec9daea860971ecdda8ed4f346fa967ac9bc59278277393c68f09fa03b8b95f,
                0x0a99b3e178db2e2e432f5cd5bef8fe4483bf5cbf70ed407c08aae24b830ad725
              )
              pRound(
                0x07cda9e63db6e39f086b89b601c2bbe407ee0abac3c817a1317abad7c5778492,
                0x08c9c65a4f955e8952d571b191bb0adb49bd8290963203b35d48aab38f8fc3a3,
                0x2737f8ce1d5a67b349590ddbfbd709ed9af54a2a3f2719d33801c9c17bdd9c9e,
                0x1049a6c65ff019f0d28770072798e8b7909432bd0c129813a9f179ba627f7d6a
              )
              pRound(
                0x18b4fe968732c462c0ea5a9beb27cecbde8868944fdf64ee60a5122361daeddb,
                0x2ff2b6fd22df49d2440b2eaeeefa8c02a6f478cfcf11f1b2a4f7473483885d19,
                0x2ec5f2f1928fe932e56c789b8f6bbcb3e8be4057cbd8dbd18a1b352f5cef42ff,
                0x265a5eccd8b92975e33ad9f75bf3426d424a4c6a7794ee3f08c1d100378e545e
              )
              pRound(
                0x2405eaa4c0bde1129d6242bb5ada0e68778e656cfcb366bf20517da1dfd4279c,
                0x094c97d8c194c42e88018004cbbf2bc5fdb51955d8b2d66b76dd98a2dbf60417,
                0x2c30d5f33bb32c5c22b9979a605bf64d508b705221e6a686330c9625c2afe0b8,
                0x01a75666f6241f6825d01cc6dcb1622d4886ea583e87299e6aa2fc716fdb6cf5
              )
              pRound(
                0x0a3290e8398113ea4d12ac091e87be7c6d359ab9a66979fcf47bf2e87d382fcb,
                0x154ade9ca36e268dfeb38461425bb0d8c31219d8fa0dfc75ecd21bf69aa0cc74,
                0x27aa8d3e25380c0b1b172d79c6f22eee99231ef5dc69d8dc13a4b5095d028772,
                0x2cf4051e6cab48301a8b2e3bca6099d756bbdf485afa1f549d395bbcbd806461
              )
              pRound(
                0x301e70f729f3c94b1d3f517ddff9f2015131feab8afa5eebb0843d7f84b23e71,
                0x298beb64f812d25d8b4d9620347ab02332dc4cef113ae60d17a8d7a4c91f83bc,
                0x1b362e72a5f847f84d03fd291c3c471ed1c14a15b221680acf11a3f02e46aa95,
                0x0dc8a2146110c0b375432902999223d5aa1ef6e78e1e5ebcbc1d9ba41dc1c737
              )
              pRound(
                0x0a48663b34ce5e1c05dc93092cb69778cb21729a72ddc03a08afa1eb922ff279,
                0x0a87391fb1cd8cdf6096b64a82f9e95f0fe46f143b702d74545bb314881098ee,
                0x1b5b2946f7c28975f0512ff8e6ca362f8826edd7ea9c29f382ba8a2a0892fd5d,
                0x01001cf512ac241d47ebe2239219bc6a173a8bbcb8a5b987b4eac1f533315b6b
              )
              pRound(
                0x2fd977c70f645db4f704fa7d7693da727ac093d3fb5f5febc72beb17d8358a32,
                0x23c0039a3fab4ad3c2d7cc688164f39e761d5355c05444d99be763a97793a9c4,
                0x19d43ee0c6081c052c9c0df6161eaac1aec356cf435888e79f27f22ff03fa25d,
                0x2d9b10c2f2e7ac1afddccffd94a563028bf29b646d020830919f9d5ca1cefe59
              )
              pRound(
                0x2457ca6c2f2aa30ec47e4aff5a66f5ce2799283e166fc81cdae2f2b9f83e4267,
                0x0abc392fe85eda855820592445094022811ee8676ed6f0c3044dfb54a7c10b35,
                0x19d2cc5ca549d1d40cebcd37f3ea54f31161ac3993acf3101d2c2bc30eac1eb0,
                0x0f97ae3033ffa01608aafb26ae13cd393ee0e4ec041ba644a3d3ab546e98c9c8
              )
              pRound(
                0x16dbc78fd28b7fb8260e404cf1d427a7fa15537ea4e168e88a166496e88cfeca,
                0x240faf28f11499b916f085f73bc4f22eef8344e576f8ad3d1827820366d5e07b,
                0x0a1bb075aa37ff0cfe6c8531e55e1770eaba808c8fdb6dbf46f8cab58d9ef1af,
                0x2e47e15ea4a47ff1a6a853aaf3a644ca38d5b085ac1042fdc4a705a7ce089f4d
              )
              pRound(
                0x166e5bf073378348860ca4a9c09d39e1673ab059935f4df35fb14528375772b6,
                0x18b42d7ffdd2ea4faf235902f057a2740cacccd027233001ed10f96538f0916f,
                0x089cb1b032238f5e4914788e3e3c7ead4fc368020b3ed38221deab1051c37702,
                0x242acd3eb3a2f72baf7c7076dd165adf89f9339c7b971921d9e70863451dd8d1
              )
              pRound(
                0x174fbb104a4ee302bf47f2bd82fce896eac9a068283f326474af860457245c3b,
                0x17340e71d96f466d61f3058ce092c67d2891fb2bb318613f780c275fe1116c6b,
                0x1e8e40ac853b7d42f00f2e383982d024f098b9f8fd455953a2fd380c4df7f6b2,
                0x0529898dc0649907e1d4d5e284b8d1075198c55cad66e8a9bf40f92938e2e961
              )
              pRound(
                0x2162754db0baa030bf7de5bb797364dce8c77aa017ee1d7bf65f21c4d4e5df8f,
                0x12c7553698c4bf6f3ceb250ae00c58c2a9f9291efbde4c8421bef44741752ec6,
                0x292643e3ba2026affcb8c5279313bd51a733c93353e9d9c79cb723136526508e,
                0x00ccf13e0cb6f9d81d52951bea990bd5b6c07c5d98e66ff71db6e74d5b87d158
              )
              pRound(
                0x185d1e20e23b0917dd654128cf2f3aaab6723873cb30fc22b0f86c15ab645b4b,
                0x14c61c836d55d3df742bdf11c60efa186778e3de0f024c0f13fe53f8d8764e1f,
                0x0f356841b3f556fce5dbe4680457691c2919e2af53008184d03ee1195d72449e,
                0x1b8fd9ff39714e075df124f887bf40b383143374fd2080ba0c0a6b6e8fa5b3e8
              )
              pRound(
                0x0e86a8c2009c140ca3f873924e2aaa14fc3c8ae04e9df0b3e9103418796f6024,
                0x2e6c5e898f5547770e5462ad932fcdd2373fc43820ca2b16b0861421e79155c8,
                0x05d797f1ab3647237c14f9d1df032bc9ff9fe1a0ecd377972ce5fd5a0c014604,
                0x29a3110463a5aae76c3d152875981d0c1daf2dcd65519ef5ca8929851da8c008
              )
              pRound(
                0x2974da7bc074322273c3a4b91c05354cdc71640a8bbd1f864b732f8163883314,
                0x1ed0fb06699ba249b2a30621c05eb12ca29cb91aa082c8bfcce9c522889b47dc,
                0x1c793ef0dcc51123654ff26d8d863feeae29e8c572eca912d80c8ae36e40fe9b,
                0x1e6aac1c6d3dd3157956257d3d234ef18c91e82589a78169fbb4a8770977dc2f
              )
              pRound(
                0x1a20ada7576234eee6273dd6fa98b25ed037748080a47d948fcda33256fb6bf5,
                0x191033d6d85ceaa6fc7a9a23a6fd9996642d772045ece51335d49306728af96c,
                0x006e5979da7e7ef53a825aa6fddc3abfc76f200b3740b8b232ef481f5d06297b,
                0x0b0d7e69c651910bbef3e68d417e9fa0fbd57f596c8f29831eff8c0174cdb06d
              )
              pRound(
                0x25caf5b0c1b93bc516435ec084e2ecd44ac46dbbb033c5112c4b20a25c9cdf9d,
                0x12c1ea892cc31e0d9af8b796d9645872f7f77442d62fd4c8085b2f150f72472a,
                0x16af29695157aba9b8bbe3afeb245feee5a929d9f928b9b81de6dadc78c32aae,
                0x0136df457c80588dd687fb2f3be18691705b87ec5a4cfdc168d31084256b67dc
              )
              pRound(
                0x1639a28c5b4c81166aea984fba6e71479e07b1efbc74434db95a285060e7b089,
                0x03d62fbf82fd1d4313f8e650f587ec06816c28b700bdc50f7e232bd9b5ca9b76,
                0x11aeeb527dc8ce44b4d14aaddca3cfe2f77a1e40fc6da97c249830de1edfde54,
                0x13f9b9a41274129479c5e6138c6c8ee36a670e6bc68c7a49642b645807bfc824
              )
              fRound(
                0x0e4772fa3d75179dc8484cd26c7c1f635ddeeed7a939440c506cae8b7ebcd15b,
                0x1b39a00cbc81e427de4bdec58febe8d8b5971752067a612b39fc46a68c5d4db4,
                0x2bedb66e1ad5a1d571e16e2953f48731f66463c2eb54a245444d1c0a3a25707e,
                0x2cf0a09a55ca93af8abd068f06a7287fb08b193b608582a27379ce35da915dec
              )
              fRound(
                0x2d1bd78fa90e77aa88830cabfef2f8d27d1a512050ba7db0753c8fb863efb387,
                0x065610c6f4f92491f423d3071eb83539f7c0d49c1387062e630d7fd283dc3394,
                0x2d933ff19217a5545013b12873452bebcc5f9969033f15ec642fb464bd607368,
                0x1aa9d3fe4c644910f76b92b3e13b30d500dae5354e79508c3c49c8aa99e0258b
              )
              fRound(
                0x027ef04869e482b1c748638c59111c6b27095fa773e1aca078cea1f1c8450bdd,
                0x2b7d524c5172cbbb15db4e00668a8c449f67a2605d9ec03802e3fa136ad0b8fb,
                0x0c7c382443c6aa787c8718d86747c7f74693ae25b1e55df13f7c3c1dd735db0f,
                0x00b4567186bc3f7c62a7b56acf4f76207a1f43c2d30d0fe4a627dcdd9bd79078
              )
              {
                let state0 := add(mload(0x0), 0x1e41fc29b825454fe6d61737fe08b47fb07fe739e4c1e61d0337490883db4fd5)
                let state1 := add(mload(0x20), 0x12507cd556b7bbcc72ee6dafc616584421e1af872d8c0e89002ae8d3ba0653b6)
                let state2 := add(mload(0x80), 0x13d437083553006bcef312e5e6f52a5d97eb36617ef36fe4d77d3e97f71cb5db)
                let state3 := add(mload(0xa0), 0x163ec73251f85443687222487dda9a65467d90b22f0b38664686077c6a4486d5)
                p := mulmod(state0, state0, F)
                state0 := mulmod(mulmod(p, p, F), state0, F)
                p := mulmod(state1, state1, F)
                state1 := mulmod(mulmod(p, p, F), state1, F)
                p := mulmod(state2, state2, F)
                state2 := mulmod(mulmod(p, p, F), state2, F)
                p := mulmod(state3, state3, F)
                state3 := mulmod(mulmod(p, p, F), state3, F)
                mstore(0x0, mod(mod(add(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), mulmod(state3, M30, F)), F), F))
                return(0, 0x20)
              }
            }
          }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        /**
         * @title ProofLib
         * @notice Facilitates accessing the public signals of a Groth16 proof.
         * @custom:semver 0.1.0
         */
        library ProofLib {
          /*///////////////////////////////////////////////////////////////
                                 WITHDRAWAL PROOF 
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Struct containing Groth16 proof elements and public signals for withdrawal verification
           * @dev The public signals array must match the order of public inputs/outputs in the circuit
           * @param pA First elliptic curve point (π_A) of the Groth16 proof, encoded as two field elements
           * @param pB Second elliptic curve point (π_B) of the Groth16 proof, encoded as 2x2 matrix of field elements
           * @param pC Third elliptic curve point (π_C) of the Groth16 proof, encoded as two field elements
           * @param pubSignals Array of public inputs and outputs:
           *        - [0] newCommitmentHash: Hash of the new commitment being created
           *        - [1] existingNullifierHash: Hash of the nullifier being spent
           *        - [2] withdrawnValue: Amount being withdrawn
           *        - [3] stateRoot: Current state root of the privacy pool
           *        - [4] stateTreeDepth: Current depth of the state tree
           *        - [5] ASPRoot: Current root of the Association Set Provider tree
           *        - [6] ASPTreeDepth: Current depth of the ASP tree
           *        - [7] context: Context value for the withdrawal operation
           */
          struct WithdrawProof {
            uint256[2] pA;
            uint256[2][2] pB;
            uint256[2] pC;
            uint256[8] pubSignals;
          }
          /**
           * @notice Retrieves the new commitment hash from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The hash of the new commitment being created
           */
          function newCommitmentHash(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[0];
          }
          /**
           * @notice Retrieves the existing nullifier hash from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The hash of the nullifier being spent in this withdrawal
           */
          function existingNullifierHash(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[1];
          }
          /**
           * @notice Retrieves the withdrawn value from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The amount being withdrawn from Privacy Pool
           */
          function withdrawnValue(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[2];
          }
          /**
           * @notice Retrieves the state root from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The root of the state tree at time of proof generation
           */
          function stateRoot(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[3];
          }
          /**
           * @notice Retrieves the state tree depth from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The depth of the state tree at time of proof generation
           */
          function stateTreeDepth(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[4];
          }
          /**
           * @notice Retrieves the ASP root from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The latest root of the ASP tree at time of proof generation
           */
          function ASPRoot(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[5];
          }
          /**
           * @notice Retrieves the ASP tree depth from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The depth of the ASP tree at time of proof generation
           */
          function ASPTreeDepth(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[6];
          }
          /**
           * @notice Retrieves the context value from the proof's public signals
           * @param _p The proof containing the public signals
           * @return The context value binding the proof to specific withdrawal data
           */
          function context(WithdrawProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[7];
          }
          /*///////////////////////////////////////////////////////////////
                                  RAGEQUIT PROOF 
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Struct containing Groth16 proof elements and public signals for ragequit verification
           * @dev The public signals array must match the order of public inputs/outputs in the circuit
           * @param pA First elliptic curve point (π_A) of the Groth16 proof, encoded as two field elements
           * @param pB Second elliptic curve point (π_B) of the Groth16 proof, encoded as 2x2 matrix of field elements
           * @param pC Third elliptic curve point (π_C) of the Groth16 proof, encoded as two field elements
           * @param pubSignals Array of public inputs and outputs:
           *        - [0] commitmentHash: Hash of the commitment being ragequit
           *        - [1] nullifierHash: Nullifier hash of commitment being ragequit
           *        - [2] value: Value of the commitment being ragequit
           *        - [3] label: Label of commitment
           */
          struct RagequitProof {
            uint256[2] pA;
            uint256[2][2] pB;
            uint256[2] pC;
            uint256[4] pubSignals;
          }
          /**
           * @notice Retrieves the new commitment hash from the proof's public signals
           * @param _p The ragequit proof containing the public signals
           * @return The new commitment hash
           */
          function commitmentHash(RagequitProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[0];
          }
          /**
           * @notice Retrieves the nullifier hash from the proof's public signals
           * @param _p The ragequit proof containing the public signals
           * @return The nullifier hash
           */
          function nullifierHash(RagequitProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[1];
          }
          /**
           * @notice Retrieves the commitment value from the proof's public signals
           * @param _p The ragequit proof containing the public signals
           * @return The commitment value
           */
          function value(RagequitProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[2];
          }
          /**
           * @notice Retrieves the commitment label from the proof's public signals
           * @param _p The ragequit proof containing the public signals
           * @return The commitment label
           */
          function label(RagequitProof memory _p) internal pure returns (uint256) {
            return _p.pubSignals[3];
          }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        /*
        Made with ♥ for 0xBow by
        ░██╗░░░░░░░██╗░█████╗░███╗░░██╗██████╗░███████╗██████╗░██╗░░░░░░█████╗░███╗░░██╗██████╗░
        ░██║░░██╗░░██║██╔══██╗████╗░██║██╔══██╗██╔════╝██╔══██╗██║░░░░░██╔══██╗████╗░██║██╔══██╗
        ░╚██╗████╗██╔╝██║░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██║░░░░░███████║██╔██╗██║██║░░██║
        ░░████╔═████║░██║░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██║░░░░░██╔══██║██║╚████║██║░░██║
        ░░╚██╔╝░╚██╔╝░╚█████╔╝██║░╚███║██████╔╝███████╗██║░░██║███████╗██║░░██║██║░╚███║██████╔╝
        ░░░╚═╝░░░╚═╝░░░╚════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═╝░░╚══╝╚═════╝░
        https://defi.sucks
        */
        import {Constants} from './lib/Constants.sol';
        import {InternalLeanIMT, LeanIMTData} from 'lean-imt/InternalLeanIMT.sol';
        import {IEntrypoint} from 'interfaces/IEntrypoint.sol';
        import {IState} from 'interfaces/IState.sol';
        import {IVerifier} from 'interfaces/IVerifier.sol';
        /**
         * @title State
         * @notice Base contract for the managing the state of a Privacy Pool
         * @custom:semver 0.1.0
         */
        abstract contract State is IState {
          using InternalLeanIMT for LeanIMTData;
          /// @inheritdoc IState
          uint32 public constant ROOT_HISTORY_SIZE = 64;
          /// @inheritdoc IState
          uint32 public constant MAX_TREE_DEPTH = 32;
          /// @inheritdoc IState
          address public immutable ASSET;
          /// @inheritdoc IState
          uint256 public immutable SCOPE;
          /// @inheritdoc IState
          IEntrypoint public immutable ENTRYPOINT;
          /// @inheritdoc IState
          IVerifier public immutable WITHDRAWAL_VERIFIER;
          /// @inheritdoc IState
          IVerifier public immutable RAGEQUIT_VERIFIER;
          /// @inheritdoc IState
          uint256 public nonce;
          /// @inheritdoc IState
          bool public dead;
          /// @inheritdoc IState
          mapping(uint256 _index => uint256 _root) public roots;
          /// @inheritdoc IState
          uint32 public currentRootIndex;
          // @notice The state merkle tree containing all commitments
          LeanIMTData internal _merkleTree;
          /// @inheritdoc IState
          mapping(uint256 _nullifierHash => bool _spent) public nullifierHashes;
          /// @inheritdoc IState
          mapping(uint256 _label => address _depositooor) public depositors;
          /**
           * @notice Check the caller is the Entrypoint
           */
          modifier onlyEntrypoint() {
            if (msg.sender != address(ENTRYPOINT)) revert OnlyEntrypoint();
            _;
          }
          /**
           * @notice Initialize the state addresses
           */
          constructor(address _asset, address _entrypoint, address _withdrawalVerifier, address _ragequitVerifier) {
            // Sanitize initial addresses
            if (_asset == address(0)) revert ZeroAddress();
            if (_entrypoint == address(0)) revert ZeroAddress();
            if (_ragequitVerifier == address(0)) revert ZeroAddress();
            if (_withdrawalVerifier == address(0)) revert ZeroAddress();
            // Store asset address
            ASSET = _asset;
            // Compute SCOPE
            SCOPE = uint256(keccak256(abi.encodePacked(address(this), block.chainid, _asset))) % Constants.SNARK_SCALAR_FIELD;
            ENTRYPOINT = IEntrypoint(_entrypoint);
            WITHDRAWAL_VERIFIER = IVerifier(_withdrawalVerifier);
            RAGEQUIT_VERIFIER = IVerifier(_ragequitVerifier);
          }
          /*///////////////////////////////////////////////////////////////
                                      VIEWS
          //////////////////////////////////////////////////////////////*/
          /// @inheritdoc IState
          function currentRoot() external view returns (uint256 _root) {
            _root = _merkleTree._root();
          }
          /// @inheritdoc IState
          function currentTreeDepth() external view returns (uint256 _depth) {
            _depth = _merkleTree.depth;
          }
          /// @inheritdoc IState
          function currentTreeSize() external view returns (uint256 _size) {
            _size = _merkleTree.size;
          }
          /*///////////////////////////////////////////////////////////////
                                INTERNAL METHODS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Spends a nullifier hash
           * @param _nullifierHash The nullifier hash to spend
           */
          function _spend(uint256 _nullifierHash) internal {
            // Check if the nullifier is already spent
            if (nullifierHashes[_nullifierHash]) revert NullifierAlreadySpent();
            // Mark as spent
            nullifierHashes[_nullifierHash] = true;
          }
          /**
           * @notice Insert a leaf into the state
           * @param _leaf The leaf to insert
           * @return _updatedRoot The new root after inserting the leaf
           */
          function _insert(uint256 _leaf) internal returns (uint256 _updatedRoot) {
            // Insert leaf in the tree
            _updatedRoot = _merkleTree._insert(_leaf);
            if (_merkleTree.depth > MAX_TREE_DEPTH) revert MaxTreeDepthReached();
            // Calculate the next index
            uint32 nextIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
            // Store the root at the next index
            roots[nextIndex] = _updatedRoot;
            // Update currentRootIndex to point to the latest root
            currentRootIndex = nextIndex;
            emit LeafInserted(_merkleTree.size, _leaf, _updatedRoot);
          }
          /**
           * @notice Returns whether the root is a known root
           * @dev A circular buffer is used for root storage to decrease the cost of storing new roots
           * @dev Optimized to start search from most recent roots, improving average case performance
           * @param _root The root to check
           * @return Returns true if the root exists in the history, false otherwise
           */
          function _isKnownRoot(uint256 _root) internal view returns (bool) {
            if (_root == 0) return false;
            // Start from the most recent root (current index)
            uint32 _index = currentRootIndex;
            // Check all possible roots in the history
            for (uint32 _i = 0; _i < ROOT_HISTORY_SIZE; _i++) {
              if (_root == roots[_index]) return true;
              _index = (_index + ROOT_HISTORY_SIZE - 1) % ROOT_HISTORY_SIZE;
            }
            return false;
          }
          /**
           * @notice Returns whether a leaf is in the state
           * @param _leaf The leaf to check
           * @return Returns true if the leaf exists in the tree, false otherwise
           */
          function _isInState(uint256 _leaf) internal view returns (bool) {
            return _merkleTree._has(_leaf);
          }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        import {IEntrypoint} from 'interfaces/IEntrypoint.sol';
        import {IVerifier} from 'interfaces/IVerifier.sol';
        /**
         * @title IState
         * @notice Interface for the State contract
         */
        interface IState {
          /*///////////////////////////////////////////////////////////////
                                      EVENTS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Emitted when inserting a leaf into the Merkle Tree
           * @param _index The index of the leaf in the tree
           * @param _leaf The leaf value
           * @param _root The updated root
           */
          event LeafInserted(uint256 _index, uint256 _leaf, uint256 _root);
          /*///////////////////////////////////////////////////////////////
                                      ERRORS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Thrown when trying to call a method only available to the Entrypoint
           */
          error OnlyEntrypoint();
          /**
           * @notice Thrown when trying to deposit into a dead pool
           */
          error PoolIsDead();
          /**
           * @notice Thrown when trying to spend a nullifier that has already been spent
           */
          error NullifierAlreadySpent();
          /**
           * @notice Thrown when trying to initiate the ragequitting process of a commitment before the waiting period
           */
          error NotYetRagequitteable();
          /**
           * @notice Thrown when the max tree depth is reached and no more commitments can be inserted
           */
          error MaxTreeDepthReached();
          /**
           * @notice Thrown when trying to set a state variable as address zero
           */
          error ZeroAddress();
          /*///////////////////////////////////////////////////////////////
                                      VIEWS 
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Returns the pool unique identifier
           * @return _scope The scope id
           */
          function SCOPE() external view returns (uint256 _scope);
          /**
           * @notice Returns the pool asset
           * @return _asset The asset address
           */
          function ASSET() external view returns (address _asset);
          /**
           * @notice Returns the root history size for root caching
           * @return _size The amount of valid roots to store
           */
          function ROOT_HISTORY_SIZE() external view returns (uint32 _size);
          /**
           * @notice Returns the maximum depth of the state tree
           * @dev Merkle tree depth must be capped at a fixed maximum because zero-knowledge circuits
           * compile to R1CS (Rank-1 Constraint System) constraints that must be determined at compile time.
           * R1CS cannot handle dynamic loops or recursion - all computation paths must be fully "unrolled"
           * into a fixed number of constraints. Since each level of the Merkle tree requires its own set
           * of constraints for hashing and path verification, we need to set a maximum depth that determines
           * the total constraint size of the circuit.
           * @return _maxDepth The max depth
           */
          function MAX_TREE_DEPTH() external view returns (uint32 _maxDepth);
          /**
           * @notice Returns the configured Entrypoint contract
           * @return _entrypoint The Entrypoint contract
           */
          function ENTRYPOINT() external view returns (IEntrypoint _entrypoint);
          /**
           * @notice Returns the configured Verifier contract for withdrawals
           * @return _verifier The Verifier contract
           */
          function WITHDRAWAL_VERIFIER() external view returns (IVerifier _verifier);
          /**
           * @notice Returns the configured Verifier contract for ragequits
           * @return _verifier The Verifier contract
           */
          function RAGEQUIT_VERIFIER() external view returns (IVerifier _verifier);
          /**
           * @notice Returns the current root index
           * @return _index The current index
           */
          function currentRootIndex() external view returns (uint32 _index);
          /**
           * @notice Returns the current state root
           * @return _root The current state root
           */
          function currentRoot() external view returns (uint256 _root);
          /**
           * @notice Returns the current state tree depth
           * @return _depth The current state tree depth
           */
          function currentTreeDepth() external view returns (uint256 _depth);
          /**
           * @notice Returns the current state tree size
           * @return _size The current state tree size
           */
          function currentTreeSize() external view returns (uint256 _size);
          /**
           * @notice Returns the current label nonce
           * @return _nonce The current nonce
           */
          function nonce() external view returns (uint256 _nonce);
          /**
           * @notice Returns the boolean indicating if the pool is dead
           * @return _dead The dead boolean
           */
          function dead() external view returns (bool _dead);
          /**
           * @notice Returns the root stored at an index
           * @param _index The root index
           * @return _root The root value
           */
          function roots(uint256 _index) external view returns (uint256 _root);
          /**
           * @notice Returns the spending status of a nullifier hash
           * @param _nullifierHash The nullifier hash
           * @return _spent The boolean indicating if it is spent
           */
          function nullifierHashes(uint256 _nullifierHash) external view returns (bool _spent);
          /**
           * @notice Returns the original depositor that generated a label
           * @param _label The label
           * @return _depositor The original depositor
           */
          function depositors(uint256 _label) external view returns (address _depositor);
        }
        // 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();
                            }
                            node = PoseidonT3.hash([node, siblingNodes[i]]);
                            oldRoot = PoseidonT3.hash([oldRoot, siblingNodes[i]]);
                            unchecked {
                                ++i;
                            }
                        } else {
                            self.sideNodes[i] = 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];
            }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        import {IERC20} from '@oz/interfaces/IERC20.sol';
        import {ProofLib} from '../contracts/lib/ProofLib.sol';
        import {IPrivacyPool} from 'interfaces/IPrivacyPool.sol';
        /**
         * @title IEntrypoint
         * @notice Interface for the Entrypoint contract
         */
        interface IEntrypoint {
          /*///////////////////////////////////////////////////////////////
                                      STRUCTS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Struct for the asset configuration
           * @param pool The Privacy Pool contracts for the asset
           * @param minimumDepositAmount The minimum amount that can be deposited
           * @param vettingfeeBPS The deposit fee in basis points
           */
          struct AssetConfig {
            IPrivacyPool pool;
            uint256 minimumDepositAmount;
            uint256 vettingFeeBPS;
            uint256 maxRelayFeeBPS;
          }
          /**
           * @notice Struct for the relay data
           * @param recipient The recipient of the funds withdrawn from the pool
           * @param feeRecipient The recipient of the fee
           * @param relayfeeBPS The relay fee in basis points
           */
          struct RelayData {
            address recipient;
            address feeRecipient;
            uint256 relayFeeBPS;
          }
          /**
           * @notice Struct for the onchain association set data
           * @param root The ASP root
           * @param ipfsCID The IPFS v1 CID of the ASP data. A content-addressed identifier computed by hashing
           *                the content with SHA-256, adding multicodec/multihash prefixes, and encoding in base32/58.
           *                This uniquely identifies data by its content rather than location.
           * @param timestamp The timestamp on which the root was updated
           */
          struct AssociationSetData {
            uint256 root;
            string ipfsCID;
            uint256 timestamp;
          }
          /*///////////////////////////////////////////////////////////////
                                      EVENTS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Emitted when pushing a new root to the association root set
           * @param _root The latest ASP root
           * @param _ipfsCID The IPFS CID of the association set data
           * @param _timestamp The timestamp of root update
           */
          event RootUpdated(uint256 _root, string _ipfsCID, uint256 _timestamp);
          /**
           * @notice Emitted when pushing a new root to the association root set
           * @param _depositor The address of the depositor
           * @param _pool The Privacy Pool contract
           * @param _commitment The commitment hash for the deposit
           * @param _amount The amount of asset deposited
           */
          event Deposited(address indexed _depositor, IPrivacyPool indexed _pool, uint256 _commitment, uint256 _amount);
          /**
           * @notice Emitted when processing a withdrawal through the Entrypoint
           * @param _relayer The address of the relayer
           * @param _recipient The address of the withdrawal recipient
           * @param _asset The asset being withdrawn
           * @param _amount The amount of asset withdrawn
           * @param _feeAmount The fee paid to the relayer
           */
          event WithdrawalRelayed(
            address indexed _relayer, address indexed _recipient, IERC20 indexed _asset, uint256 _amount, uint256 _feeAmount
          );
          /**
           * @notice Emitted when withdrawing fees from the Entrypoint
           * @param _asset The asset being withdrawn
           * @param _recipient The address of the fees withdrawal recipient
           * @param _amount The amount of asset withdrawn
           */
          event FeesWithdrawn(IERC20 _asset, address _recipient, uint256 _amount);
          /**
           * @notice Emitted when winding down a Privacy Pool
           * @param _pool The Privacy Pool contract
           */
          event PoolWindDown(IPrivacyPool _pool);
          /**
           * @notice Emitted when registering a Privacy Pool in the Entrypoint registry
           * @param _pool The Privacy Pool contract
           * @param _asset The asset of the pool
           * @param _scope The unique scope of the pool
           */
          event PoolRegistered(IPrivacyPool _pool, IERC20 _asset, uint256 _scope);
          /**
           * @notice Emitted when removing a Privacy Pool from the Entrypoint registry
           * @param _pool The Privacy Pool contract
           * @param _asset The asset of the pool
           * @param _scope The unique scope of the pool
           */
          event PoolRemoved(IPrivacyPool _pool, IERC20 _asset, uint256 _scope);
          /**
           * @notice Emitted when updating the configuration of a Privacy Pool
           * @param _pool The Privacy Pool contract
           * @param _asset The asset of the pool
           * @param _newMinimumDepositAmount The updated minimum deposit amount
           * @param _newVettingFeeBPS The updated vetting fee in basis points
           * @param _newMaxRelayFeeBPS The updated maximum relay fee in basis points
           */
          event PoolConfigurationUpdated(
            IPrivacyPool _pool,
            IERC20 _asset,
            uint256 _newMinimumDepositAmount,
            uint256 _newVettingFeeBPS,
            uint256 _newMaxRelayFeeBPS
          );
          /*///////////////////////////////////////////////////////////////
                                      ERRORS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Thrown when trying to withdraw an invalid amount
           */
          error InvalidWithdrawalAmount();
          /**
           * @notice Thrown when trying to access a non-existent pool
           */
          error PoolNotFound();
          /**
           * @notice Thrown when trying to register a dead pool
           */
          error PoolIsDead();
          /**
           * @notice Thrown when trying to register a pool whose configured Entrypoint is not this one
           */
          error InvalidEntrypointForPool();
          /**
           * @notice Thrown when trying to register a pool for an asset that is already present in the registry
           */
          error AssetPoolAlreadyRegistered();
          /**
           * @notice Thrown when trying to register a pool for a scope that is already present in the registry
           */
          error ScopePoolAlreadyRegistered();
          /**
           * @notice Thrown when trying to deposit less than the minimum deposit amount
           */
          error MinimumDepositAmount();
          /**
           * @notice Thrown when trying to relay with a relayer fee greater than the maximum configured
           */
          error RelayFeeGreaterThanMax();
          /**
           * @notice Thrown when trying to process a withdrawal with an invalid processooor
           */
          error InvalidProcessooor();
          /**
           * @notice Thrown when finding an invalid state in the pool like an invalid asset balance
           */
          error InvalidPoolState();
          /**
           * @notice Thrown when trying to push a an IPFS CID with an invalid length
           */
          error InvalidIPFSCIDLength();
          /**
           * @notice Thrown when trying to push a root with an empty root
           */
          error EmptyRoot();
          /**
           * @notice Thrown when failing to send the native asset to an account
           */
          error NativeAssetTransferFailed();
          /**
           * @notice Thrown when an address parameter is zero
           */
          error ZeroAddress();
          /**
           * @notice Thrown when a fee in basis points is greater than 10000 (100%)
           */
          error InvalidFeeBPS();
          /**
           * @notice Thrown when trying to access an association set at an invalid index
           */
          error InvalidIndex();
          /**
           * @notice Thrown when trying to get the latest root when no roots exist
           */
          error NoRootsAvailable();
          /**
           * @notice Thrown when trying to register a pool with an asset that doesn't match the pool's asset
           */
          error AssetMismatch();
          /**
           * @notice Thrown when trying to send native asset to the Entrypoint
           */
          error NativeAssetNotAccepted();
          /*//////////////////////////////////////////////////////////////
                                        LOGIC
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Initializes the contract state
           * @param _owner The initial owner
           * @param _postman The initial postman
           */
          function initialize(address _owner, address _postman) external;
          /**
           * @notice Push a new root to the association root set
           * @param _root The new ASP root
           * @param _ipfsCID The IPFS v1 CID of the association set data
           * @return _index The index of the newly added root
           */
          function updateRoot(uint256 _root, string memory _ipfsCID) external returns (uint256 _index);
          /**
           * @notice Make a native asset deposit into the Privacy Pool
           * @param _precommitment The precommitment for the deposit
           * @return _commitment The deposit commitment hash
           */
          function deposit(uint256 _precommitment) external payable returns (uint256 _commitment);
          /**
           * @notice Make an ERC20 deposit into the Privacy Pool
           * @param _asset The asset to deposit
           * @param _value The amount of asset to deposit
           * @param _precommitment The precommitment for the deposit
           * @return _commitment The deposit commitment hash
           */
          function deposit(IERC20 _asset, uint256 _value, uint256 _precommitment) external returns (uint256 _commitment);
          /**
           * @notice Process a withdrawal
           * @param _withdrawal The `Withdrawal` struct
           * @param _proof The `WithdrawProof` struct containing the withdarawal proof signals
           * @param _scope The Pool scope to withdraw from
           */
          function relay(
            IPrivacyPool.Withdrawal calldata _withdrawal,
            ProofLib.WithdrawProof calldata _proof,
            uint256 _scope
          ) external;
          /**
           * @notice Register a Privacy Pool in the registry
           * @param _asset The asset of the pool
           * @param _pool The address of the Privacy Pool contract
           * @param _minimumDepositAmount The minimum deposit amount for the asset
           * @param _vettingFeeBPS The deposit fee in basis points
           * @param _maxRelayFeeBPS The maximum relay fee in basis points
           */
          function registerPool(
            IERC20 _asset,
            IPrivacyPool _pool,
            uint256 _minimumDepositAmount,
            uint256 _vettingFeeBPS,
            uint256 _maxRelayFeeBPS
          ) external;
          /**
           * @notice Remove a Privacy Pool from the registry
           * @param _asset The asset of the pool
           */
          function removePool(IERC20 _asset) external;
          /**
           * @notice Updates the configuration of a specific pool
           * @param _asset The asset of the pool to update
           * @param _minimumDepositAmount The new minimum deposit amount
           * @param _vettingFeeBPS The new vetting fee in basis points
           * @param _maxRelayFeeBPS The new max relay fee in basis points
           */
          function updatePoolConfiguration(
            IERC20 _asset,
            uint256 _minimumDepositAmount,
            uint256 _vettingFeeBPS,
            uint256 _maxRelayFeeBPS
          ) external;
          /**
           * @notice Irreversebly halt deposits from a Privacy Pool
           * @param _pool The Privacy Pool contract
           */
          function windDownPool(IPrivacyPool _pool) external;
          /**
           * @notice Withdraw fees from the Entrypoint
           * @param _asset The asset to withdraw
           * @param _recipient The recipient of the fees
           */
          function withdrawFees(IERC20 _asset, address _recipient) external;
          /*///////////////////////////////////////////////////////////////
                                    VIEWS
          //////////////////////////////////////////////////////////////*/
          /**
           * @notice Returns the configured pool for a scope
           * @param _scope The unique scope of the pool
           * @return _pool The Privacy Pool contract
           */
          function scopeToPool(uint256 _scope) external view returns (IPrivacyPool _pool);
          /**
           * @notice Returns the configuration for an asset
           * @param _asset The asset address
           * @return _pool The Privacy Pool contract
           * @return _minimumDepositAmount The minimum deposit amount
           * @return _vettingFeeBPS The deposit fee in basis points
           * @return _maxRelayFeeBPS The max relayer fee in basis points
           */
          function assetConfig(IERC20 _asset)
            external
            view
            returns (IPrivacyPool _pool, uint256 _minimumDepositAmount, uint256 _vettingFeeBPS, uint256 _maxRelayFeeBPS);
          /**
           * @notice Returns the association set data at an index
           * @param _index The index of the array
           * @return _root The updated ASP root
           * @return _ipfsCID The IPFS v1 CID for the association set data
           * @return _timestamp The timestamp of the root update
           */
          function associationSets(uint256 _index)
            external
            view
            returns (uint256 _root, string memory _ipfsCID, uint256 _timestamp);
          /**
           * @notice Returns the latest ASP root
           * @return _root The latest ASP root
           */
          function latestRoot() external view returns (uint256 _root);
          /**
           * @notice Returns an ASP root by index
           * @param _index The index
           * @return _root The ASP root at the index
           */
          function rootByIndex(uint256 _index) external view returns (uint256 _root);
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.8.28;
        /**
         * @title IVerifier
         * @notice Interface of the Groth16 verifier contracts
         */
        interface IVerifier {
          /**
           * @notice Verifies a Withdrawal Proof
           * @param _pA First elliptic curve point (π_A) of the Groth16 proof, encoded as two field elements
           * @param _pB Second elliptic curve point (π_B) of the Groth16 proof, encoded as 2x2 matrix of field elements
           * @param _pC Third elliptic curve point (π_C) of the Groth16 proof, encoded as two field elements
           * @param _pubSignals The proof public signals (both input and output)
           * @return _valid The boolean indicating if the proof is valid
           */
          function verifyProof(
            uint256[2] memory _pA,
            uint256[2][2] memory _pB,
            uint256[2] memory _pC,
            uint256[8] memory _pubSignals
          ) external returns (bool _valid);
          /**
           * @notice Verifies a Ragequit Proof
           * @param _pA First elliptic curve point (π_A) of the Groth16 proof, encoded as two field elements
           * @param _pB Second elliptic curve point (π_B) of the Groth16 proof, encoded as 2x2 matrix of field elements
           * @param _pC Third elliptic curve point (π_C) of the Groth16 proof, encoded as two field elements
           * @param _pubSignals The proof public signals (both input and output)
           * @return _valid The boolean indicating if the proof is valid
           */
          function verifyProof(
            uint256[2] memory _pA,
            uint256[2][2] memory _pB,
            uint256[2] memory _pC,
            uint256[4] memory _pubSignals
          ) external returns (bool _valid);
        }
        /// 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)
            }
          }
        }
        // SPDX-License-Identifier: UNLICENSED
        pragma solidity ^0.8.4;
        uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
        pragma solidity ^0.8.20;
        import {IERC20} from "../token/ERC20/IERC20.sol";
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Interface of the ERC-20 standard as defined in the ERC.
         */
        interface IERC20 {
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
            /**
             * @dev Returns the value of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the value of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves a `value` amount of tokens from the caller's account to `to`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address to, uint256 value) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
             * caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 value) external returns (bool);
            /**
             * @dev Moves a `value` amount of tokens from `from` to `to` using the
             * allowance mechanism. `value` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address from, address to, uint256 value) external returns (bool);
        }
        

        File 2 of 4: ERC1967Proxy
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (proxy/ERC1967/ERC1967Proxy.sol)
        pragma solidity ^0.8.20;
        import {Proxy} from "../Proxy.sol";
        import {ERC1967Utils} from "./ERC1967Utils.sol";
        /**
         * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
         * implementation address that can be changed. This address is stored in storage in the location specified by
         * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967], so that it doesn't conflict with the storage layout of the
         * implementation behind the proxy.
         */
        contract ERC1967Proxy is Proxy {
            /**
             * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
             *
             * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
             * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
             *
             * Requirements:
             *
             * - If `data` is empty, `msg.value` must be zero.
             */
            constructor(address implementation, bytes memory _data) payable {
                ERC1967Utils.upgradeToAndCall(implementation, _data);
            }
            /**
             * @dev Returns the current implementation address.
             *
             * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
             * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
             * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
             */
            function _implementation() internal view virtual override returns (address) {
                return ERC1967Utils.getImplementation();
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
         * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
         * be specified by overriding the virtual {_implementation} function.
         *
         * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
         * different contract through the {_delegate} function.
         *
         * The success and return data of the delegated call will be returned back to the caller of the proxy.
         */
        abstract contract Proxy {
            /**
             * @dev Delegates the current call to `implementation`.
             *
             * This function does not return to its internal call site, it will return directly to the external caller.
             */
            function _delegate(address implementation) internal virtual {
                assembly {
                    // Copy msg.data. We take full control of memory in this inline assembly
                    // block because it will not return to Solidity code. We overwrite the
                    // Solidity scratch pad at memory position 0.
                    calldatacopy(0, 0, calldatasize())
                    // Call the implementation.
                    // out and outsize are 0 because we don't know the size yet.
                    let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                    // Copy the returned data.
                    returndatacopy(0, 0, returndatasize())
                    switch result
                    // delegatecall returns 0 on error.
                    case 0 {
                        revert(0, returndatasize())
                    }
                    default {
                        return(0, returndatasize())
                    }
                }
            }
            /**
             * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
             * function and {_fallback} should delegate.
             */
            function _implementation() internal view virtual returns (address);
            /**
             * @dev Delegates the current call to the address returned by `_implementation()`.
             *
             * This function does not return to its internal call site, it will return directly to the external caller.
             */
            function _fallback() internal virtual {
                _delegate(_implementation());
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
             * function in the contract matches the call data.
             */
            fallback() external payable virtual {
                _fallback();
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (proxy/ERC1967/ERC1967Utils.sol)
        pragma solidity ^0.8.21;
        import {IBeacon} from "../beacon/IBeacon.sol";
        import {IERC1967} from "../../interfaces/IERC1967.sol";
        import {Address} from "../../utils/Address.sol";
        import {StorageSlot} from "../../utils/StorageSlot.sol";
        /**
         * @dev This library provides getters and event emitting update functions for
         * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
         */
        library ERC1967Utils {
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev The `implementation` of the proxy is invalid.
             */
            error ERC1967InvalidImplementation(address implementation);
            /**
             * @dev The `admin` of the proxy is invalid.
             */
            error ERC1967InvalidAdmin(address admin);
            /**
             * @dev The `beacon` of the proxy is invalid.
             */
            error ERC1967InvalidBeacon(address beacon);
            /**
             * @dev An upgrade function sees `msg.value > 0` that may be lost.
             */
            error ERC1967NonPayable();
            /**
             * @dev Returns the current implementation address.
             */
            function getImplementation() internal view returns (address) {
                return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
            }
            /**
             * @dev Stores a new address in the ERC-1967 implementation slot.
             */
            function _setImplementation(address newImplementation) private {
                if (newImplementation.code.length == 0) {
                    revert ERC1967InvalidImplementation(newImplementation);
                }
                StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
            }
            /**
             * @dev Performs implementation upgrade with additional setup call if data is nonempty.
             * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
             * to avoid stuck value in the contract.
             *
             * Emits an {IERC1967-Upgraded} event.
             */
            function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                _setImplementation(newImplementation);
                emit IERC1967.Upgraded(newImplementation);
                if (data.length > 0) {
                    Address.functionDelegateCall(newImplementation, data);
                } else {
                    _checkNonPayable();
                }
            }
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Returns the current admin.
             *
             * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
             * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
             * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
             */
            function getAdmin() internal view returns (address) {
                return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
            }
            /**
             * @dev Stores a new address in the ERC-1967 admin slot.
             */
            function _setAdmin(address newAdmin) private {
                if (newAdmin == address(0)) {
                    revert ERC1967InvalidAdmin(address(0));
                }
                StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
            }
            /**
             * @dev Changes the admin of the proxy.
             *
             * Emits an {IERC1967-AdminChanged} event.
             */
            function changeAdmin(address newAdmin) internal {
                emit IERC1967.AdminChanged(getAdmin(), newAdmin);
                _setAdmin(newAdmin);
            }
            /**
             * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
             * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            /**
             * @dev Returns the current beacon.
             */
            function getBeacon() internal view returns (address) {
                return StorageSlot.getAddressSlot(BEACON_SLOT).value;
            }
            /**
             * @dev Stores a new beacon in the ERC-1967 beacon slot.
             */
            function _setBeacon(address newBeacon) private {
                if (newBeacon.code.length == 0) {
                    revert ERC1967InvalidBeacon(newBeacon);
                }
                StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                address beaconImplementation = IBeacon(newBeacon).implementation();
                if (beaconImplementation.code.length == 0) {
                    revert ERC1967InvalidImplementation(beaconImplementation);
                }
            }
            /**
             * @dev Change the beacon and trigger a setup call if data is nonempty.
             * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
             * to avoid stuck value in the contract.
             *
             * Emits an {IERC1967-BeaconUpgraded} event.
             *
             * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
             * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
             * efficiency.
             */
            function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                _setBeacon(newBeacon);
                emit IERC1967.BeaconUpgraded(newBeacon);
                if (data.length > 0) {
                    Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                } else {
                    _checkNonPayable();
                }
            }
            /**
             * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
             * if an upgrade doesn't perform an initialization call.
             */
            function _checkNonPayable() private {
                if (msg.value > 0) {
                    revert ERC1967NonPayable();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev This is the interface that {BeaconProxy} expects of its beacon.
         */
        interface IBeacon {
            /**
             * @dev Must return an address that can be used as a delegate call target.
             *
             * {UpgradeableBeacon} will check that this address is a contract.
             */
            function implementation() external view returns (address);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
         */
        interface IERC1967 {
            /**
             * @dev Emitted when the implementation is upgraded.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Emitted when the admin account has changed.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Emitted when the beacon is changed.
             */
            event BeaconUpgraded(address indexed beacon);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)
        pragma solidity ^0.8.20;
        import {Errors} from "./Errors.sol";
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
            /**
             * @dev There's no code at `target` (it is not a contract).
             */
            error AddressEmptyCode(address target);
            /**
             * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
             * `recipient`, forwarding all available gas and reverting on errors.
             *
             * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
             * of certain opcodes, possibly making contracts go over the 2300 gas limit
             * imposed by `transfer`, making them unable to receive funds via
             * `transfer`. {sendValue} removes this limitation.
             *
             * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
             *
             * IMPORTANT: because control is transferred to `recipient`, care must be
             * taken to not create reentrancy vulnerabilities. Consider using
             * {ReentrancyGuard} or the
             * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
             */
            function sendValue(address payable recipient, uint256 amount) internal {
                if (address(this).balance < amount) {
                    revert Errors.InsufficientBalance(address(this).balance, amount);
                }
                (bool success, ) = recipient.call{value: amount}("");
                if (!success) {
                    revert Errors.FailedCall();
                }
            }
            /**
             * @dev Performs a Solidity function call using a low level `call`. A
             * plain `call` is an unsafe replacement for a function call: use this
             * function instead.
             *
             * If `target` reverts with a revert reason or custom error, it is bubbled
             * up by this function (like regular Solidity function calls). However, if
             * the call reverted with no returned reason, this function reverts with a
             * {Errors.FailedCall} error.
             *
             * Returns the raw returned data. To convert to the expected return value,
             * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
             *
             * Requirements:
             *
             * - `target` must be a contract.
             * - calling `target` with `data` must not revert.
             */
            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCallWithValue(target, data, 0);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but also transferring `value` wei to `target`.
             *
             * Requirements:
             *
             * - the calling contract must have an ETH balance of at least `value`.
             * - the called Solidity function must be `payable`.
             */
            function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                if (address(this).balance < value) {
                    revert Errors.InsufficientBalance(address(this).balance, value);
                }
                (bool success, bytes memory returndata) = target.call{value: value}(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a static call.
             */
            function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                (bool success, bytes memory returndata) = target.staticcall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a delegate call.
             */
            function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                (bool success, bytes memory returndata) = target.delegatecall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
             * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
             * of an unsuccessful call.
             */
            function verifyCallResultFromTarget(
                address target,
                bool success,
                bytes memory returndata
            ) internal view returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    // only check if target is a contract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    if (returndata.length == 0 && target.code.length == 0) {
                        revert AddressEmptyCode(target);
                    }
                    return returndata;
                }
            }
            /**
             * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
             * revert reason or with a default {Errors.FailedCall} error.
             */
            function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    return returndata;
                }
            }
            /**
             * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
             */
            function _revert(bytes memory returndata) private pure {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    assembly ("memory-safe") {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert Errors.FailedCall();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
        // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
        pragma solidity ^0.8.20;
        /**
         * @dev Library for reading and writing primitive types to specific storage slots.
         *
         * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
         * This library helps with reading and writing to such slots without the need for inline assembly.
         *
         * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
         *
         * Example usage to set ERC-1967 implementation slot:
         * ```solidity
         * contract ERC1967 {
         *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
         *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
         *
         *     function _getImplementation() internal view returns (address) {
         *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
         *     }
         *
         *     function _setImplementation(address newImplementation) internal {
         *         require(newImplementation.code.length > 0);
         *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
         *     }
         * }
         * ```
         *
         * TIP: Consider using this library along with {SlotDerivation}.
         */
        library StorageSlot {
            struct AddressSlot {
                address value;
            }
            struct BooleanSlot {
                bool value;
            }
            struct Bytes32Slot {
                bytes32 value;
            }
            struct Uint256Slot {
                uint256 value;
            }
            struct Int256Slot {
                int256 value;
            }
            struct StringSlot {
                string value;
            }
            struct BytesSlot {
                bytes value;
            }
            /**
             * @dev Returns an `AddressSlot` with member `value` located at `slot`.
             */
            function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
             */
            function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
             */
            function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
             */
            function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns a `Int256Slot` with member `value` located at `slot`.
             */
            function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns a `StringSlot` with member `value` located at `slot`.
             */
            function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
             */
            function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := store.slot
                }
            }
            /**
             * @dev Returns a `BytesSlot` with member `value` located at `slot`.
             */
            function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
             */
            function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                assembly ("memory-safe") {
                    r.slot := store.slot
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Collection of common custom errors used in multiple contracts
         *
         * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
         * It is recommended to avoid relying on the error API for critical functionality.
         *
         * _Available since v5.1._
         */
        library Errors {
            /**
             * @dev The ETH balance of the account is not enough to perform the operation.
             */
            error InsufficientBalance(uint256 balance, uint256 needed);
            /**
             * @dev A call to an address target failed. The target may have reverted.
             */
            error FailedCall();
            /**
             * @dev The deployment failed.
             */
            error FailedDeployment();
            /**
             * @dev A necessary precompile is missing.
             */
            error MissingPrecompile(address);
        }
        

        File 3 of 4: WithdrawalVerifier
        // SPDX-License-Identifier: GPL-3.0
        // forgefmt: disable-start
        /*
            Copyright 2021 0KIMS association.
            This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
            snarkJS is a free software: you can redistribute it and/or modify it
            under the terms of the GNU General Public License as published by
            the Free Software Foundation, either version 3 of the License, or
            (at your option) any later version.
            snarkJS is distributed in the hope that it will be useful, but WITHOUT
            ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
            or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
            License for more details.
            You should have received a copy of the GNU General Public License
            along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
        */
        pragma solidity >=0.7.0 <0.9.0;
        contract WithdrawalVerifier {
            // Scalar field size
            uint256 constant r    = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
            // Base field size
            uint256 constant q   = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
            // Verification Key data
            uint256 constant alphax  = 16428432848801857252194528405604668803277877773566238944394625302971855135431;
            uint256 constant alphay  = 16846502678714586896801519656441059708016666274385668027902869494772365009666;
            uint256 constant betax1  = 3182164110458002340215786955198810119980427837186618912744689678939861918171;
            uint256 constant betax2  = 16348171800823588416173124589066524623406261996681292662100840445103873053252;
            uint256 constant betay1  = 4920802715848186258981584729175884379674325733638798907835771393452862684714;
            uint256 constant betay2  = 19687132236965066906216944365591810874384658708175106803089633851114028275753;
            uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
            uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
            uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
            uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
            uint256 constant deltax1 = 355730187017390060257088699243557931444743893437609284639879195946356391671;
            uint256 constant deltax2 = 11377546232269146885719711323617440487334358631817944307305954377320021081609;
            uint256 constant deltay1 = 14828571047823507951936654719331566168682863576761372686128260593891040163007;
            uint256 constant deltay2 = 14925671126934765953425446845541707408298799882358491896288696759849089416456;
            
            uint256 constant IC0x = 20917852783971662989037834579922189207796850157455689196836407829693273058181;
            uint256 constant IC0y = 14309172700509163829827835936087829189193823544006124999667589607573555153317;
            
            uint256 constant IC1x = 4002318554163308338961115195600756325669504095744400749661836505711747131480;
            uint256 constant IC1y = 19388553801400869339697580180794985615392396320851212290435880306887322433262;
            
            uint256 constant IC2x = 4254123736274716305094004322466639736349000292613093104635160011340821139688;
            uint256 constant IC2y = 19581123507269704428735684612376263280905609143077051758684797548075203355862;
            
            uint256 constant IC3x = 12829149822163537636941647022474968478908625676617259064999683111486877280191;
            uint256 constant IC3y = 11906986527782177454913261933143777359684553833291705890148735374364062300950;
            
            uint256 constant IC4x = 14959519196996577022953934863461427249996916985368164934760550902108247251314;
            uint256 constant IC4y = 17153998018818455451015682095753537372058398415644924731407055981674255991568;
            
            uint256 constant IC5x = 386592992276936501107132673378759567169940445750810516666781824566579325489;
            uint256 constant IC5y = 6545363418535856048783449340812901581000301323807547677423370106415935030419;
            
            uint256 constant IC6x = 14405334651179970829248032802453416652902403107461697011217734903378819167500;
            uint256 constant IC6y = 5941867495000526980426755384727509338287954936978959436019043816230884260430;
            
            uint256 constant IC7x = 6593325309923573421969784559603844408437482353554868263039840702125354704945;
            uint256 constant IC7y = 19710681365262161445645108505967116609968223704683705865914938644210040221046;
            
            uint256 constant IC8x = 13832774438085654502815602896317109691851791928314457690314578958243235503172;
            uint256 constant IC8y = 2034154171145211628085643224823864015412822036123513499722451852634747199812;
            
         
            // Memory data
            uint16 constant pVk = 0;
            uint16 constant pPairing = 128;
            uint16 constant pLastMem = 896;
            function verifyProof(uint256[2] calldata _pA, uint256[2][2] calldata _pB, uint256[2] calldata _pC, uint256[8] calldata _pubSignals) public view returns (bool) {
                assembly {
                    function checkField(v) {
                        if iszero(lt(v, r)) {
                            mstore(0, 0)
                            return(0, 0x20)
                        }
                    }
                    
                    // G1 function to multiply a G1 value(x,y) to value in an address
                    function g1_mulAccC(pR, x, y, s) {
                        let success
                        let mIn := mload(0x40)
                        mstore(mIn, x)
                        mstore(add(mIn, 32), y)
                        mstore(add(mIn, 64), s)
                        success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
                        if iszero(success) {
                            mstore(0, 0)
                            return(0, 0x20)
                        }
                        mstore(add(mIn, 64), mload(pR))
                        mstore(add(mIn, 96), mload(add(pR, 32)))
                        success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
                        if iszero(success) {
                            mstore(0, 0)
                            return(0, 0x20)
                        }
                    }
                    function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
                        let _pPairing := add(pMem, pPairing)
                        let _pVk := add(pMem, pVk)
                        mstore(_pVk, IC0x)
                        mstore(add(_pVk, 32), IC0y)
                        // Compute the linear combination vk_x
                        
                        g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
                        
                        g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
                        
                        g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64)))
                        
                        g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96)))
                        
                        g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128)))
                        
                        g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160)))
                        
                        g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192)))
                        
                        g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224)))
                        
                        // -A
                        mstore(_pPairing, calldataload(pA))
                        mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
                        // B
                        mstore(add(_pPairing, 64), calldataload(pB))
                        mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
                        mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
                        mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
                        // alpha1
                        mstore(add(_pPairing, 192), alphax)
                        mstore(add(_pPairing, 224), alphay)
                        // beta2
                        mstore(add(_pPairing, 256), betax1)
                        mstore(add(_pPairing, 288), betax2)
                        mstore(add(_pPairing, 320), betay1)
                        mstore(add(_pPairing, 352), betay2)
                        // vk_x
                        mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
                        mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
                        // gamma2
                        mstore(add(_pPairing, 448), gammax1)
                        mstore(add(_pPairing, 480), gammax2)
                        mstore(add(_pPairing, 512), gammay1)
                        mstore(add(_pPairing, 544), gammay2)
                        // C
                        mstore(add(_pPairing, 576), calldataload(pC))
                        mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
                        // delta2
                        mstore(add(_pPairing, 640), deltax1)
                        mstore(add(_pPairing, 672), deltax2)
                        mstore(add(_pPairing, 704), deltay1)
                        mstore(add(_pPairing, 736), deltay2)
                        let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
                        isOk := and(success, mload(_pPairing))
                    }
                    let pMem := mload(0x40)
                    mstore(0x40, add(pMem, pLastMem))
                    // Validate that all evaluations ∈ F
                    
                    checkField(calldataload(add(_pubSignals, 0)))
                    
                    checkField(calldataload(add(_pubSignals, 32)))
                    
                    checkField(calldataload(add(_pubSignals, 64)))
                    
                    checkField(calldataload(add(_pubSignals, 96)))
                    
                    checkField(calldataload(add(_pubSignals, 128)))
                    
                    checkField(calldataload(add(_pubSignals, 160)))
                    
                    checkField(calldataload(add(_pubSignals, 192)))
                    
                    checkField(calldataload(add(_pubSignals, 224)))
                    
                    // Validate all evaluations
                    let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
                    mstore(0, isValid)
                     return(0, 0x20)
                 }
             }
         }
        // forgefmt: disable-end
        

        File 4 of 4: PoseidonT3
        /// 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)
            }
          }
        }