diff --git a/excubiae/README.md b/excubiae/README.md
deleted file mode 100644
index 71a4bac..0000000
--- a/excubiae/README.md
+++ /dev/null
@@ -1,85 +0,0 @@
-<p align="center">
-    <h1 align="center">
-        Excubiae
-    </h1>
-    <p align="center">A flexible and modular framework for general-purpose on-chain gatekeepers.</p>
-</p>
-
-<p align="center">
-    <a href="https://github.com/privacy-scaling-explorations/excubiae">
-        <img src="https://img.shields.io/badge/project-excubiae-blue.svg?style=flat-square">
-    </a>
-    <a href="https://github.com/privacy-scaling-explorations/excubiae/blob/main/LICENSE">
-        <img alt="NPM license" src="https://img.shields.io/npm/l/excubiae?style=flat-square">
-    </a>
-    <a href="https://www.npmjs.com/package/excubiae">
-        <img alt="NPM version" src="https://img.shields.io/npm/v/excubiae?style=flat-square" />
-    </a>
-    <a href="https://npmjs.org/package/excubiae">
-        <img alt="Downloads" src="https://img.shields.io/npm/dm/excubiae.svg?style=flat-square" />
-    </a>
-    <a href="https://prettier.io/">
-        <img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
-    </a>
-</p>
-
-<div align="center">
-    <h4>
-        <a href="https://appliedzkp.org/discord">
-            🗣️ Chat & Support
-        </a>
-    </h4>
-</div>
-
-> [!NOTE]  
-> This library is experimental and untested yet - use at your own discretion...
-
-Excubiae is a generalized framework for on-chain gatekeepers that allows developers to define custom access control mechanisms using different on-chain credentials. By abstracting the gatekeeper logic, excubiae provides a reusable and composable solution for securing decentralised applications. This package provides a pre-defined set of specific excubia (_extensions_) for credentials based on different protocols.
-
-## 🛠 Install
-
-### npm or yarn
-
-Install the ` @zk-kit/excubiae` package with npm:
-
-```bash
-npm i @zk-kit/excubiae --save
-```
-
-or yarn:
-
-```bash
-yarn add @zk-kit/excubiae
-```
-
-## 📜 Usage
-
-To build your own Excubia:
-
-1. Inherit from the [Excubia](./Excubia.sol) abstract contract that conforms to the [IExcubia](./IExcubia.sol) interface.
-2. Implement the `_check()` and `_pass()` methods logic defining your own checks to prevent unwanted access as sybils or avoid to pass the gate twice with the same data / identity.
-
-```solidity
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import { Excubia } from "excubiae/contracts/Excubia.sol";
-
-contract MyExcubia is Excubia {
-    // ...
-
-    function _pass(address passerby, bytes calldata data) internal override {
-        // Implement your logic to prevent unwanted access here.
-    }
-
-    function _check(address passerby, bytes calldata data) internal view override returns (bool) {
-        // Implement custom access control logic here.
-
-        return true;
-    }
-
-    // ...
-}
-```
-
-Please see the [extensions](./extensions/) folder for more complex reference implementations and the [test contracts](./test) folder for guidance on using the libraries.
diff --git a/excubiae/src/Excubia.sol b/excubiae/src/Excubia.sol
deleted file mode 100644
index a91a55a..0000000
--- a/excubiae/src/Excubia.sol
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
-import {IExcubia} from "./IExcubia.sol";
-
-/// @title Excubia.
-/// @notice Abstract base contract which can be extended to implement a specific excubia.
-/// @dev Inherit from this contract and implement the `_pass` & `_check` methods to define
-/// your custom gatekeeping logic.
-abstract contract Excubia is IExcubia, Ownable(msg.sender) {
-    /// @notice The excubia-protected contract address.
-    /// @dev The gate can be any contract address that requires a prior check to enable logic.
-    /// For example, the gate is a Semaphore group that requires the passerby
-    /// to meet certain criteria before joining.
-    address public gate;
-
-    /// @dev Modifier to restrict function calls to only from the gate address.
-    modifier onlyGate() {
-        if (msg.sender != gate) revert GateOnly();
-        _;
-    }
-
-    /// @inheritdoc IExcubia
-    function setGate(address _gate) public virtual onlyOwner {
-        if (_gate == address(0)) revert ZeroAddress();
-        if (gate != address(0)) revert GateAlreadySet();
-
-        gate = _gate;
-
-        emit GateSet(_gate);
-    }
-
-    /// @inheritdoc IExcubia
-    function pass(address passerby, bytes calldata data) external onlyGate {
-        _pass(passerby, data);
-    }
-
-    /// @inheritdoc IExcubia
-    function check(address passerby, bytes calldata data) external view {
-        _check(passerby, data);
-    }
-
-    /// @notice Internal function to enforce the custom gate passing logic.
-    /// @dev Calls the `_check` internal logic and emits the relative event if successful.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded token identifier).
-    function _pass(address passerby, bytes calldata data) internal virtual {
-        _check(passerby, data);
-
-        emit GatePassed(passerby, gate);
-    }
-
-    /// @notice Internal function to define the custom gate protection logic.
-    /// @dev Custom logic to determine if the passerby can pass the gate.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data that may be required for the check.
-    function _check(address passerby, bytes calldata data) internal view virtual {}
-}
diff --git a/excubiae/src/IExcubia.sol b/excubiae/src/IExcubia.sol
deleted file mode 100644
index 86a4a80..0000000
--- a/excubiae/src/IExcubia.sol
+++ /dev/null
@@ -1,46 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-/// @title IExcubia.
-/// @notice Excubia contract interface.
-interface IExcubia {
-    /// @notice Event emitted when someone passes the gate check.
-    /// @param passerby The address of those who have successfully passed the check.
-    /// @param gate The address of the excubia-protected contract address.
-    event GatePassed(address indexed passerby, address indexed gate);
-
-    /// @notice Event emitted when the gate address is set.
-    /// @param gate The address of the contract set as the gate.
-    event GateSet(address indexed gate);
-
-    /// @notice Error thrown when an address equal to zero is given.
-    error ZeroAddress();
-
-    /// @notice Error thrown when the gate address is not set.
-    error GateNotSet();
-
-    /// @notice Error thrown when the callee is not the gate contract.
-    error GateOnly();
-
-    /// @notice Error thrown when the gate address has been already set.
-    error GateAlreadySet();
-
-    /// @notice Error thrown when the passerby has already passed the gate.
-    error AlreadyPassed();
-
-    /// @notice Sets the gate address.
-    /// @dev Only the owner can set the destination gate address.
-    /// @param _gate The address of the contract to be set as the gate.
-    function setGate(address _gate) external;
-
-    /// @notice Enforces the custom gate passing logic.
-    /// @dev Must call the `check` to handle the logic of checking passerby for specific gate.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded token identifier).
-    function pass(address passerby, bytes calldata data) external;
-
-    /// @dev Defines the custom gate protection logic.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data that may be required for the check.
-    function check(address passerby, bytes calldata data) external view;
-}
diff --git a/excubiae/src/extensions/EASExcubia.sol b/excubiae/src/extensions/EASExcubia.sol
deleted file mode 100644
index afe5692..0000000
--- a/excubiae/src/extensions/EASExcubia.sol
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import {Excubia} from "../Excubia.sol";
-import {IEAS} from "@ethereum-attestation-service/eas-contracts/contracts/IEAS.sol";
-import {Attestation} from "@ethereum-attestation-service/eas-contracts/contracts/Common.sol";
-
-/// @title EAS Excubia Contract.
-/// @notice This contract extends the Excubia contract to integrate with the Ethereum Attestation Service (EAS).
-/// This contract checks an EAS attestation to permit access through the gate.
-/// @dev The contract uses a specific attestation schema & attester to admit the recipient of the attestation.
-contract EASExcubia is Excubia {
-    /// @notice The Ethereum Attestation Service contract interface.
-    IEAS public immutable EAS;
-    /// @notice The specific schema ID that attestations must match to pass the gate.
-    bytes32 public immutable SCHEMA;
-    /// @notice The trusted attester address whose attestations are considered
-    /// the only ones valid to pass the gate.
-    address public immutable ATTESTER;
-
-    /// @notice Mapping to track which attestations have been registered by the contract to
-    /// avoid pass the gate twice with the same attestation.
-    mapping(bytes32 => bool) public registeredAttestations;
-
-    /// @notice Error thrown when the attestation does not match the designed schema.
-    error UnexpectedSchema();
-
-    /// @notice Error thrown when the attestation does not match the designed trusted attester.
-    error UnexpectedAttester();
-
-    /// @notice Error thrown when the attestation does not match the passerby as recipient.
-    error UnexpectedRecipient();
-
-    /// @notice Error thrown when the attestation has been revoked.
-    error RevokedAttestation();
-
-    /// @notice Constructor to initialize with target EAS contract with specific attester and schema.
-    /// @param _eas The address of the EAS contract.
-    /// @param _attester The address of the trusted attester.
-    /// @param _schema The schema ID that attestations must match.
-    constructor(address _eas, address _attester, bytes32 _schema) {
-        if (_eas == address(0) || _attester == address(0)) revert ZeroAddress();
-
-        EAS = IEAS(_eas);
-        ATTESTER = _attester;
-        SCHEMA = _schema;
-    }
-
-    /// @notice Internal function to handle the passing logic with check.
-    /// @dev Calls the parent `_pass` function and registers the attestation to avoid pass the gate twice.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded attestation ID).
-    function _pass(address passerby, bytes calldata data) internal override {
-        bytes32 attestationId = abi.decode(data, (bytes32));
-
-        // Avoiding passing the gate twice using the same attestation.
-        if (registeredAttestations[attestationId]) revert AlreadyPassed();
-
-        super._pass(passerby, data);
-
-        registeredAttestations[attestationId] = true;
-    }
-
-    /// @notice Internal function to handle the gate protection (attestation check) logic.
-    /// @dev Checks if the attestation matches the schema, attester, recipient, and is not revoked.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded attestation ID).
-    function _check(address passerby, bytes calldata data) internal view override {
-        super._check(passerby, data);
-
-        bytes32 attestationId = abi.decode(data, (bytes32));
-
-        Attestation memory attestation = EAS.getAttestation(attestationId);
-
-        if (attestation.schema != SCHEMA) revert UnexpectedSchema();
-        if (attestation.attester != ATTESTER) revert UnexpectedAttester();
-        if (attestation.recipient != passerby) revert UnexpectedRecipient();
-        if (attestation.revocationTime != 0) revert RevokedAttestation();
-    }
-}
diff --git a/excubiae/src/extensions/ERC721Excubia.sol b/excubiae/src/extensions/ERC721Excubia.sol
deleted file mode 100644
index 8e93dc7..0000000
--- a/excubiae/src/extensions/ERC721Excubia.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import {Excubia} from "../Excubia.sol";
-import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
-
-/// @title ERC721 Excubia Contract.
-/// @notice This contract extends the Excubia contract to integrate with an ERC721 token.
-/// This contract checks the ownership of an ERC721 token to permit access through the gate.
-/// @dev The contract refers to a contract implementing the ERC721 standard to admit the owner of the token.
-contract ERC721Excubia is Excubia {
-    /// @notice The ERC721 token contract interface.
-    IERC721 public immutable NFT;
-
-    /// @notice Mapping to track which token IDs have been registered by the contract to
-    /// avoid passing the gate twice with the same token ID.
-    mapping(uint256 => bool) public registeredTokenIds;
-
-    /// @notice Error thrown when the passerby is not the owner of the token.
-    error UnexpectedTokenOwner();
-
-    /// @notice Constructor to initialize with target ERC721 contract.
-    /// @param _erc721 The address of the ERC721 contract.
-    constructor(address _erc721) {
-        if (_erc721 == address(0)) revert ZeroAddress();
-
-        NFT = IERC721(_erc721);
-    }
-
-    /// @notice Internal function to handle the passing logic with check.
-    /// @dev Calls the parent `_pass` function and registers the NFT ID to avoid passing the gate twice.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded token ID).
-    function _pass(address passerby, bytes calldata data) internal override {
-        uint256 tokenId = abi.decode(data, (uint256));
-
-        // Avoiding passing the gate twice with the same token ID.
-        if (registeredTokenIds[tokenId]) revert AlreadyPassed();
-
-        super._pass(passerby, data);
-
-        registeredTokenIds[tokenId] = true;
-    }
-
-    /// @notice Internal function to handle the gate protection (token ownership check) logic.
-    /// @dev Checks if the passerby is the owner of the token.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded token ID).
-    function _check(address passerby, bytes calldata data) internal view override {
-        super._check(passerby, data);
-
-        uint256 tokenId = abi.decode(data, (uint256));
-
-        // Check if the user owns the token.
-        if (!(NFT.ownerOf(tokenId) == passerby)) revert UnexpectedTokenOwner();
-    }
-}
diff --git a/excubiae/src/extensions/FreeForAllExcubia.sol b/excubiae/src/extensions/FreeForAllExcubia.sol
deleted file mode 100644
index 936566d..0000000
--- a/excubiae/src/extensions/FreeForAllExcubia.sol
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import {Excubia} from "../Excubia.sol";
-
-/// @title FreeForAll Excubia Contract.
-/// @notice This contract extends the Excubia contract to allow free access through the gate.
-/// This contract does not perform any checks and allows any passerby to pass the gate.
-/// @dev The contract overrides the `_check` function to always return true.
-contract FreeForAllExcubia is Excubia {
-    /// @notice Constructor for the FreeForAllExcubia contract.
-    constructor() {}
-
-    /// @notice Mapping to track already registered passersby.
-    mapping(address => bool) public registeredPassersby;
-
-    /// @notice Internal function to handle the gate passing logic.
-    /// @dev This function calls the parent `_pass` function and then tracks the passerby.
-    /// @param passerby The address of the entity passing the gate.
-    /// @param data Additional data required for the pass (not used in this implementation).
-    function _pass(address passerby, bytes calldata data) internal override {
-        // Avoiding passing the gate twice with the same address.
-        if (registeredPassersby[passerby]) revert AlreadyPassed();
-
-        super._pass(passerby, data);
-
-        registeredPassersby[passerby] = true;
-    }
-
-    /// @notice Internal function to handle the gate protection logic.
-    /// @dev This function always returns true, signaling that any passerby is able to pass the gate.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (e.g., encoded attestation ID).
-    function _check(address passerby, bytes calldata data) internal view override {
-        super._check(passerby, data);
-    }
-}
diff --git a/excubiae/src/extensions/SemaphoreExcubia.sol b/excubiae/src/extensions/SemaphoreExcubia.sol
deleted file mode 100644
index bd43112..0000000
--- a/excubiae/src/extensions/SemaphoreExcubia.sol
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.0;
-
-import {Excubia} from "../Excubia.sol";
-import {ISemaphore} from "@semaphore-protocol/contracts/interfaces/ISemaphore.sol";
-
-/// @title Semaphore Excubia Contract
-/// @notice This contract extends the Excubia contract to integrate with the Semaphore protocol.
-/// It verifies the passerby Semaphore group membership proofs to grant access through the gate.
-/// @dev To allow only specific Semaphore identities from a group, the contract stores the specific group identifier.
-/// To avoid identities from passing twice, nullifiers are stored upon successful verification of the proofs.
-contract SemaphoreExcubia is Excubia {
-    /// @notice The Semaphore contract interface.
-    ISemaphore public immutable SEMAPHORE;
-    /// @notice The specific group identifier that proofs must match to pass the gate.
-    /// @dev Used as a `scope` to ensure consistency during proof membership verification.
-    uint256 public immutable GROUP_ID;
-
-    /// @notice Mapping to track which nullifiers have been used to avoid passing the
-    /// gate twice using the same Semaphore identity.
-    /// @dev The nullifier is derived from the hash of the secret and group identifier,
-    /// ensuring that the same identity cannot be registered twice for the same group.
-    mapping(uint256 => bool) public passedNullifiers;
-
-    /// @notice Error thrown when the group identifier does not match the expected one.
-    error InvalidGroup();
-
-    /// @notice Error thrown when the proof is invalid.
-    error InvalidProof();
-
-    /// @notice Error thrown when the proof scope does not match the expected group identifier.
-    error UnexpectedScope();
-
-    /// @notice Constructor to initialize with target Semaphore contract and specific group identifier.
-    /// @param _semaphore The address of the Semaphore contract.
-    /// @param _groupId The group identifier that proofs must match.
-    constructor(address _semaphore, uint256 _groupId) {
-        if (_semaphore == address(0)) revert ZeroAddress();
-
-        SEMAPHORE = ISemaphore(_semaphore);
-
-        if (ISemaphore(_semaphore).groupCounter() <= _groupId) revert InvalidGroup();
-
-        GROUP_ID = _groupId;
-    }
-
-    /// @notice Internal function to handle the passing logic with check.
-    /// @dev Calls the parent `_pass` function and registers the nullifier to avoid passing the gate twice.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (ie., encoded Semaphore proof).
-    function _pass(address passerby, bytes calldata data) internal override {
-        ISemaphore.SemaphoreProof memory proof = abi.decode(data, (ISemaphore.SemaphoreProof));
-
-        // Avoiding passing the gate twice using the same nullifier.
-        if (passedNullifiers[proof.nullifier]) revert AlreadyPassed();
-
-        super._pass(passerby, data);
-
-        passedNullifiers[proof.nullifier] = true;
-    }
-
-    /// @notice Internal function to handle the gate protection (proof check) logic.
-    /// @dev Checks if the proof matches the group ID, scope, and is valid.
-    /// @param passerby The address of the entity attempting to pass the gate.
-    /// @param data Additional data required for the check (i.e., encoded Semaphore proof).
-    function _check(address passerby, bytes calldata data) internal view override {
-        super._check(passerby, data);
-
-        ISemaphore.SemaphoreProof memory proof = abi.decode(data, (ISemaphore.SemaphoreProof));
-
-        if (GROUP_ID != proof.scope) revert UnexpectedScope();
-
-        if (!SEMAPHORE.verifyProof(GROUP_ID, proof)) revert InvalidProof();
-    }
-}
diff --git a/imt/README.md b/imt/README.md
deleted file mode 100644
index 737ec58..0000000
--- a/imt/README.md
+++ /dev/null
@@ -1,60 +0,0 @@
-<p align="center">
-    <h1 align="center">
-         Incremental Merkle Tree (Solidity)
-    </h1>
-    <p align="center">Incremental Merkle tree implementation in Solidity.</p>
-</p>
-
-<p align="center">
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity">
-        <img src="https://img.shields.io/badge/project-zk--kit-blue.svg?style=flat-square">
-    </a>
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/imt.sol/contracts/LICENSE">
-        <img alt="NPM license" src="https://img.shields.io/npm/l/%40zk-kit%2Fimt.sol?style=flat-square">
-    </a>
-    <a href="https://www.npmjs.com/package/@zk-kit/imt.sol">
-        <img alt="NPM version" src="https://img.shields.io/npm/v/@zk-kit/imt.sol?style=flat-square" />
-    </a>
-    <a href="https://npmjs.org/package/@zk-kit/imt.sol">
-        <img alt="Downloads" src="https://img.shields.io/npm/dm/@zk-kit/imt.sol.svg?style=flat-square" />
-    </a>
-    <a href="https://prettier.io/">
-        <img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
-    </a>
-</p>
-
-<div align="center">
-    <h4>
-        <a href="https://appliedzkp.org/discord">
-            🗣️ Chat &amp; Support
-        </a>
-    </h4>
-</div>
-
-> [!WARNING]  
-> These library has **not** been audited.
-
-> [!WARNING]  
-> If you are looking for the first version of this package, please visit this [link](https://github.com/privacy-scaling-explorations/zk-kit/tree/imt-v1/packages/incremental-merkle-tree.sol).
-
----
-
-## 🛠 Install
-
-### npm or yarn
-
-Install the `@zk-kit/imt.sol` package with npm:
-
-```bash
-npm i @zk-kit/imt.sol --save
-```
-
-or yarn:
-
-```bash
-yarn add @zk-kit/imt.sol
-```
-
-## 📜 Usage
-
-Please, see the [test contracts](./test) for guidance on utilizing the libraries.
diff --git a/imt/src/BinaryIMT.sol b/imt/src/BinaryIMT.sol
deleted file mode 100644
index e14a16f..0000000
--- a/imt/src/BinaryIMT.sol
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {InternalBinaryIMT, BinaryIMTData} from "./InternalBinaryIMT.sol";
-
-library BinaryIMT {
-    using InternalBinaryIMT for *;
-
-    function defaultZero(uint256 index) public pure returns (uint256) {
-        return InternalBinaryIMT._defaultZero(index);
-    }
-
-    function init(BinaryIMTData storage self, uint256 depth, uint256 zero) public {
-        InternalBinaryIMT._init(self, depth, zero);
-    }
-
-    function initWithDefaultZeroes(BinaryIMTData storage self, uint256 depth) public {
-        InternalBinaryIMT._initWithDefaultZeroes(self, depth);
-    }
-
-    function insert(BinaryIMTData storage self, uint256 leaf) public returns (uint256) {
-        return InternalBinaryIMT._insert(self, leaf);
-    }
-
-    function update(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256 newLeaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) public {
-        InternalBinaryIMT._update(self, leaf, newLeaf, proofSiblings, proofPathIndices);
-    }
-
-    function remove(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) public {
-        InternalBinaryIMT._remove(self, leaf, proofSiblings, proofPathIndices);
-    }
-
-    function verify(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) private view returns (bool) {
-        return InternalBinaryIMT._verify(self, leaf, proofSiblings, proofPathIndices);
-    }
-}
diff --git a/imt/src/Constants.sol b/imt/src/Constants.sol
deleted file mode 100644
index 9f3c455..0000000
--- a/imt/src/Constants.sol
+++ /dev/null
@@ -1,5 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.4;
-
-uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
-uint8 constant MAX_DEPTH = 32;
diff --git a/imt/src/InternalBinaryIMT.sol b/imt/src/InternalBinaryIMT.sol
deleted file mode 100644
index 98f4512..0000000
--- a/imt/src/InternalBinaryIMT.sol
+++ /dev/null
@@ -1,285 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {PoseidonT3} from "poseidon-solidity/PoseidonT3.sol";
-import {SNARK_SCALAR_FIELD, MAX_DEPTH} from "./Constants.sol";
-
-// Each incremental tree has certain properties and data that will
-// be used to add new leaves.
-struct BinaryIMTData {
-    uint256 depth; // Depth of the tree (levels - 1).
-    uint256 root; // Root hash of the tree.
-    uint256 numberOfLeaves; // Number of leaves of the tree.
-    mapping(uint256 => uint256) zeroes; // Zero hashes used for empty nodes (level -> zero hash).
-    // The nodes of the subtrees used in the last addition of a leaf (level -> [left node, right node]).
-    mapping(uint256 => uint256[2]) lastSubtrees; // Caching these values is essential to efficient appends.
-    bool useDefaultZeroes;
-}
-
-error ValueGreaterThanSnarkScalarField();
-error DepthNotSupported();
-error WrongDefaultZeroIndex();
-error TreeIsFull();
-error NewLeafCannotEqualOldLeaf();
-error LeafDoesNotExist();
-error LeafIndexOutOfRange();
-error WrongMerkleProofPath();
-
-/// @title Incremental binary Merkle tree.
-/// @dev The incremental tree allows to calculate the root hash each time a leaf is added, ensuring
-/// the integrity of the tree.
-library InternalBinaryIMT {
-    uint256 internal constant Z_0 = 0;
-    uint256 internal constant Z_1 = 14744269619966411208579211824598458697587494354926760081771325075741142829156;
-    uint256 internal constant Z_2 = 7423237065226347324353380772367382631490014989348495481811164164159255474657;
-    uint256 internal constant Z_3 = 11286972368698509976183087595462810875513684078608517520839298933882497716792;
-    uint256 internal constant Z_4 = 3607627140608796879659380071776844901612302623152076817094415224584923813162;
-    uint256 internal constant Z_5 = 19712377064642672829441595136074946683621277828620209496774504837737984048981;
-    uint256 internal constant Z_6 = 20775607673010627194014556968476266066927294572720319469184847051418138353016;
-    uint256 internal constant Z_7 = 3396914609616007258851405644437304192397291162432396347162513310381425243293;
-    uint256 internal constant Z_8 = 21551820661461729022865262380882070649935529853313286572328683688269863701601;
-    uint256 internal constant Z_9 = 6573136701248752079028194407151022595060682063033565181951145966236778420039;
-    uint256 internal constant Z_10 = 12413880268183407374852357075976609371175688755676981206018884971008854919922;
-    uint256 internal constant Z_11 = 14271763308400718165336499097156975241954733520325982997864342600795471836726;
-    uint256 internal constant Z_12 = 20066985985293572387227381049700832219069292839614107140851619262827735677018;
-    uint256 internal constant Z_13 = 9394776414966240069580838672673694685292165040808226440647796406499139370960;
-    uint256 internal constant Z_14 = 11331146992410411304059858900317123658895005918277453009197229807340014528524;
-    uint256 internal constant Z_15 = 15819538789928229930262697811477882737253464456578333862691129291651619515538;
-    uint256 internal constant Z_16 = 19217088683336594659449020493828377907203207941212636669271704950158751593251;
-    uint256 internal constant Z_17 = 21035245323335827719745544373081896983162834604456827698288649288827293579666;
-    uint256 internal constant Z_18 = 6939770416153240137322503476966641397417391950902474480970945462551409848591;
-    uint256 internal constant Z_19 = 10941962436777715901943463195175331263348098796018438960955633645115732864202;
-    uint256 internal constant Z_20 = 15019797232609675441998260052101280400536945603062888308240081994073687793470;
-    uint256 internal constant Z_21 = 11702828337982203149177882813338547876343922920234831094975924378932809409969;
-    uint256 internal constant Z_22 = 11217067736778784455593535811108456786943573747466706329920902520905755780395;
-    uint256 internal constant Z_23 = 16072238744996205792852194127671441602062027943016727953216607508365787157389;
-    uint256 internal constant Z_24 = 17681057402012993898104192736393849603097507831571622013521167331642182653248;
-    uint256 internal constant Z_25 = 21694045479371014653083846597424257852691458318143380497809004364947786214945;
-    uint256 internal constant Z_26 = 8163447297445169709687354538480474434591144168767135863541048304198280615192;
-    uint256 internal constant Z_27 = 14081762237856300239452543304351251708585712948734528663957353575674639038357;
-    uint256 internal constant Z_28 = 16619959921569409661790279042024627172199214148318086837362003702249041851090;
-    uint256 internal constant Z_29 = 7022159125197495734384997711896547675021391130223237843255817587255104160365;
-    uint256 internal constant Z_30 = 4114686047564160449611603615418567457008101555090703535405891656262658644463;
-    uint256 internal constant Z_31 = 12549363297364877722388257367377629555213421373705596078299904496781819142130;
-    uint256 internal constant Z_32 = 21443572485391568159800782191812935835534334817699172242223315142338162256601;
-
-    function _defaultZero(uint256 index) internal pure returns (uint256) {
-        if (index == 0) return Z_0;
-        if (index == 1) return Z_1;
-        if (index == 2) return Z_2;
-        if (index == 3) return Z_3;
-        if (index == 4) return Z_4;
-        if (index == 5) return Z_5;
-        if (index == 6) return Z_6;
-        if (index == 7) return Z_7;
-        if (index == 8) return Z_8;
-        if (index == 9) return Z_9;
-        if (index == 10) return Z_10;
-        if (index == 11) return Z_11;
-        if (index == 12) return Z_12;
-        if (index == 13) return Z_13;
-        if (index == 14) return Z_14;
-        if (index == 15) return Z_15;
-        if (index == 16) return Z_16;
-        if (index == 17) return Z_17;
-        if (index == 18) return Z_18;
-        if (index == 19) return Z_19;
-        if (index == 20) return Z_20;
-        if (index == 21) return Z_21;
-        if (index == 22) return Z_22;
-        if (index == 23) return Z_23;
-        if (index == 24) return Z_24;
-        if (index == 25) return Z_25;
-        if (index == 26) return Z_26;
-        if (index == 27) return Z_27;
-        if (index == 28) return Z_28;
-        if (index == 29) return Z_29;
-        if (index == 30) return Z_30;
-        if (index == 31) return Z_31;
-        if (index == 32) return Z_32;
-        revert WrongDefaultZeroIndex();
-    }
-
-    /// @dev Initializes a tree.
-    /// @param self: Tree data.
-    /// @param depth: Depth of the tree.
-    /// @param zero: Zero value to be used.
-    function _init(BinaryIMTData storage self, uint256 depth, uint256 zero) internal {
-        if (zero >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (depth <= 0 || depth > MAX_DEPTH) {
-            revert DepthNotSupported();
-        }
-
-        self.depth = depth;
-
-        for (uint8 i = 0; i < depth;) {
-            self.zeroes[i] = zero;
-            zero = PoseidonT3.hash([zero, zero]);
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        self.root = zero;
-    }
-
-    function _initWithDefaultZeroes(BinaryIMTData storage self, uint256 depth) internal {
-        if (depth <= 0 || depth > MAX_DEPTH) {
-            revert DepthNotSupported();
-        }
-
-        self.depth = depth;
-        self.useDefaultZeroes = true;
-
-        self.root = _defaultZero(depth);
-    }
-
-    /// @dev Inserts a leaf in the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be inserted.
-    function _insert(BinaryIMTData storage self, uint256 leaf) internal returns (uint256) {
-        uint256 depth = self.depth;
-
-        if (leaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (self.numberOfLeaves >= 2 ** depth) {
-            revert TreeIsFull();
-        }
-
-        uint256 index = self.numberOfLeaves;
-        uint256 hash = leaf;
-        bool useDefaultZeroes = self.useDefaultZeroes;
-
-        for (uint8 i = 0; i < depth;) {
-            if (index & 1 == 0) {
-                self.lastSubtrees[i] = [hash, useDefaultZeroes ? _defaultZero(i) : self.zeroes[i]];
-            } else {
-                self.lastSubtrees[i][1] = hash;
-            }
-
-            hash = PoseidonT3.hash(self.lastSubtrees[i]);
-            index >>= 1;
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        self.root = hash;
-        self.numberOfLeaves += 1;
-        return hash;
-    }
-
-    /// @dev Updates a leaf in the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be updated.
-    /// @param newLeaf: New leaf.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    function _update(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256 newLeaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal {
-        if (newLeaf == leaf) {
-            revert NewLeafCannotEqualOldLeaf();
-        } else if (newLeaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (!_verify(self, leaf, proofSiblings, proofPathIndices)) {
-            revert LeafDoesNotExist();
-        }
-
-        uint256 depth = self.depth;
-        uint256 hash = newLeaf;
-        uint256 updateIndex;
-
-        for (uint8 i = 0; i < depth;) {
-            updateIndex |= uint256(proofPathIndices[i]) << uint256(i);
-
-            if (proofPathIndices[i] == 0) {
-                if (proofSiblings[i] == self.lastSubtrees[i][1]) {
-                    self.lastSubtrees[i][0] = hash;
-                }
-
-                hash = PoseidonT3.hash([hash, proofSiblings[i]]);
-            } else {
-                if (proofSiblings[i] == self.lastSubtrees[i][0]) {
-                    self.lastSubtrees[i][1] = hash;
-                }
-
-                hash = PoseidonT3.hash([proofSiblings[i], hash]);
-            }
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        if (updateIndex >= self.numberOfLeaves) {
-            revert LeafIndexOutOfRange();
-        }
-
-        self.root = hash;
-    }
-
-    /// @dev Removes a leaf from the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be removed.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    function _remove(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal {
-        _update(self, leaf, self.useDefaultZeroes ? Z_0 : self.zeroes[0], proofSiblings, proofPathIndices);
-    }
-
-    /// @dev Verify if the path is correct and the leaf is part of the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be removed.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    /// @return True or false.
-    function _verify(
-        BinaryIMTData storage self,
-        uint256 leaf,
-        uint256[] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal view returns (bool) {
-        uint256 depth = self.depth;
-
-        if (leaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (proofPathIndices.length != depth || proofSiblings.length != depth) {
-            revert WrongMerkleProofPath();
-        }
-
-        uint256 hash = leaf;
-
-        for (uint8 i = 0; i < depth;) {
-            if (proofSiblings[i] >= SNARK_SCALAR_FIELD) {
-                revert ValueGreaterThanSnarkScalarField();
-            } else if (proofPathIndices[i] != 1 && proofPathIndices[i] != 0) {
-                revert WrongMerkleProofPath();
-            }
-
-            if (proofPathIndices[i] == 0) {
-                hash = PoseidonT3.hash([hash, proofSiblings[i]]);
-            } else {
-                hash = PoseidonT3.hash([proofSiblings[i], hash]);
-            }
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        return hash == self.root;
-    }
-}
diff --git a/imt/src/InternalQuinaryIMT.sol b/imt/src/InternalQuinaryIMT.sol
deleted file mode 100644
index 5376702..0000000
--- a/imt/src/InternalQuinaryIMT.sol
+++ /dev/null
@@ -1,241 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {PoseidonT6} from "poseidon-solidity/PoseidonT6.sol";
-import {SNARK_SCALAR_FIELD, MAX_DEPTH} from "./Constants.sol";
-
-// Each incremental tree has certain properties and data that will
-// be used to add new leaves.
-struct QuinaryIMTData {
-    uint256 depth; // Depth of the tree (levels - 1).
-    uint256 root; // Root hash of the tree.
-    uint256 numberOfLeaves; // Number of leaves of the tree.
-    mapping(uint256 => uint256) zeroes; // Zero hashes used for empty nodes (level -> zero hash).
-    // The nodes of the subtrees used in the last addition of a leaf (level -> [nodes]).
-    mapping(uint256 => uint256[5]) lastSubtrees; // Caching these values is essential to efficient appends.
-}
-
-error ValueGreaterThanSnarkScalarField();
-error DepthNotSupported();
-error TreeIsFull();
-error NewLeafCannotEqualOldLeaf();
-error LeafDoesNotExist();
-error LeafIndexOutOfRange();
-error WrongMerkleProofPath();
-
-/// @title Incremental quinary Merkle tree.
-/// @dev The incremental tree allows to calculate the root hash each time a leaf is added, ensuring
-/// the integrity of the tree.
-library InternalQuinaryIMT {
-    /// @dev Initializes a tree.
-    /// @param self: Tree data.
-    /// @param depth: Depth of the tree.
-    /// @param zero: Zero value to be used.
-    function _init(QuinaryIMTData storage self, uint256 depth, uint256 zero) internal {
-        if (zero >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (depth <= 0 || depth > MAX_DEPTH) {
-            revert DepthNotSupported();
-        }
-
-        self.depth = depth;
-
-        for (uint8 i = 0; i < depth;) {
-            self.zeroes[i] = zero;
-            uint256[5] memory zeroChildren;
-
-            for (uint8 j = 0; j < 5;) {
-                zeroChildren[j] = zero;
-                unchecked {
-                    ++j;
-                }
-            }
-
-            zero = PoseidonT6.hash(zeroChildren);
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        self.root = zero;
-    }
-
-    /// @dev Inserts a leaf in the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be inserted.
-    function _insert(QuinaryIMTData storage self, uint256 leaf) internal {
-        uint256 depth = self.depth;
-
-        if (leaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (self.numberOfLeaves >= 5 ** depth) {
-            revert TreeIsFull();
-        }
-
-        uint256 index = self.numberOfLeaves;
-        uint256 hash = leaf;
-
-        for (uint8 i = 0; i < depth;) {
-            uint8 position = uint8(index % 5);
-
-            self.lastSubtrees[i][position] = hash;
-
-            if (position == 0) {
-                for (uint8 j = 1; j < 5;) {
-                    self.lastSubtrees[i][j] = self.zeroes[i];
-                    unchecked {
-                        ++j;
-                    }
-                }
-            }
-
-            hash = PoseidonT6.hash(self.lastSubtrees[i]);
-            index /= 5;
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        self.root = hash;
-        self.numberOfLeaves += 1;
-    }
-
-    /// @dev Updates a leaf in the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be updated.
-    /// @param newLeaf: New leaf.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    function _update(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256 newLeaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal {
-        if (newLeaf == leaf) {
-            revert NewLeafCannotEqualOldLeaf();
-        } else if (newLeaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (!_verify(self, leaf, proofSiblings, proofPathIndices)) {
-            revert LeafDoesNotExist();
-        }
-
-        uint256 depth = self.depth;
-        uint256 hash = newLeaf;
-        uint256 updateIndex;
-
-        for (uint8 i = 0; i < depth;) {
-            uint256[5] memory nodes;
-            updateIndex += proofPathIndices[i] * 5 ** i;
-
-            for (uint8 j = 0; j < 5;) {
-                if (j < proofPathIndices[i]) {
-                    nodes[j] = proofSiblings[i][j];
-                } else if (j == proofPathIndices[i]) {
-                    nodes[j] = hash;
-                } else {
-                    nodes[j] = proofSiblings[i][j - 1];
-                }
-                unchecked {
-                    ++j;
-                }
-            }
-
-            if (nodes[0] == self.lastSubtrees[i][0] || nodes[4] == self.lastSubtrees[i][4]) {
-                self.lastSubtrees[i][proofPathIndices[i]] = hash;
-            }
-
-            hash = PoseidonT6.hash(nodes);
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        if (updateIndex >= self.numberOfLeaves) {
-            revert LeafIndexOutOfRange();
-        }
-
-        self.root = hash;
-    }
-
-    /// @dev Removes a leaf from the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be removed.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    function _remove(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal {
-        _update(self, leaf, self.zeroes[0], proofSiblings, proofPathIndices);
-    }
-
-    /// @dev Verify if the path is correct and the leaf is part of the tree.
-    /// @param self: Tree data.
-    /// @param leaf: Leaf to be removed.
-    /// @param proofSiblings: Array of the sibling nodes of the proof of membership.
-    /// @param proofPathIndices: Path of the proof of membership.
-    /// @return True or false.
-    function _verify(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) internal view returns (bool) {
-        uint256 depth = self.depth;
-
-        if (leaf >= SNARK_SCALAR_FIELD) {
-            revert ValueGreaterThanSnarkScalarField();
-        } else if (proofPathIndices.length != depth || proofSiblings.length != depth) {
-            revert WrongMerkleProofPath();
-        }
-
-        uint256 hash = leaf;
-
-        for (uint8 i = 0; i < depth;) {
-            uint256[5] memory nodes;
-
-            if (proofPathIndices[i] < 0 || proofPathIndices[i] >= 5) {
-                revert WrongMerkleProofPath();
-            }
-
-            for (uint8 j = 0; j < 5;) {
-                if (j < proofPathIndices[i]) {
-                    require(
-                        proofSiblings[i][j] < SNARK_SCALAR_FIELD,
-                        "QuinaryIMT: sibling node must be < SNARK_SCALAR_FIELD"
-                    );
-
-                    nodes[j] = proofSiblings[i][j];
-                } else if (j == proofPathIndices[i]) {
-                    nodes[j] = hash;
-                } else {
-                    require(
-                        proofSiblings[i][j - 1] < SNARK_SCALAR_FIELD,
-                        "QuinaryIMT: sibling node must be < SNARK_SCALAR_FIELD"
-                    );
-
-                    nodes[j] = proofSiblings[i][j - 1];
-                }
-
-                unchecked {
-                    ++j;
-                }
-            }
-
-            hash = PoseidonT6.hash(nodes);
-
-            unchecked {
-                ++i;
-            }
-        }
-
-        return hash == self.root;
-    }
-}
diff --git a/imt/src/LICENSE b/imt/src/LICENSE
deleted file mode 100644
index 8ef16f7..0000000
--- a/imt/src/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2024 Ethereum Foundation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/imt/src/QuinaryIMT.sol b/imt/src/QuinaryIMT.sol
deleted file mode 100644
index 41f028f..0000000
--- a/imt/src/QuinaryIMT.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {InternalQuinaryIMT, QuinaryIMTData} from "./InternalQuinaryIMT.sol";
-
-library QuinaryIMT {
-    using InternalQuinaryIMT for *;
-
-    function init(QuinaryIMTData storage self, uint256 depth, uint256 zero) public {
-        InternalQuinaryIMT._init(self, depth, zero);
-    }
-
-    function insert(QuinaryIMTData storage self, uint256 leaf) public {
-        InternalQuinaryIMT._insert(self, leaf);
-    }
-
-    function update(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256 newLeaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) public {
-        InternalQuinaryIMT._update(self, leaf, newLeaf, proofSiblings, proofPathIndices);
-    }
-
-    function remove(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) public {
-        InternalQuinaryIMT._remove(self, leaf, proofSiblings, proofPathIndices);
-    }
-
-    function verify(
-        QuinaryIMTData storage self,
-        uint256 leaf,
-        uint256[4][] calldata proofSiblings,
-        uint8[] calldata proofPathIndices
-    ) private view returns (bool) {
-        return InternalQuinaryIMT._verify(self, leaf, proofSiblings, proofPathIndices);
-    }
-}
diff --git a/lazy-imt/README.md b/lazy-imt/README.md
deleted file mode 100644
index 8073eaa..0000000
--- a/lazy-imt/README.md
+++ /dev/null
@@ -1,60 +0,0 @@
-<p align="center">
-    <h1 align="center">
-         Lazy Incremental Merkle Tree (Solidity)
-    </h1>
-    <p align="center">Lazy Incremental Merkle tree implementation in Solidity.</p>
-</p>
-
-<p align="center">
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity">
-        <img src="https://img.shields.io/badge/project-zk--kit-blue.svg?style=flat-square">
-    </a>
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/imt.sol/contracts/LICENSE">
-        <img alt="NPM license" src="https://img.shields.io/npm/l/%40zk-kit%2Flazy-imt.sol?style=flat-square">
-    </a>
-    <a href="https://www.npmjs.com/package/@zk-kit/lazy-imt.sol">
-        <img alt="NPM version" src="https://img.shields.io/npm/v/@zk-kit/lazy-imt.sol?style=flat-square" />
-    </a>
-    <a href="https://npmjs.org/package/@zk-kit/lazy-imt.sol">
-        <img alt="Downloads" src="https://img.shields.io/npm/dm/@zk-kit/lazy-imt.sol.svg?style=flat-square" />
-    </a>
-    <a href="https://prettier.io/">
-        <img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
-    </a>
-</p>
-
-<div align="center">
-    <h4>
-        <a href="https://appliedzkp.org/discord">
-            🗣️ Chat &amp; Support
-        </a>
-    </h4>
-</div>
-
-> [!WARNING]  
-> These library has **not** been audited.
-
-> [!WARNING]  
-> If you are looking for the first version of this package, please visit this [link](https://github.com/privacy-scaling-explorations/zk-kit/tree/imt-v1/packages/incremental-merkle-tree.sol).
-
----
-
-## 🛠 Install
-
-### npm or yarn
-
-Install the `@zk-kit/lazy-imt.sol` package with npm:
-
-```bash
-npm i @zk-kit/lazy-imt.sol --save
-```
-
-or yarn:
-
-```bash
-yarn add @zk-kit/lazy-imt.sol
-```
-
-## 📜 Usage
-
-Please, see the [test contracts](./test) for guidance on utilizing the libraries.
diff --git a/lazy-imt/src/Constants.sol b/lazy-imt/src/Constants.sol
deleted file mode 100644
index 9f3c455..0000000
--- a/lazy-imt/src/Constants.sol
+++ /dev/null
@@ -1,5 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.4;
-
-uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
-uint8 constant MAX_DEPTH = 32;
diff --git a/lazy-imt/src/InternalLazyIMT.sol b/lazy-imt/src/InternalLazyIMT.sol
deleted file mode 100644
index 15ba265..0000000
--- a/lazy-imt/src/InternalLazyIMT.sol
+++ /dev/null
@@ -1,265 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {PoseidonT3} from "poseidon-solidity/PoseidonT3.sol";
-import {SNARK_SCALAR_FIELD, MAX_DEPTH} from "./Constants.sol";
-
-struct LazyIMTData {
-    uint40 maxIndex;
-    uint40 numberOfLeaves;
-    mapping(uint256 => uint256) elements;
-}
-
-library InternalLazyIMT {
-    uint40 internal constant MAX_INDEX = (1 << 32) - 1;
-
-    uint256 internal constant Z_0 = 0;
-    uint256 internal constant Z_1 = 14744269619966411208579211824598458697587494354926760081771325075741142829156;
-    uint256 internal constant Z_2 = 7423237065226347324353380772367382631490014989348495481811164164159255474657;
-    uint256 internal constant Z_3 = 11286972368698509976183087595462810875513684078608517520839298933882497716792;
-    uint256 internal constant Z_4 = 3607627140608796879659380071776844901612302623152076817094415224584923813162;
-    uint256 internal constant Z_5 = 19712377064642672829441595136074946683621277828620209496774504837737984048981;
-    uint256 internal constant Z_6 = 20775607673010627194014556968476266066927294572720319469184847051418138353016;
-    uint256 internal constant Z_7 = 3396914609616007258851405644437304192397291162432396347162513310381425243293;
-    uint256 internal constant Z_8 = 21551820661461729022865262380882070649935529853313286572328683688269863701601;
-    uint256 internal constant Z_9 = 6573136701248752079028194407151022595060682063033565181951145966236778420039;
-    uint256 internal constant Z_10 = 12413880268183407374852357075976609371175688755676981206018884971008854919922;
-    uint256 internal constant Z_11 = 14271763308400718165336499097156975241954733520325982997864342600795471836726;
-    uint256 internal constant Z_12 = 20066985985293572387227381049700832219069292839614107140851619262827735677018;
-    uint256 internal constant Z_13 = 9394776414966240069580838672673694685292165040808226440647796406499139370960;
-    uint256 internal constant Z_14 = 11331146992410411304059858900317123658895005918277453009197229807340014528524;
-    uint256 internal constant Z_15 = 15819538789928229930262697811477882737253464456578333862691129291651619515538;
-    uint256 internal constant Z_16 = 19217088683336594659449020493828377907203207941212636669271704950158751593251;
-    uint256 internal constant Z_17 = 21035245323335827719745544373081896983162834604456827698288649288827293579666;
-    uint256 internal constant Z_18 = 6939770416153240137322503476966641397417391950902474480970945462551409848591;
-    uint256 internal constant Z_19 = 10941962436777715901943463195175331263348098796018438960955633645115732864202;
-    uint256 internal constant Z_20 = 15019797232609675441998260052101280400536945603062888308240081994073687793470;
-    uint256 internal constant Z_21 = 11702828337982203149177882813338547876343922920234831094975924378932809409969;
-    uint256 internal constant Z_22 = 11217067736778784455593535811108456786943573747466706329920902520905755780395;
-    uint256 internal constant Z_23 = 16072238744996205792852194127671441602062027943016727953216607508365787157389;
-    uint256 internal constant Z_24 = 17681057402012993898104192736393849603097507831571622013521167331642182653248;
-    uint256 internal constant Z_25 = 21694045479371014653083846597424257852691458318143380497809004364947786214945;
-    uint256 internal constant Z_26 = 8163447297445169709687354538480474434591144168767135863541048304198280615192;
-    uint256 internal constant Z_27 = 14081762237856300239452543304351251708585712948734528663957353575674639038357;
-    uint256 internal constant Z_28 = 16619959921569409661790279042024627172199214148318086837362003702249041851090;
-    uint256 internal constant Z_29 = 7022159125197495734384997711896547675021391130223237843255817587255104160365;
-    uint256 internal constant Z_30 = 4114686047564160449611603615418567457008101555090703535405891656262658644463;
-    uint256 internal constant Z_31 = 12549363297364877722388257367377629555213421373705596078299904496781819142130;
-    uint256 internal constant Z_32 = 21443572485391568159800782191812935835534334817699172242223315142338162256601;
-
-    function _defaultZero(uint8 index) internal pure returns (uint256) {
-        if (index == 0) return Z_0;
-        if (index == 1) return Z_1;
-        if (index == 2) return Z_2;
-        if (index == 3) return Z_3;
-        if (index == 4) return Z_4;
-        if (index == 5) return Z_5;
-        if (index == 6) return Z_6;
-        if (index == 7) return Z_7;
-        if (index == 8) return Z_8;
-        if (index == 9) return Z_9;
-        if (index == 10) return Z_10;
-        if (index == 11) return Z_11;
-        if (index == 12) return Z_12;
-        if (index == 13) return Z_13;
-        if (index == 14) return Z_14;
-        if (index == 15) return Z_15;
-        if (index == 16) return Z_16;
-        if (index == 17) return Z_17;
-        if (index == 18) return Z_18;
-        if (index == 19) return Z_19;
-        if (index == 20) return Z_20;
-        if (index == 21) return Z_21;
-        if (index == 22) return Z_22;
-        if (index == 23) return Z_23;
-        if (index == 24) return Z_24;
-        if (index == 25) return Z_25;
-        if (index == 26) return Z_26;
-        if (index == 27) return Z_27;
-        if (index == 28) return Z_28;
-        if (index == 29) return Z_29;
-        if (index == 30) return Z_30;
-        if (index == 31) return Z_31;
-        if (index == 32) return Z_32;
-        revert("LazyIMT: defaultZero bad index");
-    }
-
-    function _init(LazyIMTData storage self, uint8 depth) internal {
-        require(depth <= MAX_DEPTH, "LazyIMT: Tree too large");
-        self.maxIndex = uint40((1 << depth) - 1);
-        self.numberOfLeaves = 0;
-    }
-
-    function _reset(LazyIMTData storage self) internal {
-        self.numberOfLeaves = 0;
-    }
-
-    function _indexForElement(uint8 level, uint40 index) internal pure returns (uint40) {
-        // store the elements sparsely
-        return MAX_INDEX * level + index;
-    }
-
-    function _insert(LazyIMTData storage self, uint256 leaf) internal {
-        uint40 index = self.numberOfLeaves;
-        require(leaf < SNARK_SCALAR_FIELD, "LazyIMT: leaf must be < SNARK_SCALAR_FIELD");
-        require(index < self.maxIndex, "LazyIMT: tree is full");
-
-        self.numberOfLeaves = index + 1;
-
-        uint256 hash = leaf;
-
-        for (uint8 i = 0;;) {
-            self.elements[_indexForElement(i, index)] = hash;
-            // it's a left element so we don't hash until there's a right element
-            if (index & 1 == 0) break;
-            uint40 elementIndex = _indexForElement(i, index - 1);
-            hash = PoseidonT3.hash([self.elements[elementIndex], hash]);
-            unchecked {
-                index >>= 1;
-                i++;
-            }
-        }
-    }
-
-    function _update(LazyIMTData storage self, uint256 leaf, uint40 index) internal {
-        require(leaf < SNARK_SCALAR_FIELD, "LazyIMT: leaf must be < SNARK_SCALAR_FIELD");
-        uint40 numberOfLeaves = self.numberOfLeaves;
-        require(index < numberOfLeaves, "LazyIMT: leaf must exist");
-
-        uint256 hash = leaf;
-
-        for (uint8 i = 0; true;) {
-            self.elements[_indexForElement(i, index)] = hash;
-            uint256 levelCount = numberOfLeaves >> (i + 1);
-            if (levelCount <= index >> 1) break;
-            if (index & 1 == 0) {
-                uint40 elementIndex = _indexForElement(i, index + 1);
-                hash = PoseidonT3.hash([hash, self.elements[elementIndex]]);
-            } else {
-                uint40 elementIndex = _indexForElement(i, index - 1);
-                hash = PoseidonT3.hash([self.elements[elementIndex], hash]);
-            }
-            unchecked {
-                index >>= 1;
-                i++;
-            }
-        }
-    }
-
-    function _root(LazyIMTData storage self) internal view returns (uint256) {
-        // this will always short circuit if self.numberOfLeaves == 0
-        uint40 numberOfLeaves = self.numberOfLeaves;
-        // dynamically determine a depth
-        uint8 depth = 1;
-        while (uint40(2) ** uint40(depth) < numberOfLeaves) {
-            depth++;
-        }
-        return _root(self, numberOfLeaves, depth);
-    }
-
-    function _root(LazyIMTData storage self, uint8 depth) internal view returns (uint256) {
-        require(depth > 0, "LazyIMT: depth must be > 0");
-        require(depth <= MAX_DEPTH, "LazyIMT: depth must be <= MAX_DEPTH");
-        uint40 numberOfLeaves = self.numberOfLeaves;
-        require(uint40(2) ** uint40(depth) >= numberOfLeaves, "LazyIMT: ambiguous depth");
-        return _root(self, numberOfLeaves, depth);
-    }
-
-    // Here it's assumed that the depth value is valid. If it is either 0 or > 2^8-1
-    // this function will panic.
-    function _root(LazyIMTData storage self, uint40 numberOfLeaves, uint8 depth) internal view returns (uint256) {
-        require(depth <= MAX_DEPTH, "LazyIMT: depth must be <= MAX_DEPTH");
-        // this should always short circuit if self.numberOfLeaves == 0
-        if (numberOfLeaves == 0) return _defaultZero(depth);
-        uint256[] memory levels = new uint256[](depth + 1);
-        _levels(self, numberOfLeaves, depth, levels);
-        return levels[depth];
-    }
-
-    function _levels(LazyIMTData storage self, uint40 numberOfLeaves, uint8 depth, uint256[] memory levels)
-        internal
-        view
-    {
-        require(depth <= MAX_DEPTH, "LazyIMT: depth must be <= MAX_DEPTH");
-        require(numberOfLeaves > 0, "LazyIMT: number of leaves must be > 0");
-        // this should always short circuit if self.numberOfLeaves == 0
-        uint40 index = numberOfLeaves - 1;
-
-        if (index & 1 == 0) {
-            levels[0] = self.elements[_indexForElement(0, index)];
-        } else {
-            levels[0] = _defaultZero(0);
-        }
-
-        for (uint8 i = 0; i < depth;) {
-            if (index & 1 == 0) {
-                levels[i + 1] = PoseidonT3.hash([levels[i], _defaultZero(i)]);
-            } else {
-                uint256 levelCount = (numberOfLeaves) >> (i + 1);
-                if (levelCount > index >> 1) {
-                    uint256 parent = self.elements[_indexForElement(i + 1, index >> 1)];
-                    levels[i + 1] = parent;
-                } else {
-                    uint256 sibling = self.elements[_indexForElement(i, index - 1)];
-                    levels[i + 1] = PoseidonT3.hash([sibling, levels[i]]);
-                }
-            }
-            unchecked {
-                index >>= 1;
-                i++;
-            }
-        }
-    }
-
-    function _merkleProofElements(LazyIMTData storage self, uint40 index, uint8 depth)
-        internal
-        view
-        returns (uint256[] memory)
-    {
-        uint40 numberOfLeaves = self.numberOfLeaves;
-        require(index < numberOfLeaves, "LazyIMT: leaf must exist");
-
-        uint8 targetDepth = 1;
-        while (uint40(2) ** uint40(targetDepth) < numberOfLeaves) {
-            targetDepth++;
-        }
-        require(depth >= targetDepth, "LazyIMT: proof depth");
-        // pass depth -1 because we don't need the root value
-        uint256[] memory _elements = new uint256[](depth);
-        _levels(self, numberOfLeaves, targetDepth - 1, _elements);
-
-        // unroll the bottom entry of the tree because it will never need to
-        // be pulled from _levels
-        if (index & 1 == 0) {
-            if (index + 1 >= numberOfLeaves) {
-                _elements[0] = _defaultZero(0);
-            } else {
-                _elements[0] = self.elements[_indexForElement(0, index + 1)];
-            }
-        } else {
-            _elements[0] = self.elements[_indexForElement(0, index - 1)];
-        }
-        index >>= 1;
-
-        for (uint8 i = 1; i < depth;) {
-            uint256 currentLevelCount = numberOfLeaves >> i;
-            if (index & 1 == 0) {
-                // if the element is an uncomputed edge node we'll use the value set
-                // from _levels above
-                // otherwise set as usual below
-                if (index + 1 < currentLevelCount) {
-                    _elements[i] = self.elements[_indexForElement(i, index + 1)];
-                } else if (((numberOfLeaves - 1) >> i) <= index) {
-                    _elements[i] = _defaultZero(i);
-                }
-            } else {
-                _elements[i] = self.elements[_indexForElement(i, index - 1)];
-            }
-            unchecked {
-                index >>= 1;
-                i++;
-            }
-        }
-        return _elements;
-    }
-}
diff --git a/lazy-imt/src/LazyIMT.sol b/lazy-imt/src/LazyIMT.sol
deleted file mode 100644
index 48a2da8..0000000
--- a/lazy-imt/src/LazyIMT.sol
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {InternalLazyIMT, LazyIMTData} from "./InternalLazyIMT.sol";
-
-library LazyIMT {
-    using InternalLazyIMT for *;
-
-    function init(LazyIMTData storage self, uint8 depth) public {
-        InternalLazyIMT._init(self, depth);
-    }
-
-    function defaultZero(uint8 index) public pure returns (uint256) {
-        return InternalLazyIMT._defaultZero(index);
-    }
-
-    function reset(LazyIMTData storage self) public {
-        InternalLazyIMT._reset(self);
-    }
-
-    function indexForElement(uint8 level, uint40 index) public pure returns (uint40) {
-        return InternalLazyIMT._indexForElement(level, index);
-    }
-
-    function insert(LazyIMTData storage self, uint256 leaf) public {
-        InternalLazyIMT._insert(self, leaf);
-    }
-
-    function update(LazyIMTData storage self, uint256 leaf, uint40 index) public {
-        InternalLazyIMT._update(self, leaf, index);
-    }
-
-    function root(LazyIMTData storage self) public view returns (uint256) {
-        return InternalLazyIMT._root(self);
-    }
-
-    function root(LazyIMTData storage self, uint8 depth) public view returns (uint256) {
-        return InternalLazyIMT._root(self, depth);
-    }
-
-    function merkleProofElements(LazyIMTData storage self, uint40 index, uint8 depth)
-        public
-        view
-        returns (uint256[] memory)
-    {
-        return InternalLazyIMT._merkleProofElements(self, index, depth);
-    }
-
-    function _root(LazyIMTData storage self, uint40 numberOfLeaves, uint8 depth) internal view returns (uint256) {
-        return InternalLazyIMT._root(self, numberOfLeaves, depth);
-    }
-}
diff --git a/lazytower/README.md b/lazytower/README.md
deleted file mode 100644
index dcaa8a5..0000000
--- a/lazytower/README.md
+++ /dev/null
@@ -1,138 +0,0 @@
-<p align="center">
-    <h1 align="center">
-         LazyTower (Solidity)
-    </h1>
-    <p align="center">LazyTower Solidity library.</p>
-</p>
-
-<p align="center">
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity">
-        <img src="https://img.shields.io/badge/project-zk--kit-blue.svg?style=flat-square">
-    </a>
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/lazytower.sol/LICENSE">
-        <img alt="NPM license" src="https://img.shields.io/npm/l/%40zk-kit%2Flazytower.sol?style=flat-square">
-    </a>
-    <a href="https://www.npmjs.com/package/@zk-kit/lazytower.sol">
-        <img alt="NPM version" src="https://img.shields.io/npm/v/@zk-kit/lazytower.sol?style=flat-square" />
-    </a>
-    <a href="https://npmjs.org/package/@zk-kit/lazytower.sol">
-        <img alt="Downloads" src="https://img.shields.io/npm/dm/@zk-kit/lazytower.sol.svg?style=flat-square" />
-    </a>
-    <a href="https://prettier.io/">
-        <img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
-    </a>
-</p>
-
-<div align="center">
-    <h4>
-        <a href="https://appliedzkp.org/discord">
-            🗣️ Chat &amp; Support
-        </a>
-    </h4>
-</div>
-
-> [!WARNING]  
-> These library has **not** been audited.
-
----
-
-## 🛠 Install
-
-### npm or yarn
-
-Install the `@zk-kit/lazytower.sol` package with npm:
-
-```bash
-npm i @zk-kit/lazytower.sol --save
-```
-
-or yarn:
-
-```bash
-yarn add @zk-kit/lazytower.sol
-```
-
-## 📜 Usage
-
-### Importing and using the library
-
-```solidity
-// SPDX-License-Identifier: MIT
-
-pragma solidity ^0.8.4;
-
-import "../LazyTowerHashChain.sol";
-
-contract LazyTowerHashChainTest {
-    using LazyTowerHashChain for LazyTowerHashChainData;
-
-    event Add(uint256 item);
-
-    // map for multiple test cases
-    mapping(bytes32 => LazyTowerHashChainData) public towers;
-
-    function add(bytes32 _towerId, uint256 _item) external {
-        towers[_towerId].add(_item);
-        emit Add(_item);
-    }
-
-    function getDataForProving(bytes32 _towerId) external view returns (uint256, uint256[] memory, uint256) {
-        return towers[_towerId].getDataForProving();
-    }
-}
-```
-
-### Creating an Hardhat task to deploy the contract
-
-```typescript
-import { Contract } from "ethers"
-import { task, types } from "hardhat/config"
-
-task("deploy:lazytower-test", "Deploy a LazyTowerHashChainTest contract")
-    .addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
-    .setAction(async ({ logs }, { ethers }): Promise<Contract> => {
-        const PoseidonT3Factory = await ethers.getContractFactory("PoseidonT3")
-        const PoseidonT3 = await PoseidonT3Factory.deploy()
-
-        if (logs) {
-            console.info(`PoseidonT3 library has been deployed to: ${PoseidonT3.address}`)
-        }
-
-        const LazyTowerLibFactory = await ethers.getContractFactory("LazyTowerHashChain", {
-            libraries: {
-                PoseidonT3: PoseidonT3.address
-            }
-        })
-        const lazyTowerLib = await LazyTowerLibFactory.deploy()
-
-        await lazyTowerLib.deployed()
-
-        if (logs) {
-            console.info(`LazyTowerHashChain library has been deployed to: ${lazyTowerLib.address}`)
-        }
-
-        const ContractFactory = await ethers.getContractFactory("LazyTowerHashChainTest", {
-            libraries: {
-                LazyTowerHashChain: lazyTowerLib.address
-            }
-        })
-
-        const contract = await ContractFactory.deploy()
-
-        await contract.deployed()
-
-        if (logs) {
-            console.info(`Test contract has been deployed to: ${contract.address}`)
-        }
-
-        return contract
-    })
-```
-
-## Contacts
-
-### Developers
-
--   e-mail : lcamel@gmail.com
--   github : [@LCamel](https://github.com/LCamel)
--   website : https://www.facebook.com/LCamel
diff --git a/lazytower/src/LazyTowerHashChain.sol b/lazytower/src/LazyTowerHashChain.sol
deleted file mode 100644
index a0fd6d1..0000000
--- a/lazytower/src/LazyTowerHashChain.sol
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {PoseidonT3} from "poseidon-solidity/PoseidonT3.sol";
-// CAPACITY = W * (W**0 + W**1 + ... + W**(H - 1)) = W * (W**H - 1) / (W - 1)
-// 4 * (4**24 - 1) / (4 - 1) = 375_299_968_947_540;
-
-uint256 constant H = 24;
-uint256 constant W = 4;
-
-uint256 constant bitsPerLevel = 4;
-uint256 constant levelBitmask = 15; // (1 << bitsPerLevel) - 1
-uint256 constant ones = 0x111111111111111111111111; // H ones
-
-// Each LazyTower has certain properties and data that will
-// be used to add new items.
-struct LazyTowerHashChainData {
-    uint256 levelLengths; // length of each level
-    uint256[H] digests; // digest of each level
-    uint256[H] digestOfDigests; // digest of digests
-}
-
-/// @title LazyTower.
-/// @dev The LazyTower allows to calculate the digest of digests each time an item is added, ensuring
-/// the integrity of the LazyTower.
-library LazyTowerHashChain {
-    uint256 internal constant SNARK_SCALAR_FIELD =
-        21888242871839275222246405745257275088548364400416034343698204186575808495617;
-
-    function findLowestNonFullLevelThenInc(uint256 levelLengths)
-        internal
-        pure
-        returns (uint256 level, bool isHead, bool isTop, uint256 newLevelLengths)
-    {
-        // find the lowest non-full level
-        uint256 levelLength;
-        while (true) {
-            levelLength = levelLengths & levelBitmask;
-            if (levelLength < W) break;
-            level++;
-            levelLengths >>= bitsPerLevel;
-        }
-
-        isHead = (levelLength == 0);
-        isTop = ((levelLengths >> bitsPerLevel) == 0);
-
-        // increment the non-full levelLength(s) by one
-        // all full levels below become ones
-        uint256 fullLevelBits = level * bitsPerLevel;
-        uint256 onesMask = (1 << fullLevelBits) - 1;
-        newLevelLengths = ((levelLengths + 1) << fullLevelBits) + (onesMask & ones);
-    }
-
-    /// @dev Add an item.
-    /// @param self: LazyTower data
-    /// @param item: item to be added
-    function add(LazyTowerHashChainData storage self, uint256 item) public {
-        require(item < SNARK_SCALAR_FIELD, "LazyTower: item must be < SNARK_SCALAR_FIELD");
-
-        uint256 level;
-        bool isHead;
-        bool isTop;
-        (level, isHead, isTop, self.levelLengths) = findLowestNonFullLevelThenInc(self.levelLengths);
-
-        uint256 digest;
-        uint256 digestOfDigests;
-        uint256 toAdd;
-
-        // append at the first non-full level
-        toAdd = (level == 0) ? item : self.digests[level - 1];
-        digest = isHead ? toAdd : PoseidonT3.hash([self.digests[level], toAdd]);
-        digestOfDigests = isTop ? digest : PoseidonT3.hash([self.digestOfDigests[level + 1], digest]);
-        self.digests[level] = digest;
-        self.digestOfDigests[level] = digestOfDigests;
-
-        // the rest of levels are all full
-        while (level != 0) {
-            level--;
-
-            toAdd = (level == 0) ? item : self.digests[level - 1];
-            digest = toAdd;
-            digestOfDigests = PoseidonT3.hash([digestOfDigests, digest]); // top-down
-            self.digests[level] = digest;
-            self.digestOfDigests[level] = digestOfDigests;
-        }
-    }
-
-    function getDataForProving(LazyTowerHashChainData storage self)
-        external
-        view
-        returns (uint256, uint256[] memory, uint256)
-    {
-        uint256 len = self.digests.length;
-        uint256[] memory digests = new uint256[](len); // for returning a dynamic array
-        for (uint256 i = 0; i < len; i++) {
-            digests[i] = self.digests[i];
-        }
-        return (self.levelLengths, digests, self.digestOfDigests[0]);
-    }
-}
diff --git a/lean-imt/README.md b/lean-imt/README.md
deleted file mode 100644
index 8c5e1cb..0000000
--- a/lean-imt/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-<p align="center">
-    <h1 align="center">
-         Lean Incremental Merkle Tree (Solidity)
-    </h1>
-    <p align="center">Lean Incremental Merkle tree implementation in Solidity.</p>
-</p>
-
-<p align="center">
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity">
-        <img src="https://img.shields.io/badge/project-zk--kit-blue.svg?style=flat-square">
-    </a>
-    <a href="https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/imt.sol/contracts/LICENSE">
-        <img alt="NPM license" src="https://img.shields.io/npm/l/%40zk-kit%2Flean-imt.sol?style=flat-square">
-    </a>
-    <a href="https://www.npmjs.com/package/@zk-kit/lean-imt.sol">
-        <img alt="NPM version" src="https://img.shields.io/npm/v/@zk-kit/lean-imt.sol?style=flat-square" />
-    </a>
-    <a href="https://npmjs.org/package/@zk-kit/lean-imt.sol">
-        <img alt="Downloads" src="https://img.shields.io/npm/dm/@zk-kit/lean-imt.sol.svg?style=flat-square" />
-    </a>
-    <a href="https://prettier.io/">
-        <img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
-    </a>
-</p>
-
-<div align="center">
-    <h4>
-        <a href="https://appliedzkp.org/discord">
-            🗣️ Chat &amp; Support
-        </a>
-    </h4>
-</div>
-
-> [!NOTE]  
-> This library has been audited as part of the Semaphore V4 PSE audit: https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf.
-
-The LeanIMT is an optimized binary version of the [IMT](https://github.com/privacy-scaling-explorations/zk-kit.solidity/tree/main/packages/imt) into binary-focused model, eliminating the need for zero values and allowing dynamic depth adjustment. Unlike the IMT, which uses a zero hash for incomplete nodes, the LeanIMT directly adopts the left child's value when a node lacks a right counterpart. The tree's depth dynamically adjusts to the count of leaves, enhancing efficiency by reducing the number of required hash calculations. To understand more about the LeanIMT, take a look at this [visual explanation](https://hackmd.io/@vplasencia/S1whLBN16).
-
----
-
-## 🛠 Install
-
-### npm or yarn
-
-Install the `@zk-kit/lean-imt.sol` package with npm:
-
-```bash
-npm i @zk-kit/lean-imt.sol --save
-```
-
-or yarn:
-
-```bash
-yarn add @zk-kit/lean-imt.sol
-```
-
-## 📜 Usage
-
-Please, see the [test contracts](./test) for guidance on utilizing the libraries.
diff --git a/lean-imt/src/Constants.sol b/lean-imt/src/Constants.sol
deleted file mode 100644
index 4e86b6e..0000000
--- a/lean-imt/src/Constants.sol
+++ /dev/null
@@ -1,4 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.4;
-
-uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
diff --git a/lean-imt/src/InternalLeanIMT.sol b/lean-imt/src/InternalLeanIMT.sol
deleted file mode 100644
index 8f5c593..0000000
--- a/lean-imt/src/InternalLeanIMT.sol
+++ /dev/null
@@ -1,342 +0,0 @@
-// 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];
-    }
-}
diff --git a/lean-imt/src/LeanIMT.sol b/lean-imt/src/LeanIMT.sol
deleted file mode 100644
index 552c88e..0000000
--- a/lean-imt/src/LeanIMT.sol
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.4;
-
-import {InternalLeanIMT, LeanIMTData} from "./InternalLeanIMT.sol";
-
-library LeanIMT {
-    using InternalLeanIMT for *;
-
-    function insert(LeanIMTData storage self, uint256 leaf) public returns (uint256) {
-        return InternalLeanIMT._insert(self, leaf);
-    }
-
-    function insertMany(LeanIMTData storage self, uint256[] calldata leaves) public returns (uint256) {
-        return InternalLeanIMT._insertMany(self, leaves);
-    }
-
-    function update(LeanIMTData storage self, uint256 oldLeaf, uint256 newLeaf, uint256[] calldata siblingNodes)
-        public
-        returns (uint256)
-    {
-        return InternalLeanIMT._update(self, oldLeaf, newLeaf, siblingNodes);
-    }
-
-    function remove(LeanIMTData storage self, uint256 oldLeaf, uint256[] calldata siblingNodes)
-        public
-        returns (uint256)
-    {
-        return InternalLeanIMT._remove(self, oldLeaf, siblingNodes);
-    }
-
-    function has(LeanIMTData storage self, uint256 leaf) public view returns (bool) {
-        return InternalLeanIMT._has(self, leaf);
-    }
-
-    function indexOf(LeanIMTData storage self, uint256 leaf) public view returns (uint256) {
-        return InternalLeanIMT._indexOf(self, leaf);
-    }
-
-    function root(LeanIMTData storage self) public view returns (uint256) {
-        return InternalLeanIMT._root(self);
-    }
-}