many many commands

This commit is contained in:
erhant
2023-06-02 00:21:35 +03:00
parent 4d54425f83
commit 7e91faaf3e
24 changed files with 558 additions and 283 deletions

View File

@@ -1,3 +1,5 @@
> Work in progress...
<p align="center">
<h1 align="center">
Circomkit

View File

@@ -1,20 +0,0 @@
# proof system to be used, can be: groth16 | plonk | fflonk
CIRCOMKIT_PROOF_SYSTEM="groth16"
# name of the curve to be used: bn128 | bls12381 | goldilocks
CIRCOMKIT_ELLIPTIC_CURVE="bn128"
# solidity contract export path
CIRCOMKIT_SOLIDITY_PATH="./contracts"
# compiler args, can add --inspect and -c for example
CIRCOMKIT_COMPILER_ARGS="--r1cs --wasm --sym -l ./node_modules -p $CIRCOMKIT_ELLIPTIC_CURVE --inspect"
# solidity contract export path
CIRCOMKIT_VERSION="2.1.0"
# colors for swag terminal outputs
CIRCOMKIT_COLOR_TITLE='\033[0;34m' # blue
CIRCOMKIT_COLOR_LOG='\033[2;37m' # gray
CIRCOMKIT_COLOR_ERR='\033[0;31m' # red
CIRCOMKIT_COLOR_RESET='\033[0m' # reset color

View File

@@ -1,4 +1,4 @@
// auto-generated by instantiate.js
// auto-generated by circomkit
pragma circom 2.1.0;
include "../multiplier.circom";

View File

@@ -1,12 +1,28 @@
#!/bin/bash
# I couldn't bring myself to delete this file :(
cd "${0%/*}"/.. # get to project root
set -e # abort on error
# load CLI environment variables
source ./circomkit.env
### load CLI environment variables
# proof system to be used, can be: groth16 | plonk | fflonk
CIRCOMKIT_PROOF_SYSTEM="groth16"
# name of the curve to be used: bn128 | bls12381 | goldilocks
CIRCOMKIT_ELLIPTIC_CURVE="bn128"
# solidity contract export path
CIRCOMKIT_SOLIDITY_PATH="./contracts"
# compiler args, can add --inspect and -c for example
CIRCOMKIT_COMPILER_ARGS="--r1cs --wasm --sym -l ./node_modules -p $CIRCOMKIT_ELLIPTIC_CURVE --inspect"
# circom version
CIRCOMKIT_VERSION="2.1.0"
# colors for swag terminal outputs
CIRCOMKIT_COLOR_TITLE='\033[0;34m' # blue
CIRCOMKIT_COLOR_LOG='\033[2;37m' # gray
CIRCOMKIT_COLOR_ERR='\033[0;31m' # red
CIRCOMKIT_COLOR_RESET='\033[0m' # reset color
# check validness of variables
### check validness of variables
valid_proof_systems=("groth16" "plonk" "fflonk")
if [[ ! " ${valid_proof_systems[@]} " =~ " ${CIRCOMKIT_PROOF_SYSTEM} " ]]; then
echo -e "${CIRCOMKIT_COLOR_ERR}Invalid proof system: $CIRCOMKIT_PROOF_SYSTEM${CIRCOMKIT_COLOR_RESET}"
@@ -18,19 +34,248 @@ if [[ ! " ${valid_elliptic_curves[@]} " =~ " ${CIRCOMKIT_ELLIPTIC_CURVE} " ]]; t
exit 1
fi
# import functions
source ./scripts/functions/type.sh
source ./scripts/functions/setup.sh
source ./scripts/functions/compile.sh
source ./scripts/functions/clean.sh
source ./scripts/functions/contract.sh
source ./scripts/functions/calldata.sh
source ./scripts/functions/debug.sh
source ./scripts/functions/instantiate.sh
source ./scripts/functions/prove.sh
source ./scripts/functions/verify.sh
source ./scripts/functions/witness.sh
## Function definitions
# Generate types from a circuit template (incomplete)
type() {
set -e
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating types ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local SYM=./build/$CIRCUIT/$CIRCUIT.sym
# choose lines with 1 dot only (these are the signals of the main component), extract their names
local MAIN_SIGNALS=$(cat $SYM | awk -F '.' 'NF==2 {print $2}')
# get the unique signal names
local MAIN_SIGNAL_NAMES=$(echo "$MAIN_SIGNALS" | awk -F '[' '{print $1}' | uniq)
# get the last signal for each signal name
local SIGNALS=""
for SIGNAL in $MAIN_SIGNAL_NAMES; do
SIGNALS+="$(echo "$MAIN_SIGNALS" | grep $SIGNAL | tail -n 1) "
done
echo "$SIGNALS"
echo -e "\n${CIRCOMKIT_COLOR_LOG}Types generated!${CIRCOMKIT_COLOR_RESET}"
}
# Commence a circuit-specific setup
setup() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Circuit Setup ($CIRCOMKIT_PROOF_SYSTEM) ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1 # circuit name
local P1_PTAU=$2 # path to phase-1 ptau
local NUM_CONTRIBS=$3 # number of contributions (for groth16)
local CIRCUIT_DIR=./build/$CIRCUIT # circuit directory
local PROVER_KEY=$CIRCUIT_DIR/prover_key.zkey
local VERIFICATION_KEY=$CIRCUIT_DIR/verifier_key.json
# check if P1_PTAU exists
if [ ! -f "$P1_PTAU" ]; then
echo -e "PTAU file ${CIRCOMKIT_COLOR_ERR}${P1_PTAU} does not exist.${CIRCOMKIT_COLOR_RESET}"
exit 1
fi
if [[ "$CIRCOMKIT_PROOF_SYSTEM" == "groth16" ]]; then
local P2_PTAU=$CIRCUIT_DIR/phase2_final.ptau # phase-2 ptau
local CUR=000 # zkey id, initially 0
# if Groth16, circuit specific ceremony is needed
# start phase-2 ceremony (circuit specific)
echo -e "${CIRCOMKIT_COLOR_LOG}this may take a while...${CIRCOMKIT_COLOR_RESET}"
snarkjs powersoftau prepare phase2 $P1_PTAU $P2_PTAU -v
# generate a zkey that contains proving and verification keys, along with phase-2 contributions
snarkjs groth16 setup \
$CIRCUIT_DIR/$CIRCUIT.r1cs \
$P2_PTAU \
$CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey
# get rid of phase-2 ptau
rm $P2_PTAU
# make contributions (001, 002, ...)
for NEXT in $(seq -f "%03g" 1 ${NUM_CONTRIBS})
do
echo "Making Phase-2 Contribution: ${NEXT}"
snarkjs zkey contribute \
$CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey \
$CIRCUIT_DIR/${CIRCUIT}_${NEXT}.zkey -v
rm $CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey
CUR=$NEXT
done
echo "Phase 2 Complete."
# rename key to the prover key
mv $CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey $PROVER_KEY
else
# otherwise, we can use that phase-1 ptau alone
snarkjs $CIRCOMKIT_PROOF_SYSTEM setup $CIRCUIT_DIR/$CIRCUIT.r1cs \
$P1_PTAU \
$PROVER_KEY
fi
# export
snarkjs zkey export verificationkey $PROVER_KEY $VERIFICATION_KEY
echo -e "${CIRCOMKIT_COLOR_LOG}Generated keys\n\tProver key: $PROVER_KEY\n\tVerification key: $VERIFICATION_KEY${CIRCOMKIT_COLOR_RESET}"
}
# Compile the circuit, outputting R1CS and JS files
compile() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Compiling the circuit ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCOM_IN=./circuits/main/$CIRCUIT.circom
local CIRCOM_OUT=./build/$CIRCUIT
# create build dir if not exists already
mkdir -p $CIRCOM_OUT
# compile with circom
echo "circom $CIRCOM_IN -o $CIRCOM_OUT $CIRCOMKIT_COMPILER_ARGS"
circom $CIRCOM_IN -o $CIRCOM_OUT $CIRCOMKIT_COMPILER_ARGS
echo -e "${CIRCOMKIT_COLOR_LOG}Built artifacts under $CIRCOM_OUT${CIRCOMKIT_COLOR_RESET}"
}
# Clean build files
clean() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Cleaning artifacts ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCUIT_DIR=./build/$CIRCUIT
local TARGET=./circuits/main/$CIRCUIT.circom
rm -rf $CIRCUIT_DIR
rm -f $TARGET
echo -e "${CIRCOMKIT_COLOR_LOG}Deleted $CIRCUIT_DIR and $TARGET${CIRCOMKIT_COLOR_RESET}"
}
# Exports a solidity contract for the verifier
contract() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating Solidity verifier ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs zkey export solidityverifier \
$CIRCUIT_DIR/prover_key.zkey \
$CIRCUIT_DIR/verifier.sol
echo -e "${CIRCOMKIT_COLOR_LOG}Contract created at $CIRCUIT_DIR/verifier.sol!${CIRCOMKIT_COLOR_RESET}"
}
# Exports a solidity contract for the verifier
calldata() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Exporting calldata ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs zkey export soliditycalldata \
$CIRCUIT_DIR/$INPUT/public.json \
$CIRCUIT_DIR/$INPUT/proof.json
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}
# Debug a witness
debug() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Debugging witness ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
local OUTPUT_DIR=./build/$CIRCUIT/$INPUT # directory for proof & public signals
local INPUT_DIR=./inputs/$CIRCUIT # directory for inputs
snarkjs wtns debug \
$CIRCUIT_DIR/${CIRCUIT}_js/$CIRCUIT.wasm \
$INPUT_DIR/$INPUT.json \
$OUTPUT_DIR/witness.wtns \
$CIRCUIT_DIR/$CIRCUIT.sym
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}
# Instantiate the main component
instantiate() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Creating main component ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
# parse json for the circuit, trim first and last lines, and then remove all whitespace
local MATCH=$(sed -n "/ *\"${CIRCUIT}\": *{/, /^ *}[, ]$/p" ./circuits.json | sed '1d;$d' | tr -d "[:space:]")
if [ -z "$MATCH" ]
then
echo -e "${CIRCOMKIT_COLOR_ERR}No such circuit found!${CIRCOMKIT_COLOR_RESET}"
exit
fi
# create JSON object
local JSON_IN="{\"version\":\"${CIRCOMKIT_VERSION}\",$MATCH}"
# generate the circuit main component
local OUTDIR="./circuits/main/$CIRCUIT.circom"
npx ejs ./ejs/template.circom -i $JSON_IN -o $OUTDIR
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}
# Generate a proof
prove() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating proof ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
local OUTPUT_DIR=$CIRCUIT_DIR/$INPUT
snarkjs $CIRCOMKIT_PROOF_SYSTEM prove \
$CIRCUIT_DIR/prover_key.zkey \
$OUTPUT_DIR/witness.wtns \
$OUTPUT_DIR/proof.json \
$OUTPUT_DIR/public.json
echo -e "${CIRCOMKIT_COLOR_LOG}Generated under $OUTPUT_DIR${CIRCOMKIT_COLOR_RESET}"
}
# Verify a witness & proof
verify() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Verifying proof ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs $CIRCOMKIT_PROOF_SYSTEM verify \
$CIRCUIT_DIR/verifier_key.json \
$CIRCUIT_DIR/$INPUT/public.json \
$CIRCUIT_DIR/$INPUT/proof.json
echo -e "${CIRCOMKIT_COLOR_LOG}Verification complete.${CIRCOMKIT_COLOR_RESET}"
}
# Calculates the witness for the given circuit and input
witness() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Computing witness ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local JS_DIR=./build/$CIRCUIT/${CIRCUIT}_js # JS files for the circuit
local OUTPUT_DIR=./build/$CIRCUIT/$INPUT # directory for proof & public signals
local INPUT_DIR=./inputs/$CIRCUIT # directory for inputs
local WITNESS=$OUTPUT_DIR/witness.wtns # witness output
mkdir -p $OUTPUT_DIR
node $JS_DIR/generate_witness.js \
$JS_DIR/$CIRCUIT.wasm \
$INPUT_DIR/$INPUT.json \
$WITNESS
echo -e "${CIRCOMKIT_COLOR_LOG}Generated\n\tWitness: $WITNESS${CIRCOMKIT_COLOR_RESET}"
}
## CLI
# default values
NUM_CONTRIBS=1
INPUT="default"

View File

@@ -1,13 +0,0 @@
## Exports a solidity contract for the verifier
calldata() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Exporting calldata ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs zkey export soliditycalldata \
$CIRCUIT_DIR/$INPUT/public.json \
$CIRCUIT_DIR/$INPUT/proof.json
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,12 +0,0 @@
## Clean build files
clean() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Cleaning artifacts ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCUIT_DIR=./build/$CIRCUIT
local TARGET=./circuits/main/$CIRCUIT.circom
rm -rf $CIRCUIT_DIR
rm -f $TARGET
echo -e "${CIRCOMKIT_COLOR_LOG}Deleted $CIRCUIT_DIR and $TARGET${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,16 +0,0 @@
## Compile the circuit, outputting R1CS and JS files
compile() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Compiling the circuit ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCOM_IN=./circuits/main/$CIRCUIT.circom
local CIRCOM_OUT=./build/$CIRCUIT
# create build dir if not exists already
mkdir -p $CIRCOM_OUT
# compile with circom
echo "circom $CIRCOM_IN -o $CIRCOM_OUT $CIRCOMKIT_COMPILER_ARGS"
circom $CIRCOM_IN -o $CIRCOM_OUT $CIRCOMKIT_COMPILER_ARGS
echo -e "${CIRCOMKIT_COLOR_LOG}Built artifacts under $CIRCOM_OUT${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,12 +0,0 @@
## Exports a solidity contract for the verifier
contract() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating Solidity verifier ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs zkey export solidityverifier \
$CIRCUIT_DIR/prover_key.zkey \
$CIRCUIT_DIR/verifier.sol
echo -e "${CIRCOMKIT_COLOR_LOG}Contract created at $CIRCUIT_DIR/verifier.sol!${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,17 +0,0 @@
## Debug a witness
debug() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Debugging witness ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
local OUTPUT_DIR=./build/$CIRCUIT/$INPUT # directory for proof & public signals
local INPUT_DIR=./inputs/$CIRCUIT # directory for inputs
snarkjs wtns debug \
$CIRCUIT_DIR/${CIRCUIT}_js/$CIRCUIT.wasm \
$INPUT_DIR/$INPUT.json \
$OUTPUT_DIR/witness.wtns \
$CIRCUIT_DIR/$CIRCUIT.sym
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,22 +0,0 @@
## Instantiate the main component
instantiate() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Creating main component ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
# parse json for the circuit, trim first and last lines, and then remove all whitespace
local MATCH=$(sed -n "/ *\"${CIRCUIT}\": *{/, /^ *}[, ]$/p" ./circuits.json | sed '1d;$d' | tr -d "[:space:]")
if [ -z "$MATCH" ]
then
echo -e "${CIRCOMKIT_COLOR_ERR}No such circuit found!${CIRCOMKIT_COLOR_RESET}"
exit
fi
# create JSON object
local JSON_IN="{\"version\":\"${CIRCOMKIT_VERSION}\",$MATCH}"
# generate the circuit main component
local OUTDIR="./circuits/main/$CIRCUIT.circom"
npx ejs ./ejs/template.circom -i $JSON_IN -o $OUTDIR
echo -e "${CIRCOMKIT_COLOR_LOG}Done!${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,16 +0,0 @@
## Generate a proof
prove() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating proof ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
local OUTPUT_DIR=$CIRCUIT_DIR/$INPUT
snarkjs $CIRCOMKIT_PROOF_SYSTEM prove \
$CIRCUIT_DIR/prover_key.zkey \
$OUTPUT_DIR/witness.wtns \
$OUTPUT_DIR/proof.json \
$OUTPUT_DIR/public.json
echo -e "${CIRCOMKIT_COLOR_LOG}Generated under $OUTPUT_DIR${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,62 +0,0 @@
## Commence a circuit-specific setup
setup() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Circuit Setup ($CIRCOMKIT_PROOF_SYSTEM) ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1 # circuit name
local P1_PTAU=$2 # path to phase-1 ptau
local NUM_CONTRIBS=$3 # number of contributions (for groth16)
local CIRCUIT_DIR=./build/$CIRCUIT # circuit directory
local PROVER_KEY=$CIRCUIT_DIR/prover_key.zkey
local VERIFICATION_KEY=$CIRCUIT_DIR/verification_key.json
# check if P1_PTAU exists
if [ ! -f "$P1_PTAU" ]; then
echo -e "PTAU file ${CIRCOMKIT_COLOR_ERR}${P1_PTAU} does not exist.${CIRCOMKIT_COLOR_RESET}"
exit 1
fi
if [[ "$CIRCOMKIT_PROOF_SYSTEM" == "groth16" ]]; then
local P2_PTAU=$CIRCUIT_DIR/phase2_final.ptau # phase-2 ptau
local CUR=000 # zkey id, initially 0
# if Groth16, circuit specific ceremony is needed
# start phase-2 ceremony (circuit specific)
echo -e "${CIRCOMKIT_COLOR_LOG}this may take a while...${CIRCOMKIT_COLOR_RESET}"
snarkjs powersoftau prepare phase2 $P1_PTAU $P2_PTAU -v
# generate a zkey that contains proving and verification keys, along with phase-2 contributions
snarkjs groth16 setup \
$CIRCUIT_DIR/$CIRCUIT.r1cs \
$P2_PTAU \
$CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey
# get rid of phase-2 ptau
rm $P2_PTAU
# make contributions (001, 002, ...)
for NEXT in $(seq -f "%03g" 1 ${NUM_CONTRIBS})
do
echo "Making Phase-2 Contribution: ${NEXT}"
snarkjs zkey contribute \
$CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey \
$CIRCUIT_DIR/${CIRCUIT}_${NEXT}.zkey -v
rm $CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey
CUR=$NEXT
done
echo "Phase 2 Complete."
# rename key to the prover key
mv $CIRCUIT_DIR/${CIRCUIT}_${CUR}.zkey $PROVER_KEY
else
# otherwise, we can use that phase-1 ptau alone
snarkjs $CIRCOMKIT_PROOF_SYSTEM setup $CIRCUIT_DIR/$CIRCUIT.r1cs \
$P1_PTAU \
$PROVER_KEY
fi
# export
snarkjs zkey export verificationkey $PROVER_KEY $VERIFICATION_KEY
echo -e "${CIRCOMKIT_COLOR_LOG}Generated keys\n\tProver key: $PROVER_KEY\n\tVerification key: $VERIFICATION_KEY${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,24 +0,0 @@
## Parse the template circuit that you are using for your main component
## and generate TypeScript interfaces for it
type() {
set -e
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Generating types ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local SYM=./build/$CIRCUIT/$CIRCUIT.sym
# choose lines with 1 dot only (these are the signals of the main component), extract their names
local MAIN_SIGNALS=$(cat $SYM | awk -F '.' 'NF==2 {print $2}')
# get the unique signal names
local MAIN_SIGNAL_NAMES=$(echo "$MAIN_SIGNALS" | awk -F '[' '{print $1}' | uniq)
# get the last signal for each signal name
local SIGNALS=""
for SIGNAL in $MAIN_SIGNAL_NAMES; do
SIGNALS+="$(echo "$MAIN_SIGNALS" | grep $SIGNAL | tail -n 1) "
done
echo "$SIGNALS"
echo -e "\n${CIRCOMKIT_COLOR_LOG}Types generated!${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,14 +0,0 @@
## Verify a witness & proof
verify() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Verifying proof ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local CIRCUIT_DIR=./build/$CIRCUIT
snarkjs $CIRCOMKIT_PROOF_SYSTEM verify \
$CIRCUIT_DIR/verification_key.json \
$CIRCUIT_DIR/$INPUT/public.json \
$CIRCUIT_DIR/$INPUT/proof.json
echo -e "${CIRCOMKIT_COLOR_LOG}Verification complete.${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,19 +0,0 @@
## Calculates the witness for the given circuit and input
witness() {
echo -e "\n${CIRCOMKIT_COLOR_TITLE}=== Computing witness ===${CIRCOMKIT_COLOR_RESET}"
local CIRCUIT=$1
local INPUT=$2
local JS_DIR=./build/$CIRCUIT/${CIRCUIT}_js # JS files for the circuit
local OUTPUT_DIR=./build/$CIRCUIT/$INPUT # directory for proof & public signals
local INPUT_DIR=./inputs/$CIRCUIT # directory for inputs
local WITNESS=$OUTPUT_DIR/witness.wtns # witness output
mkdir -p $OUTPUT_DIR
node $JS_DIR/generate_witness.js \
$JS_DIR/$CIRCUIT.wasm \
$INPUT_DIR/$INPUT.json \
$WITNESS
echo -e "${CIRCOMKIT_COLOR_LOG}Generated\n\tWitness: $WITNESS${CIRCOMKIT_COLOR_RESET}"
}

View File

@@ -1,3 +1,30 @@
#!/usr/bin/env node
console.log('todo todoo');
import {Circomkit} from '../cli/';
async function main() {
const cli = new Circomkit();
// parse commands & arguments
// await cli.prove('multiplier_3', 'default');
// await cli.verify('multiplier_3', 'default');
await cli.witness('multiplier_3', 'default');
// cli.clean('multiplier_3');
// cli.instantiate('multiplier_3');
// await cli.compile('multiplier_3');
/**
* We have to exit forcefully, as SnarkJS CLI does
* too. In their code, each function returns a code,
* with the succesfull ones returning 0. If an error is
* thrown, that error is logged and process is exited
* with error code 1.
*
* See line 312 in snarkjs/cli.js
*/
// eslint-disable-next-line no-process-exit
process.exit(0);
}
main();

68
src/cli/config.ts Normal file
View File

@@ -0,0 +1,68 @@
type ColorType = `\x1b[${number}m` | `\x1b[${number};${number}m`;
type VersionType = `${number}.${number}.${number}`;
export type CircomkitConfig = {
/** Proof system to be used. */
proofSystem: 'groth16' | 'plonk';
/** Curve to be used, which defines the underlying prime field. */
curve: 'bn128' | 'bls12381' | 'goldilocks';
/** Version number for main components. */
version: VersionType;
/** Hide Circomkit logs */
silent: boolean;
/** Which files to output. */
outputs: {
/** Output R1CS file. */
r1cs: boolean;
/** Output symbol file. */
sym: boolean;
/** Output WASM circuit. */
wasm: boolean;
/** Output witness generator in C. */
c: boolean;
wat: boolean;
json: boolean;
};
colors: {
title: ColorType; // blue
log: ColorType; // gray
error: ColorType; // red
};
/** Do an additional check over the produced constraints. */
inspect: boolean;
/** Show Circom logs during compilation. */
verbose: boolean;
/**
* Optimization level.
* - `0`: No simplification is applied.
* - `1`: Only applies `var` to `var` and `var` to `constant` simplification.
* - `2`: Full constraint simplification.
*/
optimization: 0 | 1 | 2;
/** Libraries to be linked to search path. */
libraries: string[];
};
export const defaultConfig: Readonly<CircomkitConfig> = {
proofSystem: 'groth16',
curve: 'bn128',
version: '2.1.0',
silent: false,
outputs: {
r1cs: true,
sym: true,
wasm: true,
c: false,
wat: false,
json: false,
},
colors: {
title: '\x1b[0;34m', // blue
log: '\x1b[2;37m', // gray
error: '\x1b[0;31m', // red
},
inspect: true,
optimization: 0,
verbose: false,
libraries: ['./node_modules'],
};

193
src/cli/index.ts Normal file
View File

@@ -0,0 +1,193 @@
import * as snarkjs from 'snarkjs';
import {wasm as wasm_tester} from 'circom_tester';
import {CircomkitConfig, defaultConfig} from './config';
import {writeFileSync, readFileSync} from 'fs';
import {mkdirSync, rmSync} from 'fs';
import instantiate from '../utils/instantiate';
import {CircuitConfig} from '../types/circuit';
/**
* Circomkit is an opinionated wrapper around a few
* [Snarkjs](../../node_modules/snarkjs/main.js) functions.
*/
export class Circomkit {
readonly config: CircomkitConfig;
private readonly resetColor = '\x1b[0m';
constructor() {
this.config = defaultConfig;
// TODO read config from user workspace
}
/** Colorful logging based on config. */
private log(message: string, type: keyof CircomkitConfig['colors'] = 'log') {
console.log(`${this.config.colors[type]}${message}${this.resetColor}`);
}
/**
* Computes a path that requires a circuit name.
* @param circuit circuit name
* @param type path type
* @returns path
*/
private path(circuit: string, type: 'target' | 'sym' | 'pkey' | 'vkey' | 'wasm' | 'sol' | 'dir'): string {
const dir = `./build/${circuit}`;
switch (type) {
case 'dir':
return dir;
case 'target':
return `./circuits/main/${circuit}.circom`;
case 'pkey':
return `${dir}/prover_key.zkey`;
case 'vkey':
return `${dir}/verifier_key.json`;
case 'sym':
return `${dir}/symbols.sym`;
case 'sol':
return `${dir}/Verifier.sol`;
case 'wasm':
return `${dir}/${circuit}_js/${circuit}.wasm`;
default:
throw new Error('Invalid type: ' + type);
}
}
/**
* Computes a path that requires a circuit and an input name.
* @param circuit circuit name
* @param input input name
* @param type path type
* @returns path
*/
private path2(circuit: string, input: string, type: 'pubs' | 'proof' | 'wtns' | 'in' | 'dir'): string {
const dir = `./build/${circuit}/${input}`;
switch (type) {
case 'dir':
return dir;
case 'pubs':
return `${dir}/public.json`;
case 'proof':
return `${dir}/proof.json`;
case 'wtns':
return `${dir}/witness.wtns`;
case 'in':
return `./inputs/${circuit}/${input}.json`;
default:
throw new Error('Invalid type: ' + type);
}
}
/** Clean build files */
clean(circuit: string) {
this.log('=== Cleaning artifacts ===', 'title');
rmSync(this.path(circuit, 'dir'), {recursive: true, force: true});
rmSync(this.path(circuit, 'target'));
this.log('All done!');
}
/** Compile the circuit */
async compile(circuit: string) {
this.instantiate(circuit);
this.log('=== Compiling the circuit ===', 'title');
const outDir = this.path(circuit, 'dir');
await wasm_tester(this.path(circuit, 'target'), {
output: outDir,
});
this.log('Built at: ' + outDir);
}
/** Exports a solidity contract for the verifier */
async contract(circuit: string) {
this.log('=== Generating verifier contract ===', 'title');
const pkey = this.path(circuit, 'pkey');
const verifierCode = await snarkjs.zKey.exportSolidityVerifier(pkey, {
groth16: './node_modules/snarkjs/templates/verifier_groth16.sol.ejs',
plonk: './node_modules/snarkjs/templates/verifier_plonk.sol.ejs',
});
// TODO: hangs here???
this.log(verifierCode);
// output to file
const sol = this.path(circuit, 'sol');
this.log('Contract created at: ' + sol);
}
/** Instantiate the main component */
instantiate(circuit: string) {
this.log('=== Creating main component ===', 'title');
const circuits = JSON.parse(readFileSync('./circuits.json', 'utf-8'));
if (!(circuit in circuits)) {
throw new Error('No such circuit in circuits.json');
}
const circuitConfig = circuits[circuit] as CircuitConfig;
instantiate(circuit, {
...circuitConfig,
dir: 'main',
version: this.config.version,
});
this.log('Done!');
}
/** Generate a proof */
async prove(circuit: string, input: string) {
this.log('=== Generating proof ===', 'title');
const jsonInput = JSON.parse(readFileSync(this.path2(circuit, input, 'in'), 'utf-8'));
const fullProof = await snarkjs[this.config.proofSystem].fullProve(
jsonInput,
this.path(circuit, 'wasm'),
this.path(circuit, 'pkey')
);
const dir = this.path2(circuit, input, 'dir');
mkdirSync(dir, {recursive: true});
writeFileSync(this.path2(circuit, input, 'pubs'), JSON.stringify(fullProof.publicSignals, undefined, 2));
writeFileSync(this.path2(circuit, input, 'proof'), JSON.stringify(fullProof.proof, undefined, 2));
this.log('Generated under: ' + dir);
}
/** Commence a circuit-specific setup */
setup() {
throw new Error('Not implemented.');
}
/**
* Parse the template circuit that you are using for your main component
* and generate TypeScript interfaces for it
*
* @deprecated work in progress, do not use
*/
type() {
throw new Error('Not implemented.');
}
/** Verify a proof for some public signals. */
async verify(circuit: string, input: string) {
this.log('=== Verifying proof ===', 'title');
const vkey = JSON.parse(readFileSync(this.path(circuit, 'vkey'), 'utf-8'));
const pubs = JSON.parse(readFileSync(this.path2(circuit, input, 'pubs'), 'utf-8'));
const proof = JSON.parse(readFileSync(this.path2(circuit, input, 'proof'), 'utf-8'));
const result = await snarkjs[this.config.proofSystem].verify(vkey, pubs, proof);
if (result) {
this.log('Verification successful.', 'log');
} else {
this.log('Verification failed!', 'error');
}
}
/** Calculates the witness for the given circuit and input. */
async witness(circuit: string, input: string) {
this.log('=== Calculating witness ===', 'title');
const jsonInput = JSON.parse(readFileSync(this.path2(circuit, input, 'in'), 'utf-8'));
const dir = this.path2(circuit, input, 'dir');
mkdirSync(dir, {recursive: true});
await snarkjs.wtns.calculate(jsonInput, this.path(circuit, 'wasm'), this.path2(circuit, input, 'wtns'));
this.log('Created under: ' + dir);
}
}

1
src/types/circom_tester.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module 'circom_tester';

View File

@@ -58,8 +58,10 @@ export type CircuitConfig = {
file: string;
/** The template name to instantiate */
template: string;
/** Directory to read the file, defaults to `test` */
/** Directory to instantiate at */
dir?: string;
/** Target version */
version?: `${number}.${number}.${number}`;
/** An array of public input signal names, defaults to `[]` */
pubs?: string[];
/** An array of template parameters, defaults to `[]` */

1
src/types/snarkjs.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module 'snarkjs';

View File

@@ -2,8 +2,7 @@ import type {CircuitConfig} from '../types/circuit';
import ejs from 'ejs';
import {writeFileSync, existsSync, mkdirSync} from 'fs';
const EJS_TEMPLATE = `
// auto-generated by circomkit
const EJS_TEMPLATE = `// auto-generated by circomkit
pragma circom <%= typeof version == "undefined" ? "2.0.0" : version %>;
include "../<%= file %>.circom";

View File

@@ -6,8 +6,6 @@
"strict": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"allowJs": true,
"checkJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",

View File

@@ -1,14 +0,0 @@
{
"extends": "./tsconfig.base.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"module": "esnext",
"target": "es2019",
"removeComments": false,
"declaration": true,
"declarationMap": true,
"declarationDir": "./dist/types",
"outDir": "./dist/types",
"emitDeclarationOnly": true
}
}