From d24e1d0a07aa2901b3074e9fd946d3960652e782 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 08:39:08 +0100 Subject: [PATCH 1/9] expose max proofs verified --- src/lib/proof-system/zkprogram.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index 2cb0222b3..6e52fe8d2 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -213,6 +213,8 @@ function ZkProgram< } ): { name: string; + maxProofsVerified(): Promise<0 | 1 | 2>; + compile: (options?: { cache?: Cache; forceRecompile?: boolean; @@ -232,6 +234,7 @@ function ZkProgram< ReturnType >; }>; + publicInputType: ProvableOrUndefined>; publicOutputType: ProvableOrVoid>; privateInputTypes: PrivateInputs; @@ -246,6 +249,7 @@ function ZkProgram< PrivateInputs[I] >; }; + proofsEnabled: boolean; setProofsEnabled(proofsEnabled: boolean): void; } & { @@ -521,10 +525,15 @@ function ZkProgram< const program = Object.assign( selfTag, { + async maxProofsVerified() { + return maxProofsVerified; + }, + compile, verify, digest, analyzeMethods, + publicInputType: publicInputType as ProvableOrUndefined< Get >, @@ -540,6 +549,7 @@ function ZkProgram< rawMethods: Object.fromEntries( methodKeys.map((key) => [key, methods[key].method]) ) as any, + proofsEnabled: doProving, setProofsEnabled(proofsEnabled: boolean) { doProving = proofsEnabled; From 2619a07c3583687871ee959b9ebc91838451d3aa Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 08:39:20 +0100 Subject: [PATCH 2/9] fix zkprogram test --- src/tests/inductive-proofs.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/tests/inductive-proofs.ts b/src/tests/inductive-proofs.ts index ebf22754f..7102eae5c 100644 --- a/src/tests/inductive-proofs.ts +++ b/src/tests/inductive-proofs.ts @@ -1,5 +1,5 @@ -import { SelfProof, Field, ZkProgram, Proof } from 'o1js'; -import { tic, toc } from '../examples/utils/tic-toc.node.js'; +import { SelfProof, Field, ZkProgram, Proof, JsonProof } from 'o1js'; +import { tic, toc } from '../examples/utils/tic-toc.js'; let MaxProofsVerifiedZero = ZkProgram({ name: 'no-recursion', @@ -100,12 +100,12 @@ async function testRecursion( ) { console.log(`testing maxProofsVerified = ${maxProofsVerified}`); - let ProofClass = ZkProgram.Proof(Program); + class ProofClass extends ZkProgram.Proof(Program) {} tic('executing base case'); - let initialProof = await Program.baseCase(Field(0)); + let { proof: initialProof } = await Program.baseCase(Field(0)); toc(); - initialProof = testJsonRoundtrip(ProofClass, initialProof); + initialProof = await testJsonRoundtrip(ProofClass, initialProof); initialProof.verify(); initialProof.publicInput.assertEquals(Field(0)); @@ -115,13 +115,13 @@ async function testRecursion( ); } - let p1, p2; + let p1: Proof, p2: Proof; if (initialProof.maxProofsVerified === 0) return; tic('executing mergeOne'); - p1 = await Program.mergeOne(Field(1), initialProof); + p1 = (await Program.mergeOne(Field(1), initialProof)).proof; toc(); - p1 = testJsonRoundtrip(ProofClass, p1); + p1 = await testJsonRoundtrip(ProofClass, p1); p1.verify(); p1.publicInput.assertEquals(Field(1)); if (p1.maxProofsVerified != maxProofsVerified) { @@ -132,9 +132,9 @@ async function testRecursion( if (initialProof.maxProofsVerified === 1) return; tic('executing mergeTwo'); - p2 = await Program.mergeTwo(Field(2), initialProof, p1); + p2 = (await Program.mergeTwo(Field(2), initialProof, p1)).proof; toc(); - p2 = testJsonRoundtrip(ProofClass, p2); + p2 = await testJsonRoundtrip(ProofClass, p2); p2.verify(); p2.publicInput.assertEquals(Field(2)); if (p2.maxProofsVerified != maxProofsVerified) { @@ -144,7 +144,10 @@ async function testRecursion( } } -function testJsonRoundtrip(ProofClass: any, proof: Proof) { +function testJsonRoundtrip( + ProofClass: { fromJSON: (p: JsonProof) => Promise> }, + proof: Proof +) { let jsonProof = proof.toJSON(); console.log( 'json roundtrip', From 55f8ce96eb60a48cff8fbe0bfec3829bc354077c Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 08:39:55 +0100 Subject: [PATCH 3/9] delete unused and outdated test / script --- run-minimal-mina-tests.sh | 6 --- src/tests/inductive-proofs-small.ts | 81 ----------------------------- 2 files changed, 87 deletions(-) delete mode 100755 run-minimal-mina-tests.sh delete mode 100644 src/tests/inductive-proofs-small.ts diff --git a/run-minimal-mina-tests.sh b/run-minimal-mina-tests.sh deleted file mode 100755 index 327b5adfd..000000000 --- a/run-minimal-mina-tests.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -set -e - -npm run dev - -./run src/tests/inductive-proofs-small.ts --bundle diff --git a/src/tests/inductive-proofs-small.ts b/src/tests/inductive-proofs-small.ts deleted file mode 100644 index f20f7b4fc..000000000 --- a/src/tests/inductive-proofs-small.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { SelfProof, Field, ZkProgram, Proof } from 'o1js'; -import { tic, toc } from '../examples/utils/tic-toc.node.js'; - -let MaxProofsVerifiedOne = ZkProgram({ - name: 'recursive-1', - publicInput: Field, - - methods: { - baseCase: { - privateInputs: [], - - async method(publicInput: Field) { - publicInput.assertEquals(Field(0)); - }, - }, - - mergeOne: { - privateInputs: [SelfProof], - - async method( - publicInput: Field, - earlierProof: SelfProof - ) { - earlierProof.verify(); - earlierProof.publicInput.add(1).assertEquals(publicInput); - }, - }, - }, -}); - -tic('compiling program'); -await MaxProofsVerifiedOne.compile(); -toc(); - -await testRecursion(MaxProofsVerifiedOne, 1); - -async function testRecursion( - Program: typeof MaxProofsVerifiedOne, - maxProofsVerified: number -) { - console.log(`testing maxProofsVerified = ${maxProofsVerified}`); - - let ProofClass = ZkProgram.Proof(Program); - - tic('executing base case'); - let initialProof = await Program.baseCase(Field(0)); - toc(); - initialProof = testJsonRoundtrip(ProofClass, initialProof); - initialProof.verify(); - initialProof.publicInput.assertEquals(Field(0)); - - if (initialProof.maxProofsVerified != maxProofsVerified) { - throw Error( - `Expected initialProof to have maxProofsVerified = ${maxProofsVerified} but has ${initialProof.maxProofsVerified}` - ); - } - - let p1; - if (initialProof.maxProofsVerified === 0) return; - - tic('executing mergeOne'); - p1 = await Program.mergeOne(Field(1), initialProof); - toc(); - p1 = testJsonRoundtrip(ProofClass, p1); - p1.verify(); - p1.publicInput.assertEquals(Field(1)); - if (p1.maxProofsVerified != maxProofsVerified) { - throw Error( - `Expected p1 to have maxProofsVerified = ${maxProofsVerified} but has ${p1.maxProofsVerified}` - ); - } -} - -function testJsonRoundtrip(ProofClass: any, proof: Proof) { - let jsonProof = proof.toJSON(); - console.log( - 'json roundtrip', - JSON.stringify({ ...jsonProof, proof: jsonProof.proof.slice(0, 10) + '..' }) - ); - return ProofClass.fromJSON(jsonProof); -} From 6d1711bf70564ef4a4e05d4968f63b59ecf7cb66 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 09:00:07 +0100 Subject: [PATCH 4/9] simplify `TupleToInstances` type to make it disappear --- src/lib/proof-system/zkprogram.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index 6e52fe8d2..09a524588 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -1094,7 +1094,7 @@ type Infer = T extends Subclass type TupleToInstances = { [I in keyof T]: Infer; -} & any[]; +}; type PrivateInput = ProvableType | Subclass; From 551497acc3b59536567bfb90a2df49eb373bf925 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 09:09:46 +0100 Subject: [PATCH 5/9] expose Proof class on zkprogram --- src/lib/proof-system/zkprogram.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index 09a524588..bcd74d2a0 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -250,6 +250,11 @@ function ZkProgram< >; }; + Proof: typeof Proof< + InferProvableOrUndefined>, + InferProvableOrVoid> + >; + proofsEnabled: boolean; setProofsEnabled(proofsEnabled: boolean): void; } & { @@ -549,13 +554,14 @@ function ZkProgram< rawMethods: Object.fromEntries( methodKeys.map((key) => [key, methods[key].method]) ) as any, + proveRecursively, + + Proof: SelfProof, proofsEnabled: doProving, setProofsEnabled(proofsEnabled: boolean) { doProving = proofsEnabled; }, - - proveRecursively, }, provers ); From 35fe9def88883268711a6c23313b485041e3de70 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 09:10:36 +0100 Subject: [PATCH 6/9] simplfy some examples --- src/examples/zkprogram/mututal-recursion.ts | 4 +--- src/examples/zkprogram/program-with-input.ts | 8 +++----- src/lib/mina/actions/offchain-state-rollup.ts | 2 +- src/lib/proof-system/proof-system.unit-test.ts | 2 +- src/lib/provable/test/custom-gates-recursion.unit-test.ts | 2 +- src/tests/fake-proof.ts | 2 +- src/tests/inductive-proofs.ts | 2 +- 7 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/examples/zkprogram/mututal-recursion.ts b/src/examples/zkprogram/mututal-recursion.ts index 542bae1c2..89b9d7bed 100644 --- a/src/examples/zkprogram/mututal-recursion.ts +++ b/src/examples/zkprogram/mututal-recursion.ts @@ -47,15 +47,13 @@ const add = ZkProgram({ }, }); -const AddProof = ZkProgram.Proof(add); - const multiply = ZkProgram({ name: 'multiply', publicInput: Undefined, publicOutput: Field, methods: { performMultiplication: { - privateInputs: [Field, AddProof], + privateInputs: [Field, add.Proof], async method(field: Field, addProof: Proof) { addProof.verify(); const multiplicationResult = addProof.publicOutput.mul(field); diff --git a/src/examples/zkprogram/program-with-input.ts b/src/examples/zkprogram/program-with-input.ts index a6117771b..3325538c0 100644 --- a/src/examples/zkprogram/program-with-input.ts +++ b/src/examples/zkprogram/program-with-input.ts @@ -35,8 +35,6 @@ MyProgram.publicOutputType satisfies Provable; MyProgram.privateInputTypes; MyProgram.auxiliaryOutputTypes; -let MyProof = ZkProgram.Proof(MyProgram); - console.log('program digest', await MyProgram.digest()); console.log('compiling MyProgram...'); @@ -45,7 +43,7 @@ console.log('verification key', verificationKey.data.slice(0, 10) + '..'); console.log('proving base case...'); let { proof } = await MyProgram.baseCase(Field(0)); -proof = await testJsonRoundtrip(MyProof, proof); +proof = await testJsonRoundtrip(MyProgram.Proof, proof); // type sanity check proof satisfies Proof; @@ -60,7 +58,7 @@ console.log('ok (alternative)?', ok); console.log('proving step 1...'); let { proof: proof1 } = await MyProgram.inductiveCase(Field(1), proof); -proof1 = await testJsonRoundtrip(MyProof, proof1); +proof1 = await testJsonRoundtrip(MyProgram.Proof, proof1); console.log('verify...'); ok = await verify(proof1, verificationKey); @@ -72,7 +70,7 @@ console.log('ok (alternative)?', ok); console.log('proving step 2...'); let { proof: proof2 } = await MyProgram.inductiveCase(Field(2), proof1); -proof2 = await testJsonRoundtrip(MyProof, proof2); +proof2 = await testJsonRoundtrip(MyProgram.Proof, proof2); console.log('verify...'); ok = await verify(proof2.toJSON(), verificationKey); diff --git a/src/lib/mina/actions/offchain-state-rollup.ts b/src/lib/mina/actions/offchain-state-rollup.ts index a6ab88d9b..18b772f1a 100644 --- a/src/lib/mina/actions/offchain-state-rollup.ts +++ b/src/lib/mina/actions/offchain-state-rollup.ts @@ -239,7 +239,7 @@ function OffchainStateRollup({ }, }); - let RollupProof = ZkProgram.Proof(offchainStateRollup); + let RollupProof = offchainStateRollup.Proof; let isCompiled = false; diff --git a/src/lib/proof-system/proof-system.unit-test.ts b/src/lib/proof-system/proof-system.unit-test.ts index c6b570f71..da3933c5f 100644 --- a/src/lib/proof-system/proof-system.unit-test.ts +++ b/src/lib/proof-system/proof-system.unit-test.ts @@ -26,7 +26,7 @@ const EmptyProgram = ZkProgram({ methods: { run: { privateInputs: [], async method(_) {} } }, }); -class EmptyProof extends ZkProgram.Proof(EmptyProgram) {} +class EmptyProof extends EmptyProgram.Proof {} // unit-test zkprogram creation helpers: // -) sortMethodArguments diff --git a/src/lib/provable/test/custom-gates-recursion.unit-test.ts b/src/lib/provable/test/custom-gates-recursion.unit-test.ts index 4d14fecc1..c16d0696e 100644 --- a/src/lib/provable/test/custom-gates-recursion.unit-test.ts +++ b/src/lib/provable/test/custom-gates-recursion.unit-test.ts @@ -29,7 +29,7 @@ let emptyProgram = ZkProgram({ name: 'empty', methods: { run: { privateInputs: [], async method() {} } }, }); -class EmptyProof extends ZkProgram.Proof(emptyProgram) {} +class EmptyProof extends emptyProgram.Proof {} let program = ZkProgram({ name: 'ecdsa', diff --git a/src/tests/fake-proof.ts b/src/tests/fake-proof.ts index 5cc2338bf..e29dfb7f7 100644 --- a/src/tests/fake-proof.ts +++ b/src/tests/fake-proof.ts @@ -43,7 +43,7 @@ const FakeProgram = ZkProgram({ }, }); -class RealProof extends ZkProgram.Proof(RealProgram) {} +class RealProof extends RealProgram.Proof {} class Nested extends Struct({ inner: RealProof }) {} const RecursiveProgram = ZkProgram({ diff --git a/src/tests/inductive-proofs.ts b/src/tests/inductive-proofs.ts index 7102eae5c..349d3a753 100644 --- a/src/tests/inductive-proofs.ts +++ b/src/tests/inductive-proofs.ts @@ -100,7 +100,7 @@ async function testRecursion( ) { console.log(`testing maxProofsVerified = ${maxProofsVerified}`); - class ProofClass extends ZkProgram.Proof(Program) {} + class ProofClass extends Program.Proof {} tic('executing base case'); let { proof: initialProof } = await Program.baseCase(Field(0)); From db8a120a0595a156ae3a5fc1034b63c14aa40a2d Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 29 Nov 2024 15:37:31 +0100 Subject: [PATCH 7/9] fixup --- src/lib/proof-system/zkprogram.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index e96e2b08d..9f11721cf 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -542,9 +542,7 @@ function ZkProgram< const program = Object.assign( selfTag, { - async maxProofsVerified() { - return maxProofsVerified; - }, + maxProofsVerified: getMaxProofsVerified, compile, verify, From c36b64ad57f1d3ffa394cc9b80242ec9b0fc47de Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 17 Dec 2024 16:28:02 +0100 Subject: [PATCH 8/9] merge fixup --- src/lib/proof-system/zkprogram.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index 20014c629..b6e39ee96 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -553,7 +553,6 @@ function ZkProgram< rawMethods: Object.fromEntries( methodKeys.map((key) => [key, methods[key].method]) ) as any, - proveRecursively, Proof: SelfProof, From e59b340bba83c5b14cad76a9fbce06522e2651a0 Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 17 Dec 2024 16:29:13 +0100 Subject: [PATCH 9/9] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 113e05419..392dc5c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Method for optional types to assert none https://github.com/o1-labs/o1js/pull/1922 - Increased maximum supported amount of methods in a `SmartContract` or `ZkProgram` to 30. https://github.com/o1-labs/o1js/pull/1918 - Expose low-level conversion methods `Proof.{_proofToBase64,_proofFromBase64}` https://github.com/o1-labs/o1js/pull/1928 +- Expore `maxProofsVerified()` and a `Proof` class directly on ZkPrograms https://github.com/o1-labs/o1js/pull/1933 + +### Changed + +- Changed an internal type to improve IntelliSense on ZkProgram methods https://github.com/o1-labs/o1js/pull/1933 ### Fixed