diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 21605c255..2daebae10 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -15,7 +15,7 @@ jobs: - name: Upload binaries to release uses: svenstaro/upload-release-action@v2 with: - file: npm/circom.wasm + file: npm/bin/circom.wasm repo_token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.ref }} asset_name: circom.wasm diff --git a/npm/.gitignore b/npm/.gitignore index 5ea370053..bc79590b8 100644 --- a/npm/.gitignore +++ b/npm/.gitignore @@ -1,2 +1,3 @@ node_modules demo +dist diff --git a/npm/.npmignore b/npm/.npmignore deleted file mode 100644 index 258920b32..000000000 --- a/npm/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -demo -test -.prettierrc diff --git a/npm/.prettierrc b/npm/.prettierrc index bfe354d97..8f4613b53 100644 --- a/npm/.prettierrc +++ b/npm/.prettierrc @@ -1,18 +1,9 @@ { - "tabWidth": 4, - "useTabs": false, - "semi": false, - "jsxBracketSameLine": false, - "trailingComma": "es5", - "printWidth": 100, - "arrowParens": "always", - "proseWrap": "always", - "singleQuote": true, "overrides": [ { - "files": ["**/*.json", "*.json"], + "files": "*.ts", "options": { - "parser": "json", + "printWidth": 120, "tabWidth": 2 } } diff --git a/npm/README.md b/npm/README.md index 0fe7826e9..0730fdb69 100644 --- a/npm/README.md +++ b/npm/README.md @@ -10,7 +10,7 @@ This project is a version of Circom 2.0 compiled to WASM with AST serialization The package is distributed under Distributed Lab npm organization. Run the following commanad to install the compiler: ```bash -npm install @distributedlab/circom2 +npm install --global @distributedlab/circom2 ``` > [!WARNING] @@ -21,10 +21,10 @@ npm install @distributedlab/circom2 You can use the compiler in the following way: ```bash -node cli.js +circom2 ``` -Or through using `CircomRunner` class directly. Check out `cli.js` file to learn how it is done. +Or through using `CircomRunner` class directly. Check out `cli.ts` file to learn how it is done. ## Disclaimer diff --git a/npm/circom.wasm b/npm/bin/circom.wasm similarity index 100% rename from npm/circom.wasm rename to npm/bin/circom.wasm diff --git a/npm/cli.js b/npm/cli.js deleted file mode 100755 index 9f3e6df61..000000000 --- a/npm/cli.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node - -const { CircomRunner } = require('./index') -const fs = require('fs') -const path = require('path') - -async function main() { - let args = process.argv - .slice(2) - .map((k) => (k.startsWith('-') ? k : k.endsWith('/') ? path.resolve(k) + '/' : path.resolve(k))) - if (!(args.includes('-o') || args.includes('--output'))) - args.push('-o', process.cwd() + '/') - if (args.length === 0) args.push('--help') - const circom = new CircomRunner({ - args, - env: process.env, - preopens: {"/":"/"}, - }) - const wasm_bytes = fs.readFileSync(require.resolve('./circom.wasm')) - // There is a slight delay between this logging and the circom compiler version logging - if (args.includes('--version')) { - console.log('circom2 npm package', require('./package.json').version) - } - await circom.execute(wasm_bytes) -} - -main().catch((err) => { - console.error(err) - process.exit(1) -}) diff --git a/npm/index.js b/npm/index.js deleted file mode 100644 index e96054426..000000000 --- a/npm/index.js +++ /dev/null @@ -1,52 +0,0 @@ -const { WASI, WASIExitError } = require('wasi') -const fs = require('fs') -const os = require('node:os') - -const defaultPreopens = { - '.': '.', -} - -const nullDescriptor = fs.openSync(os.devNull) - -class CircomRunner { - constructor({ - args, - env, - preopens = defaultPreopens, - quiet = false, - } = {}) { - this.wasi = new WASI({ - version: 'preview1', - args: ['circom2', ...args], - env, - preopens, - stdout: quiet ? nullDescriptor : 1, - stderr: quiet ? nullDescriptor : 2, - }) - } - - async execute(bufOrResponse) { - const mod = await WebAssembly.compile(bufOrResponse) - const instance = await WebAssembly.instantiate(mod, { - ...this.wasi.getImportObject(), - }) - - try { - this.wasi.start(instance) - } catch (err) { - // The circom devs decided to start forcing an exit call instead of exiting gracefully - // so we look for WASIExitError with success code so we can actually be graceful - if (err instanceof WASIExitError && err.code === 0) { - return instance - } - - throw err - } - - // Return the instance in case someone wants to access exports or something - return instance - } -} - -module.exports.CircomRunner = CircomRunner -module.exports.preopens = defaultPreopens diff --git a/npm/package-lock.json b/npm/package-lock.json index 374dac84b..d0aa380a4 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,25 +1,25 @@ { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.0", + "version": "0.2.19-rc.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.0", + "version": "0.2.19-rc.1", "license": "GPL-3.0", "dependencies": { - "@wasmer/wasi": "^0.12.0", - "is-typed-array": "^1.1.8", - "path-browserify": "^1.0.1" + "@wasmer/wasi": "^0.12.0" }, "bin": { - "circom2": "cli.js" + "circom2": "dist/cli.js" }, "devDependencies": { "@iden3/binfileutils": "^0.0.11", + "@types/node": "^20.14.11", "prettier": "^2.5.1", - "r1csfile": "^0.0.41" + "r1csfile": "^0.0.41", + "typescript": "^5.5.4" }, "engines": { "node": ">=16.3.0" @@ -44,6 +44,15 @@ "ffjavascript": "^0.2.48" } }, + "node_modules/@types/node": { + "version": "20.14.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.13.tgz", + "integrity": "sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@wasmer/wasi": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@wasmer/wasi/-/wasi-0.12.0.tgz", @@ -55,20 +64,6 @@ "randomfill": "^1.0.4" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/axios": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", @@ -119,24 +114,6 @@ "resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz", "integrity": "sha512-Ibt+oXxhmeYJSsCkODPqNpPmyegefiD8rfutH1NYGhMZQhSp95Rz7haemgnJ6dxa6LT+JLLbtgOMORRluwKktw==" }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -158,22 +135,6 @@ "ms": "2.0.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -183,25 +144,6 @@ "node": ">=6" } }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/fastfile": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz", @@ -231,14 +173,6 @@ "node": ">=4.0" } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -257,36 +191,11 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "optional": true }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "optional": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -303,75 +212,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/hasurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hasurl/-/hasurl-1.0.0.tgz", @@ -385,6 +225,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "optional": true, "dependencies": { "once": "^1.3.0", @@ -397,31 +238,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "optional": true }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -515,14 +331,6 @@ "node": ">=0.10.0" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -600,6 +408,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "optional": true, "dependencies": { "glob": "^7.1.3" @@ -643,22 +452,6 @@ } ] }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/tar": { "version": "5.0.11", "resolved": "https://registry.npmjs.org/tar/-/tar-5.0.11.tgz", @@ -685,6 +478,25 @@ "punycode": "^2.1.0" } }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/universal-url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universal-url/-/universal-url-2.0.0.tgz", @@ -736,24 +548,6 @@ "webidl-conversions": "^4.0.2" } }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/npm/package.json b/npm/package.json index c45d1484d..296f22e9a 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,16 +1,27 @@ { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.0", + "version": "0.2.19-rc.1", "description": "Circom 2.0 in WebAssembly", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "circom2": "dist/cli.js" + }, + "files": [ + "dist/", + "src/", + "bin/", + "README.md" + ], "scripts": { "test": "node test/test.js", - "build": "docker build -o . ..", - "build-dev": "rustwasmc build --dev ../circom && cp ../circom/pkg/circom.wasm circom.wasm" + "build": "tsc --build .", + "build-compiler": "docker build -o . ..", + "build-compiler-dev": "rustwasmc build --dev ../circom && cp ../circom/pkg/circom.wasm circom.wasm" }, - "repository": "https://github.com/distributed-lab/circom-wasm", - "bin": { - "circom2": "./cli.js" + "repository": { + "type": "git", + "url": "git+https://github.com/distributed-lab/circom-wasm" }, "engines": { "node": ">=16.3.0" @@ -18,14 +29,14 @@ "author": "Distributed Lab", "license": "GPL-3.0", "dependencies": { - "@wasmer/wasi": "^0.12.0", - "is-typed-array": "^1.1.8", - "path-browserify": "^1.0.1" + "@wasmer/wasi": "^0.12.0" }, "devDependencies": { "@iden3/binfileutils": "^0.0.11", + "@types/node": "^20.14.11", "prettier": "^2.5.1", - "r1csfile": "^0.0.41" + "r1csfile": "^0.0.41", + "typescript": "^5.5.4" }, "optionalDependencies": { "rustwasmc": "^0.1.29" diff --git a/npm/src/cli.ts b/npm/src/cli.ts new file mode 100755 index 000000000..2416ee7ca --- /dev/null +++ b/npm/src/cli.ts @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +import { CircomRunner } from "./index"; +import fs from "fs"; +import path from "path"; + +async function main() { + let args = process.argv + .slice(2) + .map((k) => (k.startsWith("-") ? k : k.endsWith("/") ? path.resolve(k) + "/" : path.resolve(k))); + + if (!(args.includes("-o") || args.includes("--output"))) { + args.push("-o", process.cwd() + "/"); + } + + if (args.length === 0) { + args.push("--help"); + } + + const circom = new CircomRunner({ + args, + env: process.env, + preopens: { "/": "/" }, + }); + + const wasm_bytes = fs.readFileSync(require.resolve("../bin/circom.wasm")); + + // There is a slight delay between this logging and the circom compiler version logging + if (args.includes("--version")) { + console.log("circom2 npm package", require("../package.json").version); + } + + await circom.execute(wasm_bytes); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/npm/src/index.ts b/npm/src/index.ts new file mode 100644 index 000000000..049c4d546 --- /dev/null +++ b/npm/src/index.ts @@ -0,0 +1,56 @@ +import { WASI } from "wasi"; +import { WASIExitError } from "@wasmer/wasi"; +import fs from "fs"; +import os from "os"; + +const defaultPreopens = { + ".": ".", +}; + +const nullDescriptor = fs.openSync(os.devNull, "w"); + +interface CircomRunnerOptions { + args?: string[]; + env?: object; + preopens?: NodeJS.Dict; + quiet?: boolean; +} + +class CircomRunner { + private wasi: WASI; + + constructor({ args = [], env, preopens = defaultPreopens, quiet = false }: CircomRunnerOptions = {}) { + this.wasi = new WASI({ + version: "preview1", + args: ["circom2", ...args], + env, + preopens, + stdout: quiet ? nullDescriptor : 1, + stderr: quiet ? nullDescriptor : 2, + }); + } + + async execute(bufOrResponse: BufferSource): Promise { + const mod = await WebAssembly.compile(bufOrResponse); + const instance = await WebAssembly.instantiate(mod, { + wasi_snapshot_preview1: this.wasi.wasiImport, + }); + + try { + this.wasi.start(instance); + } catch (err) { + // The circom devs decided to start forcing an exit call instead of exiting gracefully + // so we look for WASIExitError with success code so we can actually be graceful + if (err instanceof WASIExitError && err.code === 0) { + return instance; + } + + throw err; + } + + // Return the instance in case someone wants to access exports or something + return instance; + } +} + +export { CircomRunner, defaultPreopens }; diff --git a/npm/tsconfig.json b/npm/tsconfig.json new file mode 100644 index 000000000..67c271058 --- /dev/null +++ b/npm/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "declaration": true, + "declarationMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "./dist", + "forceConsistentCasingInFileNames": true + }, + "exclude": [ + "./dist", + "./node_modules", + ], + "include": ["src", "test"] +}