Skip to content

Commit

Permalink
SnarkJS termination fix (#16)
Browse files Browse the repository at this point in the history
* upgraded snarkjs version, added termination fix

* refactored curve termination

* added curve termination to generateProof

* fixed type error

* readme

* fix readme

---------

Co-authored-by: Artem Chystiakov <[email protected]>
  • Loading branch information
mllwchrry and Arvolear authored Oct 29, 2024
1 parent e04194c commit 4fa5a95
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 72 deletions.
67 changes: 42 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
**A zero knowledge kit that helps you interact with Circom circuits.**

- Generate and verify ZK proofs with a single line of code.
- Leverage `groth16` and `plonk` proving systems.
- Render optimized Solidity | Vyper verifiers.
- Build and work with ZK witnesses.

Expand All @@ -26,76 +27,92 @@ npm install --save-dev @solarity/zkit

`CircuitZKit` is a user-friendly interface for interacting with circom circuits.

To create a CircuitZKit object it is necessary to pass a config:
To create a `CircuitZKit` object it is necessary to pass a circuit config and a `ProtocolImplementer` instance:

```typescript
CircuitZKitConfig = {
const config = {
circuitName: string;
circuitArtifactsPath: string;
verifierDirPath: string;
provingSystem?: VerifierProvingSystem;
};

const implementer = new Groth16Implementer() | new PlonkImplementer();

const circuit = new CircuitZKit<"groth16" | "plonk">(config, implementer);
```

This config contains all the information required to work with the circuit, namely:
The `config` contains all the information required to work with the circuit, namely:

- `circuitName` - Name of the circuit file without extension
- `circuitArtifactsPath` - Full path to compilation artifacts for the desired circuit
- `verifierDirPath` - Full path to the directory where Solidity | Vyper verifier file will be generated
- `provingSystem` - The proving system that will be used to generate the verifier contract. Right now only `groth16` is supported
- `circuitName` - Name of the circuit file without extension.
- `circuitArtifactsPath` - Full path to compilation artifacts for the desired circuit.
- `verifierDirPath` - Full path to the directory where Solidity | Vyper verifier file will be generated.

#### getTemplate()
The `implementer` is the instance of a certain proving system. Currently `groth16` and `plonk` systems are supported.

Static `CircuitZKit` function that returns the contents of a template file by the passed type.
#### API reference

```typescript
const templateContent = CircuitZKit.getTemplate("groth16", "sol");
```
---

#### createVerifier()
- **`async createVerifier("sol" | "vy")`**

Creates a Solidity | Vyper verifier contract on `verifierDirPath` path, which was specified in the config.

```typescript
await multiplier.createVerifier("sol");
await circuit.createVerifier("sol");
```

#### calculateWitness()
- **`async calculateWitness(inputs) -> bigint[]`**

Calculates a witness in the `tmp` directory and returns its json representation.

```typescript
/// witness = [1n, 200n, 20n, 10n]
const witness = await multiplier.calculateWitness({ a: 10, b: 20 });
const witness = await circuit.calculateWitness({ a: 10, b: 20 });
```

#### generateProof()
- **`async generateProof(inputs) -> proof`**

Generates a proof for the given inputs.

```typescript
/// { proof: { pi_a, pi_b, pi_c, protocol, curve }, publicSignals: [6] }
const proof = await multiplier.generateProof({ a: 2, b: 3 });
const proof = await circuit.generateProof({ a: 2, b: 3 });
```

#### verifyProof()
- **`async verifyProof(proof) -> bool`**

Verifies the proof.

```typescript
/// true
const isValidProof = await multiplier.verifyProof(proof);
const isValidProof = await circuit.verifyProof(proof);
```

#### generateCalldata()
- **`async generateCalldata(proof) -> calldata`**

Generates calldata by proof for the Solidity | Vyper verifier's `verifyProof()` method.

```typescript
/// You can use this calldata to call the verifier contract
const calldata = await multiplier.generateCalldata(proof);
const calldata = await circuit.generateCalldata(proof);
```

## Known limitations
- **`getCircuitName() -> string`**

Returns the name of the circuit from the config.

- **`getVerifierName() -> string`**

Returns the name of the verifier in the following form:

```typescript
<Circuit name><Proving system>Verifier
```

- **`getProvingSystemType() -> "groth16" | "plonk"`**

Returns the current proving system in use.

- **`getVerifierTemplate() -> string`**

- Currently, ZKit supports only the Groth16 proving system.
Returns the full `ejs` verifier template as a `string`.
70 changes: 30 additions & 40 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solarity/zkit",
"version": "0.3.0-rc.1",
"version": "0.3.0",
"license": "MIT",
"author": "Distributed Lab",
"readme": "README.md",
Expand Down Expand Up @@ -39,7 +39,7 @@
},
"dependencies": {
"ejs": "3.1.10",
"snarkjs": "0.7.3"
"snarkjs": "0.7.5"
},
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "3.0.5",
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BN128_CURVE_NAME = "bn128";
4 changes: 3 additions & 1 deletion src/core/CircuitZKit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export class CircuitZKit<Type extends ProvingSystemType> {

await snarkjs.wtns.calculate(inputs, wasmFile, wtnsFile);

return (await snarkjs.wtns.exportJson(wtnsFile)) as bigint[];
const wtnsJson = await snarkjs.wtns.exportJson(wtnsFile);

return wtnsJson as bigint[];
}

/**
Expand Down
14 changes: 12 additions & 2 deletions src/core/protocols/Groth16Implementer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ import { AbstractProtocolImplementer } from "./AbstractImplementer";
import { Signals } from "../../types/proof-utils";
import { Groth16ProofStruct, ProvingSystemType, Groth16Calldata } from "../../types/protocols";

import { terminateCurve } from "../../utils";

export class Groth16Implementer extends AbstractProtocolImplementer<"groth16"> {
public async generateProof(inputs: Signals, zKeyFilePath: string, wasmFilePath: string): Promise<Groth16ProofStruct> {
return (await snarkjs.groth16.fullProve(inputs, wasmFilePath, zKeyFilePath)) as Groth16ProofStruct;
const fullProof = await snarkjs.groth16.fullProve(inputs, wasmFilePath, zKeyFilePath);

await terminateCurve();

return fullProof as Groth16ProofStruct;
}

public async verifyProof(proof: Groth16ProofStruct, vKeyFilePath: string): Promise<boolean> {
const verifier = JSON.parse(fs.readFileSync(vKeyFilePath).toString());

return await snarkjs.groth16.verify(verifier, proof.publicSignals, proof.proof);
const proofVerification = await snarkjs.groth16.verify(verifier, proof.publicSignals, proof.proof);

await terminateCurve();

return proofVerification;
}

public async generateCalldata(proof: Groth16ProofStruct): Promise<Groth16Calldata> {
Expand Down
14 changes: 12 additions & 2 deletions src/core/protocols/PlonkImplementer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ import { AbstractProtocolImplementer } from "./AbstractImplementer";
import { Signals } from "../../types/proof-utils";
import { PlonkCalldata, PlonkProofStruct, ProvingSystemType } from "../../types/protocols";

import { terminateCurve } from "../../utils";

export class PlonkImplementer extends AbstractProtocolImplementer<"plonk"> {
public async generateProof(inputs: Signals, zKeyFilePath: string, wasmFilePath: string): Promise<PlonkProofStruct> {
return (await snarkjs.plonk.fullProve(inputs, wasmFilePath, zKeyFilePath)) as PlonkProofStruct;
const fullProof = await snarkjs.plonk.fullProve(inputs, wasmFilePath, zKeyFilePath);

await terminateCurve();

return fullProof as PlonkProofStruct;
}

public async verifyProof(proof: PlonkProofStruct, vKeyFilePath: string): Promise<boolean> {
const verifier = JSON.parse(fs.readFileSync(vKeyFilePath).toString());

return await snarkjs.plonk.verify(verifier, proof.publicSignals, proof.proof);
const proofVerification = await snarkjs.plonk.verify(verifier, proof.publicSignals, proof.proof);

await terminateCurve();

return proofVerification;
}

public async generateCalldata(proof: PlonkProofStruct): Promise<PlonkCalldata> {
Expand Down
6 changes: 6 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as snarkjs from "snarkjs";
import { BN128_CURVE_NAME } from "./constants";

export async function terminateCurve() {
await (await (snarkjs as any).curves.getCurveFromName(BN128_CURVE_NAME)).terminate();
}

0 comments on commit 4fa5a95

Please sign in to comment.