{"id":16517828,"url":"https://github.com/erhant/circomkit","last_synced_at":"2025-04-12T19:41:49.010Z","repository":{"id":160639213,"uuid":"602095142","full_name":"erhant/circomkit","owner":"erhant","description":"A testing \u0026 development environment for Circom.","archived":false,"fork":false,"pushed_at":"2025-02-27T20:55:59.000Z","size":5530,"stargazers_count":108,"open_issues_count":19,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-10T22:38:27.578Z","etag":null,"topics":["circom","development-environment","toolkit","typescript","zero-knowledge"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/circomkit","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erhant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-15T13:42:14.000Z","updated_at":"2025-04-07T03:11:21.000Z","dependencies_parsed_at":"2024-04-23T21:07:45.260Z","dependency_job_id":"faed326e-7288-4ef9-9013-4c2d8aedb467","html_url":"https://github.com/erhant/circomkit","commit_stats":{"total_commits":136,"total_committers":6,"mean_commits":"22.666666666666668","dds":"0.11029411764705888","last_synced_commit":"98725e6946ed76ac002dc17b6fee7982327baf2e"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erhant%2Fcircomkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erhant%2Fcircomkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erhant%2Fcircomkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erhant%2Fcircomkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erhant","download_url":"https://codeload.github.com/erhant/circomkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625075,"owners_count":21135510,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circom","development-environment","toolkit","typescript","zero-knowledge"],"created_at":"2024-10-11T16:33:53.011Z","updated_at":"2025-04-12T19:41:48.985Z","avatar_url":"https://github.com/erhant.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003e\n    Circomkit\n  \u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\u003ci\u003eA simple-to-use \u0026 opinionated circuit development \u0026 testing toolkit.\u003c/i\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/circomkit\" target=\"_blank\"\u003e\n        \u003cimg alt=\"NPM\" src=\"https://img.shields.io/npm/v/circomkit?logo=npm\u0026color=CB3837\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"./.github/workflows/tests.yml\" target=\"_blank\"\u003e\n        \u003cimg alt=\"Workflow: Tests\" src=\"https://github.com/erhant/circomkit/actions/workflows/tests.yml/badge.svg?branch=main\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://opensource.org/licenses/MIT\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n- [x] Simple CLI, abstracting away all paths with a simple config.\n- [x] Provides type-safe testing utilities to check for circuit computations \u0026 soundness errors, with minimal boilerplate code!\n- [x] Supports all protocols: `groth16`, `plonk`, and `fflonk`.\n- [x] Automatically downloads phase-1 PTAU when using `bn128`.\n- [x] Supports multiple exports such as a Solidity verifier contract and its calldata for some input, or JSON exports for R1CS and the witness file.\n\n## Installation\n\nCircomkit can be installed via:\n\n```sh\nnpm  install circomkit\npnpm install circomkit\nyarn add     circomkit\nbun  add     circomkit\n```\n\nYou will also need [Circom](https://docs.circom.io), which can be installed following the instructions [here](https://docs.circom.io/getting-started/installation/).\n\n## Usage\n\nYou can see available commands with:\n\n```sh\nnpx circomkit help\n```\n\nYou can check out examples at the [circomkit-examples](https://github.com/erhant/circomkit-examples) repository, or within the [examples](./examples/) directory here.\n\n### Command Line Interface\n\nActions that require a circuit name can be called as follows:\n\n```sh\n# Compile the circuit\nnpx circomkit compile \u003ccircuit\u003e\n\n# Create the main component\nnpx circomkit instantiate \u003ccircuit\u003e\n\n# Create a Solidity verifier contract\nnpx circomkit contract \u003ccircuit\u003e\n\n# Clear circuit artifacts\nnpx circomkit clear \u003ccircuit\u003e\n\n# Circuit-specific setup\nnpx circomkit setup \u003ccircuit\u003e [ptau-path]\n\n# Create verification key\nnpx circomkit vkey \u003ccircuit\u003e [pkey-path]\n\n# Automatically download PTAU (for BN128)\nnpx circomkit ptau \u003ccircuit\u003e\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e Circuit-specific setup optionally takes the path to a PTAU file as argument. If not provided, it will automatically decide the PTAU to use with respect to constraint count, and download that for you! This feature only works for `bn128` prime, and has an upper-limit of at most $2^{28}$ constraints.\n\nSome actions such as generating a witness, generating a proof and verifying a proof require JSON inputs to provide the signal values. For that, we specifically create our input files under the `inputs` folder, and under the target circuit name there. For example, an input named `foo` for some circuit named `bar` would be at `inputs/bar/foo.json`.\n\n```sh\n# Generate a witness\nnpx circomkit witness \u003ccircuit\u003e \u003cinput\u003e\n\n# Generate a proof\nnpx circomkit prove \u003ccircuit\u003e \u003cinput\u003e\n\n# Verify a proof with public signals\nnpx circomkit verify \u003ccircuit\u003e \u003cinput\u003e\n\n# Export Solidity calldata to console\nnpx circomkit calldata \u003ccircuit\u003e \u003cinput\u003e\n```\n\nYou can also list the circuit templates and compiled instances with the command:\n\n```sh\nnpx circomkit list\n```\n\n### Circomkit Configurations\n\nEverything used by Circomkit can be optionally overridden by providing the selected fields in its constructor. Circomkit CLI does this automatically by checking out [`circomkit.json`](src/configs/index.ts#L56) and overriding the defaults with that. You can print the active configuration via the following command:\n\n```sh\nnpx circomkit config\n```\n\nYou can edit any of the fields there to fit your needs. Most importantly, you can change the protocol to be `groth16`, `plonk` or `fflonk`; and you can change the underlying prime field to `bn128`, `bls12381` and `goldilocks`.\n\n\u003e [!NOTE]\n\u003e\n\u003e Using a prime other than `bn128` makes things a bit harder in circuit-specific setup, as you will have to find the PTAU files yourself, whereas in `bn128` we can use [Perpetual Powers of Tau](https://github.com/privacy-scaling-explorations/perpetualpowersoftau).\n\n\n### Circuit Configurations\n\nA circuit config within `circuits.json` looks like below, where the `key` is the circuit name to be used in commands, and the value is an object that describes the filename, template name, public signals and template parameters:\n\n```js\nsudoku_9x9: {\n  file:     'sudoku',\n  template: 'Sudoku',\n  pubs:     ['puzzle'],\n  params:   [3], // sqrt(9)\n}\n```\n\n\u003e [!TIP]\n\u003e\n\u003e The `pubs` and `params` options can be omitted, in which case they will default to `[]`.\n\n### Using Circomkit in Code\n\nAll CLI commands other than `init` can be used with the same name and arguments within Circomkit. Furthermore, you can provide configuration \u0026 inputs directly, instead of letting Circomkit read from `circuits.json` or from within the `inputs` folder.\n\n```ts\nimport {Circomkit} from 'circomkit';\n\nconst circomkit = new Circomkit({\n  // custom configurations\n  protocol: 'plonk',\n});\n\n// artifacts output at `build/multiplier_3` directory\nawait circomkit.compile('multiplier_3', {\n  file: 'multiplier',\n  template: 'Multiplier',\n  params: [3],\n});\n\n// proof \u0026 public signals at `build/multiplier_3/my_input` directory\nawait circomkit.prove('multiplier_3', 'my_input', {in: [3, 5, 7]});\n\n// verify with proof \u0026 public signals at `build/multiplier_3/my_input`\nawait circomkit.verify('multiplier_3', 'my_input');\n```\n\n## Writing Tests\n\nCircomkit provides two tester utilities that use Chai assertions within, which may be used in a test suite such as Mocha. The key point of these utilities is to help reduce boilerplate code and let you simply worry about the inputs and outputs of a circuit.\n\n### Witness Tester\n\nThe Witness tester extends `require('circom_tester').wasm` tool with type-safety and few assertion functions. It provides a very simple interface:\n\n- `expectPass(input)` checks if constraints \u0026 assertions are passing for an input\n- `expectPass(input, output)` additionally checks if the outputs are matching\n- `expectFail(input)` checks if any constraints / assertions are failing\n\nSee an example below:\n\n```ts\ndescribe('witness tester', () =\u003e {\n  // input signals and output signals can be given as type parameters\n  // this makes all functions type-safe!\n  let circuit: WitnessTester\u003c['in'], ['out']\u003e;\n\n  beforeAll(async () =\u003e {\n    const circomkit = new Circomkit();\n    circuit = await circomkit.WitnessTester(CIRCUIT_NAME, CIRCUIT_CONFIG);\n  });\n\n  it('should pass on correct input \u0026 output', async () =\u003e {\n    await circuit.expectPass(INPUT, OUTPUT);\n  });\n\n  it('should fail on wrong output', async () =\u003e {\n    await circuit.expectFail(INPUT, WRONG_OUTPUT);\n  });\n\n  it('should fail on bad input', async () =\u003e {\n    await circuit.expectFail(BAD_INPUT);\n  });\n});\n```\n\nYou can check if the number of constraints are correct using `expectConstraintCount`, as shown below:\n\n```ts\nit('should have correct number of constraints', async () =\u003e {\n  // expects at least N constraints\n  await circuit.expectConstraintCount(N);\n  // expects exactly N constraints\n  await circuit.expectConstraintCount(N, true);\n});\n```\n\nIf you want more control over the output signals, you can use the `compute` function. It takes in an input, and an array of output signal names used in the `main` component so that they can be extracted from the witness.\n\n```ts\nit('should compute correctly', async () =\u003e {\n  const output = await circuit.compute(INPUT, ['out']);\n  expect(output).to.haveOwnProperty('out');\n  expect(output.out).to.eq(BigInt(OUTPUT.out));\n});\n```\n\nFinally, you can run tests on the witnesses too. This is most useful when you would like to check for soundness errors.\n\n- `expectConstraintPass(witness)` checks if constraints are passing for a witness\n- `expectConstraintFail(witness)` checks if constraints are failing\n\nYou can compute the witness via the `calculateWitness(input)` function. To test for soundness errors, you may edit the witness and see if constraints are failing.\n\n\u003e \u003cpicture\u003e\n\u003e   \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/Mqxx/GitHub-Markdown/main/blockquotes/badge/light-theme/tip.svg\"\u003e\n\u003e   \u003cimg alt=\"Warning\" src=\"https://raw.githubusercontent.com/Mqxx/GitHub-Markdown/main/blockquotes/badge/dark-theme/tip.svg\"\u003e\n\u003e \u003c/picture\u003e\u003cbr\u003e\n\u003e\n\u003e Circomkit provides a nice utility for this purpose, called `editWitness(witness, symbols)`. You simply provide a dictionary of symbols to their new values, and it will edit the witness accordingly. See the example below:\n\u003e\n\u003e ```ts\n\u003e it('should pass on correct witness', async () =\u003e {\n\u003e   const witness = await circuit.calculateWitness(INPUT);\n\u003e   await circuit.expectConstraintPass(witness);\n\u003e });\n\u003e\n\u003e it('should fail on fake witness', async () =\u003e {\n\u003e   const witness = await circuit.calculateWitness(INPUT);\n\u003e   const badWitness = await circuit.editWitness(witness, {\n\u003e     'main.signal': BigInt(1234),\n\u003e     'main.component.signal': BigInt('0xCAFE'),\n\u003e     'main.foo.bar[0]': BigInt('0b0101'),\n\u003e   });\n\u003e   await circuit.expectConstraintFail(badWitness);\n\u003e });\n\u003e ```\n\n#### Using C Tester (Work in Progress ⌛)\n\nYou can make use of the C-tester as well, which performs much better for larger circuits than the WASM alternative.\n\nThere may be some prerequisites to compile, and we have an [issue on this](https://github.com/erhant/circomkit/issues/88) right now until we can have a complete setup guide.\n\n### Proof Tester\n\nAs an alternative to simulate generating a proof and verifying it, you can use Proof Tester. The proof tester makes use of WASM file, prover key and verifier key in the background. It will use the underlying Circomkit configuration to look for those files, and it can generate them automatically if they do not exist. An example using Plonk protocol is given below. Notice how we create the necessary files before creating the tester, as they are required for proof generation and verification.\n\n```ts\ndescribe('proof tester', () =\u003e {\n  // input signals and output signals can be given as type parameters\n  // this makes all functions type-safe!\n  let circuit: ProofTester\u003c['in']\u003e;\n  const protocol = 'plonk';\n\n  beforeAll(async () =\u003e {\n    const circomkit = new Circomkit({protocol});\n    circomkit.instantiate(CIRCUIT_NAME, CIRCUIT_CONFIG);\n    await circomkit.setup(CIRCUIT_NAME, PTAU_PATH);\n    circuit = await circomkit.ProofTester(CIRCUIT_NAME, protocol);\n  });\n\n  it('should verify a proof correctly', async () =\u003e {\n    const {proof, publicSignals} = await circuit.prove(INPUT);\n    await circuit.expectPass(proof, publicSignals);\n  });\n\n  it('should NOT verify a proof with invalid public signals', async () =\u003e {\n    const {proof} = await circuit.prove(INPUT);\n    await circuit.expectFail(proof, BAD_PUBLIC_SIGNALS);\n  });\n});\n```\n\n### Type-Safety\n\nYou may notice that there are optional template parameters in both testers: `WitnessTester\u003cInputSignals, OutputSignals\u003e` and `ProofTester\u003cInputSignals\u003e`. These template parameters take in an array of strings corresponding to signal names. For example, if your circuit has two input signals `in1, in2` and an output `out`, you may instantiate the tester as `WitnessTester\u003c['in1', 'in2'], ['out']\u003e`. In doing so, you will get type-checking on all inputs and outputs required by the tester.\n\n## File Structure\n\nCircomkit with its default configuration follows an _opinionated file structure_, abstracting away the pathing and orientation behind the scenes. All of these can be customized by overriding the respective settings in `circomkit.json`.\n\nAn example structure is shown below. Suppose there is a generic circuit for a Sudoku solution knowledge proof written under `circuits` folder. When instantiated, a `main` component for a 9x9 board is created under `circuits/main`. The solution along with it's puzzle is stored as a JSON object under `inputs/sudoku_9x9`. You can see the respective artifacts under `build` directory. In particular, we see `groth16` prefix on some files, indicating that Groth16 protocol was used to create them.\n\n```ml\ncircomkit\n├── circuits.json - \"circuit configurations\"\n├── circomkit.json - \"circomkit configurations\"\n│\n├── circuits - \"circuit codes are here\"\n│   ├── main - \"main components will be here\"\n│   │   └── sudoku_9x9.circom - \"auto-generated circuit instance\"\n│   └── sudoku.circom - \"circuit template\"\n│\n├── inputs - \"circuit inputs are here\"\n│   └── sudoku_9x9 - \"folder name is the circuit instance name\"\n│       └── my_solution.json - \"file name is the input name\"\n│\n├── ptau - \"PTAU files are here\"\n│   └── powersOfTau28_hez_final_08.ptau\n│\n└── build - \"build artifacts are stored here\"\n    └── sudoku_9x9 - \"folder name is the circuit instance name\"\n        ├── sudoku_9x9_js - \"WASM outputs\"\n        │   │── generate_witness.js\n        │   │── witness_calculator.js\n        │   └── sudoku_9x9.wasm\n        │\n        ├── my_solution - \"folder name is the input name\"\n        │   │── groth16_proof.json - \"proofs are created per protocol\"\n        │   │── public.json\n        │   └── witness.wtns\n        │\n        ├── sudoku_9x9.r1cs\n        ├── sudoku_9x9.sym - \"symbol file, used by tests\"\n        │\n        ├── groth16_pkey.zkey - \"proving key per protocol\"\n        ├── groth16_vkey.json - \"verification key per protocol\"\n        └── groth16_verifier.sol - \"verifier contract\"\n\n```\n\n## Testing\n\nRun all tests via:\n\n```sh\npnpm test\n```\n\n\u003e [!TIP]\n\u003e\n\u003e You can also use the CLI while developing Circomkit locally via `pnpm cli` as if you are using `npx circomkit`. This is useful for hands-on testing stuff.\n\n## Styling\n\nCircomkit uses [Google TypeScript Style Guide](https://google.github.io/styleguide/tsguide.html).\n\n```sh\n# check the formatting\npnpm format\n\n# lint everything\npnpm lint\n```\n\n## Acknowledgements\n\nWe wholeheartedly thank [BuidlGuild](https://buidlguidl.com/) \u0026 [Austin Griffith](https://twitter.com/austingriffith) for providing Circomkit with an [Ecosystem Impact Grant](https://grants.buidlguidl.com/)!\n","funding_links":[],"categories":["Code editors \u0026 tooling"],"sub_categories":["Cryptographic primitives in other languages"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferhant%2Fcircomkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferhant%2Fcircomkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferhant%2Fcircomkit/lists"}