/**
 * {@link Provable} is
 * - a namespace with tools for writing provable code
 * - the main interface for types that can be used in provable code
 */
import { Bool } from './bool.js';
import { Field } from './field.js';
import { Provable as Provable_, ProvableType } from './types/provable-intf.js';
import type { FlexibleProvable, FlexibleProvableType } from './types/struct.js';
import { Context } from '../util/global-context.js';
import { InferProvableType, InferredProvable } from './types/provable-derivers.js';
import { inCheckedComputation, inProver, asProver, constraintSystem } from './core/provable-context.js';
import { witness, witnessAsync, witnessFields } from './types/witness.js';
import { ToProvable } from '../../lib/provable/types/provable-intf.js';
export { Provable };
export { memoizationContext, MemoizationContext, memoizeWitness, getBlindingValue };
/**
 * `Provable<T>` is the general interface for provable types in o1js.
 *
 * `Provable<T>` describes how a type `T` is made up of {@link Field} elements and "auxiliary" (non-provable) data.
 *
 * `Provable<T>` is the required input type in several methods in o1js.
 * One convenient way to create a `Provable<T>` is using `Struct`.
 *
 * All built-in provable types in o1js ({@link Field}, {@link Bool}, etc.) are instances of `Provable<T>` as well.
 *
 * Note: These methods are meant to be used by the library internally and are not directly when writing provable code.
 */
type Provable<T, TValue = any> = Provable_<T, TValue>;
declare const Provable: {
    /**
     * Create a new witness. A witness, or variable, is a value that is provided as input
     * by the prover. This provides a flexible way to introduce values from outside into the circuit.
     * However, note that nothing about how the value was created is part of the proof - `Provable.witness`
     * behaves exactly like user input. So, make sure that after receiving the witness you make any assertions
     * that you want to associate with it.
     *
     * The only constraints enforced on the witnessed value come from its type. This means
     * the witnessed value may be anything which satisfies the constraints defined in `Type.check()`.
     * Note that for composite types like ({@link Struct}s, the
     * default `Type.check()` method calls `check()` on each {@link Struct} field.
     *
     * **Warning:** Be *extremely wary* of any custom `check()` methods, which may have forgotten
     * to call `check()` on sub-components of the {@link Struct}.
     *
     * @example
     * Example for re-implementing `Field.inv` with the help of `witness`:
     * ```ts
     * let invX = Provable.witness(Field, () => {
     *   // compute the inverse of `x` outside the circuit, however you like!
     *   return Field.inv(x);
     * }
     * // prove that `invX` is really the inverse of `x`:
     * invX.mul(x).assertEquals(1);
     * ```
     *
     * Example for decomposing a 64-bit integer into two 32-bit limbs. {@link Provable.witness} will
     * prove that the two limbs are actually 32-bits, ensuring the decomposition is unique.
     * ```ts
     * function decompose(value: UInt64) {
     *   // get two arbitrary 32-bit values from the prover
     *   let lowerLimb = Provable.witness(UInt32, () => {
     *     return value.and(new UInt64(0xffffffffn)).toUInt32();
     *   });
     *   let upperLimb = Provable.witness(UInt32, () => {
     *     return value
     *       .and(new UInt64(0xffffffff00000000n))
     *       .div(2 ** 32)
     *       .toUInt32();
     *   });
     *   // prove the 32-bit lower and upper limbs match the 64-bit value
     *   value.assertEquals(
     *     lowerLimb
     *       .toUInt64()
     *       .add(upperLimb.toUInt64().mul(UInt64.from(2n ** 32n)))
     *   );
     * }
     * ```
     *
     * Modified example for decomposing a 64-bit integer into two 32-bit limbs.
     * This time we use a {@link Struct} to get both 32-bit values from the prover at once,
     * while still proving each limb is actually 32 bits.
     * ```ts
     * class Decomposition extends Struct({
     *   lower: UInt32,
     *   upper: UInt32,
     * }) {}
     *
     * function decompose(value: UInt64) {
     *   // get two arbitrary 32-bit values from the prover
     *   let limbs = Provable.witness(Decomposition, () => {
     *     return new Decomposition({
     *       lower: value.and(new UInt64(0xffffffffn)).toUInt32(),
     *       upper: value
     *         .and(new UInt64(0xffffffff00000000n))
     *         .div(2 ** 32)
     *         .toUInt32(),
     *     });
     *   });
     *   // prove the 32-bit lower and upper limbs match the 64-bit value
     *   value.assertEquals(
     *     limbs.lower
     *       .toUInt64()
     *       .add(limbs.upper.toUInt64().mul(UInt64.from(2n ** 32n)))
     *   );
     * }
     * ```
     */
    witness: typeof witness;
    /**
     * Witness a tuple of field elements. This works just like {@link Provable.witness},
     * but optimized for witnessing plain field elements, which is especially common
     * in low-level provable code.
     */
    witnessFields: typeof witnessFields;
    /**
     * Create a new witness from an async callback.
     *
     * See {@link Provable.witness} for more information.
     */
    witnessAsync: typeof witnessAsync;
    /**
     * Proof-compatible if-statement.
     * This behaves like a ternary conditional statement in JS.
     *
     * **Warning**: Since `Provable.if()` is a normal JS function call, both the if and the else branch
     * are evaluated before calling it. Therefore, you can't use this function
     * to guard against execution of one of the branches. It only allows you to pick one of two values.
     *
     * @example
     * ```ts
     * const condition = Bool(true);
     * const result = Provable.if(condition, Field(1), Field(2)); // returns Field(1)
     * ```
     */
    if: typeof if_;
    /**
     * Generalization of {@link Provable.if} for choosing between more than two different cases.
     * It takes a "mask", which is an array of `Bool`s that contains only one `true` element, a type/constructor, and an array of values of that type.
     * The result is that value which corresponds to the true element of the mask.
     * @example
     * ```ts
     * let x = Provable.switch([Bool(false), Bool(true)], Field, [Field(1), Field(2)]);
     * x.assertEquals(2);
     * ```
     */
    switch: typeof switch_;
    /**
     * Asserts that two values are equal.
     * @example
     * ```ts
     * class MyStruct extends Struct({ a: Field, b: Bool }) {};
     * const a: MyStruct = { a: Field(0), b: Bool(false) };
     * const b: MyStruct = { a: Field(1), b: Bool(true) };
     * Provable.assertEqual(MyStruct, a, b);
     * ```
     */
    assertEqual: typeof assertEqual;
    /**
     * Asserts that two values are equal, if an enabling condition is true.
     *
     * If the condition is false, the assertion is skipped.
     */
    assertEqualIf: typeof assertEqualIf;
    /**
     * Checks if two elements are equal.
     * @example
     * ```ts
     * class MyStruct extends Struct({ a: Field, b: Bool }) {};
     * const a: MyStruct = { a: Field(0), b: Bool(false) };
     * const b: MyStruct = { a: Field(1), b: Bool(true) };
     * const isEqual = Provable.equal(MyStruct, a, b);
     * ```
     */
    equal: typeof equal;
    /**
     * Creates a {@link Provable} for a generic array.
     * @example
     * ```ts
     * const ProvableArray = Provable.Array(Field, 5);
     * ```
     */
    Array: typeof provableArray;
    /**
     * @internal
     * Check whether a value is constant.
     * See {@link FieldVar} for more information about constants and variables.
     *
     * @example
     * ```ts
     * let x = Field(42);
     * Provable.isConstant(Field, x); // true
     * ```
     */
    isConstant: typeof isConstant;
    /**
     * Interface to log elements within a circuit. Similar to `console.log()`.
     * @example
     * ```ts
     * const element = Field(42);
     * Provable.log(element);
     * ```
     */
    log: typeof log;
    /**
     * Runs code as a prover.
     * @example
     * ```ts
     * Provable.asProver(() => {
     *   // Your prover code here
     * });
     * ```
     */
    asProver: typeof asProver;
    /**
     * Runs provable code quickly, without creating a proof, but still checking whether constraints are satisfied.
     * @example
     * ```ts
     * await Provable.runAndCheck(() => {
     *   // Your code to check here
     * });
     * ```
     */
    runAndCheck(f: (() => Promise<void>) | (() => void)): Promise<void>;
    /**
     * Runs provable code quickly, without creating a proof, and not checking whether constraints are satisfied.
     * @example
     * ```ts
     * await Provable.runUnchecked(() => {
     *   // Your code to run here
     * });
     * ```
     */
    runUnchecked(f: (() => Promise<void>) | (() => void)): Promise<void>;
    /**
     * Returns information about the constraints created by the callback function.
     * @example
     * ```ts
     * const result = await Provable.constraintSystem(circuit);
     * console.log(result);
     * ```
     */
    constraintSystem: typeof constraintSystem;
    /**
     * Checks if the code is run in prover mode.
     * @example
     * ```ts
     * if (Provable.inProver()) {
     *   // Prover-specific code
     * }
     * ```
     */
    inProver: typeof inProver;
    /**
     * Checks if the code is run in checked computation mode.
     * @example
     * ```ts
     * if (Provable.inCheckedComputation()) {
     *   // Checked computation-specific code
     * }
     * ```
     */
    inCheckedComputation: typeof inCheckedComputation;
    /**
     * Returns a constant version of a provable type.
     */
    toConstant<T>(type: ProvableType<T>, value: T): T;
    /**
     * Return a canonical version of a value, where
     * canonical is defined by the `type`.
     */
    toCanonical<T_1>(type: Provable<T_1, any>, value: T_1): T_1;
};
type ToFieldable = {
    toFields(): Field[];
};
declare function assertEqual<T>(type: FlexibleProvableType<T>, x: T, y: T): void;
declare function assertEqual<T extends ToFieldable>(x: T, y: T): void;
declare function equal<T>(type: FlexibleProvableType<T>, x: T, y: T): Bool;
declare function if_<T>(condition: Bool, type: FlexibleProvableType<T>, x: T, y: T): T;
declare function if_<T extends ToFieldable>(condition: Bool, x: T, y: T): T;
declare function switch_<T, A extends FlexibleProvableType<T>>(mask: Bool[], type: A, values: T[], { allowNonExclusive }?: {
    allowNonExclusive?: boolean | undefined;
}): T;
declare function assertEqualIf<A extends ProvableType<any>, T extends InferProvableType<A> = InferProvableType<A>>(enabled: Bool, type: A, x: T, y: T): void;
declare function isConstant<T>(type: ProvableType<T>, x: T): boolean;
declare function log(...args: any): void;
type MemoizationContext = {
    memoized: {
        fields: Field[];
        aux: any[];
    }[];
    currentIndex: number;
    blindingValue: Field;
};
declare let memoizationContext: Context.t<MemoizationContext>;
/**
 * Like Provable.witness, but memoizes the witness during transaction construction
 * for reuse by the prover. This is needed to witness non-deterministic values.
 */
declare function memoizeWitness<T>(type: FlexibleProvable<T>, compute: () => T): T;
declare function getBlindingValue(): Field;
declare function provableArray<A extends FlexibleProvableType<any>>(elementType: A, length: number): InferredProvable<ToProvable<A>[]>;
