mirror of
https://github.com/erhant/circomkit.git
synced 2026-05-05 03:00:37 -04:00
added main comp generator, some rfks
This commit is contained in:
24
README.md
24
README.md
@@ -10,21 +10,23 @@ The repository follows an _opinionated file structure_ shown below, abstracting
|
||||
|
||||
```sh
|
||||
circom-ts-starter
|
||||
├── circuits # where you write templates
|
||||
│ ├── main # where you instantiate components
|
||||
├── circuit.config.cjs # configs for circuit main components
|
||||
├── .cli.env # environment variables for cli
|
||||
├── circuits # where you write templates
|
||||
│ ├── main # where you instantiate components
|
||||
│ │ │── foo-main.circom
|
||||
│ │ └── ...
|
||||
│ │── foo.circom
|
||||
│ └── ...
|
||||
├── inputs # where you write JSON inputs per circuit
|
||||
├── inputs # where you write JSON inputs per circuit
|
||||
│ ├── foo
|
||||
│ │ ├── input-name.json
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── ptau # universal phase-1 setups
|
||||
├── ptau # universal phase-1 setups
|
||||
│ ├── powersOfTau28_hez_final_12.ptau
|
||||
│ └── ...
|
||||
└── build # artifacts, .gitignore'd
|
||||
└── build # artifacts, .gitignore'd
|
||||
│── foo-main
|
||||
│ │── foo-main_js # artifacts of compilation
|
||||
│ │ │── generate_witness.js
|
||||
@@ -42,14 +44,22 @@ circom-ts-starter
|
||||
└── ...
|
||||
```
|
||||
|
||||
Write your circuits under `circuits` folder. The circuit code itself should be templates only. You should only create the main component under `circuits/main` folder.
|
||||
Write your circuits under `circuits` folder; the circuit code itself should be templates only. The main component itself is created automatically via a [script](./scripts/instantiate.js) which uses a simple EJS [template](./circuits/main/_template.circom) to create the main component. The target circuits are defined under the [circuit configs](./circuit.config.cjs) file, such as:
|
||||
|
||||
```js
|
||||
multiplier3: {
|
||||
file: 'multiplier',
|
||||
template: 'Multiplier',
|
||||
publicInputs: [],
|
||||
templateInputs: [3],
|
||||
}
|
||||
```
|
||||
|
||||
Use the [CLI](./scripts/cli.sh), or its wrapper scripts in [package.json](./package.json) to do stuff with your circuits.
|
||||
|
||||
```bash
|
||||
yarn compile -c circuit-name
|
||||
yarn clean -c circuit-name
|
||||
yarn type -c circuit-name
|
||||
yarn ptau -c circuit-name -n num-contribs -p phase1-ptau-path
|
||||
yarn prove -c circuit-name -i input-name
|
||||
yarn verify -c circuit-name -i input-name
|
||||
|
||||
30
circuit.config.cjs
Normal file
30
circuit.config.cjs
Normal file
@@ -0,0 +1,30 @@
|
||||
module.exports = {
|
||||
// multiplication of 3 numbers
|
||||
multiplier3: {
|
||||
file: 'multiplier',
|
||||
template: 'Multiplier',
|
||||
publicInputs: [],
|
||||
templateInputs: [3],
|
||||
},
|
||||
// A 9x9 sudoku board
|
||||
sudoku9: {
|
||||
file: 'sudoku',
|
||||
template: 'Sudoku',
|
||||
publicInputs: ['puzzle'],
|
||||
templateInputs: [3],
|
||||
},
|
||||
// 64-bit floating point, 11-bit exponent and 52-bit mantissa
|
||||
fp64: {
|
||||
file: 'float_add',
|
||||
template: 'FloatAdd',
|
||||
publicInputs: [],
|
||||
templateInputs: [11, 52],
|
||||
},
|
||||
// 32-bit floating point, 8-bit exponent and 23-bit mantissa
|
||||
fp32: {
|
||||
file: 'float_add',
|
||||
template: 'FloatAdd',
|
||||
publicInputs: [],
|
||||
templateInputs: [8, 23],
|
||||
},
|
||||
};
|
||||
18
circuits/fibonacci.circom
Normal file
18
circuits/fibonacci.circom
Normal file
@@ -0,0 +1,18 @@
|
||||
pragma circom 2.0.0;
|
||||
|
||||
// Fibonacci with custom starting numbers
|
||||
template Fibonacci(n) {
|
||||
assert(n >= 2);
|
||||
signal input in[2];
|
||||
signal output out;
|
||||
|
||||
// compute the sequence
|
||||
signal f[n+1];
|
||||
fib[0] <== in[0];
|
||||
fib[1] <== in[1];
|
||||
for (var i = 2; i <= n; i++) {
|
||||
fib[i] <== fib[i-2] + fib[i-1];
|
||||
}
|
||||
|
||||
out <== fib[n];
|
||||
}
|
||||
12
circuits/main/_template.circom
Normal file
12
circuits/main/_template.circom
Normal file
@@ -0,0 +1,12 @@
|
||||
<%#'this file is an EJS template to generate main component for circuits'-%>
|
||||
<%#'configuration is read from config.js in the project root directory'-%>
|
||||
// auto-generated by instantiate.js
|
||||
pragma circom 2.0.0;
|
||||
|
||||
include "../../circuits/<%= file %>.circom";
|
||||
|
||||
component main<%=
|
||||
publicInputs.length == 0 ?
|
||||
'' :
|
||||
' {public[' + publicInputs.join(", ") + ']}'
|
||||
%> = <%= template %>(<%= templateInputs.join(", ") %>);
|
||||
6
circuits/main/fp32.circom
Normal file
6
circuits/main/fp32.circom
Normal file
@@ -0,0 +1,6 @@
|
||||
// auto-generated by instantiate.js
|
||||
pragma circom 2.0.0;
|
||||
|
||||
include "../../circuits/float_add.circom";
|
||||
|
||||
component main = FloatAdd(8, 23);
|
||||
6
circuits/main/fp64.circom
Normal file
6
circuits/main/fp64.circom
Normal file
@@ -0,0 +1,6 @@
|
||||
// auto-generated by instantiate.js
|
||||
pragma circom 2.0.0;
|
||||
|
||||
include "../../circuits/float_add.circom";
|
||||
|
||||
component main = FloatAdd(11, 52);
|
||||
@@ -1,6 +1,6 @@
|
||||
// auto-generated by instantiate.js
|
||||
pragma circom 2.0.0;
|
||||
|
||||
include "../../circuits/multiplier.circom";
|
||||
|
||||
// Multiply 3 numbers
|
||||
component main = Multiplier(3);
|
||||
|
||||
@@ -2,5 +2,5 @@ pragma circom 2.0.0;
|
||||
|
||||
include "../../circuits/sudoku.circom";
|
||||
|
||||
// Circuit for 3^2 * 3^2 sudoku
|
||||
// Circuit for 3^2 x 3^2 sudoku
|
||||
component main {public[puzzle]} = Sudoku(3);
|
||||
|
||||
@@ -27,6 +27,5 @@ template Multiplier(N){
|
||||
comp[i+1].in1 <== comp[i].out;
|
||||
comp[i+1].in2 <== in[i+2];
|
||||
}
|
||||
|
||||
out <== comp[N-2].out;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"circom_tester": "^0.0.19",
|
||||
"circomlib": "^2.0.5",
|
||||
"circomlibjs": "^0.1.7",
|
||||
"ejs": "^3.1.9",
|
||||
"gts": "^3.1.1",
|
||||
"mocha": "^10.2.0",
|
||||
"snarkjs": "^0.5.0",
|
||||
|
||||
@@ -78,9 +78,6 @@ case $FUNC in
|
||||
verify)
|
||||
verify $CIRCUIT $INPUT
|
||||
;;
|
||||
keygen)
|
||||
compile $CIRCUIT && ptau $CIRCUIT $NUM_CONTRIBS
|
||||
;;
|
||||
*)
|
||||
echo "Usage:"
|
||||
echo " -f <function>"
|
||||
|
||||
@@ -5,13 +5,14 @@ compile() {
|
||||
local CIRCOM_IN=./circuits/main/$CIRCUIT.circom
|
||||
local CIRCOM_OUT=./build/$CIRCUIT
|
||||
|
||||
echo "Compiler: $CLIENV_COMPILER_ARGS"
|
||||
# generate the circuit main component
|
||||
node ./scripts/instantiate.js $CIRCUIT
|
||||
|
||||
# create build dir if not exists already
|
||||
mkdir -p $CIRCOM_OUT
|
||||
|
||||
# compile with circom
|
||||
circom $CIRCOM_IN -o $CIRCOM_OUT --r1cs --sym --wasm
|
||||
circom $CIRCOM_IN -o $CIRCOM_OUT --r1cs --wasm --sym
|
||||
|
||||
echo -e "${CLIENV_COLOR_LOG}Built artifacts under $CIRCOM_OUT${CLIENV_COLOR_RESET}"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
## Parse the symbols file and generate types for TypeScript
|
||||
## Parse the template circuit that you are using for your main component
|
||||
## and generate TypeScript interfaces for it
|
||||
## TODO: not sure i need this yet
|
||||
type() {
|
||||
echo -e "\n${CLIENV_COLOR_TITLE}=== Generating types ===${CLIENV_COLOR_RESET}"
|
||||
CIRCUIT=$1
|
||||
SYM=./build/$CIRCUIT/$CIRCUIT.sym
|
||||
set -e
|
||||
|
||||
# choose lines with 1 dot only (these are the signals in main file), extract their names
|
||||
cat $SYM | grep -E '^.+main[^.]*\.[^.]*$'
|
||||
echo -e "\n${CLIENV_COLOR_TITLE}=== Generating types ===${CLIENV_COLOR_RESET}"
|
||||
local CIRCUIT=$1
|
||||
local SYM=./build/$CIRCUIT/$CIRCUIT.sym
|
||||
local TMP=./scripts/utils.tmp.txt
|
||||
|
||||
# choose lines with 1 dot only (these are the signals of the main component), extract their names
|
||||
cat $SYM | awk -F '.' '{print $2}'
|
||||
|
||||
echo -e "\n${CLIENV_COLOR_LOG}Types generated!${CLIENV_COLOR_RESET}"
|
||||
}
|
||||
|
||||
# cat ./build/multiplier3/multiplier3.sym | awk -F '.' 'NF==2{print $2}'
|
||||
|
||||
17
scripts/instantiate.js
Normal file
17
scripts/instantiate.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const ejs = require('ejs');
|
||||
const {writeFileSync, readFileSync} = require('fs');
|
||||
const config = require('../circuit.config.cjs');
|
||||
|
||||
// read circuit from config
|
||||
const target = process.argv[2];
|
||||
if (!(target in config)) {
|
||||
throw new Error(`Target ${target} not found in config.`);
|
||||
}
|
||||
|
||||
// generate the main component code
|
||||
let circuit = ejs.render(readFileSync('./circuits/main/_template.circom').toString(), config[target]);
|
||||
|
||||
// output to file
|
||||
const targetPath = `./circuits/main/${target}.circom`;
|
||||
writeFileSync(targetPath, circuit);
|
||||
console.log(`Main component created at: ${targetPath}\n`);
|
||||
@@ -1,3 +0,0 @@
|
||||
for (let arg of process.argv.slice(2)) {
|
||||
console.log(arg);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {compileCircuit} from '../utils';
|
||||
import {Circuit} from '../utils/circuit';
|
||||
import {ProofTester} from '../utils/proofTester';
|
||||
import type {CircuitSignals, FullProof} from '../types/circuit';
|
||||
import type {WasmTester} from '../types/wasmTester';
|
||||
import {assert, expect} from 'chai';
|
||||
@@ -10,7 +10,7 @@ const CIRCUIT_NAME = 'multiplier3';
|
||||
describe(CIRCUIT_NAME, () => {
|
||||
const INPUT: CircuitSignals = input80;
|
||||
|
||||
describe('functionality', () => {
|
||||
describe('witness computation', () => {
|
||||
let circuit: WasmTester;
|
||||
|
||||
before(async () => {
|
||||
@@ -57,10 +57,10 @@ describe(CIRCUIT_NAME, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation', () => {
|
||||
describe('proof verification', () => {
|
||||
let fullProof: FullProof;
|
||||
|
||||
const circuit = new Circuit(CIRCUIT_NAME);
|
||||
const circuit = new ProofTester(CIRCUIT_NAME);
|
||||
|
||||
before(async () => {
|
||||
fullProof = await circuit.prove(INPUT);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {compileCircuit} from '../utils';
|
||||
import {Circuit} from '../utils/circuit';
|
||||
import type {CircuitSignals, FullProof} from '../types/circuit';
|
||||
import type {WasmTester} from '../types/wasmTester';
|
||||
import {assert, expect} from 'chai';
|
||||
@@ -10,7 +9,7 @@ const CIRCUIT_NAME = 'sudoku9';
|
||||
describe(CIRCUIT_NAME, () => {
|
||||
const INPUT: CircuitSignals = inputfoo;
|
||||
|
||||
describe('functionality', () => {
|
||||
describe('witness computation', () => {
|
||||
let circuit: WasmTester;
|
||||
|
||||
before(async () => {
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
export type CircuitSignals = {[signalName: string]: any};
|
||||
|
||||
/**
|
||||
* A witness is just an array of strings.
|
||||
* A witness is an array of bigints, corresponding to the values of each wire in
|
||||
* the evaluation of the circuit.
|
||||
*/
|
||||
export type WitnessType = bigint[];
|
||||
|
||||
|
||||
0
types/proofTester.ts
Normal file
0
types/proofTester.ts
Normal file
@@ -7,10 +7,15 @@ import {WitnessType, CircuitSignals} from './circuit';
|
||||
export type WasmTester = {
|
||||
/**
|
||||
* Assert that constraints are valid.
|
||||
* @param witness
|
||||
* @param witness witness
|
||||
*/
|
||||
checkConstraints: (witness: WitnessType) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Cleanup directory, should probably be called upon test completion
|
||||
*/
|
||||
release(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Assert the output of a given witness.
|
||||
* @param actualOut expected output signals
|
||||
@@ -32,7 +37,28 @@ export type WasmTester = {
|
||||
|
||||
/**
|
||||
* List of constraints, must call `loadConstraints` before
|
||||
* accessing this key.
|
||||
* accessing this key
|
||||
*/
|
||||
constraints: any[] | undefined;
|
||||
|
||||
/**
|
||||
* Loads the symbols in a dictionary at `this.symbols`
|
||||
* Symbols are stored under the .sym file
|
||||
* Each line has 4 comma-separated values:
|
||||
* 0: label index
|
||||
* 1: variable index
|
||||
* 2: component index
|
||||
*/
|
||||
loadSymbols(): Promise<void>;
|
||||
|
||||
/**
|
||||
* A dictionary of symbols
|
||||
*/
|
||||
symbols: object;
|
||||
|
||||
/**
|
||||
* @deprecated this is buggy right now
|
||||
* @param witness witness
|
||||
*/
|
||||
getDecoratedOutput(witness: WitnessType): Promise<string>;
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import {CircuitSignals, FullProof} from '../types/circuit';
|
||||
* A more extensive Circuit class, able to generate proofs & verify them.
|
||||
* Assumes that prover key and verifier key have been computed.
|
||||
*/
|
||||
export class Circuit {
|
||||
export class ProofTester {
|
||||
private readonly wasmPath: string;
|
||||
private readonly proverKeyPath: string;
|
||||
private readonly verificationKey: object;
|
||||
@@ -1083,6 +1083,13 @@ ejs@^3.1.6:
|
||||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
ejs@^3.1.9:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
|
||||
integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==
|
||||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
elliptic@6.5.4:
|
||||
version "6.5.4"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
|
||||
|
||||
Reference in New Issue
Block a user