ZKit - Circom Zero Knowledge Kit
June 19, 2025 ยท View on GitHub
ZKit - Circom Zero Knowledge Kit
A zero knowledge kit that helps you interact with Circom circuits.
- Generate and verify ZK proofs with a single line of code.
- Leverage
groth16andplonkproving systems. - Render optimized Solidity | Vyper verifiers.
- Build and work with ZK witnesses.
- Substitute witness signals for advanced circuits testing.
Installation
To install the package, run:
npm install --save-dev @solarity/zkit
Usage
Important
The kit is not meant to be used directly as its fitness relies heavily on the environment, Circom compilation artifacts management, processing of remappings, etc. Consider using hardhat-zkit which is a complete, developer-friendly package.
CircuitZKit
CircuitZKit is a user-friendly interface for interacting with circom circuits.
To create a CircuitZKit object it is necessary to pass a circuit config and a ProtocolImplementer instance:
const config = {
circuitName: string;
circuitArtifactsPath: string;
verifierDirPath: string;
};
const implementer = new Groth16Implementer() | new PlonkImplementer();
const circuit = new CircuitZKit<"groth16" | "plonk">(config, implementer);
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.
The implementer is the instance of a certain proving system. Currently groth16 and plonk systems are supported.
API reference
async createVerifier("sol" | "vy", verifierNameSuffix?: string)
Creates a Solidity | Vyper verifier contract with the optional verifierNameSuffix on verifierDirPath path, which was specified in the config.
await circuit.createVerifier("sol");
await circuit.createVerifier("sol", "_suffix_");
async calculateWitness(inputs, witnessOverrides?) -> bigint[]
Calculates a witness in the tmp directory and returns its json representation.
An optional witnessOverrides parameter can be provided to replace specific signal values in the generated witness file.
/// witness = [1n, 200n, 20n, 10n]
const witness = await circuit.calculateWitness({ a: 10, b: 20 });
/// witness = [1n, 200n, 35n, 10n]
const witness = await circuit.calculateWitness({ a: 10, b: 20 }, { "main.a": 35 });
async generateProof(inputs, witnessOverrides?) -> proof
Generates a proof for the given inputs and witnessOverrides.
/// { proof: { pi_a, pi_b, pi_c, protocol, curve }, publicSignals: [6] }
const proof = await circuit.generateProof({ a: 2, b: 3 });
async verifyProof(proof) -> bool
Verifies the proof.
/// true
const isValidProof = await circuit.verifyProof(proof);
async generateCalldata(proof) -> calldata
Generates Calldata struct by proof for the Solidity | Vyper verifier's verifyProof() method.
/// You can use this `calldata` sturct in the circuit verifier contract.
/// calldata: { proofPoints: { a, b, c }, publicSignals: [6] }
const calldata = await circuit.generateCalldata(proof);
getCircuitName() -> string
Returns the name of the circuit from the config.
getVerifierName(verifierNameSuffix?: string) -> string
Returns the name of the verifier in the following form:
<Circuit name><Suffix><Proving system>Verifier
getProvingSystemType() -> "groth16" | "plonk"
Returns the current proving system in use.
getVerifierTemplate() -> string
Returns the full ejs verifier template as a string.