diff --git a/.github/workflows/wasm.yml b/.github/workflows/npm.yml similarity index 80% rename from .github/workflows/wasm.yml rename to .github/workflows/npm.yml index 2056d4edf..da2a24c88 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/npm.yml @@ -1,4 +1,4 @@ -name: Build and Publish WASM<>JS Bindings +name: Build and Publish EZKL npm packages (wasm bindings and in-browser evm verifier) on: workflow_dispatch: @@ -14,7 +14,7 @@ defaults: run: working-directory: . jobs: - wasm-publish: + publish-wasm-bindings: name: publish-wasm-bindings runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') @@ -174,3 +174,40 @@ jobs: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + in-browser-evm-ver-publish: + name: publish-in-browser-evm-verifier-package + needs: ["publish-wasm-bindings"] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + steps: + - uses: actions/checkout@v4 + - name: Update version in package.json + shell: bash + env: + RELEASE_TAG: ${{ github.ref_name }} + run: | + sed -i "s|\"version\": \".*\"|\"version\": \"${{ github.ref_name }}\"|" in-browser-evm-verifier/package.json + - name: Update @ezkljs/engine version in package.json + shell: bash + env: + RELEASE_TAG: ${{ github.ref_name }} + run: | + sed -i "s|\"@ezkljs/engine\": \".*\"|\"@ezkljs/engine\": \"${{ github.ref_name }}\"|" in-browser-evm-verifier/package.json + - name: Update the engine import in in-browser-evm-verifier to use @ezkljs/engine package instead of the local one; + run: | + sed -i "s|import { encodeVerifierCalldata } from '../nodejs/ezkl';|import { encodeVerifierCalldata } from '@ezkljs/engine';|" in-browser-evm-verifier/src/index.ts + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "18.12.1" + registry-url: "https://registry.npmjs.org" + - name: Publish to npm + run: | + cd in-browser-evm-verifier + npm install + npm run build + npm ci + npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 391967c82..78c642d0e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -303,12 +303,24 @@ jobs: with: node-version: "18.12.1" cache: "pnpm" - - name: Install dependencies + - name: Install dependencies for js tests and in-browser-evm-verifier package run: | pnpm install --no-frozen-lockfile + pnpm install --dir ./in-browser-evm-verifier --no-frozen-lockfile env: CI: false NODE_ENV: development + - name: Build wasm package for nodejs target. + run: | + wasm-pack build --release --target nodejs --out-dir ./in-browser-evm-verifier/nodejs . -- -Z build-std="panic_abort,std" + - name: Replace memory definition in nodejs + run: | + sed -i "3s|.*|imports['env'] = {memory: new WebAssembly.Memory({initial:20,maximum:65536,shared:true})}|" in-browser-evm-verifier/nodejs/ezkl.js + - name: Build @ezkljs/verify package + run: | + cd in-browser-evm-verifier + pnpm build:commonjs + cd .. - name: Install solc run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.20 && solc --version - name: Install Anvil @@ -364,7 +376,7 @@ jobs: with: node-version: "18.12.1" cache: "pnpm" - - name: Install dependencies + - name: Install dependencies for js tests run: | pnpm install --no-frozen-lockfile env: diff --git a/.gitignore b/.gitignore index 1a8583ec0..052a7bf5a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ var/ *.whl *.bak node_modules +/dist timingData.json !tests/wasm/pk.key !tests/wasm/vk.key \ No newline at end of file diff --git a/README.md b/README.md index 54aa122ed..25c0fd011 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,10 @@ For more details visit the [docs](https://docs.ezkl.xyz). Build the auto-generated rust documentation and open the docs in your browser locally. `cargo doc --open` +#### In-browser EVM verifier + +As an alternative to running the native Halo2 verifier as a WASM binding in the browser, you can use the in-browser EVM verifier. The source code of which you can find in the `in-browser-evm-verifier` directory and a README with instructions on how to use it. + ### building the project 🔨 diff --git a/in-browser-evm-verifier/README.md b/in-browser-evm-verifier/README.md new file mode 100644 index 000000000..11e0ba45e --- /dev/null +++ b/in-browser-evm-verifier/README.md @@ -0,0 +1,60 @@ +# inbrowser-evm-verify + +We would like the Solidity verifier to be canonical and usually all you ever need. For this, we need to be able to run that verifier in browser. + +## How to use (Node js) + +```ts +import localEVMVerify from '@ezkljs/verify'; + +// Load in the proof file as a buffer +const proofFileBuffer = fs.readFileSync(`${path}/${example}/proof.pf`) + +// Stringified EZKL evm verifier bytecode (this is just an example don't use in production) +const bytecode = '0x608060405234801561001057600080fd5b5060d38061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063cfae321714610046575b600080fd5b6100496100f1565b60405161005691906100f1565b60405180910390f35b' + +const result = await localEVMVerify(proofFileBuffer, bytecode) + +console.log('result', result) +``` + +**Note**: Run `ezkl create-evm-verifier` to get the Solidity verifier, with which you can retrieve the bytecode once compiled. We recommend compiling to the Shanghai hardfork target, else you will have to pass an additional parameter specifying the EVM version to the `localEVMVerify` function like so (for Paris hardfork): + +```ts +import localEVMVerify, { hardfork } from '@ezkljs/verify'; + +const result = await localEVMVerify(proofFileBuffer, bytecode, hardfork['Paris']) +``` + +**Note**: You can also verify separated vk verifiers using the `localEVMVerify` function. Just pass the vk verifier bytecode as the third parameter like so: +```ts +import localEVMVerify from '@ezkljs/verify'; + +const result = await localEVMVerify(proofFileBuffer, verifierBytecode, VKBytecode) +``` + + +## How to use (Browser) + +```ts +import localEVMVerify from '@ezkljs/verify'; + +// Load in the proof file as a buffer using the web apis (fetch, FileReader, etc) +// We use fetch in this example to load the proof file as a buffer +const proofFileBuffer = await fetch(`${path}/${example}/proof.pf`).then(res => res.arrayBuffer()) + +// Stringified EZKL evm verifier bytecode (this is just an example don't use in production) +const bytecode = '0x608060405234801561001057600080fd5b5060d38061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063cfae321714610046575b600080fd5b6100496100f1565b60405161005691906100f1565b60405180910390f35b' + +const result = await browserEVMVerify(proofFileBuffer, bytecode) + +console.log('result', result) +``` + +Output: + +```ts +result: true +``` + + diff --git a/in-browser-evm-verifier/package.json b/in-browser-evm-verifier/package.json new file mode 100644 index 000000000..c35768b7d --- /dev/null +++ b/in-browser-evm-verifier/package.json @@ -0,0 +1,42 @@ +{ + "name": "@ezkljs/verify", + "version": "0.0.0", + "publishConfig": { + "access": "public" + }, + "description": "Evm verify EZKL proofs in the browser.", + "main": "dist/commonjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/commonjs/index.d.ts", + "files": [ + "dist", + "LICENSE", + "README.md" + ], + "scripts": { + "clean": "rm -r dist || true", + "build:commonjs": "tsc --project tsconfig.commonjs.json && resolve-tspaths -p tsconfig.commonjs.json", + "build:esm": "tsc --project tsconfig.esm.json && resolve-tspaths -p tsconfig.esm.json", + "build": "pnpm run clean && pnpm run build:commonjs && pnpm run build:esm" + }, + "dependencies": { + "@ethereumjs/common": "^4.0.0", + "@ethereumjs/evm": "^2.0.0", + "@ethereumjs/statemanager": "^2.0.0", + "@ethereumjs/tx": "^5.0.0", + "@ethereumjs/util": "^9.0.0", + "@ethereumjs/vm": "^7.0.0", + "@ethersproject/abi": "^5.7.0", + "@ezkljs/engine": "^9.4.4", + "ethers": "^6.7.1", + "json-bigint": "^1.0.0" + }, + "devDependencies": { + "@types/node": "^20.8.3", + "ts-loader": "^9.5.0", + "ts-node": "^10.9.1", + "resolve-tspaths": "^0.8.16", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.2.2" + } +} \ No newline at end of file diff --git a/in-browser-evm-verifier/pnpm-lock.yaml b/in-browser-evm-verifier/pnpm-lock.yaml new file mode 100644 index 000000000..d74933093 --- /dev/null +++ b/in-browser-evm-verifier/pnpm-lock.yaml @@ -0,0 +1,1479 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@ethereumjs/common': + specifier: ^4.0.0 + version: 4.0.0 + '@ethereumjs/evm': + specifier: ^2.0.0 + version: 2.0.0 + '@ethereumjs/statemanager': + specifier: ^2.0.0 + version: 2.0.0 + '@ethereumjs/tx': + specifier: ^5.0.0 + version: 5.0.0 + '@ethereumjs/util': + specifier: ^9.0.0 + version: 9.0.0 + '@ethereumjs/vm': + specifier: ^7.0.0 + version: 7.0.0 + '@ethersproject/abi': + specifier: ^5.7.0 + version: 5.7.0 + '@ezkljs/engine': + specifier: ^9.4.4 + version: 9.4.4 + ethers: + specifier: ^6.7.1 + version: 6.7.1 + json-bigint: + specifier: ^1.0.0 + version: 1.0.0 + +devDependencies: + '@types/node': + specifier: ^20.8.3 + version: 20.8.3 + resolve-tspaths: + specifier: ^0.8.16 + version: 0.8.16(typescript@5.2.2) + ts-loader: + specifier: ^9.5.0 + version: 9.5.0(typescript@5.2.2)(webpack@5.88.2) + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@20.8.3)(typescript@5.2.2) + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + +packages: + + /@adraffy/ens-normalize@1.9.2: + resolution: {integrity: sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==} + dev: false + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@ethereumjs/block@5.0.0: + resolution: {integrity: sha512-2HAe9BKRYStMG/WmJY7ePwmXGELrp0dirvXNUIFwb8+BU/QOTzuIO+XLlcJhuF+EWukOv8muKAyUvGLDdZHIKQ==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/common': 4.0.0 + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/trie': 6.0.0 + '@ethereumjs/tx': 5.0.0 + '@ethereumjs/util': 9.0.0 + ethereum-cryptography: 2.1.2 + transitivePeerDependencies: + - buffer + - c-kzg + dev: false + + /@ethereumjs/blockchain@7.0.0: + resolution: {integrity: sha512-ouyzn0YO6v5iKikNln97XEtQKgYL97TkQ06qnB9cR41iPR5BWr+lEF79mKYJeubpv39aKZnGji3hBDnjIRlgZA==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/block': 5.0.0 + '@ethereumjs/common': 4.0.0 + '@ethereumjs/ethash': 3.0.0 + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/trie': 6.0.0 + '@ethereumjs/tx': 5.0.0 + '@ethereumjs/util': 9.0.0 + debug: 4.3.4 + ethereum-cryptography: 2.1.2 + lru-cache: 10.0.1 + transitivePeerDependencies: + - buffer + - c-kzg + - supports-color + dev: false + + /@ethereumjs/common@4.0.0: + resolution: {integrity: sha512-eVa0/nC15mpotD8HOq6jB883SCWUkLjibr2jLPmPrx4FfmewXqFeh4drgR2sHjq3qWKxpCLK+5qsSJgtXwIzJQ==} + dependencies: + '@ethereumjs/util': 9.0.0 + crc: 4.3.2 + transitivePeerDependencies: + - buffer + - c-kzg + dev: false + + /@ethereumjs/ethash@3.0.0: + resolution: {integrity: sha512-FEk+Xze5zah3SHMNsN3ktHCFa3z0kMm6A78zTD6De1fY0RqL2omzXfEDBlBsNS6S/J2c8B42/QVf7EX6DtApbA==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/block': 5.0.0 + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/util': 9.0.0 + bigint-crypto-utils: 3.3.0 + ethereum-cryptography: 2.1.2 + transitivePeerDependencies: + - buffer + - c-kzg + dev: false + + /@ethereumjs/evm@2.0.0: + resolution: {integrity: sha512-BP/3qWGW8Z7zcQTtP1onlOmh3QbwW7SOHiSoEQkkMdy1TPjyOAV7HS3sHFG4dxgRLx5jiIIiz1Bf1eoDuBxfbQ==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/common': 4.0.0 + '@ethereumjs/statemanager': 2.0.0 + '@ethereumjs/tx': 5.0.0 + '@ethereumjs/util': 9.0.0 + debug: 4.3.4 + ethereum-cryptography: 2.1.2 + rustbn-wasm: 0.2.0 + transitivePeerDependencies: + - buffer + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + dev: false + + /@ethereumjs/rlp@5.0.0: + resolution: {integrity: sha512-WuS1l7GJmB0n0HsXLozCoEFc9IwYgf3l0gCkKVYgR67puVF1O4OpEaN0hWmm1c+iHUHFCKt1hJrvy5toLg+6ag==} + engines: {node: '>=18'} + hasBin: true + dev: false + + /@ethereumjs/statemanager@2.0.0: + resolution: {integrity: sha512-dA70PTc3BaCPsVNSOXleR4jqUjVPrbZPlDPVssM4L2d15pl0wVnW3KyEsXwqmG6DqsiwD2JfZiFtDPOsNX0c3A==} + dependencies: + '@ethereumjs/common': 4.0.0 + '@ethereumjs/rlp': 5.0.0 + debug: 4.3.4 + ethereum-cryptography: 2.1.2 + ethers: 6.7.1 + js-sdsl: 4.4.2 + lru-cache: 10.0.1 + transitivePeerDependencies: + - buffer + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + dev: false + + /@ethereumjs/trie@6.0.0: + resolution: {integrity: sha512-twcOoPwqBNHruMcaAL577J+uIiO0TqEIGfKou4ss+5Yx3y0KCYusvJ7ZTCWp3yYvrvcF9OkF55yjiWx0nVn6pg==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/util': 9.0.0 + '@types/readable-stream': 2.3.15 + ethereum-cryptography: 2.1.2 + lru-cache: 10.0.1 + readable-stream: 3.6.2 + transitivePeerDependencies: + - c-kzg + dev: false + + /@ethereumjs/tx@5.0.0: + resolution: {integrity: sha512-bJBC/jHVIbwvZBVsK0Ls70NzxJ8Q3UvPwskG1LO6+ryVGKY0y1bhRreo0/gR3vTkuRjD+x5QTYV6fIY16tswJA==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.0 + peerDependenciesMeta: + c-kzg: + optional: true + dependencies: + '@ethereumjs/common': 4.0.0 + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/util': 9.0.0 + ethereum-cryptography: 2.1.2 + transitivePeerDependencies: + - buffer + dev: false + + /@ethereumjs/util@9.0.0: + resolution: {integrity: sha512-V8062I+ZXfFxtFLp7xsPeiT1IxDaVOZaM78nGj1gsWUFeZ8SgADMLDKWehp+muTy1JRbVoXFljZ1qoyv9ji/2g==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.0 + peerDependenciesMeta: + c-kzg: + optional: true + dependencies: + '@ethereumjs/rlp': 5.0.0 + ethereum-cryptography: 2.1.2 + dev: false + + /@ethereumjs/vm@7.0.0: + resolution: {integrity: sha512-3oQM5AQHUoFKIuJZ6w7wHVgu91i3ViTfOKtTDKRFjf7zGJNrrT6QzGFm5Jr6Seu3NuaEYcPJDvPPm6Wx/ACZKw==} + engines: {node: '>=18'} + dependencies: + '@ethereumjs/block': 5.0.0 + '@ethereumjs/blockchain': 7.0.0 + '@ethereumjs/common': 4.0.0 + '@ethereumjs/evm': 2.0.0 + '@ethereumjs/rlp': 5.0.0 + '@ethereumjs/statemanager': 2.0.0 + '@ethereumjs/trie': 6.0.0 + '@ethereumjs/tx': 5.0.0 + '@ethereumjs/util': 9.0.0 + debug: 4.3.4 + ethereum-cryptography: 2.1.2 + transitivePeerDependencies: + - buffer + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + dev: false + + /@ethersproject/abi@5.7.0: + resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ethersproject/abstract-provider@5.7.0: + resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + dev: false + + /@ethersproject/abstract-signer@5.7.0: + resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + dev: false + + /@ethersproject/address@5.7.0: + resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/rlp': 5.7.0 + dev: false + + /@ethersproject/base64@5.7.0: + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + dependencies: + '@ethersproject/bytes': 5.7.0 + dev: false + + /@ethersproject/bignumber@5.7.0: + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + bn.js: 5.2.1 + dev: false + + /@ethersproject/bytes@5.7.0: + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/constants@5.7.0: + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + dev: false + + /@ethersproject/hash@5.7.0: + resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ethersproject/keccak256@5.7.0: + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + dependencies: + '@ethersproject/bytes': 5.7.0 + js-sha3: 0.8.0 + dev: false + + /@ethersproject/logger@5.7.0: + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + dev: false + + /@ethersproject/networks@5.7.1: + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/properties@5.7.0: + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/rlp@5.7.0: + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/signing-key@5.7.0: + resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + bn.js: 5.2.1 + elliptic: 6.5.4 + hash.js: 1.1.7 + dev: false + + /@ethersproject/strings@5.7.0: + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/transactions@5.7.0: + resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + dev: false + + /@ethersproject/web@5.7.1: + resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + dependencies: + '@ethersproject/base64': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ezkljs/engine@9.4.4: + resolution: {integrity: sha512-kNsTmDQa8mIiQ6yjJmBMwVgAAxh4nfs4NCtnewJifonyA8Mfhs+teXwwW8WhERRDoQPUofKO2pT8BPvV/XGIDA==} + dependencies: + '@types/json-bigint': 1.0.2 + json-bigint: 1.0.0 + dev: false + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/source-map@0.3.5: + resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@noble/curves@1.1.0: + resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==} + dependencies: + '@noble/hashes': 1.3.1 + dev: false + + /@noble/hashes@1.1.2: + resolution: {integrity: sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==} + dev: false + + /@noble/hashes@1.3.1: + resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==} + engines: {node: '>= 16'} + dev: false + + /@noble/secp256k1@1.7.1: + resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@scure/base@1.1.3: + resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==} + dev: false + + /@scure/bip32@1.3.1: + resolution: {integrity: sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==} + dependencies: + '@noble/curves': 1.1.0 + '@noble/hashes': 1.3.1 + '@scure/base': 1.1.3 + dev: false + + /@scure/bip39@1.2.1: + resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} + dependencies: + '@noble/hashes': 1.3.1 + '@scure/base': 1.1.3 + dev: false + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16@1.0.4: + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: true + + /@types/eslint-scope@3.7.5: + resolution: {integrity: sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==} + dependencies: + '@types/eslint': 8.44.3 + '@types/estree': 1.0.2 + dev: true + + /@types/eslint@8.44.3: + resolution: {integrity: sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==} + dependencies: + '@types/estree': 1.0.2 + '@types/json-schema': 7.0.13 + dev: true + + /@types/estree@1.0.2: + resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==} + dev: true + + /@types/json-bigint@1.0.2: + resolution: {integrity: sha512-ZXqZc1YeBj1B2my/a/f5PWpNemgIb1r5s3cALPvsMqoGEZ0NOEo1UxrSRUEZr0EtChy1BH/CuORiYuvYr4/4Fw==} + dev: false + + /@types/json-schema@7.0.13: + resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==} + dev: true + + /@types/node@18.15.13: + resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} + dev: false + + /@types/node@20.8.3: + resolution: {integrity: sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==} + + /@types/readable-stream@2.3.15: + resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} + dependencies: + '@types/node': 20.8.3 + safe-buffer: 5.1.2 + dev: false + + /@webassemblyjs/ast@1.11.6: + resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} + dependencies: + '@webassemblyjs/helper-numbers': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + dev: true + + /@webassemblyjs/floating-point-hex-parser@1.11.6: + resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + dev: true + + /@webassemblyjs/helper-api-error@1.11.6: + resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + dev: true + + /@webassemblyjs/helper-buffer@1.11.6: + resolution: {integrity: sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==} + dev: true + + /@webassemblyjs/helper-numbers@1.11.6: + resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/helper-wasm-bytecode@1.11.6: + resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + dev: true + + /@webassemblyjs/helper-wasm-section@1.11.6: + resolution: {integrity: sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/helper-buffer': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/wasm-gen': 1.11.6 + dev: true + + /@webassemblyjs/ieee754@1.11.6: + resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + dependencies: + '@xtuc/ieee754': 1.2.0 + dev: true + + /@webassemblyjs/leb128@1.11.6: + resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + dependencies: + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/utf8@1.11.6: + resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + dev: true + + /@webassemblyjs/wasm-edit@1.11.6: + resolution: {integrity: sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/helper-buffer': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.11.6 + '@webassemblyjs/wasm-gen': 1.11.6 + '@webassemblyjs/wasm-opt': 1.11.6 + '@webassemblyjs/wasm-parser': 1.11.6 + '@webassemblyjs/wast-printer': 1.11.6 + dev: true + + /@webassemblyjs/wasm-gen@1.11.6: + resolution: {integrity: sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + dev: true + + /@webassemblyjs/wasm-opt@1.11.6: + resolution: {integrity: sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/helper-buffer': 1.11.6 + '@webassemblyjs/wasm-gen': 1.11.6 + '@webassemblyjs/wasm-parser': 1.11.6 + dev: true + + /@webassemblyjs/wasm-parser@1.11.6: + resolution: {integrity: sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + dev: true + + /@webassemblyjs/wast-printer@1.11.6: + resolution: {integrity: sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==} + dependencies: + '@webassemblyjs/ast': 1.11.6 + '@xtuc/long': 4.2.2 + dev: true + + /@xtuc/ieee754@1.2.0: + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + dev: true + + /@xtuc/long@4.2.2: + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + dev: true + + /acorn-import-assertions@1.9.0(acorn@8.10.0): + resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + peerDependencies: + acorn: ^8 + dependencies: + acorn: 8.10.0 + dev: true + + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + dev: false + + /ajv-keywords@3.5.2(ajv@6.12.6): + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + dependencies: + ajv: 6.12.6 + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /bigint-crypto-utils@3.3.0: + resolution: {integrity: sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==} + engines: {node: '>=14.0.0'} + dev: false + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + dev: false + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + dev: false + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + dev: false + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001546 + electron-to-chromium: 1.4.544 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /caniuse-lite@1.0.30001546: + resolution: {integrity: sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==} + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chrome-trace-event@1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + engines: {node: '>=6.0'} + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /commander@11.0.0: + resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} + engines: {node: '>=16'} + dev: true + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true + + /crc@4.3.2: + resolution: {integrity: sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==} + engines: {node: '>=12'} + peerDependencies: + buffer: '>=6.0.3' + peerDependenciesMeta: + buffer: + optional: true + dev: false + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /electron-to-chromium@1.4.544: + resolution: {integrity: sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==} + dev: true + + /elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /enhanced-resolve@5.15.0: + resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + + /es-module-lexer@1.3.1: + resolution: {integrity: sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==} + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /ethereum-cryptography@2.1.2: + resolution: {integrity: sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==} + dependencies: + '@noble/curves': 1.1.0 + '@noble/hashes': 1.3.1 + '@scure/bip32': 1.3.1 + '@scure/bip39': 1.2.1 + dev: false + + /ethers@6.7.1: + resolution: {integrity: sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA==} + engines: {node: '>=14.0.0'} + dependencies: + '@adraffy/ens-normalize': 1.9.2 + '@noble/hashes': 1.1.2 + '@noble/secp256k1': 1.7.1 + '@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 + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 20.8.3 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /js-sdsl@4.4.2: + resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} + dev: false + + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + dev: false + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.1.2 + dev: false + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + dev: true + + /lru-cache@10.0.1: + resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} + engines: {node: 14 || >=16.14} + dev: false + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /resolve-tspaths@0.8.16(typescript@5.2.2): + resolution: {integrity: sha512-5c90plgcKFcCk66Ve1vFh6tm0fLKmSz6vaW4CezP6i69Q8fgWX3YGPYmKPEughem+nPHT1358P+rXrhw5pibwg==} + hasBin: true + peerDependencies: + typescript: '>=3.0.3' + dependencies: + ansi-colors: 4.1.3 + commander: 11.0.0 + fast-glob: 3.3.1 + typescript: 5.2.2 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rustbn-wasm@0.2.0: + resolution: {integrity: sha512-FThvYFNTqrEKGqXuseeg0zR7yROh/6U1617mCHF68OVqrN1tNKRN7Tdwy4WayPVsCmmK+eMxtIZX1qL6JxTkMg==} + dependencies: + '@scure/base': 1.1.3 + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.13 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /serialize-javascript@6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} + dependencies: + randombytes: 2.1.0 + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + + /terser-webpack-plugin@5.3.9(webpack@5.88.2): + resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.19 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.1 + terser: 5.21.0 + webpack: 5.88.2 + dev: true + + /terser@5.21.0: + resolution: {integrity: sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-loader@9.5.0(typescript@5.2.2)(webpack@5.88.2): + resolution: {integrity: sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.15.0 + micromatch: 4.0.5 + semver: 7.5.4 + source-map: 0.7.4 + typescript: 5.2.2 + webpack: 5.88.2 + dev: true + + /ts-node@10.9.1(@types/node@20.8.3)(typescript@5.2.2): + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.8.3 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.2.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.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'} + hasBin: true + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + + /watchpack@2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + dev: true + + /webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + dev: true + + /webpack@5.88.2: + resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.5 + '@types/estree': 1.0.2 + '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/wasm-edit': 1.11.6 + '@webassemblyjs/wasm-parser': 1.11.6 + acorn: 8.10.0 + acorn-import-assertions: 1.9.0(acorn@8.10.0) + browserslist: 4.22.1 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.15.0 + es-module-lexer: 1.3.1 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.9(webpack@5.88.2) + watchpack: 2.4.0 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + 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 + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true diff --git a/in-browser-evm-verifier/src/index.ts b/in-browser-evm-verifier/src/index.ts new file mode 100644 index 000000000..c60b2c44d --- /dev/null +++ b/in-browser-evm-verifier/src/index.ts @@ -0,0 +1,145 @@ +import { defaultAbiCoder as AbiCoder } from '@ethersproject/abi' +import { Address, hexToBytes } from '@ethereumjs/util' +import { Chain, Common, Hardfork } from '@ethereumjs/common' +import { LegacyTransaction, LegacyTxData } from '@ethereumjs/tx' +// import { DefaultStateManager } from '@ethereumjs/statemanager' +// import { Blockchain } from '@ethereumjs/blockchain' +import { VM } from '@ethereumjs/vm' +import { EVM } from '@ethereumjs/evm' +import { buildTransaction, encodeDeployment } from './utils/tx-builder' +import { getAccountNonce, insertAccount } from './utils/account-utils' +import { encodeVerifierCalldata } from '../nodejs/ezkl'; +import { error } from 'console' + +async function deployContract( + vm: VM, + common: Common, + senderPrivateKey: Uint8Array, + deploymentBytecode: string +): Promise
{ + // Contracts are deployed by sending their deployment bytecode to the address 0 + // The contract params should be abi-encoded and appended to the deployment bytecode. + // const data = + const data = encodeDeployment(deploymentBytecode) + const txData = { + data, + nonce: await getAccountNonce(vm, senderPrivateKey), + } + + const tx = LegacyTransaction.fromTxData( + buildTransaction(txData) as LegacyTxData, + { common, allowUnlimitedInitCodeSize: true }, + ).sign(senderPrivateKey) + + const deploymentResult = await vm.runTx({ + tx, + skipBlockGasLimitValidation: true, + skipNonce: true + }) + + if (deploymentResult.execResult.exceptionError) { + throw deploymentResult.execResult.exceptionError + } + + return deploymentResult.createdAddress! +} + +async function verify( + vm: VM, + contractAddress: Address, + caller: Address, + proof: Uint8Array | Uint8ClampedArray, + vkAddress?: Address | Uint8Array, +): Promise { + if (proof instanceof Uint8Array) { + proof = new Uint8ClampedArray(proof.buffer) + } + if (vkAddress) { + const vkAddressBytes = hexToBytes(vkAddress.toString()) + const vkAddressArray = Array.from(vkAddressBytes) + + let string = JSON.stringify(vkAddressArray) + + const uint8Array = new TextEncoder().encode(string); + + // Step 3: Convert to Uint8ClampedArray + vkAddress = new Uint8Array(uint8Array.buffer); + + // convert uitn8array of length + error('vkAddress', vkAddress) + } + const data = encodeVerifierCalldata(proof, vkAddress) + + const verifyResult = await vm.evm.runCall({ + to: contractAddress, + caller: caller, + origin: caller, // The tx.origin is also the caller here + data: data, + }) + + if (verifyResult.execResult.exceptionError) { + throw verifyResult.execResult.exceptionError + } + + const results = AbiCoder.decode(['bool'], verifyResult.execResult.returnValue) + + return results[0] +} + +/** + * Spins up an ephemeral EVM instance for executing the bytecode of a solidity verifier + * @param proof Json serialized proof file + * @param bytecode The bytecode of a compiled solidity verifier. + * @param bytecode_vk The bytecode of a contract that stores the vk. (Optional, only required if the vk is stored in a separate contract) + * @param evmVersion The evm version to use for the verification. (Default: London) + * @returns The result of the evm verification. + * @throws If the verify transaction reverts + */ +export default async function localEVMVerify( + proof: Uint8Array | Uint8ClampedArray, + bytecode_verifier: string, + bytecode_vk?: string, + evmVersion?: Hardfork, +): Promise { + try { + const hardfork = evmVersion ? evmVersion : Hardfork['Shanghai'] + const common = new Common({ chain: Chain.Mainnet, hardfork }) + const accountPk = hexToBytes( + '0xe331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', // anvil deterministic Pk + ) + + const evm = new EVM({ + allowUnlimitedContractSize: true, + allowUnlimitedInitCodeSize: true, + }) + + const vm = await VM.create({ common, evm }) + const accountAddress = Address.fromPrivateKey(accountPk) + + await insertAccount(vm, accountAddress) + + const verifierAddress = await deployContract( + vm, + common, + accountPk, + bytecode_verifier + ) + + if (bytecode_vk) { + const accountPk = hexToBytes("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); // anvil deterministic Pk + const accountAddress = Address.fromPrivateKey(accountPk) + await insertAccount(vm, accountAddress) + const output = await deployContract(vm, common, accountPk, bytecode_vk) + const result = await verify(vm, verifierAddress, accountAddress, proof, output) + return true + } + + const result = await verify(vm, verifierAddress, accountAddress, proof) + + return result + } catch (error) { + // log or re-throw the error, depending on your needs + console.error('An error occurred:', error) + throw error + } +} diff --git a/in-browser-evm-verifier/src/utils/account-utils.ts b/in-browser-evm-verifier/src/utils/account-utils.ts new file mode 100644 index 000000000..6895c55e1 --- /dev/null +++ b/in-browser-evm-verifier/src/utils/account-utils.ts @@ -0,0 +1,32 @@ +import { VM } from '@ethereumjs/vm' +import { Account, Address } from '@ethereumjs/util' + +export const keyPair = { + secretKey: + '0x3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511', + publicKey: + '0x0406cc661590d48ee972944b35ad13ff03c7876eae3fd191e8a2f77311b0a3c6613407b5005e63d7d8d76b89d5f900cde691497688bb281e07a5052ff61edebdc0', +} + +export const insertAccount = async (vm: VM, address: Address) => { + const acctData = { + nonce: 0, + balance: BigInt('1000000000000000000'), // 1 eth + } + const account = Account.fromAccountData(acctData) + + await vm.stateManager.putAccount(address, account) +} + +export const getAccountNonce = async ( + vm: VM, + accountPrivateKey: Uint8Array, +) => { + const address = Address.fromPrivateKey(accountPrivateKey) + const account = await vm.stateManager.getAccount(address) + if (account) { + return account.nonce + } else { + return BigInt(0) + } +} diff --git a/in-browser-evm-verifier/src/utils/tx-builder.ts b/in-browser-evm-verifier/src/utils/tx-builder.ts new file mode 100644 index 000000000..658d042f7 --- /dev/null +++ b/in-browser-evm-verifier/src/utils/tx-builder.ts @@ -0,0 +1,59 @@ +import { Interface, defaultAbiCoder as AbiCoder } from '@ethersproject/abi' +import { + AccessListEIP2930TxData, + FeeMarketEIP1559TxData, + TxData, +} from '@ethereumjs/tx' + +type TransactionsData = + | TxData + | AccessListEIP2930TxData + | FeeMarketEIP1559TxData + +export const encodeFunction = ( + method: string, + params?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + types: any[] + values: unknown[] + }, +): string => { + const parameters = params?.types ?? [] + const methodWithParameters = `function ${method}(${parameters.join(',')})` + const signatureHash = new Interface([methodWithParameters]).getSighash(method) + const encodedArgs = AbiCoder.encode(parameters, params?.values ?? []) + + return signatureHash + encodedArgs.slice(2) +} + +export const encodeDeployment = ( + bytecode: string, + params?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + types: any[] + values: unknown[] + }, +) => { + const deploymentData = '0x' + bytecode + if (params) { + const argumentsEncoded = AbiCoder.encode(params.types, params.values) + return deploymentData + argumentsEncoded.slice(2) + } + return deploymentData +} + +export const buildTransaction = ( + data: Partial, +): TransactionsData => { + const defaultData: Partial = { + gasLimit: 3_000_000_000_000_000, + gasPrice: 7, + value: 0, + data: '0x', + } + + return { + ...defaultData, + ...data, + } +} diff --git a/in-browser-evm-verifier/tsconfig.commonjs.json b/in-browser-evm-verifier/tsconfig.commonjs.json new file mode 100644 index 000000000..e144fd887 --- /dev/null +++ b/in-browser-evm-verifier/tsconfig.commonjs.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "outDir": "./dist/commonjs" + } +} \ No newline at end of file diff --git a/in-browser-evm-verifier/tsconfig.esm.json b/in-browser-evm-verifier/tsconfig.esm.json new file mode 100644 index 000000000..b8766339b --- /dev/null +++ b/in-browser-evm-verifier/tsconfig.esm.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "ES2020", + "outDir": "./dist/esm" + } +} diff --git a/in-browser-evm-verifier/tsconfig.json b/in-browser-evm-verifier/tsconfig.json new file mode 100644 index 000000000..d31bb11a3 --- /dev/null +++ b/in-browser-evm-verifier/tsconfig.json @@ -0,0 +1,62 @@ +{ + "compilerOptions": { + "rootDir": "src", + "target": "es2017", + "outDir": "dist", + "declaration": true, + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "checkJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": false, + "esModuleInterop": true, + "module": "CommonJS", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + // "incremental": true, + "noUncheckedIndexedAccess": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.cjs", + "src/**/*.mjs" + ], + "exclude": [ + "node_modules" + ], + // NEW: Options for file/directory watching + "watchOptions": { + // Use native file system events for files and directories + "watchFile": "useFsEvents", + "watchDirectory": "useFsEvents", + // Poll files for updates more frequently + // when they're updated a lot. + "fallbackPolling": "dynamicPriority", + // Don't coalesce watch notification + "synchronousWatchDirectory": true, + // Finally, two additional settings for reducing the amount of possible + // files to track work from these directories + "excludeDirectories": [ + "**/node_modules", + "_build" + ], + "excludeFiles": [ + "build/fileWhichChangesOften.ts" + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index 148dd22e2..0759ea556 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "jest" }, "devDependencies": { - "@ezkljs/engine": "^2.4.5", + "@ezkljs/engine": "^9.4.4", "@ezkljs/verify": "^0.0.6", "@jest/types": "^29.6.3", "@types/file-saver": "^2.0.5", @@ -27,4 +27,4 @@ "tsconfig-paths": "^4.2.0", "typescript": "5.1.6" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de9e2d478..13ea5abcf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: devDependencies: '@ezkljs/engine': - specifier: ^2.4.5 - version: 2.4.5 + specifier: ^9.4.4 + version: 9.4.4 '@ezkljs/verify': specifier: ^0.0.6 version: 0.0.6(buffer@6.0.3) @@ -785,6 +785,13 @@ packages: json-bigint: 1.0.0 dev: true + /@ezkljs/engine@9.4.4: + resolution: {integrity: sha512-kNsTmDQa8mIiQ6yjJmBMwVgAAxh4nfs4NCtnewJifonyA8Mfhs+teXwwW8WhERRDoQPUofKO2pT8BPvV/XGIDA==} + dependencies: + '@types/json-bigint': 1.0.1 + json-bigint: 1.0.0 + dev: true + /@ezkljs/verify@0.0.6(buffer@6.0.3): resolution: {integrity: sha512-9DHoEhLKl1DBGuUVseXLThuMyYceY08Zymr/OsLH0zbdA9OoISYhb77j4QPm4ANRKEm5dCi8oHDqkwGbFc2xFQ==} dependencies: diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 4d2082e3f..cef59b39f 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -858,7 +858,7 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); kzg_prove_and_verify(path, test.to_string(), "safe", "private", "private", "public", 1, None, true, "single"); #[cfg(not(feature = "icicle"))] - run_js_tests(path, test.to_string(), "testWasm"); + run_js_tests(path, test.to_string(), "testWasm", false); // test_dir.close().unwrap(); } @@ -871,7 +871,7 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); kzg_prove_and_verify(path, test.to_string(), "safe", "private", "fixed", "public", 1, None, true, "single"); #[cfg(not(feature = "icicle"))] - run_js_tests(path, test.to_string(), "testWasm"); + run_js_tests(path, test.to_string(), "testWasm", false); test_dir.close().unwrap(); } @@ -919,6 +919,7 @@ mod native_tests { use crate::native_tests::kzg_fuzz; use tempdir::TempDir; use crate::native_tests::Hardfork; + use crate::native_tests::run_js_tests; /// Currently only on chain inputs that return a non-negative value are supported. const TESTS_ON_CHAIN_INPUT: [&str; 17] = [ @@ -1013,8 +1014,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "private", "private", "public"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1026,8 +1027,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify_render_seperately(2, path, test.to_string(), "private", "private", "public"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", true); test_dir.close().unwrap(); } @@ -1040,8 +1041,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let mut _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "hashed", "private", "private"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1057,8 +1058,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let mut _anvil_child = crate::native_tests::start_anvil(false, hardfork); kzg_evm_prove_and_verify(2, path, test.to_string(), "kzgcommit", "private", "public"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1070,8 +1071,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "private", "hashed", "public"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1083,8 +1084,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "private", "private", "hashed"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1096,8 +1097,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "private", "kzgcommit", "public"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1109,8 +1110,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "private", "private", "kzgcommit"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -1121,8 +1122,8 @@ mod native_tests { let path = test_dir.path().to_str().unwrap(); crate::native_tests::mv_test_(path, test); let _anvil_child = crate::native_tests::start_anvil(false, Hardfork::Latest); kzg_evm_prove_and_verify(2, path, test.to_string(), "kzgcommit", "kzgcommit", "kzgcommit"); - // #[cfg(not(feature = "icicle"))] - // run_js_tests(path, test.to_string(), "testBrowserEvmVerify"); + #[cfg(not(feature = "icicle"))] + run_js_tests(path, test.to_string(), "testBrowserEvmVerify", false); test_dir.close().unwrap(); } @@ -2184,15 +2185,17 @@ mod native_tests { } // run js browser evm verify tests for a given example - fn run_js_tests(test_dir: &str, example_name: String, js_test: &str) { + fn run_js_tests(test_dir: &str, example_name: String, js_test: &str, vk: bool) { + let example = format!("--example={}", example_name); + let dir = format!("--dir={}", test_dir); + let mut args = vec!["run", "test", js_test, &example, &dir]; + let vk_string: String; + if vk { + vk_string = format!("--vk={}", vk); + args.push(&vk_string); + }; let status = Command::new("pnpm") - .args([ - "run", - "test", - js_test, - &format!("--example={}", example_name), - &format!("--dir={}", test_dir), - ]) + .args(&args) .status() .expect("failed to execute process"); assert!(status.success()); diff --git a/tests/wasm/testBrowserEvmVerify.test.ts b/tests/wasm/testBrowserEvmVerify.test.ts index 69e7d8de6..387cb3bd9 100644 --- a/tests/wasm/testBrowserEvmVerify.test.ts +++ b/tests/wasm/testBrowserEvmVerify.test.ts @@ -1,28 +1,42 @@ -import localEVMVerify, { Hardfork } from '@ezkljs/verify' +import localEVMVerify from '../../in-browser-evm-verifier/src/index' import { serialize, deserialize } from '@ezkljs/engine/nodejs' import { compileContracts } from './utils' import * as fs from 'fs' -exports.USER_NAME = require("minimist")(process.argv.slice(2))["example"]; +exports.EXAMPLE = require("minimist")(process.argv.slice(2))["example"]; exports.PATH = require("minimist")(process.argv.slice(2))["dir"]; +exports.VK = require("minimist")(process.argv.slice(2))["vk"]; describe('localEVMVerify', () => { - let bytecode: string + let bytecode_verifier: string + + let bytecode_vk: string | undefined = undefined let proof: any - const example = exports.USER_NAME || "1l_mlp" + const example = exports.EXAMPLE || "1l_mlp" const path = exports.PATH || "../ezkl/examples/onnx" + const vk = exports.VK || false beforeEach(() => { - let solcOutput = compileContracts(path, example) + const solcOutput = compileContracts(path, example, 'kzg') - bytecode = + bytecode_verifier = solcOutput.contracts['artifacts/Verifier.sol']['Halo2Verifier'].evm.bytecode .object - console.log('size', bytecode.length) + if (vk) { + const solcOutput_vk = compileContracts(path, example, 'vk') + + bytecode_vk = + solcOutput_vk.contracts['artifacts/Verifier.sol']['Halo2VerifyingKey'].evm.bytecode + .object + + + console.log('size of verifier bytecode', bytecode_verifier.length) + } + console.log('verifier bytecode', bytecode_verifier) }) it('should return true when verification succeeds', async () => { @@ -30,7 +44,9 @@ describe('localEVMVerify', () => { proof = deserialize(proofFileBuffer) - const result = await localEVMVerify(proofFileBuffer, bytecode) + const result = await localEVMVerify(proofFileBuffer, bytecode_verifier, bytecode_vk) + + console.log('result', result) expect(result).toBe(true) }) @@ -39,13 +55,16 @@ describe('localEVMVerify', () => { let result: boolean = true console.log(proof.proof) try { - let index = Math.floor(Math.random() * (proof.proof.length - 2)) + 2 - let number = (proof.proof[index] + 1) % 16 + let index = Math.round((Math.random() * (proof.proof.length))) % proof.proof.length + console.log('index', index) + console.log('index', proof.proof[index]) + let number = (proof.proof[index] + 1) % 256 console.log('index', index) console.log('new number', number) proof.proof[index] = number + console.log('index post', proof.proof[index]) const proofModified = serialize(proof) - result = await localEVMVerify(proofModified, bytecode) + result = await localEVMVerify(proofModified, bytecode_verifier, bytecode_vk) } catch (error) { // Check if the error thrown is the "out of gas" error. expect(error).toEqual( diff --git a/tests/wasm/utils.ts b/tests/wasm/utils.ts index 77a2564ad..0ef8dda02 100644 --- a/tests/wasm/utils.ts +++ b/tests/wasm/utils.ts @@ -43,21 +43,21 @@ export function serialize(data: object | string): Uint8ClampedArray { // data is return new Uint8ClampedArray(uint8Array.buffer); } -export function getSolcInput(path: string, example: string) { +export function getSolcInput(path: string, example: string, name: string) { return { language: 'Solidity', sources: { 'artifacts/Verifier.sol': { - content: fsSync.readFileSync(`${path}/${example}/kzg.sol`, 'utf-8'), + content: fsSync.readFileSync(`${path}/${example}/${name}.sol`, 'utf-8'), }, // If more contracts were to be compiled, they should have their own entries here }, settings: { optimizer: { enabled: true, - runs: 200, + runs: 1, }, - evmVersion: 'london', + evmVersion: 'shanghai', outputSelection: { '*': { '*': ['abi', 'evm.bytecode'], @@ -67,8 +67,8 @@ export function getSolcInput(path: string, example: string) { } } -export function compileContracts(path: string, example: string) { - const input = getSolcInput(path, example) +export function compileContracts(path: string, example: string, name: string) { + const input = getSolcInput(path, example, name) const output = JSON.parse(solc.compile(JSON.stringify(input))) let compilationFailed = false diff --git a/verifier_abi.json b/verifier_abi.json new file mode 100644 index 000000000..efb06340b --- /dev/null +++ b/verifier_abi.json @@ -0,0 +1 @@ +[{"type":"function","name":"verifyProof","inputs":[{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"uint256[]","name":"instances","type":"uint256[]"}],"outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable"}] \ No newline at end of file diff --git a/vk.abi b/vk.abi new file mode 100644 index 000000000..0b6e079d5 --- /dev/null +++ b/vk.abi @@ -0,0 +1 @@ +[{"type":"constructor","inputs":[]}] \ No newline at end of file