From 27ab6933f31540c6dba2a8933d4663f60bfa09dc Mon Sep 17 00:00:00 2001 From: Roshan <19766713+rpalakkal@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:56:36 +0530 Subject: [PATCH] halo2-lib-js + wasm devex improvements (#51) Co-authored-by: Yu Jiang Tham --- .github/workflows/halo2-browser-tests.yml | 47 + .github/workflows/halo2-wasm-tests.yml | 23 - cli/package.json | 7 +- cli/pnpm-lock.yaml | 84 +- cli/scripts/postTsc.js | 2 - cli/src/examples/circuit.ts | 5 +- cli/src/examples/run.ts | 2 +- cli/src/keygen.ts | 4 +- cli/src/scaffold.ts | 6 +- cli/src/utils.ts | 27 +- halo2-lib-js/.gitignore | 2 +- halo2-lib-js/package.json | 10 +- halo2-lib-js/pnpm-lock.yaml | 8 +- halo2-lib-js/scripts/convertDTs.js | 13 +- halo2-lib-js/src/circuit/run.ts | 25 +- halo2-lib-js/src/global.d.ts | 9 + halo2-lib-js/src/halo2lib/CircuitValue.ts | 12 +- halo2-lib-js/src/halo2lib/CircuitValue256.ts | 20 +- halo2-lib-js/src/halo2lib/ecc.ts | 146 +++ halo2-lib-js/src/halo2lib/functions.ts | 959 ++++++++---------- halo2-lib-js/src/shared/docs/halo2Docs.d.ts | 457 --------- halo2-lib-js/src/shared/docs/halo2Docs.ts | 1 - .../src/shared/docs/makePublicDocs.ts | 8 - halo2-lib-js/src/shared/index.ts | 7 +- halo2-lib-js/src/shared/log.ts | 37 - halo2-lib-js/src/shared/types.ts | 3 +- halo2-lib-js/src/shared/utils.ts | 4 +- halo2-lib-js/tests/.gitignore | 1 + halo2-lib-js/tests/gate.ts | 117 +++ halo2-lib-js/tests/range.ts | 38 + halo2-lib-js/tests/run.ts | 5 + halo2-lib-js/tests/test_constant.py | 58 ++ halo2-lib-js/tests/test_constant.sh | 5 + halo2-lib-js/tests/test_vk.py | 49 + halo2-lib-js/tests/test_vk.sh | 5 + halo2-lib-js/tests/utils.ts | 23 + halo2-lib-js/tsconfig.json | 1 - halo2-repl/app/page.tsx | 9 +- halo2-repl/app/worker/halo2repl.ts | 23 +- halo2-repl/package.json | 4 +- halo2-repl/pnpm-lock.yaml | 24 +- halo2-repl/utils/log.ts | 37 + halo2-wasm/Cargo.toml | 2 +- halo2-wasm/js/js/index.ts | 76 +- halo2-wasm/js/shared/scaffold.ts | 114 +++ halo2-wasm/js/web/index.ts | 76 +- halo2-wasm/package.json | 2 +- halo2-wasm/scripts/build.sh | 3 + halo2-wasm/src/tests/gate.rs | 74 +- halo2-wasm/src/tests/range.rs | 14 +- 50 files changed, 1349 insertions(+), 1339 deletions(-) create mode 100644 .github/workflows/halo2-browser-tests.yml delete mode 100644 .github/workflows/halo2-wasm-tests.yml create mode 100644 halo2-lib-js/src/global.d.ts delete mode 100644 halo2-lib-js/src/shared/docs/halo2Docs.d.ts delete mode 100644 halo2-lib-js/src/shared/docs/halo2Docs.ts delete mode 100644 halo2-lib-js/src/shared/docs/makePublicDocs.ts delete mode 100644 halo2-lib-js/src/shared/log.ts create mode 100644 halo2-lib-js/tests/.gitignore create mode 100644 halo2-lib-js/tests/gate.ts create mode 100644 halo2-lib-js/tests/range.ts create mode 100644 halo2-lib-js/tests/run.ts create mode 100644 halo2-lib-js/tests/test_constant.py create mode 100755 halo2-lib-js/tests/test_constant.sh create mode 100644 halo2-lib-js/tests/test_vk.py create mode 100755 halo2-lib-js/tests/test_vk.sh create mode 100644 halo2-lib-js/tests/utils.ts create mode 100644 halo2-repl/utils/log.ts create mode 100644 halo2-wasm/js/shared/scaffold.ts diff --git a/.github/workflows/halo2-browser-tests.yml b/.github/workflows/halo2-browser-tests.yml new file mode 100644 index 0000000..02538be --- /dev/null +++ b/.github/workflows/halo2-browser-tests.yml @@ -0,0 +1,47 @@ +name: halo2-browser Tests + +on: + push: + paths: + - "halo2-wasm/**" + - "halo2-lib-js/**" + +jobs: + halo2-wasm-tests: + runs-on: ubuntu-latest-64core-256ram + steps: + - uses: actions/checkout@v3 + - name: Build halo2-wasm + working-directory: halo2-wasm + run: | + rustup toolchain install nightly-2023-08-12-x86_64-unknown-linux-gnu + rustup component add rust-src --toolchain nightly-2023-08-12-x86_64-unknown-linux-gnu + cargo build --target=x86_64-unknown-linux-gnu --verbose + - name: Test halo2-wasm + working-directory: halo2-wasm + run: cargo test --target=x86_64-unknown-linux-gnu + halo2-lib-js-tests: + runs-on: ubuntu-latest-64core-256ram + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Build halo2-wasm + working-directory: halo2-wasm + run: | + rustup toolchain install nightly-2023-08-12-x86_64-unknown-linux-gnu + rustup component add rust-src --toolchain nightly-2023-08-12-x86_64-unknown-linux-gnu + cargo build --target=x86_64-unknown-linux-gnu --verbose + - name: Build halo2-lib-js + working-directory: halo2-lib-js + run: | + npm install + npm add @axiom-crypto/halo2-wasm-cli@0.1.5 + - name: Test halo2-lib-js/halo2-wasm VK equivalence + working-directory: halo2-lib-js + run: npm run test:vk + - name: Test halo2-lib-js constant equivalence + working-directory: halo2-lib-js + run: npm run test:constant + \ No newline at end of file diff --git a/.github/workflows/halo2-wasm-tests.yml b/.github/workflows/halo2-wasm-tests.yml deleted file mode 100644 index cdb200d..0000000 --- a/.github/workflows/halo2-wasm-tests.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: halo2-wasm Tests - -on: - push: - paths: - - "halo2-wasm/**" - -defaults: - run: - working-directory: halo2-wasm - -jobs: - halo2-wasm-tests: - runs-on: ubuntu-latest-64core-256ram - steps: - - uses: actions/checkout@v3 - - name: Build - run: | - rustup toolchain install nightly-2023-08-12-x86_64-unknown-linux-gnu - rustup component add rust-src --toolchain nightly-2023-08-12-x86_64-unknown-linux-gnu - cargo build --target=x86_64-unknown-linux-gnu --verbose - - name: Test - run: cargo test --target=x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/cli/package.json b/cli/package.json index 54e4319..096ed5c 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { - "name": "halo2-wasm-cli", - "version": "0.1.0", + "name": "@axiom-crypto/halo2-wasm-cli", + "version": "0.1.5", "description": "Halo2 Javascript library", "main": "index.js", "scripts": { @@ -18,7 +18,8 @@ "author": "Intrinsic Technologies", "license": "ISC", "dependencies": { - "@axiom-crypto/halo2-wasm": "^0.2.3", + "@axiom-crypto/halo2-lib-js": "0.2.13-alpha.1", + "@axiom-crypto/halo2-wasm": "0.2.10", "commander": "^11.1.0", "typescript": "^5.2.2" }, diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index e1fd565..1a8a9a7 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -5,9 +5,12 @@ settings: excludeLinksFromLockfile: false dependencies: + '@axiom-crypto/halo2-lib-js': + specifier: 0.2.13-alpha.1 + version: 0.2.13-alpha.1 '@axiom-crypto/halo2-wasm': - specifier: ^0.2.3 - version: 0.2.3 + specifier: 0.2.10 + version: 0.2.10 commander: specifier: ^11.1.0 version: 11.1.0 @@ -25,8 +28,23 @@ devDependencies: packages: - /@axiom-crypto/halo2-wasm@0.2.3: - resolution: {integrity: sha512-Yw5Nh825BiSF0tnvC0kZas4sezR8S6Z4ELJQsVKTaGiZin6416URFxBP5bQDj7u517QaFG8RTx50Do6xPIR8eg==} + /@adraffy/ens-normalize@1.10.0: + resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} + dev: false + + /@axiom-crypto/halo2-lib-js@0.2.13-alpha.1: + resolution: {integrity: sha512-RACC6uGkVNNZDJwsT7yrF/XEq9oSB/hylup78V8JYlYhp3/dZ6fAnbiEPuTe9xFMqDpIYeTN7KO/h6VEqktZfw==} + dependencies: + '@axiom-crypto/halo2-wasm': 0.2.10 + ethers: 6.9.0 + prettier: 1.18.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@axiom-crypto/halo2-wasm@0.2.10: + resolution: {integrity: sha512-88VPIGeLUPYp+kIgKuJ4QBAKZ5SbwtJheBca5DuZdyb/9vGZ02gyeyQe6/2N7yVDIn3hupHhgfAc4mqm1/4ddw==} dev: false /@babel/code-frame@7.22.13: @@ -77,6 +95,17 @@ packages: chalk: 4.1.2 dev: true + /@noble/curves@1.2.0: + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + dependencies: + '@noble/hashes': 1.3.2 + dev: false + + /@noble/hashes@1.3.2: + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} + dev: false + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -104,6 +133,10 @@ packages: pretty-format: 29.7.0 dev: true + /@types/node@18.15.13: + resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} + dev: false + /@types/node@20.8.9: resolution: {integrity: sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==} dependencies: @@ -124,6 +157,10 @@ packages: '@types/yargs-parser': 21.0.2 dev: true + /aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + dev: false + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -213,6 +250,22 @@ packages: engines: {node: '>=8'} dev: true + /ethers@6.9.0: + resolution: {integrity: sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q==} + engines: {node: '>=14.0.0'} + dependencies: + '@adraffy/ens-normalize': 1.10.0 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 18.15.13 + aes-js: 4.0.0-beta.5 + tslib: 2.4.0 + ws: 8.5.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -319,6 +372,12 @@ packages: engines: {node: '>=8.6'} dev: true + /prettier@1.18.2: + resolution: {integrity: sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==} + engines: {node: '>=4'} + hasBin: true + dev: false + /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -365,6 +424,10 @@ packages: is-number: 7.0.0 dev: true + /tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + dev: false + /typescript@5.2.2: resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} @@ -374,3 +437,16 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true + + /ws@8.5.0: + resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false diff --git a/cli/scripts/postTsc.js b/cli/scripts/postTsc.js index 8e52d62..b2c42e7 100644 --- a/cli/scripts/postTsc.js +++ b/cli/scripts/postTsc.js @@ -2,7 +2,6 @@ const fs = require('fs'); const packageJson = require('../package.json'); -const halo2WasmPackageJson = require('../../halo2-wasm/package.json'); const { execSync } = require('child_process'); // Copies a modified version of package.json to the /dist folder @@ -11,7 +10,6 @@ function copyPackageJson() { delete packageJsonCopy.scripts; delete packageJsonCopy.devDependencies; delete packageJsonCopy.publishConfig; - packageJsonCopy.dependencies['@axiom-crypto/halo2-wasm'] = halo2WasmPackageJson.version; packageJsonCopy.bin = { 'halo2-wasm': './index.js', }; diff --git a/cli/src/examples/circuit.ts b/cli/src/examples/circuit.ts index baf2552..48f4987 100644 --- a/cli/src/examples/circuit.ts +++ b/cli/src/examples/circuit.ts @@ -1,6 +1,7 @@ //@ts-ignore -- to avoid halo2-lib-js being a dependency of the cli -export const circuit = async (halo2Lib: Halo2Lib, inputs: {x: number}) => { - const {add, sub, mul, constant, witness, log, rangeCheck, makePublic, isLessThan} = halo2Lib; +import {add, sub, mul, constant, witness, log, rangeCheck, makePublic, isLessThan} from "@axiom-crypto/halo2-lib-js"; + +export const circuit = async (inputs: {x: number}) => { const x = witness(inputs.x); const a = witness(1); const b = witness(2); diff --git a/cli/src/examples/run.ts b/cli/src/examples/run.ts index d4ec129..8dafbfe 100644 --- a/cli/src/examples/run.ts +++ b/cli/src/examples/run.ts @@ -2,4 +2,4 @@ export const run = async (halo2wasm: any, halo2Lib: any, config: any, circuit: a //@ts-ignore -- to avoid halo2-lib-js being a dependency of the cli const { Halo2CircuitRunner } = await import("@axiom-crypto/halo2-lib-js"); await Halo2CircuitRunner(halo2wasm, halo2Lib, config).run(circuit, inputs); -} \ No newline at end of file +} \ No newline at end of file diff --git a/cli/src/keygen.ts b/cli/src/keygen.ts index 5d79eec..0addb56 100644 --- a/cli/src/keygen.ts +++ b/cli/src/keygen.ts @@ -9,9 +9,9 @@ export const keygen = async (path: string, options: { pk: string, vk: string, ci try { await scaffold.populateCircuit(circuit.circuit, circuit.inputs); await scaffold.keygen(); - const vk = scaffold.exportVk(); + const vk = scaffold.exportVkBuffer(); saveBufferToFile(vk, options.vk, "VK") - const pk = scaffold.exportPk(); + const pk = scaffold.exportPkBuffer(); saveBufferToFile(pk, options.pk, "PK") } catch (e) { diff --git a/cli/src/scaffold.ts b/cli/src/scaffold.ts index 0c3602a..e1c3601 100644 --- a/cli/src/scaffold.ts +++ b/cli/src/scaffold.ts @@ -27,12 +27,12 @@ export class CircuitScaffold extends ICircuitScaffold { this.halo2wasm.assignInstances(); } - exportVk() { + exportVkBuffer() { const vk = this.halo2wasm.getVk(); return Buffer.from(vk); } - exportPk() { + exportPkBuffer() { const pk = this.halo2wasm.getPk(); return Buffer.from(pk); } @@ -42,7 +42,7 @@ export class CircuitScaffold extends ICircuitScaffold { this.halo2wasm.loadPk(pk); } - exportProof() { + exportProofBuffer() { const proof = this.halo2wasm.prove(); return Buffer.from(proof); } diff --git a/cli/src/utils.ts b/cli/src/utils.ts index 9d28b75..2a013a1 100644 --- a/cli/src/utils.ts +++ b/cli/src/utils.ts @@ -12,8 +12,26 @@ export async function getFunctionFromTs(relativePath: string, shouldCircuitFunct compilerOptions: { module: ts.ModuleKind.CommonJS } }); const script = new vm.Script(result.outputText); + const customRequire = (moduleName: string) => { + try { + if (moduleName === "@axiom-crypto/halo2-lib-js") { + return require("@axiom-crypto/halo2-lib-js"); + } + else { + const npmRoot = execSync('npm root').toString().trim(); + return require(`${npmRoot}/${moduleName}`); + } + } catch (e) { + throw new Error(`Cannot find module '${moduleName}'.\n Try installing it globally with 'npm install -g ${moduleName}'`); + } + }; const context = vm.createContext({ exports: {}, + require: customRequire, + module: module, + console: console, + __filename: __filename, + __dirname: __dirname, }); script.runInContext(context); if (shouldCircuitFunctionExist && !context.exports.circuit) throw new Error("File does not export a `circuit` function"); @@ -50,8 +68,13 @@ export async function getRunCircuitFromTs(relativePath: string | undefined) { const script = new vm.Script(result.outputText); const customRequire = (moduleName: string) => { try { - const npmRoot = execSync('npm root -g').toString().trim(); - return require(`${npmRoot}/${moduleName}`); + if (moduleName === "@axiom-crypto/halo2-lib-js") { + return require("@axiom-crypto/halo2-lib-js"); + } + else { + const npmRoot = execSync('npm root').toString().trim(); + return require(`${npmRoot}/${moduleName}`); + } } catch (e) { throw new Error(`Cannot find module '${moduleName}'.\n Try installing it globally with 'npm install -g ${moduleName}'`); } diff --git a/halo2-lib-js/.gitignore b/halo2-lib-js/.gitignore index adb2fec..29c999c 100644 --- a/halo2-lib-js/.gitignore +++ b/halo2-lib-js/.gitignore @@ -41,4 +41,4 @@ public/kzg_bn256_19.bin public/kzg_bn256_20.bin my.d.ts -src/shared/docs/build.d.ts \ No newline at end of file +src/shared/build.d.ts \ No newline at end of file diff --git a/halo2-lib-js/package.json b/halo2-lib-js/package.json index d97f341..6cc6e77 100644 --- a/halo2-lib-js/package.json +++ b/halo2-lib-js/package.json @@ -1,11 +1,13 @@ { "name": "@axiom-crypto/halo2-lib-js", - "version": "0.2.9", + "version": "0.2.13", "description": "Halo2 Javascript library", "main": "index.js", "scripts": { - "build": "rm -rf ./dist && pnpm build:docs && tsc && node ./scripts/postTsc.js", - "build:docs": "./node_modules/.bin/dts-bundle-generator src/shared/docs/halo2Docs.d.ts -o src/shared/docs/build.d.ts --external-inlines=@axiom-crypto/halo2-wasm && node ./scripts/convertDTs.js" + "build": "rm -rf ./dist && tsc && node ./scripts/postTsc.js && pnpm build:docs", + "build:docs": "./node_modules/.bin/dts-bundle-generator ./dist/halo2lib/functions.d.ts -o src/shared/build.d.ts && node ./scripts/convertDTs.js && rm -rf ./src/shared/build.d.ts", + "test:vk": "./tests/test_vk.sh", + "test:constant": "./tests/test_constant.sh" }, "keywords": [ "axiom", @@ -30,7 +32,7 @@ "typescript": "^5.2.2" }, "dependencies": { - "@axiom-crypto/halo2-wasm": "0.2.7", + "@axiom-crypto/halo2-wasm": "0.2.10", "ethers": "^6.8.0", "prettier": "1.18.2" }, diff --git a/halo2-lib-js/pnpm-lock.yaml b/halo2-lib-js/pnpm-lock.yaml index f68320f..a1c0848 100644 --- a/halo2-lib-js/pnpm-lock.yaml +++ b/halo2-lib-js/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: '@axiom-crypto/halo2-wasm': - specifier: 0.2.7 - version: 0.2.7 + specifier: 0.2.10 + version: 0.2.10 ethers: specifier: ^6.8.0 version: 6.8.0 @@ -58,8 +58,8 @@ packages: '@jridgewell/trace-mapping': 0.3.20 dev: true - /@axiom-crypto/halo2-wasm@0.2.7: - resolution: {integrity: sha512-pmgFCkCJUlFgh5NCLR59WpWIiBegNxBRAAlA2UxPMga1Pba02ynZgf6SW0tbQaezMiWUdTA9SfpeosovcNI6Yg==} + /@axiom-crypto/halo2-wasm@0.2.10: + resolution: {integrity: sha512-88VPIGeLUPYp+kIgKuJ4QBAKZ5SbwtJheBca5DuZdyb/9vGZ02gyeyQe6/2N7yVDIn3hupHhgfAc4mqm1/4ddw==} dev: false /@babel/code-frame@7.22.13: diff --git a/halo2-lib-js/scripts/convertDTs.js b/halo2-lib-js/scripts/convertDTs.js index b21853c..1f1c9d3 100644 --- a/halo2-lib-js/scripts/convertDTs.js +++ b/halo2-lib-js/scripts/convertDTs.js @@ -1,11 +1,18 @@ const fs = require('fs'); -const halo2libString = fs.readFileSync('src/shared/docs/build.d.ts', 'utf8'); +const halo2libString = fs.readFileSync('src/shared/build.d.ts', 'utf8'); const filteredHalo2libString = halo2libString .split('\n') .filter(line => !line.trim().startsWith('import')) .join('\n') .replaceAll("export ", ""); +let docs = JSON.stringify(filteredHalo2libString); -const exportedHalo2libString = `export const halo2Docs = ${JSON.stringify(filteredHalo2libString)};`; -fs.writeFileSync('src/shared/docs/halo2Docs.ts', exportedHalo2libString); +const jsExport = `"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.halo2Docs = void 0; +exports.halo2Docs = ${docs} +`; +const dTsExport = `export declare const halo2Docs = ${docs};`; +fs.writeFileSync('dist/shared/docs.js', jsExport); +fs.writeFileSync('dist/shared/docs.d.ts', dTsExport); diff --git a/halo2-lib-js/src/circuit/run.ts b/halo2-lib-js/src/circuit/run.ts index 357d986..cec9e1d 100644 --- a/halo2-lib-js/src/circuit/run.ts +++ b/halo2-lib-js/src/circuit/run.ts @@ -1,6 +1,6 @@ import { Halo2LibWasm, Halo2Wasm } from "@axiom-crypto/halo2-wasm/web"; import { getInputFunctionSignature } from "../shared/utils"; -import { Halo2Lib } from "../halo2lib" +// import { Halo2Lib } from "../halo2lib" import { CircuitConfig } from "./types"; const parseInputs = (inputs: string) => { @@ -10,7 +10,8 @@ const parseInputs = (inputs: string) => { const BLINDING_FACTOR = 20; -export const autoConfigCircuit = (circuit: Halo2Wasm, config: CircuitConfig) => { +export const autoConfigCircuit = (config: CircuitConfig) => { + let circuit = globalThis.circuit.halo2wasm; const stats = circuit.getCircuitStats(); for (let i = 6; i < 20; i++) { @@ -24,10 +25,17 @@ export const autoConfigCircuit = (circuit: Halo2Wasm, config: CircuitConfig) => circuit.config(config); } +export const setCircuit = (halo2wasm: Halo2Wasm, halo2lib: Halo2LibWasm, silent?: boolean) => { + globalThis.circuit = { halo2wasm, halo2lib, silent: silent ?? false }; +} + -export function Halo2CircuitRunner(circuit: Halo2Wasm, halo2LibWasm: Halo2LibWasm, config: CircuitConfig) { +export function Halo2CircuitRunner(halo2wasm: Halo2Wasm, halo2lib: Halo2LibWasm, config: CircuitConfig, silent?: boolean) { config = { ...config }; + globalThis.circuit = { halo2wasm, halo2lib, silent: silent ?? false }; + let circuit = globalThis.circuit.halo2wasm; + let halo2LibWasm = globalThis.circuit.halo2lib; const clear = () => { circuit.clear(); @@ -36,7 +44,7 @@ export function Halo2CircuitRunner(circuit: Halo2Wasm, halo2LibWasm: Halo2LibWas async function runFromString(code: string, inputs: string) { clear(); - const halo2Lib = new Halo2Lib(circuit, halo2LibWasm, { firstPass: true }); + const halo2Lib = await import("../halo2lib/functions"); const halo2LibFns = Object.keys(halo2Lib).filter(key => !(typeof key === 'string' && key.charAt(0) === '_')); const functionInputs = getInputFunctionSignature(inputs); const parsedInputs = parseInputs(inputs); @@ -44,11 +52,9 @@ export function Halo2CircuitRunner(circuit: Halo2Wasm, halo2LibWasm: Halo2LibWas await fn(parsedInputs); circuit.assignInstances(); - autoConfigCircuit(circuit, config); + autoConfigCircuit(config); clear(); { - const halo2Lib = new Halo2Lib(circuit, halo2LibWasm); - const halo2LibFns = Object.keys(halo2Lib).filter(key => !(typeof key === 'string' && key.charAt(0) === '_')); const fn = eval(`let {${halo2LibFns.join(", ")}} = halo2Lib; (async function({${functionInputs}}) { ${code} })`); await fn(parsedInputs); } @@ -57,12 +63,11 @@ export function Halo2CircuitRunner(circuit: Halo2Wasm, halo2LibWasm: Halo2LibWas } } - async function run(f: (halo2Lib: Halo2Lib, inputs: T) => Promise, inputs: T) { + async function run(f: (inputs: T) => Promise, inputs: T) { clear(); - let halo2Lib = new Halo2Lib(circuit, halo2LibWasm); let stringifiedInputs = JSON.stringify(inputs); let parsedInputs = parseInputs(stringifiedInputs); - await f(halo2Lib, parsedInputs); + await f(parsedInputs); circuit.assignInstances(); } diff --git a/halo2-lib-js/src/global.d.ts b/halo2-lib-js/src/global.d.ts new file mode 100644 index 0000000..162adda --- /dev/null +++ b/halo2-lib-js/src/global.d.ts @@ -0,0 +1,9 @@ +import { Halo2LibWasm, Halo2Wasm } from "@axiom-crypto/halo2-wasm/web"; + +declare global { + namespace circuit { + var halo2wasm: Halo2Wasm; + var halo2lib: Halo2LibWasm; + var silent: boolean; + } +} \ No newline at end of file diff --git a/halo2-lib-js/src/halo2lib/CircuitValue.ts b/halo2-lib-js/src/halo2lib/CircuitValue.ts index 7edd7ee..3896a36 100644 --- a/halo2-lib-js/src/halo2lib/CircuitValue.ts +++ b/halo2-lib-js/src/halo2lib/CircuitValue.ts @@ -7,16 +7,16 @@ export class CircuitValue { private _circuit: Halo2LibWasm; constructor( - circuit: Halo2LibWasm, { value, cell }: { value?: bigint | number | string; cell?: number } ) { - this._circuit = circuit; + //@ts-ignore + this._circuit = globalThis.circuit.halo2lib; if (value !== undefined) { this._value = BigInt(value); this._cell = this._circuit.constant(value.toString()); } else if (cell !== undefined) { this._cell = cell; - const val = BigInt(circuit.value(cell)); + const val = BigInt(this._circuit.value(cell)); this._value = val; } else { throw new Error("Invalid input"); @@ -48,9 +48,9 @@ export class CircuitValue { b.toString(), paddedNumBits.toString() ); - const hi128CircuitValue = new CircuitValue(this._circuit, { cell: hi }); - const lo128CircuitValue = new CircuitValue(this._circuit, { cell: lo }); - const halo2LibValue256 = new CircuitValue256(this._circuit, { + const hi128CircuitValue = new CircuitValue({ cell: hi }); + const lo128CircuitValue = new CircuitValue({ cell: lo }); + const halo2LibValue256 = new CircuitValue256({ hi: hi128CircuitValue, lo: lo128CircuitValue, }); diff --git a/halo2-lib-js/src/halo2lib/CircuitValue256.ts b/halo2-lib-js/src/halo2lib/CircuitValue256.ts index ced6893..4086e7d 100644 --- a/halo2-lib-js/src/halo2lib/CircuitValue256.ts +++ b/halo2-lib-js/src/halo2lib/CircuitValue256.ts @@ -1,6 +1,6 @@ import { Halo2LibWasm } from "@axiom-crypto/halo2-wasm/web"; import { CircuitValue } from "./CircuitValue"; -import { convertInput } from "../shared/utils"; +import { convertRawInput } from "../shared/utils"; export class CircuitValue256 { private _value: bigint; @@ -8,7 +8,6 @@ export class CircuitValue256 { private _halo2Lib: Halo2LibWasm; constructor( - _halo2Lib: Halo2LibWasm, { value, hi, @@ -19,7 +18,8 @@ export class CircuitValue256 { lo?: CircuitValue; } ) { - this._halo2Lib = _halo2Lib; + //@ts-ignore + this._halo2Lib = globalThis.circuit.halo2lib; if (value !== undefined) { if (BigInt(value) < 0n) { throw new Error("Value cannot be negative."); @@ -31,11 +31,11 @@ export class CircuitValue256 { let hi128 = input.slice(0, 32); let lo128 = input.slice(32); - const hi128CircuitValue = new CircuitValue(_halo2Lib, { - cell: _halo2Lib.constant(convertInput("0x" + hi128)), + const hi128CircuitValue = new CircuitValue({ + cell: this._halo2Lib.constant(convertRawInput("0x" + hi128)), }); - const lo128CircuitValue = new CircuitValue(_halo2Lib, { - cell: _halo2Lib.constant(convertInput("0x" + lo128)), + const lo128CircuitValue = new CircuitValue({ + cell: this._halo2Lib.constant(convertRawInput("0x" + lo128)), }); this._circuitValue = [hi128CircuitValue, lo128CircuitValue]; } else if ( @@ -45,8 +45,8 @@ export class CircuitValue256 { lo instanceof CircuitValue ) { this._circuitValue = [hi, lo]; - const hiVal = BigInt(_halo2Lib.value(hi.cell())); - const loVal = BigInt(_halo2Lib.value(lo.cell())); + const hiVal = BigInt(this._halo2Lib.value(hi.cell())); + const loVal = BigInt(this._halo2Lib.value(lo.cell())); const value = hiVal * 2n ** 128n + loVal; this._value = value; } else { @@ -88,6 +88,6 @@ export class CircuitValue256 { "Cannot convert to CircuitValue (value is > 253 bits). Please use .hi()/.lo() instead." ); } - return new CircuitValue(this._halo2Lib, { cell }); + return new CircuitValue({ cell }); } } diff --git a/halo2-lib-js/src/halo2lib/ecc.ts b/halo2-lib-js/src/halo2lib/ecc.ts index 5e6ccba..00bdac7 100644 --- a/halo2-lib-js/src/halo2lib/ecc.ts +++ b/halo2-lib-js/src/halo2lib/ecc.ts @@ -1,4 +1,7 @@ +import { Bn254FqPoint, Bn254G1AffinePoint, Bn254G2AffinePoint, Secp256k1AffinePoint } from "@axiom-crypto/halo2-wasm/web"; +import { CircuitValue } from "./CircuitValue"; import { CircuitValue256 } from "./CircuitValue256"; +import { Cell } from "./functions"; export interface CircuitBn254Fq2 { c0: CircuitValue256; @@ -19,3 +22,146 @@ export interface CircuitSecp256k1Affine { x: CircuitValue256; y: CircuitValue256; } + +const toJsCircuitValue256 = (val: CircuitValue256) => { + return globalThis.circuit.halo2lib.to_js_circuit_value_256(val.hi().cell(), val.lo().cell()); +} + +const toJsCircuitBn254G1Affine = (point: CircuitBn254G1Affine) => { + return globalThis.circuit.halo2lib.to_js_circuit_bn254_g1_affine(toJsCircuitValue256(point.x), toJsCircuitValue256(point.y)); +} + +const toJsCircuitBn254Fq2 = (point: CircuitBn254Fq2) => { + return globalThis.circuit.halo2lib.to_js_circuit_bn254_fq2(toJsCircuitValue256(point.c0), toJsCircuitValue256(point.c1)); +} + +const toJsCircuitBn254G2Affine = (point: CircuitBn254G2Affine) => { + return globalThis.circuit.halo2lib.to_js_circuit_bn254_g2_affine(toJsCircuitBn254Fq2(point.x), toJsCircuitBn254Fq2(point.y)); +} + +const toJsCircuitSecp256k1Affine = (point: CircuitSecp256k1Affine) => { + return globalThis.circuit.halo2lib.to_js_circuit_secp256k1_affine(toJsCircuitValue256(point.x), toJsCircuitValue256(point.y)); +} + +/** + * + * @param val The field point to load, in hi-lo form. The hi, lo values must have been constrained to be `uint128`s. + * @returns `Bn254FqPoint` whose internals are opaque to the user. + */ +const loadBn254Fq = (val: CircuitValue256): Bn254FqPoint => { + return globalThis.circuit.halo2lib.load_bn254_fq(toJsCircuitValue256(val)); +} + +/** + * + * @param val + * @returns `val` in hi-lo form + */ +const convertBn254FqToCircuitValue256 = (val: Bn254FqPoint) => { + const _val = val.to_circuit_value_256(globalThis.circuit.halo2lib); + return new CircuitValue256({ hi: Cell(_val.hi), lo: Cell(_val.lo) }); +} + +/** + * @param point The affine point to load, with coordinates `CircuitValue256`. The hi, lo values must have been constrained to be `uint128`s. + * @returns `Bn254G1AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (0, 0). + */ +const loadBn254G1 = (point: CircuitBn254G1Affine): Bn254G1AffinePoint => { + return globalThis.circuit.halo2lib.load_bn254_g1(toJsCircuitBn254G1Affine(point)); +} + +/** + * Sums the values of the provided G1 affine points + * + * @param points - The array of `CircuitBn254G1Affine` points. All coordinates are in hi, lo form, and we assume they have been range checked to be `uint128`s. + * @returns The sum of all these points as `Bn254G1AffinePoint`. + */ +const bn254G1Sum = (points: Array): Bn254G1AffinePoint => { + const _points = []; + for (let i = 0; i < points.length; i++) { + _points.push(toJsCircuitBn254G1Affine(points[i])); + } + return globalThis.circuit.halo2lib.bn254_g1_sum(_points); +}; + +/** + * Subtracts the 2 points and returns the value. Constrains that the points are not equal and also one is not the negative of the other (this would be a point doubling, which requires a different formula). + * + * @returns The subtraction of these points. + * @param g1Point1 - G1 point, x,y in hi lo format for each coordinate + * @param g1Point2 - G1 point, x,y in hi lo format for each coordinate + */ + +const bn254G1SubUnequal = (g1Point1: CircuitBn254G1Affine, g1Point2: CircuitBn254G1Affine): Bn254G1AffinePoint => { + return globalThis.circuit.halo2lib.bn254_g1_sub_unequal(toJsCircuitBn254G1Affine(g1Point1), toJsCircuitBn254G1Affine(g1Point2)); +}; + +/** + * @param point The affine point to load, with coordinates `CircuitBn254Fq2`. The hi, lo values must have been constrained to be `uint128`s. + * @returns `Bn254G2AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (Fq2(0), Fq2(0)). + */ +const loadBn254G2 = (point: CircuitBn254G2Affine): Bn254G2AffinePoint => { + return globalThis.circuit.halo2lib.load_bn254_g2(toJsCircuitBn254G2Affine(point)); +} + +/** + * Sums the values of the provided G2 affine points + * + * @param points - The array of `CircuitBn254G2Affine` points. All coordinates are `CircuitBn254Fq2`, whose coordinates are in hi, lo form, and we assume the hi, lo's have been range checked to be `uint128`s. + * @returns The sum of all these points as `Bn254G2AffinePoint`. + */ +const bn254G2Sum = (points: Array): Bn254G2AffinePoint => { + const _points = []; + for (let i = 0; i < points.length; i++) { + _points.push(toJsCircuitBn254G2Affine(points[i])); + } + return globalThis.circuit.halo2lib.bn254_g2_sum(_points); +} + +/** + * Verifies that e(lhsG1, lhsG2) = e(rhsG1, rhsG2) by checking e(lhsG1, lhsG2)*e(-rhsG1, rhsG2) === 1 + * None of the points should be identity. + * + * @param lhsG1 + * @param lhsG2 + * @param rhsG1 + * @param rhsG2 + * @returns [CircuitValue] for the result as a boolean (1 if signature verification is successful). + */ +const bn254PairingCheck = (lhsG1: Bn254G1AffinePoint, lhsG2: Bn254G2AffinePoint, rhsG1: Bn254G1AffinePoint, rhsG2: Bn254G2AffinePoint): CircuitValue => { + return Cell(globalThis.circuit.halo2lib.bn254_pairing_check(lhsG1, lhsG2, rhsG1, rhsG2)); +} + +/** + * @param pubkey The public key to load, in the form of an affine elliptic curve point `(x, y)` where `x, y` have type `CircuitValue256`. The hi, lo values of each `CircuitValue256` must have been constrained to be `uint128`s. + * @returns `Secp256k1AffinePoint`, the public key as a loaded elliptic curve point. This has been constrained to lie on the curve. The public key is constrained to not be the identity (0, 0). + */ +const loadSecp256k1Pubkey = (pubkey: CircuitSecp256k1Affine): Secp256k1AffinePoint => { + return globalThis.circuit.halo2lib.load_secp256k1_pubkey(toJsCircuitSecp256k1Affine(pubkey)); +} + +/** + * + * Verifies the ECDSA signature `(r, s)` with message hash `msgHash` using the secp256k1 public key `pubkey`. Returns 1 if the signature is valid, 0 otherwise. + * @param pubkey + * @param r + * @param s + * @param msgHash + * @returns + */ +const verifySecp256k1ECDSASignature = (pubkey: Secp256k1AffinePoint, r: CircuitValue256, s: CircuitValue256, msgHash: CircuitValue256): CircuitValue => { + return Cell(globalThis.circuit.halo2lib.verify_secp256k1_ecdsa_signature(pubkey, toJsCircuitValue256(r), toJsCircuitValue256(s), toJsCircuitValue256(msgHash))); +} + +export { + loadBn254Fq, + convertBn254FqToCircuitValue256, + loadBn254G1, + bn254G1Sum, + bn254G1SubUnequal, + loadBn254G2, + bn254G2Sum, + bn254PairingCheck, + loadSecp256k1Pubkey, + verifySecp256k1ECDSASignature +} diff --git a/halo2-lib-js/src/halo2lib/functions.ts b/halo2-lib-js/src/halo2lib/functions.ts index 7ff100b..c255e48 100644 --- a/halo2-lib-js/src/halo2lib/functions.ts +++ b/halo2-lib-js/src/halo2lib/functions.ts @@ -1,535 +1,446 @@ -import { Halo2LibWasm, Halo2Wasm } from "@axiom-crypto/halo2-wasm/web"; -import { convertInput, joinArrays } from "../shared/utils"; +import { convertRawInput, joinArrays } from "../shared/utils"; import { CircuitValue } from "./CircuitValue"; -import { RawCircuitInput } from "../shared/types"; -import {Bn254FqPoint, Bn254G1AffinePoint, Bn254G2AffinePoint, JsCircuitBn254Fq2, JsCircuitBn254G1Affine, JsCircuitBn254G2Affine, JsCircuitSecp256k1Affine, JsCircuitValue256, Secp256k1AffinePoint} from "@axiom-crypto/halo2-wasm/web/halo2_wasm"; +import { ConstantValue, RawCircuitInput } from "../shared/types"; import { CircuitValue256 } from "./CircuitValue256"; -import { CircuitBn254Fq2, CircuitBn254G1Affine, CircuitBn254G2Affine, CircuitSecp256k1Affine } from "./ecc"; - -export class Halo2Lib { - - private _halo2wasm: Halo2Wasm; - private _halo2lib: Halo2LibWasm; - private _firstPass: boolean; - private _MAX_BITS: string; - - constructor(halo2wasm: Halo2Wasm, circuit: Halo2LibWasm, options?: { firstPass?: boolean }) { - this. _halo2lib = circuit; - this._firstPass = options?.firstPass ?? false; - this._MAX_BITS = this.getMaxPaddedNumBits(); - this._halo2wasm = halo2wasm; +//to get rid of `Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.` error +import * as x from "../global"; + +export const Cell = (a: number) => new CircuitValue({ cell: a }); + +const getMaxPaddedNumBits = () => { + const lookupBits = globalThis.circuit.halo2lib.lookup_bits(); + let maxPaddedNumBits = Math.floor(253 / lookupBits) * lookupBits - 1; + return maxPaddedNumBits.toString() +} + +const getValidatedNumBits = (numBits: string) => { + const maxBits = getMaxPaddedNumBits(); + if (Number(numBits) > Number(maxBits)) throw new Error(`Number of bits must be less than ${maxBits}`); + return numBits; +} + +const convertCircuitInput = (a: ConstantValue | CircuitValue) => { + if (a instanceof CircuitValue) { + return a.cell(); + } else { + return constant(a).cell(); } +} - private Cell(a: number) { - return new CircuitValue(this. _halo2lib, { cell: a }); - } - - private getMaxPaddedNumBits() { - const lookupBits = this. _halo2lib.lookup_bits(); - let maxPaddedNumBits = Math.floor(253 / lookupBits) * lookupBits - 1; - return maxPaddedNumBits.toString() - } - - private getValidatedNumBits(numBits: string) { - if(Number(numBits) > Number(this._MAX_BITS)) throw new Error(`Number of bits must be less than ${this._MAX_BITS}`); - return numBits; - } - - /** +/** * Creates a circuit variable from a number, bigint, or string. * * @param a - The raw circuit input. * @returns The witness cell. */ - witness = (a: RawCircuitInput) => this.Cell(this. _halo2lib.witness(convertInput(a))); - - /** - * Creates a circuit constant from a number, bigint, or string. - * - * @param a - The raw circuit input. - * @returns The constant cell. - */ - constant = (a: RawCircuitInput) => this.Cell(this. _halo2lib.constant(convertInput(a))); - - /** - * Adds two circuit values. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The sum of the two circuit values. - */ - add = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.add(a.cell(), b.cell())); - - /** - * Subtracts the second circuit value from the first circuit value. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The difference between the two circuit values. - */ - sub = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.sub(a.cell(), b.cell())); - - /** - * Negates a circuit value. - * - * @param a - The circuit value to negate. - * @returns The negation of the circuit value. - */ - neg = (a: CircuitValue) => this.Cell(this. _halo2lib.neg(a.cell())); - - /** - * Multiplies two circuit values. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The product of the two circuit values. - */ - mul = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.mul(a.cell(), b.cell())); - - /** - * Multiplies two circuit values and adds a third circuit value. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @param c - The third circuit value. - * @returns The result of multiplying the first two circuit values and adding the third circuit value. - */ - mulAdd = (a: CircuitValue, b: CircuitValue, c: CircuitValue) => this.Cell(this. _halo2lib.mul_add(a.cell(), b.cell(), c.cell())); - - /** - * Multiplies a circuit value by the negation of another circuit value. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The result of multiplying the first circuit value by the negation of the second circuit value. - */ - mulNot = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.mul_not(a.cell(), b.cell())); - - /** - * Asserts that a circuit value is a bit. - * - * @param a - The circuit value to assert. - */ - assertBit = (a: CircuitValue) => this. _halo2lib.assert_bit(a.cell()); - - /** - * Asserts that a circuit value is a constant. - * - * @param a - The circuit value to assert. - * @param b - The raw circuit input. - */ - assertIsConst = (a: CircuitValue, b: RawCircuitInput) => this. _halo2lib.assert_is_const(a.cell(), convertInput(b)); - - /** - * Computes the inner product of two arrays of circuit values. - * - * @param a - The first array of circuit values. - * @param b - The second array of circuit values. - * @returns The inner product of the two arrays. - */ - innerProduct = (a: CircuitValue[], b: CircuitValue[]) => this.Cell(this. _halo2lib.inner_product(new Uint32Array(a.map(a => a.cell())), new Uint32Array(b.map(b => b.cell())))); - - /** - * Computes the sum of an array of circuit values. - * - * @param arr - The array of circuit values. - * @returns The sum of the array of circuit values. - */ - sum = (arr: CircuitValue[]) => this.Cell(this. _halo2lib.sum(new Uint32Array(arr.map(a => a.cell())))); - - /** - * Performs a bitwise AND operation on two circuit values. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The result of the bitwise AND operation. - */ - and = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.and(a.cell(), b.cell())); - - /** - * Performs a bitwise OR operation on two circuit values. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The result of the bitwise OR operation. - */ - or = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.or(a.cell(), b.cell())); - - /** - * Performs a bitwise NOT operation on a circuit value. - * - * @param a - The circuit value. - * @returns The result of the bitwise NOT operation. - */ - not = (a: CircuitValue) => this.Cell(this. _halo2lib.not(a.cell())); - - /** - * Decrements a circuit value by 1. - * - * @param a - The circuit value. - * @returns The decremented circuit value. - */ - dec = (a: CircuitValue) => this.Cell(this. _halo2lib.dec(a.cell())); - - /** - * Selects a circuit value based on a condition. - * - * @param a - The condition circuit value. - * @param b - The first circuit value. - * @param c - The second circuit value. - * @returns The selected circuit value. - */ - select = (a: CircuitValue, b: CircuitValue, c: CircuitValue) => this.Cell(this. _halo2lib.select(a.cell(), b.cell(), c.cell())); - - /** - * Performs a bitwise OR-AND operation on three circuit values. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @param c - The third circuit value. - * @returns The result of the OR-AND operation. - */ - orAnd = (a: CircuitValue, b: CircuitValue, c: CircuitValue) => this.Cell(this. _halo2lib.or_and(a.cell(), b.cell(), c.cell())); - - /** - * Converts an array of circuit values to an indicator array. - * - * @param bits - The array of circuit values. - * @returns The indicator circuit value. - */ - bitsToIndicator = (bits: CircuitValue[]) => { - const indicator = this. _halo2lib.bits_to_indicator(new Uint32Array(bits.map(b => b.cell()))); - return [...indicator].map((a: number) => this.Cell(a)); - } - - /** - * Converts an index circuit value to an indicator circuit value. - * - * @param idx - The index circuit value. - * @param len - The length of the indicator circuit value. - * @returns The indicator circuit value. - */ - idxToIndicator = (idx: CircuitValue, len: RawCircuitInput) => { - const indicator = this. _halo2lib.idx_to_indicator(idx.cell(), convertInput(len)); - return [...indicator].map((a: number) => this.Cell(a)); - } - - /** - * Selects circuit values from an array based on an indicator circuit value. - * - * @param arr - The array of circuit values. - * @param indicator - The indicator circuit value. - * @returns The selected circuit values. - */ - selectByIndicator = (arr: CircuitValue[], indicator: CircuitValue[]) => this.Cell(this. _halo2lib.select_by_indicator(new Uint32Array(arr.map(a => a.cell())), new Uint32Array(indicator.map(a => a.cell())))); - - /** - * Selects a circuit value from an array based on an index circuit value. - * - * @param arr - The array of circuit values. - * @param idx - The index circuit value. - * @returns The selected circuit value. - */ - selectFromIdx = (arr: CircuitValue[], idx: CircuitValue) => this.Cell(this. _halo2lib.select_from_idx(new Uint32Array(arr.map(a => a.cell())), idx.cell())); - - - /** - * Checks if a circuit value is zero. - * - * @param a - The circuit value to check. - * @returns The indicator circuit value representing whether the input is zero. - */ - isZero = (a: CircuitValue) => this.Cell(this. _halo2lib.is_zero(a.cell())); - - /** - * Checks if two circuit values are equal. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @returns The indicator circuit value representing whether the two inputs are equal. - */ - isEqual = (a: CircuitValue, b: CircuitValue) => this.Cell(this. _halo2lib.is_equal(a.cell(), b.cell())); - - /** - * Converts a circuit value to an array of bits. - * - * @param a - The circuit value to convert. - * @param len - The length of the resulting bit array. - * @returns The array of bits representing the input circuit value. - */ - numToBits = (a: CircuitValue, len: RawCircuitInput) => { - const bits = this. _halo2lib.num_to_bits(a.cell(), convertInput(len)); - const circuitValues = [...bits].map((a: number) => this.Cell(a)); - return circuitValues; - } - - /** - * Asserts that two circuit values are equal. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - */ - checkEqual = (a: CircuitValue, b: CircuitValue) => this. _halo2lib.constrain_equal(a.cell(), b.cell()); - - /** - * Checks if a circuit value is within a specified range. - * - * @param a - The circuit value to check. - * @param b - The range of the circuit value. - */ - rangeCheck = (a: CircuitValue, b: RawCircuitInput) => this. _halo2lib.range_check(a.cell(), convertInput(b)); - - /** - * Checks if the first circuit value is less than the second circuit value. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @param c - The range of the circuit values. - */ - checkLessThan = (a: CircuitValue, b: CircuitValue, c: string = this._MAX_BITS) => { - this.rangeCheck(a, convertInput(c)); - this.rangeCheck(b, convertInput(c)); - this. _halo2lib.check_less_than(a.cell(), b.cell(), this.getValidatedNumBits(c)); - } - - /** - * Checks if the first circuit value is less than the second circuit value. - * - * @param a - The first circuit value. - * @param b - The second circuit value. - * @param c - The range of the circuit values. - * @returns The indicator circuit value representing whether the first input is less than the second input. - */ - isLessThan = (a: CircuitValue, b: CircuitValue, c: string = this._MAX_BITS) => { - this.rangeCheck(a, convertInput(c)); - this.rangeCheck(b, convertInput(c)); - return this.Cell(this. _halo2lib.is_less_than(a.cell(), b.cell(), this.getValidatedNumBits(c))); - } - - /** - * Divides two circuit values and returns the quotient. - * - * @param a - The dividend circuit value. - * @param b - The divisor circuit value. - * @returns The quotient. - * - */ - div = (a: CircuitValue, b: CircuitValue, c: string = this._MAX_BITS, d: string = this._MAX_BITS) => { - if (this._firstPass) { - b = this.constant(1); - } - const res = this. _halo2lib.div_mod_var(a.cell(), b.cell(), c, d) - return this.Cell(res[0]); - } - - /** - * Divides two circuit values and returns the remainder. - * - * @param a - The dividend circuit value. - * @param b - The divisor circuit value. - * @returns The remainder. - * - */ - mod = (a: CircuitValue, b: CircuitValue, c: string = this._MAX_BITS, d: string = this._MAX_BITS) => { - const [_, remainder] = this. _halo2lib.div_mod_var(a.cell(), b.cell(), c, d) - return this.Cell(remainder); - } - - /** - * Raises a circuit value to the power of another circuit value. - * - * @param a - The base circuit value. - * @param b - The exponent circuit value. - * @returns The result of the exponentiation. - */ - pow = (a: CircuitValue, b: CircuitValue, c: string = this._MAX_BITS) => { - const result = this. _halo2lib.pow_var(a.cell(), b.cell(), c); - return this.Cell(result); - } - - /** - * Computes the Poseidon hash of multiple circuit values. - * - * @param args - The circuit values to hash. - * @returns The hash value. - */ - poseidon = (...args: CircuitValue[]) => this.Cell(this. _halo2lib.poseidon(new Uint32Array(joinArrays(...args.map(a => a.cell()))))); - - /** - * Retrieves the value of a circuit value. - * - * @param a - The circuit value. - * @returns The value of the circuit value. - */ - value = (a: CircuitValue) => this. _halo2lib.value(a.cell()); - - /** - * Logs the provided *circuit* values to the console. Use `console.log` for normal logging. - * - * @param args - The values to log (can be `CircuitValue`s or `CircuitValue256`s). - */ - log = (...args: any) => { - if (this._firstPass) return; - let arr = joinArrays(...args).map(a => "0x" + a.value().toString(16)); - if (arr.length === 1) { - console.log(arr[0]); - } else { - console.log(arr); - } - }; - - /** - * Makes a circuit value public. - * - * @param a - The circuit value to make public. - */ - makePublic = (a: CircuitValue) => this. _halo2lib.make_public(this._halo2wasm, a.cell(), 0); - - ecdsaBenchmark = (sk: bigint, msg_hash: bigint, k: bigint) => { - const res = this. _halo2lib.ecdsa_benchmark(sk, msg_hash, k); - return this.Cell(res); - } - - /** - * Creates new `CircuitValue256` and range checks `hi, lo` to be `uint128`s. - * @param hi - * @param lo - * @returns - */ - newCircuitValue256 = (hi: CircuitValue, lo: CircuitValue): CircuitValue256 => { - this.rangeCheck(hi, 128); - this.rangeCheck(lo, 128); - return new CircuitValue256(this._halo2lib, { hi, lo }); - } - // ========== BN254 Elliptic Curve functions ============ - - /** - * - * @param val The field point to load, in hi-lo form. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254FqPoint` whose internals are opaque to the user. - */ - loadBn254Fq = (val: CircuitValue256): Bn254FqPoint =>{ - return this._halo2lib.load_bn254_fq(this._toJsCircuitValue256(val)); - } - - /** - * - * @param val - * @returns `val` in hi-lo form - */ - convertBn254FqToCircuitValue256 = (val: Bn254FqPoint) => { - const _val = val.to_circuit_value_256(this._halo2lib); - return new CircuitValue256(this._halo2lib, { hi: this.Cell(_val.hi), lo: this.Cell(_val.lo) }); - } - - /** - * @param point The affine point to load, with coordinates `CircuitValue256`. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254G1AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (0, 0). - */ - loadBn254G1 = (point: CircuitBn254G1Affine): Bn254G1AffinePoint => { - return this._halo2lib.load_bn254_g1(this._toJsCircuitBn254G1Affine(point)); - } - - /** - * Sums the values of the provided G1 affine points - * - * @param points - The array of `CircuitBn254G1Affine` points. All coordinates are in hi, lo form, and we assume they have been range checked to be `uint128`s. - * @returns The sum of all these points as `Bn254G1AffinePoint`. - */ - bn254G1Sum = (points: Array): Bn254G1AffinePoint => { - const _points = []; - for(let i = 0; i < points.length; i++) { - _points.push(this._toJsCircuitBn254G1Affine(points[i])); - } - return this._halo2lib.bn254_g1_sum(_points); - }; - - /** - * Subtracts the 2 points and returns the value. Constrains that the points are not equal and also one is not the negative of the other (this would be a point doubling, which requires a different formula). - * - * @returns The subtraction of these points. - * @param g1Point1 - G1 point, x,y in hi lo format for each coordinate - * @param g1Point2 - G1 point, x,y in hi lo format for each coordinate - */ - - bn254G1SubUnequal = (g1Point1: CircuitBn254G1Affine, g1Point2: CircuitBn254G1Affine): Bn254G1AffinePoint => { - return this._halo2lib.bn254_g1_sub_unequal(this._toJsCircuitBn254G1Affine(g1Point1), this._toJsCircuitBn254G1Affine(g1Point2)); - }; - - /** - * @param point The affine point to load, with coordinates `CircuitBn254Fq2`. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254G2AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (Fq2(0), Fq2(0)). - */ - loadBn254G2 = (point: CircuitBn254G2Affine): Bn254G2AffinePoint => { - return this._halo2lib.load_bn254_g2(this._toJsCircuitBn254G2Affine(point)); - } - - /** - * Sums the values of the provided G2 affine points - * - * @param points - The array of `CircuitBn254G2Affine` points. All coordinates are `CircuitBn254Fq2`, whose coordinates are in hi, lo form, and we assume the hi, lo's have been range checked to be `uint128`s. - * @returns The sum of all these points as `Bn254G2AffinePoint`. - */ - bn254G2Sum = (points: Array): Bn254G2AffinePoint => { - const _points = []; - for(let i = 0; i < points.length; i++) { - _points.push(this._toJsCircuitBn254G2Affine(points[i])); - } - return this._halo2lib.bn254_g2_sum(_points); - } - - /** - * Verifies that e(lhsG1, lhsG2) = e(rhsG1, rhsG2) by checking e(lhsG1, lhsG2)*e(-rhsG1, rhsG2) === 1 - * None of the points should be identity. - * - * @param lhsG1 - * @param lhsG2 - * @param rhsG1 - * @param rhsG2 - * @returns [CircuitValue] for the result as a boolean (1 if signature verification is successful). - */ - bn254PairingCheck = (lhsG1: Bn254G1AffinePoint, lhsG2: Bn254G2AffinePoint, rhsG1: Bn254G1AffinePoint, rhsG2: Bn254G2AffinePoint): CircuitValue => { - return this.Cell(this._halo2lib.bn254_pairing_check(lhsG1, lhsG2, rhsG1, rhsG2)); - } - - /** - * @param pubkey The public key to load, in the form of an affine elliptic curve point `(x, y)` where `x, y` have type `CircuitValue256`. The hi, lo values of each `CircuitValue256` must have been constrained to be `uint128`s. - * @returns `Secp256k1AffinePoint`, the public key as a loaded elliptic curve point. This has been constrained to lie on the curve. The public key is constrained to not be the identity (0, 0). - */ - loadSecp256k1Pubkey = (pubkey: CircuitSecp256k1Affine): Secp256k1AffinePoint => { - return this._halo2lib.load_secp256k1_pubkey(this._toJsCircuitSecp256k1Affine(pubkey)); - } - - /** - * - * Verifies the ECDSA signature `(r, s)` with message hash `msgHash` using the secp256k1 public key `pubkey`. Returns 1 if the signature is valid, 0 otherwise. - * @param pubkey - * @param r - * @param s - * @param msgHash - * @returns - */ - verifySecp256k1ECDSASignature = (pubkey: Secp256k1AffinePoint, r: CircuitValue256, s: CircuitValue256, msgHash: CircuitValue256): CircuitValue => { - return this.Cell(this._halo2lib.verify_secp256k1_ecdsa_signature(pubkey, this._toJsCircuitValue256(r), this._toJsCircuitValue256(s), this._toJsCircuitValue256(msgHash))); - } - - private _toJsCircuitValue256(val: CircuitValue256) { - return this._halo2lib.to_js_circuit_value_256(val.hi().cell(), val.lo().cell()); - } - - private _toJsCircuitBn254G1Affine(point: CircuitBn254G1Affine) { - return this._halo2lib.to_js_circuit_bn254_g1_affine(this._toJsCircuitValue256(point.x), this._toJsCircuitValue256(point.y)); - } - - private _toJsCircuitBn254Fq2(point: CircuitBn254Fq2) { - return this._halo2lib.to_js_circuit_bn254_fq2(this._toJsCircuitValue256(point.c0), this._toJsCircuitValue256(point.c1)); - } - - private _toJsCircuitBn254G2Affine(point: CircuitBn254G2Affine) { - return this._halo2lib.to_js_circuit_bn254_g2_affine(this._toJsCircuitBn254Fq2(point.x), this._toJsCircuitBn254Fq2(point.y)); - } - - private _toJsCircuitSecp256k1Affine(point: CircuitSecp256k1Affine) { - return this._halo2lib.to_js_circuit_secp256k1_affine(this._toJsCircuitValue256(point.x), this._toJsCircuitValue256(point.y)); +const witness = (a: RawCircuitInput) => Cell(globalThis.circuit.halo2lib.witness(convertRawInput(a))); + +/** + * Creates a circuit constant from a number, bigint, or string. + * + * @param a - The raw circuit input. + * @returns The constant cell. + */ +const constant = (a: RawCircuitInput) => Cell(globalThis.circuit.halo2lib.constant(convertRawInput(a))); + +/** + * Adds two circuit values. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The sum of the two circuit values. + */ +const add = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => { + return Cell(globalThis.circuit.halo2lib.add(convertCircuitInput(a), convertCircuitInput(b))); +} + +/** + * Subtracts the second circuit value from the first circuit value. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The difference between the two circuit values. + */ +const sub = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => { + return Cell(globalThis.circuit.halo2lib.sub(convertCircuitInput(a), convertCircuitInput(b))); +} + +/** + * Negates a circuit value. + * + * @param a - The circuit value to negate. + * @returns The negation of the circuit value. + */ +const neg = (a: ConstantValue | CircuitValue) => { + Cell(globalThis.circuit.halo2lib.neg(convertCircuitInput(a))); +} + +/** + * Multiplies two circuit values. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The product of the two circuit values. + */ +const mul = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => { + return Cell(globalThis.circuit.halo2lib.mul(convertCircuitInput(a), convertCircuitInput(b))); +} + +/** + * Multiplies two circuit values and adds a third circuit value. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @param c - The third circuit value. + * @returns The result of multiplying the first two circuit values and adding the third circuit value. + */ +const mulAdd = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c: ConstantValue | CircuitValue) => { + return Cell(globalThis.circuit.halo2lib.mul_add(convertCircuitInput(a), convertCircuitInput(b), convertCircuitInput(c))); +} + +/** + * Multiplies a circuit value by the negation of another circuit value. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The result of multiplying the first circuit value by the negation of the second circuit value. + */ +const mulNot = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => { + return Cell(globalThis.circuit.halo2lib.mul_not(convertCircuitInput(a), convertCircuitInput(b))); +} + +/** + * Asserts that a circuit value is a bit. + * + * @param a - The circuit value to assert. + */ +const assertBit = (a: ConstantValue | CircuitValue) => globalThis.circuit.halo2lib.assert_bit(convertCircuitInput(a)); + +/** + * Asserts that a circuit value is a constant. + * + * @param a - The circuit value to assert. + * @param b - The raw circuit input. + */ +const assertIsConst = (a: ConstantValue | CircuitValue, b: ConstantValue) => globalThis.circuit.halo2lib.assert_is_const(convertCircuitInput(a), convertRawInput(b)); + +/** + * Computes the inner product of two arrays of circuit values. + * + * @param a - The first array of circuit values. + * @param b - The second array of circuit values. + * @returns The inner product of the two arrays. + */ +const innerProduct = (a: (CircuitValue | ConstantValue)[], b: (CircuitValue | ConstantValue)[]) => Cell(globalThis.circuit.halo2lib.inner_product(new Uint32Array(a.map(a => convertCircuitInput(a))), new Uint32Array(b.map(b => convertCircuitInput(b))))); + +/** + * Computes the sum of an array of circuit values. + * + * @param arr - The array of circuit values. + * @returns The sum of the array of circuit values. + */ +const sum = (arr: (CircuitValue | ConstantValue)[]) => Cell(globalThis.circuit.halo2lib.sum(new Uint32Array(arr.map(a => convertCircuitInput(a))))); + +/** + * Performs a bitwise AND operation on two circuit values. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The result of the bitwise AND operation. + */ +const and = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.and(convertCircuitInput(a), convertCircuitInput(b))); + +/** + * Performs a bitwise OR operation on two circuit values. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The result of the bitwise OR operation. + */ +const or = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.or(convertCircuitInput(a), convertCircuitInput(b))); + +/** + * Performs a bitwise NOT operation on a circuit value. + * + * @param a - The circuit value. + * @returns The result of the bitwise NOT operation. + */ +const not = (a: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.not(convertCircuitInput(a))); + +/** + * Decrements a circuit value by 1. + * + * @param a - The circuit value. + * @returns The decremented circuit value. + */ +const dec = (a: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.dec(convertCircuitInput(a))); + +/** + * Selects a circuit value based on a condition. + * + * @param a - The condition circuit value. + * @param b - The first circuit value. + * @param c - The second circuit value. + * @returns The selected circuit value. + */ +const select = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.select(convertCircuitInput(a), convertCircuitInput(b), convertCircuitInput(c))); + +/** + * Performs a bitwise OR-AND operation on three circuit values. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @param c - The third circuit value. + * @returns The result of the OR-AND operation. + */ +const orAnd = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.or_and(convertCircuitInput(a), convertCircuitInput(b), convertCircuitInput(c))); + +/** + * Converts an array of circuit values to an indicator array. + * + * @param bits - The array of circuit values. + * @returns The indicator circuit value. + */ +const bitsToIndicator = (bits: (CircuitValue | ConstantValue)[]) => { + const indicator = globalThis.circuit.halo2lib.bits_to_indicator(new Uint32Array(bits.map(b => convertCircuitInput(b)))); + return [...indicator].map((a: number) => Cell(a)); +} + +/** + * Converts an index circuit value to an indicator circuit value. + * + * @param idx - The index circuit value. + * @param len - The length of the indicator circuit value. + * @returns The indicator circuit value. + */ +const idxToIndicator = (idx: CircuitValue | ConstantValue, len: ConstantValue) => { + const indicator = globalThis.circuit.halo2lib.idx_to_indicator(convertCircuitInput(idx), convertRawInput(len)); + return [...indicator].map((a: number) => Cell(a)); +} + +/** + * Selects circuit values from an array based on an indicator circuit value. + * + * @param arr - The array of circuit values. + * @param indicator - The indicator circuit value. + * @returns The selected circuit values. + */ +const selectByIndicator = (arr: (ConstantValue | CircuitValue)[], indicator: (ConstantValue | CircuitValue)[]) => Cell(globalThis.circuit.halo2lib.select_by_indicator(new Uint32Array(arr.map(a => convertCircuitInput(a))), new Uint32Array(indicator.map(a => convertCircuitInput(a))))); + +/** + * Selects a circuit value from an array based on an index circuit value. + * + * @param arr - The array of circuit values. + * @param idx - The index circuit value. + * @returns The selected circuit value. + */ +const selectFromIdx = (arr: (ConstantValue | CircuitValue)[], idx: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.select_from_idx(new Uint32Array(arr.map(a => convertCircuitInput(a))), convertCircuitInput(idx))); + + +/** + * Checks if a circuit value is zero. + * + * @param a - The circuit value to check. + * @returns The indicator circuit value representing whether the input is zero. + */ +const isZero = (a: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.is_zero(convertCircuitInput(a))); + +/** + * Checks if two circuit values are equal. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @returns The indicator circuit value representing whether the two inputs are equal. + */ +const isEqual = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => Cell(globalThis.circuit.halo2lib.is_equal(convertCircuitInput(a), convertCircuitInput(b))); + +/** + * Converts a circuit value to an array of bits. + * + * @param a - The circuit value to convert. + * @param len - The length of the resulting bit array. + * @returns The array of bits representing the input circuit value. + */ +const numToBits = (a: ConstantValue | CircuitValue, len: ConstantValue) => { + const bits = globalThis.circuit.halo2lib.num_to_bits(convertCircuitInput(a), convertRawInput(len)); + const circuitValues = [...bits].map((a: number) => Cell(a)); + return circuitValues; +} + +/** + * Asserts that two circuit values are equal. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + */ +const checkEqual = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue) => globalThis.circuit.halo2lib.constrain_equal(convertCircuitInput(a), convertCircuitInput(b)); + +/** + * Checks if a circuit value is within a specified range. + * + * @param a - The circuit value to check. + * @param b - The range of the circuit value. + */ +const rangeCheck = (a: ConstantValue | CircuitValue, b: ConstantValue) => globalThis.circuit.halo2lib.range_check(convertCircuitInput(a), convertRawInput(b)); + +/** + * Checks if the first circuit value is less than the second circuit value. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @param c - The range of the circuit values. + */ +const checkLessThan = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c?: string) => { + if (c === undefined) c = getMaxPaddedNumBits(); + rangeCheck(a, convertRawInput(c)); + rangeCheck(b, convertRawInput(c)); + globalThis.circuit.halo2lib.check_less_than(convertCircuitInput(a), convertCircuitInput(b), getValidatedNumBits(c)); +} + +/** + * Checks if the first circuit value is less than the second circuit value. + * + * @param a - The first circuit value. + * @param b - The second circuit value. + * @param c - The range of the circuit values. + * @returns The indicator circuit value representing whether the first input is less than the second input. + */ +const isLessThan = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c?: string) => { + if (c === undefined) c = getMaxPaddedNumBits(); + rangeCheck(a, convertRawInput(c)); + rangeCheck(b, convertRawInput(c)); + return Cell(globalThis.circuit.halo2lib.is_less_than(convertCircuitInput(a), convertCircuitInput(b), getValidatedNumBits(c))); +} + +/** + * Divides two circuit values and returns the quotient. + * + * @param a - The dividend circuit value. + * @param b - The divisor circuit value. + * @returns The quotient. + * + */ +const div = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c?: string, d?: string) => { + //TODO: if ConstantValue, set c/d to right number of bits + if (c === undefined) c = getMaxPaddedNumBits(); + if (d === undefined) d = getMaxPaddedNumBits(); + const res = globalThis.circuit.halo2lib.div_mod_var(convertCircuitInput(a), convertCircuitInput(b), c, d) + return Cell(res[0]); +} + +/** + * Divides two circuit values and returns the remainder. + * + * @param a - The dividend circuit value. + * @param b - The divisor circuit value. + * @returns The remainder. + * + */ +const mod = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c?: string, d?: string) => { + if (c === undefined) c = getMaxPaddedNumBits(); + if (d === undefined) d = getMaxPaddedNumBits(); + const [_, remainder] = globalThis.circuit.halo2lib.div_mod_var(convertCircuitInput(a), convertCircuitInput(b), c, d) + return Cell(remainder); +} + +/** + * Raises a circuit value to the power of another circuit value. + * + * @param a - The base circuit value. + * @param b - The exponent circuit value. + * @returns The result of the exponentiation. + */ +const pow = (a: ConstantValue | CircuitValue, b: ConstantValue | CircuitValue, c?: string) => { + if (c === undefined) c = getMaxPaddedNumBits(); + const result = globalThis.circuit.halo2lib.pow_var(convertCircuitInput(a), convertCircuitInput(b), c); + return Cell(result); +} + +/** + * Computes the Poseidon hash of multiple circuit values. + * + * @param args - The circuit values to hash. + * @returns The hash value. + */ +const poseidon = (...args: (CircuitValue | ConstantValue)[]) => Cell(globalThis.circuit.halo2lib.poseidon(new Uint32Array(joinArrays(...args.map(a => convertCircuitInput(a)))))); + +/** + * Retrieves the value of a circuit value. + * + * @param a - The circuit value. + * @returns The value of the circuit value. + */ +const value = (a: CircuitValue) => globalThis.circuit.halo2lib.value(convertCircuitInput(a)); + +/** + * Logs the provided *circuit* values to the console. Use `console.log` for normal logging. + * + * @param args - The values to log (can be `CircuitValue`s or `CircuitValue256`s). + */ +const log = (...args: any) => { + if (globalThis.circuit.silent) return; + let arr = joinArrays(...args).map(a => "0x" + a.value().toString(16)); + if (arr.length === 1) { + console.log(arr[0]); + } else { + console.log(arr); } +}; + +/** + * Makes a circuit value public. + * + * @param a - The circuit value to make public. + */ +const makePublic = (a: CircuitValue | ConstantValue) => globalThis.circuit.halo2lib.make_public(globalThis.circuit.halo2wasm, convertCircuitInput(a), 0); + +/** + * Creates new `CircuitValue256` and range checks `hi, lo` to be `uint128`s. + * @param hi + * @param lo + * @returns + */ +const newCircuitValue256 = (hi: CircuitValue, lo: CircuitValue): CircuitValue256 => { + rangeCheck(hi, 128); + rangeCheck(lo, 128); + return new CircuitValue256({ hi, lo }); +} + +export { + witness, + constant, + add, + sub, + neg, + mul, + mulAdd, + mulNot, + assertBit, + assertIsConst, + innerProduct, + sum, + and, + or, + not, + dec, + select, + orAnd, + bitsToIndicator, + idxToIndicator, + selectByIndicator, + selectFromIdx, + isZero, + isEqual, + numToBits, + checkEqual, + rangeCheck, + checkLessThan, + isLessThan, + div, + mod, + pow, + poseidon, + value, + log, + makePublic } \ No newline at end of file diff --git a/halo2-lib-js/src/shared/docs/halo2Docs.d.ts b/halo2-lib-js/src/shared/docs/halo2Docs.d.ts deleted file mode 100644 index c84b808..0000000 --- a/halo2-lib-js/src/shared/docs/halo2Docs.d.ts +++ /dev/null @@ -1,457 +0,0 @@ -// Generated by dts-bundle-generator v8.0.1 - -import { - Bn254FqPoint, - Bn254G1AffinePoint, - Bn254G2AffinePoint, - Secp256k1AffinePoint, -} from "@axiom-crypto/halo2-wasm/web"; -import { CircuitValue } from "../../halo2lib/CircuitValue"; -import { CircuitValue256 } from "../../halo2lib/CircuitValue256"; -import { CircuitBn254Fq2, CircuitBn254G1Affine, CircuitBn254G2Affine, CircuitSecp256k1Affine } from "../../halo2lib/ecc"; - -export type RawCircuitInput = string | number | bigint; - -/** - * Creates a circuit variable from a number, bigint, or string. - * - * @param a The raw circuit input. - * @returns The witness cell. - */ -declare const witness: (a: RawCircuitInput) => CircuitValue; -/** - * Creates a circuit constant from a number, bigint, or string. - * - * @param a The raw circuit input. - * @returns The constant cell. - */ -declare const constant: (a: RawCircuitInput) => CircuitValue; -/** - * Adds two circuit values. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The sum of the two circuit values. - */ -declare const add: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Subtracts the second circuit value from the first circuit value. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The difference between the two circuit values. - */ -declare const sub: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Negates a circuit value. - * - * @param a The circuit value to negate. - * @returns The negation of the circuit value. - */ -declare const neg: (a: CircuitValue) => CircuitValue; -/** - * Multiplies two circuit values. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The product of the two circuit values. - */ -declare const mul: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Multiplies two circuit values and adds a third circuit value. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @param c The third circuit value. - * @returns The result of multiplying the first two circuit values and adding the third circuit value. - */ -declare const mulAdd: ( - a: CircuitValue, - b: CircuitValue, - c: CircuitValue -) => CircuitValue; -/** - * Multiplies a circuit value by the negation of another circuit value. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The result of multiplying the first circuit value by the negation of the second circuit value. - */ -declare const mulNot: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Asserts that a circuit value is a bit. - * - * @param a The circuit value to assert. - */ -declare const assertBit: (a: CircuitValue) => void; -/** - * Asserts that a circuit value is a constant. - * - * @param a The circuit value to assert. - * @param b The raw circuit input. - */ -declare const assertIsConst: (a: CircuitValue, b: RawCircuitInput) => void; -/** - * Computes the inner product of two arrays of circuit values. - * - * @param a The first array of circuit values. - * @param b The second array of circuit values. - * @returns The inner product of the two arrays. - */ -declare const innerProduct: ( - a: CircuitValue[], - b: CircuitValue[] -) => CircuitValue; -/** - * Computes the sum of an array of circuit values. - * - * @param arr The array of circuit values. - * @returns The sum of the array of circuit values. - */ -declare const sum: (arr: CircuitValue[]) => CircuitValue; -/** - * Performs a bitwise AND operation on two circuit values. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The result of the bitwise AND operation. - */ -declare const and: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Performs a bitwise OR operation on two circuit values. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The result of the bitwise OR operation. - */ -declare const or: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Performs a bitwise NOT operation on a circuit value. - * - * @param a The circuit value. - * @returns The result of the bitwise NOT operation. - */ -declare const not: (a: CircuitValue) => CircuitValue; -/** - * Decrements a circuit value by 1. - * - * @param a The circuit value. - * @returns The decremented circuit value. - */ -declare const dec: (a: CircuitValue) => CircuitValue; -/** - * Selects a circuit value based on a condition. - * - * @param a The first circuit value. - * @param b The first circuit value. - * @param sel The condition boolean circuit value. - * @returns sel ? a : b - */ -declare const select: ( - a: CircuitValue, - b: CircuitValue, - sel: CircuitValue -) => CircuitValue; -/** - * Performs a bitwise OR-AND operation on three circuit values. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @param c The third circuit value. - * @returns The result of the OR-AND operation. - */ -declare const orAnd: ( - a: CircuitValue, - b: CircuitValue, - c: CircuitValue -) => CircuitValue; -/** - * Converts an array of circuit values to an indicator array. - * - * @param bits The array of circuit values. - * @returns The indicator circuit value. - */ -declare const bitsToIndicator: (bits: CircuitValue[]) => CircuitValue[]; -/** - * Converts an index circuit value to an indicator circuit value. - * - * @param idx The index circuit value. - * @param len The length of the indicator circuit value. - * @returns The indicator circuit value. - */ -declare const idxToIndicator: ( - idx: CircuitValue, - len: RawCircuitInput -) => CircuitValue[]; -/** - * Selects circuit values from an array based on an indicator circuit value. - * - * @param arr The array of circuit values. - * @param indicator The indicator circuit value. - * @returns The selected circuit values. - */ -declare const selectByIndicator: ( - arr: CircuitValue[], - indicator: CircuitValue[] -) => CircuitValue; -/** - * Selects a circuit value from an array based on an index circuit value. - * - * @param arr The array of circuit values. - * @param idx The index circuit value. - * @returns The selected circuit value. - */ -declare const selectFromIdx: ( - arr: CircuitValue[], - idx: CircuitValue -) => CircuitValue; -/** - * Checks if a circuit value is zero. - * - * @param a The circuit value to check. - * @returns The indicator circuit value representing whether the input is zero. - */ -declare const isZero: (a: CircuitValue) => CircuitValue; -/** - * Checks if two circuit values are equal. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @returns The indicator circuit value representing whether the two inputs are equal. - */ -declare const isEqual: (a: CircuitValue, b: CircuitValue) => CircuitValue; -/** - * Converts a circuit value to an array of bits. - * - * @param a The circuit value to convert. - * @param len The length of the resulting bit array. - * @returns The array of bits representing the input circuit value. - */ -declare const numToBits: ( - a: CircuitValue, - len: RawCircuitInput -) => CircuitValue[]; -/** - * Asserts that two circuit values are equal. - * - * @param a The first circuit value. - * @param b The second circuit value. - */ -declare const checkEqual: (a: CircuitValue, b: CircuitValue) => void; -/** - * Checks if a circuit value is within a specified range. - * - * @param a The circuit value to check. - * @param b The range of the circuit value. - */ -declare const rangeCheck: (a: CircuitValue, b: RawCircuitInput) => void; -/** - * Checks if the first circuit value is less than the second circuit value. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @param c The range of the circuit values. - */ -declare const checkLessThan: ( - a: CircuitValue, - b: CircuitValue, - c?: string -) => void; -/** - * Checks if the first circuit value is less than the second circuit value. - * - * @param a The first circuit value. - * @param b The second circuit value. - * @param c The range of the circuit values. - * @returns The indicator circuit value representing whether the first input is less than the second input. - */ -declare const isLessThan: ( - a: CircuitValue, - b: CircuitValue, - c?: string -) => CircuitValue; -/** - * Divides two circuit values and returns the quotient. - * - * @param a The dividend circuit value. - * @param b The divisor circuit value. - * @returns The quotient. - * - */ -declare const div: ( - a: CircuitValue, - b: CircuitValue, - c?: string, - d?: string -) => CircuitValue; -/** - * Divides two circuit values and returns the remainder. - * - * @param a The dividend circuit value. - * @param b The divisor circuit value. - * @returns The remainder. - * - */ -declare const mod: ( - a: CircuitValue, - b: CircuitValue, - c?: string, - d?: string -) => CircuitValue; -/** - * Raises a circuit value to the power of another circuit value. - * - * @param a The base circuit value. - * @param b The exponent circuit value. - * @returns The result of the exponentiation. - */ -declare const pow: ( - a: CircuitValue, - b: CircuitValue, - c?: string -) => CircuitValue; -/** - * Computes the Poseidon hash of multiple circuit values. - * - * @param args The circuit values to hash. - * @returns The hash value. - */ -declare const poseidon: (...args: CircuitValue[]) => CircuitValue; -/** - * Retrieves the value of a circuit value. - * - * @param a The circuit value. - * @returns The value of the circuit value. - */ -declare const value: (a: CircuitValue) => any; -/** - * Logs the provided *circuit* values to the console. Use `console.log` for normal logging. - * - * @param args The `CircuitValue`s to log. - */ -declare const log: (...args: any) => void; -declare const console: { - /** - * Logs any *non CircuitValue* to the console. Use `log` for logging `CircuitValue`s. - * @param args The values to log. - */ - log: (...args: any) => void; -}; -declare const ecdsaBenchmark: ( - sk: bigint, - msg_hash: bigint, - k: bigint -) => CircuitValue; - -/** - * Creates new `CircuitValue256` and range checks `hi, lo` to be `uint128`s. - * @param hi - * @param lo - * @returns - */ -declare const newCircuitValue256: ( - hi: CircuitValue, - lo: CircuitValue -) => CircuitValue256; -//ecc - -/** - * - * @param val The field point to load, in hi-lo form. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254FqPoint` whose internals are opaque to the user. - */ -declare const loadBn254Fq: (val: CircuitValue256) => Bn254FqPoint; - -/** - * - * @param val - * @returns `val` in hi-lo form - */ -declare const convertBn254FqToCircuitValue256: ( - val: Bn254FqPoint -) => CircuitValue256; - -/** - * @param point The affine point to load, with coordinates `CircuitValue256`. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254G1AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (0, 0). - */ -declare const loadBn254G1: (point: CircuitBn254G1Affine) => Bn254G1AffinePoint; - -/** - * Sums the values of the provided G1 affine points - * - * @param points - The array of `CircuitBn254G1Affine` points. All coordinates are in hi, lo form, and we assume they have been range checked to be `uint128`s. - * @returns The sum of all these points as `Bn254G1AffinePoint`. - */ -declare const bn254G1Sum: ( - points: Array -) => Bn254G1AffinePoint; - -/** - * Subtracts the 2 points and returns the value. Constrains that the points are not equal and also one is not the negative of the other (this would be a point doubling, which requires a different formula). - * - * @returns The subtraction of these points. - * @param g1Point1 - G1 point, x,y in hi lo format for each coordinate - * @param g1Point2 - G1 point, x,y in hi lo format for each coordinate - */ -declare const bn254G1SubUnequal: ( - g1Point1: CircuitBn254G1Affine, - g1Point2: CircuitBn254G1Affine -) => Bn254G1AffinePoint; - -/** - * @param point The affine point to load, with coordinates `CircuitBn254Fq2`. The hi, lo values must have been constrained to be `uint128`s. - * @returns `Bn254G2AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (Fq2(0), Fq2(0)). - */ -declare const loadBn254G2: (point: CircuitBn254G2Affine) => Bn254G2AffinePoint; - -/** - * Sums the values of the provided G2 affine points - * - * @param points - The array of `CircuitBn254G2Affine` points. All coordinates are `CircuitBn254Fq2`, whose coordinates are in hi, lo form, and we assume the hi, lo's have been range checked to be `uint128`s. - * @returns The sum of all these points as `Bn254G2AffinePoint`. - */ -declare const bn254G2Sum: ( - points: Array -) => Bn254G2AffinePoint; - -/** - * Verifies that e(lhsG1, lhsG2) = e(rhsG1, rhsG2) by checking e(lhsG1, lhsG2)*e(-rhsG1, rhsG2) === 1 - * None of the points should be identity. - * - * @param lhsG1 - * @param lhsG2 - * @param rhsG1 - * @param rhsG2 - * @returns [CircuitValue] for the result as a boolean (1 if signature verification is successful). - */ -declare const bn254PairingCheck: ( - lhsG1: Bn254G1AffinePoint, - lhsG2: Bn254G2AffinePoint, - rhsG1: Bn254G1AffinePoint, - rhsG2: Bn254G2AffinePoint -) => CircuitValue; - -/** - * @param pubkey The public key to load, in the form of an affine elliptic curve point `(x, y)` where `x, y` have type `CircuitValue256`. The hi, lo values of each `CircuitValue256` must have been constrained to be `uint128`s. - * @returns `Secp256k1AffinePoint`, the public key as a loaded elliptic curve point. This has been constrained to lie on the curve. The public key is constrained to not be the identity (0, 0). - */ -declare const loadSecp256k1Pubkey: ( - pubkey: CircuitSecp256k1Affine -) => Secp256k1AffinePoint; - -/** - * - * Verifies the ECDSA signature `(r, s)` with message hash `msgHash` using the secp256k1 public key `pubkey`. Returns 1 if the signature is valid, 0 otherwise. - * @param pubkey - * @param r - * @param s - * @param msgHash - * @returns - */ -declare const verifySecp256k1ECDSASignature: ( - pubkey: Secp256k1AffinePoint, - r: CircuitValue256, - s: CircuitValue256, - msgHash: CircuitValue256 -) => CircuitValue; diff --git a/halo2-lib-js/src/shared/docs/halo2Docs.ts b/halo2-lib-js/src/shared/docs/halo2Docs.ts deleted file mode 100644 index f655d3a..0000000 --- a/halo2-lib-js/src/shared/docs/halo2Docs.ts +++ /dev/null @@ -1 +0,0 @@ -export const halo2Docs = "// Generated by dts-bundle-generator v8.1.2\n\ninterface CircuitStats {\n\tadvice: number;\n\tlookup: number;\n\tfixed: number;\n\tinstance: number;\n\tk: number;\n}\ninterface CircuitConfig {\n\tk: number;\n\tnumAdvice: number;\n\tnumLookupAdvice: number;\n\tnumInstance: number;\n\tnumLookupBits: number;\n\tnumVirtualInstance: number;\n}\ndeclare class Bn254Fq2Point {\n\tfree(): void;\n\t/**\n\t* @returns {Bn254FqPoint}\n\t*/\n\tc0(): Bn254FqPoint;\n\t/**\n\t* @returns {Bn254FqPoint}\n\t*/\n\tc1(): Bn254FqPoint;\n}\ndeclare class Bn254FqPoint {\n\tfree(): void;\n\t/**\n\t* @param {Halo2LibWasm} lib_wasm\n\t* @returns {JsCircuitValue256}\n\t*/\n\tto_circuit_value_256(lib_wasm: Halo2LibWasm): JsCircuitValue256;\n}\ndeclare class Bn254G1AffinePoint {\n\tfree(): void;\n\t/**\n\t* @returns {Bn254FqPoint}\n\t*/\n\tx(): Bn254FqPoint;\n\t/**\n\t* @returns {Bn254FqPoint}\n\t*/\n\ty(): Bn254FqPoint;\n}\ndeclare class Bn254G2AffinePoint {\n\tfree(): void;\n\t/**\n\t* @returns {Bn254Fq2Point}\n\t*/\n\tx(): Bn254Fq2Point;\n\t/**\n\t* @returns {Bn254Fq2Point}\n\t*/\n\ty(): Bn254Fq2Point;\n}\ndeclare class Halo2LibWasm {\n\tfree(): void;\n\t/**\n\t* Takes in CircuitValue256 in hi-lo form and loads internal CircuitBn254Fq type (we use 3 limbs of 88 bits).\n\t* This function does not range check `hi,lo` to be `uint128` in case it's already done elsewhere.\n\t* @param {JsCircuitValue256} val\n\t* @returns {Bn254FqPoint}\n\t*/\n\tload_bn254_fq(val: JsCircuitValue256): Bn254FqPoint;\n\t/**\n\t* Doesn't range check limbs of g1_point.\n\t* Does not allow you to load identity point.\n\t* @param {JsCircuitBn254G1Affine} point\n\t* @returns {Bn254G1AffinePoint}\n\t*/\n\tload_bn254_g1(point: JsCircuitBn254G1Affine): Bn254G1AffinePoint;\n\t/**\n\t* `g1_points` should be array of `CircuitBn254G1Affine` in hi-lo form.\n\t* This function does not range check `hi,lo` to be `uint128` in case it's already done elsewhere.\n\t* Prevents any g1_points from being identity.\n\t* @param {Array} g1_points\n\t* @returns {Bn254G1AffinePoint}\n\t*/\n\tbn254_g1_sum(g1_points: Array): Bn254G1AffinePoint;\n\t/**\n\t* `g1_point_1` and `g1_point_2` are `CircuitBn254G1Affine` points in hi-lo form.\n\t* This function does not range check `hi,lo` to be `uint128` in case it's already done elsewhere\n\t* and also it constraints that g1_point_1.x != g1_point_2.x\n\t* Prevents any g1_points from being identity.\n\t* @param {JsCircuitBn254G1Affine} g1_point_1\n\t* @param {JsCircuitBn254G1Affine} g1_point_2\n\t* @returns {Bn254G1AffinePoint}\n\t*/\n\tbn254_g1_sub_unequal(g1_point_1: JsCircuitBn254G1Affine, g1_point_2: JsCircuitBn254G1Affine): Bn254G1AffinePoint;\n\t/**\n\t* Doesn't range check limbs of g2_point.\n\t* Does not allow you to load identity point.\n\t* @param {JsCircuitBn254G2Affine} point\n\t* @returns {Bn254G2AffinePoint}\n\t*/\n\tload_bn254_g2(point: JsCircuitBn254G2Affine): Bn254G2AffinePoint;\n\t/**\n\t* `g2_points` should be array of `CircuitBn254G2Affine` in hi-lo form.\n\t* This function does not range check `hi,lo` to be `uint128` in case it's already done elsewhere.\n\t* Prevents any g2_points from being identity.\n\t* @param {Array} g2_points\n\t* @returns {Bn254G2AffinePoint}\n\t*/\n\tbn254_g2_sum(g2_points: Array): Bn254G2AffinePoint;\n\t/**\n\t* Verifies that e(lhs_g1, lhs_g2) = e(rhs_g1, rhs_g2) by checking e(lhs_g1, lhs_g2)*e(-rhs_g1, rhs_g2) === 1\n\t* Returns [CircuitValue] for the result as a boolean (1 if signature verification is successful).\n\t* None of the points should be identity.\n\t* @param {Bn254G1AffinePoint} lhs_g1\n\t* @param {Bn254G2AffinePoint} lhs_g2\n\t* @param {Bn254G1AffinePoint} rhs_g1\n\t* @param {Bn254G2AffinePoint} rhs_g2\n\t* @returns {number}\n\t*/\n\tbn254_pairing_check(lhs_g1: Bn254G1AffinePoint, lhs_g2: Bn254G2AffinePoint, rhs_g1: Bn254G1AffinePoint, rhs_g2: Bn254G2AffinePoint): number;\n\t/**\n\t* Doesn't range check limbs of point.\n\t* Pubkey is a point on\n\t* @param {JsCircuitSecp256k1Affine} point\n\t* @returns {Secp256k1AffinePoint}\n\t*/\n\tload_secp256k1_pubkey(point: JsCircuitSecp256k1Affine): Secp256k1AffinePoint;\n\t/**\n\t* Assumes all `JsCircuitValue256` limbs have been range checked to be `u128`.\n\t* @param {Secp256k1AffinePoint} pubkey\n\t* @param {JsCircuitValue256} r\n\t* @param {JsCircuitValue256} s\n\t* @param {JsCircuitValue256} msg_hash\n\t* @returns {number}\n\t*/\n\tverify_secp256k1_ecdsa_signature(pubkey: Secp256k1AffinePoint, r: JsCircuitValue256, s: JsCircuitValue256, msg_hash: JsCircuitValue256): number;\n\t/**\n\t* @param {bigint} sk\n\t* @param {bigint} msg_hash\n\t* @param {bigint} k\n\t* @returns {number}\n\t*/\n\tecdsa_benchmark(sk: bigint, msg_hash: bigint, k: bigint): number;\n\t/**\n\t* @param {number} hi\n\t* @param {number} lo\n\t* @returns {JsCircuitValue256}\n\t*/\n\tto_js_circuit_value_256(hi: number, lo: number): JsCircuitValue256;\n\t/**\n\t* @param {JsCircuitValue256} x\n\t* @param {JsCircuitValue256} y\n\t* @returns {JsCircuitBn254G1Affine}\n\t*/\n\tto_js_circuit_bn254_g1_affine(x: JsCircuitValue256, y: JsCircuitValue256): JsCircuitBn254G1Affine;\n\t/**\n\t* @param {JsCircuitValue256} c0\n\t* @param {JsCircuitValue256} c1\n\t* @returns {JsCircuitBn254Fq2}\n\t*/\n\tto_js_circuit_bn254_fq2(c0: JsCircuitValue256, c1: JsCircuitValue256): JsCircuitBn254Fq2;\n\t/**\n\t* @param {JsCircuitBn254Fq2} x\n\t* @param {JsCircuitBn254Fq2} y\n\t* @returns {JsCircuitBn254G2Affine}\n\t*/\n\tto_js_circuit_bn254_g2_affine(x: JsCircuitBn254Fq2, y: JsCircuitBn254Fq2): JsCircuitBn254G2Affine;\n\t/**\n\t* @param {JsCircuitValue256} x\n\t* @param {JsCircuitValue256} y\n\t* @returns {JsCircuitSecp256k1Affine}\n\t*/\n\tto_js_circuit_secp256k1_affine(x: JsCircuitValue256, y: JsCircuitValue256): JsCircuitSecp256k1Affine;\n\t/**\n\t* @param {Halo2Wasm} circuit\n\t*/\n\tconstructor(circuit: Halo2Wasm);\n\t/**\n\t*/\n\tconfig(): void;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tadd(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tsub(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @returns {number}\n\t*/\n\tneg(a: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tmul(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {number} c\n\t* @returns {number}\n\t*/\n\tmul_add(a: number, b: number, c: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tmul_not(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t*/\n\tassert_bit(a: number): void;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tdiv_unsafe(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t*/\n\tassert_is_const(a: number, b: string): void;\n\t/**\n\t* @param {Uint32Array} a\n\t* @param {Uint32Array} b\n\t* @returns {number}\n\t*/\n\tinner_product(a: Uint32Array, b: Uint32Array): number;\n\t/**\n\t* @param {Uint32Array} a\n\t* @returns {number}\n\t*/\n\tsum(a: Uint32Array): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tand(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tor(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @returns {number}\n\t*/\n\tnot(a: number): number;\n\t/**\n\t* @param {number} a\n\t* @returns {number}\n\t*/\n\tdec(a: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {number} sel\n\t* @returns {number}\n\t*/\n\tselect(a: number, b: number, sel: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {number} c\n\t* @returns {number}\n\t*/\n\tor_and(a: number, b: number, c: number): number;\n\t/**\n\t* @param {Uint32Array} a\n\t* @returns {Uint32Array}\n\t*/\n\tbits_to_indicator(a: Uint32Array): Uint32Array;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t* @returns {Uint32Array}\n\t*/\n\tidx_to_indicator(a: number, b: string): Uint32Array;\n\t/**\n\t* @param {Uint32Array} a\n\t* @param {Uint32Array} indicator\n\t* @returns {number}\n\t*/\n\tselect_by_indicator(a: Uint32Array, indicator: Uint32Array): number;\n\t/**\n\t* @param {Uint32Array} a\n\t* @param {number} idx\n\t* @returns {number}\n\t*/\n\tselect_from_idx(a: Uint32Array, idx: number): number;\n\t/**\n\t* @param {number} a\n\t* @returns {number}\n\t*/\n\tis_zero(a: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @returns {number}\n\t*/\n\tis_equal(a: number, b: number): number;\n\t/**\n\t* @param {number} a\n\t* @param {string} num_bits\n\t* @returns {Uint32Array}\n\t*/\n\tnum_to_bits(a: number, num_bits: string): Uint32Array;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t*/\n\tconstrain_equal(a: number, b: number): void;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t*/\n\trange_check(a: number, b: string): void;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {string} size\n\t*/\n\tcheck_less_than(a: number, b: number, size: string): void;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t*/\n\tcheck_less_than_safe(a: number, b: string): void;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {string} size\n\t* @returns {number}\n\t*/\n\tis_less_than(a: number, b: number, size: string): number;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t* @returns {number}\n\t*/\n\tis_less_than_safe(a: number, b: string): number;\n\t/**\n\t* @param {number} a\n\t* @param {string} b\n\t* @param {string} size\n\t* @returns {Uint32Array}\n\t*/\n\tdiv_mod(a: number, b: string, size: string): Uint32Array;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {string} a_size\n\t* @param {string} b_size\n\t* @returns {Uint32Array}\n\t*/\n\tdiv_mod_var(a: number, b: number, a_size: string, b_size: string): Uint32Array;\n\t/**\n\t* @param {number} a\n\t* @param {number} b\n\t* @param {string} max_bits\n\t* @returns {number}\n\t*/\n\tpow_var(a: number, b: number, max_bits: string): number;\n\t/**\n\t* @param {Uint32Array} a\n\t* @returns {number}\n\t*/\n\tposeidon(a: Uint32Array): number;\n\t/**\n\t* @param {string} val\n\t* @returns {number}\n\t*/\n\twitness(val: string): number;\n\t/**\n\t* @param {string} val\n\t* @returns {number}\n\t*/\n\tconstant(val: string): number;\n\t/**\n\t* @param {Halo2Wasm} circuit\n\t* @param {number} a\n\t* @param {number} col\n\t*/\n\tmake_public(circuit: Halo2Wasm, a: number, col: number): void;\n\t/**\n\t* @param {Halo2Wasm} circuit\n\t* @param {number} a\n\t*/\n\tlog(circuit: Halo2Wasm, a: number): void;\n\t/**\n\t* @param {number} a\n\t* @returns {string}\n\t*/\n\tvalue(a: number): string;\n\t/**\n\t* @returns {number}\n\t*/\n\tlookup_bits(): number;\n}\ndeclare class Halo2Wasm {\n\tfree(): void;\n\t/**\n\t*/\n\tconstructor();\n\t/**\n\t*/\n\tclear(): void;\n\t/**\n\t*/\n\tclearInstances(): void;\n\t/**\n\t* @param {Uint8Array} proof\n\t*/\n\tverify(proof: Uint8Array): void;\n\t/**\n\t* @param {number} col\n\t* @returns {Uint32Array}\n\t*/\n\tgetInstances(col: number): Uint32Array;\n\t/**\n\t* @param {Uint32Array} instances\n\t* @param {number} col\n\t*/\n\tsetInstances(instances: Uint32Array, col: number): void;\n\t/**\n\t* @param {number} col\n\t* @returns {any}\n\t*/\n\tgetInstanceValues(col: number): any;\n\t/**\n\t* @param {CircuitConfig} config\n\t*/\n\tconfig(config: CircuitConfig): void;\n\t/**\n\t* @returns {CircuitStats}\n\t*/\n\tgetCircuitStats(): CircuitStats;\n\t/**\n\t* @returns {Uint8Array}\n\t*/\n\tgetVk(): Uint8Array;\n\t/**\n\t* @returns {Uint8Array}\n\t*/\n\tgetPartialVk(): Uint8Array;\n\t/**\n\t* @returns {Uint8Array}\n\t*/\n\tgetPk(): Uint8Array;\n\t/**\n\t*/\n\tassignInstances(): void;\n\t/**\n\t*/\n\tmock(): void;\n\t/**\n\t* @param {Uint8Array} params\n\t*/\n\tloadParams(params: Uint8Array): void;\n\t/**\n\t* @param {Uint8Array} vk\n\t*/\n\tloadVk(vk: Uint8Array): void;\n\t/**\n\t* @param {Uint8Array} pk\n\t*/\n\tloadPk(pk: Uint8Array): void;\n\t/**\n\t*/\n\tgenVk(): void;\n\t/**\n\t*/\n\tgenPk(): void;\n\t/**\n\t* @returns {Uint8Array}\n\t*/\n\tprove(): Uint8Array;\n\t/**\n\t* For console logging only.\n\t* @param {string} a\n\t*/\n\tlog(a: string): void;\n}\ndeclare class JsCircuitBn254Fq2 {\n\tfree(): void;\n\t/**\n\t* @param {JsCircuitValue256} c0\n\t* @param {JsCircuitValue256} c1\n\t*/\n\tconstructor(c0: JsCircuitValue256, c1: JsCircuitValue256);\n\t/**\n\t*/\n\tc0: JsCircuitValue256;\n\t/**\n\t*/\n\tc1: JsCircuitValue256;\n}\ndeclare class JsCircuitBn254G1Affine {\n\tfree(): void;\n\t/**\n\t* @param {JsCircuitValue256} x\n\t* @param {JsCircuitValue256} y\n\t*/\n\tconstructor(x: JsCircuitValue256, y: JsCircuitValue256);\n\t/**\n\t*/\n\tx: JsCircuitValue256;\n\t/**\n\t*/\n\ty: JsCircuitValue256;\n}\ndeclare class JsCircuitBn254G2Affine {\n\tfree(): void;\n\t/**\n\t* @param {JsCircuitBn254Fq2} x\n\t* @param {JsCircuitBn254Fq2} y\n\t*/\n\tconstructor(x: JsCircuitBn254Fq2, y: JsCircuitBn254Fq2);\n\t/**\n\t*/\n\tx: JsCircuitBn254Fq2;\n\t/**\n\t*/\n\ty: JsCircuitBn254Fq2;\n}\ndeclare class JsCircuitSecp256k1Affine {\n\tfree(): void;\n\t/**\n\t* @param {JsCircuitValue256} x\n\t* @param {JsCircuitValue256} y\n\t*/\n\tconstructor(x: JsCircuitValue256, y: JsCircuitValue256);\n\t/**\n\t*/\n\tx: JsCircuitValue256;\n\t/**\n\t*/\n\ty: JsCircuitValue256;\n}\ndeclare class JsCircuitValue256 {\n\tfree(): void;\n\t/**\n\t* @param {number} hi\n\t* @param {number} lo\n\t*/\n\tconstructor(hi: number, lo: number);\n\t/**\n\t*/\n\thi: number;\n\t/**\n\t*/\n\tlo: number;\n}\ndeclare class Secp256k1AffinePoint {\n\tfree(): void;\n\t/**\n\t* @returns {Secp256k1FpPoint}\n\t*/\n\tx(): Secp256k1FpPoint;\n\t/**\n\t* @returns {Secp256k1FpPoint}\n\t*/\n\ty(): Secp256k1FpPoint;\n}\ndeclare class Secp256k1FpPoint {\n\tfree(): void;\n\t/**\n\t* @param {Halo2LibWasm} lib_wasm\n\t* @returns {JsCircuitValue256}\n\t*/\n\tto_circuit_value_256(lib_wasm: Halo2LibWasm): JsCircuitValue256;\n}\ndeclare class CircuitValue256 {\n\tprivate _value;\n\tprivate _circuitValue;\n\tprivate _halo2Lib;\n\tconstructor(_halo2Lib: Halo2LibWasm, { value, hi, lo, }: {\n\t\tvalue?: bigint | string | number;\n\t\thi?: CircuitValue;\n\t\tlo?: CircuitValue;\n\t});\n\thi(): CircuitValue;\n\tlo(): CircuitValue;\n\thex(): string;\n\tvalue(): bigint;\n\ttoCircuitValue(): CircuitValue;\n}\ndeclare class CircuitValue {\n\tprivate _value;\n\tprivate _cell;\n\tprivate _circuit;\n\tconstructor(circuit: Halo2LibWasm, { value, cell }: {\n\t\tvalue?: bigint | number | string;\n\t\tcell?: number;\n\t});\n\tcell(): number;\n\tvalue(): bigint;\n\tnumber(): number;\n\taddress(): string;\n\ttoCircuitValue256(): CircuitValue256;\n}\ninterface CircuitBn254Fq2 {\n\tc0: CircuitValue256;\n\tc1: CircuitValue256;\n}\ninterface CircuitBn254G1Affine {\n\tx: CircuitValue256;\n\ty: CircuitValue256;\n}\ninterface CircuitBn254G2Affine {\n\tx: CircuitBn254Fq2;\n\ty: CircuitBn254Fq2;\n}\ninterface CircuitSecp256k1Affine {\n\tx: CircuitValue256;\n\ty: CircuitValue256;\n}\ntype RawCircuitInput = string | number | bigint;\n/**\n * Creates a circuit variable from a number, bigint, or string.\n *\n * @param a The raw circuit input.\n * @returns The witness cell.\n */\ndeclare const witness: (a: RawCircuitInput) => CircuitValue;\n/**\n * Creates a circuit constant from a number, bigint, or string.\n *\n * @param a The raw circuit input.\n * @returns The constant cell.\n */\ndeclare const constant: (a: RawCircuitInput) => CircuitValue;\n/**\n * Adds two circuit values.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The sum of the two circuit values.\n */\ndeclare const add: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Subtracts the second circuit value from the first circuit value.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The difference between the two circuit values.\n */\ndeclare const sub: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Negates a circuit value.\n *\n * @param a The circuit value to negate.\n * @returns The negation of the circuit value.\n */\ndeclare const neg: (a: CircuitValue) => CircuitValue;\n/**\n * Multiplies two circuit values.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The product of the two circuit values.\n */\ndeclare const mul: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Multiplies two circuit values and adds a third circuit value.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @param c The third circuit value.\n * @returns The result of multiplying the first two circuit values and adding the third circuit value.\n */\ndeclare const mulAdd: (a: CircuitValue, b: CircuitValue, c: CircuitValue) => CircuitValue;\n/**\n * Multiplies a circuit value by the negation of another circuit value.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The result of multiplying the first circuit value by the negation of the second circuit value.\n */\ndeclare const mulNot: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Asserts that a circuit value is a bit.\n *\n * @param a The circuit value to assert.\n */\ndeclare const assertBit: (a: CircuitValue) => void;\n/**\n * Asserts that a circuit value is a constant.\n *\n * @param a The circuit value to assert.\n * @param b The raw circuit input.\n */\ndeclare const assertIsConst: (a: CircuitValue, b: RawCircuitInput) => void;\n/**\n * Computes the inner product of two arrays of circuit values.\n *\n * @param a The first array of circuit values.\n * @param b The second array of circuit values.\n * @returns The inner product of the two arrays.\n */\ndeclare const innerProduct: (a: CircuitValue[], b: CircuitValue[]) => CircuitValue;\n/**\n * Computes the sum of an array of circuit values.\n *\n * @param arr The array of circuit values.\n * @returns The sum of the array of circuit values.\n */\ndeclare const sum: (arr: CircuitValue[]) => CircuitValue;\n/**\n * Performs a bitwise AND operation on two circuit values.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The result of the bitwise AND operation.\n */\ndeclare const and: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Performs a bitwise OR operation on two circuit values.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The result of the bitwise OR operation.\n */\ndeclare const or: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Performs a bitwise NOT operation on a circuit value.\n *\n * @param a The circuit value.\n * @returns The result of the bitwise NOT operation.\n */\ndeclare const not: (a: CircuitValue) => CircuitValue;\n/**\n * Decrements a circuit value by 1.\n *\n * @param a The circuit value.\n * @returns The decremented circuit value.\n */\ndeclare const dec: (a: CircuitValue) => CircuitValue;\n/**\n * Selects a circuit value based on a condition.\n *\n * @param a The first circuit value.\n * @param b The first circuit value.\n * @param sel The condition boolean circuit value.\n * @returns sel ? a : b\n */\ndeclare const select: (a: CircuitValue, b: CircuitValue, sel: CircuitValue) => CircuitValue;\n/**\n * Performs a bitwise OR-AND operation on three circuit values.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @param c The third circuit value.\n * @returns The result of the OR-AND operation.\n */\ndeclare const orAnd: (a: CircuitValue, b: CircuitValue, c: CircuitValue) => CircuitValue;\n/**\n * Converts an array of circuit values to an indicator array.\n *\n * @param bits The array of circuit values.\n * @returns The indicator circuit value.\n */\ndeclare const bitsToIndicator: (bits: CircuitValue[]) => CircuitValue[];\n/**\n * Converts an index circuit value to an indicator circuit value.\n *\n * @param idx The index circuit value.\n * @param len The length of the indicator circuit value.\n * @returns The indicator circuit value.\n */\ndeclare const idxToIndicator: (idx: CircuitValue, len: RawCircuitInput) => CircuitValue[];\n/**\n * Selects circuit values from an array based on an indicator circuit value.\n *\n * @param arr The array of circuit values.\n * @param indicator The indicator circuit value.\n * @returns The selected circuit values.\n */\ndeclare const selectByIndicator: (arr: CircuitValue[], indicator: CircuitValue[]) => CircuitValue;\n/**\n * Selects a circuit value from an array based on an index circuit value.\n *\n * @param arr The array of circuit values.\n * @param idx The index circuit value.\n * @returns The selected circuit value.\n */\ndeclare const selectFromIdx: (arr: CircuitValue[], idx: CircuitValue) => CircuitValue;\n/**\n * Checks if a circuit value is zero.\n *\n * @param a The circuit value to check.\n * @returns The indicator circuit value representing whether the input is zero.\n */\ndeclare const isZero: (a: CircuitValue) => CircuitValue;\n/**\n * Checks if two circuit values are equal.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @returns The indicator circuit value representing whether the two inputs are equal.\n */\ndeclare const isEqual: (a: CircuitValue, b: CircuitValue) => CircuitValue;\n/**\n * Converts a circuit value to an array of bits.\n *\n * @param a The circuit value to convert.\n * @param len The length of the resulting bit array.\n * @returns The array of bits representing the input circuit value.\n */\ndeclare const numToBits: (a: CircuitValue, len: RawCircuitInput) => CircuitValue[];\n/**\n * Asserts that two circuit values are equal.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n */\ndeclare const checkEqual: (a: CircuitValue, b: CircuitValue) => void;\n/**\n * Checks if a circuit value is within a specified range.\n *\n * @param a The circuit value to check.\n * @param b The range of the circuit value.\n */\ndeclare const rangeCheck: (a: CircuitValue, b: RawCircuitInput) => void;\n/**\n * Checks if the first circuit value is less than the second circuit value.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @param c The range of the circuit values.\n */\ndeclare const checkLessThan: (a: CircuitValue, b: CircuitValue, c?: string) => void;\n/**\n * Checks if the first circuit value is less than the second circuit value.\n *\n * @param a The first circuit value.\n * @param b The second circuit value.\n * @param c The range of the circuit values.\n * @returns The indicator circuit value representing whether the first input is less than the second input.\n */\ndeclare const isLessThan: (a: CircuitValue, b: CircuitValue, c?: string) => CircuitValue;\n/**\n * Divides two circuit values and returns the quotient.\n *\n * @param a The dividend circuit value.\n * @param b The divisor circuit value.\n * @returns The quotient.\n *\n */\ndeclare const div: (a: CircuitValue, b: CircuitValue, c?: string, d?: string) => CircuitValue;\n/**\n * Divides two circuit values and returns the remainder.\n *\n * @param a The dividend circuit value.\n * @param b The divisor circuit value.\n * @returns The remainder.\n *\n */\ndeclare const mod: (a: CircuitValue, b: CircuitValue, c?: string, d?: string) => CircuitValue;\n/**\n * Raises a circuit value to the power of another circuit value.\n *\n * @param a The base circuit value.\n * @param b The exponent circuit value.\n * @returns The result of the exponentiation.\n */\ndeclare const pow: (a: CircuitValue, b: CircuitValue, c?: string) => CircuitValue;\n/**\n * Computes the Poseidon hash of multiple circuit values.\n *\n * @param args The circuit values to hash.\n * @returns The hash value.\n */\ndeclare const poseidon: (...args: CircuitValue[]) => CircuitValue;\n/**\n * Retrieves the value of a circuit value.\n *\n * @param a The circuit value.\n * @returns The value of the circuit value.\n */\ndeclare const value: (a: CircuitValue) => any;\n/**\n * Logs the provided *circuit* values to the console. Use `console.log` for normal logging.\n *\n * @param args The `CircuitValue`s to log.\n */\ndeclare const log: (...args: any) => void;\ndeclare const console: {\n\t/**\n\t * Logs any *non CircuitValue* to the console. Use `log` for logging `CircuitValue`s.\n\t * @param args The values to log.\n\t */\n\tlog: (...args: any) => void;\n};\ndeclare const ecdsaBenchmark: (sk: bigint, msg_hash: bigint, k: bigint) => CircuitValue;\n/**\n * Creates new `CircuitValue256` and range checks `hi, lo` to be `uint128`s.\n * @param hi\n * @param lo\n * @returns\n */\ndeclare const newCircuitValue256: (hi: CircuitValue, lo: CircuitValue) => CircuitValue256;\n//ecc\n/**\n *\n * @param val The field point to load, in hi-lo form. The hi, lo values must have been constrained to be `uint128`s.\n * @returns `Bn254FqPoint` whose internals are opaque to the user.\n */\ndeclare const loadBn254Fq: (val: CircuitValue256) => Bn254FqPoint;\n/**\n *\n * @param val\n * @returns `val` in hi-lo form\n */\ndeclare const convertBn254FqToCircuitValue256: (val: Bn254FqPoint) => CircuitValue256;\n/**\n * @param point The affine point to load, with coordinates `CircuitValue256`. The hi, lo values must have been constrained to be `uint128`s.\n * @returns `Bn254G1AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (0, 0).\n */\ndeclare const loadBn254G1: (point: CircuitBn254G1Affine) => Bn254G1AffinePoint;\n/**\n * Sums the values of the provided G1 affine points\n *\n * @param points - The array of `CircuitBn254G1Affine` points. All coordinates are in hi, lo form, and we assume they have been range checked to be `uint128`s.\n * @returns The sum of all these points as `Bn254G1AffinePoint`.\n */\ndeclare const bn254G1Sum: (points: Array) => Bn254G1AffinePoint;\n/**\n * Subtracts the 2 points and returns the value. Constrains that the points are not equal and also one is not the negative of the other (this would be a point doubling, which requires a different formula).\n *\n * @returns The subtraction of these points.\n * @param g1Point1 - G1 point, x,y in hi lo format for each coordinate\n * @param g1Point2 - G1 point, x,y in hi lo format for each coordinate\n */\ndeclare const bn254G1SubUnequal: (g1Point1: CircuitBn254G1Affine, g1Point2: CircuitBn254G1Affine) => Bn254G1AffinePoint;\n/**\n * @param point The affine point to load, with coordinates `CircuitBn254Fq2`. The hi, lo values must have been constrained to be `uint128`s.\n * @returns `Bn254G2AffinePoint`, which has been constrained to lie on the curve. Currently this point is not allowed to be identity (Fq2(0), Fq2(0)).\n */\ndeclare const loadBn254G2: (point: CircuitBn254G2Affine) => Bn254G2AffinePoint;\n/**\n * Sums the values of the provided G2 affine points\n *\n * @param points - The array of `CircuitBn254G2Affine` points. All coordinates are `CircuitBn254Fq2`, whose coordinates are in hi, lo form, and we assume the hi, lo's have been range checked to be `uint128`s.\n * @returns The sum of all these points as `Bn254G2AffinePoint`.\n */\ndeclare const bn254G2Sum: (points: Array) => Bn254G2AffinePoint;\n/**\n * Verifies that e(lhsG1, lhsG2) = e(rhsG1, rhsG2) by checking e(lhsG1, lhsG2)*e(-rhsG1, rhsG2) === 1\n * None of the points should be identity.\n *\n * @param lhsG1\n * @param lhsG2\n * @param rhsG1\n * @param rhsG2\n * @returns [CircuitValue] for the result as a boolean (1 if signature verification is successful).\n */\ndeclare const bn254PairingCheck: (lhsG1: Bn254G1AffinePoint, lhsG2: Bn254G2AffinePoint, rhsG1: Bn254G1AffinePoint, rhsG2: Bn254G2AffinePoint) => CircuitValue;\n/**\n * @param pubkey The public key to load, in the form of an affine elliptic curve point `(x, y)` where `x, y` have type `CircuitValue256`. The hi, lo values of each `CircuitValue256` must have been constrained to be `uint128`s.\n * @returns `Secp256k1AffinePoint`, the public key as a loaded elliptic curve point. This has been constrained to lie on the curve. The public key is constrained to not be the identity (0, 0).\n */\ndeclare const loadSecp256k1Pubkey: (pubkey: CircuitSecp256k1Affine) => Secp256k1AffinePoint;\n/**\n *\n * Verifies the ECDSA signature `(r, s)` with message hash `msgHash` using the secp256k1 public key `pubkey`. Returns 1 if the signature is valid, 0 otherwise.\n * @param pubkey\n * @param r\n * @param s\n * @param msgHash\n * @returns\n */\ndeclare const verifySecp256k1ECDSASignature: (pubkey: Secp256k1AffinePoint, r: CircuitValue256, s: CircuitValue256, msgHash: CircuitValue256) => CircuitValue;\n\n{};\n"; \ No newline at end of file diff --git a/halo2-lib-js/src/shared/docs/makePublicDocs.ts b/halo2-lib-js/src/shared/docs/makePublicDocs.ts deleted file mode 100644 index 01df889..0000000 --- a/halo2-lib-js/src/shared/docs/makePublicDocs.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const makePublicDocs = ` -/** - * Makes a circuit value public. - * - * @param a The circuit value to make public. - */ -declare const makePublic: (a: CircuitValue) => void; -` \ No newline at end of file diff --git a/halo2-lib-js/src/shared/index.ts b/halo2-lib-js/src/shared/index.ts index 9af4f1c..4ef6a2c 100644 --- a/halo2-lib-js/src/shared/index.ts +++ b/halo2-lib-js/src/shared/index.ts @@ -1,5 +1,2 @@ -export { halo2Docs } from './docs/halo2Docs' -export { makePublicDocs } from './docs/makePublicDocs' -export { captureConsoleOutput } from './log' -export { RawCircuitInput } from './types' -export { convertInput } from './utils' \ No newline at end of file +export { RawCircuitInput, ConstantValue } from './types' +export { convertRawInput } from './utils' \ No newline at end of file diff --git a/halo2-lib-js/src/shared/log.ts b/halo2-lib-js/src/shared/log.ts deleted file mode 100644 index 2033bdd..0000000 --- a/halo2-lib-js/src/shared/log.ts +++ /dev/null @@ -1,37 +0,0 @@ -export function captureConsoleOutput(cb: any, log: any, time: any, timeEnd: any): () => number[] { - const originalLog = log; - const originalTime = time; - const originalTimeEnd = timeEnd; - let timeArray = [] as number[]; - - const timeLogs = {} as any; - - //@ts-ignore - console.log = function (...args) { - cb(args[0]); - // originalLog.apply(console, args); - }; - - console.time = function (label: string) { - timeLogs[label] = performance.now(); - }; - - console.timeEnd = function (label: string) { - const startTime = timeLogs[label]; - if (startTime !== undefined) { - const endTime = performance.now(); - const duration = endTime - startTime; - // originalLog.apply(console, [`%c${label}:`, 'color: #0074D9; font-weight: bold', `${duration.toFixed(2)}ms`]) - cb(`${label}: ${duration.toFixed(2)}ms`); - timeArray.push(duration); - delete timeLogs[label]; - } - }; - - return () => { - console.log = originalLog; - console.time = originalTime; - console.timeEnd = originalTimeEnd; - return timeArray; - }; -} \ No newline at end of file diff --git a/halo2-lib-js/src/shared/types.ts b/halo2-lib-js/src/shared/types.ts index abfcce3..e02318e 100644 --- a/halo2-lib-js/src/shared/types.ts +++ b/halo2-lib-js/src/shared/types.ts @@ -1 +1,2 @@ -export type RawCircuitInput = string | number | bigint; \ No newline at end of file +export type RawCircuitInput = string | number | bigint; +export type ConstantValue = RawCircuitInput; \ No newline at end of file diff --git a/halo2-lib-js/src/shared/utils.ts b/halo2-lib-js/src/shared/utils.ts index 7c86f1d..c3f98f9 100644 --- a/halo2-lib-js/src/shared/utils.ts +++ b/halo2-lib-js/src/shared/utils.ts @@ -12,11 +12,11 @@ export const joinArrays = (...args: any[]) => { return result; } -export const convertInput = (input: any): any => { +export const convertRawInput = (input: any): any => { if (typeof input === "string") { return BigInt(input).toString(); } else if (Array.isArray(input)) { - return input.map(convertInput); + return input.map(convertRawInput); } else if (typeof input === "number") { return input.toString(); } else if (typeof input === 'bigint') { diff --git a/halo2-lib-js/tests/.gitignore b/halo2-lib-js/tests/.gitignore new file mode 100644 index 0000000..9ae5112 --- /dev/null +++ b/halo2-lib-js/tests/.gitignore @@ -0,0 +1 @@ +circuits \ No newline at end of file diff --git a/halo2-lib-js/tests/gate.ts b/halo2-lib-js/tests/gate.ts new file mode 100644 index 0000000..664be29 --- /dev/null +++ b/halo2-lib-js/tests/gate.ts @@ -0,0 +1,117 @@ +import { writeCircuitToFile } from "./utils"; +import * as halo2Lib from "../src/halo2lib/functions"; + + +const buildGateTest = (inputs: number[], func: string) => { + return ` +import * as halo2Lib from "@axiom-crypto/halo2-lib-js"; +export const circuit = async (inputs: null) => { + const {constant, ${func}} = halo2Lib; + ${func}(${inputs.map((input) => `constant(${input})`).join(", ")}); +}`; +} + +const buildGateTestFn = (fn: (inputs: null) => void) => { + return `import * as halo2Lib from "@axiom-crypto/halo2-lib-js"; + export const circuit = async ${fn.toString()}`; +} + +const gateTest = (inputs: number[], func: string) => { + const circuit = buildGateTest(inputs, func); + writeCircuitToFile(circuit, `${func}.gate.ts`); +} + +const gateTestFn = (name: string, fn: (inputs: null) => void) => { + const circuit = buildGateTestFn(fn); + writeCircuitToFile(circuit, `${name}.gate.ts`); +} + +gateTest([15, 10], "add"); +gateTest([15, 10], "sub"); +gateTest([15], "neg"); +gateTest([15, 10], "mul"); +gateTest([15, 10, 10], "mulAdd"); +gateTest([15, 10], "mulNot"); +gateTest([1], "assertBit"); +gateTest([1, 1], "and"); +gateTest([1, 0], "or"); +gateTest([1], "not"); +gateTest([100], "dec"); +gateTest([1, 0, 1], "orAnd"); +gateTest([0], "isZero"); +gateTest([9, 5], "isEqual"); +gateTest([10, 5, 0], "select"); + +gateTestFn("assertIsConst", (_) => { + const { constant, assertIsConst } = halo2Lib; + assertIsConst(constant(15), 15); +}) + +gateTestFn("innerProduct", (_) => { + const { constant, innerProduct } = halo2Lib; + const inputs = [15, 10, 5].map(constant); + innerProduct(inputs, inputs) +}) + +gateTestFn("powVar", (_) => { + const { constant, pow } = halo2Lib; + pow(constant(15), constant(10), "4") +}) + +gateTestFn("sum", (_) => { + const { constant, sum } = halo2Lib; + sum([constant(15), constant(10), constant(5)]) +}) + +gateTestFn("bitsToIndicator", (_) => { + const { constant, bitsToIndicator } = halo2Lib; + bitsToIndicator([1, 0, 0, 1, 0].map(constant)) +}) + +gateTestFn("idxToIndicator", ( _) => { + const { constant, idxToIndicator } = halo2Lib; + idxToIndicator(constant(8), 12) +}) + +gateTestFn("selectByIndicator", (_) => { + const { constant, selectByIndicator } = halo2Lib; + const input = ["1", "2", "3", "4"].map(constant); + const indicator = ["0", "0", "1", "0"].map(constant); + selectByIndicator(input, indicator) +}) + +gateTestFn("selectFromIdx", (_) => { + const { constant, selectFromIdx } = halo2Lib; + const input = ["1", "2", "3", "4"].map(constant); + selectFromIdx(input, constant(2)) +}) + +gateTestFn("numToBits", ( _) => { + const { constant, numToBits } = halo2Lib; + numToBits(constant(15), 5) +}) + +gateTestFn("constrainEqual", ( _) => { + const { constant, checkEqual } = halo2Lib; + checkEqual(constant(15), constant(15)) +}) + +gateTestFn("constant", (_) => { + const { constant } = halo2Lib; + constant(15) +}) + +gateTestFn("witness", (_) => { + const { witness } = halo2Lib; + witness(15) +}) + +gateTestFn("poseidon", ( _) => { + const { constant, poseidon } = halo2Lib; + poseidon(...["90", "50", "12", "12"].map(constant)) +}) + +gateTestFn("makePublic", (_) => { + const { constant, makePublic } = halo2Lib; + makePublic(constant(10)) +}) \ No newline at end of file diff --git a/halo2-lib-js/tests/range.ts b/halo2-lib-js/tests/range.ts new file mode 100644 index 0000000..f9be1cc --- /dev/null +++ b/halo2-lib-js/tests/range.ts @@ -0,0 +1,38 @@ +import { writeCircuitToFile } from "./utils"; +import * as halo2Lib from "../src/halo2lib/functions"; + +const buildGateTestFn = (fn: (inputs: null) => void) => { + return `import * as halo2Lib from "@axiom-crypto/halo2-lib-js"; + export const circuit = async ${fn.toString()}`; +} + +const rangeTest = (name: string, fn: (inputs: null) => void) => { + const circuit = buildGateTestFn(fn); + writeCircuitToFile(circuit, `${name}.range.ts`); +} + +rangeTest("rangeCheck", ( _) => { + const { witness, rangeCheck } = halo2Lib; + rangeCheck(witness(15141), 128) +}) + +rangeTest("checkLessThan", ( _) => { + const { witness, checkLessThan } = halo2Lib; + checkLessThan(witness(10), witness(15), "8") +}) + +rangeTest("isLessThan", (_) => { + const { witness, isLessThan } = halo2Lib; + isLessThan(witness(10), witness(15), "8") +}) + +rangeTest("divModVar", ( _) => { + const { witness, div } = halo2Lib; + div(witness(90), witness(50), "12", "12") +}); + +rangeTest("divModVar.1", (_) => { + const { witness, mod } = halo2Lib; + mod(witness(90), witness(50), "12", "12") +}); + diff --git a/halo2-lib-js/tests/run.ts b/halo2-lib-js/tests/run.ts new file mode 100644 index 0000000..8dafbfe --- /dev/null +++ b/halo2-lib-js/tests/run.ts @@ -0,0 +1,5 @@ +export const run = async (halo2wasm: any, halo2Lib: any, config: any, circuit: any, inputs: any) => { + //@ts-ignore -- to avoid halo2-lib-js being a dependency of the cli + const { Halo2CircuitRunner } = await import("@axiom-crypto/halo2-lib-js"); + await Halo2CircuitRunner(halo2wasm, halo2Lib, config).run(circuit, inputs); +} \ No newline at end of file diff --git a/halo2-lib-js/tests/test_constant.py b/halo2-lib-js/tests/test_constant.py new file mode 100644 index 0000000..1e62879 --- /dev/null +++ b/halo2-lib-js/tests/test_constant.py @@ -0,0 +1,58 @@ +import os +import subprocess +import re +import sys + +def camel_to_snake(name): + str1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', str1).lower() + +script_dir = os.path.dirname(os.path.abspath(__file__)) +circuit_dir = os.path.join(script_dir, 'circuits') +vk_dir = os.path.join(script_dir, 'data') + +def replace_text_in_file(file_path): + with open(file_path, 'r') as file: + file_data = file.read() + + file_data = re.sub(r'constant\((.*?)\)', r'\1', file_data) + with open(file_path, 'w') as file: + file.write(file_data) + +def test_constant(filename): + file_path = os.path.join(circuit_dir, filename) + if os.path.isfile(file_path): + test_name = camel_to_snake(filename.split('.')[0]) + if "constant" in filename: + return None + replace_text_in_file(file_path) + test_type = filename.split('.')[-2] + rust_test = "tests::" + test_type + "::test_" + test_name + print("Testing " + test_name) + subprocess.run(["npx", 'halo2-wasm', 'keygen', file_path, "-c", "./tests/run.ts"], capture_output=True) + subprocess.run(['cargo', 'test', rust_test, "--quiet", "--", "--exact"], capture_output=True) + result = subprocess.run(['diff', './data/vk.bin', '../halo2-wasm/vk.bin'], capture_output=True) + if result.returncode != 0: + return (test_name, False) + return (test_name, True) + + + +if len(sys.argv) > 1: + test_constant(sys.argv[1] + ".ts") +else: + passedTests = [] + failTests = [] + for filename in os.listdir(circuit_dir): + result = test_constant(filename) + if result is not None: + if result[1]: + passedTests.append(result[0]) + else: + failTests.append(result[0]) + print("Passed tests:") + print(passedTests) + print("Failed tests:") + print(failTests) + if len(failTests) > 0: + sys.exit(1) \ No newline at end of file diff --git a/halo2-lib-js/tests/test_constant.sh b/halo2-lib-js/tests/test_constant.sh new file mode 100755 index 0000000..24f78e3 --- /dev/null +++ b/halo2-lib-js/tests/test_constant.sh @@ -0,0 +1,5 @@ +rm -rf tests/circuits +mkdir tests/circuits +npx ts-node tests/range.ts +npx ts-node tests/gate.ts +python3 tests/test_constant.py \ No newline at end of file diff --git a/halo2-lib-js/tests/test_vk.py b/halo2-lib-js/tests/test_vk.py new file mode 100644 index 0000000..55b4755 --- /dev/null +++ b/halo2-lib-js/tests/test_vk.py @@ -0,0 +1,49 @@ +import os +import subprocess +import re +import sys + +def camel_to_snake(name): + str1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', str1).lower() + +script_dir = os.path.dirname(os.path.abspath(__file__)) +circuit_dir = os.path.join(script_dir, 'circuits') +vk_dir = os.path.join(script_dir, 'data') + +def test_vk(filename): + file_path = os.path.join(circuit_dir, filename) + if os.path.isfile(file_path): + test_name = camel_to_snake(filename.split('.')[0]) + test_type = filename.split('.')[-2] + rust_test = "tests::" + test_type + "::test_" + test_name + print("Testing " + test_name) + subprocess.run(["npx", 'halo2-wasm', 'keygen', file_path, "-c", "./tests/run.ts"]) + subprocess.run(['cargo', 'test', rust_test, "--quiet", "--", "--exact"]) + result = subprocess.run(['diff', './data/vk.bin', '../halo2-wasm/vk.bin'], capture_output=True) + if result.returncode != 0: + print(result.stderr) + print(result.stdout) + return (test_name, False) + return (test_name, True) + + + +if len(sys.argv) > 1: + test_vk(sys.argv[1] + ".ts") +else: + passedTests = [] + failTests = [] + for filename in os.listdir(circuit_dir): + result = test_vk(filename) + if result is not None: + if result[1]: + passedTests.append(result[0]) + else: + failTests.append(result[0]) + print("Passed tests:") + print(passedTests) + print("Failed tests:") + print(failTests) + if len(failTests) > 0: + sys.exit(1) \ No newline at end of file diff --git a/halo2-lib-js/tests/test_vk.sh b/halo2-lib-js/tests/test_vk.sh new file mode 100755 index 0000000..897242f --- /dev/null +++ b/halo2-lib-js/tests/test_vk.sh @@ -0,0 +1,5 @@ +rm -rf tests/circuits +mkdir tests/circuits +npx ts-node tests/range.ts +npx ts-node tests/gate.ts +python3 tests/test_vk.py \ No newline at end of file diff --git a/halo2-lib-js/tests/utils.ts b/halo2-lib-js/tests/utils.ts new file mode 100644 index 0000000..9d22fd4 --- /dev/null +++ b/halo2-lib-js/tests/utils.ts @@ -0,0 +1,23 @@ +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import path from "path"; + +const config = { + k: 10, + numAdvice: 20, + numLookupAdvice: 3, + numInstance: 1, + numLookupBits: 9, + numVirtualInstance: 1, +} + +export const writeCircuitToFile = (circuit: string, relativePath: string) => { + const configStr = `export const config = ${JSON.stringify(config, null, 4)}\n`; + const inputStr = `export const inputs = {}\n`; + const filePath = path.resolve(__dirname, "./circuits", relativePath); + const folderPath = path.dirname(filePath); + if (!existsSync(folderPath)) { + mkdirSync(folderPath, { recursive: true }); + } + writeFileSync(filePath, configStr + inputStr + circuit); + console.log(`Wrote circuit to ${filePath}`); +} \ No newline at end of file diff --git a/halo2-lib-js/tsconfig.json b/halo2-lib-js/tsconfig.json index f4ce5e8..394dee4 100644 --- a/halo2-lib-js/tsconfig.json +++ b/halo2-lib-js/tsconfig.json @@ -3,7 +3,6 @@ "module": "commonjs", "target": "es2020", "moduleResolution": "node", - "rootDir": "src", "baseUrl": "src", "outDir": "dist", "lib": ["esnext", "DOM"], diff --git a/halo2-repl/app/page.tsx b/halo2-repl/app/page.tsx index 441cc34..c02fe8a 100644 --- a/halo2-repl/app/page.tsx +++ b/halo2-repl/app/page.tsx @@ -6,8 +6,7 @@ import Editor, { Monaco } from "@monaco-editor/react"; import { type editor } from 'monaco-editor'; import { useSearchParams, useRouter, usePathname } from "next/navigation"; import { Halo2Repl } from "./worker/halo2repl"; -import { halo2Docs } from "@axiom-crypto/halo2-lib-js/shared/docs/halo2Docs"; -import { makePublicDocs } from "@axiom-crypto/halo2-lib-js/shared/docs/makePublicDocs"; +import { halo2Docs } from "@axiom-crypto/halo2-lib-js/shared/docs"; import { DEFAULT_CIRCUIT_CONFIG } from "@axiom-crypto/halo2-lib-js/circuit/types"; import { DEFAULT_CODE, DEFAULT_INPUT } from "@/utils/constants"; import { fetchGist, fetchGithubAccessToken } from "@/utils/github"; @@ -200,7 +199,7 @@ function App() { appendLogs("Starting key generation. This may take up to a minute.") await workerApi.current?.keygen(); await workerApi.current?.stopConsoleCapture(); - const vk = await workerApi.current?.getVk(); + const vk = await workerApi.current?.getHalo2Vk(); if (vk) setCircuitVk(vk); }); }; @@ -221,7 +220,7 @@ function App() { } const downloadVk = async () => { - let vkExport = await workerApi.current?.exportVk(); + let vkExport = await workerApi.current?.exportHalo2Vk(); if (!vkExport) return; let a = document.createElement("a"); a.href = window.URL.createObjectURL(vkExport); @@ -279,7 +278,7 @@ function App() { target: monaco.languages.typescript.ScriptTarget.ES2020, lib: ["es2020"] }); - const docs = [{ docs: halo2Docs, name: "halo2lib.d.ts" }, { docs: makePublicDocs, name: "makePublic.d.ts" }]; + const docs = [{ docs: halo2Docs, name: "halo2lib.d.ts" }]; if (defaultInputs) { docs.push({ docs: parseCircuitTypes(defaultInputs), name: "inputs.d.ts" }) } diff --git a/halo2-repl/app/worker/halo2repl.ts b/halo2-repl/app/worker/halo2repl.ts index 57d33f6..c09c05c 100644 --- a/halo2-repl/app/worker/halo2repl.ts +++ b/halo2-repl/app/worker/halo2repl.ts @@ -1,8 +1,8 @@ import prettier from 'prettier/standalone'; import parserTypescript from 'prettier/parser-typescript'; -import { Halo2CircuitRunner, captureConsoleOutput } from '@axiom-crypto/halo2-lib-js'; -import { Halo2Lib } from '@axiom-crypto/halo2-lib-js'; +import { Halo2CircuitRunner } from '@axiom-crypto/halo2-lib-js'; import { Halo2LibWasm, getHalo2LibWasm, CircuitScaffold, getKzgParams, DEFAULT_CIRCUIT_CONFIG } from '@axiom-crypto/halo2-wasm/web' +import { captureConsoleOutput } from '@/utils/log'; export class Halo2Repl extends CircuitScaffold { @@ -39,23 +39,17 @@ export class Halo2Repl extends CircuitScaffold { this.stopConsoleCapture = captureConsoleOutput(cb, log, time, timeEnd); } - getVk() { - const vk = this.halo2wasm.getVk(); - return new Uint8Array(vk); - } - async exportCircuitCode() { if (!this.code) { console.log("Need to run populate circuit first"); return; } - let halo2Lib = new Halo2Lib(this.halo2wasm, this.halo2Lib); + let halo2Lib = await import("@axiom-crypto/halo2-lib-js"); let halo2libFns = Object.keys(halo2Lib).filter(fn => this.code.includes(fn)).join(", "); - let imports = `import { Halo2Lib } from "@axiom-crypto/halo2-js";\n` + let imports = `import { ${halo2libFns} } from "@axiom-crypto/halo2-lib-js";\n` let circuitInputImport = `import { CircuitInputs } from "./constants";\n\n` let codeInputs = Object.keys(JSON.parse(this.inputs)).join(", "); - let code = `export const circuit = async (halo2Lib: Halo2Lib, halo2Data: Halo2Data, { ${codeInputs} }: CircuitInputs) => { - const { ${halo2libFns} } = halo2Lib; + let code = `export const circuit = async ({ ${codeInputs} }: CircuitInputs) => { ${this.code} }\n` @@ -102,13 +96,6 @@ export class Halo2Repl extends CircuitScaffold { return blob; } - exportVk() { - const vk_arr = this.halo2wasm.getVk(); - const vk = "0x" + Buffer.from(vk_arr).toString('hex'); - const blob = new Blob([vk], { type: "text/plain" }); - return blob; - } - verify(proof: Uint8Array) { this.timeStart("SNARK proof verification") this.halo2wasm.verify(proof); diff --git a/halo2-repl/package.json b/halo2-repl/package.json index 2ba3f04..8f0ab57 100644 --- a/halo2-repl/package.json +++ b/halo2-repl/package.json @@ -9,8 +9,8 @@ "lint": "next lint" }, "dependencies": { - "@axiom-crypto/halo2-lib-js": "0.2.9", - "@axiom-crypto/halo2-wasm": "0.2.7", + "@axiom-crypto/halo2-lib-js": "0.2.13", + "@axiom-crypto/halo2-wasm": "0.2.10", "@devbookhq/splitter": "^1.4.2", "@headlessui/react": "^1.7.17", "@heroicons/react": "^2.0.18", diff --git a/halo2-repl/pnpm-lock.yaml b/halo2-repl/pnpm-lock.yaml index 63fec5b..da1f795 100644 --- a/halo2-repl/pnpm-lock.yaml +++ b/halo2-repl/pnpm-lock.yaml @@ -6,11 +6,11 @@ settings: dependencies: '@axiom-crypto/halo2-lib-js': - specifier: 0.2.9 - version: 0.2.9 + specifier: 0.2.13 + version: 0.2.13 '@axiom-crypto/halo2-wasm': - specifier: 0.2.7 - version: 0.2.7 + specifier: 0.2.10 + version: 0.2.10 '@devbookhq/splitter': specifier: ^1.4.2 version: 1.4.2 @@ -127,19 +127,19 @@ packages: '@jridgewell/trace-mapping': 0.3.19 dev: false - /@axiom-crypto/halo2-lib-js@0.2.9: - resolution: {integrity: sha512-U6XCsV6qROevV8c4CXSOj7uhPYZG7ugU0NlxvrHJvEOGc0GrNm4INVxByb8Eipq2X32jeP8wO3MMS6GlZUwkwQ==} + /@axiom-crypto/halo2-lib-js@0.2.13: + resolution: {integrity: sha512-pGU02OZxp9XYQylh7F7QaobrnOufljA5XQnxeeEsA4dqmBf0v/kS7GpPlhdG1rX/jM1yMmnBkw40ieg1CgbRRg==} dependencies: - '@axiom-crypto/halo2-wasm': 0.2.7 - ethers: 6.8.0 + '@axiom-crypto/halo2-wasm': 0.2.10 + ethers: 6.9.0 prettier: 1.18.2 transitivePeerDependencies: - bufferutil - utf-8-validate dev: false - /@axiom-crypto/halo2-wasm@0.2.7: - resolution: {integrity: sha512-pmgFCkCJUlFgh5NCLR59WpWIiBegNxBRAAlA2UxPMga1Pba02ynZgf6SW0tbQaezMiWUdTA9SfpeosovcNI6Yg==} + /@axiom-crypto/halo2-wasm@0.2.10: + resolution: {integrity: sha512-88VPIGeLUPYp+kIgKuJ4QBAKZ5SbwtJheBca5DuZdyb/9vGZ02gyeyQe6/2N7yVDIn3hupHhgfAc4mqm1/4ddw==} dev: false /@babel/code-frame@7.22.13: @@ -3122,8 +3122,8 @@ packages: - utf-8-validate dev: false - /ethers@6.8.0: - resolution: {integrity: sha512-zrFbmQRlraM+cU5mE4CZTLBurZTs2gdp2ld0nG/f3ecBK+x6lZ69KSxBqZ4NjclxwfTxl5LeNufcBbMsTdY53Q==} + /ethers@6.9.0: + resolution: {integrity: sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q==} engines: {node: '>=14.0.0'} dependencies: '@adraffy/ens-normalize': 1.10.0 diff --git a/halo2-repl/utils/log.ts b/halo2-repl/utils/log.ts new file mode 100644 index 0000000..55837bf --- /dev/null +++ b/halo2-repl/utils/log.ts @@ -0,0 +1,37 @@ +export function captureConsoleOutput(cb: any, log: any, time: any, timeEnd: any): () => number[] { + const originalLog = log; + const originalTime = time; + const originalTimeEnd = timeEnd; + let timeArray = [] as number[]; + + const timeLogs = {} as any; + + //@ts-ignore + console.log = function (...args) { + cb(args[0]); + // originalLog.apply(console, args); + }; + + console.time = function (label: string) { + timeLogs[label] = performance.now(); + }; + + console.timeEnd = function (label: string) { + const startTime = timeLogs[label]; + if (startTime !== undefined) { + const endTime = performance.now(); + const duration = endTime - startTime; + // originalLog.apply(console, [`%c${label}:`, 'color: #0074D9; font-weight: bold', `${duration.toFixed(2)}ms`]) + cb(`${label}: ${duration.toFixed(2)}ms`); + timeArray.push(duration); + delete timeLogs[label]; + } + }; + + return () => { + console.log = originalLog; + console.time = originalTime; + console.timeEnd = originalTimeEnd; + return timeArray; + }; + } \ No newline at end of file diff --git a/halo2-wasm/Cargo.toml b/halo2-wasm/Cargo.toml index 7d2f31b..239fcc4 100644 --- a/halo2-wasm/Cargo.toml +++ b/halo2-wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "halo2-wasm" -version = "0.2.8" +version = "0.2.10" edition = "2021" [lib] diff --git a/halo2-wasm/js/js/index.ts b/halo2-wasm/js/js/index.ts index 08b70a4..f69b93f 100644 --- a/halo2-wasm/js/js/index.ts +++ b/halo2-wasm/js/js/index.ts @@ -4,6 +4,7 @@ import { } from "../../pkg/js/halo2_wasm"; import { getKzgParams } from "../kzg"; import { DEFAULT_CIRCUIT_CONFIG } from "../shared"; +import { BaseCircuitScaffold } from "../shared/scaffold"; export { CircuitConfig, DEFAULT_CIRCUIT_CONFIG, Halo2Wasm, Halo2LibWasm, getKzgParams }; export { Bn254FqPoint, Bn254G1AffinePoint, Bn254G2AffinePoint, JsCircuitBn254Fq2, JsCircuitBn254G1Affine, JsCircuitBn254G2Affine, JsCircuitSecp256k1Affine, JsCircuitValue256, Secp256k1AffinePoint }; @@ -19,14 +20,9 @@ export const getHalo2LibWasm = (halo2wasm: Halo2Wasm) => { return halo2libwasm; } -export abstract class CircuitScaffold { - protected halo2wasm: Halo2Wasm; - protected config: CircuitConfig; - protected shouldTime: boolean; - protected proof: Uint8Array | null = null; - protected loadedVk: boolean; - +export abstract class CircuitScaffold extends BaseCircuitScaffold { constructor(options?: { config?: CircuitConfig, shouldTime?: boolean }) { + super() this.halo2wasm = getHalo2Wasm(); this.config = options?.config ?? { ...DEFAULT_CIRCUIT_CONFIG }; this.shouldTime = options?.shouldTime ?? false; @@ -34,70 +30,4 @@ export abstract class CircuitScaffold { this.halo2wasm.config(this.config); } - protected timeStart(name: string) { - if (this.shouldTime) console.time(name); - } - - protected timeEnd(name: string) { - if (this.shouldTime) console.timeEnd(name); - } - - newCircuitFromConfig(config: CircuitConfig) { - this.config = config; - this.halo2wasm.config(config); - } - - async loadParams() { - const kzgParams = await getKzgParams(this.config.k); - this.halo2wasm.loadParams(kzgParams); - } - - async loadParamsAndVk(vk: Uint8Array) { - await this.loadParams(); - this.halo2wasm.loadVk(vk); - this.loadedVk = true; - } - - mock() { - this.timeStart("Mock proving") - this.halo2wasm.mock() - this.timeEnd("Mock proving") - } - - async keygen() { - await this.loadParams(); - this.timeStart("VK generation") - this.halo2wasm.genVk(); - this.timeEnd("VK generation") - this.timeStart("PK generation") - this.halo2wasm.genPk(); - this.timeEnd("PK generation") - } - - prove() { - if (this.loadedVk) { - this.timeStart("PK generation"); - this.halo2wasm.genPk(); - this.timeEnd("PK generation"); - } - this.timeStart("SNARK proof generation") - let proof = this.halo2wasm.prove(); - this.timeEnd("SNARK proof generation") - this.proof = proof; - return proof; - } - - verify(proof: Uint8Array) { - this.timeStart("Verify SNARK proof") - this.halo2wasm.verify(proof); - this.timeEnd("Verify SNARK proof") - } - - getInstances(): string[] { - return this.halo2wasm.getInstanceValues(0); - } - - getCircuitStats() { - return this.halo2wasm.getCircuitStats(); - } } diff --git a/halo2-wasm/js/shared/scaffold.ts b/halo2-wasm/js/shared/scaffold.ts new file mode 100644 index 0000000..f2820ea --- /dev/null +++ b/halo2-wasm/js/shared/scaffold.ts @@ -0,0 +1,114 @@ +import { CircuitConfig, Halo2Wasm } from "../../pkg/web/halo2_wasm"; +import { getKzgParams } from "../kzg"; + +export abstract class BaseCircuitScaffold { + protected halo2wasm!: Halo2Wasm; + protected config: CircuitConfig; + protected shouldTime: boolean; + protected proof: Uint8Array | null = null; + protected loadedVk: boolean; + + protected timeStart(name: string) { + if (this.shouldTime) console.time(name); + } + + protected timeEnd(name: string) { + if (this.shouldTime) console.timeEnd(name); + } + + newCircuitFromConfig(config: CircuitConfig) { + this.config = config; + this.halo2wasm.config(config); + } + + async loadParams() { + const kzgParams = await getKzgParams(this.config.k); + this.halo2wasm.loadParams(kzgParams); + } + + async loadParamsAndVk(vk: Uint8Array) { + await this.loadParams(); + this.halo2wasm.loadVk(vk); + this.loadedVk = true; + } + + mock() { + this.timeStart("Mock proving") + this.halo2wasm.mock() + this.timeEnd("Mock proving") + } + + async keygen() { + await this.loadParams(); + this.timeStart("VK generation") + this.halo2wasm.genVk(); + this.timeEnd("VK generation") + this.timeStart("PK generation") + this.halo2wasm.genPk(); + this.timeEnd("PK generation") + } + + prove() { + if (this.loadedVk) { + this.timeStart("PK generation"); + this.halo2wasm.genPk(); + this.timeEnd("PK generation"); + } + this.timeStart("SNARK proof generation") + let proof = this.halo2wasm.prove(); + this.timeEnd("SNARK proof generation") + this.proof = proof; + return proof; + } + + verify(proof: Uint8Array) { + this.timeStart("Verify SNARK proof") + this.halo2wasm.verify(proof); + this.timeEnd("Verify SNARK proof") + } + + getInstances(): string[] { + return this.halo2wasm.getInstanceValues(0); + } + + getCircuitStats() { + return this.halo2wasm.getCircuitStats(); + } + + getHalo2Vk() { + const vk = this.halo2wasm.getVk(); + return new Uint8Array(vk); + } + + exportHalo2Vk() { + const vk_arr = this.halo2wasm.getVk(); + const vk = "0x" + Buffer.from(vk_arr).toString('hex'); + const blob = new Blob([vk], { type: "text/plain" }); + return blob; + } + + getPartialVk() { + return this.halo2wasm.getPartialVk(); + } + + exportPartialVk() { + const vk = this.halo2wasm.getPartialVk(); + const hexVk = "0x" + Buffer.from(vk).toString("hex"); + const blob = new Blob([hexVk], { type: "text/plain" }); + return blob; + } + + getProof() { + if (!this.proof) throw new Error("No proof to export"); + return this.proof; + } + + exportProof() { + const proof = this.getProof(); + const proofHex = "0x" + Buffer.from(proof).toString('hex'); + const blob = new Blob([proofHex], { type: "text/plain" }); + return blob; + } + + +} diff --git a/halo2-wasm/js/web/index.ts b/halo2-wasm/js/web/index.ts index 8800fe3..eb834c5 100644 --- a/halo2-wasm/js/web/index.ts +++ b/halo2-wasm/js/web/index.ts @@ -4,6 +4,7 @@ import init, { } from "../../pkg/web/halo2_wasm"; import { getKzgParams } from "../kzg"; import { DEFAULT_CIRCUIT_CONFIG } from "../shared"; +import { BaseCircuitScaffold } from "../shared/scaffold"; export { CircuitConfig, DEFAULT_CIRCUIT_CONFIG, Halo2Wasm, Halo2LibWasm, getKzgParams }; export { Bn254FqPoint, Bn254G1AffinePoint, Bn254G2AffinePoint, JsCircuitBn254Fq2, JsCircuitBn254G1Affine, JsCircuitBn254G2Affine, JsCircuitSecp256k1Affine, JsCircuitValue256, Secp256k1AffinePoint }; @@ -23,14 +24,10 @@ export const getHalo2LibWasm = (halo2wasm: Halo2Wasm) => { return halo2libwasm; } -export abstract class CircuitScaffold { - protected halo2wasm!: Halo2Wasm; - protected config: CircuitConfig; - protected shouldTime: boolean; - protected proof: Uint8Array | null = null; - protected loadedVk: boolean; +export abstract class CircuitScaffold extends BaseCircuitScaffold { constructor(options?: { config?: CircuitConfig, shouldTime?: boolean }) { + super(); this.config = options?.config ?? { ...DEFAULT_CIRCUIT_CONFIG }; this.shouldTime = options?.shouldTime ?? false; this.loadedVk = false; @@ -40,71 +37,4 @@ export abstract class CircuitScaffold { this.halo2wasm = await getHalo2Wasm(numThreads); this.halo2wasm.config(this.config); } - - protected timeStart(name: string) { - if (this.shouldTime) console.time(name); - } - - protected timeEnd(name: string) { - if (this.shouldTime) console.timeEnd(name); - } - - newCircuitFromConfig(config: CircuitConfig) { - this.config = config; - this.halo2wasm.config(config); - } - - async loadParams() { - const kzgParams = await getKzgParams(this.config.k); - this.halo2wasm.loadParams(kzgParams); - } - - async loadParamsAndVk(vk: Uint8Array) { - await this.loadParams(); - this.halo2wasm.loadVk(vk); - this.loadedVk = true; - } - - mock() { - this.timeStart("Mock proving") - this.halo2wasm.mock() - this.timeEnd("Mock proving") - } - - async keygen() { - await this.loadParams(); - this.timeStart("VK generation") - this.halo2wasm.genVk(); - this.timeEnd("VK generation") - this.timeStart("PK generation") - this.halo2wasm.genPk(); - this.timeEnd("PK generation") - } - - prove() { - if (this.loadedVk) { - this.timeStart("PK generation"); - this.halo2wasm.genPk(); - this.timeEnd("PK generation"); - } - this.timeStart("SNARK proof generation") - let proof = this.halo2wasm.prove(); - this.timeEnd("SNARK proof generation") - this.proof = proof; - return proof; - } - - verify(proof: Uint8Array) { - this.timeStart("Verify SNARK proof") - this.halo2wasm.verify(proof); - this.timeEnd("Verify SNARK proof") - } - - getInstances(): string[] { - return this.halo2wasm.getInstanceValues(0); - } - - getCircuitStats() { - return this.halo2wasm.getCircuitStats(); - } } diff --git a/halo2-wasm/package.json b/halo2-wasm/package.json index 02df4cf..0c657d6 100644 --- a/halo2-wasm/package.json +++ b/halo2-wasm/package.json @@ -1,7 +1,7 @@ { "name": "@axiom-crypto/halo2-wasm", "description": "Halo2 wasm bindings", - "version": "0.2.8", + "version": "0.2.10", "main": "index.js", "types": "index.d.ts", "scripts": { diff --git a/halo2-wasm/scripts/build.sh b/halo2-wasm/scripts/build.sh index 50d0a8e..84bf68c 100755 --- a/halo2-wasm/scripts/build.sh +++ b/halo2-wasm/scripts/build.sh @@ -14,3 +14,6 @@ sed -i '' 's#\.\./\.\./pkg/js/halo2_wasm#./halo2_wasm#g' ./pkg/js/index.js sed -i '' 's#\.\./\.\./pkg/web/halo2_wasm#./halo2_wasm#g' ./pkg/web/index.d.ts sed -i '' 's#\.\./\.\./pkg/web/halo2_wasm#./halo2_wasm#g' ./pkg/web/index.js + +sed -i '' 's#\.\./\.\./pkg/web/halo2_wasm#../web/halo2_wasm#g' ./pkg/shared/scaffold.d.ts +sed -i '' 's#\.\./\.\./pkg/web/halo2_wasm#../web/halo2_wasm#g' ./pkg/shared/scaffold.js diff --git a/halo2-wasm/src/tests/gate.rs b/halo2-wasm/src/tests/gate.rs index 90d01ce..7891443 100644 --- a/halo2-wasm/src/tests/gate.rs +++ b/halo2-wasm/src/tests/gate.rs @@ -17,11 +17,11 @@ macro_rules! gate_test { #[test] pub fn []() { let base = base_test().run_gate(|ctx, chip| { - let [a] = [$a].map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())); + let [a] = [$a].map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())); chip.$op(ctx, a); }); let wasm = base_test().run_wasm_builder(|ctx| { - let [a] = [$a].map(|x| ctx.witness(x)); + let [a] = [$a].map(|x| ctx.constant(x)); ctx.$op(a) }); assert_eq!(base, wasm); @@ -33,11 +33,11 @@ macro_rules! gate_test { #[test] pub fn []() { let base = base_test().run_gate(|ctx, chip| { - let [a, b] = [$a, $b].map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())); + let [a, b] = [$a, $b].map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())); chip.$op(ctx, a, b); }); let wasm = base_test().run_wasm_builder(|ctx| { - let [a, b] = [$a, $b].map(|x| ctx.witness(x)); + let [a, b] = [$a, $b].map(|x| ctx.constant(x)); ctx.$op(a, b) }); assert_eq!(base, wasm); @@ -49,11 +49,11 @@ macro_rules! gate_test { #[test] pub fn []() { let base = base_test().run_gate(|ctx, chip| { - let [a, b, c] = [$a, $b, $c].map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())); + let [a, b, c] = [$a, $b, $c].map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())); chip.$op(ctx, a, b, c); }); let wasm = base_test().run_wasm_builder(|ctx| { - let [a, b, c] = [$a, $b, $c].map(|x| ctx.witness(x)); + let [a, b, c] = [$a, $b, $c].map(|x| ctx.constant(x)); ctx.$op(a, b, c) }); assert_eq!(base, wasm); @@ -102,7 +102,7 @@ gate_test!( chip.assert_is_const(ctx, &a, &fe); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { - let a = ctx.witness(inputs[0]); + let a = ctx.constant(inputs[0]); ctx.assert_is_const(a, inputs[0]); } ); @@ -113,7 +113,7 @@ gate_test!( |ctx: &mut Context, chip: &GateChip, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); chip.inner_product( ctx, @@ -124,7 +124,7 @@ gate_test!( |ctx: &mut Halo2LibWasm, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); ctx.inner_product(inputs.clone().as_slice(), inputs.as_slice()); } @@ -134,13 +134,13 @@ gate_test!( test_pow_var, ("15", "10", 4), |ctx: &mut Context, chip: &GateChip, inputs: (&str, &str, usize)| { - let a = ctx.load_witness(Fr::from_str_vartime(inputs.0).unwrap()); - let exp = ctx.load_witness(Fr::from_str_vartime(inputs.1).unwrap()); + let a = ctx.load_constant(Fr::from_str_vartime(inputs.0).unwrap()); + let exp = ctx.load_constant(Fr::from_str_vartime(inputs.1).unwrap()); chip.pow_var(ctx, a, exp, inputs.2); }, |ctx: &mut Halo2LibWasm, inputs: (&str, &str, usize)| { - let a = ctx.witness(inputs.0); - let exp = ctx.witness(inputs.1); + let a = ctx.constant(inputs.0); + let exp = ctx.constant(inputs.1); ctx.pow_var(a, exp, &inputs.2.to_string()); } ); @@ -151,14 +151,14 @@ gate_test!( |ctx: &mut Context, chip: &GateChip, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); chip.sum(ctx, inputs); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); ctx.sum(inputs.as_slice()); } @@ -170,14 +170,14 @@ gate_test!( |ctx: &mut Context, chip: &GateChip, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); chip.bits_to_indicator(ctx, &inputs); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); ctx.bits_to_indicator(inputs.as_slice()); } @@ -187,11 +187,11 @@ gate_test!( test_idx_to_indicator, &["8", "12"], |ctx: &mut Context, chip: &GateChip, inputs: &[&str]| { - let idx = ctx.load_witness(Fr::from_str_vartime(inputs[0]).unwrap()); + let idx = ctx.load_constant(Fr::from_str_vartime(inputs[0]).unwrap()); chip.idx_to_indicator(ctx, idx, inputs[1].parse().unwrap()); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { - let idx = ctx.witness(inputs[0]); + let idx = ctx.constant(inputs[0]); ctx.idx_to_indicator(idx, inputs[1]); } ); @@ -202,22 +202,22 @@ gate_test!( |ctx: &mut Context, chip: &GateChip, inputs: &[&[&str]]| { let a = inputs[0] .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); let indicator = inputs[1] .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); chip.select_by_indicator(ctx, a, indicator); }, |ctx: &mut Halo2LibWasm, inputs: &[&[&str]]| { let a = inputs[0] .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); let indicator = inputs[1] .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); ctx.select_by_indicator(a.as_slice(), indicator.as_slice()); } @@ -230,18 +230,18 @@ gate_test!( let a = inputs .0 .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); - let idx = ctx.load_witness(Fr::from_str_vartime(inputs.1).unwrap()); + let idx = ctx.load_constant(Fr::from_str_vartime(inputs.1).unwrap()); chip.select_from_idx(ctx, a, idx); }, |ctx: &mut Halo2LibWasm, inputs: (&[&str; 4], &str)| { let a = inputs .0 .iter() - .map(|x| ctx.witness(x).to_u32().unwrap()) + .map(|x| ctx.constant(x).to_u32().unwrap()) .collect::>(); - let idx = ctx.witness(inputs.1); + let idx = ctx.constant(inputs.1); ctx.select_from_idx(a.as_slice(), idx); } ); @@ -250,12 +250,12 @@ gate_test!( test_num_to_bits, ("15", "5"), |ctx: &mut Context, chip: &GateChip, inputs: (&str, &str)| { - let num = ctx.load_witness(Fr::from_str_vartime(inputs.0).unwrap()); + let num = ctx.load_constant(Fr::from_str_vartime(inputs.0).unwrap()); let num_bits = inputs.1.parse().unwrap(); chip.num_to_bits(ctx, num, num_bits); }, |ctx: &mut Halo2LibWasm, inputs: (&str, &str)| { - let num = ctx.witness(inputs.0); + let num = ctx.constant(inputs.0); ctx.num_to_bits(num, inputs.1); } ); @@ -264,13 +264,13 @@ gate_test!( test_constrain_equal, ("15",), |ctx: &mut Context, _, inputs: (&str,)| { - let a = ctx.load_witness(Fr::from_str_vartime(inputs.0).unwrap()); - let b = ctx.load_witness(Fr::from_str_vartime(inputs.0).unwrap()); + let a = ctx.load_constant(Fr::from_str_vartime(inputs.0).unwrap()); + let b = ctx.load_constant(Fr::from_str_vartime(inputs.0).unwrap()); ctx.constrain_equal(&a, &b); }, |ctx: &mut Halo2LibWasm, inputs: (&str,)| { - let a = ctx.witness(inputs.0); - let b = ctx.witness(inputs.0); + let a = ctx.constant(inputs.0); + let b = ctx.constant(inputs.0); ctx.constrain_equal(a, b); } ); @@ -303,7 +303,7 @@ gate_test!( |ctx: &mut Context, chip: &GateChip, inputs: &[&str]| { let inputs = inputs .iter() - .map(|x| ctx.load_witness(Fr::from_str_vartime(x).unwrap())) + .map(|x| ctx.load_constant(Fr::from_str_vartime(x).unwrap())) .collect::>(); let spec = OptimizedPoseidonSpec::::new::(); let mut hasher = PoseidonHasher::new(spec); @@ -311,7 +311,7 @@ gate_test!( hasher.hash_fix_len_array(ctx, chip, &inputs); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { - let inputs = inputs.iter().map(|x| ctx.witness(x)).collect::>(); + let inputs = inputs.iter().map(|x| ctx.constant(x)).collect::>(); let inputs = inputs .iter() .map(|x| x.to_u32().unwrap()) @@ -323,11 +323,11 @@ gate_test!( #[test] pub fn test_make_public() { let base = base_test().run_gate_with_instances(|ctx, _, make_public| { - let a = ctx.load_witness(Fr::from_str_vartime("10").unwrap()); + let a = ctx.load_constant(Fr::from_str_vartime("10").unwrap()); make_public.push(a); }); let wasm = base_test().run_wasm_builder_with_instances(|ctx, halo2_wasm| { - let a = ctx.witness("10"); + let a = ctx.constant("10"); ctx.make_public(halo2_wasm, a, 0); }); assert_eq!(base, wasm); diff --git a/halo2-wasm/src/tests/range.rs b/halo2-wasm/src/tests/range.rs index 2ce543f..6b56b86 100644 --- a/halo2-wasm/src/tests/range.rs +++ b/halo2-wasm/src/tests/range.rs @@ -36,17 +36,23 @@ range_test!( } ); +//performs range check also since that's what halo2-lib-js does as well +//and `check_less_than` assumes that the inputs are already range checked range_test!( test_check_less_than, ("10", "15", 8), |ctx: &mut Context, chip: &RangeChip, inputs: (&str, &str, usize)| { let a = ctx.load_witness(Fr::from_str_vartime(inputs.0).unwrap()); let b = ctx.load_witness(Fr::from_str_vartime(inputs.1).unwrap()); + chip.range_check(ctx, a, inputs.2); + chip.range_check(ctx, b, inputs.2); chip.check_less_than(ctx, a, b, inputs.2); }, |ctx: &mut Halo2LibWasm, inputs: (&str, &str, usize)| { let a = ctx.witness(inputs.0); - let b = ctx.witness(inputs.0); + let b = ctx.witness(inputs.1); + ctx.range_check(a, &inputs.2.to_string()); + ctx.range_check(b, &inputs.2.to_string()); ctx.check_less_than(a, b, &inputs.2.to_string()); } ); @@ -64,17 +70,23 @@ range_test!( } ); +//performs range check also since that's what halo2-lib-js does as well +//and `is_less_than` assumes that the inputs are already range checked range_test!( test_is_less_than, &["10", "15", "8"], |ctx: &mut Context, chip: &RangeChip, inputs: &[&str]| { let a = ctx.load_witness(Fr::from_str_vartime(inputs[0]).unwrap()); let b = ctx.load_witness(Fr::from_str_vartime(inputs[1]).unwrap()); + chip.range_check(ctx, a, inputs[2].parse().unwrap()); + chip.range_check(ctx, b, inputs[2].parse().unwrap()); chip.is_less_than(ctx, a, b, inputs[2].parse().unwrap()); }, |ctx: &mut Halo2LibWasm, inputs: &[&str]| { let a = ctx.witness(inputs[0]); let b = ctx.witness(inputs[1]); + ctx.range_check(a, inputs[2]); + ctx.range_check(b, inputs[2]); ctx.is_less_than(a, b, inputs[2]); } );