UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

309 lines (308 loc) 13.1 kB
import { Bool } from './bool.js'; import { Field } from './field.js'; import { Provable } from './provable.js'; import { type InferProvable } from './types/provable-derivers.js'; import { Option } from './option.js'; import { ProvableHashable, ProvableType } from './types/provable-intf.js'; import { type From, type InferValue } from '../../bindings/lib/provable-generic.js'; export { DynamicArray }; type DynamicArray<T = any, V = any> = DynamicArrayBase<T, V>; /** * Dynamic-length array type that has a * - constant maximum capacity, but * - dynamic actual length * * ```ts * const Bytes = DynamicArray(UInt8, { capacity: 32 }); * ``` * * `capacity` can be any number from 0 to 2^16-1. * * **Details**: Internally, this is represented as a static-sized array, plus a * Field element that represents the length. * The _only_ requirement on these is that the length is less or equal capacity. * In particular, there are no provable guarantees maintained on the content of * the static-sized array beyond the actual length. Instead, our methods ensure * integrity of array operations _within_ the actual length. */ declare function DynamicArray<ElementType extends ProvableType, ProvableValue extends InferProvable<ElementType> = InferProvable<ElementType>, Value extends InferValue<ElementType> = InferValue<ElementType>>(type: ElementType, { capacity, }: { capacity: number; }): typeof DynamicArrayBase<ProvableValue, Value> & { provable: ProvableHashable<DynamicArrayBase<ProvableValue, Value>, Value[]>; /** * Create a new DynamicArray from an array of values. * * Note: Both the actual length and the values beyond the original ones will * be constant. */ from(v: (ProvableValue | Value)[] | DynamicArrayBase<ProvableValue, Value>): DynamicArrayBase<ProvableValue, Value>; }; declare namespace DynamicArray { var Base: typeof DynamicArrayBase; } declare class DynamicArrayBase<ProvableValue = any, Value = any> { #private; /** * The internal array, which includes the actual values, padded up to * `capacity` with unconstrained values. */ array: ProvableValue[]; /** * Length of the array. Guaranteed to be in [0, capacity]. */ length: Field; get innerType(): Provable<ProvableValue, Value>; static get capacity(): number; get capacity(): number; get Constructor(): typeof DynamicArrayBase; /** * Create a new {@link DynamicArrayBase} instance from an optional list of * {@link ProvableValue} elements, and optional length. * * - If no parameters are passed, it creates an empty array of length 0. * - If only `array` is passed, it creates a new array with the elements * of the array. * - If only `length` is passed, it creates a dummy array of the given length * filled with NULL values. * - If both `array` and `length` are passed, it creates a new array with the * elements of the array, and the length of the dynamic array is set to the * `length` passed, which should be less or equal than the length of the * `array` passed (this is to allow for arrays with dummy values at the end). * - In any case, if `length` is larger than the capacity, it throws. * * @example * ```ts * let arr = new DynamicArray([new Field(1), new Field(2), new Field(3)]); * let empty = new DynamicArray(); * ``` * * Note: this is different from `ProvableValue[]` because it is a provable type. */ constructor(array?: ProvableValue[], length?: Field); /** * In-circuit assertion that the given index is within the bounds of the * dynamic array. * Asserts 0 <= i < this.length, using a cached check that's not * duplicated when doing it on the same variable multiple times, failing * with an error message otherwise. * * @param i - the index to check * @param message - optional error message to use in case the assertion fails */ assertIndexInRange(i: Field, message?: string): void; /** * Gets value at index i, and proves that the index is in the array. * It uses an internal cache to avoid duplication of constraints when the * same index is used multiple times. */ get(i: Field): ProvableValue; /** * Gets a value at index i, as an option that is None if the index is not in * the array. * * Note: The correct type for `i` is actually UInt16 which doesn't exist. The * method is not complete (but sound) for i >= 2^16. This means that if the * index is larger than 2^16, the constraints could be satisfiable but the * result is not correct (because the capacity can at most be 2^16). */ getOption(i: Field): Option<ProvableValue>; /** * Gets a value at index i, ASSUMING that the index is in the array. * * If the index is in fact not in the array, the return value is completely * unconstrained. * * **Warning**: Only use this if you already know/proved by other means that * the index is within bounds. */ getOrUnconstrained(i: Field): ProvableValue; /** * Sets a value at index i and proves that the index is in the array. */ set(i: Field, value: ProvableValue, message?: string): void; /** * Sets a value at index i, or does nothing if the index is not in the array */ setOrDoNothing(i: Field, value: ProvableValue): void; /** * Map every element of the array to a new value. * * **Warning**: The callback will be passed unconstrained dummy values. */ map<MapType extends ProvableType>(type: MapType, f: (t: ProvableValue) => From<MapType>): DynamicArray<InferProvable<MapType>, InferValue<MapType>>; /** * Iterate over all elements of the array. * * The callback will be passed an element and a boolean `isDummy` indicating * whether the value is part of the actual array. Optionally, an index can be * passed as a third argument (used in `forEachReversed`) */ forEach(f: (t: ProvableValue, isDummy: Bool, i?: number) => void): void; /** * Iterate over all elements of the array, in reverse order. * * The callback will be passed an element and a boolean `isDummy` indicating whether the value is part of the actual array. * * Note: the indices are also passed in reverse order, i.e. we always have `t = this.array[i]`. */ forEachReverse(f: (t: ProvableValue, isDummy: Bool, i: number) => void): void; /** * Return a version of the same array with a larger capacity. * * **Warning**: Does not modify the array, but returns a new one. * * **Note**: this doesn't cost constraints, but currently doesn't preserve any * cached constraints. * * @param capacity - the new capacity of the array */ growCapacityTo(capacity: number, message?: string): DynamicArray<ProvableValue, Value>; /** * Return a version of the same array with a larger capacity. * * **Warning**: Does not modify the array, but returns a new one. * * **Note**: this doesn't cost constraints, but currently doesn't preserve any * cached constraints. * * @param increment - the amount to increase the capacity by */ growCapacityBy(increment: number): DynamicArray<ProvableValue>; /** * Increments the length of the current array by n elements, checking that the * new length is within the capacity, failing with the error message otherwise. * * @param n - the number of elements to increase the length by * @param message - optional error message to use in case the assertion fails */ increaseLengthBy(n: Field, message?: string): void; /** * Decrements the length of the current array by `n` elements, checking that * the `n` is less or equal than the current length, failing with the error * message otherwise. * * @param n - the number of elements to decrease the length by * @param message - optional error message to use in case the assertion fails */ decreaseLengthBy(n: Field, message?: string): void; /** * Sets the length of the current array to a new value, checking that the * new length is less or equal than the capacity. * * An optional error message can be provided to be used in case the inner * assertion fails. * * @param newLength - the new length to set the array to * @param message - optional error message * * **Warning**: This does not change (add nor remove) the values of the array. */ setLengthTo(n: Field, message?: string): void; /** * Push a value, without changing the capacity. * * Proves that the new length is still within the capacity, fails otherwise. * * To grow the capacity along with the actual length, you can use: * * ```ts * array = array.growCapacityhBy(1); * array.push(value); * ``` * * @param value - the value to push into the array * @param message - optional error message to use in case the assertion fails */ push(value: ProvableValue, message?: string): void; /** * Removes the last `n` elements from the dynamic array, decreasing the length * by n. If no amount is provided, only one element is popped. The popped * positions are set to NULL values. * * @param n - the number of elements to pop (one if not provided) * @param message - optional error message to use in case the assertion fails */ pop(n?: Field, message?: string): void; /** * In-circuit check whether the array is empty. * * @returns true or false depending on whether the dynamic array is empty */ isEmpty(): Bool; /** * Shifts all elements of the array to the left by `n` positions, reducing * the length by `n`, which must be less than or equal to the current length * (failing with an error message otherwise). * * @param n - the number of positions to shift left * @param message - optional error message to use in case the assertion fails */ shiftLeft(n: Field, message?: string): void; /** * Shifts all elements of the array to the right by `n` positions, increasing * the length by `n`, which must result in less than or equal to the capacity * (failing with an error message otherwise). The new elements on the left are * set to NULL values. * * @param n - the number of positions to shift right * @param message - optional error message to use in case the assertion fails */ shiftRight(n: Field, message?: string): void; /** * Copies the current dynamic array, returning a new instance with the same * values and length. * * @returns a new DynamicArray instance with the same values as the current. * */ copy(): this; /** * Creates a new dynamic array with the values of the current array from * index `start` (included) to index `end` (excluded). If `start` is not * provided, it defaults to 0. If `end` is not provided, it defaults to the * length of the array. * * @param start - the starting index of the slice (inclusive) * @param end - the ending index of the slice (exclusive) * * @returns a new DynamicArray instance with the sliced values */ slice(start?: Field, end?: Field): DynamicArray<ProvableValue, Value>; /** * Returns a new array with the elements reversed. */ reverse(): DynamicArray<ProvableValue, Value>; /** * Concatenates the current array with another dynamic array, returning a new * dynamic array with the values of both arrays. The capacity of the new array * is the sum of the capacities of the two arrays. * * @param other - the dynamic array to concatenate * * @returns a new DynamicArray instance with the concatenated values */ concat(other: DynamicArray<ProvableValue, Value>): DynamicArray<ProvableValue, Value>; /** * Inserts a value at index i, shifting all elements after that position to * the right by one. The length of the array is increased by one, which must * result in less than or equal to the capacity. * * @param i - the index at which to insert the value * @param value - the value to insert * @param message - optional error message to use in case the assertion fails */ insert(index: Field, value: ProvableValue, message?: string): void; /** * Checks whether the dynamic array includes a value. * * @param value - the value to check for inclusion in the array * @returns */ includes(value: ProvableValue): Bool; /** * Converts the current instance of the dynamic array to a plain array of values. * * @returns An array of values representing the elements in the dynamic array. */ toValue(): Value[]; }