Skip to content

Commit

Permalink
Merge pull request #89 from erhant/erhant/c-tester
Browse files Browse the repository at this point in the history
Add C testing support to `WitnessTester` (WIP)
  • Loading branch information
erhant authored Sep 9, 2024
2 parents f506672 + b655f7c commit 14d9ca0
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 17 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ You can compute the witness via the `calculateWitness(input)` function. To test
> });
> ```
#### Using C Tester (Work in Progress ⌛)
You can make use of the C-tester as well, which performs much better for larger circuits than the WASM alternative.
There may be some prerequisites to compile, and we have an [issue on this](https://github.com/erhant/circomkit/issues/88) right now until we can have a complete setup guide.
### Proof Tester
As an alternative to simulate generating a proof and verifying it, you can use Proof Tester. The proof tester makes use of WASM file, prover key and verifier key in the background. It will use the underlying Circomkit configuration to look for those files, and it can generate them automatically if they do not exist. An example using Plonk protocol is given below. Notice how we create the necessary files before creating the tester, as they are required for proof generation and verification.
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
testEnvironment: 'node',
verbose: true,
rootDir: './tests',
testTimeout: 100000,
globalTeardown: '<rootDir>/hooks/teardown.js',
forceExit: true,
detectOpenHandles: true,
Expand Down
10 changes: 7 additions & 3 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import * as snarkjs from 'snarkjs';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import {wasm as wasm_tester} from 'circom_tester';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import {c as c_tester} from 'circom_tester';
import {writeFileSync, readFileSync, existsSync, mkdirSync, rmSync, renameSync} from 'fs';
import {readFile, rm, writeFile} from 'fs/promises';
import {randomBytes} from 'crypto';
import loglevel from 'loglevel';
import {downloadPtau, getPtauName} from '../utils/ptau';
import type {CircuitConfig, CircuitSignals, CircomWasmTester} from '../types';
import type {CircuitConfig, CircuitSignals, CircomTester} from '../types';
import {WitnessTester, ProofTester} from '../testers';
import {prettyStringify} from '../utils';
import {CircomkitConfig, DEFAULT, PRIMES, PROTOCOLS} from '../configs';
Expand Down Expand Up @@ -486,12 +489,13 @@ export class Circomkit {
/** Compiles the circuit and returns a witness tester instance. */
async WitnessTester<IN extends string[] = [], OUT extends string[] = []>(
circuit: string,
circuitConfig: CircuitConfig & {recompile?: boolean}
circuitConfig: CircuitConfig & {recompile?: boolean},
tester: 'wasm' | 'c' = 'wasm'
) {
circuitConfig.dir ??= 'test'; // defaults to test directory

const targetPath = this.instantiate(circuit, circuitConfig);
const circomWasmTester: CircomWasmTester = await wasm_tester(targetPath, {
const circomWasmTester: CircomTester = await (tester === 'wasm' ? wasm_tester : c_tester)(targetPath, {
output: undefined, // this makes tests to be created under /tmp
prime: this.config.prime,
verbose: this.config.verbose,
Expand Down
22 changes: 11 additions & 11 deletions src/testers/witnessTester.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AssertionError} from 'node:assert';
import type {CircomWasmTester, WitnessType, CircuitSignals, SymbolsType, SignalValueType} from '../types/';
import type {CircomTester, WitnessType, CircuitSignals, SymbolsType, SignalValueType} from '../types/';

// @todo detect optimized symbols https://github.com/erhant/circomkit/issues/80

Expand All @@ -12,12 +12,12 @@ export class WitnessTester<IN extends readonly string[] = [], OUT extends readon

constructor(
/** The underlying `circom_tester` object */
private readonly circomWasmTester: CircomWasmTester
private readonly circomTester: CircomTester
) {}

/** Assert that constraints are valid for a given witness. */
async expectConstraintPass(witness: WitnessType): Promise<void> {
return this.circomWasmTester.checkConstraints(witness);
return this.circomTester.checkConstraints(witness);
}

/**
Expand All @@ -41,7 +41,7 @@ export class WitnessTester<IN extends readonly string[] = [], OUT extends readon

/** Compute witness given the input signals. */
async calculateWitness(input: CircuitSignals<IN>): Promise<WitnessType> {
return this.circomWasmTester.calculateWitness(input, false);
return this.circomTester.calculateWitness(input, false);
}

/** Returns the number of constraints. */
Expand Down Expand Up @@ -287,13 +287,13 @@ export class WitnessTester<IN extends readonly string[] = [], OUT extends readon
* @param expectedOut computed output signals
*/
private assertOut(actualOut: WitnessType, expectedOut: CircuitSignals<OUT>): Promise<void> {
return this.circomWasmTester.assertOut(actualOut, expectedOut);
return this.circomTester.assertOut(actualOut, expectedOut);
}

/** Loads the list of R1CS constraints to `this.constraints`. */
private async loadConstraints(): Promise<void> {
await this.circomWasmTester.loadConstraints();
this.constraints = this.circomWasmTester.constraints;
await this.circomTester.loadConstraints();
this.constraints = this.circomTester.constraints;
}

/**
Expand All @@ -310,23 +310,23 @@ export class WitnessTester<IN extends readonly string[] = [], OUT extends readon
private async loadSymbols(): Promise<void> {
// no need to check if symbols are already defined
// that check happens within circomWasmTester
await this.circomWasmTester.loadSymbols();
this.symbols = this.circomWasmTester.symbols;
await this.circomTester.loadSymbols();
this.symbols = this.circomTester.symbols;
}

/**
* @deprecated this is buggy right now
* @param witness witness
*/
private getDecoratedOutput(witness: WitnessType): Promise<string> {
return this.circomWasmTester.getDecoratedOutput(witness);
return this.circomTester.getDecoratedOutput(witness);
}

/**
* Cleanup directory, should probably be called upon test completion (?)
* @deprecated this is buggy right now
*/
private release(): Promise<void> {
return this.circomWasmTester.release();
return this.circomTester.release();
}
}
2 changes: 1 addition & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export type CircuitConfig = {
* Not all functions may exist here, some are omitted.
* @see https://github.com/iden3/circom_tester/blob/main/wasm/tester.js
*/
export type CircomWasmTester = {
export type CircomTester = {
checkConstraints: (witness: WitnessType) => Promise<void>;
release: () => Promise<void>;
assertOut: (actualOut: WitnessType, expectedOut: CircuitSignals) => Promise<void>;
Expand Down
2 changes: 1 addition & 1 deletion tests/common/circuits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type PreparedTestCircuit<S extends Record<string, CircuitSignals>> = {
*/
export function prepareMultiplier(N: number, order: bigint = primes['bn128']) {
const name = `multiplier_${N}`;
const config = {
const config: CircuitConfig = {
file: 'multiplier',
template: 'Multiplier',
params: [N],
Expand Down
4 changes: 3 additions & 1 deletion tests/witnessTester.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {Circomkit, WitnessTester} from '../src';
import {prepareMultiplier} from './common';

// TODO: add C tester

describe('witness tester', () => {
let circuit: WitnessTester<['in'], ['out']>;
const {
Expand All @@ -18,7 +20,7 @@ describe('witness tester', () => {
dirInputs: './tests/inputs',
dirBuild: './tests/build',
});
circuit = await circomkit.WitnessTester(name, config);
circuit = await circomkit.WitnessTester(name, {...config, recompile: true});
});

it('should have correct number of constraints', async () => {
Expand Down

0 comments on commit 14d9ca0

Please sign in to comment.