mirror of
https://github.com/erhant/circomkit.git
synced 2026-05-05 03:00:37 -04:00
many many commands
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
> Work in progress...
|
||||
|
||||
<p align="center">
|
||||
<h1 align="center">
|
||||
Circomkit
|
||||
|
||||
@@ -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
|
||||
@@ -1,4 +1,4 @@
|
||||
// auto-generated by instantiate.js
|
||||
// auto-generated by circomkit
|
||||
pragma circom 2.1.0;
|
||||
|
||||
include "../multiplier.circom";
|
||||
|
||||
275
scripts/cli.sh
275
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"
|
||||
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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
68
src/cli/config.ts
Normal 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
193
src/cli/index.ts
Normal 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
1
src/types/circom_tester.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'circom_tester';
|
||||
@@ -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
1
src/types/snarkjs.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'snarkjs';
|
||||
@@ -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";
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user