diff --git a/README.md b/README.md
index 506de0c..ca7ad60 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+> Work in progress...
+
Circomkit
diff --git a/circomkit.env b/circomkit.env
deleted file mode 100644
index 85fe643..0000000
--- a/circomkit.env
+++ /dev/null
@@ -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
diff --git a/circuits/main/multiplier_3.circom b/circuits/main/multiplier_3.circom
index 8b5618b..87c6dc4 100644
--- a/circuits/main/multiplier_3.circom
+++ b/circuits/main/multiplier_3.circom
@@ -1,4 +1,4 @@
-// auto-generated by instantiate.js
+// auto-generated by circomkit
pragma circom 2.1.0;
include "../multiplier.circom";
diff --git a/scripts/cli.sh b/scripts/cli.sh
index 4b000fd..77e1794 100755
--- a/scripts/cli.sh
+++ b/scripts/cli.sh
@@ -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"
diff --git a/scripts/functions/calldata.sh b/scripts/functions/calldata.sh
deleted file mode 100755
index 530cc4f..0000000
--- a/scripts/functions/calldata.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/clean.sh b/scripts/functions/clean.sh
deleted file mode 100755
index bf4afcf..0000000
--- a/scripts/functions/clean.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/compile.sh b/scripts/functions/compile.sh
deleted file mode 100755
index 6d6163e..0000000
--- a/scripts/functions/compile.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/contract.sh b/scripts/functions/contract.sh
deleted file mode 100755
index 8d94161..0000000
--- a/scripts/functions/contract.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/debug.sh b/scripts/functions/debug.sh
deleted file mode 100644
index a525411..0000000
--- a/scripts/functions/debug.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/instantiate.sh b/scripts/functions/instantiate.sh
deleted file mode 100755
index d848a8f..0000000
--- a/scripts/functions/instantiate.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/prove.sh b/scripts/functions/prove.sh
deleted file mode 100755
index 386651b..0000000
--- a/scripts/functions/prove.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/setup.sh b/scripts/functions/setup.sh
deleted file mode 100755
index ebfde16..0000000
--- a/scripts/functions/setup.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/type.sh b/scripts/functions/type.sh
deleted file mode 100755
index c1d6af1..0000000
--- a/scripts/functions/type.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/verify.sh b/scripts/functions/verify.sh
deleted file mode 100755
index 78001a6..0000000
--- a/scripts/functions/verify.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/scripts/functions/witness.sh b/scripts/functions/witness.sh
deleted file mode 100755
index 10af6a1..0000000
--- a/scripts/functions/witness.sh
+++ /dev/null
@@ -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}"
-}
diff --git a/src/bin/index.ts b/src/bin/index.ts
index 401205e..e36754b 100644
--- a/src/bin/index.ts
+++ b/src/bin/index.ts
@@ -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();
diff --git a/src/cli/config.ts b/src/cli/config.ts
new file mode 100644
index 0000000..62224da
--- /dev/null
+++ b/src/cli/config.ts
@@ -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 = {
+ 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'],
+};
diff --git a/src/cli/index.ts b/src/cli/index.ts
new file mode 100644
index 0000000..738f89d
--- /dev/null
+++ b/src/cli/index.ts
@@ -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);
+ }
+}
diff --git a/src/types/circom_tester.d.ts b/src/types/circom_tester.d.ts
new file mode 100644
index 0000000..834fca3
--- /dev/null
+++ b/src/types/circom_tester.d.ts
@@ -0,0 +1 @@
+declare module 'circom_tester';
diff --git a/src/types/circuit.ts b/src/types/circuit.ts
index 46afff0..a88877c 100644
--- a/src/types/circuit.ts
+++ b/src/types/circuit.ts
@@ -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 `[]` */
diff --git a/src/types/snarkjs.d.ts b/src/types/snarkjs.d.ts
new file mode 100644
index 0000000..48d4b0c
--- /dev/null
+++ b/src/types/snarkjs.d.ts
@@ -0,0 +1 @@
+declare module 'snarkjs';
diff --git a/src/utils/instantiate.ts b/src/utils/instantiate.ts
index 1d35a6d..54bed78 100644
--- a/src/utils/instantiate.ts
+++ b/src/utils/instantiate.ts
@@ -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";
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 65920cf..1ea7f64 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -6,8 +6,6 @@
"strict": true,
"resolveJsonModule": true,
"esModuleInterop": true,
- "allowJs": true,
- "checkJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
diff --git a/tsconfig.type.json b/tsconfig.type.json
deleted file mode 100644
index 8ba7e22..0000000
--- a/tsconfig.type.json
+++ /dev/null
@@ -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
- }
-}