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

Introduce recursive proofs from within ZkPrograms #1931

Merged
merged 39 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7a2f19a
create program state by default (we'll need it)
mitschabaude Nov 27, 2024
c700b18
lift collection of declared proofs into its own global context
mitschabaude Nov 28, 2024
907b202
revert unnecessary change and add comments
mitschabaude Nov 28, 2024
5b6145b
add `Proof.declare()`
mitschabaude Nov 28, 2024
b576a40
scaffold internal recursive proving feature
mitschabaude Nov 28, 2024
0f9b59e
implement recursive proving
mitschabaude Nov 28, 2024
5292142
add tests
mitschabaude Nov 28, 2024
9220094
simplify test
mitschabaude Nov 28, 2024
2250126
add test for internal proofs
mitschabaude Nov 28, 2024
afbbf93
add test to CI
mitschabaude Nov 28, 2024
258268e
move withThreadPool to common file
mitschabaude Nov 28, 2024
dbebf51
allow test to run in web
mitschabaude Nov 28, 2024
2738b59
bindings
mitschabaude Nov 28, 2024
e6b4e54
changelog
mitschabaude Nov 28, 2024
950dc43
Merge branch 'main' into feature/declare-proofs
mitschabaude Nov 28, 2024
3289b6b
properly constrain public input, and map inner args to constants
mitschabaude Nov 28, 2024
00a1c69
test witness arguments
mitschabaude Nov 28, 2024
62beb20
extract declared proofs during analyze, and refactor how maxProofsVer…
mitschabaude Nov 29, 2024
90c73af
change bindings API to expect proofs returned from js circuit and not…
mitschabaude Nov 29, 2024
cd3f73f
adapt to proofs returned from circuit
mitschabaude Nov 29, 2024
5df3ca2
extend internal proving test
mitschabaude Nov 29, 2024
e4143c5
add adversarial test
mitschabaude Nov 29, 2024
34208df
bindings
mitschabaude Nov 29, 2024
1a410b1
fix unit test
mitschabaude Nov 29, 2024
3eecacb
Merge branch 'main' into feature/declare-proofs
mitschabaude Dec 2, 2024
4b07411
feedback: more explicit type names in DeclaredProof
mitschabaude Dec 5, 2024
813a10e
feedback: add code comments
mitschabaude Dec 5, 2024
5476ace
Merge branch 'main' into feature/declare-proofs
mitschabaude Dec 5, 2024
f591f02
zkprogram context fix
mitschabaude Dec 6, 2024
46d2993
Merge branch 'main' into feature/declare-proofs
mitschabaude Dec 17, 2024
67bdf86
remove recursive provers and expose regular provers instead
mitschabaude Dec 17, 2024
484ff13
recursive provers in separate wapper
mitschabaude Dec 17, 2024
b1adf8e
export Recursive
mitschabaude Dec 17, 2024
d0ffd75
adapt changelog
mitschabaude Dec 17, 2024
353f639
remove the need to export regular provers
mitschabaude Dec 17, 2024
671685e
remove regular provers
mitschabaude Dec 17, 2024
0d04ccc
adapt example
mitschabaude Dec 17, 2024
c9c81f7
changelog tweak
mitschabaude Dec 17, 2024
bf1e275
final fix: avoid mapping over the entire zkprogram
mitschabaude Dec 17, 2024
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
9 changes: 4 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,19 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased](https://github.com/o1-labs/o1js/compare/e1bac02...HEAD)


### Added

- API for recursively proving a ZkProgram method from within another https://github.com/o1-labs/o1js/pull/1931
- `program.proveRecursively.<methodName>(...args): Promise<PublicOutput>`
- This also works within the same program, as long as the return value is type-annotated
- Add `enforceTransactionLimits` parameter on Network https://github.com/o1-labs/o1js/issues/1910
- Method for optional types to assert none https://github.com/o1-labs/o1js/pull/1922

### Fixed

- Compiling stuck in the browser for recursive zkprograms https://github.com/o1-labs/o1js/pull/1906
- Error message in `rangeCheck16` gadget https://github.com/o1-labs/o1js/pull/1920

### Added

- Method for optional types to assert none https://github.com/o1-labs/o1js/pull/1922

## [2.1.0](https://github.com/o1-labs/o1js/compare/b04520d...e1bac02) - 2024-11-13

### Added
Expand Down
1 change: 1 addition & 0 deletions run-ci-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ case $TEST_TYPE in
./run src/examples/zkapps/reducer/reducer-composite.ts --bundle
./run src/examples/zkapps/composability.ts --bundle
./run src/tests/fake-proof.ts
./run src/tests/inductive-proofs-internal.ts --bundle
./run tests/vk-regression/diverse-zk-program-run.ts --bundle
;;

Expand Down
2 changes: 1 addition & 1 deletion src/bindings
22 changes: 22 additions & 0 deletions src/lib/proof-system/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { Provable } from '../provable/provable.js';
import { assert } from '../util/assert.js';
import { Unconstrained } from '../provable/types/unconstrained.js';
import { ProvableType } from '../provable/types/provable-intf.js';
import { ZkProgramContext } from './zkprogram-context.js';

// public API
export { ProofBase, Proof, DynamicProof };
Expand All @@ -36,6 +37,27 @@ class ProofBase<Input = any, Output = any> {
maxProofsVerified: 0 | 1 | 2;
shouldVerify = Bool(false);

/**
* To verify a recursive proof inside a ZkProgram method, it has to be "declared" as part of
* the method. This is done by calling `declare()` on the proof.
*
* Note: `declare()` is a low-level method that most users will not have to call directly.
* For proofs that are inputs to the ZkProgram, it is done automatically.
*
* You can think of declaring a proof as a similar step as witnessing a variable, which introduces
* that variable to the circuit. Declaring a proof will tell Pickles to add the additional constraints
* for recursive proof verification.
*
* Similar to `Provable.witness()`, `declare()` is a no-op when run outside ZkProgram compilation or proving.
* It returns `false` in that case, and `true` if the proof was actually declared.
*/
declare() {
if (!ZkProgramContext.has()) return false;
const Proof = this.constructor as Subclass<typeof ProofBase>;
ZkProgramContext.declareProof({ Proof, proof: this });
return true;
}

toJSON(): JsonProof {
let fields = this.publicFields();
return {
Expand Down
67 changes: 66 additions & 1 deletion src/lib/proof-system/workers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { workers, setNumberOfWorkers };
export { workers, setNumberOfWorkers, WithThreadPool };

const workers = {
numWorkers: undefined as number | undefined,
Expand All @@ -15,3 +15,68 @@ const workers = {
const setNumberOfWorkers = (numWorkers: number) => {
workers.numWorkers = numWorkers;
};

type ThreadPoolState =
| { type: 'none' }
| { type: 'initializing'; initPromise: Promise<void> }
| { type: 'running' }
| { type: 'exiting'; exitPromise: Promise<void> };

function WithThreadPool({
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the added logic here comes from the bindings, see o1-labs/o1js-bindings#318

initThreadPool,
exitThreadPool,
}: {
initThreadPool: () => Promise<void>;
exitThreadPool: () => Promise<void>;
}) {
// state machine to enable calling multiple functions that need a thread pool at once
let state: ThreadPoolState = { type: 'none' };
let isNeededBy = 0;

return async function withThreadPool<T>(run: () => Promise<T>): Promise<T> {
isNeededBy++;
// none, exiting -> initializing
switch (state.type) {
case 'none': {
let initPromise = initThreadPool();
state = { type: 'initializing', initPromise };
break;
}
case 'initializing':
case 'running':
break;
case 'exiting': {
let initPromise = state.exitPromise.then(initThreadPool);
state = { type: 'initializing', initPromise };
break;
}
}
// initializing -> running
if (state.type === 'initializing') await state.initPromise;
state = { type: 'running' };

let result: T;
try {
result = await run();
} finally {
// running -> exiting IF we don't need to run longer
isNeededBy--;

if (state.type !== 'running') {
throw Error('bug in ThreadPool state machine');
}

if (isNeededBy < 1) {
let exitPromise = exitThreadPool();
state = { type: 'exiting', exitPromise };

// exiting -> none IF we didn't move exiting -> initializing
await exitPromise;
if (state.type === 'exiting') {
state = { type: 'none' };
}
}
}
return result;
};
}
29 changes: 29 additions & 0 deletions src/lib/proof-system/zkprogram-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Context } from '../util/global-context.js';
import type { Subclass } from '../util/types.js';
import type { ProofBase } from './proof.js';

export { ZkProgramContext, DeclaredProof };

type DeclaredProof = {
Proof: Subclass<typeof ProofBase<any, any>>;
mitschabaude marked this conversation as resolved.
Show resolved Hide resolved
proof: ProofBase<any, any>;
};
type ZkProgramContext = {
proofs: DeclaredProof[];
};
let context = Context.create<ZkProgramContext>();

const ZkProgramContext = {
enter() {
return context.enter({ proofs: [] });
},
leave: context.leave,
has: context.has,

declareProof(proof: DeclaredProof) {
context.get().proofs.push(proof);
},
getDeclaredProofs() {
return context.get().proofs;
},
};
Loading