├── .gitignore ├── MiMCSponge.easm ├── README.md ├── StoreZerosToCode.easm ├── contracts ├── MerkleTreeWithHistoryV1.yul ├── MerkleTreeWithHistoryV2.yul ├── MerkleTreeWithHistoryV3.yul └── MerkleTreeWithHistoryYul.yul ├── generate_mimchasher_contract.py ├── hardhat.config.js ├── package.json ├── remix ├── MerkleTreeWithHistoryV1.json ├── MerkleTreeWithHistoryV2.json └── MerkleTreeWithHistoryV3.json ├── requirements.txt ├── rounds.easm ├── scripts ├── evmasm.js ├── hardhat.tasks.js ├── hardhat.utils.js └── mimcsponge_gencontract.js └── test ├── MerkleTree.test.js └── MiMCSponge.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | build 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiMCSponge in Solidity 2 | In an effort to reduce the gas cost of the TornadoCash MerkleTreeWithHistory contract, I set out to include the MiMCSponge hasher contract directly into the MerkleTreeWithHistory contract (this was a [recommendation](https://tornado.cash/audits/TornadoCash_contract_audit_ABDK.pdf) that ABDK consulting made in their audit of the TornadoCash contracts). After extensive testing, this is the final version. 3 | 4 | # Install and Test 5 | 6 | 1. Simply clone the repo and then run `yarn` or `npm install .` in the root directory. 7 | 2. Run `npx hardhat test` from the root directory. 8 | 9 | 10 | # Final Results 11 | The results of the unit tests are below. I removed some old contracts, but the previous results can be found in older commits. Noteably, the recommendation that [Hari](https://twitter.com/_hrkrshnn) made to me was to change from the switch/case expression to `CODECOPY` instead, which reduced the gas cost a further 5k gas. In total, this is about 15k gas savings compared to the original contract! 12 | ```sh 13 | MerkleTrees 14 | ✓ MerkleTreeWithHistoryV1.yul::initialize should work (91ms) 15 | final gas used: 904133 16 | ✓ MerkleTreeWithHistoryV1.yul::insert should work (1001ms) 17 | final gas used: 899793 18 | ✓ MerkleTreeWithHistoryV3.yul::insert should work (846ms) 19 | ✓ Both implementations should share the same last root 20 | 21 | MiMCSponge 22 | ✓ MiMCHasherCircomlib should match js implementation 23 | ✓ MerkleTreeWithHistory.yul::MiMCSponge should match js implementation 24 | ✓ MerkleTreeWithHistoryV2.yul::MiMCSponge should match js implementation 25 | Circomlibjs::MiMCSponge gas estimate: 38804 26 | MerkleTreeWithHistory.yul::MiMCSponge gas estimate: 39142 relative to circomlib: 1.0087104422224513 27 | MerkleTreeWithHistoryV2.yul::MiMCSponge gas estimate: 39040 relative to circomlib: 1.0060818472322441 28 | ``` 29 | -------------------------------------------------------------------------------- /StoreZerosToCode.easm: -------------------------------------------------------------------------------- 1 | ;; constructor that stores zeros in code, to be retrieved in the merkle tree 2 | ;; in place of a `switch...case...` block 3 | 4 | PUSH 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c 5 | ;; RDS is cheaper than PUSH 0 by 1 gas! 6 | RETURNDATASIZE 7 | MSTORE 8 | PUSH 0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d 9 | PUSH 0x20 10 | MSTORE 11 | PUSH 0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200 12 | PUSH 0x40 13 | MSTORE 14 | PUSH 0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb 15 | PUSH 0x60 16 | MSTORE 17 | PUSH 0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9 18 | PUSH 0x80 19 | MSTORE 20 | PUSH 0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959 21 | PUSH 0xa0 22 | MSTORE 23 | PUSH 0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c 24 | PUSH 0xc0 25 | MSTORE 26 | PUSH 0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4 27 | PUSH 0xe0 28 | MSTORE 29 | PUSH 0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80 30 | PUSH 0x100 31 | MSTORE 32 | PUSH 0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007 33 | PUSH 0x120 34 | MSTORE 35 | PUSH 0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30 36 | PUSH 0x140 37 | MSTORE 38 | PUSH 0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5 39 | PUSH 0x160 40 | MSTORE 41 | PUSH 0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f 42 | PUSH 0x180 43 | MSTORE 44 | PUSH 0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd 45 | PUSH 0x1a0 46 | MSTORE 47 | PUSH 0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108 48 | PUSH 0x1c0 49 | MSTORE 50 | PUSH 0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6 51 | PUSH 0x1e0 52 | MSTORE 53 | PUSH 0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854 54 | PUSH 0x200 55 | MSTORE 56 | PUSH 0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea 57 | PUSH 0x220 58 | MSTORE 59 | PUSH 0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d 60 | PUSH 0x240 61 | MSTORE 62 | PUSH 0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05 63 | PUSH 0x260 64 | MSTORE 65 | PUSH 0x29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d4 66 | PUSH 0x280 67 | MSTORE 68 | PUSH 0x19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b2967 69 | PUSH 0x2a0 70 | MSTORE 71 | PUSH 0x1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc3453 72 | PUSH 0x2c0 73 | MSTORE 74 | PUSH 0x10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c48 75 | PUSH 0x2e0 76 | MSTORE 77 | PUSH 0x0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1 78 | PUSH 0x300 79 | MSTORE 80 | PUSH 0x019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c 81 | PUSH 0x320 82 | MSTORE 83 | PUSH 0x2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce99 84 | PUSH 0x340 85 | MSTORE 86 | PUSH 0x2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354 87 | PUSH 0x360 88 | MSTORE 89 | PUSH 0x002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d 90 | PUSH 0x380 91 | MSTORE 92 | PUSH 0x104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f427 93 | PUSH 0x3a0 94 | MSTORE 95 | PUSH 0x1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb 96 | PUSH 0x3c0 97 | MSTORE 98 | PUSH 0x2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc 99 | PUSH 0x3e0 100 | MSTORE 101 | PUSH 0x400 102 | PUSH 0 103 | RETURN 104 | -------------------------------------------------------------------------------- /contracts/MerkleTreeWithHistoryV1.yul: -------------------------------------------------------------------------------- 1 | object "MerkleTreeWithHistoryV1" { 2 | code { 3 | datacopy(0, dataoffset("runtime"), datasize("runtime")) 4 | return(0, datasize("runtime")) 5 | } 6 | object "runtime" { 7 | code { 8 | /* ---------- call routing ---------- */ 9 | switch selector() 10 | case 0x2d287e43 /* insert(bytes32) */ { 11 | returnUint(insert(decodeAsUint(0))) 12 | } 13 | case 0x8d8965bd /* initialize(uint32) */ { 14 | initialize(decodeAsUint(0)) 15 | } 16 | case 0xf47d33b5 /* MiMCSponge(uint256,uint256) */ { 17 | let xL, xR := mimcSponge(decodeAsUint(0), decodeAsUint(1)) 18 | returnTwoUints(xL, xR) 19 | } 20 | case 0x6d9833e3 /* isKnownRoot(bytes32) */ { 21 | returnUint(isKnownRoot(decodeAsUint(0))) 22 | } 23 | case 0xba70f757 /* getLastRoot() */ { 24 | returnUint(getLastRoot()) 25 | } 26 | case 0xe8295588 /* zeros(uint256) */ { 27 | returnUint(zeros(decodeAsUint(0))) 28 | } 29 | 30 | /* ---------- main functions ---------- */ 31 | function insert(leaf) -> leafIndex { 32 | let _levels := levels() 33 | let _nextIndex := nextIndex() 34 | if eq(_nextIndex, exp(2, _levels)) { 35 | revert(0, 0) 36 | } 37 | let currentIndex := _nextIndex 38 | let currentLevelHash := leaf 39 | let left := 0 40 | let right := 0 41 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } { 42 | let condition := mod(currentIndex, 2) 43 | if iszero(condition) { 44 | left := currentLevelHash 45 | right := zeros(i) 46 | setFilledSubtrees(i, currentLevelHash) 47 | } 48 | if condition { 49 | left := filledSubtrees(i) 50 | right := currentLevelHash 51 | } 52 | if iszero(lt(left, FIELD_SIZE())) { 53 | revert(0, 0) 54 | } 55 | if iszero(lt(right, FIELD_SIZE())) { 56 | revert(0, 0) 57 | } 58 | let R := left 59 | let C := 0 60 | R, C := mimcSponge(R, C) 61 | R := addmod(R, right, FIELD_SIZE()) 62 | R, C := mimcSponge(R, C) 63 | currentLevelHash := R 64 | currentIndex := div(currentIndex, 2) 65 | } 66 | let newRootIndex := addmod(currentRootIndex(), 1, ROOT_HISTORY_SIZE()) 67 | setCurrentRootIndex(newRootIndex) 68 | setRoots(newRootIndex, currentLevelHash) 69 | setNextIndex(add(_nextIndex, 1)) 70 | leafIndex := _nextIndex 71 | } 72 | 73 | function initialize(_levels) { 74 | if isInitialized() { revert(0, 0) } 75 | if iszero(_levels) { revert(0, 0) } 76 | if gt(_levels, 32) { revert(0, 0) } 77 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } 78 | { 79 | setFilledSubtrees(i, zeros(i)) 80 | } 81 | setLevels(_levels) 82 | setRoots(0, zeros(sub(_levels, 1))) 83 | setIsInitialized() 84 | } 85 | 86 | function isKnownRoot(root) -> isKnown { 87 | if iszero(root) { isKnown := false } 88 | 89 | let _currentRootIndex := currentRootIndex() 90 | if eq(root, roots(_currentRootIndex)) { isKnown := true } 91 | 92 | for 93 | { let i := sub(_currentRootIndex, 1) } 94 | iszero(eq(i, _currentRootIndex)) 95 | { i := sub(i, 1) } 96 | { 97 | if eq(root, roots(i)) { isKnown := 1 } 98 | if iszero(i) { i := ROOT_HISTORY_SIZE() } 99 | } 100 | isKnown := false 101 | } 102 | 103 | function getLastRoot() -> v { 104 | v := roots(currentRootIndex()) 105 | } 106 | 107 | /* ---------- constants ---------- */ 108 | function FIELD_SIZE() -> fs { fs := 21888242871839275222246405745257275088548364400416034343698204186575808495617 } 109 | function ZERO_VALUE() -> zv { zv := 21663839004416932945382355908790599225266501822907911457504978515578255421292 } 110 | function ROOT_HISTORY_SIZE() -> rhs { rhs := 30 } 111 | 112 | /* ---------- calldata encoding/decoding ---------- */ 113 | function selector() -> s { 114 | s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) 115 | } 116 | 117 | function decodeAsUint(offset) -> v { 118 | let pos := add(4, mul(offset, 0x20)) 119 | if lt(calldatasize(), add(pos, 0x20)) { 120 | revert(0, 0) 121 | } 122 | v := calldataload(pos) 123 | } 124 | 125 | function returnUint(v) { 126 | mstore(0, v) 127 | return(0, 0x20) 128 | } 129 | 130 | function returnTwoUints(u, v) { 131 | mstore(0, u) 132 | mstore(0x20, v) 133 | return(0, 0x40) 134 | } 135 | 136 | /* ---------- storage reads ---------- */ 137 | function levels() -> v { 138 | v := sload(levelsPos()) 139 | } 140 | 141 | function currentRootIndex() -> v { 142 | v := sload(currentRootIndexPos()) 143 | } 144 | 145 | function nextIndex() -> v { 146 | v := sload(nextIndexPos()) 147 | } 148 | 149 | function filledSubtrees(i) -> v { 150 | v := sload(filledSubtreesOffset(i)) 151 | } 152 | 153 | function roots(i) -> v { 154 | v := sload(rootsOffset(i)) 155 | } 156 | 157 | function isInitialized() -> v { 158 | v := sload(isInitializedPos()) 159 | } 160 | 161 | /* ---------- storage writes ---------- */ 162 | function setLevels(_levels) { 163 | sstore(levelsPos(), _levels) 164 | } 165 | 166 | function setCurrentRootIndex(_currentRootIndex) { 167 | sstore(currentRootIndexPos(), _currentRootIndex) 168 | } 169 | 170 | function setNextIndex(_nextIndex) { 171 | sstore(nextIndexPos(), _nextIndex) 172 | } 173 | 174 | function setFilledSubtrees(i, _filledSubtree) { 175 | sstore(filledSubtreesOffset(i), _filledSubtree) 176 | } 177 | 178 | function setRoots(i, _root) { 179 | sstore(rootsOffset(i), _root) 180 | } 181 | 182 | function setIsInitialized() { 183 | sstore(isInitializedPos(), 1) 184 | } 185 | 186 | /* ---------- storage layout ---------- */ 187 | /* 188 | Because this is meant to be consumed as a library, we must not 189 | modify any of the storage slots that would normally be used as 190 | a result of compiling via solidity. The twister contract will be 191 | `delegatecall`ing into this contract, and will modify its own 192 | state based upon the logic here. By using the hash of the 193 | contract name + variable name, we prevent storage collisions. 194 | */ 195 | function levelsPos() -> p { 196 | /* keccak256("MerkleTreeWithHistory.levels") */ 197 | p := 0xde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc 198 | } 199 | 200 | function currentRootIndexPos() -> p { 201 | /* keccak256("MerkleTreeWithHistory.currentRootIndex") */ 202 | p := 0x00ff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e 203 | } 204 | 205 | function nextIndexPos() -> p { 206 | /* keccak256("MerkleTreeWithHistory.nextIndex") */ 207 | p := 0xd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f 208 | } 209 | 210 | function isInitializedPos() -> p { 211 | /* keccak256("MerkleTreeWithHistory.isInitialized") */ 212 | p := 0x00d99680f702d11a0e37c0a04b851248ea5095ce648b7ecc393538c9b29df295 213 | } 214 | 215 | function filledSubtreesOffset(i) -> offset { 216 | /* keccak256(keccak256("MerkleTreeWithHistory.filledSubtrees"), i) */ 217 | mstore(0, 0xb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd14) 218 | mstore(0x20, i) 219 | offset := keccak256(0, 0x40) 220 | } 221 | 222 | function rootsOffset(i) -> offset { 223 | /* keccak256(keccak256("MerkleTreeWithHistory.roots"), i) */ 224 | mstore(0, 0x3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870) 225 | mstore(0x20, i) 226 | offset := keccak256(0, 0x40) 227 | } 228 | 229 | /* ---------- utility functions ---------- */ 230 | function zeros(i) -> z { 231 | switch i 232 | case 0 { z := 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c } 233 | case 1 { z := 0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d } 234 | case 2 { z := 0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200 } 235 | case 3 { z := 0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb } 236 | case 4 { z := 0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9 } 237 | case 5 { z := 0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959 } 238 | case 6 { z := 0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c } 239 | case 7 { z := 0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4 } 240 | case 8 { z := 0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80 } 241 | case 9 { z := 0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007 } 242 | case 10 { z := 0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30 } 243 | case 11 { z := 0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5 } 244 | case 12 { z := 0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f } 245 | case 13 { z := 0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd } 246 | case 14 { z := 0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108 } 247 | case 15 { z := 0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6 } 248 | case 16 { z := 0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854 } 249 | case 17 { z := 0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea } 250 | case 18 { z := 0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d } 251 | case 19 { z := 0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05 } 252 | case 20 { z := 0x29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d4 } 253 | case 21 { z := 0x19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b2967 } 254 | case 22 { z := 0x1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc3453 } 255 | case 23 { z := 0x10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c48 } 256 | case 24 { z := 0x0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1 } 257 | case 25 { z := 0x019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c } 258 | case 26 { z := 0x2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce99 } 259 | case 27 { z := 0x2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354 } 260 | case 28 { z := 0x002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d } 261 | case 29 { z := 0x104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f427 } 262 | case 30 { z := 0x1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb } 263 | case 31 { z := 0x2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc } 264 | } 265 | 266 | /* 267 | verbatim_Xi_Yo allows us to define an `opcode` in pure bytecode. 268 | In this case, I adapted the mimcsponge contract provided by 269 | circomlib to be a stack-based function: it takes two arguments 270 | from the stack, and returns two arguments to the stack. The 271 | original code from circomlib left a value on the stack, but this 272 | version is stack neutral. I compiled this code using geth. 273 | */ 274 | function mimcSponge(in_xL, in_xR) -> xL, xR { 275 | xL, xR := verbatim_2i_2o(hex"7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150", in_xL, in_xR) 276 | } 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /contracts/MerkleTreeWithHistoryV2.yul: -------------------------------------------------------------------------------- 1 | object "MerkleTreeWithHistory" { 2 | code { 3 | datacopy(0, dataoffset("runtime"), datasize("runtime")) 4 | return(0, datasize("runtime")) 5 | } 6 | object "runtime" { 7 | code { 8 | /* ---------- call routing ---------- */ 9 | switch selector() 10 | case 0x2d287e43 /* insert(bytes32) */ { 11 | returnUint(insert(decodeAsUint(0))) 12 | } 13 | case 0x8d8965bd /* initialize(uint32) */ { 14 | initialize(decodeAsUint(0)) 15 | } 16 | case 0xf47d33b5 /* MiMCSponge(uint256,uint256) */ { 17 | let xL, xR := mimcSponge(decodeAsUint(0), decodeAsUint(1)) 18 | returnTwoUints(xL, xR) 19 | } 20 | case 0x6d9833e3 /* isKnownRoot(bytes32) */ { 21 | returnUint(isKnownRoot(decodeAsUint(0))) 22 | } 23 | case 0xba70f757 /* getLastRoot() */ { 24 | returnUint(getLastRoot()) 25 | } 26 | case 0xe8295588 /* zeros(uint256) */ { 27 | returnUint(zeros(decodeAsUint(0))) 28 | } 29 | 30 | /* ---------- main functions ---------- */ 31 | function insert(leaf) -> leafIndex { 32 | let _levels := levels() 33 | let _nextIndex := nextIndex() 34 | if eq(_nextIndex, exp(2, _levels)) { 35 | revert(0, 0) 36 | } 37 | let currentIndex := _nextIndex 38 | let currentLevelHash := leaf 39 | let left := 0 40 | let right := 0 41 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } { 42 | let condition := mod(currentIndex, 2) 43 | if iszero(condition) { 44 | left := currentLevelHash 45 | right := zeros(i) 46 | setFilledSubtrees(i, currentLevelHash) 47 | } 48 | if condition { 49 | left := filledSubtrees(i) 50 | right := currentLevelHash 51 | } 52 | if iszero(lt(left, FIELD_SIZE())) { 53 | revert(0, 0) 54 | } 55 | if iszero(lt(right, FIELD_SIZE())) { 56 | revert(0, 0) 57 | } 58 | let R := left 59 | let C := 0 60 | R, C := mimcSponge(R, C) 61 | R := addmod(R, right, FIELD_SIZE()) 62 | R, C := mimcSponge(R, C) 63 | currentLevelHash := R 64 | currentIndex := div(currentIndex, 2) 65 | } 66 | let newRootIndex := addmod(currentRootIndex(), 1, ROOT_HISTORY_SIZE()) 67 | setCurrentRootIndex(newRootIndex) 68 | setRoots(newRootIndex, currentLevelHash) 69 | setNextIndex(add(_nextIndex, 1)) 70 | leafIndex := _nextIndex 71 | } 72 | 73 | function initialize(_levels) { 74 | mstore(0, 0xbad) 75 | log1(0, 0x20, 0xaeaeaeae) 76 | if isInitialized() { revert(0, 0) } 77 | if iszero(_levels) { revert(0, 0) } 78 | if gt(_levels, 32) { revert(0, 0) } 79 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } 80 | { 81 | setFilledSubtrees(i, zeros(i)) 82 | } 83 | setLevels(_levels) 84 | setRoots(0, zeros(sub(_levels, 1))) 85 | setIsInitialized() 86 | } 87 | 88 | function isKnownRoot(root) -> isKnown { 89 | if iszero(root) { isKnown := false } 90 | 91 | let _currentRootIndex := currentRootIndex() 92 | if eq(root, roots(_currentRootIndex)) { isKnown := true } 93 | 94 | for 95 | { let i := sub(_currentRootIndex, 1) } 96 | iszero(eq(i, _currentRootIndex)) 97 | { i := sub(i, 1) } 98 | { 99 | if eq(root, roots(i)) { isKnown := 1 } 100 | if iszero(i) { i := ROOT_HISTORY_SIZE() } 101 | } 102 | isKnown := false 103 | } 104 | 105 | function getLastRoot() -> v { 106 | v := roots(currentRootIndex()) 107 | } 108 | 109 | /* ---------- constants ---------- */ 110 | function FIELD_SIZE() -> fs { fs := 21888242871839275222246405745257275088548364400416034343698204186575808495617 } 111 | function ZERO_VALUE() -> zv { zv := 21663839004416932945382355908790599225266501822907911457504978515578255421292 } 112 | function ROOT_HISTORY_SIZE() -> rhs { rhs := 30 } 113 | 114 | /* ---------- calldata encoding/decoding ---------- */ 115 | function selector() -> s { 116 | s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) 117 | } 118 | 119 | function decodeAsUint(offset) -> v { 120 | let pos := add(4, mul(offset, 0x20)) 121 | if lt(calldatasize(), add(pos, 0x20)) { 122 | revert(0, 0) 123 | } 124 | v := calldataload(pos) 125 | } 126 | 127 | function returnUint(v) { 128 | mstore(0, v) 129 | return(0, 0x20) 130 | } 131 | 132 | function returnTwoUints(u, v) { 133 | mstore(0, u) 134 | mstore(0x20, v) 135 | return(0, 0x40) 136 | } 137 | 138 | /* ---------- storage reads ---------- */ 139 | function levels() -> v { 140 | v := sload(levelsPos()) 141 | } 142 | 143 | function currentRootIndex() -> v { 144 | v := sload(currentRootIndexPos()) 145 | } 146 | 147 | function nextIndex() -> v { 148 | v := sload(nextIndexPos()) 149 | } 150 | 151 | function filledSubtrees(i) -> v { 152 | v := sload(filledSubtreesOffset(i)) 153 | } 154 | 155 | function roots(i) -> v { 156 | v := sload(rootsOffset(i)) 157 | } 158 | 159 | function isInitialized() -> v { 160 | v := sload(isInitializedPos()) 161 | } 162 | 163 | /* ---------- storage writes ---------- */ 164 | function setLevels(_levels) { 165 | sstore(levelsPos(), _levels) 166 | } 167 | 168 | function setCurrentRootIndex(_currentRootIndex) { 169 | sstore(currentRootIndexPos(), _currentRootIndex) 170 | } 171 | 172 | function setNextIndex(_nextIndex) { 173 | sstore(nextIndexPos(), _nextIndex) 174 | } 175 | 176 | function setFilledSubtrees(i, _filledSubtree) { 177 | sstore(filledSubtreesOffset(i), _filledSubtree) 178 | } 179 | 180 | function setRoots(i, _root) { 181 | sstore(rootsOffset(i), _root) 182 | } 183 | 184 | function setIsInitialized() { 185 | sstore(isInitializedPos(), 1) 186 | } 187 | 188 | /* ---------- storage layout ---------- */ 189 | /* 190 | Because this is meant to be consumed as a library, we must not 191 | modify any of the storage slots that would normally be used as 192 | a result of compiling via solidity. The twister contract will be 193 | `delegatecall`ing into this contract, and will modify its own 194 | state based upon the logic here. By using the hash of the 195 | contract name + variable name, we prevent storage collisions. 196 | */ 197 | function levelsPos() -> p { 198 | /* keccak256("MerkleTreeWithHistory.levels") */ 199 | p := 0xde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc 200 | } 201 | 202 | function currentRootIndexPos() -> p { 203 | /* keccak256("MerkleTreeWithHistory.currentRootIndex") */ 204 | p := 0x00ff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e 205 | } 206 | 207 | function nextIndexPos() -> p { 208 | /* keccak256("MerkleTreeWithHistory.nextIndex") */ 209 | p := 0xd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f 210 | } 211 | 212 | function isInitializedPos() -> p { 213 | /* keccak256("MerkleTreeWithHistory.isInitialized") */ 214 | p := 0x00d99680f702d11a0e37c0a04b851248ea5095ce648b7ecc393538c9b29df295 215 | } 216 | 217 | function filledSubtreesOffset(i) -> offset { 218 | /* keccak256(keccak256("MerkleTreeWithHistory.filledSubtrees"), i) */ 219 | mstore(0, 0xb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd14) 220 | mstore(0x20, i) 221 | offset := keccak256(0, 0x40) 222 | } 223 | 224 | function rootsOffset(i) -> offset { 225 | /* keccak256(keccak256("MerkleTreeWithHistory.roots"), i) */ 226 | mstore(0, 0x3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870) 227 | mstore(0x20, i) 228 | offset := keccak256(0, 0x40) 229 | } 230 | 231 | /* ---------- utility functions ---------- */ 232 | function zeros(i) -> z { 233 | datacopy(0, add(dataoffset("zeros"), mul(i, 0x20)), 0x20) 234 | z := mload(0) 235 | } 236 | 237 | 238 | /* 239 | verbatim_Xi_Yo allows us to define an `opcode` in pure bytecode. 240 | In this case, I adapted the mimcsponge contract provided by 241 | circomlib to be a stack-based function: it takes two arguments 242 | from the stack, and returns two arguments to the stack. The 243 | original code from circomlib left a value on the stack, but this 244 | version is stack neutral. I compiled this code using geth. 245 | */ 246 | function mimcSponge(in_xL, in_xR) -> xL, xR { 247 | xL, xR := verbatim_2i_2o(hex"7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150", in_xL, in_xR) 248 | } 249 | } 250 | data "zeros" hex"2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c20020121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c924ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb549591ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff800058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c0071f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e301bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e50ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb10813e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b61eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db618540da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc0529d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d419be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b29671ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc345310c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c480ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce992eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f4271f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc" 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /contracts/MerkleTreeWithHistoryV3.yul: -------------------------------------------------------------------------------- 1 | object "MerkleTreeWithHistoryV3" { 2 | code { 3 | setLevels(20) 4 | setFilledSubtrees(0, 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c) 5 | setFilledSubtrees(1, 0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d) 6 | setFilledSubtrees(2, 0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200) 7 | setFilledSubtrees(3, 0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb) 8 | setFilledSubtrees(4, 0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9) 9 | setFilledSubtrees(5, 0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959) 10 | setFilledSubtrees(6, 0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c) 11 | setFilledSubtrees(7, 0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4) 12 | setFilledSubtrees(8, 0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80) 13 | setFilledSubtrees(9, 0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007) 14 | setFilledSubtrees(10, 0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30) 15 | setFilledSubtrees(11, 0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5) 16 | setFilledSubtrees(12, 0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f) 17 | setFilledSubtrees(13, 0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd) 18 | setFilledSubtrees(14, 0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108) 19 | setFilledSubtrees(15, 0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6) 20 | setFilledSubtrees(16, 0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854) 21 | setFilledSubtrees(17, 0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea) 22 | setFilledSubtrees(18, 0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d) 23 | setFilledSubtrees(19, 0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05) 24 | setRoots(0, 0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05) 25 | 26 | datacopy(0, dataoffset("runtime"), datasize("runtime")) 27 | return(0, datasize("runtime")) 28 | 29 | function setLevels(_levels) { 30 | sstore(levelsPos(), _levels) 31 | } 32 | 33 | function setFilledSubtrees(i, _filledSubtree) { 34 | sstore(filledSubtreesOffset(i), _filledSubtree) 35 | } 36 | 37 | function setRoots(i, _root) { 38 | sstore(rootsOffset(i), _root) 39 | } 40 | 41 | function levelsPos() -> p { 42 | /* keccak256("MerkleTreeWithHistory.levels") */ 43 | p := 0xde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc 44 | } 45 | 46 | function filledSubtreesOffset(i) -> offset { 47 | /* keccak256(keccak256("MerkleTreeWithHistory.filledSubtrees"), i) */ 48 | mstore(0, 0xb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd14) 49 | mstore(0x20, i) 50 | offset := keccak256(0, 0x40) 51 | } 52 | 53 | function rootsOffset(i) -> offset { 54 | /* keccak256(keccak256("MerkleTreeWithHistory.roots"), i) */ 55 | mstore(0, 0x3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870) 56 | mstore(0x20, i) 57 | offset := keccak256(0, 0x40) 58 | } 59 | } 60 | object "runtime" { 61 | code { 62 | /* ---------- call routing ---------- */ 63 | switch selector() 64 | case 0x2d287e43 /* insert(bytes32) */ { 65 | returnUint(insert(decodeAsUint(0))) 66 | } 67 | case 0xf47d33b5 /* MiMCSponge(uint256,uint256) */ { 68 | let xL, xR := mimcSponge(decodeAsUint(0), decodeAsUint(1)) 69 | returnTwoUints(xL, xR) 70 | } 71 | case 0x6d9833e3 /* isKnownRoot(bytes32) */ { 72 | returnUint(isKnownRoot(decodeAsUint(0))) 73 | } 74 | case 0xba70f757 /* getLastRoot() */ { 75 | returnUint(getLastRoot()) 76 | } 77 | case 0xe8295588 /* zeros(uint256) */ { 78 | returnUint(zeros(decodeAsUint(0))) 79 | } 80 | 81 | /* ---------- main functions ---------- */ 82 | function insert(leaf) -> leafIndex { 83 | let _levels := levels() 84 | let _nextIndex := nextIndex() 85 | if eq(_nextIndex, exp(2, _levels)) { 86 | revert(0, 0) 87 | } 88 | let currentIndex := _nextIndex 89 | let currentLevelHash := leaf 90 | let left := 0 91 | let right := 0 92 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } { 93 | let condition := mod(currentIndex, 2) 94 | if iszero(condition) { 95 | left := currentLevelHash 96 | right := zeros(i) 97 | setFilledSubtrees(i, currentLevelHash) 98 | } 99 | if condition { 100 | left := filledSubtrees(i) 101 | right := currentLevelHash 102 | } 103 | if iszero(lt(left, FIELD_SIZE())) { 104 | revert(0, 0) 105 | } 106 | if iszero(lt(right, FIELD_SIZE())) { 107 | revert(0, 0) 108 | } 109 | let R := left 110 | let C := 0 111 | R, C := mimcSponge(R, C) 112 | R := addmod(R, right, FIELD_SIZE()) 113 | R, C := mimcSponge(R, C) 114 | currentLevelHash := R 115 | currentIndex := div(currentIndex, 2) 116 | } 117 | let newRootIndex := addmod(currentRootIndex(), 1, ROOT_HISTORY_SIZE()) 118 | setCurrentRootIndex(newRootIndex) 119 | setRoots(newRootIndex, currentLevelHash) 120 | setNextIndex(add(_nextIndex, 1)) 121 | leafIndex := _nextIndex 122 | } 123 | 124 | function isKnownRoot(root) -> isKnown { 125 | if iszero(root) { isKnown := false } 126 | 127 | let _currentRootIndex := currentRootIndex() 128 | if eq(root, roots(_currentRootIndex)) { isKnown := true } 129 | 130 | for 131 | { let i := sub(_currentRootIndex, 1) } 132 | iszero(eq(i, _currentRootIndex)) 133 | { i := sub(i, 1) } 134 | { 135 | if eq(root, roots(i)) { isKnown := 1 } 136 | if iszero(i) { i := ROOT_HISTORY_SIZE() } 137 | } 138 | isKnown := false 139 | } 140 | 141 | function getLastRoot() -> v { 142 | v := roots(currentRootIndex()) 143 | } 144 | 145 | /* ---------- constants ---------- */ 146 | function FIELD_SIZE() -> fs { fs := 21888242871839275222246405745257275088548364400416034343698204186575808495617 } 147 | function ZERO_VALUE() -> zv { zv := 21663839004416932945382355908790599225266501822907911457504978515578255421292 } 148 | function ROOT_HISTORY_SIZE() -> rhs { rhs := 30 } 149 | 150 | /* ---------- calldata encoding/decoding ---------- */ 151 | function selector() -> s { 152 | s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) 153 | } 154 | 155 | function decodeAsUint(offset) -> v { 156 | let pos := add(4, mul(offset, 0x20)) 157 | if lt(calldatasize(), add(pos, 0x20)) { 158 | revert(0, 0) 159 | } 160 | v := calldataload(pos) 161 | } 162 | 163 | function returnUint(v) { 164 | mstore(0, v) 165 | return(0, 0x20) 166 | } 167 | 168 | function returnTwoUints(u, v) { 169 | mstore(0, u) 170 | mstore(0x20, v) 171 | return(0, 0x40) 172 | } 173 | 174 | /* ---------- storage reads ---------- */ 175 | function levels() -> v { 176 | v := sload(levelsPos()) 177 | } 178 | 179 | function currentRootIndex() -> v { 180 | v := sload(currentRootIndexPos()) 181 | } 182 | 183 | function nextIndex() -> v { 184 | v := sload(nextIndexPos()) 185 | } 186 | 187 | function filledSubtrees(i) -> v { 188 | v := sload(filledSubtreesOffset(i)) 189 | } 190 | 191 | function roots(i) -> v { 192 | v := sload(rootsOffset(i)) 193 | } 194 | 195 | function isInitialized() -> v { 196 | v := sload(isInitializedPos()) 197 | } 198 | 199 | /* ---------- storage writes ---------- */ 200 | function setLevels(_levels) { 201 | sstore(levelsPos(), _levels) 202 | } 203 | 204 | function setCurrentRootIndex(_currentRootIndex) { 205 | sstore(currentRootIndexPos(), _currentRootIndex) 206 | } 207 | 208 | function setNextIndex(_nextIndex) { 209 | sstore(nextIndexPos(), _nextIndex) 210 | } 211 | 212 | function setFilledSubtrees(i, _filledSubtree) { 213 | sstore(filledSubtreesOffset(i), _filledSubtree) 214 | } 215 | 216 | function setRoots(i, _root) { 217 | sstore(rootsOffset(i), _root) 218 | } 219 | 220 | function setIsInitialized() { 221 | sstore(isInitializedPos(), 1) 222 | } 223 | 224 | /* ---------- storage layout ---------- */ 225 | /* 226 | Because this is meant to be consumed as a library, we must not 227 | modify any of the storage slots that would normally be used as 228 | a result of compiling via solidity. The twister contract will be 229 | `delegatecall`ing into this contract, and will modify its own 230 | state based upon the logic here. By using the hash of the 231 | contract name + variable name, we prevent storage collisions. 232 | */ 233 | function levelsPos() -> p { 234 | /* keccak256("MerkleTreeWithHistory.levels") */ 235 | p := 0xde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc 236 | } 237 | 238 | function currentRootIndexPos() -> p { 239 | /* keccak256("MerkleTreeWithHistory.currentRootIndex") */ 240 | p := 0x00ff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e 241 | } 242 | 243 | function nextIndexPos() -> p { 244 | /* keccak256("MerkleTreeWithHistory.nextIndex") */ 245 | p := 0xd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f 246 | } 247 | 248 | function isInitializedPos() -> p { 249 | /* keccak256("MerkleTreeWithHistory.isInitialized") */ 250 | p := 0x00d99680f702d11a0e37c0a04b851248ea5095ce648b7ecc393538c9b29df295 251 | } 252 | 253 | function filledSubtreesOffset(i) -> offset { 254 | /* keccak256(keccak256("MerkleTreeWithHistory.filledSubtrees"), i) */ 255 | mstore(0, 0xb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd14) 256 | mstore(0x20, i) 257 | offset := keccak256(0, 0x40) 258 | } 259 | 260 | function rootsOffset(i) -> offset { 261 | /* keccak256(keccak256("MerkleTreeWithHistory.roots"), i) */ 262 | mstore(0, 0x3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870) 263 | mstore(0x20, i) 264 | offset := keccak256(0, 0x40) 265 | } 266 | 267 | /* ---------- utility functions ---------- */ 268 | function zeros(i) -> z { 269 | datacopy(0, add(dataoffset("zerosInCode"), mul(i, 0x20)), 0x20) 270 | z := mload(0) 271 | } 272 | 273 | /* 274 | verbatim_Xi_Yo allows us to define an `opcode` in pure bytecode. 275 | In this case, I adapted the mimcsponge contract provided by 276 | circomlib to be a stack-based function: it takes two arguments 277 | from the stack, and returns two arguments to the stack. The 278 | original code from circomlib left a value on the stack, but this 279 | version is stack neutral. I compiled this code using geth. 280 | */ 281 | function mimcSponge(in_xL, in_xR) -> xL, xR { 282 | xL, xR := verbatim_2i_2o(hex"7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150", in_xL, in_xR) 283 | } 284 | } 285 | 286 | data "zerosInCode" hex"2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c20020121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c924ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb549591ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff800058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c0071f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e301bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e50ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb10813e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b61eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db618540da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc0529d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d419be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b29671ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc345310c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c480ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce992eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f4271f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc" 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /contracts/MerkleTreeWithHistoryYul.yul: -------------------------------------------------------------------------------- 1 | object "MerkleTreeWithHistory" { 2 | code { 3 | datacopy(0, dataoffset("runtime"), datasize("runtime")) 4 | return(0, datasize("runtime")) 5 | } 6 | object "runtime" { 7 | code { 8 | /* ---------- call routing ---------- */ 9 | switch selector() 10 | case 0x2d287e43 /* insert(bytes32) */ { 11 | returnUint(insert(decodeAsUint(0))) 12 | } 13 | case 0x8d8965bd /* initialize(uint32) */ { 14 | initialize(decodeAsUint(0)) 15 | } 16 | case 0xf47d33b5 /* MiMCSponge(uint256,uint256) */ { 17 | let xL, xR := mimcSponge(decodeAsUint(0), decodeAsUint(1)) 18 | returnTwoUints(xL, xR) 19 | } 20 | case 0x6d9833e3 /* isKnownRoot(bytes32) */ { 21 | returnUint(isKnownRoot(decodeAsUint(0))) 22 | } 23 | case 0xba70f757 /* getLastRoot() */ { 24 | returnUint(getLastRoot()) 25 | } 26 | case 0xe8295588 /* zeros(uint256) */ { 27 | returnUint(zeros(decodeAsUint(0))) 28 | } 29 | 30 | /* ---------- main functions ---------- */ 31 | function insert(leaf) -> leafIndex { 32 | let _levels := levels() 33 | let _nextIndex := nextIndex() 34 | if eq(_nextIndex, exp(2, _levels)) { 35 | revert(0, 0) 36 | } 37 | let currentIndex := _nextIndex 38 | let currentLevelHash := leaf 39 | let left := 0 40 | let right := 0 41 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } { 42 | let condition := mod(currentIndex, 2) 43 | if iszero(condition) { 44 | left := currentLevelHash 45 | right := zeros(i) 46 | setFilledSubtrees(i, currentLevelHash) 47 | } 48 | if condition { 49 | left := filledSubtrees(i) 50 | right := currentLevelHash 51 | } 52 | if iszero(lt(left, FIELD_SIZE())) { 53 | revert(0, 0) 54 | } 55 | if iszero(lt(right, FIELD_SIZE())) { 56 | revert(0, 0) 57 | } 58 | let R := left 59 | let C := 0 60 | R, C := mimcSponge(R, C) 61 | R := addmod(R, right, FIELD_SIZE()) 62 | R, C := mimcSponge(R, C) 63 | currentLevelHash := R 64 | currentIndex := div(currentIndex, 2) 65 | } 66 | let newRootIndex := addmod(currentRootIndex(), 1, ROOT_HISTORY_SIZE()) 67 | setCurrentRootIndex(newRootIndex) 68 | setRoots(newRootIndex, currentLevelHash) 69 | setNextIndex(add(_nextIndex, 1)) 70 | leafIndex := _nextIndex 71 | } 72 | 73 | function initialize(_levels) { 74 | if isInitialized() { revert(0, 0) } 75 | if iszero(_levels) { revert(0, 0) } 76 | if gt(_levels, 32) { revert(0, 0) } 77 | for { let i := 0 } lt(i, _levels) { i := add(i, 1) } 78 | { 79 | setFilledSubtrees(i, zeros(i)) 80 | } 81 | setLevels(_levels) 82 | setRoots(0, zeros(sub(_levels, 1))) 83 | setIsInitialized() 84 | } 85 | 86 | function isKnownRoot(root) -> isKnown { 87 | if iszero(root) { isKnown := false } 88 | 89 | let _currentRootIndex := currentRootIndex() 90 | if eq(root, roots(_currentRootIndex)) { isKnown := true } 91 | 92 | for 93 | { let i := sub(_currentRootIndex, 1) } 94 | iszero(eq(i, _currentRootIndex)) 95 | { i := sub(i, 1) } 96 | { 97 | if eq(root, roots(i)) { isKnown := 1 } 98 | if iszero(i) { i := ROOT_HISTORY_SIZE() } 99 | } 100 | isKnown := false 101 | } 102 | 103 | function getLastRoot() -> v { 104 | v := roots(currentRootIndex()) 105 | } 106 | 107 | /* ---------- constants ---------- */ 108 | function FIELD_SIZE() -> fs { fs := 21888242871839275222246405745257275088548364400416034343698204186575808495617 } 109 | function ZERO_VALUE() -> zv { zv := 21663839004416932945382355908790599225266501822907911457504978515578255421292 } 110 | function ROOT_HISTORY_SIZE() -> rhs { rhs := 30 } 111 | 112 | /* ---------- calldata encoding/decoding ---------- */ 113 | function selector() -> s { 114 | s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) 115 | } 116 | 117 | function decodeAsUint(offset) -> v { 118 | let pos := add(4, mul(offset, 0x20)) 119 | if lt(calldatasize(), add(pos, 0x20)) { 120 | revert(0, 0) 121 | } 122 | v := calldataload(pos) 123 | } 124 | 125 | function returnUint(v) { 126 | mstore(0, v) 127 | return(0, 0x20) 128 | } 129 | 130 | function returnTwoUints(u, v) { 131 | mstore(0, u) 132 | mstore(0x20, v) 133 | return(0, 0x40) 134 | } 135 | 136 | /* ---------- storage reads ---------- */ 137 | function levels() -> v { 138 | v := sload(levelsPos()) 139 | } 140 | 141 | function currentRootIndex() -> v { 142 | v := sload(currentRootIndexPos()) 143 | } 144 | 145 | function nextIndex() -> v { 146 | v := sload(nextIndexPos()) 147 | } 148 | 149 | function filledSubtrees(i) -> v { 150 | v := sload(filledSubtreesOffset(i)) 151 | } 152 | 153 | function roots(i) -> v { 154 | v := sload(rootsOffset(i)) 155 | } 156 | 157 | function isInitialized() -> v { 158 | v := sload(isInitializedPos()) 159 | } 160 | 161 | /* ---------- storage writes ---------- */ 162 | function setLevels(_levels) { 163 | sstore(levelsPos(), _levels) 164 | } 165 | 166 | function setCurrentRootIndex(_currentRootIndex) { 167 | sstore(currentRootIndexPos(), _currentRootIndex) 168 | } 169 | 170 | function setNextIndex(_nextIndex) { 171 | sstore(nextIndexPos(), _nextIndex) 172 | } 173 | 174 | function setFilledSubtrees(i, _filledSubtree) { 175 | sstore(filledSubtreesOffset(i), _filledSubtree) 176 | } 177 | 178 | function setRoots(i, _root) { 179 | sstore(rootsOffset(i), _root) 180 | } 181 | 182 | function setIsInitialized() { 183 | sstore(isInitializedPos(), 1) 184 | } 185 | 186 | /* ---------- storage layout ---------- */ 187 | /* 188 | Because this is meant to be consumed as a library, we must not 189 | modify any of the storage slots that would normally be used as 190 | a result of compiling via solidity. The twister contract will be 191 | `delegatecall`ing into this contract, and will modify its own 192 | state based upon the logic here. By using the hash of the 193 | contract name + variable name, we prevent storage collisions. 194 | */ 195 | function levelsPos() -> p { 196 | /* keccak256("MerkleTreeWithHistory.levels") */ 197 | p := 0xde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc 198 | } 199 | 200 | function currentRootIndexPos() -> p { 201 | /* keccak256("MerkleTreeWithHistory.currentRootIndex") */ 202 | p := 0x00ff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e 203 | } 204 | 205 | function nextIndexPos() -> p { 206 | /* keccak256("MerkleTreeWithHistory.nextIndex") */ 207 | p := 0xd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f 208 | } 209 | 210 | function isInitializedPos() -> p { 211 | /* keccak256("MerkleTreeWithHistory.isInitialized") */ 212 | p := 0x00d99680f702d11a0e37c0a04b851248ea5095ce648b7ecc393538c9b29df295 213 | } 214 | 215 | function filledSubtreesOffset(i) -> offset { 216 | /* keccak256(keccak256("MerkleTreeWithHistory.filledSubtrees"), i) */ 217 | mstore(0, 0xb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd14) 218 | mstore(0x20, i) 219 | offset := keccak256(0, 0x40) 220 | } 221 | 222 | function rootsOffset(i) -> offset { 223 | /* keccak256(keccak256("MerkleTreeWithHistory.roots"), i) */ 224 | mstore(0, 0x3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870) 225 | mstore(0x20, i) 226 | offset := keccak256(0, 0x40) 227 | } 228 | 229 | /* ---------- utility functions ---------- */ 230 | function zeros(i) -> z { 231 | switch i 232 | case 0 { z := 0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c } 233 | case 1 { z := 0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d } 234 | case 2 { z := 0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200 } 235 | case 3 { z := 0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb } 236 | case 4 { z := 0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9 } 237 | case 5 { z := 0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959 } 238 | case 6 { z := 0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c } 239 | case 7 { z := 0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4 } 240 | case 8 { z := 0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80 } 241 | case 9 { z := 0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007 } 242 | case 10 { z := 0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30 } 243 | case 11 { z := 0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5 } 244 | case 12 { z := 0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f } 245 | case 13 { z := 0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd } 246 | case 14 { z := 0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108 } 247 | case 15 { z := 0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6 } 248 | case 16 { z := 0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854 } 249 | case 17 { z := 0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea } 250 | case 18 { z := 0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d } 251 | case 19 { z := 0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05 } 252 | case 20 { z := 0x29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d4 } 253 | case 21 { z := 0x19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b2967 } 254 | case 22 { z := 0x1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc3453 } 255 | case 23 { z := 0x10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c48 } 256 | case 24 { z := 0x0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1 } 257 | case 25 { z := 0x019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c } 258 | case 26 { z := 0x2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce99 } 259 | case 27 { z := 0x2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354 } 260 | case 28 { z := 0x002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d } 261 | case 29 { z := 0x104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f427 } 262 | case 30 { z := 0x1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb } 263 | case 31 { z := 0x2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc } 264 | } 265 | 266 | /* 267 | verbatim_Xi_Yo allows us to define an `opcode` in pure bytecode. 268 | In this case, I adapted the mimcsponge contract provided by 269 | circomlib to be a stack-based function: it takes two arguments 270 | from the stack, and returns two arguments to the stack. The 271 | original code from circomlib left a value on the stack, but this 272 | version is stack neutral. I compiled this code using geth. 273 | */ 274 | function mimcSponge(in_xL, in_xR) -> xL, xR { 275 | xL, xR := verbatim_2i_2o(hex"7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150", in_xL, in_xR) 276 | } 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /generate_mimchasher_contract.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | 3 | keccak = Web3.keccak 4 | toHex = Web3.toHex 5 | seed = keccak(text='mimcsponge') 6 | N = 220 7 | 8 | code = ''' 9 | pragma solidity ^0.8.0; 10 | 11 | 12 | contract MiMCHasherPython { 13 | 14 | function MiMCSponge( 15 | uint in_xL, uint in_xR 16 | ) public pure returns (uint xL, uint xR) { 17 | unchecked { assembly { 18 | let _xL := in_xL 19 | let _xR := in_xR 20 | let q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 21 | let a := 0 22 | let b := mulmod(_xL, _xL, q) 23 | let c := mulmod(b, b, q) 24 | let d := mulmod(c, _xL, q) 25 | let e := addmod(d, _xR, q) 26 | _xR := _xL 27 | _xL := e''' 28 | code_fragments = [ 29 | ''' 30 | a := addmod(%s, _xL, q) 31 | b := mulmod(a, a, q) 32 | c := mulmod(b, b, q) 33 | d := mulmod(c, a, q) 34 | e := addmod(d, _xR, q) 35 | ''', 36 | ''' _xR := _xL 37 | _xL := e''' 38 | ] 39 | 40 | code = '' 41 | 42 | for i in range(N-1): 43 | seed = keccak(seed) 44 | code += '''SWAP1 45 | DUP3 46 | DUP3 47 | PUSH %s 48 | ADDMOD 49 | DUP4 50 | SWAP1 51 | DUP2 52 | DUP1 53 | DUP3 54 | DUP1 55 | MULMOD 56 | DUP1 57 | MULMOD 58 | MULMOD 59 | DUP4 60 | SWAP2 61 | ADDMOD 62 | ''' % seed.hex() 63 | 64 | # code += ''.join([ 65 | # code_fragments[0] % (toHex(seed)) if i < N-2 else code_fragments[0] % (toHex(0)), 66 | # code_fragments[1] 67 | # ]) 68 | 69 | # code += ''' 70 | # xL := _xR 71 | # xR := _xL 72 | # }} 73 | # } 74 | # } 75 | # ''' 76 | 77 | # with open('./contracts/MiMCHasherPython.sol', 'w+') as f: 78 | # f.write(code) 79 | with open('./rounds.easm', 'w+') as f: 80 | f.write(code) 81 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle"); 2 | require('./scripts/hardhat.tasks.js'); 3 | 4 | 5 | module.exports = { 6 | defaultNetwork: "hardhat", 7 | networks: { 8 | hardhat: { 9 | // loggingEnabled: true, 10 | }, 11 | }, 12 | paths: { 13 | sources: "./contracts", 14 | cache: "./build/cache", 15 | artifacts: "./build/artifacts", 16 | tests: "./test", 17 | }, 18 | solidity: { 19 | compilers: [ 20 | { 21 | version: "0.8.6", 22 | settings: { 23 | optimizer: { 24 | enabled: true, 25 | runs: 2000000 26 | } 27 | } 28 | } 29 | ] 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "chai": "^4.3.4", 7 | "circomlib": "^0.5.3", 8 | "ethereum-waffle": "^3.4.0", 9 | "ethers": "^5.4.6", 10 | "hardhat": "^2.6.4" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /remix/MerkleTreeWithHistoryV1.json: -------------------------------------------------------------------------------- 1 | { 2 | "bytecode": "6136e56100106000396136e56000f3fe6100076103c7565b632d287e43811461004e57638d8965bd811461006d5763f47d33b5811461008457636d9833e381146100b15763ba70f75781146100d05763e829558881146100e557610100565b61006861006361005e60006103f0565b610106565b610413565b610100565b61007f61007a60006103f0565b61021a565b610100565b6100a061009160016103f0565b61009b60006103f0565b610bff565b6100aa818361041d565b5050610100565b6100cb6100c66100c160006103f0565b61030d565b610413565b610100565b6100e06100db61037f565b610413565b610100565b6100ff6100fa6100f560006103f0565b6105f7565b610413565b5b506136e4565b600061011061042b565b61011861044b565b8160020a81141561012857600080fd5b808460008060005b868110156101d857600285068061015a5784935061014d826105f7565b925061015985836104b8565b5b801561016f576101698261045b565b93508492505b610177610396565b841061018257600080fd5b61018a610396565b831061019557600080fd5b8360006101a28183610bff565b915091506101ae610396565b85830891506101bd8183610bff565b91509150819650600288049750505050600181019050610130565b506101e16103be565b60016101eb61043b565b086101f58161049e565b6101ff84826104c7565b61020b600187016104ab565b85975050505050505050919050565b610222610481565b15610251576102507f616c726561647920696e697400000000000000000000000000000000000000006105ed565b5b806102805761027f7f6c6576656c7320697320300000000000000000000000000000000000000000006105ed565b5b60208111156102b3576102b27f6c6576656c7320677420333200000000000000000000000000000000000000006105ed565b5b60005b818110156102db576102d06102ca826105f7565b826104b8565b6001810190506102b6565b506102f96102f260016102ec61042b565b036105f7565b60006104c7565b61030281610491565b61030a6104d6565b50565b60008161031957600090505b61032161043b565b61032a8161046e565b83141561033657600191505b600181035b81811419156103745761034d8161046e565b84141561035957600192505b80610369576103666103be565b90505b60018103905061033b565b506000915050919050565b600061039161038c61043b565b61046e565b905090565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001905090565b6000601e905090565b60007c010000000000000000000000000000000000000000000000000000000060003504905090565b6000602082026004016020810136101561040957600080fd5b8035915050919050565b8060005260206000f35b806000528160205260406000f35b60006104356104e3565b54905090565b600061044561050b565b54905090565b6000610455610532565b54905090565b600061046682610581565b549050919050565b6000610479826105b7565b549050919050565b600061048b61055a565b54905090565b8061049a6104e3565b5550565b806104a761050b565b5550565b806104b4610532565b5550565b816104c282610581565b555050565b816104d1826105b7565b555050565b60016104e061055a565b55565b60007fde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc905090565b60007eff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e905090565b60007fd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f905090565b60007ed99680f702d11a0e37c0a04b851248ea5095ce648b7ecc393538c9b29df295905090565b60007fb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd146000528160205260406000209050919050565b60007f3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef8706000528160205260406000209050919050565b8060005260206000fd5b600081600081146106ff5760018114610727576002811461074f5760038114610777576004811461079f57600581146107c757600681146107ef5760078114610817576008811461083f576009811461086757600a811461088e57600b81146108b657600c81146108de57600d811461090657600e811461092e57600f8114610956576010811461097e57601181146109a657601281146109ce57601381146109f65760148114610a1e5760158114610a465760168114610a6e5760178114610a965760188114610abe5760198114610ae657601a8114610b0e57601b8114610b3657601c8114610b5e57601d8114610b8557601e8114610bad57601f8114610bd557610bf9565b7f2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c9150610bf9565b7f256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d9150610bf9565b7f1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c2009150610bf9565b7f20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb9150610bf9565b7f0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c99150610bf9565b7f24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb549599150610bf9565b7f1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c9150610bf9565b7f19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb49150610bf9565b7f261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff809150610bf9565b7e58459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c0079150610bf9565b7f1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e309150610bf9565b7f1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e59150610bf9565b7f0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f9150610bf9565b7f1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd9150610bf9565b7f133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb1089150610bf9565b7f13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b69150610bf9565b7f1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db618549150610bf9565b7f0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea9150610bf9565b7f24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d9150610bf9565b7f198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc059150610bf9565b7f29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d49150610bf9565b7f19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b29679150610bf9565b7f1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc34539150610bf9565b7f10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c489150610bf9565b7f0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd19150610bf9565b7f019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c9150610bf9565b7f2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce999150610bf9565b7f2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f3549150610bf9565b7e2df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d9150610bf9565b7f104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f4279150610bf9565b7f1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb9150610bf9565b7f2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc91505b50919050565b60008083837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150915091509250929050565b", 3 | "abi": [ 4 | "function MiMCSponge(uint256 in_xL, uint256 in_xR) public pure returns (uint256 xL, uint256 xR)", 5 | "function initialize(uint32 levels) public", 6 | "function insert(bytes32 leaf) public returns (uint256 index)", 7 | "function getLastRoot() public view returns (bytes32 lastRoot)", 8 | "function zeros(uint256) public view returns (bytes32 zero)" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /remix/MerkleTreeWithHistoryV3.json: -------------------------------------------------------------------------------- 1 | { 2 | "bytecode": "6200000b6014620003cc565b620000387f2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c6000620003db565b620000657f256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d6001620003db565b620000927f1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c2006002620003db565b620000bf7f20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb6003620003db565b620000ec7f0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c96004620003db565b620001197f24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb549596005620003db565b620001467f1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c6006620003db565b620001737f19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb46007620003db565b620001a07f261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff806008620003db565b620001cc7e58459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c0076009620003db565b620001f97f1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30600a620003db565b620002267f1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5600b620003db565b620002537f0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f600c620003db565b620002807f1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd600d620003db565b620002ad7f133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108600e620003db565b620002da7f13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6600f620003db565b620003077f1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db618546010620003db565b620003347f0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea6011620003db565b620003617f24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d6012620003db565b6200038e7f198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc056013620003db565b620003bb7f198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc056000620003ec565b613384620004926000396133846000f35b80620003d7620003fd565b5550565b81620003e78262000425565b555050565b81620003f8826200045b565b555050565b60007fde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc905090565b60007fb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd146000528160205260406000209050919050565b60007f3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef870600052816020526040600020905091905056fe6100076102b0565b632d287e4381146100435763f47d33b5811461006257636d9833e3811461008f5763ba70f75781146100ae5763e829558881146100c3576100de565b61005d61005861005360006102d9565b6100e4565b6102fc565b6100de565b61007e61006f60016102d9565b61007960006102d9565b61049d565b6100888183610306565b50506100de565b6100a96100a461009f60006102d9565b6101f8565b6102fc565b6100de565b6100be6100b9610268565b6102fc565b6100de565b6100dd6100d86100d360006102d9565b610485565b6102fc565b5b50612f82565b60006100ee610314565b6100f6610334565b8160020a81141561010657600080fd5b808460008060005b868110156101b65760028506806101385784935061012b82610485565b92506101378583610384565b5b801561014d5761014782610344565b93508492505b61015561027f565b841061016057600080fd5b61016861027f565b831061017357600080fd5b836000610180818361049d565b9150915061018c61027f565b858308915061019b818361049d565b9150915081965060028804975050505060018101905061010e565b506101bf6102a7565b60016101c9610324565b086101d38161036a565b6101dd8482610393565b6101e960018701610377565b85975050505050505050919050565b60008161020457600090505b61020c610324565b61021581610357565b83141561022157600191505b600181035b81811461025d5761023681610357565b84141561024257600192505b806102525761024f6102a7565b90505b600181039050610226565b506000915050919050565b600061027a610275610324565b610357565b905090565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001905090565b6000601e905090565b60007c010000000000000000000000000000000000000000000000000000000060003504905090565b600060208202600401602081013610156102f257600080fd5b8035915050919050565b8060005260206000f35b806000528160205260406000f35b600061031e6103a2565b54905090565b600061032e6103ca565b54905090565b600061033e6103f1565b54905090565b600061034f82610419565b549050919050565b60006103628261044f565b549050919050565b806103736103ca565b5550565b806103806103f1565b5550565b8161038e82610419565b555050565b8161039d8261044f565b555050565b60007fde2ed6c39cf86ec6c46094edf836392df5606753f0bad38f3944f0d7d7378cdc905090565b60007eff991afe2a78230bbcdd43bb1812ad7b733f0560f122e06f67cd9933d6ba9e905090565b60007fd51ecf3c5a8d703fd9b1393cb4ecba6ed23884bc25601f230687eef09629a15f905090565b60007fb0c88fae7c37e544fed707550a8667cd25ee99af1d5b4f590257644dc2edfd146000528160205260406000209050919050565b60007f3824de49a43784238a1838eb1c9b2f1411a38b93366828f2f9a6c422377ef8706000528160205260406000209050919050565b60006020808302612f84016000396000519050919050565b60008083837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000191829081838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827e53f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827e63a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827e129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827ee115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c10088390818082800980090983910890828260000883908180828009800909839108909150915091509250929050565bfe2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c20020121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c924ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb549591ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff800058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c0071f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e301bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e50ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb10813e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b61eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db618540da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc0529d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d419be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b29671ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc345310c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c480ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce992eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f4271f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc", 3 | "abi": [ 4 | "function MiMCSponge(uint256 in_xL, uint256 in_xR) public pure returns (uint256 xL, uint256 xR)", 5 | "function initialize(uint32 levels) public", 6 | "function insert(bytes32 leaf) public returns (uint256 index)", 7 | "function getLastRoot() public view returns (bytes32 lastRoot)", 8 | "function zeros(uint256) public view returns (bytes32 zero)" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.7.4 2 | async-timeout==3.0.1 3 | attrs==21.2.0 4 | base58==2.1.0 5 | bitarray==1.2.2 6 | certifi==2021.5.30 7 | chardet==4.0.0 8 | charset-normalizer==2.0.4 9 | cytoolz==0.11.0 10 | eth-abi==2.1.1 11 | eth-account==0.5.5 12 | eth-hash==0.3.2 13 | eth-keyfile==0.5.1 14 | eth-keys==0.3.3 15 | eth-rlp==0.2.1 16 | eth-typing==2.2.2 17 | eth-utils==1.10.0 18 | hexbytes==0.2.2 19 | idna==3.2 20 | importlib-metadata==4.8.1 21 | ipfshttpclient==0.8.0a2 22 | jsonschema==3.2.0 23 | lru-dict==1.1.7 24 | multiaddr==0.0.9 25 | multidict==5.1.0 26 | netaddr==0.8.0 27 | parsimonious==0.8.1 28 | protobuf==3.17.3 29 | pycryptodome==3.10.1 30 | pyrsistent==0.18.0 31 | requests==2.26.0 32 | rlp==2.0.1 33 | six==1.16.0 34 | toolz==0.11.1 35 | typing-extensions==3.10.0.2 36 | urllib3==1.26.6 37 | varint==1.0.2 38 | web3==5.23.1 39 | websockets==9.1 40 | yarl==1.6.3 41 | zipp==3.5.0 42 | -------------------------------------------------------------------------------- /scripts/evmasm.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Jordi Baylina 2 | // License: LGPL-3.0+ 3 | // 4 | 5 | 6 | const Web3Utils = require("web3-utils"); 7 | 8 | class Contract { 9 | constructor() { 10 | this.code = []; 11 | this.labels = {}; 12 | this.pendingLabels = {}; 13 | } 14 | 15 | createTxData() { 16 | let C; 17 | 18 | // Check all labels are defined 19 | const pendingLabels = Object.keys(this.pendingLabels); 20 | if (pendingLabels.length>0) { 21 | throw new Error("Lables not defined: "+ pendingLabels.join(", ")); 22 | } 23 | 24 | let setLoaderLength = 0; 25 | let genLoadedLength = -1; 26 | 27 | while (genLoadedLength!=setLoaderLength) { 28 | setLoaderLength = genLoadedLength; 29 | C = new module.exports(); 30 | C.codesize(); 31 | C.push(setLoaderLength); 32 | C.push(0); 33 | C.codecopy(); 34 | 35 | C.push(this.code.length); 36 | C.push(0); 37 | C.return(); 38 | genLoadedLength = C.code.length; 39 | } 40 | 41 | return Web3Utils.bytesToHex(C.code.concat(this.code)); 42 | } 43 | 44 | stop() { this.code.push(0x00); } 45 | add() { this.code.push(0x01); } 46 | mul() { this.code.push(0x02); } 47 | sub() { this.code.push(0x03); } 48 | div() { this.code.push(0x04); } 49 | sdiv() { this.code.push(0x05); } 50 | mod() { this.code.push(0x06); } 51 | smod() { this.code.push(0x07); } 52 | addmod() { this.code.push(0x08); } 53 | mulmod() { this.code.push(0x09); } 54 | exp() { this.code.push(0x0a); } 55 | signextend() { this.code.push(0x0b); } 56 | 57 | lt() { this.code.push(0x10); } 58 | gt() { this.code.push(0x11); } 59 | slt() { this.code.push(0x12); } 60 | sgt() { this.code.push(0x13); } 61 | eq() { this.code.push(0x14); } 62 | iszero() { this.code.push(0x15); } 63 | and() { this.code.push(0x16); } 64 | or() { this.code.push(0x17); } 65 | shor() { this.code.push(0x18); } 66 | not() { this.code.push(0x19); } 67 | byte() { this.code.push(0x1a); } 68 | 69 | keccak() { this.code.push(0x20); } 70 | sha3() { this.code.push(0x20); } // alias 71 | 72 | address() { this.code.push(0x30); } 73 | balance() { this.code.push(0x31); } 74 | origin() { this.code.push(0x32); } 75 | caller() { this.code.push(0x33); } 76 | callvalue() { this.code.push(0x34); } 77 | calldataload() { this.code.push(0x35); } 78 | calldatasize() { this.code.push(0x36); } 79 | calldatacopy() { this.code.push(0x37); } 80 | codesize() { this.code.push(0x38); } 81 | codecopy() { this.code.push(0x39); } 82 | gasprice() { this.code.push(0x3a); } 83 | extcodesize() { this.code.push(0x3b); } 84 | extcodecopy() { this.code.push(0x3c); } 85 | returndatasize() { this.code.push(0x3d); } 86 | returndatacopy() { this.code.push(0x3e); } 87 | 88 | blockhash() { this.code.push(0x40); } 89 | coinbase() { this.code.push(0x41); } 90 | timestamp() { this.code.push(0x42); } 91 | number() { this.code.push(0x43); } 92 | difficulty() { this.code.push(0x44); } 93 | gaslimit() { this.code.push(0x45); } 94 | 95 | pop() { this.code.push(0x50); } 96 | mload() { this.code.push(0x51); } 97 | mstore() { this.code.push(0x52); } 98 | mstore8() { this.code.push(0x53); } 99 | sload() { this.code.push(0x54); } 100 | sstore() { this.code.push(0x55); } 101 | 102 | _pushLabel(label) { 103 | if (typeof this.labels[label] != "undefined") { 104 | this.push(this.labels[label]); 105 | } else { 106 | this.pendingLabels[label] = this.pendingLabels[label] || []; 107 | this.pendingLabels[label].push(this.code.length); 108 | this.push("0x000000"); 109 | } 110 | } 111 | 112 | _fillLabel(label) { 113 | if (!this.pendingLabels[label]) return; 114 | 115 | let dst = this.labels[label]; 116 | 117 | const dst3 = [dst >> 16, (dst >> 8) & 0xFF, dst & 0xFF]; 118 | 119 | this.pendingLabels[label].forEach((p) => { 120 | for (let i=0; i<3; i++) { 121 | this.code[p+i+1] = dst3[i]; 122 | } 123 | }); 124 | 125 | delete this.pendingLabels[label]; 126 | } 127 | 128 | 129 | jmp(label) { 130 | if (typeof label !== "undefined") { 131 | this._pushLabel(label); 132 | } 133 | this.code.push(0x56); 134 | } 135 | 136 | jmpi(label) { 137 | if (typeof label !== "undefined") { 138 | this._pushLabel(label); 139 | } 140 | this.code.push(0x57); 141 | } 142 | 143 | pc() { this.code.push(0x58); } 144 | msize() { this.code.push(0x59); } 145 | gas() { this.code.push(0x5a); } 146 | label(name) { 147 | if (typeof this.labels[name] != "undefined") { 148 | throw new Error("Label already defined"); 149 | } 150 | this.labels[name] = this.code.length; 151 | this.code.push(0x5b); 152 | 153 | this._fillLabel(name); 154 | } 155 | 156 | push(data) { 157 | if (typeof data === "number") { 158 | let isNeg; 159 | if (data<0) { 160 | isNeg = true; 161 | data = -data; 162 | } 163 | data = data.toString(16); 164 | if (data.length % 2 == 1) data = "0" + data; 165 | data = "0x" + data; 166 | if (isNeg) data = "-"+data; 167 | } 168 | const d = Web3Utils.hexToBytes(Web3Utils.toHex(data)); 169 | if (d.length == 0 || d.length > 32) { 170 | throw new Error("Assertion failed"); 171 | } 172 | this.code = this.code.concat([0x5F + d.length], d); 173 | } 174 | 175 | dup(n) { 176 | if (n < 0 || n >= 16) { 177 | throw new Error("Assertion failed"); 178 | } 179 | this.code.push(0x80 + n); 180 | } 181 | 182 | swap(n) { 183 | if (n < 1 || n > 16) { 184 | throw new Error("Assertion failed"); 185 | } 186 | this.code.push(0x8f + n); 187 | } 188 | 189 | log0() { this.code.push(0xa0); } 190 | log1() { this.code.push(0xa1); } 191 | log2() { this.code.push(0xa2); } 192 | log3() { this.code.push(0xa3); } 193 | log4() { this.code.push(0xa4); } 194 | 195 | create() { this.code.push(0xf0); } 196 | call() { this.code.push(0xf1); } 197 | callcode() { this.code.push(0xf2); } 198 | return() { this.code.push(0xf3); } 199 | delegatecall() { this.code.push(0xf4); } 200 | 201 | staticcall() { this.code.push(0xfa); } 202 | revert() { this.code.push(0xfd); } 203 | invalid() { this.code.push(0xfe); } 204 | selfdestruct() { this.code.push(0xff); } 205 | } 206 | 207 | module.exports = Contract; 208 | -------------------------------------------------------------------------------- /scripts/hardhat.tasks.js: -------------------------------------------------------------------------------- 1 | task( 2 | "accounts", 3 | "Prints the list of accounts and balances" 4 | ).setAction( 5 | async (_, hre) => { 6 | const accounts = await hre.ethers.getSigners(); 7 | for (const account of accounts) { 8 | const balance = await hre.ethers.provider.getBalance(account.address); 9 | console.log(`${account.address}: ${balance/1e18} ETH`); 10 | } 11 | } 12 | ); 13 | 14 | task( 15 | "chainid", 16 | "Prints the chainid of hardhat node" 17 | ).setAction( 18 | async (_, hre) => { 19 | const chainId = (await hre.ethers.provider.getNetwork()).chainId; 20 | console.log(`chainId: ${chainId}`); 21 | } 22 | ); 23 | 24 | task( 25 | "keccak", 26 | "Performs the solidityKeccak hash of --text" 27 | ).addParam( 28 | "text", 29 | "The text to take the solidityKeccak hash of" 30 | ).setAction( 31 | async (taskArgs, hre) => { 32 | console.log( 33 | hre.ethers.utils.solidityKeccak256(["string"], [taskArgs.text]) 34 | ); 35 | } 36 | ); 37 | 38 | task( 39 | "selector", 40 | "Computes the function selector of --signature" 41 | ).addParam( 42 | "signature", 43 | "e.g. transferFrom(address,address,uint256)" 44 | ).setAction( 45 | async (taskArgs, hre) => { 46 | let fullHash = hre.ethers.utils.solidityKeccak256( 47 | ["string"], [taskArgs.signature] 48 | ); 49 | console.log(fullHash.slice(0, 10)); 50 | } 51 | ); 52 | 53 | task( 54 | "solidityKeccak", 55 | "Performs the solidityKeccak hash of --values with given --types" 56 | ).addParam( 57 | "types", 58 | "JSON string e.g. '[\"uint256\", \"string\"]'" 59 | ).addParam( 60 | "values", 61 | "JSON string e.g. '[42, \"Jason Parser\"]'" 62 | ).setAction( 63 | async (taskArgs, hre) => { 64 | console.log( 65 | hre.ethers.utils.solidityKeccak256( 66 | JSON.parse(taskArgs.types), JSON.parse(taskArgs.values) 67 | ) 68 | ); 69 | } 70 | ); 71 | -------------------------------------------------------------------------------- /scripts/hardhat.utils.js: -------------------------------------------------------------------------------- 1 | async function impersonateAccount(account) { 2 | await hre.network.provider.request({ 3 | method: "hardhat_impersonateAccount", 4 | params: [account] 5 | }); 6 | } 7 | 8 | async function stopImpersonatingAccount(account) { 9 | await hre.network.provider.request({ 10 | method: "hardhat_stopImpersonatingAccount", 11 | params: [account] 12 | }); 13 | } 14 | 15 | async function enableForking(rpcUrl, blocknumber) { 16 | await hre.network.provider.request({ 17 | method: "hardhat_reset", 18 | params: [{ 19 | forking: { 20 | jsonRpcUrl: rpcUrl, 21 | blockNumber: blocknumber 22 | } 23 | }] 24 | }); 25 | } 26 | 27 | async function disableForking() { 28 | await hre.network.provider.request({ 29 | method: "hardhat_reset" 30 | }); 31 | } 32 | 33 | async function increaseTime(time) { 34 | await hre.network.provider.request({ 35 | method: "evm_increaseTime", 36 | params: [time] 37 | }); 38 | } 39 | 40 | async function setNextBlockTimestamp(time) { 41 | await hre.network.provider.request({ 42 | method: "evm_setNextBlockTimestamp", 43 | params: [time] 44 | }); 45 | } 46 | 47 | async function mineBlock() { 48 | await hre.network.provider.request({ 49 | method: "evm_mine", 50 | }); 51 | } 52 | 53 | async function snapshot() { 54 | const snapshotId = await hre.network.provider.request({ 55 | method: "evm_snapshot", 56 | }); 57 | return snapshotId; 58 | } 59 | 60 | async function revertSnapshot(snapshotId) { 61 | await hre.network.provider.request({ 62 | method: "evm_revert", 63 | params: [snapshotId] 64 | }); 65 | } 66 | 67 | async function deployContract(contractName, constructorArgs=[], verbose=false) { 68 | let contract; 69 | let factory = await hre.ethers.getContractFactory(contractName); 70 | if (constructorArgs == []) { 71 | contract = await factory.deploy(); 72 | } else { 73 | contract = await factory.deploy(...constructorArgs); 74 | } 75 | await contract.deployed(); 76 | if (verbose) 77 | console.log(`Deployed ${contractName} at ${contract.address}`); 78 | return contract; 79 | } 80 | 81 | async function deployWithAbiAndBytecode(contractName, abi, bytecode, verbose=false) { 82 | const [signer] = await hre.ethers.getSigners(); 83 | const interface = new hre.ethers.utils.Interface(abi); 84 | const factory = new hre.ethers.ContractFactory(interface, bytecode, signer); 85 | 86 | const contract = await factory.deploy(); 87 | await contract.deployed(); 88 | if (verbose) 89 | console.log(`Deployed ${contractName} at ${contract.address}`); 90 | return contract; 91 | } 92 | 93 | module.exports = { 94 | impersonateAccount, 95 | stopImpersonatingAccount, 96 | enableForking, 97 | disableForking, 98 | increaseTime, 99 | setNextBlockTimestamp, 100 | mineBlock, 101 | snapshot, 102 | revertSnapshot, 103 | deployContract, 104 | deployWithAbiAndBytecode, 105 | } 106 | -------------------------------------------------------------------------------- /scripts/mimcsponge_gencontract.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Jordi Baylina 2 | // License: LGPL-3.0+ 3 | // 4 | 5 | const Web3Utils = require("web3-utils"); 6 | const Contract = require("./evmasm"); 7 | 8 | function createCode(seed, n) { 9 | 10 | let ci = Web3Utils.keccak256(seed); 11 | 12 | const C = new Contract(); 13 | 14 | C.push(0x64); 15 | C.push("0x00"); 16 | C.push("0x00"); 17 | C.calldatacopy(); 18 | C.push("0x0100000000000000000000000000000000000000000000000000000000"); 19 | C.push("0x00"); 20 | C.mload(); 21 | C.div(); 22 | C.push("0xf47d33b5"); // MiMCSponge(uint256,uint256) 23 | C.eq(); 24 | C.jmpi("start"); 25 | C.invalid(); 26 | 27 | C.label("start"); 28 | C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q 29 | C.push("0x04"); 30 | C.mload(); // xL q 31 | C.dup(1); // q xL q 32 | C.push("0x24"); 33 | C.mload(); // xR q xL q 34 | C.dup(1); // q xR q xL q 35 | C.dup(3); // xL q xR q xL q 36 | C.dup(1); // q xL q xR q xL q 37 | C.dup(0); // q q xL q xR q xL q 38 | C.dup(2); // xL q q xL q xR q xL q 39 | C.dup(0); // xL xL q q xL q xR q xL q 40 | C.mulmod(); // b=xL^2 q xL q xR q xL q 41 | C.dup(0); // b b q xL q xR q xL q 42 | C.mulmod(); // c=xL^4 xL q xR q xL q 43 | C.mulmod(); // d=xL^5 xR q xL q 44 | C.addmod(); // e=xL^5+xR xL q (for next round: xL xR q) 45 | 46 | for (let i=0; i new ethers.BigNumber.from(n.toString()) 10 | 11 | describe('MerkleTrees', function() { 12 | 13 | before(async () => { 14 | this.input = toBN('0x1111111111111111111111111111111111111111111111111111111111111111') 15 | 16 | this.merkleTreeV1 = await deployWithAbiAndBytecode( 17 | 'MerkleTreeWithHistoryV1.yul', 18 | merkleTreeV1.abi, 19 | merkleTreeV1.bytecode 20 | ) 21 | this.merkleTreeV2 = await deployWithAbiAndBytecode( 22 | 'MerkleTreeWithHistoryV2.yul', 23 | merkleTreeV2.abi, 24 | merkleTreeV2.bytecode 25 | ) 26 | this.merkleTreeV3 = await deployWithAbiAndBytecode( 27 | 'MerkleTreeWithHistoryV3.yul', 28 | merkleTreeV3.abi, 29 | merkleTreeV3.bytecode 30 | ) 31 | 32 | /* 33 | shockingly, zeros works, but `initialize` doesn't! (?) I'm lost 34 | */ 35 | // for (let i = 0; i < 32; i++) { 36 | // console.log(await this.merkleTreeV2.zeros(i)) 37 | // } 38 | }) 39 | 40 | it("MerkleTreeWithHistoryV1.yul::initialize should work", async () => { 41 | await this.merkleTreeV1.initialize(20) 42 | }) 43 | 44 | // it("MerkleTreeWithHistoryV2.yul::initialize should work", async () => { 45 | // await this.merkleTreeV2.initialize(20) 46 | // }) 47 | 48 | it("MerkleTreeWithHistoryV1.yul::insert should work", async () => { 49 | let result = await this.merkleTreeV1.insert(this.input) 50 | console.log('final gas used: ', 51 | (await result.wait()).gasUsed.toString() 52 | ) 53 | }) 54 | 55 | // it("MerkleTreeWithHistoryV2.yul::insert should work", async () => { 56 | // let result = await this.merkleTreeV2.insert(this.input) 57 | // console.log('final gas used: ', 58 | // (await result.wait()).gasUsed.toString() 59 | // ) 60 | // }) 61 | 62 | it("MerkleTreeWithHistoryV3.yul::insert should work", async () => { 63 | let result = await this.merkleTreeV3.insert(this.input) 64 | console.log('final gas used: ', 65 | (await result.wait()).gasUsed.toString() 66 | ) 67 | }) 68 | 69 | it("Both implementations should share the same last root", async () => { 70 | const v1LastRoot = await this.merkleTreeV1.getLastRoot() 71 | const v3LastRoot = await this.merkleTreeV3.getLastRoot() 72 | expect(v1LastRoot).to.be.equal(v3LastRoot) 73 | }) 74 | 75 | }) 76 | -------------------------------------------------------------------------------- /test/MiMCSponge.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai') 2 | const { ethers } = require('hardhat') 3 | const { 4 | deployContract, 5 | deployWithAbiAndBytecode 6 | } = require('../scripts/hardhat.utils.js') 7 | 8 | const { mimcsponge } = require('circomlib') 9 | const genContract = require('../scripts/mimcsponge_gencontract.js') 10 | 11 | const merkleTreeV1 = require('../remix/MerkleTreeWithHistoryV1.json') 12 | const merkleTreeV2 = require('../remix/MerkleTreeWithHistoryV2.json') 13 | 14 | const toBN = n => new ethers.BigNumber.from(n.toString()) 15 | 16 | describe('MiMCSponge', function() { 17 | 18 | before(async () => { 19 | const circomlibAbi = JSON.stringify(genContract.abi) 20 | const circomlibBytecode = genContract.createCode('mimcsponge', 220) 21 | this.mimcHasherCircomlib = await deployWithAbiAndBytecode( 22 | 'MiMCHasherCircomlib', circomlibAbi, circomlibBytecode 23 | ) 24 | this.mimcSponge = await deployWithAbiAndBytecode( 25 | 'MiMCSponge', 26 | merkleTreeV1.abi, 27 | merkleTreeV1.bytecode 28 | ) 29 | this.mimcSponge2 = await deployWithAbiAndBytecode( 30 | 'MiMCSponge2', 31 | merkleTreeV2.abi, 32 | merkleTreeV2.bytecode 33 | ) 34 | this.calldata = this.mimcSponge.interface.encodeFunctionData( 35 | 'MiMCSponge(uint,uint)', [1, 2] 36 | ) 37 | const { xL, xR } = mimcsponge.hash(1, 2, 0) 38 | this.xL = toBN(xL) 39 | this.xR = toBN(xR) 40 | }) 41 | 42 | after(async() => { 43 | const estimateCircomlib = await ethers.provider.send( 44 | 'eth_estimateGas', 45 | [{to: this.mimcHasherCircomlib.address, data: this.calldata}] 46 | ) 47 | const estimateMimcSponge = await ethers.provider.send( 48 | 'eth_estimateGas', 49 | [{to: this.mimcSponge.address, data: this.calldata}] 50 | ) 51 | const estimateMimcSponge2 = await ethers.provider.send( 52 | 'eth_estimateGas', 53 | [{to: this.mimcSponge2.address, data: this.calldata}] 54 | ) 55 | console.log('Circomlibjs::MiMCSponge gas estimate: ', 56 | toBN(estimateCircomlib).toString() 57 | ) 58 | console.log('MerkleTreeWithHistory.yul::MiMCSponge gas estimate: ', 59 | toBN(estimateMimcSponge).toString(), 60 | 'relative to circomlib: ', 61 | Number(toBN(estimateMimcSponge))/Number(toBN(estimateCircomlib)) 62 | ) 63 | console.log('MerkleTreeWithHistoryV2.yul::MiMCSponge gas estimate: ', 64 | toBN(estimateMimcSponge2).toString(), 65 | 'relative to circomlib: ', 66 | Number(toBN(estimateMimcSponge2))/Number(toBN(estimateCircomlib)) 67 | ) 68 | }) 69 | 70 | it("MiMCHasherCircomlib should match js implementation", async () => { 71 | const result = await this.mimcHasherCircomlib.MiMCSponge(1, 2) 72 | const xL = toBN(result.xL) 73 | const xR = toBN(result.xR) 74 | expect(xL).to.be.equal(this.xL) 75 | expect(xR).to.be.equal(this.xR) 76 | }) 77 | 78 | it("MerkleTreeWithHistory.yul::MiMCSponge should match js implementation", async () => { 79 | const result = await this.mimcSponge.MiMCSponge(1, 2) 80 | const xL = toBN(result.xL) 81 | const xR = toBN(result.xR) 82 | expect(xL).to.be.equal(this.xL) 83 | expect(xR).to.be.equal(this.xR) 84 | }) 85 | 86 | it("MerkleTreeWithHistoryV2.yul::MiMCSponge should match js implementation", async () => { 87 | const result = await this.mimcSponge2.MiMCSponge(1, 2) 88 | const xL = toBN(result.xL) 89 | const xR = toBN(result.xR) 90 | expect(xL).to.be.equal(this.xL) 91 | expect(xR).to.be.equal(this.xR) 92 | }) 93 | }) 94 | --------------------------------------------------------------------------------