/**
 * This module defines the `RuntimeTable` class, which represents a provable table whose entries
 * can be defined at runtime within the SNARK circuit. It allows inserting key-value pairs and
 * checking for their existence.
 */
import { Field } from "../field.js";
export { RuntimeTable, };
/**
 * # RuntimeTable
 *
 * A **provable lookup table** whose entries are defined at runtime (during circuit construction).
 * It constrains that certain `(index, value)` pairs *exist* in a table identified by `id`, using
 * efficient **lookup gates** under the hood. Each inner lookup gate can batch up to **3 pairs**.
 *
 * ## When to use
 * - **small/medium, runtime-chosen set** of `(index, value)` pairs and want to prove
 *   **membership** of queried pairs in that set.
 * - **ergonomic batching**: repeated `lookup()` calls automatically group into 3-tuples
 *   so it creates pay fewer gates when possible (instead of writing repetitive `Gates.lookup(...)`
 *   calls and manually handling batching of lookup entries).
 * - **expressiveness**: all runtime tables will be condensed into one long table under the hood,
 *   so it is highly recommended to use distinct `id`s for unrelated tables to achieve better
 *   separation of concerns and avoid accidental collisions, at no extra cost.
 *
 * ## When *not* to use
 * - **static and global tables**: Prefer built-ins for fixed-tables that already exist in the system.
 *   (a.k.a. standard 4-bit XOR or 12-bit length range-check tables).
 * - **hiding properties**: lookup tables **constrain membership**, but don’t provide secrecy
 *   of the values by themselves. If data privacy is needed, consider using the **witness** to hold
 *   the values and protect from exposure to the verifier.
 * - **huge tables**: runtime lookups are efficient for a limited amount of entries, but their
 *   size is limited by the underlying circuit size (i.e. 2^16). Applications needing more storage
 *   should consider an optimized custom solution.
 * - **mutable data**: runtime tables are write-once only, so once inserted entries in table are
 *   remain fixed. To represent changing data, consider using DynamicArrays.
 * - **unknown bounded size**: runtime lookup tables require all possible `indices` to be preallocated
 *   at construction time. If the set of possible indices is not known in advance, consider using
 *   DynamicArrays instead.
 *
 * ## Invariants & constraints
 * - `id !== 0 && id !== 1`. (Reserved for XOR and range-check tables.)
 * - `indices` are **unique**. Duplicates are rejected.
 * - `indices` must be **known** at construction time.
 * - `lookup()` **batches** each 3 calls (for the same table) into **one** gate automatically.
 * - `check()` call is required for soundness to flush 1–2 pending pairs before the end of the circuit.
 *
 * ## Complexity
 * - Gate cost for membership checks is ~`ceil(#pairs / 3)` lookup gates per table id,
 *   plus one lookup gate per `insert()` triplet.
 *
 * ## Example
 * ```ts
 * // Define a runtime table with id=5 and allowed indices {10n, 20n, 30n}
 * const rt = new RuntimeTable(5, [10n, 20n, 30n]);
 *
 * // Populate some pairs (you can insert in chunks of up to 3)
 * rt.insert([
 *   [10n, Field.from(123)],
 *   [20n, Field.from(456)],
 *   [30n, Field.from(789)],
 * ]);
 *
 * // Constrain that these pairs exist in the table
 * rt.lookup(10n, Field.from(123));
 * rt.lookup(20n, Field.from(456));
 * // These two calls will be grouped; add a third, or call check() to flush
 * rt.check(); // flush pending lookups (important!)
 * ```
 *
 * ## Gotchas
 * - **Don’t forget `check()`**: If you finish a proof block with 1–2 pending `lookup()` calls,
 *   call `check()` to emit the final lookup gate. Otherwise those constraints won’t land.
 * - **Index validation**: `insert()` and `lookup()` throw if the index isn’t whitelisted in `indices`.
 * - **ID collisions**: Pick distinct `id`s for unrelated runtime tables.
 * - **flag settings**: zkApps with runtime tables must be compiled with the `withRuntimeTables` flag.
 *
 * @remarks
 * Construction registers the table configuration via `Gates.addRuntimeTableConfig(id, indices)`.
 * Subsequent `insert()`/`lookup()` use that configuration to emit lookup gates. Please refrain from
 * using that function directly, as it will be deprecated in the future.
 *
 * @see Gates.lookup
 * @see Gates.addRuntimeTableConfig
 * @see Gadgets.inTable
 * @see DynamicArray for a mutable alternative to store runtime data.
 * @public
 */
declare class RuntimeTable {
    /**
     * Unique identifier for the runtime table.
     * Must be different than 0 and 1, as those values are reserved
     * for the XOR and range-check tables, respectively.
     */
    readonly id: number;
    /**
     * Indices that define the structure of the runtime table.
     * They can be consecutive or not, but they must be unique.
     */
    readonly indices: Set<bigint>;
    /**
     * Pending pairs to be checked on the runtime table.
     */
    pairs: Array<[Field, Field]>;
    constructor(id: number, indices: bigint[]);
    /**
     * Inserts key-value pairs into the runtime table.
     * Under the hood, this method uses the `Gates.lookup` function to perform
     * lookups to the table with identifier `this.id`. One single lookup gate
     * can store up to 3 different pairs of index and value.
     *
     * It throws when trying to insert a pair with an index that is not part of
     * the runtime table.
     *
     * @param pairs Array of pairs [index, value] to insert into the runtime table.
     * Each index can be a `bigint` or a `Field`.
     */
    insert(pairs: [bigint | Field, Field][]): void;
    /**
     * In-circuit checks if a key-value pair exists in the runtime table. Note
     * that the same index can be queried several times as long as the value
     * remains the same.
     *
     * Every three calls to this method for the same identifier will be grouped
     * into a single lookup gate for efficiency.
     *
     * @param idx The index of the key to check.
     * @param value The value to check.
     */
    lookup(idx: bigint | Field, value: Field): void;
    /**
     * Finalizes any pending checks by creating a Lookup when necessary.
     * This function must be called after all `lookup()` calls of the table
     * to ensure that all pending checks are looked up in the circuit.
     */
    check(): void;
}
