erhant / circomkit Goto Github PK
View Code? Open in Web Editor NEWA testing & development environment for Circom.
Home Page: https://www.npmjs.com/package/circomkit
License: MIT License
A testing & development environment for Circom.
Home Page: https://www.npmjs.com/package/circomkit
License: MIT License
First detected here https://github.com/erhant/circomkit/actions/runs/7034811494/job/19143717941
Discussion following #33, it should make sense to allow circuit-specific source directory that overrides that of Circomkit's config.
The issue is found: for fflonk
snarkjs takes the parameters (pubs, proof)
instead of (proof, pubs)
like it does for the others.
Anyways, Im rewriting that whole part so that we can take Solidity-compatible exports too.
snarkjs.plonk.setup
snarkjs.info
This command will list the built circuits under the configured build folder. It's just a quality-of-life command to see which circuits are built. It could even go beyond and see which inputs are exported, and which protocols are outputted for each.
Note that doing this will probably allow us to input more compiler arguments.
Just found the first version of Circomkit, written in bash entirely:
#!/bin/bash
cd "${0%/*}"/.. # get to project root
set -e # abort on error
### 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
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}"
exit 1
fi
valid_elliptic_curves=("bn128" "bls12381" "goldilocks")
if [[ ! " ${valid_elliptic_curves[@]} " =~ " ${CIRCOMKIT_ELLIPTIC_CURVE} " ]]; then
echo -e "${CIRCOMKIT_COLOR_ERR}Invalid elliptic curve: $CIRCOMKIT_ELLIPTIC_CURVE${CIRCOMKIT_COLOR_RESET}"
exit 1
fi
## 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"
P1_PTAU="./ptau/powersOfTau28_hez_final_12.ptau"
# get arguments
while getopts "f:c:n:i:p:d:" opt; do
case $opt in
# function to call
f)
FUNC="$OPTARG"
;;
# circuit name
c)
CIRCUIT="$OPTARG"
;;
# number of contributions
n)
NUM_CONTRIBS="$OPTARG"
;;
# input name
i)
INPUT="$OPTARG"
;;
# phase-1 ptau path
p)
P1_PTAU="$OPTARG"
;;
# invalid option
\?)
echo "Invalid option -$OPTARG" >&2
exit 1
;;
esac
case $OPTARG in
-*) echo "Option $opt needs a valid argument"
exit 1
;;
esac
done
# parse circuit & input paths via basename
# TODO, maybe not needed
CIRCUIT=$(basename $CIRCUIT .circom)
INPUT=$(basename $INPUT .json)
case $FUNC in
clean)
clean $CIRCUIT
;;
contract)
contract $CIRCUIT
;;
calldata)
calldata $CIRCUIT $INPUT
;;
compile)
instantiate $CIRCUIT && compile $CIRCUIT
;;
debug)
debug $CIRCUIT $INPUT
;;
instantiate)
instantiate $CIRCUIT
;;
type)
type $CIRCUIT
;;
setup)
setup $CIRCUIT $P1_PTAU $NUM_CONTRIBS
;;
keygen)
compile $CIRCUIT && setup $CIRCUIT $P1_PTAU $NUM_CONTRIBS
;;
prove)
witness $CIRCUIT $INPUT && prove $CIRCUIT $INPUT
;;
witness)
witness $CIRCUIT $INPUT
;;
verify)
verify $CIRCUIT $INPUT
;;
*)
echo "Usage:"
echo " -f <function>"
echo " clean Cleans the build artifacts"
echo " contract Export Solidity verifier"
echo " calldata Export Solidity calldata for verification"
echo " compile Compile the circuit"
echo " instantiate Instantiate the main component"
echo " type Generate types for TypeScript"
echo " setup Phase-2 setup for the circuit"
echo " witness Generate witness from an input"
echo " prove Prove an input"
echo " verify Verify a proof & public signals"
echo " keygen Shorthand for compile & setup"
echo " -c <circuit-name>"
echo " -n <num-contributions> (default: $NUM_CONTRIBS)"
echo " -i <input-name>"
echo " -p <phase1-ptau-path>"
;;
esac
Need unit-tests for Circomkit functions.
Also check: how to install Circom in a Github workflow?
Multiple target is buggy with generating types, but can be done within a script with using Parcel API
With @types/snarkjs
the snarkjs functions are typed as well, i.e. the proof objects.
Currently, when compiling a circuit, it is not possible to generate the C witness calculator files. By adding a optional config entry, we can decide whether to generate those files or not.
Would you be happy to have this feature in?
ps. great work with circomkit
, we are just now integrating it in maci, and having this option would make it much easier for us to integrate it in our workflows.
There may be some issues with these types, will check https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/snarkjs
I was wondering if it's completely necessary to perform this step? https://github.com/erhant/circomkit/blob/main/src/circomkit.ts#L417
The ptau(s) that circomkit downloads are from the Hermez phase1 ceremony, which are ready to be used in a phase2 ceremony.
ps. the base url of the ptau files should be updated just to be safe - seems like they have moved to google storage
EDIT: issue breakdown
Inspired from https://hammster.vercel.app/
It seems to break the test, didnt happen with groth16
but happened with plonk
and fflonk
.
It should allow any combination, but it does not.
For example, groth16_proof.json
& groth16_public.json
and such. The reason is, when you change protocols the previous results will be overwritten due to them using the same path.
Warning
This would be a breaking change due to pathing.
Currently, compile
https://github.com/erhant/circomkit/blob/main/src/circomkit.ts#L201 uses instantiate
https://github.com/erhant/circomkit/blob/main/src/circomkit.ts#L204 without CircuitConfig
provided so it is always looking for circuits.json
for the configuration. That makes harder to use it for more than 1 circuit.
For larger circuits, otherwise recompiling everytime is not cool.
Try for a circuit with many signals (like >10)
Mocha currently exists the test forcefully. We may not need to do so, related to the issue: iden3/snarkjs#152
For example, we can see how many signals are expected there.
Circom v2.1.8 supports: bn128, bls12381, goldilocks, grumpkin, pallas, vesta, secq256r1
Consider the following test (of a logical OR gate):
await circuit.expectPass({ in: [0, 0] }, { out: 0 });
await circuit.expectPass({ in: [0, 1] }, { out: 0 });
await circuit.expectPass({ in: [1, 0] }, { out: 0 });
await circuit.expectPass({ in: [1, 1] }, { out: 1 });
If we were to use Promise.all
for these, we get errors. Need to dive deeper into why that happens.
Given a sorted array, prove that you know how the array looked like before it was sorted. The permutation array would be a secret input, and the sorted array is public input.
For example, it should output a list of pairs which the CLI prints out as something like:
Symbol | Value |
---|---|
main.in |
1 |
main.comp.in1 |
2 |
main.comp.in1 |
3 |
main.out |
4 |
and such.
If I specify a custom directory for my circuit templates (e.g. src) and run circomkit compile
it still creates a circuits/main/circuit.circom
folder for its component. It fails because the relative path generated within that circuit is wrong. "../circuit.circom"
doesn't exist in that folder.
I think the right folder for components should be src/main/circuit.circom
.
The following line could be the problem.
circomkit/src/utils/instantiate.ts
Line 42 in 0473d88
Does it make sense? Or am I missing something?
For example, we may set plonk
as the Circomkit protocol in circomkit.json
, but we would also like something such as:
{
"multiplier_3": {
"file": "multiplier",
"template": "Multiplier",
"params": [3],
"overrides:" {
// circomkit overrides here!
"version": "2.1.6",
"protocol": "groth16"
}
},
}
Have this command clone a template repo, the current method of hand-writing files is kinda stupid.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.