overall improvements, v0.0.3

This commit is contained in:
erhant
2023-06-03 20:41:49 +03:00
parent 2dfd28920a
commit fe88a1fecb
16 changed files with 130 additions and 575 deletions

24
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: build
on:
push:
branches:
- main
jobs:
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Install dependencies
run: yarn
- name: Build everything
run: yarn build

1
.gitignore vendored
View File

@@ -119,3 +119,4 @@ tmp.ptau
# ignore auto generated test circuits
circuits/test
ptau

View File

@@ -2,7 +2,7 @@
<h1 align="center">
Circomkit
</h1>
<p align="center"><i>A simple-to-use Circom & SnarkJS circuit development & testing environment.</i></p>
<p align="center"><i>A simple-to-use & opinionated circuit development & testing toolkit.</i></p>
</p>
<p align="center">
@@ -15,14 +15,8 @@
<a href="./.github/workflows/styles.yml" target="_blank">
<img alt="Workflow: Styles" src="https://github.com/erhant/circomkit/actions/workflows/styles.yml/badge.svg?branch=main">
</a>
<a href="https://mochajs.org/" target="_blank">
<img alt="Test Suite: Mocha" src="https://img.shields.io/badge/tester-mocha-8D6748?logo=Mocha">
</a>
<a href="https://eslint.org/" target="_blank">
<img alt="Linter: ESLint" src="https://img.shields.io/badge/linter-eslint-8080f2?logo=eslint">
</a>
<a href="https://prettier.io/" target="_blank">
<img alt="Formatter: Prettier" src="https://img.shields.io/badge/formatter-prettier-f8bc45?logo=prettier">
<a href="./.github/workflows/build.yml" target="_blank">
<img alt="Workflow: Build" src="https://github.com/erhant/circomkit/actions/workflows/build.yml/badge.svg?branch=main">
</a>
<a href="https://github.com/iden3/snarkjs" target="_blank">
<img alt="GitHub: SnarkJS" src="https://img.shields.io/badge/github-snarkjs-lightgray?logo=github">
@@ -68,22 +62,19 @@ You can omit `pubs` and `params` options, they default to `[]`. Afterwards, you
```bash
# Compile the circuit (generates the main component & compiles it)
yarn compile circuit-name
npx circomkit compile circuit-name
# Circuit setup
yarn setup circuit-name -p phase1-ptau-path [-n num-contribs (default: 1)]
# Shorthand for `compile` and then `setup`
yarn keygen circuit-name -p phase1-ptau-path [-n num-contribs (default: 1)]
npx circomkit setup circuit-name -p phase1-ptau-path
# Create a Solidity verifier contract
yarn contract circuit-name
npx circomkit contract circuit-name
# Clean circuit artifacts
yarn clean circuit-name
npx circomkit clean circuit-name
# Generate the `main` component without compiling it afterwards
yarn instantiate circuit-name
npx circomkit instantiate circuit-name
```
You can change some general settings such as the configured proof system or the prime field under [circomkit.env](./circomkit.env).
@@ -94,35 +85,21 @@ Some actions such as generating a witness, generating a proof and verifying a pr
```bash
# Generate a witness for some input
yarn witness circuit-name [-i input-name (default: "default")]
npx circomkit witness circuit-name [-i input-name (default: "default")]
# Generate a proof for some input
yarn prove circuit-name [-i input-name (default: "default")]
npx circomkit prove circuit-name [-i input-name (default: "default")]
# Verify a proof for some input (public signals only)
yarn verify circuit-name [-i input-name (default: "default")]
npx circomkit verify circuit-name [-i input-name (default: "default")]
# Debug a witness of some input
yarn debug circuit-name [-i input-name (default: "default")]
npx circomkit debug circuit-name input-name
# Export calldata to call your Solidity verifier contract
yarn calldata circuit-name [-i input-name (default: "default")]
npx circomkit calldata circuit-name [-i input-name (default: "default")]
```
## Testing
To run tests do the following:
```bash
# test a specific circuit
yarn test <circuit-name>
# test all circuits
yarn test:all
```
You can test both witness calculations and proof generation & verification. We describe both in their respective sections, going over an example of "Multiplication" circuit.
### Example Circuits
We have several example circuits that you can check out. With them, you can prove the following statements:
@@ -291,6 +268,20 @@ circomkit
└── ...
```
## Testing
To run tests do the following:
```bash
# test a specific circuit
yarn test <circuit-name>
# test all circuits
yarn test:all
```
You can test both witness calculations and proof generation & verification. We describe both in their respective sections, going over an example of "Multiplication" circuit.
## Styling
We use [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html) for the TypeScript codes.

5
circomkit.json Normal file
View File

@@ -0,0 +1,5 @@
{
"colors": {
"title": "\u001b[0;33m"
}
}

View File

@@ -1,382 +0,0 @@
#!/bin/bash
# I couldn't bring myself to delete this file, so here is a CLI Gist.
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

View File

@@ -5,7 +5,6 @@ import {initFiles} from '../utils/initFiles';
const CONFIG_PATH = './circomkit.json';
const DEFAULT_INPUT = 'default';
const DEFAULT_PTAU = './ptau/powersOfTau28_hez_final_12.ptau';
const USAGE = `Usage:
Compile the circuit.
@@ -20,6 +19,12 @@ const USAGE = `Usage:
Export Solidity verifier.
contract circuit
Commence circuit-specific setup.
setup circuit
Download the PTAU file needed for the circuit.
ptau circuit
Export calldata for a verifier contract.
contract circuit input
@@ -32,9 +37,6 @@ const USAGE = `Usage:
Generate a witness.
witness circuit input
Commence circuit-specific setup.
setup circuit ptau-path
Initialize a Circomkit project.
init [name]
`;
@@ -151,6 +153,8 @@ async function cli(): Promise<number> {
}
})
);
circomkit.log('Circomkit project created!', 'success');
break;
}

View File

@@ -2,7 +2,7 @@ const snarkjs = require('snarkjs');
const wasm_tester = require('circom_tester').wasm;
import {writeFileSync, readFileSync, existsSync, mkdirSync} from 'fs';
import {readFile, rm, writeFile} from 'fs/promises';
import instantiate from './utils/instantiate';
import {instantiate} from './utils/instantiate';
import {downloadPtau, getPtauName} from './utils/ptau';
import type {CircuitConfig, R1CSInfoType} from './types/circuit';
import type {CircomkitConfig, CircuitInputPathBuilders, CircuitPathBuilders} from './types/circomkit';
@@ -13,7 +13,13 @@ const defaultConfig: Readonly<CircomkitConfig> = {
curve: 'bn128',
version: '2.1.0',
silent: false,
ptauDir: './ptau',
dirs: {
ptau: './ptau',
circuits: './circuits',
inputs: './inputs',
main: 'main',
build: './build',
},
compiler: {
optimization: 0,
verbose: false,
@@ -21,10 +27,10 @@ const defaultConfig: Readonly<CircomkitConfig> = {
include: ['./node_modules'],
},
colors: {
title: '\x1b[0;34m', // blue
log: '\x1b[2;37m', // gray
error: '\x1b[0;31m', // red
success: '\x1b[0;32m', // green
title: '\u001b[0;34m', // blue
log: '\u001b[2;37m', // gray
error: '\u001b[0;31m', // red
success: '\u001b[0;32m', // green
},
};
@@ -78,12 +84,12 @@ export class Circomkit {
* @returns path
*/
private path(circuit: string, type: CircuitPathBuilders): string {
const dir = `./build/${circuit}`;
const dir = `${this.config.dirs.build}/${circuit}`;
switch (type) {
case 'dir':
return dir;
case 'target':
return `./circuits/main/${circuit}.circom`;
return `${this.config.dirs.circuits}/${this.config.dirs.main}/${circuit}.circom`;
case 'pkey':
return `${dir}/prover_key.zkey`;
case 'vkey':
@@ -109,7 +115,7 @@ export class Circomkit {
* @returns path
*/
private path2(circuit: string, input: string, type: CircuitInputPathBuilders): string {
const dir = `./build/${circuit}/${input}`;
const dir = `${this.config.dirs.build}/${circuit}/${input}`;
switch (type) {
case 'dir':
return dir;
@@ -120,7 +126,7 @@ export class Circomkit {
case 'wtns':
return `${dir}/witness.wtns`;
case 'in':
return `./inputs/${circuit}/${input}.json`;
return `${this.config.dirs.inputs}/${circuit}/${input}.json`;
default:
throw new Error('Invalid type: ' + type);
}
@@ -153,12 +159,12 @@ export class Circomkit {
const ptauName = getPtauName(constraints);
// return if ptau exists already
const ptauPath = `${this.config.ptauDir}/${ptauName}`;
const ptauPath = `${this.config.dirs.ptau}/${ptauName}`;
if (existsSync(ptauPath)) {
return ptauPath;
} else {
this.log('Downloading ' + ptauName + '...');
return await downloadPtau(ptauName, this.config.ptauDir);
return await downloadPtau(ptauName, this.config.dirs.ptau);
}
}
@@ -193,7 +199,9 @@ export class Circomkit {
return outDir;
}
/** Exports a solidity contract for the verifier. */
/** Exports a solidity contract for the verifier.
* @returns path to exported Solidity contract
*/
async contract(circuit: string) {
const pkey = this.path(circuit, 'pkey');
const template = readFileSync(
@@ -209,7 +217,9 @@ export class Circomkit {
return contractPath;
}
/** Export calldata to console. */
/** Export calldata to console.
* @returns calldata as a string
*/
async calldata(circuit: string, input: string) {
const [pubs, proof] = (
await Promise.all(
@@ -219,18 +229,22 @@ export class Circomkit {
return await snarkjs[this.config.proofSystem].exportSolidityCallData(proof, pubs);
}
/** Instantiate the `main` component. */
/** Instantiate the `main` component.
* @returns path to created main component
*/
instantiate(circuit: string) {
const circuitConfig = this.readCircuitConfig(circuit);
const target = instantiate(circuit, {
...circuitConfig,
dir: 'main',
dir: this.config.dirs.main,
version: this.config.version,
});
return target;
}
/** Generate a proof. */
/** Generate a proof.
* @returns path to directory where public signals and proof are created
*/
async prove(circuit: string, input: string) {
const jsonInput = JSON.parse(readFileSync(this.path2(circuit, input, 'in'), 'utf-8'));
const fullProof = await snarkjs[this.config.proofSystem].fullProve(
@@ -248,7 +262,9 @@ export class Circomkit {
return dir;
}
/** Commence a circuit-specific setup. */
/** Commence a circuit-specific setup.
* @returns path to prover key
*/
async setup(circuit: string) {
const r1csPath = this.path(circuit, 'r1cs');
const pkeyPath = this.path(circuit, 'pkey');
@@ -265,7 +281,7 @@ export class Circomkit {
const ptau = await this.ptau(circuit);
// circuit specific setup
if (this.config.proofSystem === 'plonk' || this.config.proofSystem === 'fflonk') {
if (this.config.proofSystem === 'plonk') {
await snarkjs.plonk.setup(this.path(circuit, 'r1cs'), ptau, pkeyPath);
} else {
throw new Error('Not implemented.');

View File

@@ -1,6 +1,7 @@
import ProofTester from './testers/proofTester';
import WasmTester from './testers/wasmTester';
import instantiate from './utils/instantiate';
import {instantiate} from './utils/instantiate';
import {Circomkit} from './circomkit';
export * from './types/circuit';
export {ProofTester, WasmTester, instantiate, Circomkit};

View File

@@ -1,21 +1,22 @@
import {readFileSync, existsSync} from 'fs';
const snarkjs = require('snarkjs');
import {expect} from 'chai';
import type {CircuitSignals, FullProof, ProofSystem} from '../types/circuit';
import type {CircuitSignals, FullProof} from '../types/circuit';
/** Allowed proof systems as defined in SnarkJS. */
const PROOF_SYSTEMS = ['groth16', 'plonk', 'fflonk'] as const;
const PROOF_SYSTEMS = ['groth16', 'plonk'] as const;
/**
* A more extensive Circuit class, able to generate proofs & verify them.
* Assumes that prover key and verifier key have been computed.
*/
export default class ProofTester<IN extends string[] = []> {
public readonly protocol: ProofSystem;
public readonly protocol: 'groth16' | 'plonk';
private readonly wasmPath: string;
private readonly proverKeyPath: string;
private readonly verificationKeyPath: string;
private readonly verificationKey: unknown & {protocol: ProofSystem};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private readonly verificationKey: any;
/**
* Sets the paths & loads the verification key. The underlying proof system is checked by looking

View File

@@ -2,7 +2,7 @@ const wasm_tester = require('circom_tester').wasm;
import type {WitnessType, CircuitSignals, SymbolsType, SignalValueType, CircuitConfig} from '../types/circuit';
import type {CircomWasmTester} from '../types/wasmTester';
import {assert, expect} from 'chai';
import instantiate from '../utils/instantiate';
import {instantiate} from '../utils/instantiate';
/** A utility class to test your circuits. Use `expectFail` and `expectPass` to test out evaluations. */
export default class WasmTester<IN extends readonly string[] = [], OUT extends readonly string[] = []> {

View File

@@ -3,11 +3,22 @@ type VersionType = `${number}.${number}.${number}`;
export type CircomkitConfig = {
/** Proof system to be used. */
proofSystem: 'groth16' | 'plonk' | 'fflonk';
proofSystem: 'groth16' | 'plonk';
/** Curve to be used, which defines the underlying prime field. */
curve: 'bn128' | 'bls12381' | 'goldilocks';
/** Directory to download PTAU files. */
ptauDir: string;
/** Directory overrides, it is best you leave this as is. */
dirs: {
/** Directory to read circuits from. */
circuits: string;
/** Folder name to output the main component under `circuits` directory. */
main: string;
/** Directory to read inputs from. */
inputs: string;
/** Directory to download PTAU files. */
ptau: string;
/** Directory to output circuit build files. */
build: string;
};
/** Version number for main components. */
version: VersionType;
/** Hide Circomkit logs */

View File

@@ -36,9 +36,6 @@ export type FullProof = {
publicSignals: string[];
};
/** Proof system to be used by SnarkJS. */
export type ProofSystem = 'groth16' | 'plonk' | 'fflonk';
/** A configuration object for circuit main components. */
export type CircuitConfig = {
/** File to read the template from */

View File

@@ -18,7 +18,7 @@ component main${config.pubs.length === 0 ? '' : ' {public[' + config.pubs.join('
* @param circuitConfig circuit configuration
* @return path to the created file
*/
export default function instantiate(name: string, circuitConfig: CircuitConfig): string {
export function instantiate(name: string, circuitConfig: CircuitConfig): string {
// directory to output the file
const directory = circuitConfig.dir || 'test';

View File

@@ -1,11 +1,11 @@
import {createWriteStream} from 'fs';
import {get} from 'https';
/** Base PTAU URL as seen in [SnarkJS docs](https://github.com/iden3/snarkjs#7-prepare-phase-2). */
const PTAU_URL_BASE = 'https://hermez.s3-eu-west-1.amazonaws.com';
/**
* Returns the name of PTAU file for a given number of constraints.
*
* @see {@link https://github.com/iden3/snarkjs#7-prepare-phase-2}
* @param n number of constraints
* @returns name of the PTAU file

View File

@@ -1,4 +1,4 @@
import {ProofTester, WasmTester} from '../src';
import {FullProof, ProofTester, WasmTester} from '../src';
describe('multiplier', () => {
const N = 3;
@@ -42,7 +42,7 @@ describe('multiplier utilities', () => {
describe.skip('multiplier proofs', () => {
const N = 3;
let fullProof: any;
let fullProof: FullProof;
let circuit: ProofTester<['in']>;
before(async () => {
const circuitName = 'multiplier_' + N;

122
yarn.lock
View File

@@ -160,11 +160,6 @@
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4"
integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==
"@types/ejs@^3.1.2":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.1.2.tgz#75d277b030bc11b3be38c807e10071f45ebc78d9"
integrity sha512-ZmiaE3wglXVWBM9fyVC17aGPkLo/UgaOjEiI2FXQfyczrCefORPxIe+2dVmnmk3zkVIbizjrlQzmPGhSYGXG5g==
"@types/json-schema@^7.0.7":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
@@ -646,24 +641,6 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
copyfiles@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5"
integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==
dependencies:
glob "^7.0.5"
minimatch "^3.0.3"
mkdirp "^1.0.4"
noms "0.0.0"
through2 "^2.0.1"
untildify "^4.0.0"
yargs "^16.1.0"
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
@@ -1194,7 +1171,7 @@ glob@^10.2.5:
minipass "^5.0.0 || ^6.0.2"
path-scurry "^1.7.0"
glob@^7.0.5, glob@^7.1.3:
glob@^7.1.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -1362,7 +1339,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
inherits@2, inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1483,16 +1460,6 @@ is-unicode-supported@^0.1.0:
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -1714,7 +1681,7 @@ minimatch@5.0.1:
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -1749,11 +1716,6 @@ minimist-options@4.1.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-6.0.2.tgz#542844b6c4ce95b202c0995b0a471f1229de4c81"
integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==
mkdirp@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mocha@^10.2.0:
version "10.2.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
@@ -1816,14 +1778,6 @@ ncp@^2.0.0:
resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
integrity sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==
noms@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==
dependencies:
inherits "^2.0.1"
readable-stream "~1.0.31"
normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@@ -1997,11 +1951,6 @@ prettier@^2.1.2:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.3.tgz#ab697b1d3dd46fb4626fbe2f543afe0cc98d8632"
integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@@ -2068,29 +2017,6 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
readable-stream@~1.0.31:
version "1.0.34"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -2186,11 +2112,6 @@ safe-buffer@^5.1.0:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
@@ -2337,18 +2258,6 @@ string-width@^5.0.1, string-width@^5.1.2:
emoji-regex "^9.2.2"
strip-ansi "^7.0.1"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
@@ -2422,14 +2331,6 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
through2@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
dependencies:
readable-stream "~2.3.6"
xtend "~4.0.1"
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -2553,11 +2454,6 @@ typescript@^4.9.5:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
untildify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@@ -2565,11 +2461,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
util@^0.12.4:
version "0.12.5"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
@@ -2685,11 +2576,6 @@ write-file-atomic@^3.0.3:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
@@ -2720,7 +2606,7 @@ yargs-unparser@2.0.0:
flat "^5.0.2"
is-plain-obj "^2.1.0"
yargs@16.2.0, yargs@^16.1.0:
yargs@16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==