├── .eslintrc.js ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── feature.yml │ └── question.yml └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json ├── src ├── block-keys-utils.js ├── block-utils.js ├── constants.js ├── contract-utils.js ├── database.js ├── l1-info-tree-utils.js ├── mem-db.js ├── mt-bridge-utils.js ├── mt-bridge.js ├── poseidon.js ├── poseidon_constants_opt.js ├── poseidon_opt.js ├── poseidon_optimize_constants.js ├── processor-utils.js ├── processor.js ├── smt-utils.js ├── smt.js ├── state-utils.js ├── tmp-smt-db.js ├── utils.js ├── virtual-counters-manager-utils.js ├── virtual-counters-manager.js └── zkevm-db.js ├── test ├── 0-get-poseidon.test.js ├── block-info.test.js ├── contract-utils.test.js ├── contracts │ ├── BlockInfo.sol │ ├── Constructor.sol │ ├── EtherTransfer.sol │ ├── Selfdestruct.sol │ └── Test.sol ├── database.test.js ├── hardhat.config.js ├── helpers │ ├── test-utils.js │ └── test-vectors │ │ ├── block-info │ │ ├── block-info-batches.json │ │ ├── block-info-tree.json │ │ └── block-info.json │ │ ├── effective-gas-price │ │ └── effective-gas-price.json │ │ ├── end-to-end │ │ ├── README.md │ │ └── state-transition-e2e.json │ │ ├── inputs-executor │ │ └── input_executor.json │ │ ├── l1-info-tree │ │ └── l1-info-tree.json │ │ ├── l2-tx-hash │ │ └── txs.json │ │ ├── merkle-tree-bridge │ │ └── global-index.json │ │ ├── merkle-tree │ │ ├── smt-full-genesis.json │ │ ├── smt-genesis.json │ │ ├── smt-hash-bytecode.json │ │ ├── smt-key-contract-code.json │ │ ├── smt-key-contract-length.json │ │ ├── smt-key-contract-storage.json │ │ ├── smt-key-eth-balance.json │ │ ├── smt-key-eth-nonce.json │ │ └── smt-raw.json │ │ ├── processor │ │ ├── state-transition-etrog.json │ │ └── state-transition.json │ │ ├── selfdestruct │ │ └── selfdestruct.json │ │ └── zkevm-db │ │ ├── recursive.json │ │ └── state-transition.json ├── l1-info-tree-utils.test.js ├── l1-info-tree.test.js ├── mem-db.test.js ├── mt-bridge-utils.test.js ├── mt-bridge.test.js ├── poseidon.test.js ├── processor-utils.test.js ├── processor.test.js ├── smt-full-genesis.test.js ├── smt-genesis.test.js ├── smt-raw.test.js ├── smt-utils.test.js ├── smt.test.js ├── state-utils.test.js ├── tmp-smt-db.test.js ├── utils.test.js └── zkevm-db.test.js └── tools ├── generate-claim └── generate-claim-exit-root.js ├── generate-l1-info-tree-proofs ├── .gitignore ├── README.md ├── gen-l1-info-tree-smt.js └── generator.example.json └── update-tests └── update-tests.sh /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'mocha', 4 | ], 5 | env: { 6 | node: true, 7 | mocha: true, 8 | }, 9 | extends: 'airbnb-base', 10 | rules: { 11 | indent: ['error', 4], 12 | 'mocha/no-exclusive-tests': 'error', 13 | 'max-len': ['error', { 14 | code: 140, comments: 200, ignoreStrings: true, ignoreTemplateLiterals: true, 15 | }], 16 | 'no-unused-vars': [2, { varsIgnorePattern: 'export^' }], 17 | 'no-return-assign': [0], 18 | 'no-underscore-dangle': [0], 19 | 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], 20 | 'func-names': [0], 21 | 'class-methods-use-this': [0], 22 | 'no-bitwise': [0], 23 | 'no-param-reassign': 'off', 24 | 'no-console': [2, { allow: ['warn', 'error'] }], 25 | 'import/prefer-default-export': [0], 26 | 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }], 27 | 'no-await-in-loop': 'off', 28 | 'newline-before-return': 'error', 29 | }, 30 | parserOptions: { 31 | ecmaVersion: 2020, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # global owner 2 | * @krlosMata 3 | 4 | # src owners 5 | /src/ @krlosMata @laisolizq @invocamanman @ignasirv 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | assignees: 6 | - krlosMata 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Fill in all necessary information to report a bug 12 | - type: input 13 | id: version 14 | attributes: 15 | label: Version 16 | description: What version are you using ? 17 | placeholder: 'ex: v1.0.0' 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: description 22 | attributes: 23 | label: Description 24 | description: Explain the bug found and the expected result 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: steps 29 | attributes: 30 | label: Steps to reproduce 31 | description: Please share detailed information about ho to reproduce the bug 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: logs 36 | attributes: 37 | label: Relevant log 38 | description: Please copy and paste any relevant log output 39 | render: shell -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: File a bug report 3 | title: "[Feature]: " 4 | labels: ["feature"] 5 | assignees: 6 | - krlosMata 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Fill in all necessary information to request a feature 12 | - type: input 13 | id: version 14 | attributes: 15 | label: Version 16 | description: What version the features should be added ? 17 | placeholder: 'ex: v1.0.0' 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: description 22 | attributes: 23 | label: Description 24 | description: Explain the feature 25 | validations: 26 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | name: Question 2 | description: Submit a question 3 | title: "[Question]: " 4 | labels: ["question"] 5 | assignees: 6 | - krlosMata 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Fill in all necessary information to submit a question 12 | - type: input 13 | id: version 14 | attributes: 15 | label: Version 16 | description: What version the question is refering to ? 17 | placeholder: 'ex: v1.0.0' 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: question 22 | attributes: 23 | label: Description 24 | description: Explain the question 25 | validations: 26 | required: true -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Main CI 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - develop 11 | pull_request: 12 | branches: 13 | - main 14 | - develop 15 | - feature/fork-etrog 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | strategy: 22 | matrix: 23 | node-version: [16.x] 24 | 25 | steps: 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v1 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | - name: Checkout code 31 | uses: actions/checkout@v2 32 | - name: setup 33 | run: | 34 | npm install -g npm@7.13.0 35 | npm run setup 36 | - name: eslint 37 | run: npm run eslint 38 | - name: test 39 | run: npm run test 40 | 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # VScode 107 | .vscode/ 108 | 109 | # Hardhat build 110 | test/artifacts 111 | test/cache 112 | 113 | # custom 114 | package-lock.json 115 | 116 | # ignore genesis 117 | tools/fill-genesis/*.ignore.json 118 | 119 | # input examples 120 | tools/inputs-examples/ 121 | 122 | # ignore 123 | *.ignore/ 124 | tools/*.ignore/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zkevm-commonjs 2 | 3 | Javascript library implementing common utilities for polygon-hermez zkevm 4 | 5 | [![Main CI](https://github.com/0xPolygonHermez/zkevm-commonjs/actions/workflows/main.yml/badge.svg)](https://github.com/0xPolygonHermez/zkevm-commonjs/actions/workflows/main.yml) 6 | 7 | ## Usage 8 | 9 | ``` 10 | const zkevmCommon = require("@0xpolygonhermez/zkevm-commonjs"); 11 | ``` 12 | 13 | You will find the following modules inside the package: 14 | 15 | - `Constants`: zkevm global constants 16 | - `contractUtils`: zkevm smart contract utils 17 | - `Processor`: class to add transactions and process them 18 | - `processorUtils`: utils used in processor 19 | - `MemDb`: class implementing memory database 20 | - `smtUtils`: sparse-merkle-tree utils 21 | - `SMT`: class implementing the zkevm sparse-merkle-tree 22 | - `stateUtils`: zkevm state utils 23 | - `TmpSmtDB`: temporary sparse-merkle-tree database 24 | - `utils`: general utils 25 | - `ZkEVMDB`: class implementing the zkevm database 26 | - `getPoseidon`: singleton to build poseidon just only once 27 | - `MTBridge`: Merkle tree implementation used by the bridge 28 | - `mtBridgeUtils`: Merkle tree bridge utils 29 | 30 | ## Test 31 | 32 | ``` 33 | npm run eslint & npm run test 34 | ``` 35 | 36 | ## Note 37 | 38 | In order to test, the following private keys are being used. This keys are not meant to be used in any production environment: 39 | 40 | - private key: `0x28b2b0318721be8c8339199172cd7cc8f5e273800a35616ec893083a4b32c02e` 41 | - address: `0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D` 42 | - private key: `0x4d27a600dce8c29b7bd080e29a26972377dbb04d7a27d919adbb602bf13cfd23` 43 | - address: `0x4d5Cf5032B2a844602278b01199ED191A86c93ff` 44 | - private key: `0x1d0722aff4b29780e9a78e0bf28d5e127fb276cfbb0c3eb6a0e1728401777f17` 45 | - address: `0xeB17ce701E9D92724AA2ABAdA7E4B28830597Dd9` 46 | - private key: `0xd049e68efa0d85a3824c0b79f6817a986bb0cb3a075bcc2699118eca881d70ce` 47 | - address: `0x187Bd40226A7073b49163b1f6c2b73d8F2aa8478` 48 | - private key: `0x0b929d50d7fda8155539e6befa96ff297e3e9ebce4d908f570310bdf774cb32b` 49 | - address: `0xabCcEd19d7f290B84608feC510bEe872CC8F5112` 50 | - private key: `0xdfd01798f92667dbf91df722434e8fbe96af0211d4d1b82bbbbc8f1def7a814f` 51 | - address:`0xc949254d682d8c9ad5682521675b8f43b102aec4` 52 | 53 | 54 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports.Constants = require('./src/constants'); 2 | module.exports.contractUtils = require('./src/contract-utils'); 3 | module.exports.Processor = require('./src/processor'); 4 | module.exports.processorUtils = require('./src/processor-utils'); 5 | module.exports.MemDB = require('./src/mem-db'); 6 | module.exports.smtUtils = require('./src/smt-utils'); 7 | module.exports.SMT = require('./src/smt'); 8 | module.exports.stateUtils = require('./src/state-utils'); 9 | module.exports.TmpSmtDB = require('./src/tmp-smt-db'); 10 | module.exports.utils = require('./src/utils'); 11 | module.exports.ZkEVMDB = require('./src/zkevm-db'); 12 | module.exports.getPoseidon = require('./src/poseidon_opt'); 13 | module.exports.MTBridge = require('./src/mt-bridge'); 14 | module.exports.mtBridgeUtils = require('./src/mt-bridge-utils'); 15 | module.exports.Database = require('./src/database'); 16 | module.exports.l1InfoTreeUtils = require('./src/l1-info-tree-utils'); 17 | module.exports.VirtualCountersManager = require('./src/virtual-counters-manager'); 18 | module.exports.blockUtils = require('./src/block-utils'); 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@0xpolygonhermez/zkevm-commonjs", 3 | "description": "Javascript library implementing common utilities for zkevm", 4 | "version": "5.0.0", 5 | "main": "index.js", 6 | "scripts": { 7 | "setup": "npm i", 8 | "test": "cd test && npx hardhat compile && cd .. && npx mocha ./test/*.test.js && npm run test:e2e && npm run test:blockinfo && npm run test:selfdestruct && npm run test:etrog", 9 | "test:etrog": "npx mocha ./test/processor.test.js --etrog", 10 | "test:e2e": "npx mocha ./test/processor.test.js --e2e", 11 | "test:blockinfo": "npx mocha ./test/processor.test.js --blockinfo", 12 | "test:selfdestruct": "npx mocha ./test/processor.test.js --selfdestruct", 13 | "eslint": "npx eslint src/** test/*.test.js && npx eslint tools", 14 | "eslint:fix": "npx eslint src/** test/*.test.js --fix && npx eslint tools --fix", 15 | "test:update": "cd test && npx hardhat compile && cd .. && ./tools/update-tests/update-tests.sh", 16 | "test:database": "npx mocha ./test/database.test.js", 17 | "build:inputs": "npx mocha ./test/processor.test.js --update --geninputs && npx mocha ./test/processor.test.js --etrog --update --geninputs" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/0xPolygonHermez/zkevm-commonjs.git" 22 | }, 23 | "keywords": [ 24 | "zkevm", 25 | "snark", 26 | "polygon", 27 | "hermez", 28 | "stark", 29 | "EVM", 30 | "ethereum", 31 | "blockchain" 32 | ], 33 | "author": "0xPolygonHermez", 34 | "license": "pending", 35 | "bugs": { 36 | "url": "https://github.com/0xPolygonHermez/zkevm-commonjs/issues" 37 | }, 38 | "homepage": "https://github.com/0xPolygonHermez/zkevm-commonjs#readme", 39 | "devDependencies": { 40 | "@0xpolygonhermez/zkevm-contracts": "github:0xPolygonHermez/zkevm-contracts#feature/l1-info-tree", 41 | "@ethersproject/abi": "^5.6.4", 42 | "@nomiclabs/hardhat-ethers": "^2.1.0", 43 | "@nomiclabs/hardhat-waffle": "^2.0.2", 44 | "chai": "^4.3.4", 45 | "eslint": "^8.5.0", 46 | "eslint-config-airbnb-base": "^15.0.0", 47 | "eslint-plugin-import": "^2.25.3", 48 | "eslint-plugin-mocha": "^10.0.3", 49 | "mocha": "^9.1.3", 50 | "yargs": "^16.2.0" 51 | }, 52 | "dependencies": { 53 | "@ethereumjs/block": "^3.6.2", 54 | "@ethereumjs/tx": "^3.4.0", 55 | "@polygon-hermez/common": "2.6.5", 56 | "@polygon-hermez/vm": "7.0.3", 57 | "ethereumjs-util": "^7.1.4", 58 | "ethers": "^5.5.4", 59 | "ffjavascript": "^0.2.55", 60 | "lodash": "^4.17.21", 61 | "pg": "^8.7.1" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/block-keys-utils.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | const { Scalar } = require('ffjavascript'); 3 | 4 | const constants = require('./constants'); 5 | const getPoseidon = require('./poseidon'); 6 | const { scalar2fea, stringToH4 } = require('./smt-utils'); 7 | 8 | /** 9 | * Leaf type 7: 10 | * hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0]) 11 | * key: H([blockHeaderParams[0:4], blockHeaderParams[4:8], blockHeaderParams[8:12], blockHeaderParams[12:16], blockHeaderParams[16:20], 0, SMT_KEY_BLOCK_HEADER_PARAM, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 12 | * @param {Number} txIndex - current tx index 13 | * @returns {Scalar} - key computed 14 | */ 15 | async function keyBlockHeaderParams(paramKey) { 16 | const poseidon = await getPoseidon(); 17 | const { F } = poseidon; 18 | 19 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_PARAM); 20 | const blockHeaderParams = scalar2fea(F, Scalar.e(paramKey)); 21 | 22 | const key1 = [blockHeaderParams[0], blockHeaderParams[1], blockHeaderParams[2], blockHeaderParams[3], blockHeaderParams[4], blockHeaderParams[5], constant, F.zero]; 23 | const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES); 24 | 25 | return poseidon(key1, key1Capacity); 26 | } 27 | 28 | /** 29 | * Leaf type 8: 30 | * hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0]) 31 | * key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_TRANSACTION_HASH, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 32 | * @param {Number} txIndex - current tx index 33 | * @returns {Scalar} - key computed 34 | */ 35 | async function keyTxHash(_txIndex) { 36 | const poseidon = await getPoseidon(); 37 | const { F } = poseidon; 38 | 39 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_TRANSACTION_HASH); 40 | const txIndex = scalar2fea(F, Scalar.e(_txIndex)); 41 | 42 | const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero]; 43 | const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES); 44 | 45 | return poseidon(key1, key1Capacity); 46 | } 47 | 48 | /** 49 | * Leaf type 9: 50 | * hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0]) 51 | * key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_STATUS, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 52 | * @param {Number} txIndex - current tx index 53 | * @returns {Scalar} - key computed 54 | */ 55 | async function keyTxStatus(_txIndex) { 56 | const poseidon = await getPoseidon(); 57 | const { F } = poseidon; 58 | 59 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_STATUS); 60 | const txIndex = scalar2fea(F, Scalar.e(_txIndex)); 61 | 62 | const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero]; 63 | const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES); 64 | 65 | return poseidon(key1, key1Capacity); 66 | } 67 | 68 | /** 69 | * Leaf type 10: 70 | * hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0]) 71 | * key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_CUMULATIVE_GAS_USED, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 72 | * @param {Number} txIndex - current tx index 73 | * @returns {Scalar} - key computed 74 | */ 75 | async function keyTxCumulativeGasUsed(_txIndex) { 76 | const poseidon = await getPoseidon(); 77 | const { F } = poseidon; 78 | 79 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_CUMULATIVE_GAS_USED); 80 | const txIndex = scalar2fea(F, Scalar.e(_txIndex)); 81 | 82 | const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero]; 83 | const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES); 84 | 85 | return poseidon(key1, key1Capacity); 86 | } 87 | 88 | /** 89 | * Leaf type 11: 90 | * hk0: H([logIndex[0:4], logIndex[4:8], logIndex[8:12], logIndex[12:16], logIndex[16:20], logIndex[20:24], logIndex[24:28], logIndex[28:32], [0, 0, 0, 0]) 91 | * key: H([logIndexKey[0:4], logIndexKey[4:8], logIndexKey[8:12], logIndexKey[12:16], logIndexKey[16:20], 0, SMT_KEY_BLOCK_HEADER_LOGS, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 92 | * @param {Number} logIndex - current log index 93 | * @returns {Scalar} - key computed 94 | */ 95 | async function keyTxLogs(_txIndex, _logIndex) { 96 | const poseidon = await getPoseidon(); 97 | const { F } = poseidon; 98 | 99 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_LOGS); 100 | const txIndexKey = scalar2fea(F, Scalar.e(_txIndex)); 101 | 102 | const key1 = [txIndexKey[0], txIndexKey[1], txIndexKey[2], txIndexKey[3], txIndexKey[4], txIndexKey[5], constant, F.zero]; 103 | const logIndex = Scalar.e(_logIndex); 104 | const logIndexArray = scalar2fea(F, logIndex); 105 | const hk0 = poseidon(logIndexArray, [F.zero, F.zero, F.zero, F.zero]); 106 | 107 | return poseidon(key1, hk0); 108 | } 109 | 110 | /** 111 | * Leaf type 12: 112 | * hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0]) 113 | * key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_EFFECTIVE_PERCENTAGE, 0], [hk0[0], hk0[1], hk0[2], hk0[3]]) 114 | * @param {Number} txIndex - current tx index 115 | * @returns {Scalar} - key computed 116 | */ 117 | async function keyTxEffectivePercentage(_txIndex) { 118 | const poseidon = await getPoseidon(); 119 | const { F } = poseidon; 120 | 121 | const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_EFFECTIVE_PERCENTAGE); 122 | const txIndex = scalar2fea(F, Scalar.e(_txIndex)); 123 | 124 | const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero]; 125 | const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES); 126 | 127 | return poseidon(key1, key1Capacity); 128 | } 129 | 130 | module.exports = { 131 | keyBlockHeaderParams, 132 | keyTxLogs, 133 | keyTxStatus, 134 | keyTxHash, 135 | keyTxCumulativeGasUsed, 136 | keyTxEffectivePercentage, 137 | }; 138 | -------------------------------------------------------------------------------- /src/block-utils.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-syntax */ 2 | /* eslint-disable no-undef */ 3 | const { Scalar } = require('ffjavascript'); 4 | 5 | const constants = require('./constants'); 6 | const { 7 | keyBlockHeaderParams, keyTxLogs, keyTxStatus, keyTxHash, keyTxCumulativeGasUsed, keyTxEffectivePercentage, 8 | } = require('./block-keys-utils'); 9 | const { linearPoseidon } = require('./smt-utils'); 10 | 11 | /** 12 | * Set a state of an ethereum address 13 | * @param {Object} smt merkle tree structure 14 | * @param {Array[Field]} root merkle tree root 15 | * @param {String} oldBlockHash old block hash 16 | * @param {String} coinbase block coinbase 17 | * @param {Scalar|Number} blockNumber block number 18 | * @param {Scalar|Number} gasLimit block gas limit 19 | * @param {Scalar|Number} timestamp block timestamp 20 | * @param {String} GER block's global exit root 21 | * @param {String} blockHashL1 block hash L1 22 | * @returns {Array[Field]} new state root 23 | */ 24 | async function initBlockHeader(smt, root, oldBlockHash, coinbase, blockNumber, gasLimit, timestamp, GER, blockHashL1) { 25 | const keyBlockHash = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH); 26 | const keyCoinbase = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_COINBASE); 27 | const keyBlockNumber = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_NUMBER); 28 | const keyGasLimit = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GAS_LIMIT); 29 | const keyTimestamp = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_TIMESTAMP); 30 | const keyGER = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GER); 31 | const keyBlockHashL1 = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH_L1); 32 | 33 | let result = await smt.set(root, keyBlockHash, Scalar.e(oldBlockHash)); 34 | result = await smt.set(result.newRoot, keyCoinbase, Scalar.e(coinbase)); 35 | result = await smt.set(result.newRoot, keyBlockNumber, Scalar.e(blockNumber)); 36 | result = await smt.set(result.newRoot, keyGasLimit, Scalar.e(gasLimit)); 37 | result = await smt.set(result.newRoot, keyTimestamp, Scalar.e(timestamp)); 38 | result = await smt.set(result.newRoot, keyGER, Scalar.e(GER)); 39 | result = await smt.set(result.newRoot, keyBlockHashL1, Scalar.e(blockHashL1)); 40 | 41 | return result.newRoot; 42 | } 43 | 44 | /** 45 | * Set a state of an ethereum address 46 | * @param {Object} smt merkle tree structure 47 | * @param {Array[Field]} root merkle tree root 48 | * @param {Scalar|Number} gasUsed block gasUsed 49 | * @returns {Array[Field]} new state root 50 | */ 51 | async function setBlockGasUsed(smt, root, gasUsed) { 52 | const keyGasUsed = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GAS_USED); 53 | const result = await smt.set(root, keyGasUsed, Scalar.e(gasUsed)); 54 | 55 | return result.newRoot; 56 | } 57 | 58 | /** 59 | * Set tx hash to smt 60 | * @param {Object} smt merkle tree structure 61 | * @param {Array[Field]} root merkle tree root 62 | * @param {Number} txIndex transaction index 63 | * @param {String} hash transaction status 64 | * @returns {Array[Field]} new state root 65 | */ 66 | async function setL2TxHash(smt, root, txIndex, hash) { 67 | const keyHash = await keyTxHash(txIndex); 68 | const result = await smt.set(root, keyHash, Scalar.e(hash)); 69 | 70 | return result.newRoot; 71 | } 72 | 73 | /** 74 | * Set tx status to smt 75 | * @param {Object} smt merkle tree structure 76 | * @param {Array[Field]} root merkle tree root 77 | * @param {Number} txIndex transaction index 78 | * @param {Number} status transaction status 79 | * @returns {Array[Field]} new state root 80 | */ 81 | async function setTxStatus(smt, root, txIndex, status) { 82 | const keyStatus = await keyTxStatus(txIndex); 83 | const result = await smt.set(root, keyStatus, Scalar.e(status)); 84 | 85 | return result.newRoot; 86 | } 87 | 88 | /** 89 | * Set cumulative gas used to smt 90 | * @param {Object} smt merkle tree structure 91 | * @param {Array[Field]} root merkle tree root 92 | * @param {Number} txIndex transaction index 93 | * @param {Number} cumulativeGasUsed transaction cumulativeGasUsed 94 | * @returns {Array[Field]} new state root 95 | */ 96 | async function setCumulativeGasUsed(smt, root, txIndex, cumulativeGasUsed) { 97 | const keyStatus = await keyTxCumulativeGasUsed(txIndex); 98 | const result = await smt.set(root, keyStatus, Scalar.e(cumulativeGasUsed)); 99 | 100 | return result.newRoot; 101 | } 102 | 103 | /** 104 | * Set effective percentage to smt 105 | * @param {Object} smt merkle tree structure 106 | * @param {Array[Field]} root merkle tree root 107 | * @param {Number} txIndex transaction index 108 | * @param {Number|String} effectivePercentage transaction effectivePercentage 109 | * @returns {Array[Field]} new state root 110 | */ 111 | async function setEffectivePercentage(smt, root, txIndex, effectivePercentage) { 112 | const keyStatus = await keyTxEffectivePercentage(txIndex); 113 | const result = await smt.set(root, keyStatus, Scalar.e(effectivePercentage)); 114 | 115 | return result.newRoot; 116 | } 117 | 118 | /** 119 | * Set logs to smt 120 | * @param {Number} logIndex current tx index 121 | * @param {Object} smt merkle tree structure 122 | * @param {String} logHash linear poseidon hash of log value H(topics + data) 123 | * @param {Array[Field]} root merkle tree root 124 | * @returns {Array[Field]} new state root 125 | */ 126 | async function setTxLog(smt, root, txIndex, logIndex, logValue) { 127 | // Get smt key from txIndex 128 | const key = await keyTxLogs(txIndex, logIndex); 129 | // Put log value in smt 130 | const res = await smt.set(root, key, logValue); 131 | 132 | return res.newRoot; 133 | } 134 | 135 | /** 136 | * Fill block info tree with tx receipt 137 | * @param {Object} smt sparse merkle tree structure 138 | * @param {Array[Field]} currentBlockInfoRoot smt current root 139 | * @param {Number} txIndex current transaction index 140 | * @param {Object} logs array object of logs 141 | * @param {Number} logIndex current log index in the block 142 | * @param {Number} status value 0/1 143 | * @param {String} l2TxHash l2 transaction hash in hex string 144 | * @param {Number} cumulativeGasUsed cumulative gas used in the block 145 | * @param {String} effectivePercentage effective percentage in hex string (1 byte) 146 | * @returns new block info root 147 | */ 148 | async function fillReceiptTree( 149 | smt, 150 | currentBlockInfoRoot, 151 | txIndex, 152 | logs, 153 | logIndex, 154 | status, 155 | l2TxHash, 156 | cumulativeGasUsed, 157 | effectivePercentage, 158 | ) { 159 | // Set tx hash at smt 160 | currentBlockInfoRoot = await setL2TxHash(smt, currentBlockInfoRoot, txIndex, l2TxHash); 161 | // Set tx status at smt 162 | currentBlockInfoRoot = await setTxStatus(smt, currentBlockInfoRoot, txIndex, status); 163 | // Set tx gas used at smt 164 | currentBlockInfoRoot = await setCumulativeGasUsed(smt, currentBlockInfoRoot, txIndex, cumulativeGasUsed); 165 | for (const log of logs) { 166 | // Loop logs 167 | const bTopics = log[1]; 168 | const topics = bTopics.reduce((previousValue, currentValue) => previousValue + currentValue.toString('hex'), ''); 169 | // Encode log: linearPoseidon(logData + topics) 170 | const encoded = await linearPoseidon(`0x${log[2].toString('hex')}${topics}`); 171 | currentBlockInfoRoot = await setTxLog(smt, currentBlockInfoRoot, txIndex, logIndex, encoded); 172 | logIndex += 1; 173 | } 174 | // Set tx effective percentage at smt 175 | currentBlockInfoRoot = await setEffectivePercentage(smt, currentBlockInfoRoot, txIndex, effectivePercentage); 176 | 177 | return currentBlockInfoRoot; 178 | } 179 | 180 | module.exports = { 181 | initBlockHeader, 182 | setBlockGasUsed, 183 | setL2TxHash, 184 | setTxStatus, 185 | setCumulativeGasUsed, 186 | setTxLog, 187 | setEffectivePercentage, 188 | fillReceiptTree, 189 | }; 190 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | const { Scalar } = require('ffjavascript'); 3 | 4 | // Database keys 5 | module.exports.DB_LAST_BATCH = ethers.utils.id(('ZKEVM_DB_LAST_BATCH')); 6 | module.exports.DB_STATE_ROOT = ethers.utils.id(('ZKEVM_DB_STATE_ROOT')); 7 | module.exports.DB_ACC_INPUT_HASH = ethers.utils.id(('ZKEVM_DB_ACC_INPUT_HASH')); 8 | module.exports.DB_LOCAL_EXIT_ROOT = ethers.utils.id(('ZKEVM_DB_LOCAL_EXIT_ROOT')); 9 | module.exports.DB_GLOBAL_EXIT_ROOT = ethers.utils.id(('ZKEVM_DB_GLOBAL_EXIT_ROOT')); 10 | module.exports.DB_ADDRESS_STORAGE = ethers.utils.id(('ZKEVM_DB_ADDRESS_STORAGE')); 11 | module.exports.DB_TOUCHED_ACCOUNTS = ethers.utils.id(('ZKEVM_DB_TOUCHED_ACCOUNTS')); 12 | module.exports.DB_STARK_INPUT = ethers.utils.id(('ZKEVM_DB_STARK_INPUT')); 13 | 14 | // Default values and global constants 15 | module.exports.DEFAULT_MAX_TX = 1000; 16 | module.exports.SIGNATURE_BYTES = 32 + 32 + 1; 17 | module.exports.EFFECTIVE_PERCENTAGE_BYTES = 1; 18 | module.exports.FrSNARK = Scalar.e('21888242871839275222246405745257275088548364400416034343698204186575808495617'); 19 | module.exports.FrSTARK = Scalar.e('18446744069414584321'); 20 | 21 | // SMT constant keys 22 | module.exports.SMT_KEY_BALANCE = 0; 23 | module.exports.SMT_KEY_NONCE = 1; 24 | module.exports.SMT_KEY_SC_CODE = 2; 25 | module.exports.SMT_KEY_SC_STORAGE = 3; 26 | module.exports.SMT_KEY_SC_LENGTH = 4; 27 | 28 | // SMT touched-tree constant keys 29 | module.exports.SMT_KEY_TOUCHED_ADDR = 5; 30 | module.exports.SMT_KEY_TOUCHED_SLOTS = 6; 31 | 32 | // SMT block header constant keys 33 | module.exports.SMT_KEY_BLOCK_HEADER_PARAM = 7; 34 | module.exports.SMT_KEY_BLOCK_HEADER_TRANSACTION_HASH = 8; 35 | module.exports.SMT_KEY_BLOCK_HEADER_STATUS = 9; 36 | module.exports.SMT_KEY_BLOCK_HEADER_CUMULATIVE_GAS_USED = 10; 37 | module.exports.SMT_KEY_BLOCK_HEADER_LOGS = 11; 38 | module.exports.SMT_KEY_BLOCK_HEADER_EFFECTIVE_PERCENTAGE = 12; 39 | 40 | // SMT block header data leaf keys 41 | module.exports.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH = 0; 42 | module.exports.INDEX_BLOCK_HEADER_PARAM_COINBASE = 1; 43 | module.exports.INDEX_BLOCK_HEADER_PARAM_NUMBER = 2; 44 | module.exports.INDEX_BLOCK_HEADER_PARAM_GAS_LIMIT = 3; 45 | module.exports.INDEX_BLOCK_HEADER_PARAM_TIMESTAMP = 4; 46 | module.exports.INDEX_BLOCK_HEADER_PARAM_GER = 5; 47 | module.exports.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH_L1 = 6; 48 | module.exports.INDEX_BLOCK_HEADER_PARAM_GAS_USED = 7; 49 | 50 | // SMT constant 51 | module.exports.BYTECODE_ELEMENTS_HASH = 8; 52 | module.exports.BYTECODE_BYTES_ELEMENT = 7; 53 | module.exports.BYTECODE_EMPTY = '0x0000000000000000000000000000000000000000000000000000000000000000'; 54 | module.exports.HASH_POSEIDON_ALL_ZEROES = '0xc71603f33a1144ca7953db0ab48808f4c4055e3364a246c33c18a9786cb0b359'; 55 | 56 | // EVM constant 57 | module.exports.ADDRESS_BRIDGE = '0x9D98DeAbC42dd696Deb9e40b4f1CAB7dDBF55988'; 58 | module.exports.ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 = '0xa40D5f56745a118D0906a34E69aeC8C0Db1cB8fA'; 59 | module.exports.GLOBAL_EXIT_ROOT_STORAGE_POS = 0; 60 | module.exports.LOCAL_EXIT_ROOT_STORAGE_POS = 1; 61 | module.exports.BLOCK_GAS_LIMIT = 1125899906842624; 62 | module.exports.TX_GAS_LIMIT = 30000000; 63 | module.exports.BATCH_DIFFICULTY = 0; 64 | module.exports.ADDRESS_SYSTEM = '0x000000000000000000000000000000005ca1ab1e'; 65 | 66 | // Adress system storage slots 67 | module.exports.LAST_BLOCK_STORAGE_POS = 0; 68 | module.exports.STATE_ROOT_STORAGE_POS = 1; 69 | module.exports.TIMESTAMP_STORAGE_POS = 2; 70 | module.exports.BLOCK_INFO_ROOT_STORAGE_POS = 3; 71 | 72 | // Bridge Leaf Types 73 | module.exports.BRIDGE_LEAF_TYPE_ASSET = 0; 74 | module.exports.BRIDGE_LEAF_TYPE_MESSAGE = 1; 75 | 76 | // Tx Types 77 | module.exports.TX_CHANGE_L2_BLOCK = 11; 78 | 79 | // Tx Type 11: Change L2 Block constants 80 | module.exports.DELTA_TIMESTAMP_BYTES = 4; 81 | module.exports.INDEX_L1INFOTREE_BYTES = 4; 82 | module.exports.TYPE_BYTES = 1; 83 | 84 | // Bridge 85 | module.exports.GLOBAL_INDEX_MAINNET_FLAG = Scalar.pow(2, 64); 86 | 87 | // Common 88 | module.exports.ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000'; 89 | module.exports.L1_INFO_DATA_ZERO = '0x3cac317908c699fe873a7f6ee4e8cd63fbe9918b2315c97be91585590168e301'; 90 | -------------------------------------------------------------------------------- /src/contract-utils.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | const { Scalar } = require('ffjavascript'); 3 | const { sha256Snark, padZeros } = require('./utils'); 4 | 5 | /** 6 | * Compute accumulateInputHash = Keccak256(oldAccInputHash, batchHashData, l1InfoRoot, timestampLimit, seqAddress) 7 | * @param {String} oldAccInputHash - old accumulateInputHash 8 | * @param {String} batchHashData - Batch hash data 9 | * @param {String} l1InfoRoot - Global Exit Root 10 | * @param {Number} timestampLimit - Block timestampLimit 11 | * @param {String} sequencerAddress - Sequencer address 12 | * @param {String} forcedBlockHashL1 - Flag for forced transaction 13 | * @returns {String} - accumulateInputHash in hex encoding 14 | */ 15 | function calculateAccInputHash( 16 | oldAccInputHash, 17 | batchHashData, 18 | l1InfoRoot, 19 | timestampLimit, 20 | sequencerAddress, 21 | forcedBlockHashL1, 22 | ) { 23 | const oldAccInputHashHex = `0x${Scalar.e(oldAccInputHash).toString(16).padStart(64, '0')}`; 24 | 25 | const hashKeccak = ethers.utils.solidityKeccak256( 26 | ['bytes32', 'bytes32', 'bytes32', 'uint64', 'address', 'bytes32'], 27 | [ 28 | oldAccInputHashHex, 29 | batchHashData, 30 | l1InfoRoot, 31 | timestampLimit, 32 | sequencerAddress, 33 | forcedBlockHashL1, 34 | ], 35 | ); 36 | 37 | return hashKeccak; 38 | } 39 | 40 | /** 41 | * Compute input for SNARK circuit: sha256(aggrAddress, oldStateRoot, oldAccInputHash, oldNumBatch, chainID, forkID, newStateRoot, newAccInputHash, newLocalExitRoot, newNumBatch) % FrSNARK 42 | * @param {String} oldStateRoot - Current state Root 43 | * @param {String} newStateRoot - New State root once the batch is processed 44 | * @param {String} oldAccInputHash - initial accumulateInputHash 45 | * @param {String} newAccInputHash - final accumulateInputHash 46 | * @param {String} newLocalExitRoot - New local exit root once the all batches is processed 47 | * @param {Number} oldNumBatch - initial batch number 48 | * @param {Number} newNumBatch - final batch number 49 | * @param {Number} chainID - L2 chainID 50 | * @param {String} aggregatorAddress - Aggregator Ethereum address in hex string 51 | * @param {Number} forkID - L2 rom fork identifier 52 | * @returns {String} - input snark in hex encoding 53 | */ 54 | async function calculateSnarkInput( 55 | oldStateRoot, 56 | newStateRoot, 57 | newLocalExitRoot, 58 | oldAccInputHash, 59 | newAccInputHash, 60 | oldNumBatch, 61 | newNumBatch, 62 | chainID, 63 | aggregatorAddress, 64 | forkID, 65 | ) { 66 | // 20 bytes agggregator address 67 | const strAggregatorAddress = padZeros((Scalar.fromString(aggregatorAddress, 16)).toString(16), 40); 68 | 69 | // 32 bytes each field element for oldStateRoot 70 | const strOldStateRoot = padZeros((Scalar.fromString(oldStateRoot, 16)).toString(16), 64); 71 | 72 | // 32 bytes each field element for oldStateRoot 73 | const strOldAccInputHash = padZeros((Scalar.fromString(oldAccInputHash, 16)).toString(16), 64); 74 | 75 | // 8 bytes for oldNumBatch 76 | const strOldNumBatch = padZeros(Scalar.e(oldNumBatch).toString(16), 16); 77 | 78 | // 8 bytes for chainID 79 | const strChainID = padZeros(Scalar.e(chainID).toString(16), 16); 80 | 81 | // 8 bytes for forkID 82 | const strForkID = padZeros(Scalar.e(forkID).toString(16), 16); 83 | 84 | // 32 bytes each field element for oldStateRoot 85 | const strNewStateRoot = padZeros((Scalar.fromString(newStateRoot, 16)).toString(16), 64); 86 | 87 | // 32 bytes each field element for oldStateRoot 88 | const strNewAccInputHash = padZeros((Scalar.fromString(newAccInputHash, 16)).toString(16), 64); 89 | 90 | // 32 bytes each field element for oldStateRoot 91 | const strNewLocalExitRoot = padZeros((Scalar.fromString(newLocalExitRoot, 16)).toString(16), 64); 92 | 93 | // 8 bytes for newNumBatch 94 | const strNewNumBatch = padZeros(Scalar.e(newNumBatch).toString(16), 16); 95 | 96 | // build final bytes sha256 97 | const finalStr = strAggregatorAddress 98 | .concat(strOldStateRoot) 99 | .concat(strOldAccInputHash) 100 | .concat(strOldNumBatch) 101 | .concat(strChainID) 102 | .concat(strForkID) 103 | .concat(strNewStateRoot) 104 | .concat(strNewAccInputHash) 105 | .concat(strNewLocalExitRoot) 106 | .concat(strNewNumBatch); 107 | 108 | return sha256Snark(finalStr); 109 | } 110 | 111 | /** 112 | * Batch hash data 113 | * @param {String} transactions - All raw transaction data concatenated 114 | * @returns {String} - Batch hash data 115 | */ 116 | function calculateBatchHashData( 117 | transactions, 118 | ) { 119 | return ethers.utils.solidityKeccak256( 120 | ['bytes'], 121 | [ 122 | transactions, 123 | ], 124 | ); 125 | } 126 | 127 | /** 128 | * Prepare zkSnark inputs for smart contract 129 | * @param {Object} proofJson - Contain the proof data related from snarkJs 130 | * @returns {Object} - Proof structure ready to be sent to smart contract 131 | */ 132 | function generateSolidityInputs( 133 | proofJson, 134 | ) { 135 | const { evaluations, polynomials } = proofJson; 136 | const proof = [ 137 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.C1[0]).toHexString(), 32), 138 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.C1[1]).toHexString(), 32), 139 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.C2[0]).toHexString(), 32), 140 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.C2[1]).toHexString(), 32), 141 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.W1[0]).toHexString(), 32), 142 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.W1[1]).toHexString(), 32), 143 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.W2[0]).toHexString(), 32), 144 | ethers.utils.hexZeroPad(ethers.BigNumber.from(polynomials.W2[1]).toHexString(), 32), 145 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.ql).toHexString(), 32), 146 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.qr).toHexString(), 32), 147 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.qm).toHexString(), 32), 148 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.qo).toHexString(), 32), 149 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.qc).toHexString(), 32), 150 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.s1).toHexString(), 32), 151 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.s2).toHexString(), 32), 152 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.s3).toHexString(), 32), 153 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.a).toHexString(), 32), 154 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.b).toHexString(), 32), 155 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.c).toHexString(), 32), 156 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.z).toHexString(), 32), 157 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.zw).toHexString(), 32), 158 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.t1w).toHexString(), 32), 159 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.t2w).toHexString(), 32), 160 | ethers.utils.hexZeroPad(ethers.BigNumber.from(evaluations.inv).toHexString(), 32), 161 | ]; 162 | 163 | return proof; 164 | } 165 | 166 | module.exports = { 167 | calculateAccInputHash, 168 | calculateSnarkInput, 169 | calculateBatchHashData, 170 | generateSolidityInputs, 171 | }; 172 | -------------------------------------------------------------------------------- /src/database.js: -------------------------------------------------------------------------------- 1 | const { Client } = require('pg'); 2 | const { Scalar } = require('ffjavascript'); 3 | const { h4toString } = require('./smt-utils'); 4 | 5 | class Database { 6 | /** 7 | * Constructor Database 8 | * @param {Field} F - Field element 9 | * @param {Object} db - Initial database to load in memory 10 | */ 11 | constructor(F, db) { 12 | this.F = F; 13 | this.useRemoteDB = false; 14 | this.connected = false; 15 | this.readOnly = true; 16 | this.dbNodesTable = 'state.nodes'; 17 | this.dbProgramTable = 'state.program'; 18 | if (db) this.db = db; 19 | else this.db = {}; 20 | } 21 | 22 | /** 23 | * Check if a remote connection to a SQL database is used 24 | */ 25 | _checkUseRemoteDB() { 26 | if (!this.useRemoteDB) { 27 | throw new Error('SQL database is not configured'); 28 | } 29 | } 30 | 31 | /** 32 | * Check if connected to the SQL database 33 | */ 34 | _checkConnected() { 35 | if (!this.connected) { 36 | throw new Error('SQL database is not connected'); 37 | } 38 | } 39 | 40 | /** 41 | * Insert data in the SQL database for a specific hash value 42 | * @param {String} tableName - name of the table where to insert the data 43 | * @param {String} hash - hash value 44 | * @param {String} data - data value 45 | */ 46 | async _insertDB(tableName, hash, data) { 47 | this._checkConnected(); 48 | 49 | // Remove initial "0x" 50 | const h = (hash.startsWith('0x') ? hash.slice(2) : hash); 51 | 52 | const query = `INSERT INTO ${tableName} ( hash, data ) VALUES ( E'\\\\x${h}', E'\\\\x${data}' ) ON CONFLICT (hash) DO NOTHING;`; 53 | 54 | await this.client.query(query); 55 | } 56 | 57 | /** 58 | * Retrieve data from the SQL database for a specific hash value 59 | * @param {String} tableName - name of the table from where to retrieve data 60 | * @param {String} hash - hash value 61 | */ 62 | async _selectDB(tableName, hash) { 63 | this._checkConnected(); 64 | 65 | // Remove initial "0x" 66 | const h = (hash.startsWith('0x') ? hash.slice(2) : hash); 67 | 68 | const query = `SELECT * FROM ${tableName} WHERE hash = E'\\\\x${h}';`; 69 | 70 | const res = await this.client.query(query); 71 | 72 | if (res.rows.length === 0) { 73 | return null; 74 | } 75 | 76 | const dataS = Buffer.from(res.rows[0].data).toString('hex'); 77 | 78 | return dataS; 79 | } 80 | 81 | /** 82 | * Connect to the SQL database 83 | * @param {String} connectionString - Connection string for the database. If the value is "local" or "memdb" no remote SQL database will be used, data will be stored only in memory 84 | * @param {String} dbNodesTable - Name of the table used to store/read nodes data. Default is "state.nodes" 85 | * @param {String} dbProgramTable - Name of the table used to store/read program data. Default is "state.program" 86 | * @param {Object} options - options for DB connection 87 | * @param {Boolean} options.readOnly - read only on SQL DB connection. Default: true 88 | */ 89 | async connect(connectionString, dbNodesTable, dbProgramTable, options = {}) { 90 | if (connectionString && !['local', 'memdb'].includes(connectionString)) { 91 | this.useRemoteDB = true; 92 | if (dbNodesTable) this.dbNodesTable = dbNodesTable; 93 | if (dbProgramTable) this.dbProgramTable = dbProgramTable; 94 | if (options.readOnly === false) this.readOnly = false; 95 | this.client = new Client({ connectionString }); 96 | await this.client.connect(); 97 | this.connected = true; 98 | } 99 | } 100 | 101 | /** 102 | * Disconnect from the SQL database 103 | */ 104 | async disconnect() { 105 | this._checkUseRemoteDB(); 106 | 107 | await this.client.end(); 108 | this.connected = false; 109 | } 110 | 111 | /** 112 | * Get merkle-tree node value 113 | * @param {Array[Field]} key - key in Array Field representation 114 | * @returns {Array[Fields] | null} Node childs if found, otherwise return null 115 | */ 116 | async getSmtNode(key) { 117 | if (key.length !== 4) { 118 | throw Error('SMT key must be an array of 4 Fields'); 119 | } 120 | 121 | const keyS = h4toString(key); 122 | let found = false; 123 | 124 | if (typeof this.db[keyS] === 'undefined') { 125 | if (this.useRemoteDB) { 126 | const dataS = await this._selectDB(this.dbNodesTable, keyS); 127 | if (dataS !== null) { 128 | if (dataS.length % 16 !== 0) { 129 | throw new Error(`Found incorrect DATA value size: ${dataS.length}`); 130 | } 131 | 132 | this.db[keyS] = []; 133 | for (let i = 0; i < dataS.length; i += 16) { 134 | this.db[keyS].push(dataS.substring(i, i + 16)); 135 | } 136 | 137 | found = true; 138 | } 139 | } 140 | } else found = true; 141 | 142 | if (found) { 143 | const data = []; 144 | for (let i = 0; i < this.db[keyS].length; i++) { 145 | data.push(this.F.e(`0x${this.db[keyS][i]}`)); 146 | } 147 | 148 | if (this.capturing) { 149 | this.capturing[keyS] = this.db[keyS]; 150 | } 151 | 152 | return data; 153 | } 154 | 155 | return null; 156 | } 157 | 158 | /** 159 | * Set merkle-tree node 160 | * @param {Array[Field]} key - key in Field representation 161 | * @param {Array[Field]} value - child array 162 | */ 163 | async setSmtNode(key, value) { 164 | if (key.length !== 4) { 165 | throw Error('SMT key must be an array of 4 Fields'); 166 | } 167 | 168 | const keyS = h4toString(key); 169 | 170 | this.db[keyS] = []; 171 | 172 | for (let i = 0; i < value.length; i++) { 173 | this.db[keyS].push(this.F.toString(value[i], 16).padStart(16, '0')); 174 | } 175 | 176 | if (this.useRemoteDB && !this.readOnly) { 177 | let dataS = ''; 178 | for (let i = 0; i < this.db[keyS].length; i++) { 179 | dataS += this.db[keyS][i]; 180 | } 181 | await this._insertDB(this.dbNodesTable, keyS, dataS); 182 | } 183 | } 184 | 185 | /** 186 | * Set value 187 | * @param {String | Scalar} key - key in scalar or hex representation 188 | * @param {Any} value - value to insert into the DB (JSON valid format) 189 | */ 190 | async setValue(key, value) { 191 | const keyS = Scalar.e(key).toString(16).padStart(64, '0'); 192 | const jsonS = JSON.stringify(value); 193 | 194 | this.db[keyS] = Buffer.from(jsonS, 'utf8').toString('hex'); 195 | 196 | if (this.useRemoteDB && !this.readOnly) { 197 | await this._insertDB(this.dbProgramTable, keyS, this.db[keyS]); 198 | } 199 | } 200 | 201 | /** 202 | * Get value 203 | * @param {String | Scalar} key - key in scalar or hex representation 204 | * @returns {Any} - value retrieved from database 205 | */ 206 | async getValue(key) { 207 | const keyS = Scalar.e(key).toString(16).padStart(64, '0'); 208 | let found = false; 209 | 210 | if (typeof this.db[keyS] === 'undefined') { 211 | if (this.useRemoteDB) { 212 | const dataS = await this._selectDB(this.dbProgramTable, keyS); 213 | if (dataS != null) { 214 | this.db[keyS] = dataS; 215 | found = true; 216 | } 217 | } 218 | } else found = true; 219 | 220 | if (found) { 221 | if (this.capturing) { 222 | this.capturing[keyS] = this.db[keyS]; 223 | } 224 | 225 | return JSON.parse(Buffer.from(this.db[keyS], 'hex').toString('utf-8')); 226 | } 227 | 228 | return null; 229 | } 230 | 231 | /** 232 | * Get program value 233 | * @param {Array[Field]} key - key in Array Field representation 234 | * @returns {Array[Byte] | null} Node childs if found, otherwise return null 235 | */ 236 | async getProgram(key) { 237 | if (key.length !== 4) { 238 | throw Error('Program key must be an array of 4 Fields'); 239 | } 240 | 241 | const keyS = h4toString(key); 242 | let found = false; 243 | 244 | if (typeof this.db[keyS] === 'undefined') { 245 | if (this.useRemoteDB) { 246 | const dataS = await this._selectDB(this.dbProgramTable, keyS); 247 | if (dataS != null) { 248 | this.db[keyS] = dataS; 249 | found = true; 250 | } 251 | } 252 | } else found = true; 253 | 254 | if (found) { 255 | if (this.capturing) { 256 | this.capturing[keyS] = this.db[keyS]; 257 | } 258 | 259 | return Array.prototype.slice.call(Buffer.from(this.db[keyS], 'hex')); 260 | } 261 | 262 | return null; 263 | } 264 | 265 | /** 266 | * Set program node 267 | * @param {Array[Field]} key - key in Field representation 268 | * @param {Array[byte]} value - child array 269 | */ 270 | async setProgram(key, value) { 271 | if (key.length !== 4) { 272 | throw Error('Program key must be an array of 4 Fields'); 273 | } 274 | 275 | const keyS = h4toString(key); 276 | 277 | this.db[keyS] = Buffer.from(value).toString('hex'); 278 | 279 | if (this.useRemoteDB && !this.readOnly) { 280 | await this._insertDB(this.dbProgramTable, keyS, this.db[keyS]); 281 | } 282 | } 283 | 284 | /** 285 | * Enable capture of data read from the SQL database 286 | */ 287 | startCapture() { 288 | this.capturing = {}; 289 | } 290 | 291 | /** 292 | * Stop capturing data read from the SQL database 293 | */ 294 | endCapture() { 295 | const res = this.capturing; 296 | delete this.capturing; 297 | 298 | return res; 299 | } 300 | } 301 | 302 | module.exports = Database; 303 | -------------------------------------------------------------------------------- /src/l1-info-tree-utils.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | 3 | /** 4 | * Calculate L1InfoTree leaf value 5 | * @param {String} globalExitRoot - global exit root 6 | * @param {String} blockHash - block hash 7 | * @param {BigInt} timestamp - Timestamp 8 | * @returns {Sting} - Leaf value 9 | */ 10 | function getL1InfoTreeValue(globalExitRoot, blockHash, timestamp) { 11 | return ethers.utils.solidityKeccak256( 12 | ['bytes32', 'bytes32', 'uint64'], 13 | [ 14 | globalExitRoot, 15 | blockHash, 16 | timestamp, 17 | ], 18 | ); 19 | } 20 | 21 | module.exports = { 22 | getL1InfoTreeValue, 23 | }; 24 | -------------------------------------------------------------------------------- /src/mem-db.js: -------------------------------------------------------------------------------- 1 | const { Scalar } = require('ffjavascript'); 2 | const { h4toString } = require('./smt-utils'); 3 | 4 | class MemDB { 5 | /** 6 | * Constructor Memory Db 7 | * @param {Field} F - Field element 8 | * @param {Object} db - Database to load 9 | */ 10 | constructor(F, db) { 11 | if (db) { 12 | this.db = db; 13 | } else { 14 | this.db = {}; 15 | } 16 | this.F = F; 17 | } 18 | 19 | /** 20 | * Get merkle-tree node value 21 | * @param {Array[Field]} key - key in Array Field representation 22 | * @returns {Array[Fields] | null} Node childs if found, otherwise return null 23 | */ 24 | async getSmtNode(key) { 25 | if (key.length !== 4) { 26 | throw Error('SMT key must be an array of 4 Fields'); 27 | } 28 | 29 | const keyS = h4toString(key); 30 | const res = []; 31 | 32 | if (typeof this.db[keyS] === 'undefined') { 33 | return null; 34 | } 35 | 36 | for (let i = 0; i < this.db[keyS].length; i++) { 37 | res.push(this.F.e(`0x${this.db[keyS][i]}`)); 38 | } 39 | 40 | if (this.capturing) { 41 | this.capturing[keyS] = this.db[keyS]; 42 | } 43 | 44 | return res; 45 | } 46 | 47 | /** 48 | * Set merkle-tree node 49 | * @param {Array[Field]} key - key in Field representation 50 | * @param {Array[Field]} value - child array 51 | */ 52 | async setSmtNode(key, value) { 53 | if (key.length !== 4) { 54 | throw Error('SMT key must be an array of 4 Fields'); 55 | } 56 | 57 | const keyS = h4toString(key); 58 | this.db[keyS] = []; 59 | 60 | for (let i = 0; i < value.length; i++) { 61 | this.db[keyS].push(this.F.toString(value[i], 16).padStart(16, '0')); 62 | } 63 | } 64 | 65 | /** 66 | * Set value 67 | * @param {String | Scalar} key - key in scalar or hex representation 68 | * @param {Any} value - value to insert into the DB (JSON valid format) 69 | */ 70 | async setValue(key, value) { 71 | const keyS = Scalar.e(key).toString(16).padStart(64, '0'); 72 | this.db[keyS] = JSON.stringify(value); 73 | } 74 | 75 | /** 76 | * Get value 77 | * @param {String | Scalar} key - key in scalar or hex representation 78 | * @returns {Any} - value retirved from database 79 | */ 80 | async getValue(key) { 81 | const keyS = Scalar.e(key).toString(16).padStart(64, '0'); 82 | 83 | if (typeof this.db[keyS] === 'undefined') { 84 | return null; 85 | } 86 | 87 | return JSON.parse(this.db[keyS]); 88 | } 89 | 90 | /** 91 | * Get program value 92 | * @param {Array[Field]} key - key in Array Field representation 93 | * @returns {Array[Byte] | null} Node childs if found, otherwise return null 94 | */ 95 | async getProgram(key) { 96 | if (key.length !== 4) { 97 | throw Error('Program key must be an array of 4 Fields'); 98 | } 99 | 100 | const keyS = h4toString(key); 101 | 102 | if (typeof this.db[keyS] === 'undefined') { 103 | return null; 104 | } 105 | 106 | if (this.capturing) { 107 | this.capturing[keyS] = this.db[keyS]; 108 | } 109 | 110 | return this.db[keyS]; 111 | } 112 | 113 | /** 114 | * Set program node 115 | * @param {Array[Field]} key - key in Field representation 116 | * @param {Array[byte]} value - child array 117 | */ 118 | async setProgram(key, value) { 119 | if (key.length !== 4) { 120 | throw Error('Program key must be an array of 4 Fields'); 121 | } 122 | 123 | const keyS = h4toString(key); 124 | this.db[keyS] = value; 125 | } 126 | 127 | startCapture() { 128 | this.capturing = {}; 129 | } 130 | 131 | endCapture() { 132 | const res = this.capturing; 133 | delete this.capturing; 134 | 135 | return res; 136 | } 137 | } 138 | 139 | module.exports = MemDB; 140 | -------------------------------------------------------------------------------- /src/mt-bridge-utils.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | const { Scalar } = require('ffjavascript'); 3 | const Constants = require('./constants'); 4 | 5 | /** 6 | * Calculate an array zero hashes of 7 | * @param {Number} height - Merkle tree height 8 | * @returns {Array} - Zero hashes array with length: height - 1 9 | */ 10 | function generateZeroHashes(height) { 11 | const zeroHashes = []; 12 | zeroHashes.push(ethers.constants.HashZero); 13 | for (let i = 1; i < height; i++) { 14 | zeroHashes.push(ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [zeroHashes[i - 1], zeroHashes[i - 1]])); 15 | } 16 | 17 | return zeroHashes; 18 | } 19 | 20 | /** 21 | * Verify merkle proof 22 | * @param {BigNumber} leaf - Leaf value 23 | * @param {Array} smtProof - Array of siblings 24 | * @param {Number} index - Index of the leaf 25 | * @param {BigNumber} root - Merkle root 26 | * @returns {Boolean} - Whether the merkle proof is correct or not 27 | */ 28 | function verifyMerkleProof(leaf, smtProof, index, root) { 29 | let value = leaf; 30 | for (let i = 0; i < smtProof.length; i++) { 31 | if (Math.floor(index / 2 ** i) % 2 !== 0) { 32 | value = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [smtProof[i], value]); 33 | } else { 34 | value = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [value, smtProof[i]]); 35 | } 36 | } 37 | 38 | return value === root; 39 | } 40 | 41 | /** 42 | * Calculate leaf value 43 | * @param {Number} leafType - Leaf Type 44 | * @param {Number} originNetwork - Original network 45 | * @param {String} originAddress - Token address 46 | * @param {Number} destinationNetwork - Destination network 47 | * @param {String} destinationAddress - Destination address 48 | * @param {BigNumber} amount - Amount of tokens 49 | * @param {BigNumber} metadataHash - Hash of the metadata 50 | * @returns {String} - Leaf value 51 | */ 52 | function getLeafValue(leafType, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadataHash) { 53 | return ethers.utils.solidityKeccak256(['uint8', 'uint32', 'address', 'uint32', 'address', 'uint256', 'bytes32'], [leafType, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadataHash]); 54 | } 55 | 56 | /** 57 | * Compute globalIndex 58 | * | 191 bits | 1 bit | 32 bits | 32 bits | 59 | * | 0 | mainnetFlag | indexRollup | indexLocal | 60 | * @param {Number | BigInt} indexLocal - leaf index on the mainnet exit tree 61 | * @param {Number | BigInt} indexRollup - leaf index on the rollup tree 62 | * @param {Bool} isMainnet flag that indicates if it is mainnet 63 | * @returns {BigInt} global index 64 | */ 65 | function computeGlobalIndex(indexLocal, indexRollup, isMainnet) { 66 | if (isMainnet === true) { 67 | return Scalar.add(indexLocal, Constants.GLOBAL_INDEX_MAINNET_FLAG); 68 | } 69 | 70 | return Scalar.add(indexLocal, Scalar.mul(indexRollup, Scalar.pow(2, 32))); 71 | } 72 | 73 | module.exports = { 74 | generateZeroHashes, 75 | verifyMerkleProof, 76 | getLeafValue, 77 | computeGlobalIndex, 78 | }; 79 | -------------------------------------------------------------------------------- /src/mt-bridge.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | const { 3 | generateZeroHashes, 4 | } = require('./mt-bridge-utils'); 5 | 6 | class MTBridge { 7 | constructor(height) { 8 | if (height <= 1) { 9 | throw new Error('MT height is not greater than 1'); 10 | } 11 | this.height = height; 12 | this.zeroHashes = generateZeroHashes(height); 13 | const tree = []; 14 | for (let i = 0; i <= height; i++) { 15 | tree.push([]); 16 | } 17 | this.tree = tree; 18 | this.dirty = false; 19 | } 20 | 21 | add(leaf) { 22 | this.dirty = true; 23 | this.tree[0].push(leaf); 24 | } 25 | 26 | calcBranches() { 27 | for (let i = 0; i < this.height; i++) { 28 | const parent = this.tree[i + 1]; 29 | const child = this.tree[i]; 30 | for (let j = 0; j < child.length; j += 2) { 31 | const leftNode = child[j]; 32 | const rightNode = (j + 1 < child.length) ? child[j + 1] : this.zeroHashes[i]; 33 | parent[j / 2] = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [leftNode, rightNode]); 34 | } 35 | } 36 | this.dirty = false; 37 | } 38 | 39 | getProofTreeByIndex(index) { 40 | if (this.dirty) this.calcBranches(); 41 | const proof = []; 42 | let currentIndex = index; 43 | for (let i = 0; i < this.height; i++) { 44 | currentIndex = currentIndex % 2 === 1 ? currentIndex - 1 : currentIndex + 1; 45 | if (currentIndex < this.tree[i].length) proof.push(this.tree[i][currentIndex]); 46 | else proof.push(this.zeroHashes[i]); 47 | currentIndex = Math.floor(currentIndex / 2); 48 | } 49 | 50 | return proof; 51 | } 52 | 53 | getProofTreeByValue(value) { 54 | const index = this.tree[0].indexOf(value); 55 | 56 | return this.getProofTreeByIndex(index); 57 | } 58 | 59 | getRoot() { 60 | if (this.tree[0][0] === undefined) { 61 | // No leafs in the tree, calculate root with all leafs to 0 62 | return ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [this.zeroHashes[this.height - 1], this.zeroHashes[this.height - 1]]); 63 | } 64 | if (this.dirty) this.calcBranches(); 65 | 66 | return this.tree[this.height][0]; 67 | } 68 | } 69 | 70 | module.exports = MTBridge; 71 | -------------------------------------------------------------------------------- /src/poseidon.js: -------------------------------------------------------------------------------- 1 | const { F1Field } = require('ffjavascript'); 2 | 3 | let poseidon; 4 | let isBuilt = false; 5 | 6 | /** 7 | * Build poseidon hash function with golden prime 8 | * @returns {Object} poseidon function 9 | */ 10 | async function buildPoseidon() { 11 | const goldenPrime = (1n << 64n) - (1n << 32n) + 1n; 12 | 13 | const F = new F1Field(goldenPrime); 14 | 15 | const t = 12; 16 | const nRoundsF = 8; 17 | const nRoundsP = 22; 18 | 19 | const C = [ 20 | 0xb585f766f2144405n, 0x7746a55f43921ad7n, 0xb2fb0d31cee799b4n, 0x0f6760a4803427d7n, 21 | 0xe10d666650f4e012n, 0x8cae14cb07d09bf1n, 0xd438539c95f63e9fn, 0xef781c7ce35b4c3dn, 22 | 0xcdc4a239b0c44426n, 0x277fa208bf337bffn, 0xe17653a29da578a1n, 0xc54302f225db2c76n, 23 | 0x86287821f722c881n, 0x59cd1a8a41c18e55n, 0xc3b919ad495dc574n, 0xa484c4c5ef6a0781n, 24 | 0x308bbd23dc5416ccn, 0x6e4a40c18f30c09cn, 0x9a2eedb70d8f8cfan, 0xe360c6e0ae486f38n, 25 | 0xd5c7718fbfc647fbn, 0xc35eae071903ff0bn, 0x849c2656969c4be7n, 0xc0572c8c08cbbbadn, 26 | 0xe9fa634a21de0082n, 0xf56f6d48959a600dn, 0xf7d713e806391165n, 0x8297132b32825dafn, 27 | 0xad6805e0e30b2c8an, 0xac51d9f5fcf8535en, 0x502ad7dc18c2ad87n, 0x57a1550c110b3041n, 28 | 0x66bbd30e6ce0e583n, 0x0da2abef589d644en, 0xf061274fdb150d61n, 0x28b8ec3ae9c29633n, 29 | 0x92a756e67e2b9413n, 0x70e741ebfee96586n, 0x019d5ee2af82ec1cn, 0x6f6f2ed772466352n, 30 | 0x7cf416cfe7e14ca1n, 0x61df517b86a46439n, 0x85dc499b11d77b75n, 0x4b959b48b9c10733n, 31 | 0xe8be3e5da8043e57n, 0xf5c0bc1de6da8699n, 0x40b12cbf09ef74bfn, 0xa637093ecb2ad631n, 32 | 0x3cc3f892184df408n, 0x2e479dc157bf31bbn, 0x6f49de07a6234346n, 0x213ce7bede378d7bn, 33 | 0x5b0431345d4dea83n, 0xa2de45780344d6a1n, 0x7103aaf94a7bf308n, 0x5326fc0d97279301n, 34 | 0xa9ceb74fec024747n, 0x27f8ec88bb21b1a3n, 0xfceb4fda1ded0893n, 0xfac6ff1346a41675n, 35 | 0x7131aa45268d7d8cn, 0x9351036095630f9fn, 0xad535b24afc26bfbn, 0x4627f5c6993e44ben, 36 | 0x645cf794b8f1cc58n, 0x241c70ed0af61617n, 0xacb8e076647905f1n, 0x3737e9db4c4f474dn, 37 | 0xe7ea5e33e75fffb6n, 0x90dee49fc9bfc23an, 0xd1b1edf76bc09c92n, 0x0b65481ba645c602n, 38 | 0x99ad1aab0814283bn, 0x438a7c91d416ca4dn, 0xb60de3bcc5ea751cn, 0xc99cab6aef6f58bcn, 39 | 0x69a5ed92a72ee4ffn, 0x5e7b329c1ed4ad71n, 0x5fc0ac0800144885n, 0x32db829239774ecan, 40 | 0x0ade699c5830f310n, 0x7cc5583b10415f21n, 0x85df9ed2e166d64fn, 0x6604df4fee32bcb1n, 41 | 0xeb84f608da56ef48n, 0xda608834c40e603dn, 0x8f97fe408061f183n, 0xa93f485c96f37b89n, 42 | 0x6704e8ee8f18d563n, 0xcee3e9ac1e072119n, 0x510d0e65e2b470c1n, 0xf6323f486b9038f0n, 43 | 0x0b508cdeffa5ceefn, 0xf2417089e4fb3cbdn, 0x60e75c2890d15730n, 0xa6217d8bf660f29cn, 44 | 0x7159cd30c3ac118en, 0x839b4e8fafead540n, 0x0d3f3e5e82920adcn, 0x8f7d83bddee7bba8n, 45 | 0x780f2243ea071d06n, 0xeb915845f3de1634n, 0xd19e120d26b6f386n, 0x016ee53a7e5fecc6n, 46 | 0xcb5fd54e7933e477n, 0xacb8417879fd449fn, 0x9c22190be7f74732n, 0x5d693c1ba3ba3621n, 47 | 0xdcef0797c2b69ec7n, 0x3d639263da827b13n, 0xe273fd971bc8d0e7n, 0x418f02702d227ed5n, 48 | 0x8c25fda3b503038cn, 0x2cbaed4daec8c07cn, 0x5f58e6afcdd6ddc2n, 0x284650ac5e1b0eban, 49 | 0x635b337ee819dab5n, 0x9f9a036ed4f2d49fn, 0xb93e260cae5c170en, 0xb0a7eae879ddb76dn, 50 | 0xd0762cbc8ca6570cn, 0x34c6efb812b04bf5n, 0x40bf0ab5fa14c112n, 0xb6b570fc7c5740d3n, 51 | 0x5a27b9002de33454n, 0xb1a5b165b6d2b2d2n, 0x8722e0ace9d1be22n, 0x788ee3b37e5680fbn, 52 | 0x14a726661551e284n, 0x98b7672f9ef3b419n, 0xbb93ae776bb30e3an, 0x28fd3b046380f850n, 53 | 0x30a4680593258387n, 0x337dc00c61bd9ce1n, 0xd5eca244c7a4ff1dn, 0x7762638264d279bdn, 54 | 0xc1e434bedeefd767n, 0x0299351a53b8ec22n, 0xb2d456e4ad251b80n, 0x3e9ed1fda49cea0bn, 55 | 0x2972a92ba450bed8n, 0x20216dd77be493den, 0xadffe8cf28449ec6n, 0x1c4dbb1c4c27d243n, 56 | 0x15a16a8a8322d458n, 0x388a128b7fd9a609n, 0x2300e5d6baedf0fbn, 0x2f63aa8647e15104n, 57 | 0xf1c36ce86ecec269n, 0x27181125183970c9n, 0xe584029370dca96dn, 0x4d9bbc3e02f1cfb2n, 58 | 0xea35bc29692af6f8n, 0x18e21b4beabb4137n, 0x1e3b9fc625b554f4n, 0x25d64362697828fdn, 59 | 0x5a3f1bb1c53a9645n, 0xdb7f023869fb8d38n, 0xb462065911d4e1fcn, 0x49c24ae4437d8030n, 60 | 0xd793862c112b0566n, 0xaadd1106730d8febn, 0xc43b6e0e97b0d568n, 0xe29024c18ee6fca2n, 61 | 0x5e50c27535b88c66n, 0x10383f20a4ff9a87n, 0x38e8ee9d71a45af8n, 0xdd5118375bf1a9b9n, 62 | 0x775005982d74d7f7n, 0x86ab99b4dde6c8b0n, 0xb1204f603f51c080n, 0xef61ac8470250ecfn, 63 | 0x1bbcd90f132c603fn, 0x0cd1dabd964db557n, 0x11a3ae5beb9d1ec9n, 0xf755bfeea585d11dn, 64 | 0xa3b83250268ea4d7n, 0x516306f4927c93afn, 0xddb4ac49c9efa1dan, 0x64bb6dec369d4418n, 65 | 0xf9cc95c22b4c1fccn, 0x08d37f755f4ae9f6n, 0xeec49b613478675bn, 0xf143933aed25e0b0n, 66 | 0xe4c5dd8255dfc622n, 0xe7ad7756f193198en, 0x92c2318b87fff9cbn, 0x739c25f8fd73596dn, 67 | 0x5636cac9f16dfed0n, 0xdd8f909a938e0172n, 0xc6401fe115063f5bn, 0x8ad97b33f1ac1455n, 68 | 0x0c49366bb25e8513n, 0x0784d3d2f1698309n, 0x530fb67ea1809a81n, 0x410492299bb01f49n, 69 | 0x139542347424b9acn, 0x9cb0bd5ea1a1115en, 0x02e3f615c38f49a1n, 0x985d4f4a9c5291efn, 70 | 0x775b9feafdcd26e7n, 0x304265a6384f0f2dn, 0x593664c39773012cn, 0x4f0a2e5fb028f2cen, 71 | 0xdd611f1000c17442n, 0xd8185f9adfea4fd0n, 0xef87139ca9a3ab1en, 0x3ba71336c34ee133n, 72 | 0x7d3a455d56b70238n, 0x660d32e130182684n, 0x297a863f48cd1f43n, 0x90e0a736a751ebb7n, 73 | 0x549f80ce550c4fd3n, 0x0f73b2922f38bd64n, 0x16bf1f73fb7a9c3fn, 0x6d1f5a59005bec17n, 74 | 0x02ff876fa5ef97c4n, 0xc5cb72a2a51159b0n, 0x8470f39d2d5c900en, 0x25abb3f1d39fcb76n, 75 | 0x23eb8cc9b372442fn, 0xd687ba55c64f6364n, 0xda8d9e90fd8ff158n, 0xe3cbdc7d2fe45ea7n, 76 | 0xb9a8c9b3aee52297n, 0xc0d28a5c10960bd3n, 0x45d7ac9b68f71a34n, 0xeeb76e397069e804n, 77 | 0x3d06c8bd1514e2d9n, 0x9c9c98207cb10767n, 0x65700b51aedfb5efn, 0x911f451539869408n, 78 | 0x7ae6849fbc3a0ec6n, 0x3bb340eba06afe7en, 0xb46e9d8b682ea65en, 0x8dcf22f9a3b34356n, 79 | 0x77bdaeda586257a7n, 0xf19e400a5104d20dn, 0xc368a348e46d950fn, 0x9ef1cd60e679f284n, 80 | 0xe89cd854d5d01d33n, 0x5cd377dc8bb882a2n, 0xa7b0fb7883eee860n, 0x7684403ec392950dn, 81 | 0x5fa3f06f4fed3b52n, 0x8df57ac11bc04831n, 0x2db01efa1e1e1897n, 0x54846de4aadb9ca2n, 82 | 0xba6745385893c784n, 0x541d496344d2c75bn, 0xe909678474e687fen, 0xdfe89923f6c9c2ffn, 83 | 0xece5a71e0cfedc75n, 0x5ff98fd5d51fe610n, 0x83e8941918964615n, 0x5922040b47f150c1n, 84 | 0xf97d750e3dd94521n, 0x5080d4c2b86f56d7n, 0xa7de115b56c78d70n, 0x6a9242ac87538194n, 85 | 0xf7856ef7f9173e44n, 0x2265fc92feb0dc09n, 0x17dfc8e4f7ba8a57n, 0x9001a64209f21db8n, 86 | 0x90004c1371b893c5n, 0xb932b7cf752e5545n, 0xa0b1df81b6fe59fcn, 0x8ef1dd26770af2c2n, 87 | 0x0541a4f9cfbeed35n, 0x9e61106178bfc530n, 0xb3767e80935d8af2n, 0x0098d5782065af06n, 88 | 0x31d191cd5c1466c7n, 0x410fefafa319ac9dn, 0xbdf8f242e316c4abn, 0x9e8cd55b57637ed0n, 89 | 0xde122bebe9a39368n, 0x4d001fd58f002526n, 0xca6637000eb4a9f8n, 0x2f2339d624f91f78n, 90 | 0x6d1a7918c80df518n, 0xdf9a4939342308e9n, 0xebc2151ee6c8398cn, 0x03cc2ba8a1116515n, 91 | 0xd341d037e840cf83n, 0x387cb5d25af4afccn, 0xbba2515f22909e87n, 0x7248fe7705f38e47n, 92 | 0x4d61e56a525d225an, 0x262e963c8da05d3dn, 0x59e89b094d220ec2n, 0x055d5b52b78b9c5en, 93 | 0x82b27eb33514ef99n, 0xd30094ca96b7ce7bn, 0xcf5cb381cd0a1535n, 0xfeed4db6919e5a7cn, 94 | 0x41703f53753be59fn, 0x5eeea940fcde8b6fn, 0x4cd1f1b175100206n, 0x4a20358574454ec0n, 95 | 0x1478d361dbbf9facn, 0x6f02dc07d141875cn, 0x296a202ed8e556a2n, 0x2afd67999bf32ee5n, 96 | 0x7acfd96efa95491dn, 0x6798ba0c0abb2c6dn, 0x34c6f57b26c92122n, 0x5736e1bad206b5den, 97 | 0x20057d2a0056521bn, 0x3dea5bd5d0578bd7n, 0x16e50d897d4634acn, 0x29bff3ecb9b7a6e3n, 98 | 0x475cd3205a3bdcden, 0x18a42105c31b7e88n, 0x023e7414af663068n, 0x15147108121967d7n, 99 | 0xe4a3dff1d7d6fef9n, 0x01a8d1a588085737n, 0x11b4c74eda62beefn, 0xe587cc0d69a73346n, 100 | 0x1ff7327017aa2a6en, 0x594e29c42473d06bn, 0xf6f31db1899b12d5n, 0xc02ac5e47312d3can, 101 | 0xe70201e960cb78b8n, 0x6f90ff3b6a65f108n, 0x42747a7245e7fa84n, 0xd1f507e43ab749b2n, 102 | 0x1c86d265f15750cdn, 0x3996ce73dd832c1cn, 0x8e7fba02983224bdn, 0xba0dec7103255dd4n, 103 | 0x9e9cbd781628fc5bn, 0xdae8645996edd6a5n, 0xdebe0853b1a1d378n, 0xa49229d24d014343n, 104 | 0x7be5b9ffda905e1cn, 0xa3c95eaec244aa30n, 0x0230bca8f4df0544n, 0x4135c2bebfe148c6n, 105 | 0x166fc0cc438a3c72n, 0x3762b59a8ae83efan, 0xe8928a4c89114750n, 0x2a440b51a4945ee5n, 106 | 0x80cefd2b7d99ff83n, 0xbb9879c6e61fd62an, 0x6e7c8f1a84265034n, 0x164bb2de1bbeddc8n, 107 | 0xf3c12fe54d5c653bn, 0x40b9e922ed9771e2n, 0x551f5b0fbe7b1840n, 0x25032aa7c4cb1811n, 108 | 0xaaed34074b164346n, 0x8ffd96bbf9c9c81dn, 0x70fc91eb5937085cn, 0x7f795e2a5f915440n, 109 | 0x4543d9df5476d3cbn, 0xf172d73e004fc90dn, 0xdfd1c4febcc81238n, 0xbc8dfb627fe558fcn, 110 | ]; 111 | 112 | for (let i = 0; i < C.length; i++) C[i] = F.e(C[i]); 113 | 114 | const MCIRC = [17n, 15n, 41n, 16n, 2n, 28n, 13n, 13n, 39n, 18n, 34n, 20n]; 115 | const MDIAG = [8n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]; 116 | 117 | const M = []; 118 | for (let i = 0; i < 12; i++) { 119 | M[i] = []; 120 | for (let j = 0; j < 12; j++) { 121 | M[i][j] = F.e(MCIRC[(-i + j + 12) % 12]); 122 | if (i === j) M[i][j] = F.add(M[i][j], MDIAG[i]); 123 | } 124 | } 125 | 126 | const pow7 = (a) => { 127 | const a2 = F.square(a); 128 | const a4 = F.square(a2); 129 | const a3 = F.mul(a, a2); 130 | 131 | return F.mul(a3, a4); 132 | }; 133 | 134 | poseidon = function (inputs, capacity) { 135 | if (inputs.length !== 8) throw new Error('Invalid Input size (must be 8)'); 136 | 137 | let state; 138 | 139 | if (capacity) { 140 | if (capacity.length !== 4) throw new Error('Invalid Capacity size (must be 4)'); 141 | state = [...inputs.map((a) => F.e(a)), ...capacity.map((a) => F.e(a))]; 142 | } else { 143 | state = [...inputs.map((a) => F.e(a)), F.zero, F.zero, F.zero, F.zero]; 144 | } 145 | for (let r = 0; r < nRoundsF + nRoundsP; r++) { 146 | state = state.map((a, i) => F.add(a, C[r * t + i])); 147 | 148 | if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) { 149 | state = state.map((a) => pow7(a)); 150 | } else { 151 | state[0] = pow7(state[0]); 152 | } 153 | 154 | // eslint-disable-next-line no-loop-func 155 | state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(M[i][j], a)), F.zero)); 156 | } 157 | 158 | return [state[0], state[1], state[2], state[3]]; 159 | }; 160 | 161 | poseidon.F = F; 162 | 163 | return poseidon; 164 | } 165 | 166 | /** 167 | * singleton to build poseidon once 168 | * @returns {Object} - poseidon hash function 169 | */ 170 | async function getPoseidon() { 171 | if (isBuilt === false) { 172 | poseidon = await buildPoseidon(); 173 | isBuilt = true; 174 | } 175 | 176 | return poseidon; 177 | } 178 | 179 | module.exports = getPoseidon; 180 | -------------------------------------------------------------------------------- /src/poseidon_opt.js: -------------------------------------------------------------------------------- 1 | // Optimization is taken from https://github.com/filecoin-project/neptune 2 | 3 | const { F1Field, Scalar } = require('ffjavascript'); 4 | const poseidonConstants = require('./poseidon_constants_opt'); 5 | 6 | let poseidon; 7 | let isBuilt = false; 8 | 9 | function unsringifyConstants(Fr, o) { 10 | if ((typeof (o) === 'string') && (/^[0-9]+$/.test(o))) { 11 | return Fr.e(o); 12 | } if ((typeof (o) === 'string') && (/^0x[0-9a-fA-F]+$/.test(o))) { 13 | return Fr.e(o); 14 | } if (Array.isArray(o)) { 15 | return o.map(unsringifyConstants.bind(null, Fr)); 16 | } if (typeof o === 'object') { 17 | if (o === null) return null; 18 | const res = {}; 19 | const keys = Object.keys(o); 20 | keys.forEach((k) => { 21 | res[k] = unsringifyConstants(Fr, o[k]); 22 | }); 23 | 24 | return res; 25 | } 26 | 27 | return o; 28 | } 29 | 30 | /** 31 | * Build poseidon hash function with golden prime 32 | * @returns {Object} poseidon function 33 | */ 34 | async function buildPoseidon() { 35 | const goldenPrime = (1n << 64n) - (1n << 32n) + 1n; 36 | 37 | const F = new F1Field(Scalar.e(goldenPrime)); 38 | 39 | const opt = unsringifyConstants(F, poseidonConstants); 40 | 41 | const pow7 = (a) => F.mul(a, F.square(F.mul(a, F.square(a, a)))); 42 | 43 | poseidon = function (inputs, capacity) { 44 | if (inputs.length !== 8) throw new Error('Invalid Input size (must be 8)'); 45 | 46 | let state; 47 | 48 | if (capacity) { 49 | if (capacity.length !== 4) throw new Error('Invalid Capacity size (must be 4)'); 50 | state = [...inputs.map((a) => F.e(a)), ...capacity.map((a) => F.e(a))]; 51 | } else { 52 | state = [...inputs.map((a) => F.e(a)), F.zero, F.zero, F.zero, F.zero]; 53 | } 54 | 55 | const t = 12; 56 | const nRoundsF = 8; 57 | const nRoundsP = 22; 58 | const { 59 | C, S, M, P, 60 | } = opt; 61 | 62 | state = state.map((a, i) => F.add(a, C[i])); 63 | 64 | for (let r = 0; r < nRoundsF / 2 - 1; r++) { 65 | state = state.map((a) => pow7(a)); 66 | state = state.map((a, i) => F.add(a, C[(r + 1) * t + i])); 67 | // eslint-disable-next-line no-loop-func 68 | state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero)); 69 | } 70 | state = state.map((a) => pow7(a)); 71 | state = state.map((a, i) => F.add(a, C[(nRoundsF / 2 - 1 + 1) * t + i])); 72 | state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(P[j][i], a)), F.zero)); 73 | for (let r = 0; r < nRoundsP; r++) { 74 | state[0] = pow7(state[0]); 75 | state[0] = F.add(state[0], C[(nRoundsF / 2 + 1) * t + r]); 76 | 77 | const s0 = state.reduce((acc, a, j) => F.add(acc, F.mul(S[(t * 2 - 1) * r + j], a)), F.zero); 78 | for (let k = 1; k < t; k++) { 79 | state[k] = F.add(state[k], F.mul(state[0], S[(t * 2 - 1) * r + t + k - 1])); 80 | } 81 | state[0] = s0; 82 | } 83 | for (let r = 0; r < nRoundsF / 2 - 1; r++) { 84 | state = state.map((a) => pow7(a)); 85 | state = state.map((a, i) => F.add(a, C[(nRoundsF / 2 + 1) * t + nRoundsP + r * t + i])); 86 | // eslint-disable-next-line no-loop-func 87 | state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero)); 88 | } 89 | state = state.map((a) => pow7(a)); 90 | state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero)); 91 | 92 | return [state[0], state[1], state[2], state[3]]; 93 | }; 94 | 95 | poseidon.F = F; 96 | 97 | return poseidon; 98 | } 99 | 100 | /** 101 | * singleton to build poseidon once 102 | * @returns {Object} - poseidon hash function 103 | */ 104 | async function getPoseidon() { 105 | if (isBuilt === false) { 106 | poseidon = await buildPoseidon(); 107 | isBuilt = true; 108 | } 109 | 110 | return poseidon; 111 | } 112 | 113 | module.exports = getPoseidon; 114 | -------------------------------------------------------------------------------- /src/state-utils.js: -------------------------------------------------------------------------------- 1 | const { Scalar } = require('ffjavascript'); 2 | const smtUtils = require('./smt-utils'); 3 | 4 | /** 5 | * Get the current state of an ethereum address 6 | * @param {String} ethAddr ethereum address 7 | * @param {Object} smt merkle tree structure 8 | * @param {Array[Field]} root merkle tree root 9 | * @returns {Object} ethereum address state 10 | */ 11 | async function getState(ethAddr, smt, root) { 12 | const keyBalance = await smtUtils.keyEthAddrBalance(ethAddr); 13 | const keyNonce = await smtUtils.keyEthAddrNonce(ethAddr); 14 | 15 | let response; 16 | try { 17 | const resBalance = await smt.get(root, keyBalance); 18 | const resNonce = await smt.get(root, keyNonce); 19 | response = { 20 | balance: resBalance.value, 21 | nonce: resNonce.value, 22 | }; 23 | } catch (error) { 24 | response = { 25 | balance: Scalar.e(0), 26 | nonce: Scalar.e(0), 27 | }; 28 | } 29 | 30 | return response; 31 | } 32 | 33 | /** 34 | * Set a state of an ethereum address 35 | * @param {String} ethAddr ethereum address 36 | * @param {Object} smt merkle tree structure 37 | * @param {Array[Field]} root merkle tree root 38 | * @param {Scalar|Number} balance new balance 39 | * @param {Scalar|Number} nonce new nonce 40 | * @returns {Array[Field]} new state root 41 | */ 42 | async function setAccountState(ethAddr, smt, root, balance, nonce) { 43 | const keyBalance = await smtUtils.keyEthAddrBalance(ethAddr); 44 | const keyNonce = await smtUtils.keyEthAddrNonce(ethAddr); 45 | 46 | let auxRes = await smt.set(root, keyBalance, Scalar.e(balance)); 47 | auxRes = await smt.set(auxRes.newRoot, keyNonce, Scalar.e(nonce)); 48 | 49 | return auxRes.newRoot; 50 | } 51 | 52 | /** 53 | * Get the hash(bytecode) of a smart contract 54 | * @param {String} ethAddr ethereum address 55 | * @param {Object} smt merkle tree structure 56 | * @param {Array[Field]} root merkle tree root 57 | * @returns {String} hash(bytecode) represented as hexadecimal string 58 | */ 59 | async function getContractHashBytecode(ethAddr, smt, root) { 60 | const keyContractCode = await smtUtils.keyContractCode(ethAddr); 61 | const res = await smt.get(root, keyContractCode); 62 | 63 | return `0x${res.value.toString(16).padStart(64, '0')}`; 64 | } 65 | 66 | /** 67 | * Get the bytecode length of a smart contract 68 | * @param {String} ethAddr ethereum address 69 | * @param {Object} smt merkle tree structure 70 | * @param {Array[Field]} root merkle tree root 71 | * @returns {Number} contract length in bytes 72 | */ 73 | async function getContractBytecodeLength(ethAddr, smt, root) { 74 | const keyContractLength = await smtUtils.keyContractLength(ethAddr); 75 | const res = await smt.get(root, keyContractLength); 76 | 77 | return Number(res.value); 78 | } 79 | 80 | /** 81 | * Set the bytecode and its length of a smart contract 82 | * @param {String} ethAddr ethereum address 83 | * @param {Object} smt merkle tree structure 84 | * @param {Array[Field]} root merkle tree root 85 | * @param {String} bytecode smart contract bytecode represented as hexadecimal string 86 | * @param {Bool} flagDelete flag to set bytecode to 0 87 | * @returns {Array[Field]} new state root 88 | */ 89 | async function setContractBytecode(ethAddr, smt, root, bytecode) { 90 | const keyContractCode = await smtUtils.keyContractCode(ethAddr); 91 | const keyContractLength = await smtUtils.keyContractLength(ethAddr); 92 | 93 | const hashByteCode = await smtUtils.hashContractBytecode(bytecode); 94 | let parsedBytecode = bytecode.startsWith('0x') ? bytecode.slice(2) : bytecode.slice(); 95 | parsedBytecode = (parsedBytecode.length % 2) ? `0${parsedBytecode}` : parsedBytecode; 96 | const bytecodeLength = parsedBytecode.length / 2; 97 | let res = await smt.set(root, keyContractCode, Scalar.fromString(hashByteCode, 16)); 98 | res = await smt.set(res.newRoot, keyContractLength, bytecodeLength); 99 | 100 | return res.newRoot; 101 | } 102 | 103 | /** 104 | * Get the sorage values of a smart contract 105 | * @param {String} ethAddr ethereum address 106 | * @param {Object} smt merkle tree structure 107 | * @param {Array[Field]} root merkle tree root 108 | * @param {Array[String|Scalar]} storagePos smart contract storage position 109 | * @returns {Object} mapping [storagePosition - value] 110 | */ 111 | async function getContractStorage(ethAddr, smt, root, storagePos) { 112 | const res = {}; 113 | 114 | for (let i = 0; i < storagePos.length; i++) { 115 | const pos = storagePos[i]; 116 | const keyStoragePos = await smtUtils.keyContractStorage(ethAddr, pos); 117 | const resSMT = await smt.get(root, keyStoragePos); 118 | res[(Scalar.e(pos)).toString()] = resSMT.value; 119 | } 120 | 121 | return res; 122 | } 123 | 124 | /** 125 | * Set the storage of a smart contract address 126 | * @param {String} ethAddr ethereum address 127 | * @param {Object} smt merkle tree structure 128 | * @param {Array[Field]} root merkle tree root 129 | * @param {Object} storage [key-value] object containing [storagePos - stoValue] 130 | * @returns {Array[Field]} new state root 131 | */ 132 | async function setContractStorage(ethAddr, smt, root, storage) { 133 | let tmpRoot = root; 134 | 135 | const storagePos = Object.keys(storage); 136 | 137 | for (let i = 0; i < storagePos.length; i++) { 138 | const pos = storagePos[i]; 139 | const value = storage[pos]; 140 | 141 | const keyStoragePos = await smtUtils.keyContractStorage(ethAddr, pos); 142 | 143 | const auxRes = await smt.set(tmpRoot, keyStoragePos, Scalar.e(value)); 144 | tmpRoot = auxRes.newRoot; 145 | } 146 | 147 | return tmpRoot; 148 | } 149 | 150 | /** 151 | * Set the smt genesis with an array of addresses, amounts and nonces 152 | * @param {String} addressArray ethereum address array 153 | * @param {Object} amountArray amount array 154 | * @param {Array[Field]} nonceArray nonce array 155 | * @param {Object} smt merkle tree structure 156 | */ 157 | async function setGenesisBlock(addressArray, amountArray, nonceArray, smt) { 158 | let currentRoot = smt.empty; 159 | for (let i = 0; i < addressArray.length; i++) { 160 | currentRoot = await setAccountState(addressArray[i], smt, currentRoot, amountArray[i], nonceArray[i]); 161 | } 162 | 163 | return currentRoot; 164 | } 165 | 166 | module.exports = { 167 | getState, 168 | setAccountState, 169 | setContractBytecode, 170 | setContractStorage, 171 | getContractBytecodeLength, 172 | getContractHashBytecode, 173 | getContractStorage, 174 | setGenesisBlock, 175 | }; 176 | -------------------------------------------------------------------------------- /src/tmp-smt-db.js: -------------------------------------------------------------------------------- 1 | const { h4toString, stringToH4 } = require('./smt-utils'); 2 | 3 | /** 4 | * This is a DB which intends to get all the state from the srcDB and 5 | * store all the inserts insetead of modifying the DB 6 | * in case the inserts are accepted, can be populated to the srcDB 7 | */ 8 | class TmpSmtDB { 9 | constructor(srcDb) { 10 | this.srcDb = srcDb; 11 | this.F = srcDb.F; 12 | this.inserts = {}; 13 | } 14 | 15 | /** 16 | * Get function of the DB, return and array of values 17 | * Use the srcDb in case there's no inserts stored with this key 18 | * @param {Array[Field]} key - Key 19 | * @returns {Array[String]} Array of hex values 20 | */ 21 | async getSmtNode(key) { 22 | if (key.length !== 4) { 23 | throw Error('SMT key must be an array of 4 Fields'); 24 | } 25 | 26 | const keyS = h4toString(key); 27 | let res = []; 28 | 29 | if (this.inserts[keyS]) { 30 | for (let i = 0; i < this.inserts[keyS].length; i++) { 31 | res.push(this.F.e(`0x${this.inserts[keyS][i]}`)); 32 | } 33 | } else { 34 | res = await this.srcDb.getSmtNode(key); 35 | } 36 | 37 | return res; 38 | } 39 | 40 | /** 41 | * Set function of the DB, all the inserts will be stored 42 | * In the inserts Object 43 | * @param {Array[Fields]} key - Key 44 | * @param {Array[Fields]} value - Value 45 | */ 46 | async setSmtNode(key, value) { 47 | if (key.length !== 4) { 48 | throw Error('SMT key must be an array of 4 Fields'); 49 | } 50 | 51 | const keyS = h4toString(key); 52 | 53 | this.inserts[keyS] = []; 54 | 55 | for (let i = 0; i < value.length; i++) { 56 | this.inserts[keyS].push(this.F.toString(value[i], 16).padStart(16, '0')); 57 | } 58 | } 59 | 60 | /** 61 | * Populate all the inserts made to the tmpDB to the srcDB 62 | */ 63 | async populateSrcDb() { 64 | const insertKeys = Object.keys(this.inserts); 65 | for (let i = 0; i < insertKeys.length; i++) { 66 | const key = stringToH4(insertKeys[i]); 67 | const value = this.inserts[insertKeys[i]].map((element) => this.F.e(`0x${element}`)); 68 | await this.srcDb.setSmtNode(key, value); 69 | } 70 | } 71 | } 72 | 73 | module.exports = TmpSmtDB; 74 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-use-before-define */ 2 | /* eslint-disable no-restricted-syntax */ 3 | const crypto = require('crypto'); 4 | const { Scalar } = require('ffjavascript'); 5 | const { FrSNARK } = require('./constants'); 6 | 7 | /** 8 | * Log2 function 9 | * @param {Number} V - value 10 | * @returns {Number} 11 | */ 12 | function log2(V) { 13 | return (((V & 0xFFFF0000) !== 0 14 | ? (V &= 0xFFFF0000, 16) : 0) | ((V & 0xFF00FF00) !== 0 15 | ? (V &= 0xFF00FF00, 8) : 0) | ((V & 0xF0F0F0F0) !== 0 16 | ? (V &= 0xF0F0F0F0, 4) : 0) | ((V & 0xCCCCCCCC) !== 0 17 | ? (V &= 0xCCCCCCCC, 2) : 0) | ((V & 0xAAAAAAAA) !== 0)); 18 | } 19 | 20 | /** 21 | * Convert a value into in its hexadecimal string representation 22 | * @param {Number | BigInt} _value - value to encode 23 | * @param {Boolean} prefix - attach '0x' at the beginning of the string 24 | * @returns {String} encoded value in hexadecimal string 25 | */ 26 | function valueToHexStr(_value, prefix = false) { 27 | if (!(typeof _value === 'number' || typeof _value === 'bigint')) { 28 | throw new Error(`${getFuncName()}: _value is not a number or BigInt type`); 29 | } 30 | 31 | if (prefix !== false && typeof prefix !== 'boolean') { 32 | throw new Error(`${getFuncName()}: _prefix is not a boolean`); 33 | } 34 | 35 | let valueHex = Scalar.e(_value).toString(16); 36 | valueHex = valueHex.length % 2 ? `0${valueHex}` : valueHex; 37 | 38 | return prefix ? `0x${valueHex}` : valueHex; 39 | } 40 | 41 | /** 42 | * Gets current fuction name being called 43 | * @returns {String} function name 44 | */ 45 | function getFuncName() { 46 | return getFuncName.caller.name; 47 | } 48 | 49 | /** 50 | * Converts a byte array into an hex string 51 | * @param {Array[Number]} byteArray - array of bytes 52 | * @returns {String} hexadecimal string 53 | */ 54 | function byteArray2HexString(byteArray) { 55 | let s = ''; 56 | for (const byte of byteArray) { 57 | s += byte.toString(16).padStart(2, '0'); 58 | } 59 | 60 | return s; 61 | } 62 | 63 | /** 64 | * Convert hex string into an array of bytes 65 | * @param {String} hex - hexadecimal string 66 | * @returns {Array[Number]} 67 | */ 68 | function hexString2byteArray(_hex) { 69 | const hex = _hex.startsWith('0x') ? _hex.slice(2) : _hex; 70 | 71 | if (hex.length % 2 !== 0) { 72 | throw new Error(`${getFuncName()}: Must have an even number of hex digits to convert to bytes`); 73 | } 74 | 75 | const numBytes = hex.length / 2; 76 | const byteArray = []; 77 | 78 | for (let i = 0; i < numBytes; i++) { 79 | byteArray[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); 80 | } 81 | 82 | return byteArray; 83 | } 84 | 85 | /** 86 | * Pad a string hex number with 0 87 | * @param {String} str - String input 88 | * @param {Number} length - Length of the resulting string 89 | * @returns {String} Resulting string 90 | */ 91 | function padZeros(str, length) { 92 | if (length > str.length) { 93 | str = '0'.repeat(length - str.length) + str; 94 | } 95 | 96 | return str; 97 | } 98 | 99 | /** 100 | * (Hash Sha256 of an hexadecimal string) % (Snark field) 101 | * @param {String} str - String input in hexadecimal encoding 102 | * @returns {Scalar} Resulting sha256 hash 103 | */ 104 | function sha256Snark(str) { 105 | const hash = crypto.createHash('sha256') 106 | .update(str, 'hex') 107 | .digest('hex'); 108 | const h = Scalar.mod(Scalar.fromString(hash, 16), FrSNARK); 109 | 110 | return h; 111 | } 112 | 113 | module.exports = { 114 | log2, 115 | byteArray2HexString, 116 | hexString2byteArray, 117 | sha256Snark, 118 | padZeros, 119 | valueToHexStr, 120 | getFuncName, 121 | }; 122 | -------------------------------------------------------------------------------- /src/virtual-counters-manager-utils.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-destructuring */ 2 | /* eslint-disable no-plusplus */ 3 | /* eslint-disable max-len */ 4 | /* eslint-disable no-undef */ 5 | /* eslint-disable no-unused-vars */ 6 | /* eslint-disable no-restricted-syntax */ 7 | /* eslint-disable guard-for-in */ 8 | /* eslint-disable camelcase */ 9 | /* eslint-disable no-use-before-define */ 10 | 11 | function expectedModExpCounters(lenB, lenE, lenM, B, E, M) { 12 | const [Q_B_M, R_B_M] = [B / M, B % M]; 13 | 14 | const lenQE2 = Math.floor(lenE / 2) || 1; 15 | 16 | // const log2E = Math.floor(Math.log(Number(E)) / Math.log(2)); 17 | 18 | let nTimesOdd = 0; 19 | while (E > 0n) { 20 | nTimesOdd += Number(E & 1n); 21 | E >>= 1n; 22 | } 23 | const nTimesEven = lenE * 256 - nTimesOdd; 24 | 25 | const counters = { ariths: 0, binaries: 0, steps: 0 }; 26 | const a = setupAndFirstDivCounters(); 27 | const b = halfLoopCounters(); 28 | const c = fullLoopCounters(); 29 | 30 | for (const key in counters) { 31 | // counters[key] = a[key] + log2E * b[key]; 32 | counters[key] = a[key] + nTimesEven * b[key] + nTimesOdd * c[key]; 33 | } 34 | 35 | return counters; 36 | 37 | // Computes the length of the given unsigned integer x in base 2^256. 38 | function computeLenThisBase(x) { 39 | if (x === 0n) return 1; 40 | 41 | let len = 0; 42 | while (x > 0n) { 43 | x >>= 256n; 44 | len += 1; 45 | } 46 | 47 | return len; 48 | } 49 | 50 | // Counters computation of the setup and first division. + 2 last steps 51 | function setupAndFirstDivCounters() { 52 | return { 53 | steps: 54 | 84 55 | + 2 // last 2 steps 56 | + 10 * lenB 57 | + 3 * lenM 58 | + (8 + 19 * lenM) * computeLenThisBase(Q_B_M) 59 | + 12 * computeLenThisBase(R_B_M), 60 | binaries: 61 | 4 62 | - lenM 63 | + computeLenThisBase(R_B_M) 64 | + 2 * computeLenThisBase(Q_B_M) * lenM, 65 | ariths: 66 | lenM * computeLenThisBase(Q_B_M), 67 | }; 68 | } 69 | 70 | function halfLoopCounters() { 71 | return { 72 | steps: 73 | 153 74 | + 82 * lenM 75 | + 6 * lenE 76 | + (80 * lenM * (lenM - 1)) / 2 77 | + 19 * lenM ** 2 78 | + 25 * lenQE2, 79 | binaries: 80 | 9 81 | + 6 * lenM 82 | + (23 * lenM * (lenM - 1)) / 2 83 | + 2 * lenM ** 2 84 | + 3 * lenQE2, 85 | ariths: 86 | -1 87 | + 2 * lenM 88 | + (2 * lenM * (lenM - 1)) / 2 89 | + lenM ** 2, 90 | }; 91 | } 92 | 93 | function fullLoopCounters() { 94 | return { 95 | steps: 96 | 263 97 | + 114 * lenM 98 | + 6 * lenE 99 | + (80 * lenM * (lenM - 1)) / 2 100 | + 57 * lenM ** 2 101 | + 25 * lenQE2, 102 | binaries: 103 | 17 104 | + 3 * lenM 105 | + (23 * lenM * (lenM - 1)) / 2 106 | + 6 * lenM ** 2 107 | + 3 * lenQE2, 108 | ariths: 109 | -1 110 | + 2 * lenM 111 | + (2 * lenM * (lenM - 1)) / 2 112 | + 3 * lenM ** 2, 113 | }; 114 | } 115 | } 116 | 117 | module.exports = { 118 | expectedModExpCounters, 119 | }; 120 | -------------------------------------------------------------------------------- /test/0-get-poseidon.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow-callback */ 2 | const { performance } = require('perf_hooks'); 3 | const { expect } = require('chai'); 4 | 5 | const { 6 | getPoseidon, 7 | } = require('../index'); 8 | 9 | describe('getPoseidon', async function () { 10 | this.timeout(30000); 11 | const numtimes = 5; 12 | let firstTime; 13 | let secondTime; 14 | 15 | it('get one time poseidon', async () => { 16 | const startTime = performance.now(); 17 | await getPoseidon(); 18 | const stopTime = performance.now(); 19 | firstTime = stopTime - startTime; 20 | }); 21 | 22 | it('get 10 times poseidon', async () => { 23 | const startTime = performance.now(); 24 | await getPoseidon(); 25 | const stopTime = performance.now(); 26 | secondTime = stopTime - startTime; 27 | }); 28 | 29 | it('check times', async () => { 30 | expect(numtimes * firstTime).to.be.greaterThan(firstTime + numtimes * secondTime); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/contract-utils.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { expect } = require('chai'); 4 | 5 | const { contractUtils } = require('../index'); 6 | 7 | const { pathTestVectors } = require('./helpers/test-utils'); 8 | 9 | describe('contractUtils', function () { 10 | this.timeout(10000); 11 | let testVector; 12 | 13 | const expectedBatchHashData = '0x5e7875ab198c4d93379c92990a5d0111af59a0e62b2c4a0e3898e5bd24a18e58'; 14 | // TODO: input taken from pil-stark 15 | const expectedStarkHashExecutor = '0xcfae2cfa3b8f3f12abce1bccd90e9b203dfdbe56c0c412114f2d3e67c9a897db'; 16 | const expectedSnarkInputHash = '19704504443275424030853930423657339055467823429269903357094355701515609372092'; 17 | 18 | before(async () => { 19 | testVector = JSON.parse(fs.readFileSync(path.join(pathTestVectors, 'inputs-executor/input_executor.json'))); 20 | }); 21 | 22 | it('calculateBatchHashData', async () => { 23 | const { 24 | batchL2Data, 25 | } = testVector; 26 | const computedBatchHashData = await contractUtils.calculateBatchHashData( 27 | batchL2Data, 28 | ); 29 | 30 | expect(computedBatchHashData).to.be.equal(expectedBatchHashData); 31 | }); 32 | 33 | it('calculateStarkInput', async () => { 34 | const { 35 | oldAccInputHash, 36 | l1InfoRoot, 37 | timestampLimit, 38 | sequencerAddr, 39 | forcedBlockHashL1, 40 | } = testVector; 41 | 42 | const computedGlobalHash = await contractUtils.calculateAccInputHash( 43 | oldAccInputHash, 44 | expectedBatchHashData, 45 | l1InfoRoot, 46 | timestampLimit, 47 | sequencerAddr, 48 | forcedBlockHashL1, 49 | ); 50 | 51 | expect(computedGlobalHash).to.be.equal(expectedStarkHashExecutor); 52 | }); 53 | 54 | it('calculateSnarkInput', async () => { 55 | const aggregatorAddress = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; 56 | 57 | const { 58 | oldStateRoot, 59 | newStateRoot, 60 | newLocalExitRoot, 61 | oldAccInputHash, 62 | newAccInputHash, 63 | oldNumBatch, 64 | newNumBatch, 65 | chainID, 66 | forkID, 67 | } = testVector; 68 | 69 | const computedSnark = await contractUtils.calculateSnarkInput( 70 | oldStateRoot, 71 | newStateRoot, 72 | newLocalExitRoot, 73 | oldAccInputHash, 74 | newAccInputHash, 75 | oldNumBatch, 76 | newNumBatch, 77 | chainID, 78 | aggregatorAddress, 79 | forkID, 80 | ); 81 | 82 | expect(computedSnark.toString()).to.be.equal(expectedSnarkInputHash.toString()); 83 | }); 84 | 85 | it('generateSolidityInputs', async () => { 86 | const proof = { 87 | curve: 'bn128', 88 | evaluations: { 89 | a: '4983158065320214845283038983582714794121964269562335314678893656777021441179', 90 | b: '16954997558800292241285829119127460476904096592673528833252764751611060529484', 91 | c: '19907833497231071751218286765571700657325411817908398200273971646708015379973', 92 | inv: '18709665057908509070263370622788831970132874950834195224194644231239185584210', 93 | qc: '20180602900474771698084616126077100208356111092204988183321341655700554153925', 94 | ql: '7184999557986328041227742592357896348308235205977343838440292814392908122881', 95 | qm: '15746852530918129899779268569777451179135139920956069008692985644822220905703', 96 | qo: '13462912426112262926122926010350351554433337487986864956678163989077059113211', 97 | qr: '6568608538196612762571047871488288774379289573507562301133500821227615565887', 98 | s1: '4145481673072174106132167909558117791672267673805945989604332690796053782432', 99 | s2: '15782738447523150431534509736720608895283309997276128169797612832103285063167', 100 | s3: '19634098809781954721014027775373460063999142848882963646522218392404089810535', 101 | t1w: '12615874520776110669137696889769441431608620414683221044483077139972249600041', 102 | t2w: '11090232877753387518493513406564271995307200865708888231927238026947532688442', 103 | z: '7913346757900002207061111855181610923063545513720236141063077259230406195290', 104 | zw: '6945617974772266811420525947339673414061993254604597387828495161555542243328', 105 | }, 106 | polynomials: { 107 | C1: [ 108 | '1516727195767032049478026110690514930328617858088881270561325457504317755265', 109 | '10229217548795788059590132216160098233900569755246947343259447557867867172692', 110 | '1', 111 | ], 112 | C2: [ 113 | '3475379816990314882936193548878132035412215578240917195896393268962061568972', 114 | '10751373682874687105995746569663280587012340153544618395586133953388185455780', 115 | '1', 116 | ], 117 | W1: [ 118 | '12027817076964442105066123439933980891010823272467787472712480987240897894022', 119 | '1758471555828315015802732549631060772594129568829830200815254450382850741062', 120 | '1', 121 | ], 122 | W2: [ 123 | '20071089056538896761442454883397954176108153445163507949192920056889877719511', 124 | '5269947004785587272927540811637953545419916464090031798344937064625701134544', 125 | '1', 126 | ], 127 | }, 128 | protocol: 'fflonk', 129 | }; 130 | 131 | const expectedOut = [ 132 | '0x035a6fea6f3dfcb8ebd4db937e0d8dfdc0bbef5f05dd423fa3c41aae263c4f81', 133 | '0x169d882e7cb494ca843ab8bff6449f0bdabc256bed73659ae2db3ec858336f54', 134 | '0x07aefec9ee7a52d1909e38c1cd205c6e3e19bcc3ca2b7c5d3cea0861b7bdcbcc', 135 | '0x17c50fd5edb732be11fee3d4a8d7ebdecebd11b83841e45795971b0d2d090ca4', 136 | '0x1a9780d2cfec264b2c87a25340b972c9ca7e4219da6af97d6ad8f1a01356d686', 137 | '0x03e342771b5c0197cf3c5dd4076a20354bf12e49758c24f61bc692618523d346', 138 | '0x2c5fd575cb8b10518cf4b82ac3d19d7e083f2291d762f36e6e74bd6e836fe9d7', 139 | '0x0ba6af2e7081674972f6dd833eb72a83b358a389655f806ba79a8fc0e6a020d0', 140 | '0x0fe290cd881d06f44c4459e6af3c01f550b3620404decbc9d68c4a7965090b01', 141 | '0x0e85b35fe9d27a33bea3430b9c1c4ae949aa3109a1c38db1efb82cd3ab14383f', 142 | '0x22d067169dd27ede08cc64ce3ae290682e8e9d059484502b04c23b40937e1ce7', 143 | '0x1dc3bd07c56162212dd6e342e6f9226bf7b0f9c51b3d77f14c0ffe59bd7f10fb', 144 | '0x2c9dd10407bc215dc702b07ee6625f9e5c0a2d9f96cb71a6f413d72aefc87fc5', 145 | '0x092a426d3176669d76da7e3ad2916ff8623db8f15e90874cccd93e4547e3dfa0', 146 | '0x22e4b6a13e105c3a48b0d90762069a054ca8e519e9505649f99da9850936fdff', 147 | '0x2b688190af39f4437548662b88b11573378e1c3c64857a1401c60a8b1012ae67', 148 | '0x0b045e157513d29cbc228764227e47836a353b35ea38d135e27b8da33b93c49b', 149 | '0x257c30444cc7b9fec564fc7a74c3cc184ffe5564707f24a9b587ed69fbbba94c', 150 | '0x2c036f388c438c3e36f382d5597df9500b18b42af8fbf19d8b57b49f4b133605', 151 | '0x117ecba8ab5400b5fed3a2aef81c4482f9235aab55549337dc0bbc8f53b7385a', 152 | '0x0f5b14991f9df5d40dcd1c2cf4cd9378601a07befa54270e57947de1f8d67800', 153 | '0x1be454f9b008d4a19a67fec1e0ddb8bd0a74a6fed270b6f6592eb58aee17c029', 154 | '0x1884d97006f5be9a999575bc889a3b562c4f73f517f63dd135dd5b10c4240c3a', 155 | '0x295d4b8f19d85d73ba394c09a67a289b56def34d27a972bde05c3a48ada5d052', 156 | ]; 157 | 158 | const result = await contractUtils.generateSolidityInputs(proof); 159 | expect(result).to.be.deep.equal(expectedOut); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /test/contracts/BlockInfo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | 4 | contract BlockInfo { 5 | 6 | address public testCoinbase; 7 | bytes32 public testBlockhash; 8 | uint256 public testTimestamp; 9 | uint256 public testBatchNumber; 10 | uint256 public testDifficulty; 11 | uint256 public testGasLimit; 12 | uint256 public testChainId; 13 | 14 | function getTimestamp() public { 15 | testTimestamp = block.timestamp; 16 | } 17 | 18 | function getCoinbase() public { 19 | testCoinbase = block.coinbase; 20 | } 21 | 22 | function getBatchNumber() public { 23 | testBatchNumber = block.number; 24 | } 25 | 26 | function getDifficulty() public { 27 | testDifficulty = block.difficulty; 28 | } 29 | 30 | function getGasLimit() public { 31 | testGasLimit = block.gaslimit; 32 | } 33 | 34 | function getChainId() public { 35 | testChainId = block.chainid; 36 | } 37 | 38 | function getBlockhash(uint blockNumber) public { 39 | testBlockhash = blockhash(blockNumber); 40 | } 41 | } -------------------------------------------------------------------------------- /test/contracts/Constructor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | 4 | contract Constructor{ 5 | 6 | uint256 public amount; 7 | 8 | constructor(uint _amount) { 9 | amount = _amount; 10 | } 11 | 12 | fallback() external payable {} 13 | 14 | receive() external payable {} 15 | 16 | function payMe() public payable returns(bool success) { 17 | return true; 18 | } 19 | 20 | function fundtransfer(address payable destination) public{ 21 | destination.transfer(amount); 22 | } 23 | } -------------------------------------------------------------------------------- /test/contracts/EtherTransfer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | 4 | contract Ethertransfer{ 5 | 6 | fallback() external payable {} 7 | 8 | receive() external payable {} 9 | 10 | function payMe() public payable returns(bool success) { 11 | return true; 12 | } 13 | 14 | function fundtransfer(address payable destination, uint256 amount) public{ 15 | destination.transfer(amount); 16 | } 17 | } -------------------------------------------------------------------------------- /test/contracts/Selfdestruct.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | 4 | contract Selfdestruct { 5 | 6 | address receiver; 7 | uint256 public value; 8 | 9 | function setReceiver(address _receiver) public { 10 | receiver = _receiver; 11 | } 12 | 13 | function setVal() public payable { 14 | value = msg.value; 15 | } 16 | 17 | function destruct() public { 18 | selfdestruct(payable(receiver)); 19 | } 20 | } -------------------------------------------------------------------------------- /test/contracts/Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.7; 3 | 4 | contract Test { 5 | 6 | uint256 public stoFirst = 1; 7 | uint256 public stoSecond = 2; 8 | 9 | mapping(uint256 => uint256) public stoMapping; 10 | 11 | function setFirst(uint256 _stoFirst) public { 12 | stoFirst = _stoFirst; 13 | } 14 | 15 | function setSecond(uint256 _stoSecond) public { 16 | stoSecond = _stoSecond; 17 | } 18 | 19 | function setMapping(uint256 key, uint256 value) public { 20 | stoMapping[key] = value; 21 | } 22 | } -------------------------------------------------------------------------------- /test/database.test.js: -------------------------------------------------------------------------------- 1 | const { Scalar } = require('ffjavascript'); 2 | const { expect } = require('chai'); 3 | 4 | const { 5 | Database, getPoseidon, 6 | } = require('../index'); 7 | 8 | describe('Database', () => { 9 | let poseidon; 10 | let F; 11 | let db; 12 | 13 | before(async () => { 14 | poseidon = await getPoseidon(); 15 | F = poseidon.F; 16 | }); 17 | 18 | it('create new instance', async () => { 19 | db = new Database(F); 20 | // await db.connect('postgresql://statedb:statedb@127.0.0.1:5432/testdb'); 21 | }); 22 | 23 | it('getSmtNode: no value', async () => { 24 | const key = [F.e(1), F.e(1), F.e(1), F.e(1)]; 25 | 26 | // no value found 27 | const res = await db.getSmtNode(key); 28 | expect(res).to.be.equal(null); 29 | }); 30 | 31 | it('setSmtNode & getSmtNode', async () => { 32 | const key = [F.e(1), F.e(2), F.e(3), F.e(4)]; 33 | const value = [F.e(0), F.e(1), F.e(2), F.e(3), F.e(4), F.e(5), F.e(6), F.e(7)]; 34 | 35 | await db.setSmtNode(key, value); 36 | const res = await db.getSmtNode(key); 37 | expect(value).to.be.deep.equal(res); 38 | }); 39 | 40 | it('getValue: no value', async () => { 41 | const key = Scalar.e(100); 42 | 43 | // no value found 44 | const res = await db.getValue(key); 45 | expect(res).to.be.equal(null); 46 | }); 47 | 48 | it('setValue & getValue', async () => { 49 | const key = Scalar.e(101); 50 | const value = { testN: 2, testStr: 'helloworld' }; 51 | 52 | await db.setValue(key, value); 53 | const res = await db.getValue(key); 54 | 55 | expect(value).to.be.deep.equal(res); 56 | }); 57 | 58 | it('getProgram: no value', async () => { 59 | const key = [F.e(1), F.e(1), F.e(1), F.e(1)]; 60 | 61 | // no program found 62 | const res = await db.getProgram(key); 63 | expect(res).to.be.equal(null); 64 | }); 65 | 66 | it('setProgram & getProgram', async () => { 67 | const key = [F.e(5), F.e(6), F.e(7), F.e(8)]; 68 | const value = [10, 11, 12, 13, 14, 15]; 69 | 70 | await db.setProgram(key, value); 71 | const res = await db.getProgram(key); 72 | expect(value).to.be.deep.equal(res); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /test/hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle"); 2 | DEFAULT_MNEMONIC = "test test test test test test test test test test test junk"; 3 | 4 | /** 5 | * @type import('hardhat/config').HardhatUserConfig 6 | */ 7 | module.exports = { 8 | solidity: { 9 | compilers: [ 10 | { 11 | version: "0.8.7", 12 | }, 13 | { 14 | version: "0.8.9", 15 | }, 16 | { 17 | version: "0.6.11", 18 | } 19 | ] 20 | }, 21 | networks: { 22 | localhost: { 23 | url: "http://127.0.0.1:8545", 24 | accounts: { 25 | mnemonic: DEFAULT_MNEMONIC, 26 | path: "m/44'/60'/0'/0", 27 | initialIndex: 0, 28 | count: 20, 29 | }, 30 | }, 31 | } 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /test/helpers/test-utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { Scalar } = require('ffjavascript'); 3 | 4 | const pathTestVectors = path.join(__dirname, './test-vectors'); 5 | 6 | /** 7 | * Compute key that will result in a ath equals to the scalar input 8 | * @param {Scalar} s - scalar 9 | * @param {Field} F - field 10 | * @returns {Array[Field]} - computed key 11 | */ 12 | function scalar2key(s, F) { 13 | const auxk = [Scalar.zero, Scalar.zero, Scalar.zero, Scalar.zero]; 14 | let r = Scalar.e(s); 15 | let i = 0; 16 | while (!Scalar.isZero(r)) { 17 | if (!Scalar.isZero(Scalar.band(r, Scalar.one))) { 18 | auxk[i % 4] = Scalar.add(auxk[i % 4], Scalar.shl(Scalar.one, Math.floor(i / 4))); 19 | } 20 | r = Scalar.shr(r, 1); 21 | i += 1; 22 | } 23 | 24 | return [F.e(auxk[0]), F.e(auxk[1]), F.e(auxk[2]), F.e(auxk[3])]; 25 | } 26 | 27 | module.exports = { 28 | pathTestVectors, 29 | scalar2key, 30 | }; 31 | -------------------------------------------------------------------------------- /test/helpers/test-vectors/block-info/block-info-tree.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "oldStateRoot": "0x1fe466d9df83e1d2a4c32e21c6078b8f5f590e7db30b006965faa2f27a9b4fea", 4 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 5 | "newBlockNumber": 1, 6 | "blockGasLimit": "0xffffffff", 7 | "finalTimestamp": 1944498031, 8 | "finalGER": "0x0000000000000000000000000000000000000000000000000000000000000000", 9 | "finalBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "txs": [ 11 | { 12 | "logs": [ 13 | [ 14 | "0x", 15 | ["0000000000000000000000000000000000000000000000000000000000000001"], 16 | "0000000000000000000000000000000000000000000000000000000000000000" 17 | ], 18 | [ 19 | "0x", 20 | [["0000000000000000000000000000000000000000000000000000000000000004"],["0000000000000000000000000000000000000000000000000000000000000005"],["0000000000000000000000000000000000000000000000000000000000000006"]], "0000000000000000000000000000000000000000000000000000000000000000" 21 | ], 22 | [ 23 | "0x", 24 | [["0000000000000000000000000000000000000000000000000000000000000001"],["0000000000000000000000000000000000000000000000000000000000000002"]], 25 | "0000000000000000000000000000000000000000000000000000000000000000" 26 | ] 27 | ], 28 | "status": 1, 29 | "l2TxHash": "0xd2a69c7d3c99953bae9d273f2375b2653bd4ec47a05eefc5fc7c041d07fba8a0", 30 | "gasUsed": 26336, 31 | "effectivePercentage": "0xff" 32 | } 33 | ], 34 | "finalBlockInfoRoot": "0xc613144bc2893293e4ec4db6a225ccaf58ab9ebe820035e74f44013f85db1067" 35 | }, 36 | { 37 | "oldStateRoot": "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d", 38 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 39 | "newBlockNumber": 1, 40 | "blockGasLimit": "0xffffffff", 41 | "finalTimestamp": 1944498031, 42 | "finalGER": "0x0000000000000000000000000000000000000000000000000000000000000000", 43 | "finalBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 44 | "txs": [ 45 | { 46 | "logs": [], 47 | "status": 0, 48 | "l2TxHash": "0xac65e2fd657a4ee6318cc66cf98b05ae74ce3f0f3982370af951176e7b599c2c", 49 | "gasUsed": 21000, 50 | "effectivePercentage": "0x00" 51 | } 52 | ], 53 | "finalBlockInfoRoot": "0x01f06eb68cadab49affb988b9f03dcb1789f852e1046c6f74c3b0d758af1cc8b" 54 | }, 55 | { 56 | "oldStateRoot": "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d", 57 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 58 | "newBlockNumber": 1, 59 | "blockGasLimit": "0xffffffff", 60 | "finalTimestamp": 1944498031, 61 | "finalGER": "0x0000000000000000000000000000000000000000000000000000000000000000", 62 | "finalBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 63 | "txs": [ 64 | { 65 | "logs": [], 66 | "status": 1, 67 | "l2TxHash": "0xac65e2fd657a4ee6318cc66cf98b05ae74ce3f0f3982370af951176e7b599c2c", 68 | "gasUsed": 21000, 69 | "effectivePercentage": "0xff" 70 | } 71 | ], 72 | "finalBlockInfoRoot": "0x34805cbe4a3afd8f8d2d091f284a2bb52a60827af14cce94063bc54728466703" 73 | }, 74 | { 75 | "oldStateRoot": "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d", 76 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 77 | "newBlockNumber": 5, 78 | "blockGasLimit": "0xffffffff", 79 | "finalTimestamp": 1944498031, 80 | "finalGER": "0x0000000000000000000000000000000000000000000000000000000000000000", 81 | "finalBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 82 | "txs": [ 83 | { 84 | "logs": [], 85 | "status": 1, 86 | "l2TxHash": "0x8f9b0375a6b0f1bd9d54ff499921766828ae8e5314fc44a494736b5c4cc3bb56", 87 | "gasUsed": 10000, 88 | "effectivePercentage": "0xff" 89 | } 90 | ], 91 | "finalBlockInfoRoot": "0x774e651f18ea6fb4ecfb698ec769bc519b59474474dae344c360301792d0a9f1" 92 | } 93 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/end-to-end/README.md: -------------------------------------------------------------------------------- 1 | # Additional test information 2 | `e2e` test aims to check two functionalities related to the `zkEVMBridge`: 3 | - `claimAsset` 4 | - `bridgeAsset` 5 | 6 | ## Steps to build the `e2e` tests 7 | - Go to [contracts repository](https://github.com/0xPolygonHermez/zkevm-contracts) and perform a deployment. One of the outcomes of the deployment will be a `genesis.json` file 8 | - Copy the `genesis.json` file into the `e2e/state-transition.json` in the `genesis` object property 9 | - Check `PolygonZkEVMBridge proxy` smart contract address in the `genesis` and copy it into each transaction. Therefore, `to` value in each transaction must match `PolygonZkEVMBridge proxy` address 10 | - Add in the genesis the following account: 11 | ``` 12 | { 13 | "balance": "0", 14 | "nonce": "3", 15 | "address": "0xc949254d682d8c9ad5682521675b8f43b102aec4", 16 | "pvtKey": "0xdfd01798f92667dbf91df722434e8fbe96af0211d4d1b82bbbbc8f1def7a814f" 17 | } 18 | ``` 19 | 20 | ## Notes 21 | - `contractName` string under genesis property in `state-transition.json` is taken in order to load ABI interface to interact with contracts afterwards 22 | - if a proxy is used, `contractName` should have the following pattern as a name: `${contractName} ${proxy}` 23 | - ABI `${contractName}` will be loaded then -------------------------------------------------------------------------------- /test/helpers/test-vectors/inputs-executor/input_executor.json: -------------------------------------------------------------------------------- 1 | { 2 | "oldStateRoot": "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d", 3 | "newStateRoot": "0xfe1c484e849d892b043c9cba9a199a3a56e23f4322bfefdfea05b8ac71c4b862", 4 | "oldAccInputHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 5 | "newAccInputHash": "0xcfae2cfa3b8f3f12abce1bccd90e9b203dfdbe56c0c412114f2d3e67c9a897db", 6 | "newLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 7 | "oldNumBatch": 0, 8 | "newNumBatch": 1, 9 | "chainID": 1000, 10 | "forkID": 12, 11 | "forcedBlockHashL1": "0x0000000000000000000000000000000000000000000000000000000000000000", 12 | "batchL2Data": "0x0b73e6af6e00000001ee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff0b0000000100000002", 13 | "l1InfoRoot": "0x462ed3d694d640f04f637e5e3893e8d12f407a53f50201401fd992bb5ab0faf0", 14 | "timestampLimit": "1944498031", 15 | "sequencerAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 16 | "batchHashData": "0x5e7875ab198c4d93379c92990a5d0111af59a0e62b2c4a0e3898e5bd24a18e58", 17 | "contractsBytecode": {}, 18 | "l1InfoTree": { 19 | "1": { 20 | "globalExitRoot": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 21 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 22 | "timestamp": "42", 23 | "smtProof": [ 24 | "0x3cac317908c699fe873a7f6ee4e8cd63fbe9918b2315c97be91585590168e301", 25 | "0x30f3b931216da3f44de9b9f8ae29257ce7fe2d6d229dfaba81fbd5c8a51b2b3a", 26 | "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", 27 | "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", 28 | "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", 29 | "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", 30 | "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", 31 | "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", 32 | "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", 33 | "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", 34 | "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", 35 | "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", 36 | "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", 37 | "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", 38 | "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", 39 | "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", 40 | "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", 41 | "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", 42 | "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", 43 | "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", 44 | "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", 45 | "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", 46 | "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", 47 | "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", 48 | "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", 49 | "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", 50 | "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", 51 | "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", 52 | "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", 53 | "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", 54 | "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", 55 | "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" 56 | ] 57 | }, 58 | "2": { 59 | "globalExitRoot": "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", 60 | "blockHash": "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", 61 | "timestamp": "4242", 62 | "smtProof": [ 63 | "0x0000000000000000000000000000000000000000000000000000000000000000", 64 | "0xdb8b8c21db418043e579ccc9ed3ac15d73f1f6c99a1f1ac6002eab637f6da8b1", 65 | "0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30", 66 | "0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85", 67 | "0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344", 68 | "0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d", 69 | "0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968", 70 | "0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83", 71 | "0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af", 72 | "0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0", 73 | "0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5", 74 | "0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892", 75 | "0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c", 76 | "0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb", 77 | "0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc", 78 | "0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2", 79 | "0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f", 80 | "0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a", 81 | "0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0", 82 | "0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0", 83 | "0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2", 84 | "0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9", 85 | "0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377", 86 | "0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652", 87 | "0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef", 88 | "0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d", 89 | "0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0", 90 | "0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e", 91 | "0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e", 92 | "0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322", 93 | "0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735", 94 | "0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9" 95 | ] 96 | } 97 | }, 98 | "db": { 99 | "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d": [ 100 | "0000000000000000", 101 | "0000000000000000", 102 | "0000000000000000", 103 | "0000000000000000", 104 | "9ec300ed8bd3f934", 105 | "389b06b4dc13fc14", 106 | "72715e7972ca0eaa", 107 | "7782f27412c48d2c", 108 | "0000000000000000", 109 | "0000000000000000", 110 | "0000000000000000", 111 | "0000000000000000" 112 | ], 113 | "0x7782f27412c48d2c72715e7972ca0eaa389b06b4dc13fc149ec300ed8bd3f934": [ 114 | "597bb4307b5e299f", 115 | "f5029596ddb82f37", 116 | "3daa688690ceee05", 117 | "06b719f2bf4cb5e9", 118 | "ebb05ed2082602b9", 119 | "c538204eb07f3d6c", 120 | "a5ed480ede7b8f0e", 121 | "52621f81fded9c35", 122 | "0000000000000000", 123 | "0000000000000000", 124 | "0000000000000000", 125 | "0000000000000000" 126 | ], 127 | "0x06b719f2bf4cb5e93daa688690ceee05f5029596ddb82f37597bb4307b5e299f": [ 128 | "16dde42596b907f0", 129 | "49015d7e991a1528", 130 | "94dd9dadd060910b", 131 | "60b4d5e9af514018", 132 | "494f9491c8507dc3", 133 | "e92914c00b37a1cd", 134 | "f6b613135380bd5f", 135 | "b487e2e7e1d98168", 136 | "0000000000000001", 137 | "0000000000000000", 138 | "0000000000000000", 139 | "0000000000000000" 140 | ], 141 | "0xb487e2e7e1d98168f6b613135380bd5fe92914c00b37a1cd494f9491c8507dc3": [ 142 | "00000000c6200000", 143 | "00000000d78ebc5a", 144 | "000000000000000a", 145 | "0000000000000000", 146 | "0000000000000000", 147 | "0000000000000000", 148 | "0000000000000000", 149 | "0000000000000000" 150 | ], 151 | "0x52621f81fded9c35a5ed480ede7b8f0ec538204eb07f3d6cebb05ed2082602b9": [ 152 | "66ee2be0687eea76", 153 | "6926f8ca8796c78a", 154 | "4c2f3e938869b82d", 155 | "649e63bfe1247ba4", 156 | "35f28afeae0ff489", 157 | "b6d75a1b213c2f7c", 158 | "521f1ce7fca92f45", 159 | "2afffacb569cf689", 160 | "0000000000000001", 161 | "0000000000000000", 162 | "0000000000000000", 163 | "0000000000000000" 164 | ], 165 | "0x2afffacb569cf689521f1ce7fca92f45b6d75a1b213c2f7c35f28afeae0ff489": [ 166 | "0000000063100000", 167 | "000000006bc75e2d", 168 | "0000000000000005", 169 | "0000000000000000", 170 | "0000000000000000", 171 | "0000000000000000", 172 | "0000000000000000", 173 | "0000000000000000" 174 | ] 175 | } 176 | } -------------------------------------------------------------------------------- /test/helpers/test-vectors/l1-info-tree/l1-info-tree.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "description": "empty tree", 4 | "leafs": [], 5 | "expectedRoot": "0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757" 6 | }, 7 | { 8 | "description": "one leaf", 9 | "leafs": [ 10 | { 11 | "leafData": { 12 | "ger": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 13 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 14 | "timestamp": "1697231573" 15 | }, 16 | "expectedLeafValue": "0xf62f487534b899b1c362242616725878188ca891fab60854b792ca0628286de7" 17 | } 18 | ], 19 | "expectedRoot": "0x0a45670382cab3b636561952f7cc1ebbd5f9734e907d762875e89b419ce89c04" 20 | }, 21 | { 22 | "description": "two leafs", 23 | "leafs": [ 24 | { 25 | "leafData": { 26 | "ger": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 27 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 28 | "timestamp": "1697231573" 29 | }, 30 | "expectedLeafValue": "0xf62f487534b899b1c362242616725878188ca891fab60854b792ca0628286de7" 31 | }, 32 | { 33 | "leafData": { 34 | "ger": "0x356682567c5d485bbabe89590d3d72b08671a0a07899dcbaddccbe0599491669", 35 | "blockHash": "0x8f9cfb43c0f6bc7ce9f9e43e8761776a2ef9657ccf87318e2487c313d119b8cf", 36 | "timestamp": "658736476" 37 | }, 38 | "expectedLeafValue": "0xba9c9985e6c9cee54f57991049af0c42439fa2b2915a0597f4d63f63d31c1d4f" 39 | } 40 | ], 41 | "expectedRoot": "0xce3937cebcd96734c492f13d47a8bc22e466cce44117fec1c28e2636d8cf543b" 42 | }, 43 | { 44 | "description": "three leafs", 45 | "leafs": [ 46 | { 47 | "leafData": { 48 | "ger": "0x0000000000000000000000000000000000000000000000000000000000000000", 49 | "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 50 | "timestamp": "0" 51 | }, 52 | "expectedLeafValue": "0x3cac317908c699fe873a7f6ee4e8cd63fbe9918b2315c97be91585590168e301" 53 | }, 54 | { 55 | "leafData": { 56 | "ger": "0x356682567c5d485bbabe89590d3d72b08671a0a07899dcbaddccbe0599491669", 57 | "blockHash": "0x8f9cfb43c0f6bc7ce9f9e43e8761776a2ef9657ccf87318e2487c313d119b8cf", 58 | "timestamp": "658736476" 59 | }, 60 | "expectedLeafValue": "0xba9c9985e6c9cee54f57991049af0c42439fa2b2915a0597f4d63f63d31c1d4f" 61 | }, 62 | { 63 | "leafData": { 64 | "ger": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 65 | "blockHash": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 66 | "timestamp": "0xffffffffffffffff" 67 | }, 68 | "expectedLeafValue": "0xc2db4c8d173afd8fff4a7344663525d3ae155f2a60db2f157850eccb46887589" 69 | } 70 | ], 71 | "expectedRoot": "0xe4f94a9663b007e7a1186cf27047aa2b85387c65c840e3811b7ac63c97555091" 72 | } 73 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree-bridge/global-index.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "indexLocal": "0", 4 | "indexRollup": "0", 5 | "isMainnet": false, 6 | "expectedGlobalIndex": "0" 7 | }, 8 | { 9 | "indexLocal": "0", 10 | "indexRollup": "0", 11 | "isMainnet": true, 12 | "expectedGlobalIndex": "18446744073709551616" 13 | }, 14 | { 15 | "indexLocal": "1", 16 | "indexRollup": "0", 17 | "isMainnet": false, 18 | "expectedGlobalIndex": "1" 19 | }, 20 | { 21 | "indexLocal": "1", 22 | "indexRollup": "0", 23 | "isMainnet": true, 24 | "expectedGlobalIndex": "18446744073709551617" 25 | }, 26 | { 27 | "indexLocal": "0", 28 | "indexRollup": "1", 29 | "isMainnet": false, 30 | "expectedGlobalIndex": "4294967296" 31 | }, 32 | { 33 | "indexLocal": "0", 34 | "indexRollup": "1", 35 | "isMainnet": true, 36 | "expectedGlobalIndex": "18446744073709551616" 37 | }, 38 | { 39 | "indexLocal": "18446744073709551615", 40 | "indexRollup": "18446744073709551615", 41 | "isMainnet": false, 42 | "expectedGlobalIndex": "79228162532711081662958534655" 43 | }, 44 | { 45 | "indexLocal": "18446744073709551615", 46 | "indexRollup": "18446744073709551615", 47 | "isMainnet": true, 48 | "expectedGlobalIndex": "36893488147419103231" 49 | } 50 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-full-genesis.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "addresses": [ 4 | { 5 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 6 | "balance": "100000000000000000000", 7 | "nonce": "0", 8 | "bytecode": "0x1234", 9 | "storage": { 10 | "0": "1", 11 | "1": "2" 12 | } 13 | }, 14 | { 15 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 16 | "balance": "200000000000000000000", 17 | "nonce": "0", 18 | "bytecode": "0x1234", 19 | "storage": { 20 | "1": "1", 21 | "23487": "2926" 22 | } 23 | } 24 | ], 25 | "expectedRoot": "93140224510619825439035019871597094471843931144712404873638375336628482559167" 26 | }, 27 | { 28 | "addresses": [ 29 | { 30 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 31 | "balance": "100000000000000000000", 32 | "nonce": "0" 33 | }, 34 | { 35 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 36 | "balance": "200000000000000000000", 37 | "nonce": "0" 38 | }, 39 | { 40 | "address": "0x03e75d7dd38cce2e20ffee35ec914c57780a8e29", 41 | "balance": "0", 42 | "nonce": "0", 43 | "bytecode": "60606040525b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7ed9ffbb5fda0265983ac7980029" 44 | } 45 | ], 46 | "expectedRoot": "49461512068930131501252998918674096186707801477301326632372959001738876161218" 47 | }, 48 | { 49 | "addresses": [ 50 | { 51 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 52 | "balance": "100000000000000000000", 53 | "nonce": "0" 54 | }, 55 | { 56 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 57 | "balance": "200000000000000000000", 58 | "nonce": "0" 59 | }, 60 | { 61 | "address": "0x03e75d7dd38cce2e20ffee35ec914c57780a8e29", 62 | "balance": "0", 63 | "nonce": "0", 64 | "bytecode": "60606040525b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7ed9ffbb5fda0265983ac7980029", 65 | "storage": { 66 | "115792089237316195423570985008687907853269984665640564039457584007913129639935": "115792089237316195423570985008687907853269984665640564039457584007913129639934", 67 | "115792089237316195423570985008687907853269984665640564039457584007913129639934": "115792089237316195423570985008687907853269984665640564039457584007913129639935", 68 | "320487598743569375603": "7943875943875408" 69 | } 70 | } 71 | ], 72 | "expectedRoot": "93539645631309125100221934019143338919186084987333234187435258483172191717623" 73 | }, 74 | { 75 | "addresses": [ 76 | { 77 | "address": "0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e", 78 | "balance": "1614500000000000000000", 79 | "nonce": "3" 80 | }, 81 | { 82 | "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 83 | "balance": "3000000000000000000", 84 | "nonce": "291" 85 | }, 86 | { 87 | "address": "0xd51a44d3fae010294c616388b506acda1bfaae46", 88 | "balance": "1000000000000000001", 89 | "nonce": "96302" 90 | }, 91 | { 92 | "address": "0xa258c4606ca8206d8aa700ce2143d7db854d168c", 93 | "balance": "1", 94 | "nonce": "0" 95 | }, 96 | { 97 | "address": "0x08638ef1a205be6762a8b935f5da9b700cf7322c", 98 | "balance": "11000000000000000000", 99 | "nonce": "92" 100 | }, 101 | { 102 | "address": "0x5aa40c7c8158d8e29ca480d7e05e5a32dd819332", 103 | "balance": "121200000000000000000", 104 | "nonce": "256" 105 | }, 106 | { 107 | "address": "0x8ff42fd8f5fe291f02e276a0b0aa8243f2fe311d", 108 | "balance": "1466490276", 109 | "nonce": "257" 110 | }, 111 | { 112 | "address": "0xbf49b8f00a6d9826907fa72f8edbcbcc0eede1cc", 113 | "balance": "991227364", 114 | "nonce": "255" 115 | }, 116 | { 117 | "address": "0x08638ef1a205be6762a8b935f5da9b700cf7322d", 118 | "balance": "75557863725914323419135", 119 | "nonce": "2" 120 | }, 121 | { 122 | "address": "0xd51a44d3fae010294c616388b506acda1bfaae43", 123 | "balance": "5519830474000000000", 124 | "nonce": "238" 125 | }, 126 | { 127 | "address": "0x3ee18b2214aff97000d974cf647e7c347e8fa585", 128 | "balance": "9246730474000000000", 129 | "nonce": "2091" 130 | }, 131 | { 132 | "address": "0x5934807cc0654d46755ebd2848840b616256c6ef", 133 | "balance": "92876344", 134 | "nonce": "7" 135 | }, 136 | { 137 | "address": "0x4f868c1aa37fcf307ab38d215382e88fca6275e2", 138 | "balance": "11123936", 139 | "nonce": "10348" 140 | }, 141 | { 142 | "address": "0x2feb1512183545f48f6b9c5b4ebfcaf49cfca6f3", 143 | "balance": "71093487", 144 | "nonce": "2" 145 | }, 146 | { 147 | "address": "0x56178a0d5f301baf6cf3e1cd53d9863437345bf9", 148 | "balance": "4289283480297365542397649264", 149 | "nonce": "111" 150 | }, 151 | { 152 | "address": "0xbcf844fbf125bb023d94422a40fbe2036a497e1d", 153 | "balance": "138365423", 154 | "nonce": "103" 155 | }, 156 | { 157 | "address": "0x13e75d7dd38cce2e20ffee35ec914c57780a8e29", 158 | "balance": "0", 159 | "nonce": "0", 160 | "bytecode": "30306040525b600080fd00a165627a7a7230582012c9bd00152fa1c480f6827f81515bb19c3e63bf7ed9ffbb5fda0265983ac7980029", 161 | "storage": { 162 | "115792089237316195423570985008687907853269984665640564039457584007913129639935": "115792089237316195423570985008687907853269984665640564039457584007913129639934", 163 | "115792089237316195423570985008687907853269984665640564039457584007913129639934": "115792089237316195423570985008687907853269984665640564039457584007913129639935", 164 | "320487598743569375603": "7943875943875408" 165 | } 166 | }, 167 | { 168 | "address": "0x13e75d7dd38cce2e20ffee35ec914c57780a8e29", 169 | "balance": "0", 170 | "nonce": "0", 171 | "bytecode": "30306040525b600080fd00a165627a7a", 172 | "storage": { 173 | "12456": "3487547", 174 | "09987": "987263", 175 | "0027653": "92488756" 176 | } 177 | }, 178 | { 179 | "address": "0x13e75d7dd38cce2e20ffee35ec914c57780a8e29", 180 | "balance": "26592349873240827349", 181 | "nonce": "193438467356", 182 | "bytecode": "0a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a70a165627a7", 183 | "storage": { 184 | "0": "0", 185 | "1": "2", 186 | "3": "0" 187 | } 188 | } 189 | ], 190 | "expectedRoot": "38697856531810778833199809894112622398920590247109339909948080423193468974217" 191 | } 192 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-genesis.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "addresses": [ 4 | { 5 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 6 | "balance": "100000000000000000000", 7 | "nonce": "0" 8 | }, 9 | { 10 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 11 | "balance": "200000000000000000000", 12 | "nonce": "0" 13 | } 14 | ], 15 | "expectedRoot": "33746756112715549509799501069416620287488781321139344085581028504667736843869" 16 | }, 17 | { 18 | "addresses": [ 19 | { 20 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 21 | "balance": "100000000000000000000", 22 | "nonce": "0" 23 | }, 24 | { 25 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 26 | "balance": "200000000000000000000", 27 | "nonce": "0" 28 | } 29 | ], 30 | "expectedRoot": "33746756112715549509799501069416620287488781321139344085581028504667736843869" 31 | }, 32 | { 33 | "addresses": [ 34 | { 35 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 36 | "balance": "100000000000000000000", 37 | "nonce": "2" 38 | }, 39 | { 40 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 41 | "balance": "200000000000000000000", 42 | "nonce": "3" 43 | } 44 | ], 45 | "expectedRoot": "21325877998580057082261372401435859725504729767606579433194632371488285785841" 46 | }, 47 | { 48 | "addresses": [ 49 | { 50 | "address": "0x0000000000000000000000000000000000000000", 51 | "balance": "10000000000000000000000", 52 | "nonce": "982487" 53 | }, 54 | { 55 | "address": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 56 | "balance": "324989324865345874387554", 57 | "nonce": "916348" 58 | }, 59 | { 60 | "address": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0", 61 | "balance": "0", 62 | "nonce": "0" 63 | } 64 | ], 65 | "expectedRoot": "19446318495734678640980943684709715379686010146624499051284653837571603843329" 66 | }, 67 | { 68 | "addresses": [ 69 | { 70 | "address": "0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e", 71 | "balance": "1614500000000000000000", 72 | "nonce": "3" 73 | }, 74 | { 75 | "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 76 | "balance": "3000000000000000000", 77 | "nonce": "291" 78 | }, 79 | { 80 | "address": "0xd51a44d3fae010294c616388b506acda1bfaae46", 81 | "balance": "1000000000000000001", 82 | "nonce": "96302" 83 | }, 84 | { 85 | "address": "0xa258c4606ca8206d8aa700ce2143d7db854d168c", 86 | "balance": "1", 87 | "nonce": "0" 88 | }, 89 | { 90 | "address": "0x08638ef1a205be6762a8b935f5da9b700cf7322c", 91 | "balance": "11000000000000000000", 92 | "nonce": "92" 93 | }, 94 | { 95 | "address": "0x5aa40c7c8158d8e29ca480d7e05e5a32dd819332", 96 | "balance": "121200000000000000000", 97 | "nonce": "256" 98 | }, 99 | { 100 | "address": "0x8ff42fd8f5fe291f02e276a0b0aa8243f2fe311d", 101 | "balance": "1466490276", 102 | "nonce": "257" 103 | }, 104 | { 105 | "address": "0xbf49b8f00a6d9826907fa72f8edbcbcc0eede1cc", 106 | "balance": "991227364", 107 | "nonce": "255" 108 | }, 109 | { 110 | "address": "0x08638ef1a205be6762a8b935f5da9b700cf7322d", 111 | "balance": "75557863725914323419135", 112 | "nonce": "2" 113 | }, 114 | { 115 | "address": "0xd51a44d3fae010294c616388b506acda1bfaae43", 116 | "balance": "5519830474000000000", 117 | "nonce": "238" 118 | }, 119 | { 120 | "address": "0x3ee18b2214aff97000d974cf647e7c347e8fa585", 121 | "balance": "9246730474000000000", 122 | "nonce": "2091" 123 | }, 124 | { 125 | "address": "0x5934807cc0654d46755ebd2848840b616256c6ef", 126 | "balance": "92876344", 127 | "nonce": "7" 128 | }, 129 | { 130 | "address": "0x4f868c1aa37fcf307ab38d215382e88fca6275e2", 131 | "balance": "11123936", 132 | "nonce": "10348" 133 | }, 134 | { 135 | "address": "0x2feb1512183545f48f6b9c5b4ebfcaf49cfca6f3", 136 | "balance": "71093487", 137 | "nonce": "2" 138 | }, 139 | { 140 | "address": "0x56178a0d5f301baf6cf3e1cd53d9863437345bf9", 141 | "balance": "4289283480297365542397649264", 142 | "nonce": "111" 143 | }, 144 | { 145 | "address": "0xbcf844fbf125bb023d94422a40fbe2036a497e1d", 146 | "balance": "138365423", 147 | "nonce": "103" 148 | } 149 | ], 150 | "expectedRoot": "47775479333750920215959756780611148904583164867627893827197694804520800728132" 151 | } 152 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-key-contract-code.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "leafType": 2, 4 | "ethAddr": "0x0000000000000000000000000000000000000000", 5 | "arity": 3, 6 | "expectedKey": "72618736525103033809705966741823173469010530487114812728907809351129229387686" 7 | }, 8 | { 9 | "leafType": 2, 10 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 11 | "arity": 3, 12 | "expectedKey": "100339618010685329502920959863456851722741867804653471565599858216996781583185" 13 | }, 14 | { 15 | "leafType": 2, 16 | "ethAddr": "0x0000000000000000000000000000000000000000", 17 | "arity": 4, 18 | "expectedKey": "72618736525103033809705966741823173469010530487114812728907809351129229387686" 19 | }, 20 | { 21 | "leafType": 2, 22 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 23 | "arity": 4, 24 | "expectedKey": "100339618010685329502920959863456851722741867804653471565599858216996781583185" 25 | }, 26 | { 27 | "leafType": 2, 28 | "ethAddr": "0xEEF9f339514298C6A857EfCfC1A762aF84438dEE", 29 | "arity": 3, 30 | "expectedKey": "37702541001567369137011480863022602456875150323680555331519352316148423991760" 31 | }, 32 | { 33 | "leafType": 2, 34 | "ethAddr": "0xEEF9f339514298C6A857EfCfC1A762aF84438dEE", 35 | "arity": 4, 36 | "expectedKey": "37702541001567369137011480863022602456875150323680555331519352316148423991760" 37 | } 38 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-key-contract-length.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "leafType": 4, 4 | "ethAddr": "0x0000000000000000000000000000000000000000", 5 | "expectedKey": "41007279171909826356801898715236946089777777871690100429699594563988270638848" 6 | }, 7 | { 8 | "leafType": 4, 9 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 10 | "expectedKey": "34646114882128150922895390038184820825657559006046553149154512997547296886401" 11 | }, 12 | { 13 | "leafType": 4, 14 | "ethAddr": "0x0000000000000000000000000000000000000000", 15 | "expectedKey": "41007279171909826356801898715236946089777777871690100429699594563988270638848" 16 | }, 17 | { 18 | "leafType": 4, 19 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 20 | "expectedKey": "34646114882128150922895390038184820825657559006046553149154512997547296886401" 21 | }, 22 | { 23 | "leafType": 4, 24 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 25 | "expectedKey": "67333650611713081285498556561630066492444591228552483499725412664140662692510" 26 | }, 27 | { 28 | "leafType": 4, 29 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 30 | "expectedKey": "73491272310643147477523815380199478860516427525044236486332221964020922584980" 31 | }, 32 | { 33 | "leafType": 4, 34 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 35 | "expectedKey": "67333650611713081285498556561630066492444591228552483499725412664140662692510" 36 | }, 37 | { 38 | "leafType": 4, 39 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 40 | "expectedKey": "73491272310643147477523815380199478860516427525044236486332221964020922584980" 41 | } 42 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-key-contract-storage.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "leafType": 3, 4 | "ethAddr": "0x0000000000000000000000000000000000000000", 5 | "storagePosition": "0", 6 | "expectedKey": "12534214928306848758475099215268104288950840610411881349004256209866079801855" 7 | }, 8 | { 9 | "leafType": 3, 10 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 11 | "storagePosition": "115792089237316195423570985008687907853269984665640564039457584007913129639935", 12 | "expectedKey": "33137250487625679402353497751179166536828572303855484396343252601253270796565" 13 | }, 14 | { 15 | "leafType": 3, 16 | "ethAddr": "0x0000000000000000000000000000000000000000", 17 | "storagePosition": "0", 18 | "expectedKey": "12534214928306848758475099215268104288950840610411881349004256209866079801855" 19 | }, 20 | { 21 | "leafType": 3, 22 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 23 | "storagePosition": "115792089237316195423570985008687907853269984665640564039457584007913129639935", 24 | "expectedKey": "33137250487625679402353497751179166536828572303855484396343252601253270796565" 25 | }, 26 | { 27 | "leafType": 3, 28 | "ethAddr": "0xEEF9f339514298C6A857EfCfC1A762aF84438dEE", 29 | "storagePosition": "7264", 30 | "expectedKey": "83856652265636757733606490452162031059172593606140564507822531867780274877175" 31 | }, 32 | { 33 | "leafType": 3, 34 | "ethAddr": "0xEEF9f339514298C6A857EfCfC1A762aF84438dEE", 35 | "storagePosition": "7264", 36 | "expectedKey": "83856652265636757733606490452162031059172593606140564507822531867780274877175" 37 | } 38 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-key-eth-balance.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "leafType": 0, 4 | "ethAddr": "0x0000000000000000000000000000000000000000", 5 | "expectedKey": "26833593870529421166492422877314944811724038685477806060577465163426988022737" 6 | }, 7 | { 8 | "leafType": 0, 9 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 10 | "expectedKey": "40127382331240911157907914324528741813743915534659976972051985426947551260673" 11 | }, 12 | { 13 | "leafType": 0, 14 | "ethAddr": "0x0000000000000000000000000000000000000000", 15 | "expectedKey": "26833593870529421166492422877314944811724038685477806060577465163426988022737" 16 | }, 17 | { 18 | "leafType": 0, 19 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 20 | "expectedKey": "40127382331240911157907914324528741813743915534659976972051985426947551260673" 21 | }, 22 | { 23 | "leafType": 0, 24 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 25 | "expectedKey": "45511135140510043104127159862914553230179041101689561753801876001524381766893" 26 | }, 27 | { 28 | "leafType": 0, 29 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 30 | "expectedKey": "43741542307756197806968621038083986403476477276779293271513030919451674021857" 31 | }, 32 | { 33 | "leafType": 0, 34 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 35 | "expectedKey": "45511135140510043104127159862914553230179041101689561753801876001524381766893" 36 | }, 37 | { 38 | "leafType": 0, 39 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 40 | "expectedKey": "43741542307756197806968621038083986403476477276779293271513030919451674021857" 41 | } 42 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-key-eth-nonce.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "leafType": 1, 4 | "ethAddr": "0x0000000000000000000000000000000000000000", 5 | "expectedKey": "28358077366816831193326378002625509892290580640052650926129802772493521696670" 6 | }, 7 | { 8 | "leafType": 1, 9 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 10 | "expectedKey": "46601686036392058419641250406383581470536953255400137235565480209972996937304" 11 | }, 12 | { 13 | "leafType": 1, 14 | "ethAddr": "0x0000000000000000000000000000000000000000", 15 | "expectedKey": "28358077366816831193326378002625509892290580640052650926129802772493521696670" 16 | }, 17 | { 18 | "leafType": 1, 19 | "ethAddr": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 20 | "expectedKey": "46601686036392058419641250406383581470536953255400137235565480209972996937304" 21 | }, 22 | { 23 | "leafType": 1, 24 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 25 | "expectedKey": "98790850219450538256104290071020195215871038788594574188656606927809546484197" 26 | }, 27 | { 28 | "leafType": 1, 29 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 30 | "expectedKey": "45555081975440947041848992181135418706314820385341877748019327868663035195938" 31 | }, 32 | { 33 | "leafType": 1, 34 | "ethAddr": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 35 | "expectedKey": "98790850219450538256104290071020195215871038788594574188656606927809546484197" 36 | }, 37 | { 38 | "leafType": 1, 39 | "ethAddr": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 40 | "expectedKey": "45555081975440947041848992181135418706314820385341877748019327868663035195938" 41 | } 42 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/merkle-tree/smt-raw.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": [ 4 | "0" 5 | ], 6 | "values": [ 7 | "0" 8 | ], 9 | "expectedRoot": "0x0000000000000000000000000000000000000000000000000000000000000000" 10 | }, 11 | { 12 | "keys": [ 13 | "0" 14 | ], 15 | "values": [ 16 | "1" 17 | ], 18 | "expectedRoot": "0x42bb2f66296df03552203ae337815976ca9c1bf52cc1bdd59399ede8fea8a822" 19 | }, 20 | { 21 | "keys": [ 22 | "1" 23 | ], 24 | "values": [ 25 | "18446744073709551615" 26 | ], 27 | "expectedRoot": "0xfe8e54ccf991c23ee0287172ef5dd21f7712b6f9ad22310650ae1c4b83527c96" 28 | }, 29 | { 30 | "keys": [ 31 | "1" 32 | ], 33 | "values": [ 34 | "18446744073709551614" 35 | ], 36 | "expectedRoot": "0x33361e22e308403da886199cc3bdfe396fd331378472c119cfbd5b67e8176edc" 37 | }, 38 | { 39 | "keys": [ 40 | "1" 41 | ], 42 | "values": [ 43 | "18446744073709551616" 44 | ], 45 | "expectedRoot": "0x2ba6b371e7f721f18e705f64747f51a506b7a684fd16fb37caa2347d7e2bb14a" 46 | }, 47 | { 48 | "keys": [ 49 | "1" 50 | ], 51 | "values": [ 52 | "340282366920938463463374607431768211455" 53 | ], 54 | "expectedRoot": "0xa9c0b45fc8ae249981f0ecd85d305c5e7b20f2d3752b0b91a475c3e0a1cec759" 55 | }, 56 | { 57 | "keys": [ 58 | "1" 59 | ], 60 | "values": [ 61 | "340282366920938463463374607431768211454" 62 | ], 63 | "expectedRoot": "0x64c78ae2095e9023a18058fa0a3681de90eb6b557881cdaecf1cf98b5aeaed11" 64 | }, 65 | { 66 | "keys": [ 67 | "1" 68 | ], 69 | "values": [ 70 | "340282366920938463463374607431768211456" 71 | ], 72 | "expectedRoot": "0xbc0611f295ea1741bfd408f94256239e29f9a24923cf0a44cb17c978994b3dbe" 73 | }, 74 | { 75 | "keys": [ 76 | "1" 77 | ], 78 | "values": [ 79 | "6277101735386680763835789423207666416102355444464034512895" 80 | ], 81 | "expectedRoot": "0x35e00ac3f1bda4e5ae1919b3181debc3a19c9cd109823e56c677df8d36bf3338" 82 | }, 83 | { 84 | "keys": [ 85 | "1" 86 | ], 87 | "values": [ 88 | "6277101735386680763835789423207666416102355444464034512896" 89 | ], 90 | "expectedRoot": "0xc56b249e35e9f3899dcbbe43295e93de38e2f7b11dec248a697dfcf4fbf4c3dd" 91 | }, 92 | { 93 | "keys": [ 94 | "1" 95 | ], 96 | "values": [ 97 | "6277101735386680763835789423207666416102355444464034512894" 98 | ], 99 | "expectedRoot": "0x5b62cbf085ca46fa78746b2a91ca460151d98e4da0c770a170dcf6ed1f1986ea" 100 | }, 101 | { 102 | "keys": [ 103 | "2" 104 | ], 105 | "values": [ 106 | "115792089237316195423570985008687907853269984665640564039457584007913129639935" 107 | ], 108 | "expectedRoot": "0x9cc0a048793c5ad151b83339e76e9cdc556efc2fbd3f6bea921f0087e3b31d6a" 109 | }, 110 | { 111 | "keys": [ 112 | "2" 113 | ], 114 | "values": [ 115 | "115792089237316195423570985008687907853269984665640564039457584007913129639934" 116 | ], 117 | "expectedRoot": "0x796c63e633a10025e78d8e99a58e78470f078dbdf01afb3179bfcd73e5a7a43b" 118 | }, 119 | { 120 | "keys": [ 121 | "1" 122 | ], 123 | "values": [ 124 | "1" 125 | ], 126 | "expectedRoot": "0xb26e0de762d186d2efc35d9ff4388def6c96ec15f942d83d779141386fe1d2e1" 127 | }, 128 | { 129 | "keys": [ 130 | "2" 131 | ], 132 | "values": [ 133 | "115792089237316195423570985008687907853269984665640564039457584007913129639935" 134 | ], 135 | "expectedRoot": "0x9cc0a048793c5ad151b83339e76e9cdc556efc2fbd3f6bea921f0087e3b31d6a" 136 | }, 137 | { 138 | "keys": [ 139 | "2" 140 | ], 141 | "values": [ 142 | "1293876327903274693576" 143 | ], 144 | "expectedRoot": "0x2a8bbd5bbf93f0daac12315d36ec50a9a8118be1ae8ea9ebec1f1cc984ae4526" 145 | }, 146 | { 147 | "keys": [ 148 | "0", 149 | "1", 150 | "2", 151 | "3" 152 | ], 153 | "values": [ 154 | "1", 155 | "2", 156 | "3", 157 | "4" 158 | ], 159 | "expectedRoot": "0x085130c4e67235dc830e48acdc6cee540cf204dd4fbfd43d579a838f58031b1f" 160 | }, 161 | { 162 | "keys": [ 163 | "2", 164 | "4", 165 | "6", 166 | "8" 167 | ], 168 | "values": [ 169 | "9123864", 170 | "12948357", 171 | "93232784", 172 | "93287346" 173 | ], 174 | "expectedRoot": "0xb7da117ea50981e7fa14a411d3babfb9f2766e0089df2e5978dc9d36a2f681a7" 175 | }, 176 | { 177 | "keys": [ 178 | "17185", 179 | "16929" 180 | ], 181 | "values": [ 182 | "1", 183 | "1" 184 | ], 185 | "expectedRoot": "0x5eb96ea83a6f62628dcf350e96214fae3d852fa15d9ee98742b07864be9a5730" 186 | }, 187 | { 188 | "keys": [ 189 | "0", 190 | "4369", 191 | "69905" 192 | ], 193 | "values": [ 194 | "1", 195 | "2", 196 | "3" 197 | ], 198 | "expectedRoot": "0xa7db6a59f3df30492054fe2419cf1584e4100f915c75e957938477562c2f2cea" 199 | }, 200 | { 201 | "keys": [ 202 | "17185", 203 | "16929" 204 | ], 205 | "values": [ 206 | "9123864", 207 | "12948357" 208 | ], 209 | "expectedRoot": "0x2e359e78489a4085f5059c918d90a0d8075b13d8ad20ab929d614ecc464423f4" 210 | }, 211 | { 212 | "keys": [ 213 | "4294967296", 214 | "0", 215 | "4803839316197376", 216 | "35791394", 217 | "4599194146", 218 | "365091809505837056" 219 | ], 220 | "values": [ 221 | "252", 222 | "253", 223 | "254", 224 | "255", 225 | "256", 226 | "257" 227 | ], 228 | "expectedRoot": "0x43567b6b04f5d8d83d109002767462808e225a5c90f2a9afc9ed4672bd54676a" 229 | }, 230 | { 231 | "keys": [ 232 | "0", 233 | "91343852333181432387730302044767688728495783936", 234 | "1" 235 | ], 236 | "values": [ 237 | "1", 238 | "91343852333181432387730302044767688728495783936", 239 | "1" 240 | ], 241 | "expectedRoot": "0x46a27b5cce9b87692dd7b97920b51bca15cad6f07e001225e8ecfa4d43602dbc" 242 | } 243 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/selfdestruct/selfdestruct.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "description": "Selfdestruct", 5 | "chainID": 1000, 6 | "forkID": 12, 7 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 8 | "sequencerPvtKey": "0x28b2b0318721be8c8339199172cd7cc8f5e273800a35616ec893083a4b32c02e", 9 | "genesis": [ 10 | { 11 | "balance": "0", 12 | "nonce": "0", 13 | "address": "0x0000000000000000000000000000000000000000" 14 | }, 15 | { 16 | "balance": "0", 17 | "nonce": "0", 18 | "address": "0xAE4bB80bE56B819606589DE61d5ec3b522EEB032" 19 | }, 20 | { 21 | "balance": "100000000000000000000", 22 | "nonce": "1", 23 | "address": "0x617b3a3528f9cdd6630fd3301b9c8911f7bf063d", 24 | "pvtKey": "0x28b2b0318721be8c8339199172cd7cc8f5e273800a35616ec893083a4b32c02e" 25 | }, 26 | { 27 | "balance": "0", 28 | "nonce": "1", 29 | "address": "0x1275fbb540c8efc58b812ba83b0d0b8b9917ae98", 30 | "bytecode": "0x60806040526004361061003f5760003560e01c80632b68b9c6146100445780633fa4f2451461005b5780635cfb28e714610086578063718da7ee14610090575b600080fd5b34801561005057600080fd5b506100596100b9565b005b34801561006757600080fd5b506100706100f2565b60405161007d9190610195565b60405180910390f35b61008e6100f8565b005b34801561009c57600080fd5b506100b760048036038101906100b29190610159565b610101565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b60015481565b34600181905550565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600081359050610153816101f1565b92915050565b60006020828403121561016f5761016e6101ec565b5b600061017d84828501610144565b91505092915050565b61018f816101e2565b82525050565b60006020820190506101aa6000830184610186565b92915050565b60006101bb826101c2565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600080fd5b6101fa816101b0565b811461020557600080fd5b5056fea26469706673582212207ae6e5d5feddef608b24cca98990c37cf78f8b377163a7c4951a429d90d6120464736f6c63430008070033", 31 | "storage": {}, 32 | "contractName": "Selfdestruct" 33 | }, 34 | { 35 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 36 | "pvtKey": "0x4d27a600dce8c29b7bd080e29a26972377dbb04d7a27d919adbb602bf13cfd23", 37 | "balance": "200000000000000000000", 38 | "nonce": "0" 39 | } 40 | ], 41 | "expectedOldRoot": "0x2761798d338f390fa233a5ff12c7fd6a50ab8a82e559c25e2895516c3e4213c6", 42 | "txs": [ 43 | { 44 | "type": 11, 45 | "deltaTimestamp": "1944498031", 46 | "l1Info": { 47 | "globalExitRoot": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 48 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 49 | "timestamp": "42" 50 | }, 51 | "indexL1InfoTree": 0, 52 | "reason": "", 53 | "customRawTx": "0x0b73e6af6f00000000" 54 | }, 55 | { 56 | "from": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 57 | "to": "0x1275fbb540c8efc58b812ba83b0d0b8b9917ae98", 58 | "nonce": 0, 59 | "value": "0", 60 | "contractName": "Selfdestruct", 61 | "function": "setReceiver", 62 | "params": [ 63 | "0x0000000000000000000000000000000000000001" 64 | ], 65 | "chainId": 1000, 66 | "reason": "", 67 | "gasLimit": 100000, 68 | "gasPrice": "1000000000", 69 | "data": "0x718da7ee0000000000000000000000000000000000000000000000000000000000000001", 70 | "customRawTx": "0xf84a80843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880a4718da7ee00000000000000000000000000000000000000000000000000000000000000018203e880800f169b9405991a5f4a96f9d1d726e43ab9d42e1d0b4daac7ec9b4797dd39e9b724cf48c46cbc1924dd25adc6536ef259bedcd822979734ae347e01d715303ad01cff", 71 | "rawTx": "0xf88a80843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880a4718da7ee00000000000000000000000000000000000000000000000000000000000000018207f4a00f169b9405991a5f4a96f9d1d726e43ab9d42e1d0b4daac7ec9b4797dd39e9b7a024cf48c46cbc1924dd25adc6536ef259bedcd822979734ae347e01d715303ad0" 72 | }, 73 | { 74 | "from": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 75 | "to": "0x1275fbb540c8efc58b812ba83b0d0b8b9917ae98", 76 | "nonce": 1, 77 | "value": "123456789", 78 | "contractName": "Selfdestruct", 79 | "function": "setVal", 80 | "params": [], 81 | "chainId": 1000, 82 | "reason": "", 83 | "gasLimit": 100000, 84 | "gasPrice": "1000000000", 85 | "data": "0x5cfb28e7", 86 | "customRawTx": "0xee01843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9884075bcd15845cfb28e78203e88080b22ac440612ebcd45672cfc7dcbbbe7cde784294e5076827b1812f9ea9eee2736c3c774150514808053972653f74bbeb33918dc74aa9182cee7993283b1faa541bff", 87 | "rawTx": "0xf86e01843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9884075bcd15845cfb28e78207f3a0b22ac440612ebcd45672cfc7dcbbbe7cde784294e5076827b1812f9ea9eee273a06c3c774150514808053972653f74bbeb33918dc74aa9182cee7993283b1faa54" 88 | }, 89 | { 90 | "from": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 91 | "to": "0x1275fbb540c8efc58b812ba83b0d0b8b9917ae98", 92 | "nonce": 2, 93 | "value": "0", 94 | "contractName": "Selfdestruct", 95 | "function": "destruct", 96 | "params": [], 97 | "chainId": 1000, 98 | "reason": "", 99 | "gasLimit": 100000, 100 | "gasPrice": "1000000000", 101 | "data": "0x2b68b9c6", 102 | "customRawTx": "0xea02843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880842b68b9c68203e88080f5b684b995dd9549bb5fd2ed23d3b388f75f559b14110277b4ae7de5bd7775ef1be51078330d1ef03f0e4fe0271e8e2502b6e98c1f7664a5e2aeae3ab04156d41cff", 103 | "rawTx": "0xf86a02843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880842b68b9c68207f4a0f5b684b995dd9549bb5fd2ed23d3b388f75f559b14110277b4ae7de5bd7775efa01be51078330d1ef03f0e4fe0271e8e2502b6e98c1f7664a5e2aeae3ab04156d4" 104 | } 105 | ], 106 | "expectedNewRoot": "0x895f95fa944da09237bb1b9711a0e66f7bc3fd27b08eb4e2b2b94726d0b2d0cd", 107 | "expectedNewLeafs": { 108 | "0x0000000000000000000000000000000000000000": { 109 | "balance": "0", 110 | "nonce": "0", 111 | "storage": null, 112 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 113 | "bytecodeLength": 0 114 | }, 115 | "0xae4bb80be56b819606589de61d5ec3b522eeb032": { 116 | "balance": "0", 117 | "nonce": "0", 118 | "storage": null, 119 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 120 | "bytecodeLength": 0 121 | }, 122 | "0x617b3a3528f9cdd6630fd3301b9c8911f7bf063d": { 123 | "balance": "100000140508000000000", 124 | "nonce": "1", 125 | "storage": null, 126 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 127 | "bytecodeLength": 0 128 | }, 129 | "0x1275fbb540c8efc58b812ba83b0d0b8b9917ae98": { 130 | "balance": "0", 131 | "nonce": "1", 132 | "storage": { 133 | "0x0000000000000000000000000000000000000000000000000000000000000000": "0x01", 134 | "0x0000000000000000000000000000000000000000000000000000000000000001": "0x075bcd15" 135 | }, 136 | "hashBytecode": "0xbbebd914926f549bcc798e9081a339e3745b9831b3c3906fb8bb2bcf2e05a160", 137 | "bytecodeLength": 574 138 | }, 139 | "0x4d5cf5032b2a844602278b01199ed191a86c93ff": { 140 | "balance": "199999859491876543211", 141 | "nonce": "3", 142 | "storage": null, 143 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 144 | "bytecodeLength": 0 145 | }, 146 | "0x000000000000000000000000000000005ca1ab1e": { 147 | "balance": "0", 148 | "nonce": "0", 149 | "storage": { 150 | "0x0000000000000000000000000000000000000000000000000000000000000000": "0x01", 151 | "0x0000000000000000000000000000000000000000000000000000000000000002": "0x73e6af6f", 152 | "0xa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49": "0x2761798d338f390fa233a5ff12c7fd6a50ab8a82e559c25e2895516c3e4213c6", 153 | "0x0000000000000000000000000000000000000000000000000000000000000003": "0xec9a95baade06355dff5723669ed4dec0b8c7404f8a36146ce93dd31235a48ec" 154 | }, 155 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 156 | "bytecodeLength": 0 157 | }, 158 | "0x0000000000000000000000000000000000000001": { 159 | "balance": "123456789", 160 | "nonce": "0", 161 | "storage": null, 162 | "hashBytecode": "0x0000000000000000000000000000000000000000000000000000000000000000", 163 | "bytecodeLength": 0 164 | } 165 | }, 166 | "batchL2Data": "0x0b73e6af6f00000000f84a80843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880a4718da7ee00000000000000000000000000000000000000000000000000000000000000018203e880800f169b9405991a5f4a96f9d1d726e43ab9d42e1d0b4daac7ec9b4797dd39e9b724cf48c46cbc1924dd25adc6536ef259bedcd822979734ae347e01d715303ad01cffee01843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9884075bcd15845cfb28e78203e88080b22ac440612ebcd45672cfc7dcbbbe7cde784294e5076827b1812f9ea9eee2736c3c774150514808053972653f74bbeb33918dc74aa9182cee7993283b1faa541bffea02843b9aca00830186a0941275fbb540c8efc58b812ba83b0d0b8b9917ae9880842b68b9c68203e88080f5b684b995dd9549bb5fd2ed23d3b388f75f559b14110277b4ae7de5bd7775ef1be51078330d1ef03f0e4fe0271e8e2502b6e98c1f7664a5e2aeae3ab04156d41cff", 167 | "l1InfoRoot": "0x090bcaf734c4f06c93954a827b45a6e8c67b8e0fd1e0a35a1c5982d6961828f9", 168 | "newLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 169 | "batchHashData": "0xedccf03522991cfea46db3203eeef15ab40066dffcaf3f763bef14ecf44d0149", 170 | "oldLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 171 | "oldAccInputHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 172 | "timestampLimit": 1944498031, 173 | "expectedNewAccInputHash": "0xbc2a2f16da1eda57e334ec9903ed17685c876299758c4044964679e9e9a064ce" 174 | } 175 | ] -------------------------------------------------------------------------------- /test/helpers/test-vectors/zkevm-db/state-transition.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "description": "2 accounts and 1 valid transaction.", 5 | "chainID": 1000, 6 | "forkID": 12, 7 | "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 8 | "genesis": [ 9 | { 10 | "address": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 11 | "pvtKey": "0x28b2b0318721be8c8339199172cd7cc8f5e273800a35616ec893083a4b32c02e", 12 | "balance": "100000000000000000000", 13 | "nonce": "0" 14 | }, 15 | { 16 | "address": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 17 | "pvtKey": "0x4d27a600dce8c29b7bd080e29a26972377dbb04d7a27d919adbb602bf13cfd23", 18 | "balance": "200000000000000000000", 19 | "nonce": "0" 20 | } 21 | ], 22 | "expectedOldRoot": "0x4a9bfcb163ec91c5beb22e6aca41592433092c8c7821b01d37fd0de483f9265d", 23 | "txs": [ 24 | { 25 | "type": 11, 26 | "deltaTimestamp": "1944498031", 27 | "l1Info": { 28 | "globalExitRoot": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 29 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 30 | "timestamp": "42" 31 | }, 32 | "indexL1InfoTree": 0, 33 | "reason": "", 34 | "customRawTx": "0x0b73e6af6f00000000" 35 | }, 36 | { 37 | "id": 0, 38 | "from": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 39 | "to": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff", 40 | "nonce": 0, 41 | "value": "100000000000000000", 42 | "gasLimit": 100000, 43 | "gasPrice": "1000000000", 44 | "chainId": 1000, 45 | "rawTx": "0xf86d80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808207f5a01186622d03b6b8da7cf111d1ccba5bb185c56deae6a322cebc6dda0556f3cb979f910c26408b64b51c5da36ba2f38ef55ba1cee719d5a6c01225968799907432", 46 | "reason": "", 47 | "customRawTx": "0xee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff" 48 | } 49 | ], 50 | "expectedNewRoot": "0x5fc97a9a6ea9918f4b26e2dd52b27a688621cd4d2ff5c624c2df0cd1986d3b41", 51 | "expectedNewLeafs": { 52 | "0x617b3a3528f9cdd6630fd3301b9c8911f7bf063d": { 53 | "balance": "99900000000000000000", 54 | "nonce": "1" 55 | }, 56 | "0x4d5cf5032b2a844602278b01199ed191a86c93ff": { 57 | "balance": "200100000000000000000", 58 | "nonce": "0" 59 | } 60 | }, 61 | "batchL2Data": "0x0b73e6af6f00000000ee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff", 62 | "l1InfoRoot": "0x090bcaf734c4f06c93954a827b45a6e8c67b8e0fd1e0a35a1c5982d6961828f9", 63 | "newLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 64 | "inputHash": "0x58dc76197a13d9a9f0894e3d5984098339944ad4fa2cff01945b053d39cd1c9e", 65 | "batchHashData": "0x3d53e7e5be04b00f66af647512af6d17e4e767a5e41fa1293010b885c9fe06db", 66 | "oldAccInputHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 67 | "expectedNewAccInputHash": "0xe50b49f540b950cad5526ef669ff2d5bd8c81c86d9daeeb26d72a7a82920d25c", 68 | "timestampLimit": 1944498031 69 | } 70 | ] -------------------------------------------------------------------------------- /test/l1-info-tree-utils.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { Scalar } = require('ffjavascript'); 3 | 4 | const { 5 | getL1InfoTreeValue, 6 | } = require('../index').l1InfoTreeUtils; 7 | 8 | describe('L1 info tree utils', () => { 9 | it('getL1InfoTreeValue', async () => { 10 | const globalExitRoot = '0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f'; 11 | const blockHash = '0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb'; 12 | const timestamp = Scalar.e('1697231573'); 13 | 14 | const expectedValue = '0xf62f487534b899b1c362242616725878188ca891fab60854b792ca0628286de7'; 15 | 16 | const res = getL1InfoTreeValue(globalExitRoot, blockHash, timestamp); 17 | 18 | expect(res).to.be.equal(expectedValue); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/l1-info-tree.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { expect } = require('chai'); 4 | const { argv } = require('yargs'); 5 | 6 | const { pathTestVectors } = require('./helpers/test-utils'); 7 | const { MTBridge, l1InfoTreeUtils } = require('../index'); 8 | 9 | describe('l1 Info Tree', async function () { 10 | this.timeout(50000); 11 | 12 | const pathFullL1InfoTree = path.join(pathTestVectors, 'l1-info-tree/l1-info-tree.json'); 13 | 14 | let update; 15 | let testVectors; 16 | 17 | before(async () => { 18 | testVectors = JSON.parse(fs.readFileSync(pathFullL1InfoTree)); 19 | 20 | update = argv.update === true; 21 | }); 22 | 23 | it('Should check test vectors', async () => { 24 | const height = 32; 25 | 26 | // build tree and check root 27 | for (let i = 0; i < testVectors.length; i++) { 28 | const { leafs, expectedRoot } = testVectors[i]; 29 | 30 | const l1InfoTree = new MTBridge(height); 31 | 32 | for (let j = 0; j < leafs.length; j++) { 33 | const { leafData, expectedLeafValue } = leafs[j]; 34 | 35 | const valueLeaf = l1InfoTreeUtils.getL1InfoTreeValue( 36 | leafData.ger, 37 | leafData.blockHash, 38 | leafData.timestamp, 39 | ); 40 | 41 | l1InfoTree.add(valueLeaf); 42 | 43 | if (update) { 44 | testVectors[i].leafs[j].expectedLeafValue = valueLeaf; 45 | } else { 46 | expect(valueLeaf).to.be.equal(expectedLeafValue); 47 | } 48 | } 49 | 50 | const root = l1InfoTree.getRoot(); 51 | 52 | if (update) { 53 | testVectors[i].expectedRoot = root; 54 | } else { 55 | expect(root).to.be.equal(expectedRoot); 56 | } 57 | } 58 | 59 | if (update) { 60 | fs.writeFileSync(pathFullL1InfoTree, JSON.stringify(testVectors, null, 2)); 61 | } 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/mem-db.test.js: -------------------------------------------------------------------------------- 1 | const { Scalar } = require('ffjavascript'); 2 | const { expect } = require('chai'); 3 | 4 | const { 5 | MemDB, getPoseidon, 6 | } = require('../index'); 7 | 8 | describe('MemDB', () => { 9 | let poseidon; 10 | let F; 11 | let db; 12 | 13 | before(async () => { 14 | poseidon = await getPoseidon(); 15 | F = poseidon.F; 16 | }); 17 | 18 | it('create new instance', async () => { 19 | db = new MemDB(F); 20 | }); 21 | 22 | it('getSmtNode: no value', async () => { 23 | const key = [F.e(1), F.e(1), F.e(1), F.e(1)]; 24 | 25 | // no value found 26 | const res = await db.getSmtNode(key); 27 | expect(res).to.be.equal(null); 28 | }); 29 | 30 | it('getValue: no value', async () => { 31 | const key = Scalar.e(1); 32 | 33 | // no value found 34 | const res = await db.getValue(key); 35 | expect(res).to.be.equal(null); 36 | }); 37 | 38 | it('setValue & getValue', async () => { 39 | const key = Scalar.e(1); 40 | const value = { testN: 2, testStr: 'helloworld' }; 41 | 42 | await db.setValue(key, value); 43 | const res = await db.getValue(key); 44 | 45 | expect(value).to.be.deep.equal(res); 46 | }); 47 | 48 | it('setSmtNode & getSmtNode', async () => { 49 | const key = [F.e(1), F.e(2), F.e(3), F.e(4)]; 50 | const value = [F.e(0), F.e(1), F.e(2), F.e(3), F.e(4), F.e(5), F.e(6), F.e(7)]; 51 | 52 | await db.setSmtNode(key, value); 53 | const res = await db.getSmtNode(key); 54 | expect(value).to.be.deep.equal(res); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/mt-bridge-utils.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { Scalar } = require('ffjavascript'); 4 | const { expect } = require('chai'); 5 | const { argv } = require('yargs'); 6 | const { 7 | computeGlobalIndex, 8 | } = require('../index').mtBridgeUtils; 9 | const { pathTestVectors } = require('./helpers/test-utils'); 10 | 11 | describe('Merkle Bridge Utils', () => { 12 | const pathTests = path.join(pathTestVectors, 'merkle-tree-bridge/global-index.json'); 13 | 14 | let update; 15 | let testVectors; 16 | 17 | before(async () => { 18 | testVectors = JSON.parse(fs.readFileSync(pathTests)); 19 | update = argv.update === true; 20 | }); 21 | 22 | it('computeGlobalIndex', async () => { 23 | for (let i = 0; i < testVectors.length; i++) { 24 | const { 25 | indexLocal, indexRollup, isMainnet, expectedGlobalIndex, 26 | } = testVectors[i]; 27 | 28 | const computedGlobalIndex = computeGlobalIndex( 29 | Scalar.e(indexLocal), 30 | Scalar.e(indexRollup), 31 | isMainnet, 32 | ); 33 | 34 | if (update) { 35 | testVectors[i].expectedGlobalIndex = computedGlobalIndex.toString(); 36 | } else { 37 | expect(computedGlobalIndex.toString()).to.be.equal(expectedGlobalIndex); 38 | } 39 | } 40 | 41 | if (update) { 42 | fs.writeFileSync(pathTests, JSON.stringify(testVectors, null, 2)); 43 | } 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/mt-bridge.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const ethers = require('ethers'); 3 | const { MTBridge } = require('../index'); 4 | const { 5 | verifyMerkleProof, 6 | } = require('../index').mtBridgeUtils; 7 | 8 | describe('Merkle Bridge', () => { 9 | it('Check merkle tree', async () => { 10 | const height = 32; 11 | const merkleTree = new MTBridge(height); 12 | const leafValue = ethers.utils.formatBytes32String('1'); 13 | merkleTree.add(leafValue); 14 | const root = merkleTree.getRoot(); 15 | const proof = merkleTree.getProofTreeByIndex(0); 16 | const index = 0; 17 | const verification = verifyMerkleProof(leafValue, proof, index, root); 18 | expect(verification).to.be.equal(true); 19 | }); 20 | 21 | it('Check add 1 leaf to the merkle tree', async () => { 22 | const height = 32; 23 | const merkleTree = new MTBridge(height); 24 | 25 | const leafValue = ethers.utils.formatBytes32String('123'); 26 | merkleTree.add(leafValue); 27 | 28 | const root = merkleTree.getRoot(); 29 | 30 | // verify root 31 | const zerHashesArray = merkleTree.zeroHashes; 32 | let currentNode = leafValue; 33 | for (let i = 0; i < height; i++) { 34 | currentNode = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [currentNode, zerHashesArray[i]]); 35 | } 36 | expect(currentNode).to.be.equal(root); 37 | 38 | // check merkle proof 39 | const proof = merkleTree.getProofTreeByIndex(0); 40 | const index = 0; 41 | const verification = verifyMerkleProof(leafValue, proof, index, root); 42 | expect(verification).to.be.equal(true); 43 | }); 44 | 45 | it('Check add multipple leafs to the merkle tree', async () => { 46 | const height = 32; 47 | const merkleTree = new MTBridge(height); 48 | 49 | const leafValue = ethers.utils.formatBytes32String('123'); 50 | const leafValue2 = ethers.utils.formatBytes32String('456'); 51 | 52 | merkleTree.add(leafValue); 53 | merkleTree.add(leafValue2); 54 | 55 | const root = merkleTree.getRoot(); 56 | 57 | // verify root; 58 | const zerHashesArray = merkleTree.zeroHashes; 59 | let currentNode = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [leafValue, leafValue2]); 60 | for (let i = 1; i < height; i++) { 61 | currentNode = ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [currentNode, zerHashesArray[i]]); 62 | } 63 | expect(currentNode).to.be.equal(root); 64 | 65 | // check merkle proof 66 | const index = 0; 67 | const proof = merkleTree.getProofTreeByIndex(index); 68 | const verification = verifyMerkleProof(leafValue, proof, index, root); 69 | expect(verification).to.be.equal(true); 70 | 71 | // check merkle proof 72 | const index2 = 1; 73 | const proof2 = merkleTree.getProofTreeByIndex(index2); 74 | const verification2 = verifyMerkleProof(leafValue2, proof2, index2, root); 75 | expect(verification2).to.be.equal(true); 76 | 77 | // following merkle proofs are invalid 78 | expect(verifyMerkleProof(leafValue, proof2, index2, root)).to.be.equal(false); 79 | expect(verifyMerkleProof(leafValue, proof2, index2, proof)).to.be.equal(false); 80 | expect(verifyMerkleProof(leafValue, proof2, index2, proof)).to.be.equal(false); 81 | expect(verifyMerkleProof(leafValue, proof2, index2 + 1, proof)).to.be.equal(false); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/poseidon.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow-callback */ 2 | /* eslint-disable no-console */ 3 | const { assert } = require('chai'); 4 | const { getPoseidon } = require('../index'); 5 | 6 | describe('poseidon', async function () { 7 | this.timeout(300000000); 8 | 9 | it('should calculate poseidon of test vector 0...0', async () => { 10 | const poseidon = await getPoseidon(); 11 | const { F } = poseidon; 12 | 13 | const res = poseidon([0, 0, 0, 0, 0, 0, 0, 0]); 14 | const expectedRes = [F.e('0x3c18a9786cb0b359'), F.e('0xc4055e3364a246c3'), F.e('0x7953db0ab48808f4'), F.e('0xc71603f33a1144ca')]; 15 | 16 | for (let i = 0; i < 4; i++) { 17 | assert(F.eq(res[i], expectedRes[i])); 18 | } 19 | }); 20 | 21 | it('should calculate poseidon of test vector 0..11', async () => { 22 | const poseidon = await getPoseidon(); 23 | const { F } = poseidon; 24 | 25 | const res = poseidon([0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11]); 26 | const expectedRes = [F.e('0xd64e1e3efc5b8e9e'), F.e('0x53666633020aaa47'), F.e('0xd40285597c6a8825'), F.e('0x613a4f81e81231d2')]; 27 | 28 | for (let i = 0; i < 4; i++) { 29 | assert(F.eq(res[i], expectedRes[i])); 30 | } 31 | }); 32 | 33 | it('should calculate poseidon of test vector -1..-1', async () => { 34 | const poseidon = await getPoseidon(); 35 | const { F } = poseidon; 36 | 37 | const res = poseidon([-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1]); 38 | const expectedRes = [F.e('0xbe0085cfc57a8357'), F.e('0xd95af71847d05c09'), F.e('0xcf55a13d33c1c953'), F.e('0x95803a74f4530e82')]; 39 | 40 | for (let i = 0; i < 4; i++) { 41 | assert(F.eq(res[i], expectedRes[i])); 42 | } 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/smt-full-genesis.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { expect } = require('chai'); 4 | const { argv } = require('yargs'); 5 | 6 | const { 7 | MemDB, SMT, stateUtils, getPoseidon, smtUtils, 8 | } = require('../index'); 9 | const { pathTestVectors } = require('./helpers/test-utils'); 10 | 11 | describe('smt full-genesis', async function () { 12 | this.timeout(50000); 13 | 14 | const pathFullGenesis = path.join(pathTestVectors, 'merkle-tree/smt-full-genesis.json'); 15 | 16 | let update; 17 | let poseidon; 18 | let F; 19 | let testVectors; 20 | 21 | before(async () => { 22 | poseidon = await getPoseidon(); 23 | F = poseidon.F; 24 | testVectors = JSON.parse(fs.readFileSync(pathFullGenesis)); 25 | 26 | update = argv.update === true; 27 | }); 28 | 29 | it('Should check test vectors', async () => { 30 | // build tree and check root 31 | for (let i = 0; i < testVectors.length; i++) { 32 | const { addresses, expectedRoot } = testVectors[i]; 33 | 34 | const db = new MemDB(F); 35 | const smt = new SMT(db, poseidon, poseidon.F); 36 | 37 | let tmpRoot = smt.empty; 38 | 39 | for (let j = 0; j < addresses.length; j++) { 40 | const { 41 | address, balance, nonce, 42 | bytecode, storage, 43 | } = addresses[j]; 44 | // add balance and nonce 45 | tmpRoot = await stateUtils.setAccountState(address, smt, tmpRoot, balance, nonce); 46 | // add bytecode if defined 47 | if (typeof bytecode !== 'undefined') { 48 | tmpRoot = await stateUtils.setContractBytecode(address, smt, tmpRoot, bytecode); 49 | } 50 | // add storage if defined 51 | if (typeof storage !== 'undefined') { 52 | tmpRoot = await stateUtils.setContractStorage(address, smt, tmpRoot, storage); 53 | } 54 | } 55 | 56 | if (update) { 57 | testVectors[i].expectedRoot = (smtUtils.h4toScalar(tmpRoot)).toString(); 58 | } else { 59 | expect((smtUtils.h4toScalar(tmpRoot)).toString()).to.be.equal(expectedRoot); 60 | } 61 | } 62 | 63 | if (update) { 64 | fs.writeFileSync(pathFullGenesis, JSON.stringify(testVectors, null, 2)); 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/smt-genesis.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { Scalar } = require('ffjavascript'); 4 | const { expect } = require('chai'); 5 | const { argv } = require('yargs'); 6 | 7 | const { 8 | MemDB, SMT, smtUtils, getPoseidon, 9 | } = require('../index'); 10 | const { pathTestVectors } = require('./helpers/test-utils'); 11 | 12 | describe('smt genesis', async function () { 13 | this.timeout(10000); 14 | const pathGenesis = path.join(pathTestVectors, 'merkle-tree/smt-genesis.json'); 15 | 16 | let update; 17 | let poseidon; 18 | let F; 19 | let testVectors; 20 | 21 | before(async () => { 22 | poseidon = await getPoseidon(); 23 | F = poseidon.F; 24 | testVectors = JSON.parse(fs.readFileSync(pathGenesis)); 25 | 26 | update = argv.update === true; 27 | }); 28 | 29 | it('Should check test vectors', async () => { 30 | // build tree and check root 31 | for (let i = 0; i < testVectors.length; i++) { 32 | const { addresses, expectedRoot } = testVectors[i]; 33 | 34 | const db = new MemDB(F); 35 | const smt = new SMT(db, poseidon, poseidon.F); 36 | 37 | let tmpRoot = smt.empty; 38 | 39 | for (let j = 0; j < addresses.length; j++) { 40 | const { address, balance, nonce } = addresses[j]; 41 | 42 | const keyAddress = await smtUtils.keyEthAddrBalance(address); 43 | const keyNonce = await smtUtils.keyEthAddrNonce(address); 44 | 45 | let auxRes = await smt.set(tmpRoot, keyAddress, Scalar.e(balance)); 46 | auxRes = await smt.set(auxRes.newRoot, keyNonce, Scalar.e(nonce)); 47 | tmpRoot = auxRes.newRoot; 48 | } 49 | 50 | if (update) { 51 | testVectors[i].expectedRoot = (smtUtils.h4toScalar(tmpRoot)).toString(); 52 | } else { 53 | expect((smtUtils.h4toScalar(tmpRoot)).toString()).to.be.equal(expectedRoot); 54 | } 55 | } 56 | 57 | if (update) { 58 | fs.writeFileSync(pathGenesis, JSON.stringify(testVectors, null, 2)); 59 | } 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/smt-raw.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { Scalar } = require('ffjavascript'); 4 | const { expect } = require('chai'); 5 | const { argv } = require('yargs'); 6 | 7 | const { 8 | MemDB, SMT, getPoseidon, smtUtils, 9 | } = require('../index'); 10 | const { pathTestVectors } = require('./helpers/test-utils'); 11 | 12 | describe('smt raw', async function () { 13 | this.timeout(10000); 14 | 15 | const pathRaw = path.join(pathTestVectors, 'merkle-tree/smt-raw.json'); 16 | 17 | let update; 18 | let poseidon; 19 | let F; 20 | let testVectors; 21 | 22 | before(async () => { 23 | poseidon = await getPoseidon(); 24 | F = poseidon.F; 25 | testVectors = JSON.parse(fs.readFileSync(pathRaw)); 26 | 27 | update = argv.update === true; 28 | }); 29 | 30 | it('Should check test vectors', async () => { 31 | // build tree and check root 32 | for (let i = 0; i < testVectors.length; i++) { 33 | const { 34 | keys, values, expectedRoot, 35 | } = testVectors[i]; 36 | 37 | const db = new MemDB(F); 38 | const smt = new SMT(db, poseidon, poseidon.F); 39 | 40 | expect(keys.length).to.be.equal(values.length); 41 | 42 | let tmpRoot = smt.empty; 43 | 44 | for (let j = 0; j < keys.length; j++) { 45 | const key = smtUtils.scalar2h4(keys[j]); 46 | const value = Scalar.e(values[j]); 47 | 48 | const res = await smt.set(tmpRoot, key, value); 49 | tmpRoot = res.newRoot; 50 | } 51 | 52 | if (update) { 53 | testVectors[i].expectedRoot = smtUtils.h4toString(tmpRoot); 54 | } else { 55 | expect(smtUtils.h4toString(tmpRoot)).to.be.equal(expectedRoot); 56 | } 57 | } 58 | 59 | if (update) { 60 | fs.writeFileSync(pathRaw, JSON.stringify(testVectors, null, 2)); 61 | } 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/smt-utils.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { Scalar } = require('ffjavascript'); 4 | const { expect } = require('chai'); 5 | const lodash = require('lodash'); 6 | const { argv } = require('yargs'); 7 | 8 | const { 9 | smtUtils, getPoseidon, Constants, SMT, MemDB, 10 | } = require('../index'); 11 | const { pathTestVectors, scalar2key } = require('./helpers/test-utils'); 12 | const { h4toScalar } = require('../src/smt-utils'); 13 | 14 | // eslint-disable-next-line prefer-arrow-callback 15 | describe('smtUtils', async function () { 16 | this.timeout(60000); 17 | 18 | const pathKeysBalance = path.join(pathTestVectors, 'merkle-tree/smt-key-eth-balance.json'); 19 | const pathKeysNonce = path.join(pathTestVectors, 'merkle-tree/smt-key-eth-nonce.json'); 20 | const pathKeysContractCode = path.join(pathTestVectors, 'merkle-tree/smt-key-contract-code.json'); 21 | const pathKeysContractStorage = path.join(pathTestVectors, 'merkle-tree/smt-key-contract-storage.json'); 22 | const pathKeysContractLength = path.join(pathTestVectors, 'merkle-tree/smt-key-contract-length.json'); 23 | const pathHashBytecode = path.join(pathTestVectors, 'merkle-tree/smt-hash-bytecode.json'); 24 | 25 | let update; 26 | let poseidon; 27 | let F; 28 | let testVectorsKeysBalance; 29 | let testVectorsKeysNonce; 30 | let testVectorsKeysContractStorage; 31 | let testVectorsKeysContractCode; 32 | let testVectorsKeysContractLength; 33 | let testVectorsHashBytecode; 34 | 35 | before(async () => { 36 | poseidon = await getPoseidon(); 37 | F = poseidon.F; 38 | testVectorsKeysBalance = JSON.parse(fs.readFileSync(pathKeysBalance)); 39 | testVectorsKeysNonce = JSON.parse(fs.readFileSync(pathKeysNonce)); 40 | testVectorsKeysContractCode = JSON.parse(fs.readFileSync(pathKeysContractCode)); 41 | testVectorsKeysContractStorage = JSON.parse(fs.readFileSync(pathKeysContractStorage)); 42 | testVectorsKeysContractLength = JSON.parse(fs.readFileSync(pathKeysContractLength)); 43 | testVectorsHashBytecode = JSON.parse(fs.readFileSync(pathHashBytecode)); 44 | 45 | update = argv.update === true; 46 | }); 47 | 48 | it('scalar2fea & fea2scalar', async () => { 49 | const value = (Scalar.e('115792089237316195423570985008687907853269984665640564039457584007913129639935')).toString(16); 50 | 51 | const fea = smtUtils.string2fea(F, value); 52 | const str = smtUtils.fea2String(F, fea); 53 | 54 | expect(str).to.be.equal(`0x${value}`); 55 | }); 56 | 57 | it('fea2String & string2fea', async () => { 58 | const value = Scalar.e('115792089237316195423570985008687907853269984665640564039457584007913129639935'); 59 | 60 | const fea = smtUtils.scalar2fea(F, value); 61 | const sca = smtUtils.fea2scalar(F, fea); 62 | 63 | expect(sca.toString()).to.be.equal(value.toString()); 64 | }); 65 | 66 | it('fe2n: positive', async () => { 67 | // positive value 68 | const number = 1; 69 | const value = F.e(number); 70 | 71 | const res = smtUtils.fe2n(F, value); 72 | expect(res).to.be.equal(number); 73 | }); 74 | 75 | it('fe2n: negative', async () => { 76 | // positive value 77 | const number = -1; 78 | const value = F.e(number); 79 | 80 | const res = smtUtils.fe2n(F, value); 81 | expect(res).to.be.equal(number); 82 | }); 83 | 84 | it('fe2n: error over 32 bit value', async () => { 85 | /* 86 | * 1 bit is used as a sign 87 | * over 32 bits 88 | */ 89 | let number = 2 ** 31; 90 | let value = F.e(number); 91 | 92 | try { 93 | smtUtils.fe2n(F, value); 94 | expect(true).to.be.equal(false); 95 | } catch (error) { 96 | expect(error.message.includes('Accessing a no 32bit value')).to.be.equal(true); 97 | } 98 | 99 | // edge case 100 | number = (2 ** 31) - 1; 101 | value = F.e(number); 102 | 103 | const res = smtUtils.fe2n(F, value); 104 | expect(res).to.be.equal(number); 105 | }); 106 | 107 | it('h4toScalar, scalar2h4, h4toString & stringToH4', async () => { 108 | const input = [Scalar.e(0), Scalar.e('18446744069414584321'), Scalar.e('4294967296'), Scalar.e('328469')]; 109 | 110 | const resScalar = smtUtils.h4toScalar(input); 111 | const resString = smtUtils.h4toString(input); 112 | expect(resString).to.be.equal(`0x${Scalar.toString(resScalar, 16).padStart(64, '0')}`); 113 | 114 | const resTest = smtUtils.stringToH4(resString); 115 | expect(lodash.isEqual(resTest, input)).to.be.equal(true); 116 | 117 | const init = smtUtils.scalar2h4(resScalar); 118 | expect(lodash.isEqual(init, input)).to.be.equal(true); 119 | }); 120 | 121 | it('keyEthAddrBalance', async () => { 122 | for (let i = 0; i < testVectorsKeysBalance.length; i++) { 123 | const { 124 | leafType, ethAddr, expectedKey, 125 | } = testVectorsKeysBalance[i]; 126 | 127 | const res = await smtUtils.keyEthAddrBalance(ethAddr); 128 | 129 | if (update) { 130 | testVectorsKeysBalance[i].expectedKey = h4toScalar(res).toString(); 131 | } else { 132 | expect(h4toScalar(res).toString()).to.be.equal(expectedKey); 133 | expect(leafType).to.be.equal(Constants.SMT_KEY_BALANCE); 134 | } 135 | } 136 | 137 | if (update) { 138 | fs.writeFileSync(pathKeysBalance, JSON.stringify(testVectorsKeysBalance, null, 2)); 139 | } 140 | }); 141 | 142 | it('keyEthAddrNonce', async () => { 143 | for (let i = 0; i < testVectorsKeysNonce.length; i++) { 144 | const { 145 | leafType, ethAddr, expectedKey, 146 | } = testVectorsKeysNonce[i]; 147 | 148 | const res = await smtUtils.keyEthAddrNonce(ethAddr); 149 | 150 | if (update) { 151 | testVectorsKeysNonce[i].expectedKey = h4toScalar(res).toString(); 152 | } else { 153 | expect(h4toScalar(res).toString()).to.be.equal(expectedKey); 154 | expect(leafType).to.be.equal(Constants.SMT_KEY_NONCE); 155 | } 156 | } 157 | 158 | if (update) { 159 | fs.writeFileSync(pathKeysNonce, JSON.stringify(testVectorsKeysNonce, null, 2)); 160 | } 161 | }); 162 | 163 | it('keyContractCode', async () => { 164 | for (let i = 0; i < testVectorsKeysContractCode.length; i++) { 165 | const { 166 | leafType, ethAddr, expectedKey, 167 | } = testVectorsKeysContractCode[i]; 168 | 169 | const res = await smtUtils.keyContractCode(ethAddr); 170 | 171 | if (update) { 172 | testVectorsKeysContractCode[i].expectedKey = h4toScalar(res).toString(); 173 | } else { 174 | expect(h4toScalar(res).toString()).to.be.equal(expectedKey); 175 | expect(leafType).to.be.equal(Constants.SMT_KEY_SC_CODE); 176 | } 177 | } 178 | 179 | if (update) { 180 | fs.writeFileSync(pathKeysContractCode, JSON.stringify(testVectorsKeysContractCode, null, 2)); 181 | } 182 | }); 183 | 184 | it('keyContractStorage', async () => { 185 | for (let i = 0; i < testVectorsKeysContractStorage.length; i++) { 186 | const { 187 | leafType, ethAddr, storagePosition, expectedKey, 188 | } = testVectorsKeysContractStorage[i]; 189 | 190 | const res = await smtUtils.keyContractStorage(ethAddr, storagePosition); 191 | 192 | if (update) { 193 | testVectorsKeysContractStorage[i].expectedKey = h4toScalar(res).toString(); 194 | } else { 195 | expect(h4toScalar(res).toString()).to.be.equal(expectedKey); 196 | expect(leafType).to.be.equal(Constants.SMT_KEY_SC_STORAGE); 197 | } 198 | } 199 | 200 | if (update) { 201 | fs.writeFileSync(pathKeysContractStorage, JSON.stringify(testVectorsKeysContractStorage, null, 2)); 202 | } 203 | }); 204 | 205 | it('keyContractLength', async () => { 206 | for (let i = 0; i < testVectorsKeysContractLength.length; i++) { 207 | const { 208 | leafType, ethAddr, expectedKey, 209 | } = testVectorsKeysContractLength[i]; 210 | 211 | const res = await smtUtils.keyContractLength(ethAddr); 212 | 213 | if (update) { 214 | testVectorsKeysContractLength[i].expectedKey = h4toScalar(res).toString(); 215 | } else { 216 | expect(h4toScalar(res).toString()).to.be.equal(expectedKey); 217 | expect(leafType).to.be.equal(Constants.SMT_KEY_SC_LENGTH); 218 | } 219 | } 220 | 221 | if (update) { 222 | fs.writeFileSync(pathKeysContractLength, JSON.stringify(testVectorsKeysContractLength, null, 2)); 223 | } 224 | }); 225 | 226 | it('getCurrentDB', async () => { 227 | const db = new MemDB(F); 228 | const smt = new SMT(db, poseidon, poseidon.F); 229 | 230 | const r1 = await smt.set(smt.empty, scalar2key(1, F), Scalar.e(1)); 231 | const r2 = await smt.set(r1.newRoot, scalar2key(2, F), Scalar.e(2)); 232 | const r3 = await smt.set(r2.newRoot, scalar2key(3, F), Scalar.e(3)); 233 | const r4 = await smt.set(r3.newRoot, scalar2key(4, F), Scalar.e(4)); 234 | const r5 = await smt.set(r4.newRoot, scalar2key(17, F), Scalar.e(5)); 235 | 236 | const fullDB = await smtUtils.getCurrentDB(r5.newRoot, db, F); 237 | 238 | const expectedNodes = 16; 239 | expect(expectedNodes).to.be.equal(Object.keys(fullDB).length); 240 | }); 241 | 242 | it('hashContractBytecode', async () => { 243 | for (let i = 0; i < testVectorsHashBytecode.length; i++) { 244 | const { bytecode, expectedHash } = testVectorsHashBytecode[i]; 245 | const hashBytecode = await smtUtils.hashContractBytecode(bytecode); 246 | if (update) { 247 | testVectorsHashBytecode[i].expectedHash = hashBytecode; 248 | } else { 249 | expect(hashBytecode).to.be.equal(expectedHash); 250 | } 251 | } 252 | 253 | if (update) { 254 | fs.writeFileSync(pathHashBytecode, JSON.stringify(testVectorsHashBytecode, null, 2)); 255 | } 256 | }); 257 | }); 258 | -------------------------------------------------------------------------------- /test/smt.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | const { Scalar } = require('ffjavascript'); 3 | const { assert } = require('chai'); 4 | 5 | const { 6 | SMT, MemDB, getPoseidon, smtUtils, 7 | } = require('../index'); 8 | 9 | const { scalar2key } = require('./helpers/test-utils'); 10 | 11 | describe('SMT', async function () { 12 | let poseidon; 13 | let F; 14 | this.timeout(100000); 15 | 16 | before(async () => { 17 | poseidon = await getPoseidon(); 18 | F = poseidon.F; 19 | }); 20 | 21 | it('It should add and remove an element', async () => { 22 | const db = new MemDB(F); 23 | const smt = new SMT(db, poseidon, poseidon.F); 24 | 25 | const r1 = await smt.set(smt.empty, scalar2key(1, F), Scalar.e(2)); 26 | 27 | const rGet = await smt.get(r1.newRoot, scalar2key(1, F)); 28 | 29 | assert(Scalar.eq(rGet.value, Scalar.e(2))); 30 | 31 | const r2 = await smt.set(r1.newRoot, scalar2key(1, F), Scalar.e(0)); 32 | assert(smtUtils.nodeIsZero(r2.newRoot, F)); 33 | }); 34 | 35 | it('It should update an element 1', async () => { 36 | const db = new MemDB(F); 37 | const smt = new SMT(db, poseidon, poseidon.F); 38 | 39 | const r1 = await smt.set(smt.empty, scalar2key(1, F), Scalar.e(2)); 40 | const r2 = await smt.set(r1.newRoot, scalar2key(1, F), Scalar.e(3)); 41 | const r3 = await smt.set(r2.newRoot, scalar2key(1, F), Scalar.e(2)); 42 | 43 | assert(smtUtils.nodeIsEq(r1.newRoot, r3.newRoot, F)); 44 | }); 45 | 46 | it('It should add a shared element 2', async () => { 47 | const db = new MemDB(F); 48 | const smt = new SMT(db, poseidon, poseidon.F); 49 | 50 | const r1 = await smt.set(smt.empty, scalar2key(8, F), Scalar.e(2)); 51 | const r2 = await smt.set(r1.newRoot, scalar2key(9, F), Scalar.e(3)); 52 | const r3 = await smt.set(r2.newRoot, scalar2key(8, F), Scalar.e(0)); 53 | const r4 = await smt.set(r3.newRoot, scalar2key(9, F), Scalar.e(0)); 54 | 55 | assert(smtUtils.nodeIsZero(r4.newRoot, F)); 56 | }); 57 | 58 | it('It should add a shared element 3', async () => { 59 | const db = new MemDB(F); 60 | const smt = new SMT(db, poseidon, poseidon.F); 61 | 62 | const r1 = await smt.set(smt.empty, scalar2key(7, F), Scalar.e(2)); 63 | const r2 = await smt.set(r1.newRoot, scalar2key(15, F), Scalar.e(3)); 64 | const r3 = await smt.set(r2.newRoot, scalar2key(7, F), Scalar.e(0)); 65 | const r4 = await smt.set(r3.newRoot, scalar2key(15, F), Scalar.e(0)); 66 | 67 | assert(smtUtils.nodeIsZero(r4.newRoot, F)); 68 | }); 69 | 70 | it('It should add a shared element', async () => { 71 | const db = new MemDB(F); 72 | const smt = new SMT(db, poseidon, poseidon.F); 73 | 74 | const r1 = await smt.set(smt.empty, scalar2key(7, F), Scalar.e(107)); 75 | const r2 = await smt.set(r1.newRoot, scalar2key(15, F), Scalar.e(115)); 76 | const r3 = await smt.set(r2.newRoot, scalar2key(3, F), Scalar.e(103)); 77 | const r4 = await smt.set(r3.newRoot, scalar2key(7, F), Scalar.e(0)); 78 | const r5 = await smt.set(r4.newRoot, scalar2key(15, F), Scalar.e(0)); 79 | const r6 = await smt.set(r5.newRoot, scalar2key(3, F), Scalar.e(0)); 80 | 81 | assert(smtUtils.nodeIsZero(r6.newRoot, F)); 82 | }); 83 | 84 | it('Add-Remove 128 elements', async () => { 85 | const N = 128; 86 | const db = new MemDB(F); 87 | const smt = new SMT(db, poseidon, poseidon.F); 88 | 89 | let r = { 90 | newRoot: smt.empty, 91 | }; 92 | 93 | for (let i = 0; i < N; i++) { 94 | r = await smt.set(r.newRoot, scalar2key(i, F), Scalar.e(i + 1000)); 95 | } 96 | 97 | for (let i = 0; i < N; i++) { 98 | r = await smt.set(r.newRoot, scalar2key(i, F), Scalar.e(0)); 99 | } 100 | 101 | assert(smtUtils.nodeIsZero(r.newRoot, F)); 102 | }); 103 | 104 | it('Should read random', async () => { 105 | const N = 3; 106 | const db = new MemDB(F); 107 | const smt = new SMT(db, poseidon, poseidon.F); 108 | 109 | const vals = {}; 110 | 111 | let r = { 112 | newRoot: smt.empty, 113 | }; 114 | 115 | let rr; 116 | 117 | for (let i = 0; i < N; i++) { 118 | const key = i; 119 | const val = i; 120 | vals[key] = val; 121 | r = await smt.set(r.newRoot, scalar2key(key, F), Scalar.e(val)); 122 | } 123 | 124 | for (let i = 0; i < N; i++) { 125 | rr = await smt.get(r.newRoot, scalar2key(i, F)); 126 | const v = vals[i] ? vals[i] : 0; 127 | assert(Scalar.eq(rr.value, Scalar.e(v))); 128 | } 129 | }); 130 | 131 | it('It should add elements with similar keys', async () => { 132 | const db = new MemDB(F); 133 | const smt = new SMT(db, poseidon, poseidon.F); 134 | 135 | const expectedRoot = [ 136 | 442750481621001142n, 137 | 12174547650106208885n, 138 | 10730437371575329832n, 139 | 4693848817100050981n, 140 | ]; 141 | 142 | const r0 = await smt.set(smt.empty, scalar2key(0, F), Scalar.e(2)); // 0x00 143 | const r1 = await smt.set(r0.newRoot, scalar2key(4369, F), Scalar.e(2)); // 0x1111 144 | const r2 = await smt.set(r1.newRoot, scalar2key(69905, F), Scalar.e(3)); // 0x11111 145 | 146 | assert(smtUtils.nodeIsEq(expectedRoot, r2.newRoot, F)); 147 | }); 148 | 149 | it('It should update leaf with more than one level depth', async () => { 150 | const db = new MemDB(F); 151 | const smt = new SMT(db, poseidon, poseidon.F); 152 | 153 | const expectedRoot = [ 154 | 13590506365193044307n, 155 | 13215874698458506886n, 156 | 4743455437729219665n, 157 | 1933616419393621600n, 158 | ]; 159 | 160 | const r0 = await smt.set( 161 | smt.empty, 162 | scalar2key(Scalar.e('56714103185361745016746792718676985000067748055642999311525839752090945477479'), F), 163 | Scalar.e('8163644824788514136399898658176031121905718480550577527648513153802600646339'), 164 | ); 165 | 166 | const r1 = await smt.set( 167 | r0.newRoot, 168 | scalar2key(Scalar.e('980275562601266368747428591417466442501663392777380336768719359283138048405'), F), 169 | Scalar.e('115792089237316195423570985008687907853269984665640564039457584007913129639934'), 170 | ); 171 | 172 | const r2 = await smt.set( 173 | r1.newRoot, 174 | scalar2key(Scalar.e('53001048207672216258532366725645107222481888169041567493527872624420899640125'), F), 175 | Scalar.e('115792089237316195423570985008687907853269984665640564039457584007913129639935'), 176 | ); 177 | 178 | const r3 = await smt.set( 179 | r2.newRoot, 180 | scalar2key(Scalar.e('60338373645545410525187552446039797737650319331856456703054942630761553352879'), F), 181 | Scalar.e('7943875943875408'), 182 | ); 183 | 184 | const r4 = await smt.set( 185 | r3.newRoot, 186 | scalar2key(Scalar.e('56714103185361745016746792718676985000067748055642999311525839752090945477479'), F), 187 | Scalar.e('35179347944617143021579132182092200136526168785636368258055676929581544372820'), 188 | ); 189 | assert(smtUtils.nodeIsEq(expectedRoot, r4.newRoot, F)); 190 | }); 191 | 192 | it('It should Zero to Zero with isOldZero=0', async () => { 193 | const db = new MemDB(F); 194 | const smt = new SMT(db, poseidon, poseidon.F); 195 | 196 | const r0 = await smt.set(smt.empty, scalar2key(0x1, F), Scalar.e(2)); // 0x00 197 | const r1 = await smt.set(r0.newRoot, scalar2key(0x2, F), Scalar.e(3)); // 0x00 198 | const r2 = await smt.set(r1.newRoot, scalar2key(0x10000, F), Scalar.e(0)); // 0x1111 199 | 200 | assert(!r2.isOldZero); 201 | }); 202 | }); 203 | -------------------------------------------------------------------------------- /test/state-utils.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable quote-props */ 2 | const { Scalar } = require('ffjavascript'); 3 | const { expect } = require('chai'); 4 | const lodash = require('lodash'); 5 | 6 | const { 7 | smtUtils, SMT, MemDB, getPoseidon, stateUtils, 8 | } = require('../index'); 9 | 10 | // eslint-disable-next-line prefer-arrow-callback 11 | describe('smtUtils', async function () { 12 | this.timeout(60000); 13 | 14 | let poseidon; 15 | let F; 16 | 17 | before(async () => { 18 | poseidon = await getPoseidon(); 19 | F = poseidon.F; 20 | }); 21 | 22 | it('set-get account', async () => { 23 | const db = new MemDB(F); 24 | const smt = new SMT(db, poseidon, poseidon.F); 25 | 26 | const ethAddr = '0x12345'; 27 | const account = { 28 | balance: Scalar.e('1000000000'), 29 | nonce: Scalar.e('735'), 30 | }; 31 | 32 | const root = await stateUtils.setAccountState(ethAddr, smt, smt.empty, account.balance, account.nonce); 33 | const resAccount = await stateUtils.getState(ethAddr, smt, root); 34 | 35 | expect(account.balance.toString()).to.be.equal(resAccount.balance.toString()); 36 | expect(account.nonce.toString()).to.be.equal(resAccount.nonce.toString()); 37 | }); 38 | 39 | it('set-get hash bytecode and length', async () => { 40 | const db = new MemDB(F); 41 | const smt = new SMT(db, poseidon, poseidon.F); 42 | 43 | const ethAddr = '0x123456'; 44 | const bytecode = '0x6789AB'; 45 | 46 | const hashBytecode = await smtUtils.hashContractBytecode(bytecode); 47 | const root = await stateUtils.setContractBytecode(ethAddr, smt, smt.empty, bytecode); 48 | 49 | const resHashBytecode = await stateUtils.getContractHashBytecode(ethAddr, smt, root); 50 | const resBytecodeLength = await stateUtils.getContractBytecodeLength(ethAddr, smt, root); 51 | 52 | expect(resBytecodeLength.toString()).to.be.equal(((bytecode.length - 2) / 2).toString()); 53 | expect(hashBytecode).to.be.equal(resHashBytecode); 54 | }); 55 | 56 | it('set-get contract storage', async () => { 57 | const db = new MemDB(F); 58 | const smt = new SMT(db, poseidon, poseidon.F); 59 | 60 | const ethAddr = '0x12345'; 61 | const storage = { 62 | '873274': Scalar.e(23), 63 | '7264': Scalar.e(57), 64 | '2873': Scalar.e(77), 65 | }; 66 | 67 | const root = await stateUtils.setContractStorage(ethAddr, smt, smt.empty, storage); 68 | const resStorage = await stateUtils.getContractStorage(ethAddr, smt, root, Object.keys(storage)); 69 | 70 | expect(lodash.isEqual(resStorage, storage)).to.be.equal(true); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/tmp-smt-db.test.js: -------------------------------------------------------------------------------- 1 | const { Scalar } = require('ffjavascript'); 2 | const { expect } = require('chai'); 3 | const ethers = require('ethers'); 4 | 5 | const { 6 | MemDB, SMT, smtUtils, TmpSmtDB, getPoseidon, 7 | } = require('../index'); 8 | 9 | describe('TmpSmtDB', () => { 10 | let poseidon; 11 | let F; 12 | 13 | before(async () => { 14 | poseidon = await getPoseidon(); 15 | F = poseidon.F; 16 | }); 17 | 18 | it('Check that tmpDB gets the state from srcDb', async () => { 19 | const address = '0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D'; 20 | const balance = Scalar.e(ethers.utils.parseEther('100')); 21 | 22 | // memDB 23 | const db = new MemDB(F); 24 | const smt = new SMT(db, poseidon, poseidon.F); 25 | 26 | // create TmpSmtDB 27 | const tmpDB = new TmpSmtDB(db); 28 | const smtTmp = new SMT(tmpDB, poseidon, poseidon.F); 29 | 30 | const keyBalance = await smtUtils.keyEthAddrBalance(address); 31 | const zeroRoot = smt.empty; 32 | 33 | const auxRes = await smt.set(zeroRoot, keyBalance, balance); 34 | const genesisRoot = auxRes.newRoot; 35 | 36 | const resBalance = await smt.get(genesisRoot, keyBalance); 37 | const resBalanceTmp = await smtTmp.get(genesisRoot, keyBalance); 38 | 39 | expect(resBalance).to.be.deep.equal(resBalanceTmp); 40 | }); 41 | 42 | it('Update and populate memDB with tmpDb', async () => { 43 | const address = '0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D'; 44 | const balance = Scalar.e(ethers.utils.parseEther('100')); 45 | 46 | const db = new MemDB(F); 47 | const smt = new SMT(db, poseidon, poseidon.F); 48 | 49 | // create TmpDB 50 | const tmpDB = new TmpSmtDB(db); 51 | 52 | // load smtTMp 53 | const smtTmp = new SMT(tmpDB, poseidon, poseidon.F); 54 | 55 | const keyBalance = await smtUtils.keyEthAddrBalance(address); 56 | const zeroRoot = smt.empty; 57 | 58 | const auxRes = await smtTmp.set(zeroRoot, keyBalance, balance); 59 | const genesisRoot = auxRes.newRoot; 60 | 61 | let resBalance; 62 | try { 63 | resBalance = await smt.get(genesisRoot, keyBalance); 64 | } catch (error) { 65 | resBalance = { value: Scalar.e(0) }; 66 | } 67 | const resBalanceTmp = await smtTmp.get(genesisRoot, keyBalance); 68 | 69 | expect(resBalance.value).to.be.equal(Scalar.e(0)); 70 | expect(resBalanceTmp.value).to.be.equal(balance); 71 | 72 | // populate db with the content of the tmpDb 73 | await tmpDB.populateSrcDb(); 74 | 75 | let resBalance2; 76 | try { 77 | resBalance2 = await smt.get(genesisRoot, keyBalance); 78 | } catch (error) { 79 | resBalance2 = { value: Scalar.e(0) }; 80 | } 81 | const resBalance2Tmp = await smtTmp.get(genesisRoot, keyBalance); 82 | const tempDBArray = await smtUtils.getCurrentDB(genesisRoot, tmpDB, F); 83 | const DBArray = await smtUtils.getCurrentDB(genesisRoot, db, F); 84 | 85 | expect(resBalance2Tmp.value).to.be.equal(balance); 86 | expect(resBalance2Tmp.value.toString()).to.be.equal(resBalance2.value.toString()); 87 | expect(tempDBArray).to.be.deep.equal(DBArray); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /test/utils.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | 3 | const { 4 | utils, 5 | } = require('../index'); 6 | 7 | // eslint-disable-next-line prefer-arrow-callback 8 | describe('utils', async function () { 9 | it('byteArray2HexString & hexString2byteArray', async () => { 10 | const inputHex = '0x010203040506070809'; 11 | const inputArray = utils.hexString2byteArray(inputHex); 12 | const outputHex = utils.byteArray2HexString(inputArray); 13 | 14 | expect(outputHex).to.be.equal(inputHex.slice(2)); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tools/generate-claim/generate-claim-exit-root.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | const ethers = require('ethers'); 4 | 5 | const MerkleTreeBridge = require('../../index').MTBridge; 6 | const { 7 | verifyMerkleProof, 8 | getLeafValue, 9 | } = require('../../index').mtBridgeUtils; 10 | 11 | const { Constants } = require('../../index'); 12 | 13 | function calculateGlobalExitRoot(mainnetExitRoot, rollupExitRoot) { 14 | return ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [mainnetExitRoot, rollupExitRoot]); 15 | } 16 | 17 | const networkIDMainnet = 0; 18 | const networkIDRollup = 1; 19 | 20 | async function main() { 21 | const claimAddress = '0xc949254d682d8c9ad5682521675b8f43b102aec4'; 22 | 23 | // Add a claim leaf to rollup exit tree 24 | const originNetwork = networkIDMainnet; 25 | const tokenAddress = ethers.constants.AddressZero; // ether 26 | const amount = ethers.utils.parseEther('10'); 27 | const destinationNetwork = networkIDRollup; 28 | const destinationAddress = claimAddress; 29 | 30 | const metadata = '0x';// since is ether does not have metadata 31 | const metadataHash = ethers.utils.solidityKeccak256(['bytes'], [metadata]); 32 | 33 | // pre compute root merkle tree in Js 34 | const height = 32; 35 | const merkleTree = new MerkleTreeBridge(height); 36 | const leafValue = getLeafValue( 37 | Constants.BRIDGE_LEAF_TYPE_ASSET, 38 | originNetwork, 39 | tokenAddress, 40 | destinationNetwork, 41 | destinationAddress, 42 | amount, 43 | metadataHash, 44 | ); 45 | merkleTree.add(leafValue); 46 | 47 | const rootJSMainnet = merkleTree.getRoot(); 48 | const rollupExitRoot = ethers.constants.HashZero; 49 | 50 | const globalExitRoot = calculateGlobalExitRoot(rootJSMainnet, rollupExitRoot); 51 | const index = 0; 52 | const proof = merkleTree.getProofTreeByIndex(index); 53 | 54 | const output = { 55 | claimCallData: { 56 | proof, 57 | index, 58 | rootJSMainnet, 59 | rollupExitRoot, 60 | originNetwork, 61 | tokenAddress, 62 | destinationNetwork, 63 | destinationAddress, 64 | amount, 65 | metadata, 66 | }, 67 | globalExitRoot, 68 | }; 69 | console.log(verifyMerkleProof(leafValue, proof, index, rootJSMainnet)); 70 | console.log(output); 71 | } 72 | /* 73 | * We recommend this pattern to be able to use async/await everywhere 74 | * and properly handle errors. 75 | */ 76 | main() 77 | .then(() => process.exit(0)) 78 | .catch((error) => { 79 | console.error(error); 80 | process.exit(1); 81 | }); 82 | -------------------------------------------------------------------------------- /tools/generate-l1-info-tree-proofs/.gitignore: -------------------------------------------------------------------------------- 1 | generator.json 2 | smt-output-*.json -------------------------------------------------------------------------------- /tools/generate-l1-info-tree-proofs/README.md: -------------------------------------------------------------------------------- 1 | # Tool to compute L1InfoTree smtProofs 2 | - All commands are executed in the tool folder `./tools/generate-l1-info-tree-proofs` 3 | 4 | ## Setup generator 5 | - copy `generator.example.json` to `generator.json` 6 | ``` 7 | cp generator.example.json generator.json 8 | ``` 9 | - Fill in all the smt leafs to build the smt 10 | 11 | ## Output 12 | - add flag `--output` 13 | - Script generates an output with the following name: `smt-output-${timestamp}.json` which contains 14 | - array of leafs sorted by its index 15 | - leaf data 16 | - value data 17 | - smtProof -------------------------------------------------------------------------------- /tools/generate-l1-info-tree-proofs/gen-l1-info-tree-smt.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | /* eslint-disable no-console */ 3 | const { expect } = require('chai'); 4 | const fs = require('fs'); 5 | const { argv } = require('yargs'); 6 | const { Constants } = require('../../index'); 7 | 8 | const MerkleTreeBridge = require('../../index').MTBridge; 9 | const { verifyMerkleProof } = require('../../index').mtBridgeUtils; 10 | const { getL1InfoTreeValue } = require('../../index').l1InfoTreeUtils; 11 | 12 | async function main() { 13 | // read gen file 14 | const genFile = JSON.parse(fs.readFileSync('generator.json')); 15 | 16 | // Compute leafs value and add it to the tree 17 | const height = 32; 18 | const merkleTree = new MerkleTreeBridge(height); 19 | const leafs = []; 20 | 21 | for (let i = 0; i < genFile.leafs.length; i++) { 22 | const leafValue = getL1InfoTreeValue( 23 | genFile.leafs[i].globalExitRoot, 24 | genFile.leafs[i].blockHash, 25 | genFile.leafs[i].timestamp, 26 | ); 27 | leafs.push(leafValue); 28 | merkleTree.add(leafValue); 29 | } 30 | 31 | // compute root and proofs 32 | const root = merkleTree.getRoot(); 33 | 34 | // generate proofs for all indexes 35 | const proofs = []; 36 | for (let i = 0; i < genFile.leafs.length; i++) { 37 | proofs.push(merkleTree.getProofTreeByIndex(i)); 38 | } 39 | 40 | // verify proofs 41 | for (let i = 0; i < genFile.length; i++) { 42 | const proof = proofs[i]; 43 | const index = i; 44 | const valueLeaf = leafs[index]; 45 | expect(verifyMerkleProof(valueLeaf, proof, index, root)).to.be.equal(true); 46 | } 47 | 48 | // create output json file with gen info plus value leafs and proofs 49 | const output = []; 50 | for (let i = 0; i < genFile.leafs.length; i++) { 51 | const smtProof = proofs[i]; 52 | const index = i; 53 | const valueLeaf = leafs[index]; 54 | output.push({ 55 | ...genFile.leafs[i], 56 | l1InfoRoot: root, 57 | valueLeaf, 58 | index, 59 | smtProof, 60 | }); 61 | } 62 | 63 | // generate proofs for extra indexes 64 | for (let i = 0; i < genFile.extraMTProofs.length; i++) { 65 | const indexToGetProof = genFile.extraMTProofs[i]; 66 | const proof = merkleTree.getProofTreeByIndex(indexToGetProof); 67 | 68 | if (indexToGetProof > genFile.leafs.length - 1) { 69 | output.push({ 70 | globalExitRoot: Constants.ZERO_BYTES32, 71 | blockHash: Constants.ZERO_BYTES32, 72 | timestamp: 0, 73 | l1InfoRoot: root, 74 | valueLeaf: Constants.ZERO_BYTES32, 75 | index: indexToGetProof, 76 | smtProof: proof, 77 | }); 78 | 79 | expect(verifyMerkleProof(Constants.ZERO_BYTES32, proof, indexToGetProof, root)).to.be.equal(true); 80 | } 81 | } 82 | 83 | // save outout file depending on flag by argv --output and the timestamp 84 | const timestamp = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''); 85 | 86 | if (argv.output !== undefined) { 87 | fs.writeFileSync(`smt-output-${timestamp}.json`, JSON.stringify(output, null, 2)); 88 | } 89 | 90 | // print output in console 91 | console.log(JSON.stringify(output, null, 2)); 92 | } 93 | /* 94 | * We recommend this pattern to be able to use async/await everywhere 95 | * and properly handle errors. 96 | */ 97 | main() 98 | .then(() => process.exit(0)) 99 | .catch((error) => { 100 | console.error(error); 101 | process.exit(1); 102 | }); 103 | -------------------------------------------------------------------------------- /tools/generate-l1-info-tree-proofs/generator.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "leafs": [ 3 | { 4 | "globalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", 5 | "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 6 | "timestamp": "0" 7 | }, 8 | { 9 | "globalExitRoot": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 10 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 11 | "timestamp": "42" 12 | }, 13 | { 14 | "globalExitRoot": "0x16994edfddddb9480667b64174fc00d3b6da7290d37b8db3a16571b4ddf0789f", 15 | "blockHash": "0x24a5871d68723340d9eadc674aa8ad75f3e33b61d5a9db7db92af856a19270bb", 16 | "timestamp": "42" 17 | } 18 | ], 19 | "extraMTProofs": [7] 20 | } -------------------------------------------------------------------------------- /tools/update-tests/update-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # block-info 4 | # processor 5 | # zkevmDb 6 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 7 | 8 | # set path script 9 | cd $SCRIPT_DIR 10 | # set path repository 11 | cd ../.. 12 | 13 | # run uddate tests 14 | npx mocha ./test/smt-utils.test.js --update 15 | npx mocha ./test/smt-full-genesis.test.js --update 16 | npx mocha ./test/smt-genesis.test.js --update 17 | 18 | npx mocha ./test/block-info.test.js --update 19 | npx mocha ./test/processor.test.js --update 20 | npx mocha ./test/processor.test.js --update --e2e --geninput 21 | npx mocha ./test/processor.test.js --update --blockinfo --geninput 22 | npx mocha ./test/processor.test.js --update --selfdestruct --geninput 23 | npx mocha ./test/processor.test.js --update --etrog --geninput 24 | npx mocha ./test/zkevm-db.test.js --update --------------------------------------------------------------------------------