Skip to content

Commit

Permalink
Merge pull request #884 from o1-labs/remove-duplicate-user-command-fi…
Browse files Browse the repository at this point in the history
…elds

Remove duplicate user command fields
  • Loading branch information
mitschabaude committed May 30, 2023
2 parents 147c36f + 91eb907 commit 265c311
Show file tree
Hide file tree
Showing 25 changed files with 968 additions and 348 deletions.
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,21 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
_Security_ in case of vulnerabilities.
-->

## [Unreleased](https://github.com/o1-labs/snarkyjs/compare/bcc666f2...HEAD)
## [Unreleased](https://github.com/o1-labs/snarkyjs/compare/a632313a...HEAD)

> No unreleased changes yet
### Changes

- New decorator `CatchAndPrettifyStacktrace` for printing better stack traces thrown from SnarkyJS https://github.com/o1-labs/snarkyjs/pull/890
- Cleans up stack traces by filtering out extra details, making them more readable

## [0.10.1](https://github.com/o1-labs/snarkyjs/compare/bcc666f2...a632313a)

### Changes

- Allow ZkPrograms to return their public output https://github.com/o1-labs/snarkyjs/pull/874 https://github.com/o1-labs/snarkyjs/pull/876
- new option `ZkProgram({ publicOutput?: Provable<any>, ... })`; `publicOutput` has to match the _return type_ of all ZkProgram methods.
- the `publicInput` option becomes optional; if not provided, methods no longer expect the public input as first argument
- full usage example: https://github.com/o1-labs/snarkyjs/blob/f95cf2903e97292df9e703b74ee1fc3825df826d/src/examples/program.ts

## [0.10.0](https://github.com/o1-labs/snarkyjs/compare/97e393ed...bcc666f2)

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "snarkyjs",
"description": "TypeScript framework for zk-SNARKs and zkApps",
"version": "0.10.0",
"version": "0.10.1",
"license": "Apache-2.0",
"homepage": "https://github.com/o1-labs/snarkyjs/",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion src/bindings
95 changes: 95 additions & 0 deletions src/examples/program-with-input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
SelfProof,
Field,
Experimental,
verify,
isReady,
Proof,
JsonProof,
Provable,
} from 'snarkyjs';

await isReady;

let MyProgram = Experimental.ZkProgram({
publicInput: Field,

methods: {
baseCase: {
privateInputs: [],
method(input: Field) {
input.assertEquals(Field(0));
},
},

inductiveCase: {
privateInputs: [SelfProof],
method(input: Field, earlierProof: SelfProof<Field, void>) {
earlierProof.verify();
earlierProof.publicInput.add(1).assertEquals(input);
},
},
},
});
// type sanity checks
MyProgram.publicInputType satisfies typeof Field;
MyProgram.publicOutputType satisfies Provable<void>;

let MyProof = Experimental.ZkProgram.Proof(MyProgram);

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

console.log('compiling MyProgram...');
let { verificationKey } = await MyProgram.compile();
console.log('verification key', verificationKey.slice(0, 10) + '..');

console.log('proving base case...');
let proof = await MyProgram.baseCase(Field(0));
proof = testJsonRoundtrip(MyProof, proof);

// type sanity check
proof satisfies Proof<Field, void>;

console.log('verify...');
let ok = await verify(proof.toJSON(), verificationKey);
console.log('ok?', ok);

console.log('verify alternative...');
ok = await MyProgram.verify(proof);
console.log('ok (alternative)?', ok);

console.log('proving step 1...');
proof = await MyProgram.inductiveCase(Field(1), proof);
proof = testJsonRoundtrip(MyProof, proof);

console.log('verify...');
ok = await verify(proof, verificationKey);
console.log('ok?', ok);

console.log('verify alternative...');
ok = await MyProgram.verify(proof);
console.log('ok (alternative)?', ok);

console.log('proving step 2...');
proof = await MyProgram.inductiveCase(Field(2), proof);
proof = testJsonRoundtrip(MyProof, proof);

console.log('verify...');
ok = await verify(proof.toJSON(), verificationKey);

console.log('ok?', ok && proof.publicInput.toString() === '2');

function testJsonRoundtrip<
P extends Proof<any, any>,
MyProof extends { fromJSON(jsonProof: JsonProof): P }
>(MyProof: MyProof, proof: P) {
let jsonProof = proof.toJSON();
console.log(
'json proof',
JSON.stringify({
...jsonProof,
proof: jsonProof.proof.slice(0, 10) + '..',
})
);
return MyProof.fromJSON(jsonProof);
}
62 changes: 43 additions & 19 deletions src/examples/program.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
import { SelfProof, Field, Experimental, verify, isReady } from 'snarkyjs';
import {
SelfProof,
Field,
Experimental,
verify,
isReady,
Proof,
JsonProof,
Provable,
Empty,
} from 'snarkyjs';

await isReady;

let MyProgram = Experimental.ZkProgram({
publicInput: Field,
publicOutput: Field,

methods: {
baseCase: {
privateInputs: [],

method(publicInput: Field) {
publicInput.assertEquals(Field(0));
method() {
return Field(0);
},
},

inductiveCase: {
privateInputs: [SelfProof],

method(publicInput: Field, earlierProof: SelfProof<Field>) {
method(earlierProof: SelfProof<Empty, Field>) {
earlierProof.verify();
earlierProof.publicInput.add(1).assertEquals(publicInput);
return earlierProof.publicOutput.add(1);
},
},
},
});
// type sanity checks
MyProgram.publicInputType satisfies Provable<Empty>;
MyProgram.publicOutputType satisfies typeof Field;

let MyProof = Experimental.ZkProgram.Proof(MyProgram);

Expand All @@ -34,39 +45,52 @@ let { verificationKey } = await MyProgram.compile();
console.log('verification key', verificationKey.slice(0, 10) + '..');

console.log('proving base case...');
let proof = await MyProgram.baseCase(Field(0));
proof = testJsonRoundtrip(proof);
let proof = await MyProgram.baseCase();
proof = testJsonRoundtrip(MyProof, proof);

// type sanity check
proof satisfies Proof<undefined, Field>;

console.log('verify...');
let ok = await verify(proof.toJSON(), verificationKey);
console.log('ok?', ok);

console.log('proving step 1...');
proof = await MyProgram.inductiveCase(Field(1), proof);
proof = testJsonRoundtrip(proof);

console.log('verify alternative...');
ok = await MyProgram.verify(proof);
console.log('ok (alternative)?', ok);

console.log('proving step 1...');
proof = await MyProgram.inductiveCase(proof);
proof = testJsonRoundtrip(MyProof, proof);

console.log('verify...');
ok = await verify(proof, verificationKey);
console.log('ok?', ok);

console.log('verify alternative...');
ok = await MyProgram.verify(proof);
console.log('ok (alternative)?', ok);

console.log('proving step 2...');
proof = await MyProgram.inductiveCase(Field(2), proof);
proof = testJsonRoundtrip(proof);
proof = await MyProgram.inductiveCase(proof);
proof = testJsonRoundtrip(MyProof, proof);

console.log('verify...');
ok = await verify(proof.toJSON(), verificationKey);

console.log('ok?', ok && proof.publicInput.toString() === '2');
console.log('ok?', ok && proof.publicOutput.toString() === '2');

function testJsonRoundtrip(proof: any): any {
function testJsonRoundtrip<
P extends Proof<any, any>,
MyProof extends { fromJSON(jsonProof: JsonProof): P }
>(MyProof: MyProof, proof: P) {
let jsonProof = proof.toJSON();
console.log(
'json proof',
JSON.stringify({ ...jsonProof, proof: jsonProof.proof.slice(0, 10) + '..' })
JSON.stringify({
...jsonProof,
proof: jsonProof.proof.slice(0, 10) + '..',
})
);
return MyProof.fromJSON(jsonProof);
}
3 changes: 2 additions & 1 deletion src/examples/zkapps/simple_zkapp_with_proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ZkappPublicInput,
SelfProof,
verify,
Empty,
} from 'snarkyjs';

await isReady;
Expand All @@ -32,7 +33,7 @@ class NotSoSimpleZkapp extends SmartContract {

@method update(
y: Field,
oldProof: SelfProof<ZkappPublicInput>,
oldProof: SelfProof<ZkappPublicInput, Empty>,
trivialProof: TrivialProof
) {
oldProof.verify();
Expand Down
10 changes: 9 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ export {
Reducer,
} from './lib/zkapp.js';
export { state, State, declareState } from './lib/state.js';
export { Proof, SelfProof, verify } from './lib/proof_system.js';
export {
Proof,
SelfProof,
verify,
JsonProof,
Empty,
Undefined,
Void,
} from './lib/proof_system.js';

export {
Token,
Expand Down
25 changes: 18 additions & 7 deletions src/lib/account_update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SmartContract } from './zkapp.js';
import * as Precondition from './precondition.js';
import {
dummyBase64Proof,
Empty,
inCheckedComputation,
Proof,
Prover,
Expand All @@ -29,7 +30,7 @@ import { TokenId as Base58TokenId } from './base58-encodings.js';
import { hashWithPrefix, packToFields } from './hash.js';
import { prefixes } from '../bindings/crypto/constants.js';
import { Context } from './global-context.js';
import { assert } from './errors.js';
import { assert, prettifyStacktrace } from './errors.js';

// external API
export { AccountUpdate, Permissions, ZkappPublicInput };
Expand Down Expand Up @@ -592,7 +593,7 @@ type LazyProof = {
kind: 'lazy-proof';
methodName: string;
args: any[];
previousProofs: { publicInput: Field[]; proof: Pickles.Proof }[];
previousProofs: Pickles.Proof[];
ZkappClass: typeof SmartContract;
memoized: { fields: Field[]; aux: any[] }[];
blindingValue: Field;
Expand Down Expand Up @@ -974,7 +975,12 @@ class AccountUpdate implements Types.AccountUpdate {
* be (can be) authorized by a signature.
*/
requireSignature() {
this.sign();
try {
this.sign();
} catch (error) {
if (error instanceof Error) error.stack = prettifyStacktrace(error);
throw error;
}
}
/**
* @deprecated `.sign()` is deprecated in favor of `.requireSignature()`
Expand Down Expand Up @@ -1945,7 +1951,7 @@ async function addMissingProofs(
{ proofsEnabled = true }
): Promise<{
zkappCommand: ZkappCommandProved;
proofs: (Proof<ZkappPublicInput> | undefined)[];
proofs: (Proof<ZkappPublicInput, Empty> | undefined)[];
}> {
type AccountUpdateProved = AccountUpdate & {
lazyAuthorization?: LazySignature;
Expand Down Expand Up @@ -1989,7 +1995,7 @@ async function addMissingProofs(
if (ZkappClass._methods === undefined) throw Error(methodError);
let i = ZkappClass._methods.findIndex((m) => m.methodName === methodName);
if (i === -1) throw Error(methodError);
let [, [, proof]] = await zkAppProver.run(
let [, [, { proof }]] = await zkAppProver.run(
[accountUpdate.publicKey, accountUpdate.tokenId, ...args],
{ transaction: zkappCommand, accountUpdate, index },
() =>
Expand All @@ -2015,15 +2021,20 @@ async function addMissingProofs(
const Proof = ZkappClass.Proof();
return {
accountUpdateProved: accountUpdate as AccountUpdateProved,
proof: new Proof({ publicInput, proof, maxProofsVerified }),
proof: new Proof({
publicInput,
publicOutput: undefined,
proof,
maxProofsVerified,
}),
};
}

let { feePayer, accountUpdates, memo } = zkappCommand;
// compute proofs serially. in parallel would clash with our global variable
// hacks
let accountUpdatesProved: AccountUpdateProved[] = [];
let proofs: (Proof<ZkappPublicInput> | undefined)[] = [];
let proofs: (Proof<ZkappPublicInput, Empty> | undefined)[] = [];
for (let i = 0; i < accountUpdates.length; i++) {
let { accountUpdateProved, proof } = await addProof(i, accountUpdates[i]);
accountUpdatesProved.push(accountUpdateProved);
Expand Down
3 changes: 3 additions & 0 deletions src/lib/circuit_value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
export {
CircuitValue,
ProvableExtended,
ProvablePureExtended,
prop,
arrayProp,
matrixProp,
Expand Down Expand Up @@ -65,6 +66,8 @@ type ProvableExtension<T, TJson = any> = {

type ProvableExtended<T, TJson = any> = Provable<T> &
ProvableExtension<T, TJson>;
type ProvablePureExtended<T, TJson = any> = ProvablePure<T> &
ProvableExtension<T, TJson>;

type Struct<T> = ProvableExtended<NonMethods<T>> &
Constructor<T> & { _isStruct: true };
Expand Down
Loading

0 comments on commit 265c311

Please sign in to comment.