mirror of
https://github.com/erhant/circomkit.git
synced 2026-05-05 03:00:37 -04:00
added tests
This commit is contained in:
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@@ -7,25 +7,6 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build checks
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build everything
|
||||
run: yarn build
|
||||
|
||||
style:
|
||||
name: Styling checks
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -44,3 +25,6 @@ jobs:
|
||||
|
||||
- name: Lint code
|
||||
run: yarn lint
|
||||
|
||||
- name: Build everything
|
||||
run: yarn build
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
name: test
|
||||
name: tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- erhant/tests
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -22,6 +21,13 @@ jobs:
|
||||
cd circom
|
||||
cargo build --release
|
||||
cargo install --path circom
|
||||
cd ..
|
||||
|
||||
- name: Print help
|
||||
- name: Print Circom version
|
||||
run: circom --help
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Run tests
|
||||
run: yarn test
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -107,19 +107,12 @@ dist
|
||||
build
|
||||
dist
|
||||
|
||||
# circuit-specific powers of tau are ignored
|
||||
*.ptau
|
||||
# universal ptaus not ignored
|
||||
!ptau/*
|
||||
# temporary ptaus are ignored
|
||||
tmp.ptau
|
||||
|
||||
# is this still a thing lol
|
||||
.DS_Store
|
||||
|
||||
# ignore auto generated test circuits
|
||||
circuits/test
|
||||
ptau
|
||||
|
||||
# for init tests
|
||||
tmptest
|
||||
inputs/multiplier_3/test-input.json
|
||||
|
||||
13
README.md
13
README.md
@@ -15,6 +15,9 @@
|
||||
<a href="./.github/workflows/build.yml" target="_blank">
|
||||
<img alt="Workflow: Build" src="https://github.com/erhant/circomkit/actions/workflows/build.yml/badge.svg?branch=main">
|
||||
</a>
|
||||
<a href="./.github/workflows/tests.yml" target="_blank">
|
||||
<img alt="Workflow: Tests" src="https://github.com/erhant/circomkit/actions/workflows/tests.yml/badge.svg?branch=main">
|
||||
</a>
|
||||
<a href="https://github.com/iden3/snarkjs" target="_blank">
|
||||
<img alt="GitHub: SnarkJS" src="https://img.shields.io/badge/github-snarkjs-lightgray?logo=github">
|
||||
</a>
|
||||
@@ -126,7 +129,7 @@ npx circomkit calldata circuit input
|
||||
|
||||
Circomkit with its default configuration follows an _opinionated file structure_, abstracting away the pathing and orientation behind the scenes. All of these can be customized by overriding the respective settings in `circomkit.json`.
|
||||
|
||||
Here is an example structure, where we have a generic Sudoku proof-of-solution circuit, and we instantiate it for a 9x9 board:
|
||||
An example structure is shown below. Suppose there is a generic circuit for a Sudoku solution knowledge proof written under `circuits` folder. When instantiated, a `main` component for a 9x9 board is created under `circuits/main`. The solution along with it's puzzle is stored as a JSON object under `inputs/sudoku_9x9`. You can see the respective artifacts under `build` directory. In particular, we see `groth16` prefix on some files, indicating that Groth16 protocol was used to create them.
|
||||
|
||||
```sh
|
||||
circomkit
|
||||
@@ -159,8 +162,10 @@ circomkit
|
||||
│
|
||||
│── sudoku_9x9.r1cs
|
||||
│── sudoku_9x9.sym
|
||||
│── prover_key.zkey
|
||||
└── verifier_key.json
|
||||
│
|
||||
│── groth16_pkey.zkey
|
||||
│── groth16_vkey.json
|
||||
└── groth16_verifier.sol
|
||||
|
||||
```
|
||||
|
||||
@@ -172,6 +177,8 @@ Run all tests via:
|
||||
yarn test
|
||||
```
|
||||
|
||||
You can also use the CLI in the repo by `yarn cli` as if you are using `npx circomkit`. This is useful for hands-on testing stuff.
|
||||
|
||||
## Styling
|
||||
|
||||
Circomkit uses [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html).
|
||||
|
||||
@@ -37,27 +37,24 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.4",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/mocha-each": "^2.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
"gts": "^3.1.1",
|
||||
"mocha": "^10.2.0",
|
||||
"mocha-each": "^2.0.1",
|
||||
"rimraf": "^5.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"circomlib": "^2.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"chai": "^4.3.7",
|
||||
"circom_tester": "^0.0.19",
|
||||
"loglevel": "^1.8.1",
|
||||
"snarkjs": "^0.6.0"
|
||||
"snarkjs": "^0.7.0"
|
||||
},
|
||||
"keywords": [
|
||||
"circom",
|
||||
"zk",
|
||||
"zero knowledge",
|
||||
"zero-knowledge",
|
||||
"snarkjs",
|
||||
"typescript",
|
||||
"cli",
|
||||
|
||||
BIN
ptau/powersOfTau28_hez_final_08.ptau
Normal file
BIN
ptau/powersOfTau28_hez_final_08.ptau
Normal file
Binary file not shown.
@@ -1,58 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs';
|
||||
import {Circomkit} from '../circomkit';
|
||||
import {initFiles, postInitString} from '../utils/initFiles';
|
||||
import {initFiles, postInitString, usageString} from '../utils';
|
||||
import {prettyStringify} from '../utils';
|
||||
|
||||
const CONFIG_PATH = './circomkit.json';
|
||||
const DEFAULT_INPUT = 'default';
|
||||
const USAGE = `Usage:
|
||||
|
||||
Compile the circuit.
|
||||
> compile circuit
|
||||
|
||||
Create main component.
|
||||
> instantiate circuit
|
||||
|
||||
Print circuit information.
|
||||
> info circuit
|
||||
|
||||
Clean build artifacts & main component.
|
||||
> clean circuit
|
||||
|
||||
Export Solidity verifier.
|
||||
> contract circuit
|
||||
|
||||
Export calldata for a verifier contract.
|
||||
> calldata circuit input
|
||||
|
||||
Export JSON for a chosen file.
|
||||
> json r1cs circuit
|
||||
> json zkey circuit
|
||||
> json wtns circuit input
|
||||
|
||||
Commence circuit-specific setup.
|
||||
> setup circuit
|
||||
> setup circuit ptau-path
|
||||
|
||||
Download the PTAU file needed for the circuit.
|
||||
> ptau circuit
|
||||
|
||||
Generate a proof.
|
||||
> prove circuit input
|
||||
|
||||
Verify a proof.
|
||||
> verify circuit input
|
||||
|
||||
Generate a witness.
|
||||
> witness circuit input
|
||||
|
||||
Initialize a Circomkit project.
|
||||
> init # initializes in current folder
|
||||
> init project-name # initializes in a new folder
|
||||
|
||||
Print configurations to console.
|
||||
> config
|
||||
`;
|
||||
|
||||
async function cli(): Promise<number> {
|
||||
// read user configs & override if there are any
|
||||
@@ -91,12 +44,12 @@ async function cli(): Promise<number> {
|
||||
|
||||
case 'json': {
|
||||
titleLog('Exporting JSON file');
|
||||
const path = await circomkit.json(
|
||||
const {json, path} = await circomkit.json(
|
||||
process.argv[3] as 'r1cs' | 'zkey' | 'wtns',
|
||||
process.argv[4],
|
||||
process.argv[5],
|
||||
true
|
||||
process.argv[5]
|
||||
);
|
||||
writeFileSync(path, prettyStringify(json));
|
||||
circomkit.log('Exported at: ' + path, 'success');
|
||||
break;
|
||||
}
|
||||
@@ -163,8 +116,8 @@ async function cli(): Promise<number> {
|
||||
case 'setup': {
|
||||
titleLog('Circuit-specific setup');
|
||||
const paths = await circomkit.setup(process.argv[3]);
|
||||
circomkit.log('Prover key created: ' + paths.proverKey, 'success');
|
||||
circomkit.log('Verifier key created: ' + paths.verifierKey, 'success');
|
||||
circomkit.log('Prover key created: ' + paths.proverKeyPath, 'success');
|
||||
circomkit.log('Verifier key created: ' + paths.verifierKeyPath, 'success');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -196,7 +149,7 @@ async function cli(): Promise<number> {
|
||||
}
|
||||
|
||||
default:
|
||||
console.log(USAGE);
|
||||
console.log(usageString);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {writeFileSync, readFileSync, existsSync, mkdirSync, rmSync, renameSync}
|
||||
import {readFile, rm, writeFile} from 'fs/promises';
|
||||
import {instantiate} from './utils/instantiate';
|
||||
import {downloadPtau, getPtauName} from './utils/ptau';
|
||||
import type {CircuitConfig, R1CSInfoType} from './types/circuit';
|
||||
import type {CircuitConfig, CircuitSignals, R1CSInfoType} from './types/circuit';
|
||||
import {Logger, getLogger} from 'loglevel';
|
||||
import type {
|
||||
CircomkitConfig,
|
||||
@@ -16,7 +16,7 @@ import {randomBytes} from 'crypto';
|
||||
import {CircomWasmTester} from './types/circom_tester';
|
||||
import WasmTester from './testers/wasmTester';
|
||||
import ProofTester from './testers/proofTester';
|
||||
import {primeToCurveName} from './utils/curves';
|
||||
import {prettyStringify, primeToCurveName} from './utils';
|
||||
import {defaultConfig, colors, CURVES, PROTOCOLS} from './utils/config';
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ import {defaultConfig, colors, CURVES, PROTOCOLS} from './utils/config';
|
||||
* const circomkit = new Circomkit()
|
||||
* ```
|
||||
*
|
||||
* It also provides a WasmTester and a ProofTester module which uses Chai assertions within.
|
||||
* It also provides a **WasmTester** and a **ProofTester** module which uses Chai assertions within.
|
||||
*
|
||||
* ```ts
|
||||
* const wasmTester = await circomkit.WasmTester(circuitName, circuitConfig)
|
||||
@@ -65,11 +65,6 @@ export class Circomkit {
|
||||
}
|
||||
}
|
||||
|
||||
/** Pretty-print for JSON stringify. */
|
||||
private prettyStringify(obj: unknown): string {
|
||||
return JSON.stringify(obj, undefined, 2);
|
||||
}
|
||||
|
||||
/** Parse circuit config from `circuits.json` */
|
||||
private readCircuitConfig(circuit: string): CircuitConfig {
|
||||
const circuits = JSON.parse(readFileSync(this.config.circuits, 'utf-8'));
|
||||
@@ -92,18 +87,18 @@ export class Circomkit {
|
||||
return dir;
|
||||
case 'target':
|
||||
return `${this.config.dirCircuits}/main/${circuit}.circom`;
|
||||
case 'pkey':
|
||||
return `${dir}/prover_key.zkey`;
|
||||
case 'vkey':
|
||||
return `${dir}/verifier_key.json`;
|
||||
case 'r1cs':
|
||||
return `${dir}/${circuit}.r1cs`;
|
||||
case 'sym':
|
||||
return `${dir}/${circuit}.sym`;
|
||||
case 'sol':
|
||||
return `${dir}/Verifier_${this.config.protocol}.sol`;
|
||||
case 'wasm':
|
||||
return `${dir}/${circuit}_js/${circuit}.wasm`;
|
||||
case 'pkey':
|
||||
return `${dir}/${this.config.protocol}_pkey.zkey`;
|
||||
case 'vkey':
|
||||
return `${dir}/${this.config.protocol}_vkey.json`;
|
||||
case 'sol':
|
||||
return `${dir}/${this.config.protocol}_verifier.sol`;
|
||||
default:
|
||||
throw new Error('Invalid type: ' + type);
|
||||
}
|
||||
@@ -166,7 +161,7 @@ export class Circomkit {
|
||||
|
||||
/** Information about circuit. */
|
||||
async info(circuit: string): Promise<R1CSInfoType> {
|
||||
// we do not pass this._logger here in purpose
|
||||
// we do not pass this._logger here on purpose
|
||||
const r1csinfo = await snarkjs.r1cs.info(this.path(circuit, 'r1cs'), undefined);
|
||||
return {
|
||||
variables: r1csinfo.nVars,
|
||||
@@ -250,7 +245,11 @@ export class Circomkit {
|
||||
/** Export calldata to console.
|
||||
* @returns calldata as a string
|
||||
*/
|
||||
async calldata(circuit: string, input: string) {
|
||||
async calldata(circuit: string, input: string): Promise<string> {
|
||||
// fflonk gives error (tested at snarkjs v0.7.0)
|
||||
if (this.config.protocol === 'fflonk') {
|
||||
throw new Error('Exporting calldata is not supported for fflonk yet.');
|
||||
}
|
||||
const [pubs, proof] = (
|
||||
await Promise.all(
|
||||
(['pubs', 'proof'] as const)
|
||||
@@ -307,8 +306,8 @@ export class Circomkit {
|
||||
const dir = this.pathWithInput(circuit, input, 'dir');
|
||||
mkdirSync(dir, {recursive: true});
|
||||
await Promise.all([
|
||||
writeFile(this.pathWithInput(circuit, input, 'pubs'), this.prettyStringify(fullProof.publicSignals)),
|
||||
writeFile(this.pathWithInput(circuit, input, 'proof'), this.prettyStringify(fullProof.proof)),
|
||||
writeFile(this.pathWithInput(circuit, input, 'pubs'), prettyStringify(fullProof.publicSignals)),
|
||||
writeFile(this.pathWithInput(circuit, input, 'proof'), prettyStringify(fullProof.proof)),
|
||||
]);
|
||||
return dir;
|
||||
}
|
||||
@@ -316,7 +315,7 @@ export class Circomkit {
|
||||
/** Commence a circuit-specific setup.
|
||||
* @returns path to verifier key and prover key
|
||||
*/
|
||||
async setup(circuit: string, ptauPath?: string): Promise<{proverKey: string; verifierKey: string}> {
|
||||
async setup(circuit: string, ptauPath?: string): Promise<{proverKeyPath: string; verifierKeyPath: string}> {
|
||||
const r1csPath = this.path(circuit, 'r1cs');
|
||||
const pkeyPath = this.path(circuit, 'pkey');
|
||||
const vkeyPath = this.path(circuit, 'vkey');
|
||||
@@ -377,8 +376,8 @@ export class Circomkit {
|
||||
|
||||
// export verification key
|
||||
const vkey = await snarkjs.zKey.exportVerificationKey(pkeyPath, this._logger);
|
||||
writeFileSync(vkeyPath, this.prettyStringify(vkey));
|
||||
return {verifierKey: vkeyPath, proverKey: pkeyPath};
|
||||
writeFileSync(vkeyPath, prettyStringify(vkey));
|
||||
return {verifierKeyPath: vkeyPath, proverKeyPath: pkeyPath};
|
||||
}
|
||||
|
||||
/** Verify a proof for some public signals.
|
||||
@@ -412,20 +411,27 @@ export class Circomkit {
|
||||
return wtnsPath;
|
||||
}
|
||||
|
||||
/** Exports a JSON input file for some circuit with the given object.
|
||||
* This is useful for testing real circuits, or creating an input programmatically.
|
||||
* Overwrites an existing input.
|
||||
* @returns path to created input file
|
||||
*/
|
||||
input(circuit: string, input: string, data: CircuitSignals): string {
|
||||
const inputPath = this.pathWithInput(circuit, input, 'in');
|
||||
writeFileSync(inputPath, prettyStringify(data));
|
||||
return inputPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a circuit artifact in JSON format. If the last argument `write` is true, it will write to
|
||||
* file with the appropriate path, and return the path. Otheriwse, returns the JSON obejct.
|
||||
* @param type type of file to export
|
||||
* @returns a JSON object or the path that it would be exported to.
|
||||
*/
|
||||
async json(
|
||||
type: 'r1cs' | 'zkey' | 'wtns',
|
||||
circuit: string,
|
||||
input?: string,
|
||||
write?: boolean
|
||||
): Promise<object | string> {
|
||||
async json(type: 'r1cs' | 'zkey' | 'wtns', circuit: string, input?: string): Promise<{json: object; path: string}> {
|
||||
let json: object;
|
||||
let path: string;
|
||||
|
||||
switch (type) {
|
||||
// R1CS
|
||||
case 'r1cs': {
|
||||
@@ -435,6 +441,11 @@ export class Circomkit {
|
||||
}
|
||||
// Prover key
|
||||
case 'zkey': {
|
||||
// must be groth16, others give error (tested at snarkjs v0.7.0)
|
||||
if (this.config.protocol !== 'groth16') {
|
||||
throw new Error('Exporting zKey to JSON only supported for groth16 at the moment.');
|
||||
}
|
||||
|
||||
path = this.path(circuit, 'pkey');
|
||||
json = await snarkjs.zKey.exportJson(path, undefined); // does not take logger
|
||||
break;
|
||||
@@ -450,13 +461,10 @@ export class Circomkit {
|
||||
throw new Error('Unknown export target: ' + type);
|
||||
}
|
||||
|
||||
if (write) {
|
||||
path += '.json';
|
||||
writeFileSync(path, this.prettyStringify(json));
|
||||
return path;
|
||||
} else {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
json,
|
||||
path: path + '.json',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,13 +96,7 @@ export default class WasmTester<IN extends readonly string[] = [], OUT extends r
|
||||
console.log(`# constraints: ${numConstraints}`);
|
||||
|
||||
if (expected !== undefined) {
|
||||
if (numConstraints < expected) {
|
||||
console.log(`\x1b[0;31mx expectation: ${expected}\x1b[0m`);
|
||||
} else if (numConstraints > expected) {
|
||||
console.log(`\x1b[0;33m! expectation: ${expected}\x1b[0m`);
|
||||
} else {
|
||||
console.log(`\x1b[0;32m✔\x1b[2;37m expectation: ${expected}\x1b[0m`);
|
||||
}
|
||||
expect(numConstraints).to.be.greaterThanOrEqual(expected, 'Circuit is under-constrained!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import type {CircomkitConfig} from '../types/circomkit';
|
||||
|
||||
/** A mapping from prime (decimals) to curve name. */
|
||||
export const primeToCurveName: {[key: `${number}`]: CircomkitConfig['curve']} = {
|
||||
'21888242871839275222246405745257275088548364400416034343698204186575808495617': 'bn128',
|
||||
'52435875175126190479447740508185965837690552500527637822603658699938581184513': 'bls12381',
|
||||
'18446744069414584321': 'goldilocks',
|
||||
} as const;
|
||||
@@ -1,3 +1,17 @@
|
||||
import type {CircomkitConfig} from '../types/circomkit';
|
||||
|
||||
/** A mapping from prime (decimals) to curve name. */
|
||||
export const primeToCurveName: {[key: `${number}`]: CircomkitConfig['curve']} = {
|
||||
'21888242871839275222246405745257275088548364400416034343698204186575808495617': 'bn128',
|
||||
'52435875175126190479447740508185965837690552500527637822603658699938581184513': 'bls12381',
|
||||
'18446744069414584321': 'goldilocks',
|
||||
} as const;
|
||||
|
||||
/** JSON Stringify with a prettier format. */
|
||||
export function prettyStringify(obj: unknown): string {
|
||||
return JSON.stringify(obj, undefined, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial files for Cirocmkit development environment.
|
||||
* This is most likely to be used by the CLI via `npx circomkit init`.
|
||||
@@ -101,3 +115,52 @@ You should also install the following packages:
|
||||
npm install --save-dev ts-node typescript mocha @types/mocha
|
||||
|
||||
`;
|
||||
|
||||
export const usageString = `Usage:
|
||||
|
||||
Compile the circuit.
|
||||
> compile circuit
|
||||
|
||||
Create main component.
|
||||
> instantiate circuit
|
||||
|
||||
Print circuit information.
|
||||
> info circuit
|
||||
|
||||
Clean build artifacts & main component.
|
||||
> clean circuit
|
||||
|
||||
Export Solidity verifier.
|
||||
> contract circuit
|
||||
|
||||
Export calldata for a verifier contract.
|
||||
> calldata circuit input
|
||||
|
||||
Export JSON for a chosen file.
|
||||
> json r1cs circuit
|
||||
> json zkey circuit
|
||||
> json wtns circuit input
|
||||
|
||||
Commence circuit-specific setup.
|
||||
> setup circuit
|
||||
> setup circuit ptau-path
|
||||
|
||||
Download the PTAU file needed for the circuit.
|
||||
> ptau circuit
|
||||
|
||||
Generate a proof.
|
||||
> prove circuit input
|
||||
|
||||
Verify a proof.
|
||||
> verify circuit input
|
||||
|
||||
Generate a witness.
|
||||
> witness circuit input
|
||||
|
||||
Initialize a Circomkit project.
|
||||
> init # initializes in current folder
|
||||
> init project-name # initializes in a new folder
|
||||
|
||||
Print configurations to console.
|
||||
> config
|
||||
`;
|
||||
101
tests/circomkit.test.ts
Normal file
101
tests/circomkit.test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import forEach from 'mocha-each';
|
||||
import {PROTOCOLS} from '../src/utils/config';
|
||||
import {Circomkit} from '../src';
|
||||
import {expect} from 'chai';
|
||||
import {existsSync} from 'fs';
|
||||
import {CIRCUIT_CONFIG, CIRCUIT_NAME, INPUT, INPUT_NAME, PTAU_PATH} from './common';
|
||||
|
||||
// we are not testing all curves because PTAU is only available for bn128
|
||||
forEach(PROTOCOLS).describe('protocol: %s', (protocol: (typeof PROTOCOLS)[number]) => {
|
||||
let circomkit: Circomkit;
|
||||
|
||||
before(() => {
|
||||
circomkit = new Circomkit({
|
||||
protocol,
|
||||
verbose: false,
|
||||
logLevel: 'silent',
|
||||
});
|
||||
});
|
||||
|
||||
it('should instantiate circuit', () => {
|
||||
const path = circomkit.instantiate(CIRCUIT_NAME, CIRCUIT_CONFIG);
|
||||
expect(existsSync(path)).to.be.true;
|
||||
});
|
||||
|
||||
it('should compile circuit', async () => {
|
||||
await circomkit.compile(CIRCUIT_NAME);
|
||||
});
|
||||
|
||||
it('should give correct circuit info', async () => {
|
||||
const info = await circomkit.info(CIRCUIT_NAME);
|
||||
expect(info.curve).to.eq('bn128');
|
||||
expect(info.constraints).to.eq(3); // three constraints for 3 numbers
|
||||
expect(info.privateInputs).to.eq(3); // input is 3 numbers, all private
|
||||
expect(info.publicInputs).to.eq(0); // there are no public inputs
|
||||
expect(info.outputs).to.eq(1); // there is only 1 output, the product
|
||||
expect(info.labels).to.eq(7); // 3 inputs + 2 inner signals + 1 output + 1 constant
|
||||
expect(info.variables).to.eq(7); // 3 inputs + 2 inner signals + 1 output + 1 constant
|
||||
});
|
||||
|
||||
it('should setup circuit', async () => {
|
||||
await circomkit.setup(CIRCUIT_NAME, PTAU_PATH);
|
||||
});
|
||||
|
||||
it('should create an input', async () => {
|
||||
const path = circomkit.input(CIRCUIT_NAME, INPUT_NAME, INPUT);
|
||||
expect(existsSync(path)).to.be.true;
|
||||
});
|
||||
|
||||
it('should create a witness', async () => {
|
||||
const path = await circomkit.witness(CIRCUIT_NAME, INPUT_NAME);
|
||||
expect(existsSync(path)).to.be.true;
|
||||
});
|
||||
|
||||
it('should create a proof', async () => {
|
||||
const path = await circomkit.prove(CIRCUIT_NAME, INPUT_NAME);
|
||||
expect(existsSync(path)).to.be.true;
|
||||
});
|
||||
|
||||
it('should verify the proof', async () => {
|
||||
const isVerified = await circomkit.verify(CIRCUIT_NAME, INPUT_NAME);
|
||||
expect(isVerified).to.be.true;
|
||||
});
|
||||
|
||||
it('should export verifier contract', async () => {
|
||||
const path = await circomkit.contract(CIRCUIT_NAME);
|
||||
expect(existsSync(path)).to.be.true;
|
||||
});
|
||||
|
||||
it('should export contract calldata', async () => {
|
||||
try {
|
||||
await circomkit.calldata(CIRCUIT_NAME, INPUT_NAME);
|
||||
|
||||
// fflonk should fail for `calldata`
|
||||
if (protocol === 'fflonk') {
|
||||
throw new Error('Should have thrown an error before this.');
|
||||
}
|
||||
} catch (err) {
|
||||
expect((err as Error).message).to.eq('Exporting calldata is not supported for fflonk yet.');
|
||||
}
|
||||
});
|
||||
|
||||
it('should export JSON files', async () => {
|
||||
await circomkit.json('r1cs', CIRCUIT_NAME);
|
||||
await circomkit.json('wtns', CIRCUIT_NAME, INPUT_NAME);
|
||||
|
||||
try {
|
||||
await circomkit.json('zkey', CIRCUIT_NAME);
|
||||
|
||||
// only groth16 is allowed to export zkey
|
||||
if (protocol !== 'groth16') {
|
||||
throw new Error('Should have thrown an error before this.');
|
||||
}
|
||||
} catch (err) {
|
||||
expect((err as Error).message).to.eq('Exporting zKey to JSON only supported for groth16 at the moment.');
|
||||
}
|
||||
});
|
||||
|
||||
it('should clean artifacts', async () => {
|
||||
await circomkit.clean(CIRCUIT_NAME);
|
||||
});
|
||||
});
|
||||
21
tests/common/index.ts
Normal file
21
tests/common/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// create N random numbers for the multiplier circuit and find its product
|
||||
export const N = 3;
|
||||
|
||||
const numbers = Array.from({length: N}, () => Math.floor(Math.random() * 100 * N));
|
||||
const product = numbers.reduce((prev, acc) => acc * prev);
|
||||
|
||||
export const CIRCUIT_NAME = `multiplier_${N}`;
|
||||
export const CIRCUIT_CONFIG = {
|
||||
file: 'multiplier',
|
||||
template: 'Multiplier',
|
||||
params: [N],
|
||||
};
|
||||
export const INPUT_NAME = 'test-input';
|
||||
export const PTAU_PATH = './ptau/powersOfTau28_hez_final_08.ptau';
|
||||
|
||||
export const INPUT = {
|
||||
in: numbers,
|
||||
};
|
||||
export const OUTPUT = {
|
||||
out: product,
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
import {expect} from 'chai';
|
||||
import {Circomkit} from '../src';
|
||||
|
||||
// try and compile with all protocol + curve combinations
|
||||
describe('compilation tests', () => {});
|
||||
@@ -1,32 +1,18 @@
|
||||
import {Circomkit, FullProof, ProofTester, WasmTester} from '../src';
|
||||
import {expect} from 'chai';
|
||||
import {CIRCUIT_CONFIG, CIRCUIT_NAME, INPUT, N, OUTPUT} from './common';
|
||||
|
||||
describe('testers with multiplier circuit', () => {
|
||||
describe('testers', () => {
|
||||
const circomkit = new Circomkit({
|
||||
verbose: false,
|
||||
logLevel: 'silent',
|
||||
});
|
||||
|
||||
const N = 3;
|
||||
const circuitName = `multiplier_${N}`;
|
||||
const numbers = Array.from({length: N}, () => Math.floor(Math.random() * 100 * N));
|
||||
const product = numbers.reduce((prev, acc) => acc * prev);
|
||||
|
||||
const INPUT = {
|
||||
in: numbers,
|
||||
};
|
||||
const OUTPUT = {
|
||||
out: product,
|
||||
};
|
||||
|
||||
describe('wasm tester', () => {
|
||||
let circuit: WasmTester<['in'], ['out']>;
|
||||
|
||||
before(async () => {
|
||||
circuit = await circomkit.WasmTester(circuitName, {
|
||||
file: 'multiplier',
|
||||
template: 'Multiplier',
|
||||
params: [N],
|
||||
});
|
||||
circuit = await circomkit.WasmTester(CIRCUIT_NAME, CIRCUIT_CONFIG);
|
||||
await circuit.checkConstraintCount(N);
|
||||
});
|
||||
|
||||
@@ -47,7 +33,7 @@ describe('testers with multiplier circuit', () => {
|
||||
let fullProof: FullProof;
|
||||
|
||||
before(async () => {
|
||||
circuit = await circomkit.ProofTester(circuitName);
|
||||
circuit = await circomkit.ProofTester(CIRCUIT_NAME);
|
||||
fullProof = await circuit.prove(INPUT);
|
||||
});
|
||||
|
||||
@@ -56,8 +42,7 @@ describe('testers with multiplier circuit', () => {
|
||||
});
|
||||
|
||||
it('should NOT verify', async () => {
|
||||
// just give a prime number as the output, assuming none of the inputs are 1
|
||||
await circuit.expectFail(fullProof.proof, ['13']);
|
||||
await circuit.expectFail(fullProof.proof, ['1']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user