Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Provable to documentation #1972

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 248 additions & 2 deletions src/lib/provable/provable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
* - 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,
InferProvable,
ProvableExtended,
} from './types/struct.js';
import { Context } from '../util/global-context.js';
Expand All @@ -26,11 +28,12 @@ import {
generateWitness,
} from './core/provable-context.js';
import { witness, witnessAsync, witnessFields } from './types/witness.js';
import { InferValue } from '../../bindings/lib/provable-generic.js';
import { From, InferValue } from '../../bindings/lib/provable-generic.js';
import { ToProvable } from '../../lib/provable/types/provable-intf.js';
import { TupleN } from '../util/types.js';

// external API
export { Provable };
export { Provable, ProvableNamespace };

// internal API
export {
Expand All @@ -51,9 +54,236 @@ export {
* 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.
*
* For documentation about the methods in the `Provable` namespace, see {@link ProvableNamespace}.
*/
type Provable<T, TValue = any> = Provable_<T, TValue>;

/**
* The `Provable` namespace contains methods for writing provable code.
*
* Access these methods by importing `Provable` from o1js.
*
*/
type ProvableNamespace = {
/**
* 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.
* @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);
* ```
*/
witness: <
A extends ProvableType<any, any>,
T extends From<ToProvable<A>> = From<ToProvable<A>>
>(
type: A,
compute: () => T
) => InferProvable<ToProvable<A>>;
/**
* 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: <N extends number, C extends () => TupleN<bigint | Field, N>>(
size: N,
compute: C
) => TupleN<Field, N>;
/**
* Create a new witness from an async callback.
*
* See {@link Provable.witness} for more information.
*/
witnessAsync: <
A extends ProvableType<any, any>,
T extends From<ToProvable<A>> = From<ToProvable<A>>
>(
type: A,
compute: () => Promise<T>
) => Promise<T>;
/**
* 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: <T>(condition: Bool, type: FlexibleProvableType<T>, x: T, y: T) => T;
/**
* 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: <T, A extends FlexibleProvableType<T>>(
mask: Bool[],
type: A,
values: T[],
{
allowNonExclusive,
}?: {
allowNonExclusive?: boolean | undefined;
}
) => T;
/**
* 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: <T>(type: FlexibleProvableType<T>, x: T, y: T) => void;
/**
* Asserts that two values are equal, if an enabling condition is true.
*
* If the condition is false, the assertion is skipped.
*/
assertEqualIf: <A, T>(enabled: Bool, type: A, x: T, y: T) => void;
/**
* 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: <T>(type: FlexibleProvableType<T>, x: T, y: T) => Bool;
/**
* Creates a {@link Provable} for a generic array.
* @example
* ```ts
* const ProvableArray = Provable.Array(Field, 5);
* ```
*/
Array: <A extends FlexibleProvableType<any>>(
elementType: A,
length: number
) => InferredProvable<ToProvable<A>[]>;
/**
* 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: <T>(type: ProvableType<T>, x: T) => boolean;
/**
* Interface to log elements within a circuit. Similar to `console.log()`.
* @example
* ```ts
* const element = Field(42);
* Provable.log(element);
* ```
*/
log: (...args: any) => void;
/**
* Runs code as a prover.
* @example
* ```ts
* Provable.asProver(() => {
* // Your prover code here
* });
* ```
*/
asProver: (f: () => void) => void;
/**
* 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: 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: Promise<void>;
/**
* Returns information about the constraints created by the callback function.
* @example
* ```ts
* const result = await Provable.constraintSystem(circuit);
* console.log(result);
* ```
*/
constraintSystem: (f: (() => Promise<void>) | (() => void)) => Promise<{}>;
/**
* Checks if the code is run in prover mode.
* @example
* ```ts
* if (Provable.inProver()) {
* // Prover-specific code
* }
* ```
*/
inProver: () => boolean;
/**
* Checks if the code is run in checked computation mode.
* @example
* ```ts
* if (Provable.inCheckedComputation()) {
* // Checked computation-specific code
* }
* ```
*/
inCheckedComputation: () => boolean;

/**
* 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>(type: Provable<T>, value: T) => T;
};

/**
* For documentation about the methods in the `Provable` namespace, see {@link ProvableNamespace}.
*/
/**
* The Provable namespace provides various utility functions and methods
* for working with provable computations and constraints.
*/
const Provable = {
/**
* Create a new witness. A witness, or variable, is a value that is provided as input
Expand All @@ -73,18 +303,21 @@ const Provable = {
* ```
*/
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,

/**
* Create a new witness from an async callback.
*
* See {@link Provable.witness} for more information.
*/
witnessAsync,

/**
* Proof-compatible if-statement.
* This behaves like a ternary conditional statement in JS.
Expand All @@ -100,6 +333,7 @@ const Provable = {
* ```
*/
if: 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.
Expand All @@ -111,6 +345,7 @@ const Provable = {
* ```
*/
switch: switch_,

/**
* Asserts that two values are equal.
* @example
Expand All @@ -122,12 +357,14 @@ const Provable = {
* ```
*/
assertEqual,

/**
* Asserts that two values are equal, if an enabling condition is true.
*
* If the condition is false, the assertion is skipped.
*/
assertEqualIf,

/**
* Checks if two elements are equal.
* @example
Expand All @@ -139,6 +376,7 @@ const Provable = {
* ```
*/
equal,

/**
* Creates a {@link Provable} for a generic array.
* @example
Expand All @@ -147,6 +385,7 @@ const Provable = {
* ```
*/
Array: provableArray,

/**
* Check whether a value is constant.
* See {@link FieldVar} for more information about constants and variables.
Expand All @@ -158,6 +397,7 @@ const Provable = {
* ```
*/
isConstant,

/**
* Interface to log elements within a circuit. Similar to `console.log()`.
* @example
Expand All @@ -167,6 +407,7 @@ const Provable = {
* ```
*/
log,

/**
* Runs code as a prover.
* @example
Expand All @@ -177,6 +418,7 @@ const Provable = {
* ```
*/
asProver,

/**
* Runs provable code quickly, without creating a proof, but still checking whether constraints are satisfied.
* @example
Expand All @@ -189,6 +431,7 @@ const Provable = {
async runAndCheck(f: (() => Promise<void>) | (() => void)) {
await generateWitness(f, { checkConstraints: true });
},

/**
* Runs provable code quickly, without creating a proof, and not checking whether constraints are satisfied.
* @example
Expand All @@ -201,6 +444,7 @@ const Provable = {
async runUnchecked(f: (() => Promise<void>) | (() => void)) {
await generateWitness(f, { checkConstraints: false });
},

/**
* Returns information about the constraints created by the callback function.
* @example
Expand All @@ -210,6 +454,7 @@ const Provable = {
* ```
*/
constraintSystem,

/**
* Checks if the code is run in prover mode.
* @example
Expand All @@ -220,6 +465,7 @@ const Provable = {
* ```
*/
inProver,

/**
* Checks if the code is run in checked computation mode.
* @example
Expand Down
Loading
Loading