-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from zkemail/feat/prover-api
add prover import
- Loading branch information
Showing
5 changed files
with
204 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import { | ||
BarretenbergBackend, | ||
CompiledCircuit, | ||
ProofData, | ||
UltraHonkBackend, | ||
} from "@noir-lang/backend_barretenberg"; | ||
import { Noir } from "@noir-lang/noir_js"; | ||
import { InputValue } from "@noir-lang/noirc_abi"; | ||
import { CircuitInput } from "./index"; | ||
|
||
type ProvingBackend = "honk" | "plonk" | "all"; | ||
|
||
export class ZKEmailProver { | ||
private plonk?: BarretenbergBackend; | ||
private honk?: UltraHonkBackend; | ||
private noir: Noir; | ||
|
||
constructor( | ||
/* The ACIR of the Noir circuit to prove */ | ||
circuit: CompiledCircuit, | ||
/* Define the prover backend to use */ | ||
private provingBackend: ProvingBackend = "plonk" | ||
) { | ||
// initialize the backends | ||
if (provingBackend === "plonk" || provingBackend === "all") { | ||
this.plonk = new BarretenbergBackend(circuit); | ||
} | ||
if (provingBackend === "honk" || provingBackend === "all") { | ||
this.honk = new UltraHonkBackend(circuit); | ||
} | ||
// initialize the Noir instance | ||
this.noir = new Noir(circuit); | ||
} | ||
|
||
/** | ||
* Compute the witness for a given input to the circuit without generating a proof | ||
* | ||
* @param input - the input that should produce a satisfying witness for the circuit | ||
* @returns - the witness for the input and the output of the circuit if satisfiable | ||
*/ | ||
async simulateWitness( | ||
input: CircuitInput | ||
): Promise<{ witness: Uint8Array; returnValue: InputValue }> { | ||
return await this.noir.execute(input); | ||
} | ||
|
||
/** | ||
* Generate a proof of a satisfying input to the circuit using a provided witness | ||
* | ||
* @param input - a satisfying witness for the circuit | ||
* @param provingBackend - optionally provided if the class was initialized with both proving schemes | ||
* @returns proof of valid execution of the circuit | ||
*/ | ||
async prove( | ||
witness: Uint8Array, | ||
provingBackend?: ProvingBackend | ||
): Promise<ProofData> { | ||
// determine proving backend to use | ||
let backend: BarretenbergBackend | UltraHonkBackend; | ||
if (provingBackend) { | ||
// check that the asserted backend is initialized | ||
if (provingBackend === "plonk" && this.plonk) { | ||
backend = this.plonk; | ||
} else if (provingBackend === "honk" && this.honk) { | ||
backend = this.honk; | ||
} else { | ||
throw new Error(`Proving scheme ${provingBackend} not initialized`); | ||
} | ||
} else { | ||
// default to the backend used to initialize the class | ||
if (this.provingBackend === "honk" && this.honk) { | ||
backend = this.honk; | ||
} else if (this.provingBackend === "plonk" && this.plonk) { | ||
backend = this.plonk; | ||
} else { | ||
throw new Error(`Proving scheme ${this.provingBackend} not initialized`); | ||
} | ||
} | ||
// generate the proof | ||
return await backend.generateProof(witness); | ||
} | ||
|
||
/** | ||
* Simulate the witness for a given input and generate a proof | ||
* | ||
* @param input - the input that should produce a satisfying witness for the circuit | ||
* @param provingBackend - optionally provided if the class was initialized with both proving schemes | ||
* @returns proof of valid execution of the circuit | ||
*/ | ||
async fullProve( | ||
input: CircuitInput, | ||
provingBackend?: ProvingBackend | ||
): Promise<ProofData> { | ||
const { witness } = await this.simulateWitness(input); | ||
return await this.prove(witness, provingBackend); | ||
} | ||
|
||
/** | ||
* Verify a proof of a satisfying input to the circuit for a given proving scheme | ||
* | ||
* @param proof - the proof to verify | ||
* @param provingBackend - optionally provided if the class was initialized with both proving schemes | ||
* @returns true if the proof is valid, false otherwise | ||
*/ | ||
async verify( | ||
proof: ProofData, | ||
provingBackend?: ProvingBackend | ||
): Promise<boolean> { | ||
// determine proving backend to use | ||
let backend: BarretenbergBackend | UltraHonkBackend; | ||
if (provingBackend) { | ||
// check that the asserted backend is initialized | ||
if (provingBackend === "plonk" && this.plonk) { | ||
backend = this.plonk; | ||
} else if (provingBackend === "honk" && this.honk) { | ||
backend = this.honk; | ||
} else { | ||
throw new Error(`Proving scheme ${provingBackend} not initialized`); | ||
} | ||
} else { | ||
// default to the backend used to initialize the class | ||
if (this.provingBackend === "honk" && this.honk) { | ||
backend = this.honk; | ||
} else if (this.provingBackend === "plonk" && this.plonk) { | ||
backend = this.plonk; | ||
} else { | ||
throw new Error(`Proving scheme ${this.provingBackend} not initialized`); | ||
} | ||
} | ||
// verify the proof | ||
return await backend.verifyProof(proof); | ||
} | ||
|
||
/** | ||
* End the prover wasm instance(s) and clean up resources | ||
*/ | ||
async destroy() { | ||
if (this.plonk) { | ||
await this.plonk.destroy(); | ||
} | ||
if (this.honk) { | ||
await this.honk.destroy(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters