UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

304 lines (303 loc) 11.6 kB
/** * {@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>[]>;