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

Export more utility and bindings functions #2083

Merged
merged 34 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
60f7358
export constants
Trivo25 Mar 17, 2025
a1a9c57
export helpers
Trivo25 Mar 17, 2025
d0cf22e
bindings
Trivo25 Mar 17, 2025
ec962d4
dont use namespace
Trivo25 Mar 17, 2025
e256bd1
bindings
Trivo25 Mar 17, 2025
54dd608
export more helpers
Trivo25 Mar 18, 2025
e5f1a81
fix oxlint
Trivo25 Mar 18, 2025
4204816
more exports (tbd)
Trivo25 Mar 19, 2025
54c4ff0
Merge remote-tracking branch 'origin/remove-flaky-benchmarks' into ex…
Trivo25 Mar 20, 2025
ad4b3fd
export as Core (TBD)
Trivo25 Mar 20, 2025
6771d22
Move split to a better place
Trivo25 Mar 20, 2025
7f15e07
move slice field too
Trivo25 Mar 20, 2025
31598f0
doc comment for lib size constants
Trivo25 Mar 20, 2025
47f6f86
changelog
Trivo25 Mar 20, 2025
5c5bf1c
apply patch
Trivo25 Mar 20, 2025
268f724
move octets functions tbd
Trivo25 Mar 25, 2025
aff1675
export poseidon
Trivo25 Mar 27, 2025
7f3230c
move functions
Trivo25 Mar 27, 2025
de024f0
remove octets
Trivo25 Mar 27, 2025
99e46ed
move functions to internal use
Trivo25 Mar 27, 2025
565693d
Merge branch 'main' into export-util-functions
Trivo25 Mar 27, 2025
4e778bf
fix changelog
Trivo25 Mar 27, 2025
0278dc5
fix submodule
Trivo25 Mar 27, 2025
af5611c
fix weird merge conflict
Trivo25 Mar 27, 2025
f6be0c1
fix submodule
Trivo25 Mar 27, 2025
801c5a1
fix submodule
Trivo25 Mar 27, 2025
90de3b0
fix soundness of toProvableBytes and minor typos
querolita Mar 27, 2025
6fd211c
lint
querolita Mar 27, 2025
88ab2f8
soundness note in Field3.toBytes
querolita Mar 27, 2025
066a007
camelcase
querolita Mar 27, 2025
be5f37a
fix submodule
Trivo25 Mar 27, 2025
38db15c
Merge branch 'main' into export-util-functions
Trivo25 Mar 27, 2025
239ab49
cant import, thanks to circular dependencies :(
Trivo25 Mar 27, 2025
7fed175
remove unused imports
Trivo25 Mar 27, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Export various internal functions and types. https://github.com/o1-labs/o1js/pull/2083
- Export part of the core cryptography layer via the `Core` namespace. https://github.com/o1-labs/o1js/pull/2083
- _Experimental_ New bindings layer for new API types. https://github.com/o1-labs/o1js/pull/2032
- _Experimental_ New API types for https://github.com/o1-labs/o1js/pull/2042
- `AccountUpdate`, `Account`, `Authorization`, `Permissions` etc.
Expand Down
10 changes: 9 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export {
AlmostForeignField,
CanonicalForeignField,
} from './lib/provable/foreign-field.js';
export { createForeignCurve, ForeignCurve } from './lib/provable/crypto/foreign-curve.js';
export { createForeignCurve, ForeignCurve, toPoint } from './lib/provable/crypto/foreign-curve.js';
export type { FlexiblePoint } from './lib/provable/crypto/foreign-curve.js';
export { createEcdsa, EcdsaSignature } from './lib/provable/crypto/foreign-ecdsa.js';
export { ScalarField } from './lib/provable/scalar-field.js';
export { Poseidon, TokenSymbol, ProvableHashable } from './lib/provable/crypto/poseidon.js';
Expand All @@ -24,6 +25,10 @@ export type {
FlexibleProvablePure,
InferProvable,
} from './lib/provable/types/struct.js';

export { provableFromClass } from './lib/provable/types/provable-derivers.js';
export type { ProvablePureExtended } from './lib/provable/types/struct.js';

export { From, InferValue, InferJson, IsPure } from './bindings/lib/provable-generic.js';
export { ProvableType } from './lib/provable/types/provable-intf.js';
export { provable, provablePure } from './lib/provable/types/provable-derivers.js';
Expand Down Expand Up @@ -187,3 +192,6 @@ namespace Experimental {
}

Error.stackTraceLimit = 100000;

// export parts of the low-level bindings interface for advanced users
export * as Core from './bindings/index.js';
2 changes: 2 additions & 0 deletions src/lib/provable/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,8 @@ class Field {
* Create an array of digits equal to the [little-endian](https://en.wikipedia.org/wiki/Endianness) byte order of the given {@link Field} element.
* Note that the array has always 32 elements as the {@link Field} is a `finite-field` in the order of {@link Field.ORDER}.
*
* **Warning**: This operation does _not_ affect the circuit and can't be used to prove anything about the byte representation of the {@link Field}.
*
* @param value - The {@link Field} element to generate the array of bytes of.
*
* @return An array of digits equal to the [little-endian](https://en.wikipedia.org/wiki/Endianness) byte order of the given {@link Field} element.
Expand Down
2 changes: 1 addition & 1 deletion src/lib/provable/foreign-field.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mod, Fp, FiniteField, createField } from '../../bindings/crypto/finite-field.js';
import { Field, checkBitLength, withMessage } from './field.js';
import { checkBitLength, Field, withMessage } from './field.js';
import { Provable } from './provable.js';
import { Bool } from './bool.js';
import { Tuple, TupleMap, TupleN } from '../util/types.js';
Expand Down
26 changes: 25 additions & 1 deletion src/lib/provable/gadgets/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { TupleN } from '../../util/types.js';
import { exists, existsOne } from '../core/exists.js';
import { createField } from '../core/field-constructor.js';
import { assert } from '../../util/assert.js';
import { ProvableType } from '../types/provable-intf.js';
import { Provable } from '../provable.js';

export { assertMul, assertBilinear, arrayGet, assertOneOf, assertNotVectorEquals };
export { assertMul, assertBilinear, arrayGet, assertOneOf, assertNotVectorEquals, arrayGetGeneric };

// internal
export { reduceToScaledVar, toLinearCombination, emptyCell, linear, bilinear, ScaledVar, Constant };
Expand Down Expand Up @@ -363,3 +365,25 @@ function getLinear(x: ScaledVar | Constant): [[bigint, VarFieldVar], bigint] {
}

const ScaledVar = { isVar, getVar, isConst, getConst };

/**
* Get value from array in O(n) constraints.
*
* Assumes that index is in [0, n), returns an unconstrained result otherwise.
*/
function arrayGetGeneric<T>(type: ProvableType<T>, array: T[], index: Field) {
type = ProvableType.get(type);
// witness result
let a = Provable.witness(type, () => array[Number(index)]);
let aFields = type.toFields(a);

// constrain each field of the result
let size = type.sizeInFields();
let arrays = array.map(type.toFields);

for (let j = 0; j < size; j++) {
let arrayFieldsJ = arrays.map((x) => x[j]);
arrayGet(arrayFieldsJ, index).assertEquals(aFields[j]);
}
return a;
}
25 changes: 1 addition & 24 deletions src/lib/provable/gadgets/elliptic-curve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import {
import { Bool } from '../bool.js';
import { provable } from '../types/provable-derivers.js';
import { assertPositiveInteger } from '../../../bindings/crypto/non-negative.js';
import { arrayGet, assertNotVectorEquals } from './basic.js';
import { arrayGetGeneric, assertNotVectorEquals } from './basic.js';
import { sliceField3 } from './bit-slices.js';
import { exists } from '../core/exists.js';
import { ProvableType } from '../types/provable-intf.js';

// external API
export { EllipticCurve, Point, Ecdsa };
Expand Down Expand Up @@ -673,28 +672,6 @@ function simpleMapToCurve(x: bigint, Curve: CurveAffine) {
return p;
}

/**
* Get value from array in O(n) constraints.
*
* Assumes that index is in [0, n), returns an unconstrained result otherwise.
*/
function arrayGetGeneric<T>(type: ProvableType<T>, array: T[], index: Field) {
type = ProvableType.get(type);
// witness result
let a = Provable.witness(type, () => array[Number(index)]);
let aFields = type.toFields(a);

// constrain each field of the result
let size = type.sizeInFields();
let arrays = array.map(type.toFields);

for (let j = 0; j < size; j++) {
let arrayFieldsJ = arrays.map((x) => x[j]);
arrayGet(arrayFieldsJ, index).assertEquals(aFields[j]);
}
return a;
}

// type/conversion helpers

const Point = {
Expand Down
18 changes: 18 additions & 0 deletions src/lib/provable/gadgets/foreign-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const ForeignField = {

assertLessThan,
assertLessThanOrEqual,
assertEquals,

equals,
toCanonical,
Expand Down Expand Up @@ -406,6 +407,19 @@ function equals(x: Field3, c: bigint, f: bigint) {
}
}

// Field3 equality checking that each of the 3 limbs are exactly the same (not modular equality).
function assertEquals(x: Field3, y: Field3) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cherry picked from #1949

// constant case
if (Field3.isConstant(x) && Field3.isConstant(y)) {
assert(Field3.toBigint(x) === Field3.toBigint(y), 'assertEqual: got x != y');
return;
}
//provable case
x[0].assertEquals(y[0]);
x[1].assertEquals(y[1]);
x[2].assertEquals(y[2]);
}

/**
* Convert x, which may be unreduced, to a canonical representative < f.
*
Expand Down Expand Up @@ -471,6 +485,10 @@ const Field3 = {
return x;
},
} satisfies ProvablePureExtended<Field3, bigint, [string, string, string]>,
/**
* Splits a bigint into three limbs using bitwise operations.
*/
split,
};

type Field2 = [Field, Field];
Expand Down
54 changes: 51 additions & 3 deletions src/lib/provable/gadgets/gadgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import {
rangeCheck64,
rangeCheckN,
isDefinitelyInRangeN,
l2Mask,
lMask,
l2,
l,
l3,
} from './range-check.js';
import {
not,
Expand All @@ -29,7 +34,8 @@ import { SHA2 } from './sha2.js';
import { SHA256 } from './sha256.js';
import { BLAKE2B } from './blake2b.js';
import { rangeCheck3x12 } from './lookup.js';
import { arrayGet } from './basic.js';
import { arrayGet, arrayGetGeneric } from './basic.js';
import { sliceField3 } from './bit-slices.js';

export { Gadgets, Field3, ForeignFieldSum };

Expand All @@ -51,6 +57,12 @@ const Gadgets = {
* **Note**: This saves n constraints compared to `Provable.switch(array.map((_, i) => index.equals(i)), type, array)`.
*/
arrayGet,
/**
* Get value from array in O(n) constraints.
*
* Assumes that index is in [0, n), returns an unconstrained result otherwise.
*/
arrayGetGeneric,

/**
* Asserts that the input value is in the range [0, 2^64).
Expand Down Expand Up @@ -626,6 +638,17 @@ const Gadgets = {
return ForeignField.add(x, y, f);
},

/**
* Check whether `x = c mod f`
*
* `c` is a constant, and we require `c` in `[0, f)`
*
* Assumes that `x` is almost reduced modulo `f`, so we know that `x` might be `c` or `c + f`, but not `c + 2f`, `c + 3f`, ...
*/
equals(x: Field3, c: bigint, f: bigint) {
return ForeignField.equals(x, c, f);
},

/**
* Foreign field subtraction: `x - y mod f`
*
Expand Down Expand Up @@ -788,9 +811,10 @@ const Gadgets = {
x: Field3 | ForeignFieldSum,
y: Field3 | ForeignFieldSum,
z: Field3 | ForeignFieldSum,
f: bigint
f: bigint,
message?: string
) {
return ForeignField.assertMul(x, y, z, f);
return ForeignField.assertMul(x, y, z, f, message);
},

/**
Expand Down Expand Up @@ -870,6 +894,12 @@ const Gadgets = {
ForeignField.assertLessThanOrEqual(x, f);
},

/**
* Proves that x is equal to y.
*/
assertEquals(x: Field3, y: Field3) {
ForeignField.assertEquals(x, y);
},
/**
* Convert x, which may be unreduced, to a canonical representative xR < f
* such that x = xR mod f
Expand All @@ -880,6 +910,12 @@ const Gadgets = {
toCanonical(x: Field3, f: bigint) {
return ForeignField.toCanonical(x, f);
},
/**
* Provable method for slicing a 3x88-bit bigint into smaller bit chunks of length `chunkSize`
*
* This serves as a range check that the input is in [0, 2^maxBits)
*/
sliceField3,
},

/**
Expand All @@ -888,6 +924,7 @@ const Gadgets = {
* **Note:** This interface does not contain any provable methods.
*/
Field3,

/**
* Division modulo 2^32. The operation decomposes a {@link Field} element in the range [0, 2^64) into two 32-bit limbs, `remainder` and `quotient`, using the following equation: `n = quotient * 2^32 + remainder`.
*
Expand Down Expand Up @@ -1023,4 +1060,15 @@ const Gadgets = {
*
*/
BLAKE2B: BLAKE2B,

/**
* Default limb size constants mostly used in range checks.
*/
Constants: {
l2Mask,
l,
l2,
l3,
lMask,
},
};
1 change: 1 addition & 0 deletions src/snarky.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ declare const Snarky: {
* Check whether we are inside an asProver or exists block
*/
inProverBlock(): boolean;

/**
* Setting that controls whether snarky throws an exception on violated constraint.
*/
Expand Down
Loading