Skip to content

Commit

Permalink
Merge pull request #1933 from o1-labs/feature/zkprogram-qol
Browse files Browse the repository at this point in the history
ZkPrograms QoL improvements
  • Loading branch information
mitschabaude authored Dec 19, 2024
2 parents 1122d05 + fe77072 commit 17adf4b
Show file tree
Hide file tree
Showing 11 changed files with 43 additions and 111 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,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

Expand Down
6 changes: 0 additions & 6 deletions run-minimal-mina-tests.sh

This file was deleted.

4 changes: 1 addition & 3 deletions src/examples/zkprogram/mututal-recursion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Undefined, Field>) {
addProof.verify();
const multiplicationResult = addProof.publicOutput.mul(field);
Expand Down
8 changes: 3 additions & 5 deletions src/examples/zkprogram/program-with-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ MyProgram.publicOutputType satisfies Provable<void>;
MyProgram.privateInputTypes;
MyProgram.auxiliaryOutputTypes;

let MyProof = ZkProgram.Proof(MyProgram);

console.log('program digest', await MyProgram.digest());

console.log('compiling MyProgram...');
Expand All @@ -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<Field, void>;
Expand All @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/mina/actions/offchain-state-rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ function OffchainStateRollup({
},
});

let RollupProof = ZkProgram.Proof(offchainStateRollup);
let RollupProof = offchainStateRollup.Proof;

let isCompiled = false;

Expand Down
2 changes: 1 addition & 1 deletion src/lib/proof-system/proof-system.unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion src/lib/proof-system/zkprogram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ function ZkProgram<
}
): {
name: string;
maxProofsVerified(): Promise<0 | 1 | 2>;

compile: (options?: {
cache?: Cache;
forceRecompile?: boolean;
Expand All @@ -243,13 +245,20 @@ function ZkProgram<
ReturnType<typeof analyzeMethod>
>;
}>;

publicInputType: ProvableOrUndefined<Get<Config, 'publicInput'>>;
publicOutputType: ProvableOrVoid<Get<Config, 'publicOutput'>>;
privateInputTypes: PrivateInputs;
auxiliaryOutputTypes: AuxiliaryOutputs;
rawMethods: {
[I in keyof Config['methods']]: Methods[I]['method'];
};

Proof: typeof Proof<
InferProvableOrUndefined<Get<Config, 'publicInput'>>,
InferProvableOrVoid<Get<Config, 'publicOutput'>>
>;

proofsEnabled: boolean;
setProofsEnabled(proofsEnabled: boolean): void;
} & {
Expand Down Expand Up @@ -522,10 +531,13 @@ function ZkProgram<
const program = Object.assign(
selfTag,
{
maxProofsVerified: getMaxProofsVerified,

compile,
verify,
digest,
analyzeMethods,

publicInputType: publicInputType as ProvableOrUndefined<
Get<Config, 'publicInput'>
>,
Expand All @@ -541,6 +553,9 @@ function ZkProgram<
rawMethods: Object.fromEntries(
methodKeys.map((key) => [key, methods[key].method])
) as any,

Proof: SelfProof,

proofsEnabled: doProving,
setProofsEnabled(proofsEnabled: boolean) {
doProving = proofsEnabled;
Expand Down Expand Up @@ -1127,7 +1142,7 @@ type Infer<T> = T extends Subclass<typeof ProofBase>

type TupleToInstances<T> = {
[I in keyof T]: Infer<T[I]>;
} & any[];
};

type PrivateInput = ProvableType | Subclass<typeof ProofBase>;

Expand Down
2 changes: 1 addition & 1 deletion src/lib/provable/test/custom-gates-recursion.unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion src/tests/fake-proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const FakeProgram = ZkProgram({
},
});

class RealProof extends ZkProgram.Proof(RealProgram) {}
class RealProof extends RealProgram.Proof {}
class Nested extends Struct({ inner: RealProof }) {}

const RecursiveProgram = ZkProgram({
Expand Down
81 changes: 0 additions & 81 deletions src/tests/inductive-proofs-small.ts

This file was deleted.

25 changes: 14 additions & 11 deletions src/tests/inductive-proofs.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand Down Expand Up @@ -100,12 +100,12 @@ async function testRecursion(
) {
console.log(`testing maxProofsVerified = ${maxProofsVerified}`);

let ProofClass = ZkProgram.Proof(Program);
class ProofClass extends Program.Proof {}

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));

Expand All @@ -115,13 +115,13 @@ async function testRecursion(
);
}

let p1, p2;
let p1: Proof<any, any>, p2: Proof<any, any>;
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) {
Expand All @@ -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) {
Expand All @@ -144,7 +144,10 @@ async function testRecursion(
}
}

function testJsonRoundtrip(ProofClass: any, proof: Proof<Field, void>) {
function testJsonRoundtrip(
ProofClass: { fromJSON: (p: JsonProof) => Promise<Proof<any, any>> },
proof: Proof<Field, void>
) {
let jsonProof = proof.toJSON();
console.log(
'json roundtrip',
Expand Down

0 comments on commit 17adf4b

Please sign in to comment.