diff --git a/src/lib/proof-system/proof.ts b/src/lib/proof-system/proof.ts index c1d6af333..44e9fc134 100644 --- a/src/lib/proof-system/proof.ts +++ b/src/lib/proof-system/proof.ts @@ -3,7 +3,7 @@ import { initializeBindings, withThreadPool, } from '../../snarky.js'; -import { Pickles } from '../../snarky.js'; +import { Pickles, Base64ProofString } from '../../snarky.js'; import { Field, Bool } from '../provable/wrapped.js'; import type { FlexibleProvable, @@ -121,7 +121,10 @@ class ProofBase { return (this.constructor as typeof ProofBase).publicFields(this); } - static _proofFromBase64(proofString: string, maxProofsVerified: 0 | 1 | 2) { + static _proofFromBase64( + proofString: Base64ProofString, + maxProofsVerified: 0 | 1 | 2 + ) { assertBindingsInitialized(); return Pickles.proofOfBase64(proofString, maxProofsVerified)[1]; } diff --git a/src/lib/proof-system/zkprogram.ts b/src/lib/proof-system/zkprogram.ts index 01c04322c..c3f11b069 100644 --- a/src/lib/proof-system/zkprogram.ts +++ b/src/lib/proof-system/zkprogram.ts @@ -1,5 +1,10 @@ import { EmptyUndefined, EmptyVoid } from '../../bindings/lib/generic.js'; -import { Snarky, initializeBindings, withThreadPool } from '../../snarky.js'; +import { + Base64ProofString, + Snarky, + initializeBindings, + withThreadPool, +} from '../../snarky.js'; import { Pickles, Gate } from '../../snarky.js'; import { Field } from '../provable/wrapped.js'; import { @@ -118,6 +123,13 @@ function createProgramState() { }; } +/** + * Initializes {@link Pickles} bindings, serializes the input proof and VK for use in Ocaml, then calls into {@link Pickles.verify} to verify the proof. + * + * @param proof Either a Proof instance or a JSON proof which gets converted into an {@link MlPair} of {@link FieldConst} arrays for use in the bindings. + * @param verificationKey Either a string containing a base64 serialized verification key or a VerificationKey which gets converted into a string for use in the bindings. + * @returns A promise that resolves to a boolean indicating whether the proof is valid. + */ async function verify( proof: ProofBase | JsonProof, verificationKey: string | VerificationKey @@ -155,11 +167,16 @@ async function verify( ); } +/** + * Serializeable representation of a Pickles proof, useful for caching compiled proofs. + */ type JsonProof = { + /** Array of string, where each string is a {@link Field} in the publicInput of this proof */ publicInput: string[]; + /** Array of string, where each string is a {@link Field} in the publicOutput of this proof */ publicOutput: string[]; maxProofsVerified: 0 | 1 | 2; - proof: string; + proof: Base64ProofString; }; type CompiledTag = unknown; @@ -183,6 +200,33 @@ let SideloadedTag = { }, }; +/** + * Wraps config + provable code into a program capable of producing {@link Proof}s. + * + * @example + * ```ts + * const ExampleProgram = ZkProgram({ + * name: 'ExampleProgram', + * publicOutput: Int64, + * methods: { + * // Prove that I know 2 numbers less than 100 each, whose product is greater than 1000 + * provableMultiply: { + * privateInputs: [Int64, Int64], + * method: async (n1: Int64, n2: Int64) => { + * n1.assertLessThan(100); + * n2.assertLessThan(100); + * const publicOutput = n1.mul(n2); + * publicOutput.assertGreaterThan(1000); + * return { publicOutput: n1.mul(n2) } + * } + * } + * } + * }); + * ``` + * + * @param config The configuration of the program, describing the type of the public input and public output, as well as defining the methods which can be executed provably. + * @returns an object that can be used to compile, prove, and verify the program. + */ function ZkProgram< Config extends { publicInput?: ProvableType; @@ -591,6 +635,33 @@ type ZkProgram< } > = ReturnType>; +/** + * A class representing the type of Proof produced by the {@link ZkProgram} in which it is used. + * + * @example + * ```ts + * const ExampleProgram = ZkProgram({ + * name: 'ExampleProgram', + * publicOutput: Field, + * methods: { + * baseCase: { + * privateInputs: [], + * method: async () => { + * return { publicOutput: Field(0) } + * } + * }, + * add: { + * privateInputs: [SelfProof, Field], + * // `previous` is the type of proof produced by ExampleProgram + * method: async (previous: SelfProof, f: Field) => { + * previous.verify(); + * return { publicOutput: previous.publicOutput.add(f) } + * } + * } + * } + * }); + * ``` + */ class SelfProof extends Proof< PublicInput, PublicOutput diff --git a/src/snarky.d.ts b/src/snarky.d.ts index feac69d9d..998f8f4f0 100644 --- a/src/snarky.d.ts +++ b/src/snarky.d.ts @@ -48,10 +48,16 @@ export { MlPublicKeyVar, MlFeatureFlags, areBindingsInitialized, + Base64ProofString, }; declare let areBindingsInitialized: boolean; +/** + * A string representation of a {@link Pickles.Proof} in base64 encoding, used for communication between Ocaml and TypeScript and for JSON serialization. + */ +type Base64ProofString = string; + type WasmModule = typeof wasm; type MlGroup = MlPair; @@ -725,7 +731,7 @@ declare const Pickles: { encodeVerificationKey: (vk: MlWrapVerificationKey) => string; decodeVerificationKey: (vk: string) => MlWrapVerificationKey; - proofToBase64: (proof: [0 | 1 | 2, Pickles.Proof]) => string; + proofToBase64: (proof: [0 | 1 | 2, Pickles.Proof]) => Base64ProofString; proofOfBase64: ( base64: string, maxProofsVerified: N