├── .gas-snapshot ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── README.md ├── broadcast └── FrameVerifyTest.s.sol │ └── 8453 │ ├── run-1706546460.json │ ├── run-1706546628.json │ ├── run-1706546654.json │ ├── run-1706546684.json │ ├── run-1706546690.json │ ├── run-1706548145.json │ ├── run-1706548151.json │ └── run-latest.json ├── foundry.toml ├── src ├── Encoder.sol ├── FrameVerifier.sol ├── examples │ ├── ERC4337 │ │ ├── Account.sol │ │ ├── Paymaster.sol │ │ └── UserOperation.sol │ └── SharedVerifier.sol └── libraries │ ├── Blake3.sol │ ├── Ed25519.sol │ ├── Ed25519_pow.sol │ ├── ProtobufLib.sol │ └── Sha512.sol └── test └── FrameVerifier.t.sol /.gas-snapshot: -------------------------------------------------------------------------------- 1 | CounterTest:test() (gas: 1279650) -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/openzeppelin-contracts"] 5 | path = lib/openzeppelin-contracts 6 | url = https://github.com/openzeppelin/openzeppelin-contracts 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Inspired by [Farcaster-Solidity](https://github.com/pavlovdog/farcaster-solidity), a lib for building, encoding, and verifying Farcaster MessageData structs containing Frame actions. This might be useful, for example, if you want to use Frames to control a ERC-4337 account, and you want to do more than just check a valid signature. You could accept some fields from the caller, like fid, and populate others yourself: e.g. you could expect the url to match `user-op/:`, in order to verify something about the data that was signed. 2 | 3 | Code is not audited, provided as is. Use at your own risk :) 4 | 5 | 6 | ``` 7 | function test_EncodeAndVerify() public { 8 | MessageData memory md = MessageData({ 9 | type_: MessageType.MESSAGE_TYPE_FRAME_ACTION, 10 | fid: 64417, 11 | timestamp: 97190733, 12 | network: FarcasterNetwork.FARCASTER_NETWORK_TESTNET, 13 | frame_action_body: FrameActionBody({ 14 | url: hex"68747470733a2f2f6578616d706c652e636f6d", 15 | button_index: 1, 16 | cast_id: CastId({fid: 64417, hash: hex"e9eca527e4d2043b1f77b5b4d847d4f71172116b"}) 17 | }) 18 | }); 19 | assertEq( 20 | MessageDataCodec.encode(md), 21 | // result from hub monorepo 22 | hex"080d10a1f70318cd86ac2e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a08a1f7031214e9eca527e4d2043b1f77b5b4d847d4f71172116b" 23 | ); 24 | 25 | // from hub mono repo 26 | bytes memory sigHex = 27 | hex"17bdafddf9cf7464959a28d57fb5da7c596de4796f663588ea24d804c13ca043f46a546ca474d1b4420cc48e8720d8051786b21a689cdf485f78e51e36a12b05"; 28 | (bytes32 r, bytes32 s) = abi.decode(sigHex, (bytes32, bytes32)); 29 | bytes32 pk = 0x292404752ddd67080bbfe93af4017e51388ebc3c9fb96b8984658155de590b38; 30 | bool ret = FrameVerifier.verifyMessageData({public_key: pk, signature_r: r, signature_s: s, messageData: md}); 31 | assertTrue(ret); 32 | } 33 | ``` -------------------------------------------------------------------------------- /broadcast/FrameVerifyTest.s.sol/8453/run-1706546654.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": null, 5 | "transactionType": "CREATE", 6 | "contractName": "Blake3", 7 | "contractAddress": "0x1A683552a75b6D0601195aa0f0376EE880C42Eb1", 8 | "function": null, 9 | "arguments": null, 10 | "transaction": { 11 | "type": "0x02", 12 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 13 | "gas": "0x1d619f", 14 | "data": "0x6119d361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063227bb04d1461003a575b600080fd5b61004d610048366004611640565b610063565b60405161005a9190611702565b60405180910390f35b6060600061006f61009e565b905061007b81856100c3565b50610094610088826101bd565b8463ffffffff166101ec565b9150505b92915050565b6100a66114e2565b60006100b0610254565b90506100bd8160006102ba565b91505090565b6100cb6114e2565b60005b82518110156101b5578351610400906100e69061030f565b0361013e5760006101026100fd8660000151610331565b6103ab565b855160200151909150600090610119906001611767565b90506101268683836103e8565b6101398660200151828860800151610432565b865250505b600061014d856000015161030f565b61015990610400611788565b905060006101798284875161016e9190611788565b63ffffffff1661049a565b90506000610191868561018c818661179b565b6104b2565b90506101a1876000015182610576565b6101ab828561179b565b93505050506100ce565b509192915050565b6040805160208082528183019092526060916000919060208201818036833701905050905061009883826106df565b606082518267ffffffffffffffff16111561024e5760405162461bcd60e51b815260206004820152601d60248201527f4c656e6774682065786365656473206d657373616765206c656e67746800000060448201526064015b60405180910390fd5b50815290565b61025c611523565b506040805161010081018252636a09e667815263bb67ae856020820152633c6ef3729181019190915263a54ff53a606082015263510e527f6080820152639b05688c60a0820152631f83d9ab60c0820152635be0cd1960e082015290565b6102c26114e2565b6102ca611542565b6040518060a001604052806102e186600087610432565b8152602001858152602001828152602001600060ff1681526020018463ffffffff1681525091505092915050565b600081606001518260800151604061032791906117ae565b610098919061179b565b610339611570565b6103416115ab565b61034f836040015182610766565b6040518060a0016040528084600001518152602001828152602001846020015167ffffffffffffffff16815260200184606001518152602001600261039386610842565b8660a00151171763ffffffff16815250915050919050565b6103b3611523565b60006103d683600001518460200151856040015186606001518760800151610865565b90506103e181610b41565b9392505050565b600181166000036104235761040f6103ff84610ba5565b8385602001518660800151610bf1565b915060011c677fffffffffffffff166103e8565b61042d8383610c11565b505050565b61043a6115ca565b60408051818152606081018252600091602082018180368337019050506040805160c08101825296875267ffffffffffffffff90951660208701529385019390935250600060608401819052608084015263ffffffff1660a08301525090565b6000818310156104ab575081610098565b5080610098565b606060006104c08484611788565b905060008167ffffffffffffffff8111156104dd576104dd611616565b6040519080825280601f01601f191660200182016040528015610507576020820181803683370190505b50905060005b8281101561056c5786610520828861179b565b81518110610530576105306117c5565b602001015160f81c60f81b82828151811061054d5761054d6117c5565b60200101906001600160f81b031916908160001a90535060010161050d565b5095945050505050565b60005b815181101561042d576040836060015103610612576105966115ab565b6105a4846040015182610766565b6105d06105cb856000015183876020015160406105c08a610842565b8a60a0015117610865565b610b41565b8452608084018051600191906105e790839061179b565b9052506040805181815260608101825290602082018180368337505050604085015250600060608401525b6000836060015160406106259190611788565b9050600061063f8284865161063a9190611788565b61049a565b905060005b818110156106b65784610657828661179b565b81518110610667576106676117c5565b602001015160f81c60f81b8660400151876060015183610687919061179b565b81518110610697576106976117c5565b60200101906001600160f81b031916908160001a905350600101610644565b5080856060018181516106c9919061179b565b9052506106d6818461179b565b92505050610579565b60006106ee8360000151610331565b606084015190915060ff165b63ffffffff811615610756576107116001826117db565b905061074f84604001518263ffffffff1660368110610732576107326117c5565b6020020151610740846103ab565b86602001518760800151610c53565b91506106fa565b6107608284610d3e565b50505050565b6040825111158015610783575060048251610781919061180e565b155b6107ec5760405162461bcd60e51b815260206004820152603460248201527f4461746120627974657320697320746f6f206c6f6e6720746f20636f6e7665726044820152737420746f20313620342d6279746520776f72647360601b6064820152608401610245565b60005b600483516107fd9190611822565b81101561042d57610818836108138360046117ae565b610dae565b82826010811061082a5761082a6117c5565b63ffffffff90921660209290920201526001016107ef565b6000816080015160000361085857506001919050565b506000919050565b919050565b61086d6115ab565b6000610877610254565b90506108816115ab565b60005b60108110156108ce5787816010811061089f5761089f6117c5565b60200201518282601081106108b6576108b66117c5565b63ffffffff9092166020929092020152600101610884565b5060006040518061020001604052808a6000600881106108f0576108f06117c5565b6020908102919091015163ffffffff168252018a60016020908102919091015163ffffffff168252018a60026020908102919091015163ffffffff168252018a60036020908102919091015163ffffffff168252018a60046020908102919091015163ffffffff168252018a60056020908102919091015163ffffffff168252018a60066020908102919091015163ffffffff168252018a60076020908102919091015163ffffffff168252018460006020908102919091015163ffffffff168252018460016020908102919091015163ffffffff168252018460026020908102919091015163ffffffff168252018460036020908102919091015163ffffffff90811683528a811683830152908a901c81166040830152888116606083015287166080909101529050610a248183610e7c565b610a2d82610f64565b610a378183610e7c565b610a4082610f64565b610a4a8183610e7c565b610a5382610f64565b610a5d8183610e7c565b610a6682610f64565b610a708183610e7c565b610a7982610f64565b610a838183610e7c565b610a8c82610f64565b610a968183610e7c565b60005b6008811015610b345781610aae82600861179b565b60108110610abe57610abe6117c5565b6020020151828260108110610ad557610ad56117c5565b6020020180519190911863ffffffff169052898160088110610af957610af96117c5565b602002015182610b0a83600861179b565b60108110610b1a57610b1a6117c5565b6020020180519190911863ffffffff169052600101610a99565b5098975050505050505050565b610b49611523565b610b51611523565b60005b6008811015610b9e57838160108110610b6f57610b6f6117c5565b6020020151828260088110610b8657610b866117c5565b63ffffffff9092166020929092020152600101610b54565b5092915050565b610bad611523565b600182606001818151610bc09190611836565b60ff908116909152604084015160608501519092501660368110610be657610be66117c5565b602002015192915050565b610bf9611523565b610c086100fd86868686610c53565b95945050505050565b808260400151836060015160ff1660368110610c2f57610c2f6117c5565b602002015260608201805160019190610c4990839061184f565b60ff169052505050565b610c5b611570565b610c636115ab565b60005b6008811015610cb057868160088110610c8157610c816117c5565b6020020151828260108110610c9857610c986117c5565b63ffffffff9092166020929092020152600101610c66565b5060085b6010811015610d085785610cc9600883611788565b60088110610cd957610cd96117c5565b6020020151828260108110610cf057610cf06117c5565b63ffffffff9092166020929092020152600101610cb4565b506040805160a081018252948552602085019190915260008482015260608401525060041763ffffffff16608082015292915050565b6000610d6183600001518460200151600086606001516008886080015117610865565b905060005b60088163ffffffff16101561076057610da6828263ffffffff1660108110610d9057610d906117c5565b602002015184610da1846004611868565b61102c565b600101610d66565b6000610dbb82600461179b565b83511015610e0b5760405162461bcd60e51b815260206004820152601f60248201527f6c655f62797465735f6765745f75696e7433325f6f75744f66426f756e6473006044820152606401610245565b6000805b6004811015610e7457610e238160086117ae565b8585610e30846003611788565b610e3a919061179b565b81518110610e4a57610e4a6117c5565b0160200151610e6a916001600160f81b0319909116901c60e01c83611890565b9150600101610e0f565b509392505050565b610e9d82600060046008600c868460200201518760015b60200201516110a1565b610eb982600160056009600d8660026020020151876003610e93565b610ed58260026006600a600e8660046020020151876005610e93565b610ef18260036007600b600f8660066020020151876007610e93565b610f0d8260006005600a600f8660086020020151876009610e93565b610f298260016006600b600c86600a602002015187600b610e93565b610f4582600260076008600d86600c602002015187600d610e93565b610f6082600360046009600e8681602002015187600f610e93565b5050565b6000610f6e61141f565b9050610f786115ab565b60005b6010811015610fde5783838260108110610f9757610f976117c5565b602002015160ff1660108110610faf57610faf6117c5565b6020020151828260108110610fc657610fc66117c5565b63ffffffff9092166020929092020152600101610f7b565b5060005b601081101561076057818160108110610ffd57610ffd6117c5565b6020020151848260108110611014576110146117c5565b63ffffffff9092166020929092020152600101610fe2565b60005b6004811015610760576110438160086117ae565b61104e906002611991565b61105e9063ffffffff8616611822565b60f81b836110728363ffffffff861661179b565b81518110611082576110826117c5565b60200101906001600160f81b031916908160001a90535060010161102f565b81878663ffffffff16601081106110ba576110ba6117c5565b6020020151888863ffffffff16601081106110d7576110d76117c5565b60200201510101878763ffffffff16601081106110f6576110f66117c5565b602002019063ffffffff16908163ffffffff1681525050611152878763ffffffff1660108110611128576111286117c5565b6020020151888563ffffffff1660108110611145576111456117c5565b60200201511860106114ad565b878463ffffffff166010811061116a5761116a6117c5565b602002019063ffffffff16908163ffffffff1681525050868363ffffffff1660108110611199576111996117c5565b6020020151878563ffffffff16601081106111b6576111b66117c5565b602002015101878563ffffffff16601081106111d4576111d46117c5565b602002019063ffffffff16908163ffffffff1681525050611230878563ffffffff1660108110611206576112066117c5565b6020020151888763ffffffff1660108110611223576112236117c5565b602002015118600c6114ad565b878663ffffffff1660108110611248576112486117c5565b602002019063ffffffff16908163ffffffff168152505080878663ffffffff1660108110611278576112786117c5565b6020020151888863ffffffff1660108110611295576112956117c5565b60200201510101878763ffffffff16601081106112b4576112b46117c5565b602002019063ffffffff16908163ffffffff1681525050611310878763ffffffff16601081106112e6576112e66117c5565b6020020151888563ffffffff1660108110611303576113036117c5565b60200201511860086114ad565b878463ffffffff1660108110611328576113286117c5565b602002019063ffffffff16908163ffffffff1681525050868363ffffffff1660108110611357576113576117c5565b6020020151878563ffffffff1660108110611374576113746117c5565b602002015101878563ffffffff1660108110611392576113926117c5565b602002019063ffffffff16908163ffffffff16815250506113ee878563ffffffff16601081106113c4576113c46117c5565b6020020151888763ffffffff16601081106113e1576113e16117c5565b60200201511860076114ad565b878663ffffffff1660108110611406576114066117c5565b63ffffffff909216602092909202015250505050505050565b6114276115ab565b5060408051610200810182526002815260066020820152600391810191909152600a606082015260076080820152600060a0820152600460c0820152600d60e08201526001610100820152600b610120820152600c61014082015260056101608201526009610180820152600e6101a0820152600f6101c082015260086101e082015290565b600060e083901b6114bf836020611836565b6001600160e01b031990911660ff84811682901c92161b1760e01c905092915050565b6040518060a001604052806114f56115ca565b8152602001611502611523565b815260200161150f611542565b815260006020820181905260409091015290565b6040518061010001604052806008906020820280368337509192915050565b604051806106c001604052806036905b61155a611523565b8152602001906001900390816115525790505090565b6040518060a00160405280611583611523565b81526020016115906115ab565b81526000602082018190526040820181905260609091015290565b6040518061020001604052806010906020820280368337509192915050565b6040518060c001604052806115dd611523565b8152602001600067ffffffffffffffff168152602001606081526020016000815260200160008152602001600063ffffffff1681525090565b634e487b7160e01b600052604160045260246000fd5b803563ffffffff8116811461086057600080fd5b6000806040838503121561165357600080fd5b823567ffffffffffffffff8082111561166b57600080fd5b818501915085601f83011261167f57600080fd5b81358181111561169157611691611616565b604051601f8201601f19908116603f011681019083821181831017156116b9576116b9611616565b816040528281528860208487010111156116d257600080fd5b8260208601602083013760006020848301015280965050505050506116f96020840161162c565b90509250929050565b60006020808352835180602085015260005b8181101561173057858101830151858201604001528201611714565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b67ffffffffffffffff818116838216019080821115610b9e57610b9e611751565b8181038181111561009857610098611751565b8082018082111561009857610098611751565b808202811582820484141761009857610098611751565b634e487b7160e01b600052603260045260246000fd5b63ffffffff828116828216039080821115610b9e57610b9e611751565b634e487b7160e01b600052601260045260246000fd5b60008261181d5761181d6117f8565b500690565b600082611831576118316117f8565b500490565b60ff828116828216039081111561009857610098611751565b60ff818116838216019081111561009857610098611751565b63ffffffff81811683821602808216919082811461188857611888611751565b505092915050565b63ffffffff818116838216019080821115610b9e57610b9e611751565b600181815b808511156118e85781600019048211156118ce576118ce611751565b808516156118db57918102915b93841c93908002906118b2565b509250929050565b6000826118ff57506001610098565b8161190c57506000610098565b8160018114611922576002811461192c57611948565b6001915050610098565b60ff84111561193d5761193d611751565b50506001821b610098565b5060208310610133831016604e8410600b841016171561196b575081810a610098565b61197583836118ad565b806000190482111561198957611989611751565b029392505050565b60006103e183836118f056fea26469706673582212201c18d5fbc7fc9d90f69217328033c6549ba9b718ba8a9ddd94f595ffc6c485ab64736f6c63430008180033", 15 | "nonce": "0x10", 16 | "accessList": [] 17 | }, 18 | "additionalContracts": [], 19 | "isFixedGasLimit": false 20 | }, 21 | { 22 | "hash": null, 23 | "transactionType": "CREATE", 24 | "contractName": "Ed25519_pow", 25 | "contractAddress": "0x687372443cD062c22266c0f33A3cd8b4B6FC3C0c", 26 | "function": null, 27 | "arguments": null, 28 | "transaction": { 29 | "type": "0x02", 30 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 31 | "gas": "0x104fc3", 32 | "data": "0x610de461003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80631d9b5e6f1461003a575b600080fd5b61004d610048366004610d95565b610066565b6040805192835260208301919091520160405180910390f35b6000806013600160ff1b0383840990506013600160ff1b0381820991506013600160ff1b03836013600160ff1b038485090991506013600160ff1b0381830990506013600160ff1b03826013600160ff1b0383840909915060006013600160ff1b0383840990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381840992506013600160ff1b0383840990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b03818409905060006013600160ff1b0382830990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382850993506013600160ff1b0384850991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382850991506013600160ff1b0382830990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381820990506013600160ff1b0381830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382850993505050915091565b600060208284031215610da757600080fd5b503591905056fea264697066735822122061be3e8c6914c4c01260fa88f12a8c4009117d588f4d8c4a7fb25dd42db4ac2a64736f6c63430008180033", 33 | "nonce": "0x11", 34 | "accessList": [] 35 | }, 36 | "additionalContracts": [], 37 | "isFixedGasLimit": false 38 | }, 39 | { 40 | "hash": null, 41 | "transactionType": "CREATE", 42 | "contractName": "Sha512", 43 | "contractAddress": "0xA0711Ef69e5ED96E31C1dC79fBb25abdDFe8FA5a", 44 | "function": null, 45 | "arguments": null, 46 | "transaction": { 47 | "type": "0x02", 48 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 49 | "gas": "0x12035f", 50 | "data": "0x610f7461003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063aa1e84de1461003a575b600080fd5b61004d610048366004610d50565b610063565b60405161005a9190610e00565b60405180910390f35b61006b610cdd565b6040805161010081018252676a09e667f3bcc908815267bb67ae8584caa73b6020820152673c6ef372fe94f82b9181019190915267a54ff53a5f1d36f1606082015267510e527fade682d16080820152679b05688c2b3e6c1f60a0820152671f83d9abfb41bd6b60c0820152675be0cd19137e217960e08201526000806100f0610cfc565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260408051610a008101825267428a2f98d728ae228152677137449123ef65cd602082015267b5c0fbcfec4d3b2f9181019190915267e9b5dba58189dbbc6060820152673956c25bf348b53860808201526759f111f1b605d01960a082015267923f82a4af194f9b60c082015267ab1c5ed5da6d811860e082015267d807aa98a30302426101008201526712835b0145706fbe61012082015267243185be4ee4b28c61014082015267550c7dc3d5ffb4e26101608201526772be5d74f27b896f6101808201526780deb1fe3b1696b16101a0820152679bdc06a725c712356101c082015267c19bf174cf6926946101e082015267e49b69c19ef14ad261020082015267efbe4786384f25e3610220820152670fc19dc68b8cd5b561024082015267240ca1cc77ac9c65610260820152672de92c6f592b0275610280820152674a7484aa6ea6e4836102a0820152675cb0a9dcbd41fbd46102c08201526776f988da831153b56102e082015267983e5152ee66dfab61030082015267a831c66d2db4321061032082015267b00327c898fb213f61034082015267bf597fc7beef0ee461036082015267c6e00bf33da88fc261038082015267d5a79147930aa7256103a08201526706ca6351e003826f6103c082015267142929670a0e6e706103e08201526727b70a8546d22ffc610400820152672e1b21385c26c926610420820152674d2c6dfc5ac42aed6104408201526753380d139d95b3df61046082015267650a73548baf63de61048082015267766a0abb3c77b2a86104a08201526781c2c92e47edaee66104c08201526792722c851482353b6104e082015267a2bfe8a14cf1036461050082015267a81a664bbc42300161052082015267c24b8b70d0f8979161054082015267c76c51a30654be3061056082015267d192e819d6ef521861058082015267d69906245565a9106105a082015267f40e35855771202a6105c082015267106aa07032bbd1b86105e08201526719a4c116b8d2d0c8610600820152671e376c085141ab53610620820152672748774cdf8eeb996106408201526734b0bcb5e19b48a861066082015267391c0cb3c5c95a63610680820152674ed8aa4ae3418acb6106a0820152675b9cca4f7763e3736106c082015267682e6ff3d6b2b8a36106e082015267748f82ee5defb2fc6107008201526778a5636f43172f606107208201526784c87814a1f0ab72610740820152678cc702081a6439ec6107608201526790befffa23631e2861078082015267a4506cebde82bde96107a082015267bef9a3f7b2c679156107c082015267c67178f2e372532b6107e082015267ca273eceea26619c61080082015267d186b8c721c0c20761082082015267eada7dd6cde0eb1e61084082015267f57d4f7fee6ed1786108608201526706f067aa72176fba610880820152670a637dc5a2c898a66108a082015267113f9804bef90dae6108c0820152671b710b35131c471b6108e08201526728db77f523047d846109008201526732caab7b40c72493610920820152673c9ebe0a15c9bebc61094082015267431d67c49c100d4c610960820152674cc5d4becb3e42b661098082015267597f299cfc657e2a6109a0820152675fcb6fab3ad6faec6109c0820152676c44198c4a4758176109e082015260006105ee8961091d565b905060005b608082518161060457610604610e3b565b0481101561090f5760006106188383610b26565b89516001600160401b0390811687526020808c01518216908801526040808c01518216908801526060808c01518216908801526080808c015182169088015260a0808c015182169088015260c0808c015182169088015260e0808c015190911690870152905060005b60508110156108745760108110156106d4578181601081106106a5576106a5610e51565b60200201518782605081106106bc576106bc610e51565b6001600160401b039092166020929092020152610775565b8660108203605081106106e9576106e9610e51565b602002015161071088600f84036050811061070657610706610e51565b6020020151610bb8565b88600784036050811061072557610725610e51565b602002015161074c8a600286036050811061074257610742610e51565b6020020151610be7565b01010187826050811061076157610761610e51565b6001600160401b0390921660209290920201525b86816050811061078757610787610e51565b602002015185826050811061079e5761079e610e51565b60200201516107c688608001518960a001518a60c001516001600160401b0383181691161890565b6107d38960800151610c0e565b8960e001510101010198506107ff86600001518760200151886040015180821690831691909216181890565b865161080a90610c31565b60c0880180516001600160401b0390811660e08b015260a08a018051821690925260808a018051821690925260608a0180518e01821690925260408a018051821690925260208a01805182169092528951811690915291018a810190911687529750600101610681565b5050835188516001600160401b03910181168952602080860151908a01805190910182169052604080860151908a01805190910182169052606080860151908a01805190910182169052608080860151908a0180519091018216905260a080860151908a0180519091018216905260c080860151908a0180519091018216905260e080860151908a01805190910190911690526001016105f3565b509598975050505050505050565b606060006080835161092f9190610e67565b61093a906080610e9f565b905060706080845161094c9190610e67565b1061096e576080835161095f9190610e67565b61096b90610100610e9f565b90505b600081845161097d9190610eb2565b6001600160401b0381111561099457610994610d3a565b6040519080825280601f01601f1916602001820160405280156109be576020820181803683370190505b50905060005b8451811015610a1b578481815181106109df576109df610e51565b602001015160f81c60f81b8282815181106109fc576109fc610e51565b60200101906001600160f81b031916908160001a9053506001016109c4565b50608060f81b81855181518110610a3457610a34610e51565b60200101906001600160f81b031916908160001a905350600084516008610a5b9190610ec5565b60408051608083901b6fffffffffffffffffffffffffffffffff1916602082015281516010818303018152603090910190915290915060005b8151811015610b1b57818160018451610aad9190610e9f565b610ab79190610e9f565b81518110610ac757610ac7610e51565b602001015160f81c60f81b848260018751610ae29190610e9f565b610aec9190610e9f565b81518110610afc57610afc610e51565b60200101906001600160f81b031916908160001a905350600101610a94565b509195945050505050565b610b2e610d1b565b610b36610d1b565b60005b60108160ff161015610bae57610b7185610b54836008610edc565b60ff16610b62876080610ec5565b610b6c9190610eb2565b610c54565b60c01c828260ff1660108110610b8957610b89610e51565b6001600160401b03909216602092909202015280610ba681610eff565b915050610b39565b5090505b92915050565b60006701ffffffffffffff600783901c16610bd4836008610ca7565b610bdf846001610ca7565b181892915050565b60006703ffffffffffffff600683901c16610c0383603d610ca7565b610bdf846013610ca7565b6000610c1b826029610ca7565b610c26836012610ca7565b610bdf84600e610ca7565b6000610c3e826027610ca7565b610c49836022610ca7565b610bdf84601c610ca7565b60008060005b6008811015610bae57610c6e816008610ec5565b85610c798387610eb2565b81518110610c8957610c89610e51565b01602001516001600160f81b031916901c9190911790600101610c5a565b60006001600160401b038316821c610cc0836040610e9f565b846001600160401b0316901b610cd69190610f1e565b9392505050565b6040518061010001604052806008906020820280368337509192915050565b60405180610a0001604052806050906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610d6257600080fd5b81356001600160401b0380821115610d7957600080fd5b818401915084601f830112610d8d57600080fd5b813581811115610d9f57610d9f610d3a565b604051601f8201601f19908116603f01168101908382118183101715610dc757610dc7610d3a565b81604052828152876020848701011115610de057600080fd5b826020860160208301376000928101602001929092525095945050505050565b6101008101818360005b6008811015610e325781516001600160401b0316835260209283019290910190600101610e0a565b50505092915050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600082610e8457634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bb257610bb2610e89565b80820180821115610bb257610bb2610e89565b8082028115828204841417610bb257610bb2610e89565b60ff8181168382160290811690818114610ef857610ef8610e89565b5092915050565b600060ff821660ff8103610f1557610f15610e89565b60010192915050565b6001600160401b03818116838216019080821115610ef857610ef8610e8956fea26469706673582212203e7429792f50f9e9f1cc44f35714b460d4fd7590cf36c21493be9d1bf6dd499264736f6c63430008180033", 51 | "nonce": "0x12", 52 | "accessList": [] 53 | }, 54 | "additionalContracts": [], 55 | "isFixedGasLimit": false 56 | }, 57 | { 58 | "hash": null, 59 | "transactionType": "CREATE", 60 | "contractName": "Ed25519", 61 | "contractAddress": "0x880B037c449E587d16C6bC45CcF14B2BE80e57B1", 62 | "function": null, 63 | "arguments": null, 64 | "transaction": { 65 | "type": "0x02", 66 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 67 | "gas": "0x20f8c4", 68 | "data": "0x611d3261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80632bf6eda81461003a575b600080fd5b61004d610048366004611b17565b610061565b604051901515815260200160405180910390f35b80516000908190819060400167ffffffffffffffff81111561008557610085611ad0565b6040519080825280601f01601f1916602001820160405280156100af576020820181803683370190505b50905060005b6020811015610105578681602081106100d0576100d0611bc9565b1a60f81b8282815181106100e6576100e6611bc9565b60200101906001600160f81b031916908160001a9053506001016100b5565b5060005b602081101561015c5787816020811061012457610124611bc9565b1a60f81b82826020018151811061013d5761013d611bc9565b60200101906001600160f81b031916908160001a905350600101610109565b5060005b84518110156101ba5784818151811061017b5761017b611bc9565b602001015160f81c60f81b82826040018151811061019b5761019b611bc9565b60200101906001600160f81b031916908160001a905350600101610160565b5060405163550f426f60e11b815260009073a0711ef69e5ed96e31c1dc79fbb25abddfe8fa5a9063aa1e84de906101f5908590600401611bdf565b61010060405180830381865af4158015610213573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102379190611c2e565b9050600060c0826003602002015167ffffffffffffffff16901b6080836002602002015167ffffffffffffffff16901b6040846001602002015167ffffffffffffffff16901b846000602002015167ffffffffffffffff1617171790506008817fff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0016901c6008827eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff16901b1790506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c6010827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff16901b1790506020817bffffffff00000000ffffffff00000000ffffffff00000000ffffffff1916901c6020827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16901b179050600060c08360076008811061039457610394611bc9565b602002015167ffffffffffffffff16901b6080846006602002015167ffffffffffffffff16901b6040856005602002015167ffffffffffffffff16901b856004602002015167ffffffffffffffff1617171790506008817fff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0016901c6008827eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff16901b1790506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c6010827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff16901b1790506020817bffffffff00000000ffffffff00000000ffffffff00000000ffffffff1916901c6020827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16901b1790506f14def9dea2f79cd65812631a5cf5d3ed600160fc1b01806104f5576104f5611cc2565b6f14def9dea2f79cd65812631a5cf5d3ed600160fc1b017f0ffffffffffffffffffffffffffffffec6ef5bf4737dcf70d6ec31748d98951d8309830867ffffffff0000000063ffffffff60a01b017dff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0060088d811b9182167cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff9e90911c9d8e1617601090811b7fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000009092167eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000909e169d909d17909c1c9b909b17602081811b9c8d1663ffffffff63ffffffff60801b019290911c91821617604090811b600163ffffffff60601b01600160e01b0319909d1663ffffffff60401b63ffffffff60c01b0190921691909117901c9a909a17608081811b91901c17999450506001600160ff1b0389169250600091508190506013600160ff1b03838409905060006013600160ff1b036014600160ff1b038308905060006013600160ff1b037f52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a38409600101905060006013600160ff1b03828409604051631d9b5e6f60e01b81526004810182905290915073687372443cd062c22266c0f33a3cd8b4b6fc3c0c90631d9b5e6f906024016040805180830381865af4158015610711573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107359190611cd8565b5094506013600160ff1b0385860994506013600160ff1b0380826013600160ff1b0388890909840994506013600160ff1b03826013600160ff1b038788090990508281146107cb57826013600160ff1b0303811461079d576000975050505050505050611a4f565b6013600160ff1b037f2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0860994505b5050505060ff88901c60018216146107e7576013600160ff1b03035b67ffffffff0000000063ffffffff60a01b017dff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00600888811b9182167cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff9990911c98891617601090811b7fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0000009092167eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff00009099169890981790971c96909617602081811b97881663ffffffff63ffffffff60801b019290911c91821617604090811b600163ffffffff60601b01600160e01b031990981663ffffffff60401b63ffffffff60c01b0190921691909117901c95909517608081811b91901c17946f14def9dea2f79cd65812631a5cf5d3ed600160fc1b0186106109265760009350505050611a4f565b600080600080610934611a57565b8587016013600160ff1b038789038101906000907f2406d9dc56dffce7198e80f2eef3d13000e0149a8283b156ebd69b9426b2f1596013600160ff1b038c8c09099050898960018060006013600160ff1b03828509905060006013600160ff1b03848709905060006013600160ff1b03848609905060006013600160ff1b03848509905060006013600160ff1b03848509905060006013600160ff1b03858709905060006013600160ff1b03858609905081820199508383036013600160ff1b030198508284019a506013600160ff1b0380610a1257610a12611cc2565b89602519038283010897505050505050505060006013600160ff1b0380610a3b57610a3b611cc2565b828509905060006013600160ff1b03848709905060006013600160ff1b03848609905060006013600160ff1b03848509905060006013600160ff1b03848509905060006013600160ff1b03858709905060006013600160ff1b03858609905081820199508383036013600160ff1b030198508284019a506013600160ff1b0380610ac757610ac7611cc2565b89602519038283010897505050505050505060006013600160ff1b0380610af057610af0611cc2565b828509905060006013600160ff1b03848709905060006013600160ff1b03848609905060006013600160ff1b03848509905060006013600160ff1b03848509905060006013600160ff1b03858709905060006013600160ff1b03858609905081820199508383036013600160ff1b030198508284019a506013600160ff1b0380610b7c57610b7c611cc2565b8960251903828301089750600196508e955060009450505050505b6000808080806013600160ff1b03898c09905060006013600160ff1b038b8e09905060006013600160ff1b038b8d0990506013600160ff1b038e8e0960208a0151518484019850939092036013600160ff1b030195509093508001915084908660088110610c0757610c07611bc9565b6020020152828660016020020151600160200201518660088110610c2d57610c2d611bc9565b60200201526013600160ff1b037f2406d9dc56dffce7198e80f2eef3d13000e0149a8283b156ebd69b9426b2f15983096020870151604001518660088110610c7757610c77611bc9565b602002015285515181908660088110610c9257610c92611bc9565b6020020152868660006020020151600160200201518660088110610cb857610cb8611bc9565b60200201526013600160ff1b03818809965084600703610cdb5750505050610d5e565b60006013600160ff1b038f8609905060006013600160ff1b038f8609905060006013600160ff1b038f860990508183036013600160ff1b03019c506013600160ff1b0380610d2b57610d2b611cc2565b8185088383019e509b506013600160ff1b03816013600160ff1b030385089a505060019096019550610b97945050505050565b50604051631d9b5e6f60e01b81526004810183905260009073687372443cd062c22266c0f33a3cd8b4b6fc3c0c90631d9b5e6f906024016040805180830381865af4158015610db1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd59190611cd8565b90935090506013600160ff1b0383840992506013600160ff1b0383840992506013600160ff1b0383840992506013600160ff1b0383840992506013600160ff1b0383840992506013600160ff1b03818409925060075b8251602001516000906013600160ff1b03908360088110610e4e57610e4e611bc9565b602002015186096020850151519091506013600160ff1b039082908460088110610e7a57610e7a611bc9565b6020020151096020850151518360088110610e9757610e97611bc9565b60200201526013600160ff1b03818560016020020151600160200201518460088110610ec557610ec5611bc9565b60200201510960208086015101518360088110610ee457610ee4611bc9565b60200201526013600160ff1b03818560016020020151600260200201518460088110610f1257610f12611bc9565b6020020151096020850151604001518360088110610f3257610f32611bc9565b60200201526000829003610f465750610f76565b8351516013600160ff1b03908360088110610f6357610f63611bc9565b6020020151860994505060001901610e2b565b5060405180606001604052806040518061010001604052807f43e7ce9d19ea5d329385a44c321ea16167c996e37dc6070c97de49e37ac61db981526020017f40cff34425d8ec30a3bb74ba58cd5854fa1e38186ad0d31ebc8ae251ceb2c97e81526020017f459bd27046e8dd45aea7008db87a5a8f7906779253d64523589518599fdfbf4b81526020017f69fdd1e28c23cc3894d0c8ff90e76f6d5b6e4c2e620136d04dd83c4a51581ab981526020017f54dceb3413ce5cfa11196dfc960b6edaf4b380c6d4d2378419cc0279ba49c5f381526020017f4e24184dd71a3d77eef3729f7f8cf7c17224cf40aa7b9548b9942f3c5084ceed81526020017f5a0e5aab20262674ae1175761cbf5e889b52a55fd7ac5027c228cebdc8d2360a81526020017f26239334073e9b38c62859556d451c3dcc8d30e84b361174f488eadde2cf17d981525081526020016040518061010001604052807f227e97c94c7c0933d2e0c21a3447c504fe9ccf82e8a05f59ce881c82eba0489f81526020017f226a3e0ecc4afec6fd0d288413014a9dbddecf06c1a2f0bb702ba77c613d820981526020017f34d7efc851d45c5e71efeb0f235b794691de6228877569b3a8d52bf058b8a4a081526020017f3c1f5fb3ca7166fce1471c9b752b6d28c56301ad7b65e8451b2c8c5526726e1281526020017f6102416cf02f02ff5be75275f55f28db89b2a9d2456b860ce22fc0e5031f7cc581526020017f40adf677f1bfdae057f0fd179c12617918ddaa2891a6530fb1a4294fa866549081526020017f61936f3c415609046187b8baa978cbc9b47893363ae5a3cc7d909f3635ae7f4881526020017f562a9662b6ec47f9e979d473c02b51e4423368238c58ddb52f0e5c6a180e641081525081526020016040518061010001604052807f3788bdb44f8632d42d0dbee5eea1acc6136cf411e655624f55e48902c3bd553481526020017f6190cf2c2a7b5ad769d594a82844f23b4167fa7c8ac30e51aa6cfbebdcd4b94581526020017f65f7787096be9204123a71f3ac88a87be1513217737d6a1e2f3a13a43d7e3a9a81526020017f023af32dbfa67975536479a7a7ce74a02142147fac0480187f1f13349cda1f2d81526020017f64fc44b7fc6841bddb0ced8b8b0fe6759137ef87ee96651215fc1dbcd25c64dc81526020017f1434aa3748b701d5b69df3d7d340c1fe3f6b9c1efc617484caadb47e382f447581526020017f457a6da8c962ef35f2b217423e5844e9d23534527e8ea4290d24e3ddf21720c681526020017f63b9540ceb60ccb51e4d989d956e053cf2511837efb79089d2ff40284202c53d8152508152508260006002811061135057611350611bc9565b602002018190525050505050505050505050600060038c60001c901b90506000897f80000000000000000000000000000000a6f7cef517bce6b2c09318d2e7ae9f6001905060008060019050600060019050600060019050600060fc90505b6008811b878116156114f1576000808080806013600160ff1b03888c09905060006013600160ff1b038b8b09905081810195508181036013600160ff1b030194506013600160ff1b038061140557611405611cc2565b898c0993506013600160ff1b038a8d09925050506000868d901c6007169050866007901b198d169c5060008e905060006013600160ff1b038061144a5761144a611cc2565b825160200151846008811061146157611461611bc9565b602002015187098251519091506000906013600160ff1b0390856008811061148b5761148b611bc9565b602002015189098351604001519091506000906013600160ff1b039086600881106114b8576114b8611bc9565b6020020151870990508282036013600160ff1b03019e508087019d508282019c508087036013600160ff1b03019b505050505050505050505b8681161561162a576000808080806013600160ff1b03888c09905060006013600160ff1b038b8b09905081810195508181036013600160ff1b030194506013600160ff1b038061154357611543611cc2565b898c0993506013600160ff1b038a8d096007808a1b198f169e91945090891c1691508e905060006013600160ff1b03826001602002015160006020020151846008811061159257611592611bc9565b6020020151870960208084015101519091506000906013600160ff1b039085600881106115c1576115c1611bc9565b602002015189096020840151604001519091506000906013600160ff1b039086600881106115f1576115f1611bc9565b6020020151870990508282036013600160ff1b03019e508087036013600160ff1b03019d508282019c508087019b505050505050505050505b8160000361175c576000808080806013600160ff1b03888c09905060006013600160ff1b038b8b09905081810195508181036013600160ff1b030194506013600160ff1b038061167c5761167c611cc2565b898c0993506013600160ff1b038a8d099250505060078b168d60006013600160ff1b0382600160200201516000602002015184600881106116bf576116bf611bc9565b6020020151870960208084015101519091506000906013600160ff1b039085600881106116ee576116ee611bc9565b602002015189096020840151604001519091506000906013600160ff1b0390866008811061171e5761171e611bc9565b6020020151870990508282036013600160ff1b03019e508087036013600160ff1b03019d508282019c508087019b5050505050505050505050611812565b60006013600160ff1b03848809905060006013600160ff1b03878709905060006013600160ff1b03868909905060006013600160ff1b03848509905060006013600160ff1b03848509905060006013600160ff1b03858709905060006013600160ff1b0385860990508182019c508383036013600160ff1b03019b508284019a506013600160ff1b03806117f2576117f2611cc2565b8c602519038283010899505060001990970196506113af95505050505050565b50929950909750955093506000915081905073687372443cd062c22266c0f33a3cd8b4b6fc3c0c631d9b5e6f6013600160ff1b038689096040518263ffffffff1660e01b815260040161186791815260200190565b6040805180830381865af4158015611883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a79190611cd8565b915091506013600160ff1b03806118c0576118c0611cc2565b82830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0382830991506013600160ff1b0381830991506013600160ff1b0380858409880996506013600160ff1b0380878409860967ffffffff0000000063ffffffff60a01b017dff000000ff000000ff000000ff000000ff000000ff000000ff000000ff0060ff9990991b909117600881811b998a167cff000000ff000000ff000000ff000000ff000000ff000000ff000000ff9290911c91821617601090811b7fff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000000909a167eff000000ff000000ff000000ff000000ff000000ff000000ff000000ff000090921691909117901c97909717602081811b98891663ffffffff63ffffffff60801b019290911c91821617604090811b600163ffffffff60601b01600160e01b031990991663ffffffff60401b63ffffffff60c01b0190921691909117901c96909617608081811b91901c178d1499505050505050505050505b949350505050565b60405180604001604052806002905b611a6e611a84565b815260200190600190039081611a665790505090565b60405180606001604052806003905b611a9b611ab1565b815260200190600190039081611a935790505090565b6040518061010001604052806008906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611b0f57611b0f611ad0565b604052919050565b60008060008060808587031215611b2d57600080fd5b84359350602080860135935060408601359250606086013567ffffffffffffffff80821115611b5b57600080fd5b818801915088601f830112611b6f57600080fd5b813581811115611b8157611b81611ad0565b611b93601f8201601f19168501611ae6565b91508082528984828501011115611ba957600080fd5b808484018584013760008482840101525080935050505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60006020808352835180602085015260005b81811015611c0d57858101830151858201604001528201611bf1565b506000604082860101526040601f19601f8301168501019250505092915050565b6000610100808385031215611c4257600080fd5b83601f840112611c5157600080fd5b60405181810167ffffffffffffffff8282108183111715611c7457611c74611ad0565b81604052829150838601935086841115611c8d57600080fd5b855b84811015611cb65780518281168114611ca85760008081fd5b835260209283019201611c8f565b50919695505050505050565b634e487b7160e01b600052601260045260246000fd5b60008060408385031215611ceb57600080fd5b50508051602090910151909290915056fea264697066735822122042a10eef23076fe21108641c0873e215e3c8b798a1dc998ca570a0c70ca9dfa064736f6c63430008180033", 69 | "nonce": "0x13", 70 | "accessList": [] 71 | }, 72 | "additionalContracts": [], 73 | "isFixedGasLimit": false 74 | }, 75 | { 76 | "hash": null, 77 | "transactionType": "CREATE", 78 | "contractName": "FarcasterSolidity", 79 | "contractAddress": "0x461Bf1372db198ec5a9B747FAFb8f39514D12e93", 80 | "function": null, 81 | "arguments": null, 82 | "transaction": { 83 | "type": "0x02", 84 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 85 | "gas": "0x3ff9e9", 86 | "data": "0x61396a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806369c20bdd1461003a575b600080fd5b81801561004657600080fd5b5061005a61005536600461369e565b61005c565b005b600061006a858585856100a6565b9050600d8151600d8111156100815761008161373a565b1461009f57604051635b60892f60e01b815260040160405180910390fd5b5050505050565b6100ae613450565b60405163227bb04d60e01b8152600090731a683552a75b6d0601195aa0f0376ee880c42eb19063227bb04d906100eb9086906014906004016137a0565b600060405180830381865af4158015610108573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261013091908101906137c8565b9050600073880b037c449e587d16c6bc45ccf14b2be80e57b1632bf6eda8888888866040518563ffffffff1660e01b8152600401610171949392919061383e565b602060405180830381865af415801561018e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b2919061386d565b9050806101d257604051638baa579f60e01b815260040160405180910390fd5b6000806101e26000878851610211565b925050915081610205576040516356a6881560e11b815260040160405180910390fd5b98975050505050505050565b60008061021c613450565b610224613450565b6000876001600160401b03811661023b88836138ac565b6001600160401b0316101561025a576000955093509091506103999050565b6001600160401b03871661026e8a836138d3565b6001600160401b0316101561035c57600080600061028c848c6103a2565b9196509194509092509050826102b057506000975091955092935061039992505050565b6010826001600160401b031611156102d657506000975091955092935061039992505050565b846001600160401b0316826001600160401b03161161030357506000975091955092935061039992505050565b61030d8282610494565b92508261032857506000975091955092935061039992505050565b610335848c8c858a610636565b945092508261035257506000975091955092935061039992505050565b50925061025a9050565b610366878a6138ac565b6001600160401b0316816001600160401b03161461038e576000955093509091506103999050565b600195509350909150505b93509350939050565b60008060008060008060006103b7898961084c565b925092509250826103d757506000955093508492506006915061048b9050565b600381901c671fffffffffffffff16600782166006811061040b57600084600060069850985098509850505050505061048b565b6000816001600160401b031660068111156104285761042861373a565b9050600381600681111561043e5761043e61373a565b148061045b575060048160068111156104595761045961373a565b145b1561047a5760008560006006995099509950995050505050505061048b565b600199509397509095509193505050505b92959194509250565b6000826001600160401b03166001036104c45760005b8260068111156104bc576104bc61373a565b149050610630565b826001600160401b03166002036104dc5760006104aa565b826001600160401b03166003036104f45760006104aa565b826001600160401b031660040361050c5760006104aa565b826001600160401b03166005036105245760026104aa565b826001600160401b031660060361053c5760006104aa565b826001600160401b03166007036105545760026104aa565b826001600160401b031660080361056c5760006104aa565b826001600160401b03166009036105845760026104aa565b826001600160401b0316600a0361059c5760006104aa565b826001600160401b0316600b036105b45760006104aa565b826001600160401b0316600c036105cc5760006104aa565b826001600160401b0316600d036105e45760006104aa565b826001600160401b0316600e036105fc5760026104aa565b826001600160401b0316600f036106145760006104aa565b826001600160401b031660100361062c5760026104aa565b5060005b92915050565b600080866001600160401b0385166001036106795760006106588289876109ec565b925090508061066d5750600092509050610842565b50600192509050610842565b846001600160401b0316600203610697576000610658828987610aa8565b846001600160401b03166003036106b5576000610658828987610b0f565b846001600160401b03166004036106d3576000610658828987610b70565b846001600160401b03166005036106f1576000610658828987610c1a565b846001600160401b031660060361070f576000610658828987610ca8565b846001600160401b031660070361072d576000610658828987610d01565b846001600160401b031660080361074b576000610658828987610d8f565b846001600160401b0316600903610769576000610658828987610de8565b846001600160401b0316600a03610787576000610658828987610e77565b846001600160401b0316600b036107a5576000610658828987610ed1565b846001600160401b0316600c036107c3576000610658828987610f2b565b846001600160401b0316600d036107e1576000610658828987610f85565b846001600160401b0316600e036107ff576000610658828987610fdf565b846001600160401b0316600f0361081d576000610658828987611083565b846001600160401b031660100361083b5760006106588289876110dd565b6000925090505b9550959350505050565b60008060008060005b600a6001600160401b038216101561093757855161087388836138ac565b6001600160401b03161061089357600087600094509450945050506109e5565b6000866108a0838a6138ac565b6001600160401b0316815181106108b9576108b96138f3565b016020015160f81c9050607f81166108d2836007613909565b60ff82166001600160401b03919091161b93909317926080821660000361092d576000836001600160401b031611801561090d575060ff8116155b15610926576000896000965096509650505050506109e5565b5050610937565b5050600101610855565b600a6001600160401b0382161061095a57600087600094509450945050506109e5565b6109666001600a6138d3565b6001600160401b0316816001600160401b0316036109c45760018661098b838a6138ac565b6001600160401b0316815181106109a4576109a46138f3565b016020015160f81c11156109c457600087600094509450945050506109e5565b60016109d082896138ac565b6109db9060016138ac565b8394509450945050505b9250925092565b6000806000806109fc878761116c565b909850909250905081610a1757600087935093505050610aa0565b8060030b600003610a3057600087935093505050610aa0565b60008160030b1280610a455750600d8160030b135b15610a5857600087935093505050610aa0565b8060030b600d811115610a6d57610a6d61373a565b8590600d811115610a8057610a8061373a565b9081600d811115610a9357610a9361373a565b9052506001935086925050505b935093915050565b600080600080610ab88787611188565b909850909250905081610ad357600087935093505050610aa0565b806001600160401b0316600003610af257600087935093505050610aa0565b6001600160401b0316602094909401939093525060019492505050565b600080600080610b1f87876111c6565b909850909250905081610b3a57600087935093505050610aa0565b8063ffffffff16600003610b5657600087935093505050610aa0565b63ffffffff16604094909401939093525060019492505050565b600080600080610b80878761116c565b909850909250905081610b9b57600087935093505050610aa0565b8060030b600003610bb457600087935093505050610aa0565b60008160030b1280610bc9575060038160030b135b15610bdc57600087935093505050610aa0565b8060030b6003811115610bf157610bf161373a565b85606001906003811115610c0757610c0761373a565b90816003811115610a9357610a9361373a565b600080600080610c2a8787611216565b909850909250905081610c4557600087935093505050610aa0565b806001600160401b0316600003610c6457600087935093505050610aa0565b610c6c613506565b610c77888884611225565b909950909350905082610c935760008894509450505050610aa0565b60809590950194909452506001959350505050565b600080600080610cb88787611370565b909850909250905081610cd357600087935093505050610aa0565b801515600003610ceb57600087935093505050610aa0565b151560a094909401939093525060019492505050565b600080600080610d118787611216565b909850909250905081610d2c57600087935093505050610aa0565b806001600160401b0316600003610d4b57600087935093505050610aa0565b610d5361355c565b610d5e8888846113f6565b909950909350905082610d7a5760008894509450505050610aa0565b60c09590950194909452506001959350505050565b600080600080610d9f8787611370565b909850909250905081610dba57600087935093505050610aa0565b801515600003610dd257600087935093505050610aa0565b151560e094909401939093525060019492505050565b600080600080610df88787611216565b909850909250905081610e1357600087935093505050610aa0565b806001600160401b0316600003610e3257600087935093505050610aa0565b610e3a613597565b610e45888884611541565b909950909350905082610e615760008894509450505050610aa0565b6101009590950194909452506001959350505050565b600080600080610e878787611370565b909850909250905081610ea257600087935093505050610aa0565b801515600003610eba57600087935093505050610aa0565b151561012094909401939093525060019492505050565b600080600080610ee18787611370565b909850909250905081610efc57600087935093505050610aa0565b801515600003610f1457600087935093505050610aa0565b151561014094909401939093525060019492505050565b600080600080610f3b8787611370565b909850909250905081610f5657600087935093505050610aa0565b801515600003610f6e57600087935093505050610aa0565b151561016094909401939093525060019492505050565b600080600080610f958787611370565b909850909250905081610fb057600087935093505050610aa0565b801515600003610fc857600087935093505050610aa0565b151561018094909401939093525060019492505050565b600080600080610fef8787611216565b90985090925090508161100a57600087935093505050610aa0565b806001600160401b031660000361102957600087935093505050610aa0565b604080516060808201835281526000602082018190529181019190915261105188888461168c565b90995090935090508261106d5760008894509450505050610aa0565b6101a09590950194909452506001959350505050565b6000806000806110938787611370565b9098509092509050816110ae57600087935093505050610aa0565b8015156000036110c657600087935093505050610aa0565b15156101c094909401939093525060019492505050565b6000806000806110ed8787611216565b90985090925090508161110857600087935093505050610aa0565b806001600160401b031660000361112757600087935093505050610aa0565b61112f6135d2565b61113a8888846117f9565b9099509093509050826111565760008894509450505050610aa0565b6101e09590950194909452506001959350505050565b600080600061117b8585611944565b9250925092509250925092565b60008060008060008061119b888861084c565b925092509250826111b757506000945092508391506109e59050565b60019891975095509350505050565b6000806000806000806111d9888861084c565b925092509250826111f557506000945092508391506109e59050565b67ffffffff000000008116156111b757506000945092508391506109e59050565b600080600061117b85856119a3565b600080611230613506565b611238613506565b6000876001600160401b03811661124f88836138ac565b6001600160401b0316101561126e576000955093509091506103999050565b6001600160401b0387166112828a836138d3565b6001600160401b0316101561035c5760008060006112a0848c6103a2565b9196509194509092509050826112c457506000975091955092935061039992505050565b6007826001600160401b031611156112ea57506000975091955092935061039992505050565b846001600160401b0316826001600160401b03161161131757506000975091955092935061039992505050565b6113218282611a2b565b92508261133c57506000975091955092935061039992505050565b611349848c8c858a611ad5565b945092508261136657506000975091955092935061039992505050565b50925061126e9050565b600080600080600080611383888861084c565b9250925092508261139f57506000945092508391506109e59050565b6001816001600160401b031611156113c257506000945092508391506109e59050565b806001600160401b03166000036113e55750600194509250600091506109e59050565b506001979096508795509350505050565b60008061140161355c565b61140961355c565b6000876001600160401b03811661142088836138ac565b6001600160401b0316101561143f576000955093509091506103999050565b6001600160401b0387166114538a836138d3565b6001600160401b0316101561035c576000806000611471848c6103a2565b91965091945090925090508261149557506000975091955092935061039992505050565b6003826001600160401b031611156114bb57506000975091955092935061039992505050565b846001600160401b0316826001600160401b0316116114e857506000975091955092935061039992505050565b6114f28282611bab565b92508261150d57506000975091955092935061039992505050565b61151a848c8c858a611bf5565b945092508261153757506000975091955092935061039992505050565b50925061143f9050565b60008061154c613597565b611554613597565b6000876001600160401b03811661156b88836138ac565b6001600160401b0316101561158a576000955093509091506103999050565b6001600160401b03871661159e8a836138d3565b6001600160401b0316101561035c5760008060006115bc848c6103a2565b9196509194509092509050826115e057506000975091955092935061039992505050565b6005826001600160401b0316111561160657506000975091955092935061039992505050565b846001600160401b0316826001600160401b03161161163357506000975091955092935061039992505050565b61163d8282611c53565b92508261165857506000975091955092935061039992505050565b611665848c8c858a611ccd565b945092508261168257506000975091955092935061039992505050565b50925061158a9050565b60408051606080820183528082526000602080840182905283850182905284518084018652928352820181905292810183905282919082876001600160401b0381166116d888836138ac565b6001600160401b031610156116f7576000955093509091506103999050565b6001600160401b03871661170b8a836138d3565b6001600160401b0316101561035c576000806000611729848c6103a2565b91965091945090925090508261174d57506000975091955092935061039992505050565b6003826001600160401b0316111561177357506000975091955092935061039992505050565b846001600160401b0316826001600160401b0316116117a057506000975091955092935061039992505050565b6117aa8282611d67565b9250826117c557506000975091955092935061039992505050565b6117d2848c8c858a611db1565b94509250826117ef57506000975091955092935061039992505050565b5092506116f79050565b6000806118046135d2565b61180c6135d2565b6000876001600160401b03811661182388836138ac565b6001600160401b03161015611842576000955093509091506103999050565b6001600160401b0387166118568a836138d3565b6001600160401b0316101561035c576000806000611874848c6103a2565b91965091945090925090508261189857506000975091955092935061039992505050565b6003826001600160401b031611156118be57506000975091955092935061039992505050565b846001600160401b0316826001600160401b0316116118eb57506000975091955092935061039992505050565b6118f58282611e0f565b92508261191057506000975091955092935061039992505050565b61191d848c8c858a611e41565b945092508261193a57506000975091955092935061039992505050565b5092506118429050565b600080600080600080611957888861084c565b9250925092508261197357506000945092508391506109e59050565b6001603f82901c166000036111b75767ffffffff000000008116156111b757506000945092508391506109e59050565b6000806000806000806119b6888861084c565b925092509250826119d257506000945092508391506109e59050565b816001600160401b03168183016001600160401b031610156119ff57506000945092508391506109e59050565b8651611a0b83836138ac565b6001600160401b031611156111b757506000945092508391506109e59050565b6000826001600160401b0316600103611a455760026104aa565b826001600160401b0316600203611a5d5760026104aa565b826001600160401b0316600303611a755760026104aa565b826001600160401b0316600403611a8d5760026104aa565b826001600160401b0316600503611aa55760026104aa565b826001600160401b0316600603611abd5760026104aa565b826001600160401b031660070361062c5760026104aa565b600080866001600160401b038516600103611af7576000610658828987611e9f565b846001600160401b0316600203611b15576000610658828987611eef565b846001600160401b0316600303611b335760006106588289876120ee565b846001600160401b0316600403611b51576000610658828987612189565b846001600160401b0316600503611b6f5760006106588289876121e0565b846001600160401b0316600603611b8d57600061065882898761239b565b846001600160401b031660070361083b5760006106588289876125f3565b6000826001600160401b0316600103611bc55760006104aa565b826001600160401b0316600203611bdd5760026104aa565b826001600160401b031660030361062c5760026104aa565b600080866001600160401b038516600103611c1757600061065882898761264a565b846001600160401b0316600203611c355760006106588289876126f1565b846001600160401b031660030361083b57600061065882898761278c565b6000826001600160401b0316600103611c6d5760026104aa565b826001600160401b0316600203611c855760026104aa565b826001600160401b0316600303611c9d5760026104aa565b826001600160401b0316600403611cb55760006104aa565b826001600160401b031660050361062c5760006104aa565b600080866001600160401b038516600103611cef5760006106588289876127e3565b846001600160401b0316600203611d0d57600061065882898761291f565b846001600160401b0316600303611d2b576000610658828987612a44565b846001600160401b0316600403611d49576000610658828987612b69565b846001600160401b031660050361083b576000610658828987612bca565b6000826001600160401b0316600103611d815760026104aa565b826001600160401b0316600203611d995760006104aa565b826001600160401b031660030361062c5760006104aa565b600080866001600160401b038516600103611dd3576000610658828987611e9f565b846001600160401b0316600203611df1576000610658828987612c2b565b846001600160401b031660030361083b576000610658828987612c8c565b6000826001600160401b0316600103611e295760026104aa565b826001600160401b0316600203611bdd5760006104aa565b600080866001600160401b038516600103611e63576000610658828987612cf3565b846001600160401b0316600203611e81576000610658828987612c2b565b846001600160401b031660030361083b5760006106588289876120ee565b60008060006060611eb08787612e15565b909850909250905081611ecb57600087935093505050610aa0565b8051600003611ee257600087935093505050610aa0565b9093525060019492505050565b600080600080611eff87876119a3565b909850909250905081611f1a57600087935093505050610aa0565b806001600160401b0316600003611f3957600087935093505050610aa0565b866001600160401b038116611f4e83836138ac565b6001600160401b03161015611f6c5760008894509450505050610aa0565b60005b6001600160401b038316611f83838b6138d3565b6001600160401b03161015611fcf576000611f9e8a8a611188565b909b50909550905084611fbc5760008a965096505050505050610aa0565b611fc76001836138ac565b915050611f6f565b806001600160401b03166001600160401b03811115611ff057611ff0613631565b604051908082528060200260200182016040528015612019578160200160208202803683370190505b506020880152909750879060005b816001600160401b0316816001600160401b031610156120ad57600061204d8b8b611188565b909c5090965090508561206c5760008b97509750505050505050610aa0565b808960200151836001600160401b03168151811061208c5761208c6138f3565b6001600160401b039092166020928302919091019091015250600101612027565b506120b883836138ac565b6001600160401b0316896001600160401b0316146120e0576000899550955050505050610aa0565b506001989650505050505050565b6000806000806120fe8787611216565b90985090925090508161211957600087935093505050610aa0565b806001600160401b031660000361213857600087935093505050610aa0565b604080518082019091526000815260606020820152612158888884612f49565b9099509093509050826121745760008894509450505050610aa0565b60409590950194909452506001959350505050565b6000806000606061219a8787612e15565b9098509092509050816121b557600087935093505050610aa0565b80516000036121cc57600087935093505050610aa0565b606094909401939093525060019492505050565b6000806000806121f087876119a3565b90985090925090508161220b57600087935093505050610aa0565b806001600160401b031660000361222a57600087935093505050610aa0565b866001600160401b03811661223f83836138ac565b6001600160401b0316101561225d5760008894509450505050610aa0565b60005b6001600160401b038316612274838b6138d3565b6001600160401b031610156122c057600061228f8a8a6111c6565b909b509095509050846122ad5760008a965096505050505050610aa0565b6122b86001836138ac565b915050612260565b806001600160401b03166001600160401b038111156122e1576122e1613631565b60405190808252806020026020018201604052801561230a578160200160208202803683370190505b506080880152909750879060005b816001600160401b0316816001600160401b031610156120ad57600061233e8b8b6111c6565b909c5090965090508561235d5760008b97509750505050505050610aa0565b808960800151836001600160401b03168151811061237d5761237d6138f3565b63ffffffff9092166020928302919091019091015250600101612318565b6000808085815b8651886001600160401b031610156124905760006123c08989611216565b909a509094509050836123dd576000899550955050505050610aa0565b6001600160401b0389166123f1828b6138ac565b6001600160401b03161015612410576000899550955050505050610aa0565b61241a818a6138ac565b98506124276001836138ac565b91508751896001600160401b0316106124405750612490565b60008061244d8b8b6103a2565b919d5091975090925090508561246f5760008b97509750505050505050610aa0565b816001600160401b031660061461248857505050612490565b5050506123a2565b806001600160401b03166001600160401b038111156124b1576124b1613631565b6040519080825280602002602001820160405280156124ea57816020015b6124d7613604565b8152602001906001900390816124cf5790505b5060a0870152909650869060005b816001600160401b0316816001600160401b031610156120e057600061251e8a8a611216565b909b5090955090508461253c5760008a965096505050505050610aa0565b899350612547613604565b6125528b8b846130b4565b909c509096509050856125715760008b97509750505050505050610aa0565b808960a00151846001600160401b031681518110612591576125916138f3565b60209081029190910101526125a76001856138d3565b6001600160401b0316836001600160401b031610156125e9576125ca8b8b611188565b909c509096509150856125e95760008b97509750505050505050610aa0565b50506001016124f8565b600080600060606126048787612e15565b90985090925090508161261f57600087935093505050610aa0565b805160000361263657600087935093505050610aa0565b60c094909401939093525060019492505050565b60008060008061265a878761116c565b90985090925090508161267557600087935093505050610aa0565b8060030b60000361268e57600087935093505050610aa0565b60008160030b12806126a3575060028160030b135b156126b657600087935093505050610aa0565b8060030b60028111156126cb576126cb61373a565b859060028111156126de576126de61373a565b90816002811115610a9357610a9361373a565b6000806000806127018787611216565b90985090925090508161271c57600087935093505050610aa0565b806001600160401b031660000361273b57600087935093505050610aa0565b60408051808201909152600081526060602082015261275b888884612f49565b9099509093509050826127775760008894509450505050610aa0565b60209590950194909452506001959350505050565b6000806000606061279d8787612e15565b9098509092509050816127b857600087935093505050610aa0565b80516000036127cf57600087935093505050610aa0565b604094909401939093525060019492505050565b6000806000806127f38787611216565b90985090925090508161280e57600087935093505050610aa0565b806001600160401b031660000361282d57600087935093505050610aa0565b806001600160401b03166001600160401b0381111561284e5761284e613631565b6040519080825280601f01601f191660200182016040528015612878576020820181803683370190505b50855260005b816001600160401b0316816001600160401b0316101561290557866128a3828a6138ac565b6001600160401b0316815181106128bc576128bc6138f3565b602001015160f81c60f81b8660000151826001600160401b0316815181106128e6576128e66138f3565b60200101906001600160f81b031916908160001a90535060010161287e565b5061291081886138ac565b60019890975095505050505050565b60008060008061292f8787611216565b90985090925090508161294a57600087935093505050610aa0565b806001600160401b031660000361296957600087935093505050610aa0565b806001600160401b03166001600160401b0381111561298a5761298a613631565b6040519080825280601f01601f1916602001820160405280156129b4576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b0316101561290557866129e2828a6138ac565b6001600160401b0316815181106129fb576129fb6138f3565b602001015160f81c60f81b8660200151826001600160401b031681518110612a2557612a256138f3565b60200101906001600160f81b031916908160001a9053506001016129bd565b600080600080612a548787611216565b909850909250905081612a6f57600087935093505050610aa0565b806001600160401b0316600003612a8e57600087935093505050610aa0565b806001600160401b03166001600160401b03811115612aaf57612aaf613631565b6040519080825280601f01601f191660200182016040528015612ad9576020820181803683370190505b50604086015260005b816001600160401b0316816001600160401b031610156129055786612b07828a6138ac565b6001600160401b031681518110612b2057612b206138f3565b602001015160f81c60f81b8660400151826001600160401b031681518110612b4a57612b4a6138f3565b60200101906001600160f81b031916908160001a905350600101612ae2565b600080600080612b7987876111c6565b909850909250905081612b9457600087935093505050610aa0565b8063ffffffff16600003612bb057600087935093505050610aa0565b63ffffffff16606094909401939093525060019492505050565b600080600080612bda87876111c6565b909850909250905081612bf557600087935093505050610aa0565b8063ffffffff16600003612c1157600087935093505050610aa0565b63ffffffff16608094909401939093525060019492505050565b600080600080612c3b87876111c6565b909850909250905081612c5657600087935093505050610aa0565b8063ffffffff16600003612c7257600087935093505050610aa0565b63ffffffff16602094909401939093525060019492505050565b600080600080612c9c8787611188565b909850909250905081612cb757600087935093505050610aa0565b806001600160401b0316600003612cd657600087935093505050610aa0565b6001600160401b0316604094909401939093525060019492505050565b600080600080612d038787611216565b909850909250905081612d1e57600087935093505050610aa0565b806001600160401b0316600003612d3d57600087935093505050610aa0565b806001600160401b03166001600160401b03811115612d5e57612d5e613631565b6040519080825280601f01601f191660200182016040528015612d88576020820181803683370190505b50855260005b816001600160401b0316816001600160401b031610156129055786612db3828a6138ac565b6001600160401b031681518110612dcc57612dcc6138f3565b602001015160f81c60f81b8660000151826001600160401b031681518110612df657612df66138f3565b60200101906001600160f81b031916908160001a905350600101612d8e565b60008060606000806000612e2988886119a3565b92509250925082612e5557600082604051806020016040528060008152509550955095505050506109e5565b6000816001600160401b03166001600160401b03811115612e7857612e78613631565b6040519080825280601f01601f191660200182016040528015612ea2576020820181803683370190505b50905060005b826001600160401b0316816001600160401b03161015612f2b5788612ecd82866138ac565b6001600160401b031681518110612ee657612ee66138f3565b602001015160f81c60f81b82826001600160401b031681518110612f0c57612f0c6138f3565b60200101906001600160f81b031916908160001a905350600101612ea8565b506001612f3883856138ac565b909750955093505050509250925092565b600080612f6760408051808201909152600081526060602082015290565b6040805180820190915260008152606060208201526000876001600160401b038116612f9388836138ac565b6001600160401b03161015612fb2576000955093509091506103999050565b6001600160401b038716612fc68a836138d3565b6001600160401b0316101561035c576000806000612fe4848c6103a2565b91965091945090925090508261300857506000975091955092935061039992505050565b6002826001600160401b0316111561302e57506000975091955092935061039992505050565b846001600160401b0316826001600160401b03161161305b57506000975091955092935061039992505050565b61306582826131ff565b92508261308057506000975091955092935061039992505050565b61308d848c8c858a613231565b94509250826130aa57506000975091955092935061039992505050565b509250612fb29050565b6000806130bf613604565b6130c7613604565b6000876001600160401b0381166130de88836138ac565b6001600160401b031610156130fd576000955093509091506103999050565b6001600160401b0387166131118a836138d3565b6001600160401b0316101561035c57600080600061312f848c6103a2565b91965091945090925090508261315357506000975091955092935061039992505050565b6002826001600160401b0316111561317957506000975091955092935061039992505050565b846001600160401b0316826001600160401b0316116131a657506000975091955092935061039992505050565b6131b08282613271565b9250826131cb57506000975091955092935061039992505050565b6131d8848c8c858a61328b565b94509250826131f557506000975091955092935061039992505050565b5092506130fd9050565b6000826001600160401b03166001036132195760006104aa565b826001600160401b031660020361062c5760026104aa565b600080866001600160401b0385166001036132535760006106588289876132cb565b846001600160401b031660020361083b57600061065882898761332b565b6000826001600160401b03166001036132195760026104aa565b600080866001600160401b0385166001036132ad576000610658828987611e9f565b846001600160401b031660020361083b5760006106588289876126f1565b6000806000806132db8787611188565b9098509092509050816132f657600087935093505050610aa0565b806001600160401b031660000361331557600087935093505050610aa0565b6001600160401b03169093525060019492505050565b60008060008061333b8787611216565b90985090925090508161335657600087935093505050610aa0565b806001600160401b031660000361337557600087935093505050610aa0565b806001600160401b03166001600160401b0381111561339657613396613631565b6040519080825280601f01601f1916602001820160405280156133c0576020820181803683370190505b50602086015260005b816001600160401b0316816001600160401b0316101561290557866133ee828a6138ac565b6001600160401b031681518110613407576134076138f3565b602001015160f81c60f81b8660200151826001600160401b031681518110613431576134316138f3565b60200101906001600160f81b031916908160001a9053506001016133c9565b6040805161020081018252600080825260208201819052918101829052606081019190915260808101613481613506565b81526000602082015260400161349561355c565b8152600060208201526040016134a9613597565b81526000602082018190526040820181905260608201819052608082015260a0016134ed604080516060808201835281526000602082018190529181019190915290565b8152600060208201526040016135016135d2565b905290565b6040518060e00160405280606081526020016060815260200161353a60408051808201909152600081526060602082015290565b8152602001606081526020016060815260200160608152602001606081525090565b6040805160608101909152806000815260200161358a60408051808201909152600081526060602082015290565b8152602001606081525090565b6040518060a00160405280606081526020016060815260200160608152602001600063ffffffff168152602001600063ffffffff1681525090565b604080516060808201835281526000602082015290810161350160408051808201909152600081526060602082015290565b60405180604001604052806060815260200161350160408051808201909152600081526060602082015290565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561366f5761366f613631565b604052919050565b60006001600160401b0382111561369057613690613631565b50601f01601f191660200190565b600080600080608085870312156136b457600080fd5b84359350602085013592506040850135915060608501356001600160401b038111156136df57600080fd5b8501601f810187136136f057600080fd5b80356137036136fe82613677565b613647565b81815288602083850101111561371857600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b634e487b7160e01b600052602160045260246000fd5b60005b8381101561376b578181015183820152602001613753565b50506000910152565b6000815180845261378c816020860160208601613750565b601f01601f19169290920160200192915050565b6040815260006137b36040830185613774565b905063ffffffff831660208301529392505050565b6000602082840312156137da57600080fd5b81516001600160401b038111156137f057600080fd5b8201601f8101841361380157600080fd5b805161380f6136fe82613677565b81815285602083850101111561382457600080fd5b613835826020830160208601613750565b95945050505050565b8481528360208201528260408201526080606082015260006138636080830184613774565b9695505050505050565b60006020828403121561387f57600080fd5b8151801515811461388f57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b038181168382160190808211156138cc576138cc613896565b5092915050565b6001600160401b038281168282160390808211156138cc576138cc613896565b634e487b7160e01b600052603260045260246000fd5b6001600160401b0381811683821602808216919082811461392c5761392c613896565b50509291505056fea264697066735822122074d79aa39e58526beca76857742916e925f8e90273db4ae5a93c9a0b1a512f6a64736f6c63430008180033", 87 | "nonce": "0x14", 88 | "accessList": [] 89 | }, 90 | "additionalContracts": [], 91 | "isFixedGasLimit": false 92 | }, 93 | { 94 | "hash": null, 95 | "transactionType": "CREATE", 96 | "contractName": "Dummy", 97 | "contractAddress": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 98 | "function": null, 99 | "arguments": null, 100 | "transaction": { 101 | "type": "0x02", 102 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 103 | "gas": "0x37bfa", 104 | "value": "0x0", 105 | "data": "0x608060405234801561001057600080fd5b50610237806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806369c20bdd14610030575b600080fd5b61004361003e3660046100ce565b610045565b005b6040516369c20bdd60e01b815273461bf1372db198ec5a9b747fafb8f39514d12e93906369c20bdd9061008290879087908790879060040161019c565b60006040518083038186803b15801561009a57600080fd5b505af41580156100ae573d6000803e3d6000fd5b5050505050505050565b634e487b7160e01b600052604160045260246000fd5b600080600080608085870312156100e457600080fd5b843593506020850135925060408501359150606085013567ffffffffffffffff8082111561011157600080fd5b818701915087601f83011261012557600080fd5b813581811115610137576101376100b8565b604051601f8201601f19908116603f0116810190838211818310171561015f5761015f6100b8565b816040528281528a602084870101111561017857600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8481526000602085602084015284604084015260806060840152835180608085015260005b818110156101dd5785810183015185820160a0015282016101c1565b50600060a0828601015260a0601f19601f830116850101925050509594505050505056fea26469706673582212209bb8b10977aa31d4fc484d4674b56853bbc29c555310389b7b7a00239165c9bb64736f6c63430008180033", 106 | "nonce": "0x15", 107 | "accessList": [] 108 | }, 109 | "additionalContracts": [], 110 | "isFixedGasLimit": false 111 | } 112 | ], 113 | "receipts": [], 114 | "libraries": [ 115 | "lib/farcaster-solidity/contracts/libraries/Blake3.sol:Blake3:0x1a683552a75b6d0601195aa0f0376ee880c42eb1", 116 | "lib/farcaster-solidity/contracts/libraries/Ed25519.sol:Ed25519:0x880b037c449e587d16c6bc45ccf14b2be80e57b1", 117 | "lib/farcaster-solidity/contracts/libraries/Ed25519_pow.sol:Ed25519_pow:0x687372443cd062c22266c0f33a3cd8b4b6fc3c0c", 118 | "lib/farcaster-solidity/contracts/libraries/Sha512.sol:Sha512:0xa0711ef69e5ed96e31c1dc79fbb25abddfe8fa5a", 119 | "src/FarcasterSolidity.sol:FarcasterSolidity:0x461bf1372db198ec5a9b747fafb8f39514d12e93" 120 | ], 121 | "pending": [], 122 | "returns": {}, 123 | "timestamp": 1706546654, 124 | "chain": 8453, 125 | "multi": false, 126 | "commit": "f51c058" 127 | } -------------------------------------------------------------------------------- /broadcast/FrameVerifyTest.s.sol/8453/run-1706548145.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 8 | "function": "verifyFrameActionBodyMessage(bytes32,bytes32,bytes32,bytes)", 9 | "arguments": [ 10 | "0x4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d0", 11 | "0x68c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687", 12 | "0xbe15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd09", 13 | "0x080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e" 14 | ], 15 | "transaction": { 16 | "type": "0x02", 17 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 18 | "to": "0x1030afaa62bcd43de6273d89b1c127c642d5a63f", 19 | "gas": "0x1b7a4e", 20 | "value": "0x0", 21 | "data": "0x69c20bdd4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d068c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687be15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd0900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000043080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e0000000000000000000000000000000000000000000000000000000000", 22 | "nonce": "0x17", 23 | "accessList": [] 24 | }, 25 | "additionalContracts": [], 26 | "isFixedGasLimit": false 27 | } 28 | ], 29 | "receipts": [], 30 | "libraries": [], 31 | "pending": [ 32 | "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857" 33 | ], 34 | "returns": {}, 35 | "timestamp": 1706548145, 36 | "chain": 8453, 37 | "multi": false, 38 | "commit": "e5f28ad" 39 | } -------------------------------------------------------------------------------- /broadcast/FrameVerifyTest.s.sol/8453/run-1706548151.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 8 | "function": "verifyFrameActionBodyMessage(bytes32,bytes32,bytes32,bytes)", 9 | "arguments": [ 10 | "0x4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d0", 11 | "0x68c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687", 12 | "0xbe15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd09", 13 | "0x080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e" 14 | ], 15 | "transaction": { 16 | "type": "0x02", 17 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 18 | "to": "0x1030afaa62bcd43de6273d89b1c127c642d5a63f", 19 | "gas": "0x1b7a4e", 20 | "value": "0x0", 21 | "data": "0x69c20bdd4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d068c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687be15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd0900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000043080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e0000000000000000000000000000000000000000000000000000000000", 22 | "nonce": "0x17", 23 | "accessList": [] 24 | }, 25 | "additionalContracts": [], 26 | "isFixedGasLimit": false 27 | } 28 | ], 29 | "receipts": [ 30 | { 31 | "transactionHash": "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857", 32 | "transactionIndex": "0x12", 33 | "blockHash": "0xeaeca0ee606a6fcd9f2d9eccfe8076adfd3444b2467c86eb506fc889794c0241", 34 | "blockNumber": "0x96bf68", 35 | "from": "0xfd896Bf5Eba7E1B9843B91ef6182DE16B547273B", 36 | "to": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 37 | "cumulativeGasUsed": "0x49850f", 38 | "gasUsed": "0x13e4b6", 39 | "contractAddress": null, 40 | "logs": [], 41 | "status": "0x1", 42 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 43 | "type": "0x2", 44 | "effectiveGasPrice": "0x30f" 45 | } 46 | ], 47 | "libraries": [], 48 | "pending": [], 49 | "returns": {}, 50 | "timestamp": 1706548151, 51 | "chain": 8453, 52 | "multi": false, 53 | "commit": "e5f28ad" 54 | } -------------------------------------------------------------------------------- /broadcast/FrameVerifyTest.s.sol/8453/run-latest.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857", 5 | "transactionType": "CALL", 6 | "contractName": null, 7 | "contractAddress": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 8 | "function": "verifyFrameActionBodyMessage(bytes32,bytes32,bytes32,bytes)", 9 | "arguments": [ 10 | "0x4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d0", 11 | "0x68c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687", 12 | "0xbe15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd09", 13 | "0x080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e" 14 | ], 15 | "transaction": { 16 | "type": "0x02", 17 | "from": "0xfd896bf5eba7e1b9843b91ef6182de16b547273b", 18 | "to": "0x1030afaa62bcd43de6273d89b1c127c642d5a63f", 19 | "gas": "0x1b7a4e", 20 | "value": "0x0", 21 | "data": "0x69c20bdd4fe8406370be9f8cbaddc6f0e909b2fc75c9d1f56d19395f9a90d9741b4f42d068c44d89761d24d6a33f9fc0373a4fbc047c9f22835177d1a5eb33c91a0f2687be15a695fc7039845d9ce37f87d850cdef7f16b944a3d6f92a09825cb7a0fd0900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000043080d1095c90218e3d8a52e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a0895c902121473a773451c6b36d0a8dc8c806407a8a3f5f7da9e0000000000000000000000000000000000000000000000000000000000", 22 | "nonce": "0x17", 23 | "accessList": [] 24 | }, 25 | "additionalContracts": [], 26 | "isFixedGasLimit": false 27 | } 28 | ], 29 | "receipts": [ 30 | { 31 | "transactionHash": "0x407f51d491fe8ed2fb47e9db128ed1949e07448dc6602c957316600c503ed857", 32 | "transactionIndex": "0x12", 33 | "blockHash": "0xeaeca0ee606a6fcd9f2d9eccfe8076adfd3444b2467c86eb506fc889794c0241", 34 | "blockNumber": "0x96bf68", 35 | "from": "0xfd896Bf5Eba7E1B9843B91ef6182DE16B547273B", 36 | "to": "0x1030aFaA62BcD43de6273D89b1c127C642d5A63F", 37 | "cumulativeGasUsed": "0x49850f", 38 | "gasUsed": "0x13e4b6", 39 | "contractAddress": null, 40 | "logs": [], 41 | "status": "0x1", 42 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 43 | "type": "0x2", 44 | "effectiveGasPrice": "0x30f" 45 | } 46 | ], 47 | "libraries": [], 48 | "pending": [], 49 | "returns": {}, 50 | "timestamp": 1706548151, 51 | "chain": 8453, 52 | "multi": false, 53 | "commit": "e5f28ad" 54 | } -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | 6 | # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options 7 | -------------------------------------------------------------------------------- /src/Encoder.sol: -------------------------------------------------------------------------------- 1 | // File automatically generated by protoc-gen-sol v0.2.0 2 | // and then fixed by @wilsoncusack :) 3 | // SPDX-License-Identifier: CC0 4 | pragma solidity >=0.8.4 <0.9.0; 5 | pragma experimental ABIEncoderV2; 6 | 7 | import "./libraries/ProtobufLib.sol"; 8 | 9 | enum MessageType { 10 | MESSAGE_TYPE_NONE, 11 | MESSAGE_TYPE_CAST_ADD, 12 | MESSAGE_TYPE_CAST_REMOVE, 13 | MESSAGE_TYPE_REACTION_ADD, 14 | MESSAGE_TYPE_REACTION_REMOVE, 15 | MESSAGE_TYPE_LINK_ADD, 16 | MESSAGE_TYPE_LINK_REMOVE, 17 | MESSAGE_TYPE_VERIFICATION_ADD_ETH_ADDRESS, 18 | MESSAGE_TYPE_VERIFICATION_REMOVE, 19 | MESSAGE_TYPE_SIGNER_ADD, 20 | MESSAGE_TYPE_SIGNER_REMOVE, 21 | MESSAGE_TYPE_USER_DATA_ADD, 22 | MESSAGE_TYPE_USERNAME_PROOF, 23 | MESSAGE_TYPE_FRAME_ACTION 24 | } 25 | 26 | enum FarcasterNetwork { 27 | FARCASTER_NETWORK_NONE, 28 | FARCASTER_NETWORK_MAINNET, 29 | FARCASTER_NETWORK_TESTNET, 30 | FARCASTER_NETWORK_DEVNET 31 | } 32 | 33 | struct MessageData { 34 | MessageType type_; 35 | uint64 fid; 36 | uint32 timestamp; 37 | FarcasterNetwork network; 38 | FrameActionBody frame_action_body; 39 | } 40 | 41 | library MessageDataCodec { 42 | // Holds encoded version of message 43 | struct MessageData__Encoded { 44 | bytes type___Key; 45 | bytes type_; 46 | bytes fid__Key; 47 | bytes fid; 48 | bytes timestamp__Key; 49 | bytes timestamp; 50 | bytes network__Key; 51 | bytes network; 52 | FrameActionBodyCodec.FrameActionBody__Encoded__Nested frame_action_body; 53 | bytes frame_action_body__Encoded; 54 | } 55 | 56 | // Holds encoded version of nested message 57 | struct MessageData__Encoded__Nested { 58 | bytes key; 59 | bytes length; 60 | bytes nestedInstance; 61 | } 62 | 63 | function encode(MessageData memory instance) internal pure returns (bytes memory) { 64 | // Omit encoding fields if default value 65 | bytes memory type__Key = 66 | uint64(instance.type_) != 0 ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); 67 | bytes memory type_ = 68 | uint64(instance.type_) != 0 ? ProtobufLib.encode_int32(int32(uint32(instance.type_))) : new bytes(0); 69 | bytes memory fid__Key = 70 | uint64(instance.fid) != 0 ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); 71 | bytes memory fid = uint64(instance.fid) != 0 ? ProtobufLib.encode_uint64(instance.fid) : new bytes(0); 72 | bytes memory timestamp__Key = uint64(instance.timestamp) != 0 73 | ? ProtobufLib.encode_key(3, uint64(ProtobufLib.WireType.Varint)) 74 | : new bytes(0); 75 | bytes memory timestamp = 76 | uint64(instance.timestamp) != 0 ? ProtobufLib.encode_uint32(instance.timestamp) : new bytes(0); 77 | bytes memory network__Key = uint64(instance.network) != 0 78 | ? ProtobufLib.encode_key(4, uint64(ProtobufLib.WireType.Varint)) 79 | : new bytes(0); 80 | bytes memory network = 81 | uint64(instance.network) != 0 ? ProtobufLib.encode_int32(int32(uint32(instance.network))) : new bytes(0); 82 | 83 | // Encode frame_action_body 84 | FrameActionBodyCodec.FrameActionBody__Encoded__Nested memory frame_action_body = 85 | FrameActionBodyCodec.encodeNested(16, instance.frame_action_body); 86 | bytes memory frame_action_body__Encoded = 87 | abi.encodePacked(frame_action_body.key, frame_action_body.length, frame_action_body.nestedInstance); 88 | 89 | // Use abi.encodePacked for efficient concatenation 90 | return abi.encodePacked( 91 | type__Key, 92 | type_, 93 | fid__Key, 94 | fid, 95 | timestamp__Key, 96 | timestamp, 97 | network__Key, 98 | network, 99 | frame_action_body__Encoded 100 | ); 101 | } 102 | 103 | // Encode a nested MessageData, wrapped in key and length if non-default 104 | function encodeNested(uint64 field_number, MessageData memory instance) 105 | internal 106 | pure 107 | returns (MessageData__Encoded__Nested memory) 108 | { 109 | bytes memory nestedInstance = encode(instance); 110 | uint64 len = uint64(nestedInstance.length); 111 | bytes memory key = len > 0 ? ProtobufLib.encode_key(field_number, 2) : new bytes(0); 112 | bytes memory length = len > 0 ? ProtobufLib.encode_uint64(len) : new bytes(0); 113 | 114 | return MessageData__Encoded__Nested(key, length, nestedInstance); 115 | } 116 | } 117 | 118 | struct CastId { 119 | uint64 fid; 120 | bytes hash; 121 | } 122 | 123 | library CastIdCodec { 124 | // Holds encoded version of message 125 | struct CastId__Encoded { 126 | bytes fid__Key; 127 | bytes fid; 128 | bytes hash__Key; 129 | bytes hash__Length; 130 | bytes hash; 131 | } 132 | 133 | // Holds encoded version of nested message 134 | struct CastId__Encoded__Nested { 135 | bytes key; 136 | bytes length; 137 | bytes nestedInstance; 138 | } 139 | 140 | function encode(CastId memory instance) internal pure returns (bytes memory) { 141 | bytes memory fid__Key = 142 | uint64(instance.fid) != 0 ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.Varint)) : new bytes(0); 143 | bytes memory fid = uint64(instance.fid) != 0 ? ProtobufLib.encode_uint64(instance.fid) : new bytes(0); 144 | bytes memory hash__Key = instance.hash.length > 0 145 | ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.LengthDelimited)) 146 | : new bytes(0); 147 | bytes memory hash__Length = 148 | instance.hash.length > 0 ? ProtobufLib.encode_uint64(uint64(instance.hash.length)) : new bytes(0); 149 | bytes memory hash = instance.hash.length > 0 ? bytes(instance.hash) : new bytes(0); 150 | 151 | return abi.encodePacked(fid__Key, fid, hash__Key, hash__Length, hash); 152 | } 153 | 154 | // Encode a nested CastId, wrapped in key and length if non-default 155 | function encodeNested(uint64 field_number, CastId memory instance) 156 | internal 157 | pure 158 | returns (CastId__Encoded__Nested memory) 159 | { 160 | bytes memory nestedInstance = encode(instance); 161 | uint64 len = uint64(nestedInstance.length); 162 | bytes memory key = len > 0 ? ProtobufLib.encode_key(field_number, 2) : new bytes(0); 163 | bytes memory length = len > 0 ? ProtobufLib.encode_uint64(len) : new bytes(0); 164 | 165 | return CastId__Encoded__Nested(key, length, nestedInstance); 166 | } 167 | } 168 | 169 | struct FrameActionBody { 170 | bytes url; 171 | uint32 button_index; 172 | CastId cast_id; 173 | } 174 | 175 | library FrameActionBodyCodec { 176 | // Holds encoded version of message 177 | struct FrameActionBody__Encoded { 178 | bytes url__Key; 179 | bytes url__Length; 180 | bytes url; 181 | bytes button_index__Key; 182 | bytes button_index; 183 | CastIdCodec.CastId__Encoded__Nested cast_id; 184 | bytes cast_id__Encoded; 185 | } 186 | 187 | // Holds encoded version of nested message 188 | struct FrameActionBody__Encoded__Nested { 189 | bytes key; 190 | bytes length; 191 | bytes nestedInstance; 192 | } 193 | 194 | function encode(FrameActionBody memory instance) internal pure returns (bytes memory) { 195 | bytes memory url__Key = instance.url.length > 0 196 | ? ProtobufLib.encode_key(1, uint64(ProtobufLib.WireType.LengthDelimited)) 197 | : new bytes(0); 198 | bytes memory url__Length = 199 | instance.url.length > 0 ? ProtobufLib.encode_uint64(uint64(instance.url.length)) : new bytes(0); 200 | bytes memory url = instance.url.length > 0 ? bytes(instance.url) : new bytes(0); 201 | bytes memory button_index__Key = uint64(instance.button_index) != 0 202 | ? ProtobufLib.encode_key(2, uint64(ProtobufLib.WireType.Varint)) 203 | : new bytes(0); 204 | bytes memory button_index = 205 | uint64(instance.button_index) != 0 ? ProtobufLib.encode_uint32(instance.button_index) : new bytes(0); 206 | CastIdCodec.CastId__Encoded__Nested memory cast_id = CastIdCodec.encodeNested(3, instance.cast_id); 207 | bytes memory cast_id__Encoded = abi.encodePacked(cast_id.key, cast_id.length, cast_id.nestedInstance); 208 | 209 | return abi.encodePacked(url__Key, url__Length, url, button_index__Key, button_index, cast_id__Encoded); 210 | } 211 | 212 | // Encode a nested FrameActionBody, wrapped in key and length if non-default 213 | function encodeNested(uint64 field_number, FrameActionBody memory instance) 214 | internal 215 | pure 216 | returns (FrameActionBody__Encoded__Nested memory) 217 | { 218 | bytes memory nestedInstance = encode(instance); 219 | uint64 len = uint64(nestedInstance.length); 220 | bytes memory key = len > 0 ? ProtobufLib.encode_key(field_number, 2) : new bytes(0); 221 | bytes memory length = len > 0 ? ProtobufLib.encode_uint64(len) : new bytes(0); 222 | 223 | return FrameActionBody__Encoded__Nested(key, length, nestedInstance); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/FrameVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.9; 3 | 4 | import {Blake3} from "./libraries/Blake3.sol"; 5 | import {Ed25519} from "./libraries/Ed25519.sol"; 6 | import {MessageData, MessageDataCodec} from "./Encoder.sol"; 7 | 8 | library FrameVerifier { 9 | error InvalidSignature(); 10 | error InvalidEncoding(); 11 | error InvalidMessageType(); 12 | 13 | function _verifyMessage(bytes32 public_key, bytes32 signature_r, bytes32 signature_s, bytes memory message) 14 | internal 15 | pure 16 | returns (bool) 17 | { 18 | // Calculate Blake3 hash of FC message (first 20 bytes) 19 | bytes memory message_hash = Blake3.hash(message, 20); 20 | 21 | // Verify signature 22 | return Ed25519.verify(public_key, signature_r, signature_s, message_hash); 23 | } 24 | 25 | function verifyMessageData( 26 | bytes32 public_key, 27 | bytes32 signature_r, 28 | bytes32 signature_s, 29 | MessageData memory messageData 30 | ) external pure returns (bool) { 31 | return _verifyMessage(public_key, signature_r, signature_s, MessageDataCodec.encode(messageData)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/examples/ERC4337/Account.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.9; 3 | 4 | import {MessageData} from "../../FrameVerifier.sol"; 5 | import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; 6 | 7 | import {UserOperation} from "./UserOperation.sol"; 8 | import {SharedVerifier} from "../SharedVerifier.sol"; 9 | 10 | /// @dev WARNING: This was written quickly with no tests, almost certainly has bugs 11 | contract Account { 12 | bytes32 public publicKey; 13 | string public baseUrl; 14 | SharedVerifier public sharedVerifier; 15 | uint256 public lastFrameTimstamp; 16 | 17 | struct FrameUserOpSignature { 18 | bytes32 signature_r; 19 | bytes32 signature_s; 20 | MessageData messageData; 21 | } 22 | 23 | function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) 24 | external 25 | returns (uint256 validationData) 26 | { 27 | // check msg.sender is entrypoint 28 | 29 | FrameUserOpSignature memory frameStruct = abi.decode(userOp.signature, (FrameUserOpSignature)); 30 | string memory expectedUrl = 31 | string.concat(baseUrl, Strings.toString(block.chainid), ":", string(userOp.callData)); 32 | frameStruct.messageData.frame_action_body.url = bytes(expectedUrl); 33 | 34 | if ( 35 | sharedVerifier.verifyMessageData( 36 | SharedVerifier.VerifyRequest( 37 | publicKey, frameStruct.signature_r, frameStruct.signature_s, frameStruct.messageData 38 | ) 39 | ) 40 | ) { 41 | if (frameStruct.messageData.timestamp < lastFrameTimstamp) { 42 | return 1; 43 | } 44 | lastFrameTimstamp = frameStruct.messageData.timestamp; 45 | return 0; 46 | } 47 | 48 | return 1; 49 | 50 | // pay missing account funds 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/examples/ERC4337/Paymaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.9; 3 | 4 | import {UserOperation} from "./UserOperation.sol"; 5 | import {Account} from "./Account.sol"; 6 | import {SharedVerifier} from "../SharedVerifier.sol"; 7 | 8 | /// @dev WARNING: This was written quickly with no tests, almost certainly has bugs 9 | contract Paymaster { 10 | enum PostOpMode { 11 | opSucceeded, 12 | opReverted, 13 | postOpReverted 14 | } 15 | 16 | mapping(bytes32 => uint256) public castBalance; 17 | mapping(uint256 => uint256) public fidBalance; 18 | 19 | enum SponsorType { 20 | cast, 21 | fid 22 | } 23 | 24 | SharedVerifier public sharedVerifier; 25 | 26 | function validatePaymasterUserOp(UserOperation calldata userOp, bytes32, uint256 maxCost) 27 | external 28 | returns (bytes memory context, uint256 validationData) 29 | { 30 | // check msg.sender is entrypoint 31 | 32 | Account.FrameUserOpSignature memory frameStruct = abi.decode(userOp.signature, (Account.FrameUserOpSignature)); 33 | 34 | // assume invalid 35 | validationData = 1; 36 | 37 | if ( 38 | sharedVerifier.verifyMessageData( 39 | SharedVerifier.VerifyRequest( 40 | Account(userOp.sender).publicKey(), 41 | frameStruct.signature_r, 42 | frameStruct.signature_s, 43 | frameStruct.messageData 44 | ) 45 | ) 46 | ) { 47 | bytes32 castHash = bytes32(frameStruct.messageData.frame_action_body.cast_id.hash); 48 | if (castBalance[castHash] >= maxCost) { 49 | castBalance[castHash] -= maxCost; 50 | validationData = 0; 51 | context = abi.encode(maxCost, uint256(castHash), SponsorType.cast); 52 | } 53 | 54 | if (fidBalance[frameStruct.messageData.fid] >= maxCost) { 55 | fidBalance[frameStruct.messageData.fid] -= maxCost; 56 | validationData = 0; 57 | context = abi.encode(maxCost, frameStruct.messageData.fid, SponsorType.fid); 58 | } 59 | } 60 | } 61 | 62 | function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external { 63 | // check msg.sender is entrypoint 64 | 65 | if (mode == PostOpMode.postOpReverted) { 66 | return; 67 | } 68 | 69 | (uint256 maxCost, uint256 identifier, SponsorType sType) = abi.decode(context, (uint256, uint256, SponsorType)); 70 | uint256 credit = maxCost - actualGasCost; 71 | if (sType == SponsorType.cast) { 72 | castBalance[bytes32(identifier)] += credit; 73 | } else { 74 | fidBalance[identifier] += credit; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/examples/ERC4337/UserOperation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | struct UserOperation { 5 | address sender; 6 | uint256 nonce; 7 | bytes initCode; 8 | bytes callData; 9 | uint256 callGasLimit; 10 | uint256 verificationGasLimit; 11 | uint256 preVerificationGas; 12 | uint256 maxFeePerGas; 13 | uint256 maxPriorityFeePerGas; 14 | bytes paymasterAndData; 15 | bytes signature; 16 | } 17 | -------------------------------------------------------------------------------- /src/examples/SharedVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.9; 3 | 4 | import {MessageData, FrameVerifier} from "../FrameVerifier.sol"; 5 | 6 | /// @notice To attempt to save gas verifying Frames in multiple contracts 7 | /// we can use a shared verifier that saves the result 8 | /// @dev WARNING: This was written quickly with no tests, almost certainly has bugs 9 | contract SharedVerifier { 10 | mapping(bytes32 => bool) public isValid; 11 | 12 | struct VerifyRequest { 13 | bytes32 public_key; 14 | bytes32 signature_r; 15 | bytes32 signature_s; 16 | MessageData messageData; 17 | } 18 | 19 | function verifyMessageData(VerifyRequest memory request) external returns (bool) { 20 | bytes32 hash = keccak256(abi.encode(request.messageData)); 21 | if (isValid[hash]) { 22 | return true; 23 | } 24 | 25 | bool valid = FrameVerifier.verifyMessageData( 26 | request.public_key, request.signature_r, request.signature_s, request.messageData 27 | ); 28 | 29 | if (valid) { 30 | isValid[hash] = true; 31 | } 32 | 33 | return valid; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/libraries/Blake3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.9; 3 | 4 | library Blake3 { 5 | uint256 constant BLOCK_LEN = 64; 6 | uint32 constant OUT_LEN = 32; 7 | uint32 constant CHUNK_LEN = 1024; 8 | 9 | // Flag constants 10 | uint32 constant CHUNK_START = 1 << 0; 11 | uint32 constant CHUNK_END = 1 << 1; 12 | uint32 constant PARENT = 1 << 2; 13 | uint32 constant ROOT = 1 << 3; 14 | uint32 constant KEYED_HASH = 1 << 4; 15 | uint32 constant DERIVE_KEY_CONTEXT = 1 << 5; 16 | uint32 constant DERIVE_KEY_MATERIAL = 1 << 6; 17 | 18 | // Product of a ChunkState before deriving chain value 19 | struct Output { 20 | uint32[8] input_chaining_value; 21 | uint32[16] block_words; 22 | uint64 counter; 23 | uint256 block_len; 24 | uint32 flags; 25 | } 26 | 27 | struct ChunkState { 28 | uint32[8] chaining_value; 29 | uint64 chunk_counter; 30 | // Has a max size of BLOCK_LEN 31 | bytes block_bytes; 32 | uint256 block_len; 33 | uint256 blocks_compressed; 34 | uint32 flags; 35 | } 36 | 37 | // An incremental hasher that can accept any number of writes. 38 | struct Hasher { 39 | ChunkState chunk_state; 40 | uint32[8] key_words; 41 | uint32[8][54] cv_stack; // Space for 54 subtree chaining values: 42 | uint8 cv_stack_len; // 2^54 * CHUNK_LEN = 2^64 43 | uint32 flags; 44 | } 45 | 46 | // INTERNAL FUNCTIONS 47 | 48 | // This should remain constant but solidity doesn't support declaring it 49 | // uint8[16] MSG_PERMUTATION = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; 50 | // uint32[8] IV = [ 51 | // 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 52 | // ]; 53 | function _MSG_PERMUTATION() internal pure returns (uint8[16] memory) { 54 | return [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; 55 | } 56 | 57 | function _IV() internal pure returns (uint32[8] memory) { 58 | return [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]; 59 | } 60 | 61 | // Mixing function G 62 | function _g(uint32[16] memory state, uint32 a, uint32 b, uint32 c, uint32 d, uint32 mx, uint32 my) internal pure { 63 | unchecked { 64 | state[a] = state[a] + state[b] + mx; 65 | state[d] = _rotr(state[d] ^ state[a], 16); 66 | state[c] = state[c] + state[d]; 67 | state[b] = _rotr(state[b] ^ state[c], 12); 68 | state[a] = state[a] + state[b] + my; 69 | state[d] = _rotr(state[d] ^ state[a], 8); 70 | state[c] = state[c] + state[d]; 71 | state[b] = _rotr(state[b] ^ state[c], 7); 72 | } 73 | } 74 | 75 | function _round(uint32[16] memory state, uint32[16] memory m) internal pure { 76 | // Mix the columns. 77 | _g(state, 0, 4, 8, 12, m[0], m[1]); 78 | _g(state, 1, 5, 9, 13, m[2], m[3]); 79 | _g(state, 2, 6, 10, 14, m[4], m[5]); 80 | _g(state, 3, 7, 11, 15, m[6], m[7]); 81 | 82 | // Mix the diagonals. 83 | _g(state, 0, 5, 10, 15, m[8], m[9]); 84 | _g(state, 1, 6, 11, 12, m[10], m[11]); 85 | _g(state, 2, 7, 8, 13, m[12], m[13]); 86 | _g(state, 3, 4, 9, 14, m[14], m[15]); 87 | } 88 | 89 | function _permute(uint32[16] memory m) internal pure { 90 | uint8[16] memory MSG_PERMUTATION = _MSG_PERMUTATION(); 91 | uint32[16] memory permuted; 92 | 93 | for (uint256 i = 0; i < 16; ++i) { 94 | permuted[i] = m[MSG_PERMUTATION[i]]; 95 | } 96 | 97 | for (uint256 i = 0; i < 16; ++i) { 98 | m[i] = permuted[i]; 99 | } 100 | } 101 | 102 | function _compress( 103 | uint32[8] memory chaining_value, 104 | uint32[16] memory block_words_ref, 105 | uint64 counter, 106 | uint256 block_len, 107 | uint32 flags 108 | ) internal pure returns (uint32[16] memory) { 109 | uint32[8] memory IV = _IV(); 110 | uint32[16] memory block_words; 111 | for (uint256 i = 0; i < 16; ++i) { 112 | block_words[i] = block_words_ref[i]; 113 | } 114 | 115 | uint32[16] memory state = [ 116 | chaining_value[0], 117 | chaining_value[1], 118 | chaining_value[2], 119 | chaining_value[3], 120 | chaining_value[4], 121 | chaining_value[5], 122 | chaining_value[6], 123 | chaining_value[7], 124 | IV[0], 125 | IV[1], 126 | IV[2], 127 | IV[3], 128 | uint32(counter), 129 | uint32(counter >> 32), 130 | /////////////////////////////// 131 | uint32(block_len), 132 | flags 133 | ]; 134 | 135 | _round(state, block_words); // round 1 136 | _permute(block_words); 137 | _round(state, block_words); // round 2 138 | _permute(block_words); 139 | _round(state, block_words); // round 3 140 | _permute(block_words); 141 | _round(state, block_words); // round 4 142 | _permute(block_words); 143 | _round(state, block_words); // round 5 144 | _permute(block_words); 145 | _round(state, block_words); // round 6 146 | _permute(block_words); 147 | _round(state, block_words); // round 7 148 | 149 | for (uint256 i = 0; i < 8; ++i) { 150 | state[i] ^= state[i + 8]; 151 | state[i + 8] ^= chaining_value[i]; 152 | } 153 | 154 | return state; 155 | } 156 | 157 | function _rotr(uint32 x, uint8 n) internal pure returns (uint32) { 158 | bytes4 b = bytes4(x); 159 | return uint32((b >> n) | (b << (32 - n))); 160 | } 161 | 162 | function _chaining_value(Output memory o) internal pure returns (uint32[8] memory) { 163 | uint32[16] memory compression_output = 164 | _compress(o.input_chaining_value, o.block_words, o.counter, o.block_len, o.flags); 165 | 166 | return _first_8_words(compression_output); 167 | } 168 | 169 | function _root_output_bytes(Output memory self, bytes memory out_slice) internal pure { 170 | //uint32 output_block_counter = 0; 171 | // Take 64-byte chunks at a time from out_slice 172 | //for (uint32 i = 0; i < out_slice.length; i += 2 * OUT_LEN) { 173 | uint32[16] memory words = _compress( 174 | self.input_chaining_value, 175 | self.block_words, 176 | 0, 177 | //output_block_counter, 178 | self.block_len, 179 | self.flags | ROOT 180 | ); 181 | 182 | // Load compressed words into out_slice (4 bytes at a time) 183 | // The output length might not be a multiple of 4. 184 | //for (uint32 j = 0; j < words.length && out_slice.length > j*4; j++) { 185 | //for (uint32 j = 0; j < words.length; j++) { 186 | for (uint32 j = 0; j < 8; j++) { 187 | // Load word at j into out_slice as little endian 188 | _load_uint32_to_le_bytes(words[j], out_slice, j * 4); 189 | } 190 | 191 | //output_block_counter += 1; 192 | //} 193 | } 194 | 195 | function _load_uint32_to_le_bytes(uint32 n, bytes memory buf, uint32 offset) internal pure { 196 | for (uint256 i = 0; i < 4; ++i) { 197 | buf[offset + i] = bytes1(uint8(n / (2 ** (i * 8)))); 198 | } 199 | } 200 | 201 | function _uint32_to_le_bytes(uint32 n) internal pure returns (bytes4) { 202 | bytes4 buf; 203 | for (uint256 i = 0; i < 4; ++i) { 204 | assembly { 205 | let cc := add(buf, 0x20) 206 | let buf_idx := add(cc, sub(3, i)) 207 | let n_idx := add(n, i) 208 | mstore8(buf_idx, n_idx) 209 | } 210 | } 211 | 212 | return buf; 213 | } 214 | 215 | function _le_bytes_get_uint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { 216 | require(_bytes.length >= _start + 4, "le_bytes_get_uint32_outOfBounds"); 217 | uint32 tempUint; 218 | 219 | for (uint256 i = 0; i < 4; ++i) { 220 | //tempUint += uint32(uint8(_bytes[i]) * (2 ** (8*i))); 221 | tempUint += uint32(bytes4(_bytes[3 - i + _start]) >> (8 * i)); 222 | } 223 | /* 224 | assembly { 225 | // TODO why is this 0x4 in the bytes library??? 226 | //tempUint := mload(add(add(_bytes, 0x4), _start)) 227 | 228 | // Load 32 bytes from array (u256) 229 | tempUint := mload(add(add(_bytes, 0x20), _start)) 230 | // Keep just the first 4 bytes (u32) 231 | //tempUint := xor(tempUint, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000) 232 | tempUint := xor(tempUint, 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff) 233 | } 234 | */ 235 | 236 | return tempUint; 237 | } 238 | 239 | function _words_from_little_endian_bytes8(bytes memory data_bytes, uint32[8] memory words) internal pure { 240 | require(data_bytes.length <= 4 * 8, "Data bytes is too long to convert to 8 4-byte words"); 241 | 242 | for (uint256 i = 0; i < data_bytes.length / 4; ++i) { 243 | words[i] = _le_bytes_get_uint32(data_bytes, i * 4); 244 | } 245 | } 246 | 247 | function _words_from_little_endian_bytes(bytes memory data_bytes, uint32[16] memory words) internal pure { 248 | require( 249 | data_bytes.length <= 64 && data_bytes.length % 4 == 0, 250 | "Data bytes is too long to convert to 16 4-byte words" 251 | ); 252 | 253 | for (uint256 i = 0; i < data_bytes.length / 4; ++i) { 254 | words[i] = _le_bytes_get_uint32(data_bytes, i * 4); 255 | } 256 | } 257 | 258 | // TODO I wish this didn't require a copy to convert array sizes 259 | function _first_8_words(uint32[16] memory words) internal pure returns (uint32[8] memory) { 260 | // TODO there must be a way to do this without copying 261 | // How to take a slice of a memory array? 262 | uint32[8] memory first_8; 263 | for (uint256 i = 0; i < 8; ++i) { 264 | first_8[i] = words[i]; 265 | } 266 | 267 | return first_8; 268 | } 269 | 270 | // 271 | // Chunk state functions 272 | // 273 | function _new_chunkstate(uint32[8] memory key_words, uint64 chunk_counter, uint32 flags) 274 | internal 275 | pure 276 | returns (ChunkState memory) 277 | { 278 | bytes memory block_bytes = new bytes(BLOCK_LEN); 279 | return ChunkState({ 280 | chaining_value: key_words, 281 | chunk_counter: chunk_counter, 282 | block_bytes: block_bytes, 283 | block_len: 0, 284 | blocks_compressed: 0, 285 | flags: flags 286 | }); 287 | } 288 | 289 | function _len(ChunkState memory chunk) internal pure returns (uint256) { 290 | return BLOCK_LEN * chunk.blocks_compressed + chunk.block_len; 291 | } 292 | 293 | function _start_flag(ChunkState memory chunk) internal pure returns (uint32) { 294 | if (chunk.blocks_compressed == 0) { 295 | return CHUNK_START; 296 | } else { 297 | return 0; 298 | } 299 | } 300 | 301 | // Returns a new input offset 302 | function _update_chunkstate(ChunkState memory chunk, bytes memory input) internal pure { 303 | //returns (uint32) { 304 | uint256 input_offset = 0; 305 | while (input_offset < input.length) { 306 | // If the block buffer is full, compress it and clear it. More 307 | // input is coming, so this compression is not CHUNK_END. 308 | if (chunk.block_len == BLOCK_LEN) { 309 | uint32[16] memory block_words; 310 | _words_from_little_endian_bytes(chunk.block_bytes, block_words); 311 | chunk.chaining_value = _first_8_words( 312 | _compress( 313 | chunk.chaining_value, 314 | block_words, 315 | chunk.chunk_counter, 316 | BLOCK_LEN, 317 | chunk.flags | _start_flag(chunk) 318 | ) 319 | ); 320 | chunk.blocks_compressed += 1; 321 | // TODO probably cheaper to zero-out byte array than to reallocate 322 | chunk.block_bytes = new bytes(BLOCK_LEN); 323 | chunk.block_len = 0; 324 | } 325 | 326 | // Take enough to fill a block [min(want, input.length)] 327 | uint256 want = BLOCK_LEN - chunk.block_len; 328 | uint256 take = _min(want, input.length - input_offset); 329 | 330 | // Copy bytes from input to chunk block 331 | //chunk.block_bytes[self.block_len as usize..][..take].copy_from_slice(&input[..take]); 332 | for (uint256 i = 0; i < take; ++i) { 333 | // TODO recheck this logic 334 | chunk.block_bytes[i + chunk.block_len] = input[input_offset + i]; 335 | } 336 | /* 337 | bytes memory block_ref = chunk.block_bytes; 338 | uint32 blen = chunk.block_len; 339 | assembly { 340 | let block_addr := add(add(block_ref, 0x20), blen) 341 | let input_addr := add(add(input.offset, 0x20), input_offset) 342 | memorycopy(block_addr, input_addr, take) 343 | } 344 | */ 345 | 346 | chunk.block_len += take; 347 | input_offset += take; 348 | } 349 | } 350 | 351 | function _min(uint256 x, uint256 y) internal pure returns (uint256) { 352 | if (x < y) { 353 | return x; 354 | } else { 355 | return y; 356 | } 357 | } 358 | 359 | function _output(ChunkState memory chunk) internal pure returns (Output memory) { 360 | uint32[16] memory block_words; 361 | _words_from_little_endian_bytes(chunk.block_bytes, block_words); 362 | 363 | return Output({ 364 | input_chaining_value: chunk.chaining_value, 365 | block_words: block_words, 366 | counter: chunk.chunk_counter, 367 | block_len: chunk.block_len, 368 | flags: chunk.flags | _start_flag(chunk) | CHUNK_END 369 | }); 370 | } 371 | 372 | // 373 | // Parent functions 374 | // 375 | function _parent_output( 376 | uint32[8] memory left_child_cv, 377 | uint32[8] memory right_child_cv, 378 | uint32[8] memory key_words, 379 | uint32 flags 380 | ) internal pure returns (Output memory) { 381 | uint32[16] memory block_words; 382 | 383 | for (uint256 i = 0; i < 8; ++i) { 384 | block_words[i] = left_child_cv[i]; 385 | } 386 | 387 | for (uint256 i = 8; i < 16; ++i) { 388 | block_words[i] = right_child_cv[i - 8]; 389 | } 390 | 391 | return Output({ 392 | input_chaining_value: key_words, 393 | block_words: block_words, 394 | counter: 0, // Always 0 for parent nodes. 395 | block_len: BLOCK_LEN, // Always BLOCK_LEN (64) for parent nodes. 396 | flags: PARENT | flags 397 | }); 398 | } 399 | 400 | function _parent_cv( 401 | uint32[8] memory left_child_cv, 402 | uint32[8] memory right_child_cv, 403 | uint32[8] memory key_words, 404 | uint32 flags 405 | ) internal pure returns (uint32[8] memory) { 406 | return _chaining_value(_parent_output(left_child_cv, right_child_cv, key_words, flags)); 407 | } 408 | 409 | // 410 | // Hasher functions 411 | // 412 | function _new_hasher_internal(uint32[8] memory key_words, uint32 flags) internal pure returns (Hasher memory) { 413 | uint32[8][54] memory cv_stack; 414 | return Hasher({ 415 | chunk_state: _new_chunkstate(key_words, 0, flags), 416 | key_words: key_words, 417 | cv_stack: cv_stack, 418 | cv_stack_len: 0, 419 | flags: flags 420 | }); 421 | } 422 | 423 | /// Construct a new `Hasher` for the regular hash function. 424 | function new_hasher() internal pure returns (Hasher memory) { 425 | uint32[8] memory IV = _IV(); 426 | return _new_hasher_internal(IV, 0); 427 | } 428 | 429 | /// Construct a new `Hasher` for the keyed hash function. 430 | function new_keyed(bytes memory key) internal pure returns (Hasher memory) { 431 | uint32[8] memory key_words; 432 | bytes memory key_mem = key; 433 | _words_from_little_endian_bytes8(key_mem, key_words); 434 | return _new_hasher_internal(key_words, KEYED_HASH); 435 | } 436 | 437 | // Construct a new `Hasher` for the key derivation function. The context 438 | // string should be hardcoded, globally unique, and application-specific 439 | function new_derive_key(bytes memory context) internal pure returns (Hasher memory) { 440 | uint32[8] memory IV = _IV(); 441 | Hasher memory context_hasher = _new_hasher_internal(IV, DERIVE_KEY_CONTEXT); 442 | update_hasher(context_hasher, context); 443 | 444 | bytes memory context_key = new bytes(256); 445 | _finalize_internal(context_hasher, context_key); 446 | 447 | uint32[8] memory context_key_words; 448 | _words_from_little_endian_bytes8(context_key, context_key_words); 449 | 450 | return _new_hasher_internal(context_key_words, DERIVE_KEY_MATERIAL); 451 | } 452 | 453 | function _push_stack(Hasher memory self, uint32[8] memory cv) internal pure { 454 | self.cv_stack[self.cv_stack_len] = cv; 455 | self.cv_stack_len += 1; 456 | } 457 | 458 | function _pop_stack(Hasher memory self) internal pure returns (uint32[8] memory) { 459 | self.cv_stack_len -= 1; 460 | return self.cv_stack[self.cv_stack_len]; 461 | } 462 | 463 | function _add_chunk_chaining_value(Hasher memory self, uint32[8] memory new_cv, uint64 total_chunks) 464 | internal 465 | pure 466 | { 467 | while (total_chunks & 1 == 0) { 468 | new_cv = _parent_cv(_pop_stack(self), new_cv, self.key_words, self.flags); 469 | total_chunks >>= 1; 470 | } 471 | 472 | _push_stack(self, new_cv); 473 | } 474 | 475 | function _slice(bytes memory data, uint256 start, uint256 end) internal pure returns (bytes memory) { 476 | uint256 dataSliceLength = end - start; 477 | bytes memory dataSlice = new bytes(dataSliceLength); 478 | 479 | for (uint256 i = 0; i < dataSliceLength; ++i) { 480 | dataSlice[i] = data[start + i]; 481 | } 482 | 483 | return dataSlice; 484 | } 485 | 486 | // Add input to the hash state. This can be called any number of times. 487 | function update_hasher(Hasher memory self, bytes memory input) internal pure returns (Hasher memory) { 488 | uint256 input_offset = 0; 489 | 490 | while (input_offset < input.length) { 491 | // If the current chunk is complete, finalize it and reset the 492 | // chunk state. More input is coming, so this chunk is not ROOT. 493 | if (_len(self.chunk_state) == CHUNK_LEN) { 494 | uint32[8] memory chunk_cv = _chaining_value(_output(self.chunk_state)); 495 | uint64 total_chunks = self.chunk_state.chunk_counter + 1; 496 | 497 | _add_chunk_chaining_value(self, chunk_cv, total_chunks); 498 | 499 | self.chunk_state = _new_chunkstate(self.key_words, total_chunks, self.flags); 500 | } 501 | 502 | // Compress input bytes into the current chunk state. 503 | uint256 want = CHUNK_LEN - _len(self.chunk_state); 504 | uint256 take = _min(want, uint32(input.length - input_offset)); 505 | 506 | // Update chunk state 507 | bytes memory input_slice = _slice(input, input_offset, take + input_offset); 508 | _update_chunkstate(self.chunk_state, input_slice); 509 | 510 | input_offset += take; 511 | } 512 | 513 | return self; 514 | } 515 | 516 | function finalize(Hasher memory self) internal pure returns (bytes memory) { 517 | bytes memory output = new bytes(32); 518 | 519 | _finalize_internal(self, output); 520 | 521 | return output; 522 | } 523 | 524 | function _finalize_internal(Hasher memory self, bytes memory out_slice) internal pure { 525 | // Starting with the Output from the current chunk, compute all the 526 | // parent chaining values along the right edge of the tree, until we 527 | // have the root Output. 528 | Output memory output = _output(self.chunk_state); 529 | uint32 parent_nodes_remaining = self.cv_stack_len; 530 | 531 | while (parent_nodes_remaining > 0) { 532 | parent_nodes_remaining -= 1; 533 | 534 | output = _parent_output( 535 | self.cv_stack[parent_nodes_remaining], _chaining_value(output), self.key_words, self.flags 536 | ); 537 | } 538 | _root_output_bytes(output, out_slice); 539 | } 540 | 541 | function sliceBytes(bytes memory message, uint64 length) internal pure returns (bytes memory) { 542 | require(length <= message.length, "Length exceeds message length"); 543 | 544 | // Overwrite the length field of the bytes to crop the message 545 | assembly { 546 | mstore(message, length) 547 | } 548 | 549 | return message; 550 | } 551 | 552 | function hash(bytes memory message, uint32 length) external pure returns (bytes memory) { 553 | Hasher memory hasher = new_hasher(); 554 | update_hasher(hasher, message); 555 | 556 | return sliceBytes(finalize(hasher), length); 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /src/libraries/Ed25519.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.9; 3 | 4 | import "./Sha512.sol"; 5 | import "./Ed25519_pow.sol"; 6 | 7 | library Ed25519 { 8 | function verify(bytes32 k, bytes32 r, bytes32 s, bytes memory m) external pure returns (bool) { 9 | unchecked { 10 | uint256 hh; 11 | // Step 1: compute SHA-512(R, A, M) 12 | { 13 | bytes memory rs = new bytes(k.length + r.length + m.length); 14 | for (uint256 i = 0; i < r.length; i++) { 15 | rs[i] = r[i]; 16 | } 17 | for (uint256 i = 0; i < k.length; i++) { 18 | rs[i + 32] = k[i]; 19 | } 20 | for (uint256 i = 0; i < m.length; i++) { 21 | rs[i + 64] = m[i]; 22 | } 23 | uint64[8] memory result = Sha512.hash(rs); 24 | 25 | uint256 h0 = uint256(result[0]) | uint256(result[1]) << 64 | uint256(result[2]) << 128 26 | | uint256(result[3]) << 192; 27 | 28 | h0 = ((h0 & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) 29 | | ((h0 & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8); 30 | h0 = ((h0 & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) 31 | | ((h0 & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16); 32 | h0 = ((h0 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) 33 | | ((h0 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32); 34 | 35 | uint256 h1 = uint256(result[4]) | uint256(result[5]) << 64 | uint256(result[6]) << 128 36 | | uint256(result[7]) << 192; 37 | 38 | h1 = ((h1 & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) 39 | | ((h1 & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8); 40 | h1 = ((h1 & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) 41 | | ((h1 & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16); 42 | h1 = ((h1 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) 43 | | ((h1 & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32); 44 | hh = addmod( 45 | h0, 46 | mulmod( 47 | h1, 48 | 0xfffffff_ffffffff_ffffffff_fffffffe_c6ef5bf4_737dcf70_d6ec3174_8d98951d, 49 | 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed 50 | ), 51 | 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed 52 | ); 53 | } 54 | // Step 2: unpack k 55 | k = bytes32( 56 | ((uint256(k) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) 57 | | ((uint256(k) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) 58 | ); 59 | k = bytes32( 60 | ((uint256(k) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) 61 | | ((uint256(k) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) 62 | ); 63 | k = bytes32( 64 | ((uint256(k) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) 65 | | ((uint256(k) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) 66 | ); 67 | k = bytes32( 68 | ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) 69 | | ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) 70 | ); 71 | k = bytes32((uint256(k) << 128) | (uint256(k) >> 128)); 72 | uint256 ky = uint256(k) & 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff; 73 | uint256 kx; 74 | { 75 | uint256 ky2 = mulmod(ky, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 76 | uint256 u = addmod( 77 | ky2, 78 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffec, 79 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 80 | ); 81 | uint256 v = mulmod( 82 | ky2, 83 | 0x52036cee_2b6ffe73_8cc74079_7779e898_00700a4d_4141d8ab_75eb4dca_135978a3, 84 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 85 | ) + 1; 86 | uint256 t = mulmod(u, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 87 | (kx,) = Ed25519_pow.pow22501(t); 88 | kx = mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 89 | kx = mulmod( 90 | u, 91 | mulmod( 92 | mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 93 | t, 94 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 95 | ), 96 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 97 | ); 98 | t = mulmod( 99 | mulmod(kx, kx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 100 | v, 101 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 102 | ); 103 | if (t != u) { 104 | if (t != 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - u) { 105 | return false; 106 | } 107 | kx = mulmod( 108 | kx, 109 | 0x2b832480_4fc1df0b_2b4d0099_3dfbd7a7_2f431806_ad2fe478_c4ee1b27_4a0ea0b0, 110 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 111 | ); 112 | } 113 | } 114 | if ((kx & 1) != uint256(k) >> 255) { 115 | kx = 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx; 116 | } 117 | // Verify s 118 | s = bytes32( 119 | ((uint256(s) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) 120 | | ((uint256(s) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) 121 | ); 122 | s = bytes32( 123 | ((uint256(s) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) 124 | | ((uint256(s) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) 125 | ); 126 | s = bytes32( 127 | ((uint256(s) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) 128 | | ((uint256(s) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) 129 | ); 130 | s = bytes32( 131 | ((uint256(s) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) 132 | | ((uint256(s) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) 133 | ); 134 | s = bytes32((uint256(s) << 128) | (uint256(s) >> 128)); 135 | if (uint256(s) >= 0x10000000_00000000_00000000_00000000_14def9de_a2f79cd6_5812631a_5cf5d3ed) { 136 | return false; 137 | } 138 | uint256 vx; 139 | uint256 vu; 140 | uint256 vy; 141 | uint256 vv; 142 | // Step 3: compute multiples of k 143 | uint256[8][3][2] memory tables; 144 | { 145 | uint256 ks = ky + kx; 146 | uint256 kd = ky + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - kx; 147 | uint256 k2dt = mulmod( 148 | mulmod(kx, ky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 149 | 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159, 150 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 151 | ); 152 | uint256 kky = ky; 153 | uint256 kkx = kx; 154 | uint256 kku = 1; 155 | uint256 kkv = 1; 156 | { 157 | uint256 xx = 158 | mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 159 | uint256 yy = 160 | mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 161 | uint256 zz = 162 | mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 163 | uint256 xx2 = 164 | mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 165 | uint256 yy2 = 166 | mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 167 | uint256 xxyy = 168 | mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 169 | uint256 zz2 = 170 | mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 171 | kkx = xxyy + xxyy; 172 | kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 173 | kky = xx2 + yy2; 174 | kkv = addmod( 175 | zz2 + zz2, 176 | 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 177 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 178 | ); 179 | } 180 | { 181 | uint256 xx = 182 | mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 183 | uint256 yy = 184 | mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 185 | uint256 zz = 186 | mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 187 | uint256 xx2 = 188 | mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 189 | uint256 yy2 = 190 | mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 191 | uint256 xxyy = 192 | mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 193 | uint256 zz2 = 194 | mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 195 | kkx = xxyy + xxyy; 196 | kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 197 | kky = xx2 + yy2; 198 | kkv = addmod( 199 | zz2 + zz2, 200 | 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 201 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 202 | ); 203 | } 204 | { 205 | uint256 xx = 206 | mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 207 | uint256 yy = 208 | mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 209 | uint256 zz = 210 | mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 211 | uint256 xx2 = 212 | mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 213 | uint256 yy2 = 214 | mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 215 | uint256 xxyy = 216 | mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 217 | uint256 zz2 = 218 | mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 219 | kkx = xxyy + xxyy; 220 | kku = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 221 | kky = xx2 + yy2; 222 | kkv = addmod( 223 | zz2 + zz2, 224 | 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - kku, 225 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 226 | ); 227 | } 228 | uint256 cprod = 1; 229 | uint256[8][3][2] memory tables_ = tables; 230 | for (uint256 i = 0;; i++) { 231 | uint256 cs; 232 | uint256 cd; 233 | uint256 ct; 234 | uint256 c2z; 235 | { 236 | uint256 cx = 237 | mulmod(kkx, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 238 | uint256 cy = 239 | mulmod(kky, kku, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 240 | uint256 cz = 241 | mulmod(kku, kkv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 242 | ct = mulmod(kkx, kky, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 243 | cs = cy + cx; 244 | cd = cy - cx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 245 | c2z = cz + cz; 246 | } 247 | tables_[1][0][i] = cs; 248 | tables_[1][1][i] = cd; 249 | tables_[1][2][i] = mulmod( 250 | ct, 251 | 0x2406d9dc_56dffce7_198e80f2_eef3d130_00e0149a_8283b156_ebd69b94_26b2f159, 252 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 253 | ); 254 | tables_[0][0][i] = c2z; 255 | tables_[0][1][i] = cprod; 256 | cprod = 257 | mulmod(cprod, c2z, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 258 | if (i == 7) { 259 | break; 260 | } 261 | uint256 ab = 262 | mulmod(cs, ks, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 263 | uint256 aa = 264 | mulmod(cd, kd, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 265 | uint256 ac = 266 | mulmod(ct, k2dt, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 267 | kkx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 268 | kku = addmod(c2z, ac, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 269 | kky = ab + aa; 270 | kkv = addmod( 271 | c2z, 272 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed - ac, 273 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 274 | ); 275 | } 276 | uint256 t; 277 | (cprod, t) = Ed25519_pow.pow22501(cprod); 278 | cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 279 | cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 280 | cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 281 | cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 282 | cprod = mulmod(cprod, cprod, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 283 | cprod = mulmod(cprod, t, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 284 | for (uint256 i = 7;; i--) { 285 | uint256 cinv = mulmod( 286 | cprod, 287 | tables_[0][1][i], 288 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 289 | ); 290 | tables_[1][0][i] = mulmod( 291 | tables_[1][0][i], 292 | cinv, 293 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 294 | ); 295 | tables_[1][1][i] = mulmod( 296 | tables_[1][1][i], 297 | cinv, 298 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 299 | ); 300 | tables_[1][2][i] = mulmod( 301 | tables_[1][2][i], 302 | cinv, 303 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 304 | ); 305 | if (i == 0) { 306 | break; 307 | } 308 | cprod = mulmod( 309 | cprod, 310 | tables_[0][0][i], 311 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 312 | ); 313 | } 314 | tables_[0] = [ 315 | [ 316 | 0x43e7ce9d_19ea5d32_9385a44c_321ea161_67c996e3_7dc6070c_97de49e3_7ac61db9, 317 | 0x40cff344_25d8ec30_a3bb74ba_58cd5854_fa1e3818_6ad0d31e_bc8ae251_ceb2c97e, 318 | 0x459bd270_46e8dd45_aea7008d_b87a5a8f_79067792_53d64523_58951859_9fdfbf4b, 319 | 0x69fdd1e2_8c23cc38_94d0c8ff_90e76f6d_5b6e4c2e_620136d0_4dd83c4a_51581ab9, 320 | 0x54dceb34_13ce5cfa_11196dfc_960b6eda_f4b380c6_d4d23784_19cc0279_ba49c5f3, 321 | 0x4e24184d_d71a3d77_eef3729f_7f8cf7c1_7224cf40_aa7b9548_b9942f3c_5084ceed, 322 | 0x5a0e5aab_20262674_ae117576_1cbf5e88_9b52a55f_d7ac5027_c228cebd_c8d2360a, 323 | 0x26239334_073e9b38_c6285955_6d451c3d_cc8d30e8_4b361174_f488eadd_e2cf17d9 324 | ], 325 | [ 326 | 0x227e97c9_4c7c0933_d2e0c21a_3447c504_fe9ccf82_e8a05f59_ce881c82_eba0489f, 327 | 0x226a3e0e_cc4afec6_fd0d2884_13014a9d_bddecf06_c1a2f0bb_702ba77c_613d8209, 328 | 0x34d7efc8_51d45c5e_71efeb0f_235b7946_91de6228_877569b3_a8d52bf0_58b8a4a0, 329 | 0x3c1f5fb3_ca7166fc_e1471c9b_752b6d28_c56301ad_7b65e845_1b2c8c55_26726e12, 330 | 0x6102416c_f02f02ff_5be75275_f55f28db_89b2a9d2_456b860c_e22fc0e5_031f7cc5, 331 | 0x40adf677_f1bfdae0_57f0fd17_9c126179_18ddaa28_91a6530f_b1a4294f_a8665490, 332 | 0x61936f3c_41560904_6187b8ba_a978cbc9_b4789336_3ae5a3cc_7d909f36_35ae7f48, 333 | 0x562a9662_b6ec47f9_e979d473_c02b51e4_42336823_8c58ddb5_2f0e5c6a_180e6410 334 | ], 335 | [ 336 | 0x3788bdb4_4f8632d4_2d0dbee5_eea1acc6_136cf411_e655624f_55e48902_c3bd5534, 337 | 0x6190cf2c_2a7b5ad7_69d594a8_2844f23b_4167fa7c_8ac30e51_aa6cfbeb_dcd4b945, 338 | 0x65f77870_96be9204_123a71f3_ac88a87b_e1513217_737d6a1e_2f3a13a4_3d7e3a9a, 339 | 0x23af32d_bfa67975_536479a7_a7ce74a0_2142147f_ac048018_7f1f1334_9cda1f2d, 340 | 0x64fc44b7_fc6841bd_db0ced8b_8b0fe675_9137ef87_ee966512_15fc1dbc_d25c64dc, 341 | 0x1434aa37_48b701d5_b69df3d7_d340c1fe_3f6b9c1e_fc617484_caadb47e_382f4475, 342 | 0x457a6da8_c962ef35_f2b21742_3e5844e9_d2353452_7e8ea429_0d24e3dd_f21720c6, 343 | 0x63b9540c_eb60ccb5_1e4d989d_956e053c_f2511837_efb79089_d2ff4028_4202c53d 344 | ] 345 | ]; 346 | } 347 | // Step 4: compute s*G - h*A 348 | { 349 | uint256 ss = uint256(s) << 3; 350 | uint256 hhh = hh + 0x80000000_00000000_00000000_00000000_a6f7cef5_17bce6b2_c09318d2_e7ae9f60; 351 | uint256 vvx = 0; 352 | uint256 vvu = 1; 353 | uint256 vvy = 1; 354 | uint256 vvv = 1; 355 | for (uint256 i = 252;; i--) { 356 | uint256 bit = 8 << i; 357 | if ((ss & bit) != 0) { 358 | uint256 ws; 359 | uint256 wd; 360 | uint256 wz; 361 | uint256 wt; 362 | { 363 | uint256 wx = mulmod( 364 | vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 365 | ); 366 | uint256 wy = mulmod( 367 | vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 368 | ); 369 | ws = wy + wx; 370 | wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 371 | wz = mulmod( 372 | vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 373 | ); 374 | wt = mulmod( 375 | vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 376 | ); 377 | } 378 | uint256 j = (ss >> i) & 7; 379 | ss &= ~(7 << i); 380 | uint256[8][3][2] memory tables_ = tables; 381 | uint256 aa = mulmod( 382 | wd, 383 | tables_[0][1][j], 384 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 385 | ); 386 | uint256 ab = mulmod( 387 | ws, 388 | tables_[0][0][j], 389 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 390 | ); 391 | uint256 ac = mulmod( 392 | wt, 393 | tables_[0][2][j], 394 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 395 | ); 396 | vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 397 | vvu = wz + ac; 398 | vvy = ab + aa; 399 | vvv = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 400 | } 401 | if ((hhh & bit) != 0) { 402 | uint256 ws; 403 | uint256 wd; 404 | uint256 wz; 405 | uint256 wt; 406 | { 407 | uint256 wx = mulmod( 408 | vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 409 | ); 410 | uint256 wy = mulmod( 411 | vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 412 | ); 413 | ws = wy + wx; 414 | wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 415 | wz = mulmod( 416 | vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 417 | ); 418 | wt = mulmod( 419 | vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 420 | ); 421 | } 422 | uint256 j = (hhh >> i) & 7; 423 | hhh &= ~(7 << i); 424 | uint256[8][3][2] memory tables_ = tables; 425 | uint256 aa = mulmod( 426 | wd, 427 | tables_[1][0][j], 428 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 429 | ); 430 | uint256 ab = mulmod( 431 | ws, 432 | tables_[1][1][j], 433 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 434 | ); 435 | uint256 ac = mulmod( 436 | wt, 437 | tables_[1][2][j], 438 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 439 | ); 440 | vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 441 | vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 442 | vvy = ab + aa; 443 | vvv = wz + ac; 444 | } 445 | if (i == 0) { 446 | uint256 ws; 447 | uint256 wd; 448 | uint256 wz; 449 | uint256 wt; 450 | { 451 | uint256 wx = mulmod( 452 | vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 453 | ); 454 | uint256 wy = mulmod( 455 | vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 456 | ); 457 | ws = wy + wx; 458 | wd = wy - wx + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 459 | wz = mulmod( 460 | vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 461 | ); 462 | wt = mulmod( 463 | vvx, vvy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 464 | ); 465 | } 466 | uint256 j = hhh & 7; 467 | uint256[8][3][2] memory tables_ = tables; 468 | uint256 aa = mulmod( 469 | wd, 470 | tables_[1][0][j], 471 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 472 | ); 473 | uint256 ab = mulmod( 474 | ws, 475 | tables_[1][1][j], 476 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 477 | ); 478 | uint256 ac = mulmod( 479 | wt, 480 | tables_[1][2][j], 481 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 482 | ); 483 | vvx = ab - aa + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 484 | vvu = wz - ac + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 485 | vvy = ab + aa; 486 | vvv = wz + ac; 487 | break; 488 | } 489 | { 490 | uint256 xx = 491 | mulmod(vvx, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 492 | uint256 yy = 493 | mulmod(vvy, vvu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 494 | uint256 zz = 495 | mulmod(vvu, vvv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 496 | uint256 xx2 = 497 | mulmod(xx, xx, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 498 | uint256 yy2 = 499 | mulmod(yy, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 500 | uint256 xxyy = 501 | mulmod(xx, yy, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 502 | uint256 zz2 = 503 | mulmod(zz, zz, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 504 | vvx = xxyy + xxyy; 505 | vvu = yy2 - xx2 + 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed; 506 | vvy = xx2 + yy2; 507 | vvv = addmod( 508 | zz2 + zz2, 509 | 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffda - vvu, 510 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 511 | ); 512 | } 513 | } 514 | vx = vvx; 515 | vu = vvu; 516 | vy = vvy; 517 | vv = vvv; 518 | } 519 | // Step 5: compare the points 520 | (uint256 vi, uint256 vj) = Ed25519_pow.pow22501( 521 | mulmod(vu, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed) 522 | ); 523 | vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 524 | vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 525 | vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 526 | vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 527 | vi = mulmod(vi, vi, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 528 | vi = mulmod(vi, vj, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 529 | vx = mulmod( 530 | vx, 531 | mulmod(vi, vv, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 532 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 533 | ); 534 | vy = mulmod( 535 | vy, 536 | mulmod(vi, vu, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 537 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 538 | ); 539 | bytes32 vr = bytes32(vy | (vx << 255)); 540 | vr = bytes32( 541 | ((uint256(vr) & 0xff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff_00ff00ff) << 8) 542 | | ((uint256(vr) & 0xff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00_ff00ff00) >> 8) 543 | ); 544 | vr = bytes32( 545 | ((uint256(vr) & 0xffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff_0000ffff) << 16) 546 | | ((uint256(vr) & 0xffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000_ffff0000) >> 16) 547 | ); 548 | vr = bytes32( 549 | ((uint256(vr) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff) << 32) 550 | | ((uint256(vr) & 0xffffffff_00000000_ffffffff_00000000_ffffffff_00000000_ffffffff_00000000) >> 32) 551 | ); 552 | vr = bytes32( 553 | ((uint256(vr) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff) << 64) 554 | | ((uint256(vr) & 0xffffffff_ffffffff_00000000_00000000_ffffffff_ffffffff_00000000_00000000) >> 64) 555 | ); 556 | vr = bytes32((uint256(vr) << 128) | (uint256(vr) >> 128)); 557 | 558 | return vr == r; 559 | } 560 | } 561 | } 562 | -------------------------------------------------------------------------------- /src/libraries/Ed25519_pow.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.9; 3 | 4 | library Ed25519_pow { 5 | // Computes (v^(2^250-1), v^11) mod p 6 | function pow22501(uint256 v) external pure returns (uint256 p22501, uint256 p11) { 7 | p11 = mulmod(v, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 8 | p22501 = mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 9 | p22501 = mulmod( 10 | mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 11 | v, 12 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 13 | ); 14 | p11 = mulmod(p22501, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 15 | p22501 = mulmod( 16 | mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed), 17 | p22501, 18 | 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed 19 | ); 20 | uint256 a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 21 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 22 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 23 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 24 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 25 | p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 26 | a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 27 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 28 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 29 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 30 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 31 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 32 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 33 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 34 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 35 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 36 | a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 37 | uint256 b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 38 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 39 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 40 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 41 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 42 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 43 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 44 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 45 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 46 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 47 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 48 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 49 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 50 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 51 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 52 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 53 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 54 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 55 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 56 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 57 | a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 58 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 59 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 60 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 61 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 62 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 63 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 64 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 65 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 66 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 67 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 68 | p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 69 | a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 70 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 71 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 72 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 73 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 74 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 75 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 76 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 77 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 78 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 79 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 80 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 81 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 82 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 83 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 84 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 85 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 86 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 87 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 88 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 89 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 90 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 91 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 92 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 93 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 94 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 95 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 96 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 97 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 98 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 99 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 100 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 101 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 102 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 103 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 104 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 105 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 106 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 107 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 108 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 109 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 110 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 111 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 112 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 113 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 114 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 115 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 116 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 117 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 118 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 119 | a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 120 | b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 121 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 122 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 123 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 124 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 125 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 126 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 127 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 128 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 129 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 130 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 131 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 132 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 133 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 134 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 135 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 136 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 137 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 138 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 139 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 140 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 141 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 142 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 143 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 144 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 145 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 146 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 147 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 148 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 149 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 150 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 151 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 152 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 153 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 154 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 155 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 156 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 157 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 158 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 159 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 160 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 161 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 162 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 163 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 164 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 165 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 166 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 167 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 168 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 169 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 170 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 171 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 172 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 173 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 174 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 175 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 176 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 177 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 178 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 179 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 180 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 181 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 182 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 183 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 184 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 185 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 186 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 187 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 188 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 189 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 190 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 191 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 192 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 193 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 194 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 195 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 196 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 197 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 198 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 199 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 200 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 201 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 202 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 203 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 204 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 205 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 206 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 207 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 208 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 209 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 210 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 211 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 212 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 213 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 214 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 215 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 216 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 217 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 218 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 219 | b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 220 | a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 221 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 222 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 223 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 224 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 225 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 226 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 227 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 228 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 229 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 230 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 231 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 232 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 233 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 234 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 235 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 236 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 237 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 238 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 239 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 240 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 241 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 242 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 243 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 244 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 245 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 246 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 247 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 248 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 249 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 250 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 251 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 252 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 253 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 254 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 255 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 256 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 257 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 258 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 259 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 260 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 261 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 262 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 263 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 264 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 265 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 266 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 267 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 268 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 269 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 270 | a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 271 | p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/libraries/ProtobufLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // from https://github.com/celestiaorg/protobuf3-solidity-lib/blob/master/contracts/ProtobufLib.sol 3 | pragma solidity >=0.8.4 <0.9.0; 4 | 5 | library ProtobufLib { 6 | /// @notice Protobuf wire types. 7 | enum WireType { 8 | Varint, 9 | Bits64, 10 | LengthDelimited, 11 | StartGroup, 12 | EndGroup, 13 | Bits32, 14 | WIRE_TYPE_MAX 15 | } 16 | 17 | /// @dev Maximum number of bytes for a varint. 18 | /// @dev 64 bits, in groups of base-128 (7 bits). 19 | uint64 internal constant MAX_VARINT_BYTES = 10; 20 | 21 | //////////////////////////////////// 22 | // Decoding 23 | //////////////////////////////////// 24 | 25 | /// @notice Decode key. 26 | /// @dev https://developers.google.com/protocol-buffers/docs/encoding#structure 27 | /// @param p Position 28 | /// @param buf Buffer 29 | /// @return Success 30 | /// @return New position 31 | /// @return Field number 32 | /// @return Wire type 33 | function decode_key(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64, WireType) { 34 | // The key is a varint with encoding 35 | // (field_number << 3) | wire_type 36 | (bool success, uint64 pos, uint64 key) = decode_varint(p, buf); 37 | if (!success) { 38 | return (false, pos, 0, WireType.WIRE_TYPE_MAX); 39 | } 40 | 41 | uint64 field_number = key >> 3; 42 | uint64 wire_type_val = key & 0x07; 43 | // Check that wire type is bounded 44 | if (wire_type_val >= uint64(WireType.WIRE_TYPE_MAX)) { 45 | return (false, pos, 0, WireType.WIRE_TYPE_MAX); 46 | } 47 | WireType wire_type = WireType(wire_type_val); 48 | 49 | // Start and end group types are deprecated, so forbid them 50 | if (wire_type == WireType.StartGroup || wire_type == WireType.EndGroup) { 51 | return (false, pos, 0, WireType.WIRE_TYPE_MAX); 52 | } 53 | 54 | return (true, pos, field_number, wire_type); 55 | } 56 | 57 | /// @notice Decode varint. 58 | /// @dev https://developers.google.com/protocol-buffers/docs/encoding#varints 59 | /// @param p Position 60 | /// @param buf Buffer 61 | /// @return Success 62 | /// @return New position 63 | /// @return Decoded int 64 | function decode_varint(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 65 | uint64 val; 66 | uint64 i; 67 | 68 | for (i = 0; i < MAX_VARINT_BYTES; i++) { 69 | // Check that index is within bounds 70 | if (i + p >= buf.length) { 71 | return (false, p, 0); 72 | } 73 | 74 | // Get byte at offset 75 | uint8 b = uint8(buf[p + i]); 76 | 77 | // Highest bit is used to indicate if there are more bytes to come 78 | // Mask to get 7-bit value: 0111 1111 79 | uint8 v = b & 0x7F; 80 | 81 | // Groups of 7 bits are ordered least significant first 82 | val |= uint64(v) << uint64(i * 7); 83 | 84 | // Mask to get keep going bit: 1000 0000 85 | if (b & 0x80 == 0) { 86 | // [STRICT] 87 | // Check for trailing zeroes if more than one byte is used 88 | // (the value 0 still uses one byte) 89 | if (i > 0 && v == 0) { 90 | return (false, p, 0); 91 | } 92 | 93 | break; 94 | } 95 | } 96 | 97 | // Check that at most MAX_VARINT_BYTES are used 98 | if (i >= MAX_VARINT_BYTES) { 99 | return (false, p, 0); 100 | } 101 | 102 | // [STRICT] 103 | // If all 10 bytes are used, the last byte (most significant 7 bits) 104 | // must be at most 0000 0001, since 7*9 = 63 105 | if (i == MAX_VARINT_BYTES - 1) { 106 | if (uint8(buf[p + i]) > 1) { 107 | return (false, p, 0); 108 | } 109 | } 110 | 111 | return (true, p + i + 1, val); 112 | } 113 | 114 | /// @notice Decode varint int32. 115 | /// @param p Position 116 | /// @param buf Buffer 117 | /// @return Success 118 | /// @return New position 119 | /// @return Decoded int 120 | function decode_int32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int32) { 121 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 122 | if (!success) { 123 | return (false, pos, 0); 124 | } 125 | 126 | // [STRICT] 127 | // Highest 4 bytes must be 0 if positive 128 | if (val >> 63 == 0) { 129 | if (val & 0xFFFFFFFF00000000 != 0) { 130 | return (false, pos, 0); 131 | } 132 | } 133 | 134 | return (true, pos, int32(uint32(val))); 135 | } 136 | 137 | /// @notice Decode varint int64. 138 | /// @param p Position 139 | /// @param buf Buffer 140 | /// @return Success 141 | /// @return New position 142 | /// @return Decoded int 143 | function decode_int64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int64) { 144 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 145 | if (!success) { 146 | return (false, pos, 0); 147 | } 148 | 149 | return (true, pos, int64(val)); 150 | } 151 | 152 | /// @notice Decode varint uint32. 153 | /// @param p Position 154 | /// @param buf Buffer 155 | /// @return Success 156 | /// @return New position 157 | /// @return Decoded int 158 | function decode_uint32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint32) { 159 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 160 | if (!success) { 161 | return (false, pos, 0); 162 | } 163 | 164 | // [STRICT] 165 | // Highest 4 bytes must be 0 166 | if (val & 0xFFFFFFFF00000000 != 0) { 167 | return (false, pos, 0); 168 | } 169 | 170 | return (true, pos, uint32(val)); 171 | } 172 | 173 | /// @notice Decode varint uint64. 174 | /// @param p Position 175 | /// @param buf Buffer 176 | /// @return Success 177 | /// @return New position 178 | /// @return Decoded int 179 | function decode_uint64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 180 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 181 | if (!success) { 182 | return (false, pos, 0); 183 | } 184 | 185 | return (true, pos, val); 186 | } 187 | 188 | /// @notice Decode varint sint32. 189 | /// @param p Position 190 | /// @param buf Buffer 191 | /// @return Success 192 | /// @return New position 193 | /// @return Decoded int 194 | function decode_sint32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int32) { 195 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 196 | if (!success) { 197 | return (false, pos, 0); 198 | } 199 | 200 | // [STRICT] 201 | // Highest 4 bytes must be 0 202 | if (val & 0xFFFFFFFF00000000 != 0) { 203 | return (false, pos, 0); 204 | } 205 | 206 | // https://stackoverflow.com/questions/2210923/zig-zag-decoding/2211086#2211086 207 | uint64 zigzag_val; 208 | unchecked { 209 | zigzag_val = (val >> 1) - (~(val & 1) + 1); 210 | } 211 | 212 | return (true, pos, int32(uint32(zigzag_val))); 213 | } 214 | 215 | /// @notice Decode varint sint64. 216 | /// @param p Position 217 | /// @param buf Buffer 218 | /// @return Success 219 | /// @return New position 220 | /// @return Decoded int 221 | function decode_sint64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int64) { 222 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 223 | if (!success) { 224 | return (false, pos, 0); 225 | } 226 | 227 | // https://stackoverflow.com/questions/2210923/zig-zag-decoding/2211086#2211086 228 | uint64 zigzag_val; 229 | unchecked { 230 | zigzag_val = (val >> 1) - (~(val & 1) + 1); 231 | } 232 | 233 | return (true, pos, int64(zigzag_val)); 234 | } 235 | 236 | /// @notice Decode Boolean. 237 | /// @param p Position 238 | /// @param buf Buffer 239 | /// @return Success 240 | /// @return New position 241 | /// @return Decoded bool 242 | function decode_bool(uint64 p, bytes memory buf) internal pure returns (bool, uint64, bool) { 243 | (bool success, uint64 pos, uint64 val) = decode_varint(p, buf); 244 | if (!success) { 245 | return (false, pos, false); 246 | } 247 | 248 | // [STRICT] 249 | // Value must be 0 or 1 250 | if (val > 1) { 251 | return (false, pos, false); 252 | } 253 | 254 | if (val == 0) { 255 | return (true, pos, false); 256 | } 257 | 258 | return (true, pos, true); 259 | } 260 | 261 | /// @notice Decode enumeration. 262 | /// @param p Position 263 | /// @param buf Buffer 264 | /// @return Success 265 | /// @return New position 266 | /// @return Decoded enum as raw int 267 | function decode_enum(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int32) { 268 | return decode_int32(p, buf); 269 | } 270 | 271 | /// @notice Decode fixed 64-bit int. 272 | /// @param p Position 273 | /// @param buf Buffer 274 | /// @return Success 275 | /// @return New position 276 | /// @return Decoded int 277 | function decode_bits64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 278 | uint64 val; 279 | 280 | // Check that index is within bounds 281 | if (8 + p > buf.length) { 282 | return (false, p, 0); 283 | } 284 | 285 | for (uint64 i = 0; i < 8; i++) { 286 | uint8 b = uint8(buf[p + i]); 287 | 288 | // Little endian 289 | val |= uint64(b) << uint64(i * 8); 290 | } 291 | 292 | return (true, p + 8, val); 293 | } 294 | 295 | /// @notice Decode fixed uint64. 296 | /// @param p Position 297 | /// @param buf Buffer 298 | /// @return Success 299 | /// @return New position 300 | /// @return Decoded int 301 | function decode_fixed64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 302 | (bool success, uint64 pos, uint64 val) = decode_bits64(p, buf); 303 | if (!success) { 304 | return (false, pos, 0); 305 | } 306 | 307 | return (true, pos, val); 308 | } 309 | 310 | /// @notice Decode fixed int64. 311 | /// @param p Position 312 | /// @param buf Buffer 313 | /// @return Success 314 | /// @return New position 315 | /// @return Decoded int 316 | function decode_sfixed64(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int64) { 317 | (bool success, uint64 pos, uint64 val) = decode_bits64(p, buf); 318 | if (!success) { 319 | return (false, pos, 0); 320 | } 321 | 322 | return (true, pos, int64(val)); 323 | } 324 | 325 | /// @notice Decode fixed 32-bit int. 326 | /// @param p Position 327 | /// @param buf Buffer 328 | /// @return Success 329 | /// @return New position 330 | /// @return Decoded int 331 | function decode_bits32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint32) { 332 | uint32 val; 333 | 334 | // Check that index is within bounds 335 | if (4 + p > buf.length) { 336 | return (false, p, 0); 337 | } 338 | 339 | for (uint64 i = 0; i < 4; i++) { 340 | uint8 b = uint8(buf[p + i]); 341 | 342 | // Little endian 343 | val |= uint32(b) << uint32(i * 8); 344 | } 345 | 346 | return (true, p + 4, val); 347 | } 348 | 349 | /// @notice Decode fixed uint32. 350 | /// @param p Position 351 | /// @param buf Buffer 352 | /// @return Success 353 | /// @return New position 354 | /// @return Decoded int 355 | function decode_fixed32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint32) { 356 | (bool success, uint64 pos, uint32 val) = decode_bits32(p, buf); 357 | if (!success) { 358 | return (false, pos, 0); 359 | } 360 | 361 | return (true, pos, val); 362 | } 363 | 364 | /// @notice Decode fixed int32. 365 | /// @param p Position 366 | /// @param buf Buffer 367 | /// @return Success 368 | /// @return New position 369 | /// @return Decoded int 370 | function decode_sfixed32(uint64 p, bytes memory buf) internal pure returns (bool, uint64, int32) { 371 | (bool success, uint64 pos, uint32 val) = decode_bits32(p, buf); 372 | if (!success) { 373 | return (false, pos, 0); 374 | } 375 | 376 | return (true, pos, int32(val)); 377 | } 378 | 379 | /// @notice Decode length-delimited field. 380 | /// @param p Position 381 | /// @param buf Buffer 382 | /// @return Success 383 | /// @return New position (after size) 384 | /// @return Size in bytes 385 | function decode_length_delimited(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 386 | // Length-delimited fields begin with a varint of the number of bytes that follow 387 | (bool success, uint64 pos, uint64 size) = decode_varint(p, buf); 388 | if (!success) { 389 | return (false, pos, 0); 390 | } 391 | 392 | // Check for overflow 393 | unchecked { 394 | if (pos + size < pos) { 395 | return (false, pos, 0); 396 | } 397 | } 398 | 399 | // Check that index is within bounds 400 | if (size + pos > buf.length) { 401 | return (false, pos, 0); 402 | } 403 | 404 | return (true, pos, size); 405 | } 406 | 407 | /// @notice Decode string. 408 | /// @param p Position 409 | /// @param buf Buffer 410 | /// @return Success 411 | /// @return New position 412 | /// @return Size in bytes 413 | function decode_string(uint64 p, bytes memory buf) internal pure returns (bool, uint64, string memory) { 414 | (bool success, uint64 pos, uint64 size) = decode_length_delimited(p, buf); 415 | if (!success) { 416 | return (false, pos, ""); 417 | } 418 | 419 | bytes memory field = new bytes(size); 420 | for (uint64 i = 0; i < size; i++) { 421 | field[i] = buf[pos + i]; 422 | } 423 | 424 | return (true, pos + size, string(field)); 425 | } 426 | 427 | /// @notice Decode bytes array. 428 | /// @param p Position 429 | /// @param buf Buffer 430 | /// @return Success 431 | /// @return New position (after size) 432 | /// @return Size in bytes 433 | function decode_bytes(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 434 | return decode_length_delimited(p, buf); 435 | } 436 | 437 | /// @notice Decode embedded message. 438 | /// @param p Position 439 | /// @param buf Buffer 440 | /// @return Success 441 | /// @return New position (after size) 442 | /// @return Size in bytes 443 | function decode_embedded_message(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 444 | return decode_length_delimited(p, buf); 445 | } 446 | 447 | /// @notice Decode packed repeated field. 448 | /// @param p Position 449 | /// @param buf Buffer 450 | /// @return Success 451 | /// @return New position (after size) 452 | /// @return Size in bytes 453 | function decode_packed_repeated(uint64 p, bytes memory buf) internal pure returns (bool, uint64, uint64) { 454 | return decode_length_delimited(p, buf); 455 | } 456 | 457 | //////////////////////////////////// 458 | // Encoding 459 | //////////////////////////////////// 460 | 461 | /// @notice Encode key. 462 | /// @dev https://developers.google.com/protocol-buffers/docs/encoding#structure 463 | /// @param field_number Field number 464 | /// @param wire_type Wire type 465 | /// @return Marshaled bytes 466 | function encode_key(uint64 field_number, uint64 wire_type) internal pure returns (bytes memory) { 467 | uint64 key = (field_number << 3) | wire_type; 468 | 469 | bytes memory buf = encode_varint(key); 470 | 471 | return buf; 472 | } 473 | 474 | /// @notice Encode varint. 475 | /// @dev https://developers.google.com/protocol-buffers/docs/encoding#varints 476 | /// @param n Number 477 | /// @return Marshaled bytes 478 | function encode_varint(uint64 n) internal pure returns (bytes memory) { 479 | // Count the number of groups of 7 bits 480 | // We need this pre-processing step since Solidity doesn't allow dynamic memory resizing 481 | uint64 tmp = n; 482 | uint64 num_bytes = 1; 483 | while (tmp > 0x7F) { 484 | tmp = tmp >> 7; 485 | num_bytes += 1; 486 | } 487 | 488 | bytes memory buf = new bytes(num_bytes); 489 | 490 | tmp = n; 491 | for (uint64 i = 0; i < num_bytes; i++) { 492 | // Set the first bit in the byte for each group of 7 bits 493 | buf[i] = bytes1(0x80 | uint8(tmp & 0x7F)); 494 | tmp = tmp >> 7; 495 | } 496 | // Unset the first bit of the last byte 497 | buf[num_bytes - 1] &= 0x7F; 498 | 499 | return buf; 500 | } 501 | 502 | /// @notice Encode varint int32. 503 | /// @param n Number 504 | /// @return Marshaled bytes 505 | function encode_int32(int32 n) internal pure returns (bytes memory) { 506 | return encode_varint(uint64(int64(n))); 507 | } 508 | 509 | /// @notice Decode varint int64. 510 | /// @param n Number 511 | /// @return Marshaled bytes 512 | function encode_int64(int64 n) internal pure returns (bytes memory) { 513 | return encode_varint(uint64(n)); 514 | } 515 | 516 | /// @notice Encode varint uint32. 517 | /// @param n Number 518 | /// @return Marshaled bytes 519 | function encode_uint32(uint32 n) internal pure returns (bytes memory) { 520 | return encode_varint(n); 521 | } 522 | 523 | /// @notice Encode varint uint64. 524 | /// @param n Number 525 | /// @return Marshaled bytes 526 | function encode_uint64(uint64 n) internal pure returns (bytes memory) { 527 | return encode_varint(n); 528 | } 529 | 530 | /// @notice Encode varint sint32. 531 | /// @param n Number 532 | /// @return Marshaled bytes 533 | function encode_sint32(int32 n) internal pure returns (bytes memory) { 534 | // https://developers.google.com/protocol-buffers/docs/encoding#signed_integers 535 | uint32 mask = 0; 536 | if (n < 0) { 537 | unchecked { 538 | mask -= 1; 539 | } 540 | } 541 | uint32 zigzag_val = (uint32(n) << 1) ^ mask; 542 | 543 | return encode_varint(zigzag_val); 544 | } 545 | 546 | /// @notice Encode varint sint64. 547 | /// @param n Number 548 | /// @return Marshaled bytes 549 | function encode_sint64(int64 n) internal pure returns (bytes memory) { 550 | // https://developers.google.com/protocol-buffers/docs/encoding#signed_integers 551 | uint64 mask = 0; 552 | if (n < 0) { 553 | unchecked { 554 | mask -= 1; 555 | } 556 | } 557 | uint64 zigzag_val = (uint64(n) << 1) ^ mask; 558 | 559 | return encode_varint(zigzag_val); 560 | } 561 | 562 | /// @notice Encode Boolean. 563 | /// @param b Boolean 564 | /// @return Marshaled bytes 565 | function encode_bool(bool b) internal pure returns (bytes memory) { 566 | uint64 n = b ? 1 : 0; 567 | 568 | return encode_varint(n); 569 | } 570 | 571 | /// @notice Encode enumeration. 572 | /// @param n Number 573 | /// @return Marshaled bytes 574 | function encode_enum(int32 n) internal pure returns (bytes memory) { 575 | return encode_int32(n); 576 | } 577 | 578 | /// @notice Encode fixed 64-bit int. 579 | /// @param n Number 580 | /// @return Marshaled bytes 581 | function encode_bits64(uint64 n) internal pure returns (bytes memory) { 582 | bytes memory buf = new bytes(8); 583 | 584 | uint64 tmp = n; 585 | for (uint64 i = 0; i < 8; i++) { 586 | // Little endian 587 | buf[i] = bytes1(uint8(tmp & 0xFF)); 588 | tmp = tmp >> 8; 589 | } 590 | 591 | return buf; 592 | } 593 | 594 | /// @notice Encode fixed uint64. 595 | /// @param n Number 596 | /// @return Marshaled bytes 597 | function encode_fixed64(uint64 n) internal pure returns (bytes memory) { 598 | return encode_bits64(n); 599 | } 600 | 601 | /// @notice Encode fixed int64. 602 | /// @param n Number 603 | /// @return Marshaled bytes 604 | function encode_sfixed64(int64 n) internal pure returns (bytes memory) { 605 | return encode_bits64(uint64(n)); 606 | } 607 | 608 | /// @notice Decode fixed 32-bit int. 609 | /// @param n Number 610 | /// @return Marshaled bytes 611 | function encode_bits32(uint32 n) internal pure returns (bytes memory) { 612 | bytes memory buf = new bytes(4); 613 | 614 | uint64 tmp = n; 615 | for (uint64 i = 0; i < 4; i++) { 616 | // Little endian 617 | buf[i] = bytes1(uint8(tmp & 0xFF)); 618 | tmp = tmp >> 8; 619 | } 620 | 621 | return buf; 622 | } 623 | 624 | /// @notice Encode fixed uint32. 625 | /// @param n Number 626 | /// @return Marshaled bytes 627 | function encode_fixed32(uint32 n) internal pure returns (bytes memory) { 628 | return encode_bits32(n); 629 | } 630 | 631 | /// @notice Encode fixed int32. 632 | /// @param n Number 633 | /// @return Marshaled bytes 634 | function encode_sfixed32(int32 n) internal pure returns (bytes memory) { 635 | return encode_bits32(uint32(n)); 636 | } 637 | 638 | /// @notice Encode length-delimited field. 639 | /// @param b Bytes 640 | /// @return Marshaled bytes 641 | function encode_length_delimited(bytes memory b) internal pure returns (bytes memory) { 642 | // Length-delimited fields begin with a varint of the number of bytes that follow 643 | bytes memory length_buf = encode_uint64(uint64(b.length)); 644 | bytes memory buf = new bytes(b.length + length_buf.length); 645 | 646 | for (uint64 i = 0; i < length_buf.length; i++) { 647 | buf[i] = length_buf[i]; 648 | } 649 | 650 | for (uint64 i = 0; i < b.length; i++) { 651 | buf[i + length_buf.length] = b[i]; 652 | } 653 | 654 | return buf; 655 | } 656 | 657 | /// @notice Encode string. 658 | /// @param s String 659 | /// @return Marshaled bytes 660 | function encode_string(string memory s) internal pure returns (bytes memory) { 661 | return encode_length_delimited(bytes(s)); 662 | } 663 | 664 | /// @notice Encode bytes array. 665 | /// @param b Bytes 666 | /// @return Marshaled bytes 667 | function encode_bytes(bytes memory b) internal pure returns (bytes memory) { 668 | return encode_length_delimited(b); 669 | } 670 | 671 | /// @notice Encode embedded message. 672 | /// @param m Message 673 | /// @return Marshaled bytes 674 | function encode_embedded_message(bytes memory m) internal pure returns (bytes memory) { 675 | return encode_length_delimited(m); 676 | } 677 | 678 | /// @notice Encode packed repeated field. 679 | /// @param b Bytes 680 | /// @return Marshaled bytes 681 | function encode_packed_repeated(bytes memory b) internal pure returns (bytes memory) { 682 | return encode_length_delimited(b); 683 | } 684 | } 685 | -------------------------------------------------------------------------------- /src/libraries/Sha512.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.9; 3 | 4 | // Reference: https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf 5 | 6 | library Sha512 { 7 | // @notice: The message, M, shall be padded before hash computation begins. 8 | // The purpose of this padding is to ensure that the padded message is a multiple of 1024 bits. 9 | // @param message input raw message bytes 10 | // @return padded message bytes 11 | function preprocess(bytes memory message) internal pure returns (bytes memory) { 12 | uint256 padding = 128 - (message.length % 128); 13 | if (message.length % 128 >= 112) { 14 | padding = 256 - (message.length % 128); 15 | } 16 | bytes memory result = new bytes(message.length + padding); 17 | 18 | for (uint256 i = 0; i < message.length; i++) { 19 | result[i] = message[i]; 20 | } 21 | result[message.length] = 0x80; 22 | 23 | uint128 bitSize = uint128(message.length * 8); 24 | bytes memory bitlength = abi.encodePacked(bitSize); 25 | for (uint256 index = 0; index < bitlength.length; index++) { 26 | result[result.length - 1 - index] = bitlength[bitlength.length - 1 - index]; 27 | } 28 | return result; 29 | } 30 | 31 | function bytesToBytes8(bytes memory b, uint256 offset) internal pure returns (bytes8) { 32 | bytes8 out; 33 | for (uint256 i = 0; i < 8; i++) { 34 | out |= bytes8(b[offset + i] & 0xFF) >> (i * 8); 35 | } 36 | return out; 37 | } 38 | 39 | function cutBlock(bytes memory data, uint256 blockIndex) internal pure returns (uint64[16] memory) { 40 | uint64[16] memory result; 41 | for (uint8 r = 0; r < result.length; r++) { 42 | result[r] = uint64(bytesToBytes8(data, blockIndex * 128 + r * 8)); 43 | } 44 | return result; 45 | } 46 | 47 | // This section defines the functions that are used by sha-512. 48 | // https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf#page=15 49 | 50 | // @notice: Thus, ROTR(x, n) is equivalent to a circular shift (rotation) of x by n positions to the right. 51 | // @param x input num 52 | // @param n num of positions to circular shift 53 | // @return uint64 54 | function ROTR(uint64 x, uint256 n) internal pure returns (uint64) { 55 | return (x << (64 - n)) + (x >> n); 56 | } 57 | 58 | // @notice: The right shift operation SHR n(x), where x is a w-bit word and n is an integer with 0 <= n < w, is defined by SHR(x, n) = x >> n. 59 | // @param x input num 60 | // @param n num of positions to shift 61 | // @return uint64 62 | function SHR(uint64 x, uint256 n) internal pure returns (uint64) { 63 | return uint64(x >> n); 64 | } 65 | 66 | // @notice: Ch(x, y, z) = (x ^ y) ⊕ (﹁ x ^ z) 67 | // @param x x 68 | // @param y y 69 | // @param z z 70 | // @return uint64 71 | function Ch(uint64 x, uint64 y, uint64 z) internal pure returns (uint64) { 72 | return (x & y) ^ ((x ^ 0xffffffffffffffff) & z); 73 | } 74 | 75 | // @notice: Maj(x, y, z) = (x ^ y) ⊕ (x ^ z) ⊕ (y ^ z) 76 | // @param x x 77 | // @param y y 78 | // @param z z 79 | // @return uint64 80 | function Maj(uint64 x, uint64 y, uint64 z) internal pure returns (uint64) { 81 | return (x & y) ^ (x & z) ^ (y & z); 82 | } 83 | 84 | // @notice: sigma0(x) = ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39) 85 | // @param x x 86 | // @return uint64 87 | function sigma0(uint64 x) internal pure returns (uint64) { 88 | return ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39); 89 | } 90 | 91 | // @notice: sigma1(x) = ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41) 92 | // @param x x 93 | // @return uint64 94 | function sigma1(uint64 x) internal pure returns (uint64) { 95 | return ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41); 96 | } 97 | 98 | // @notice: gamma0(x) = OTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7) 99 | // @param x x 100 | // @return uint64 101 | function gamma0(uint64 x) internal pure returns (uint64) { 102 | return ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7); 103 | } 104 | 105 | // @notice: gamma1(x) = ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6) 106 | // @param x x 107 | // @return uint64 108 | function gamma1(uint64 x) internal pure returns (uint64) { 109 | return ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6); 110 | } 111 | 112 | struct FuncVar { 113 | uint64 a; 114 | uint64 b; 115 | uint64 c; 116 | uint64 d; 117 | uint64 e; 118 | uint64 f; 119 | uint64 g; 120 | uint64 h; 121 | } 122 | 123 | // @notice Calculate the SHA512 of input data. 124 | // @param data input data bytes 125 | // @return 512 bits hash result 126 | function hash(bytes memory data) external pure returns (uint64[8] memory) { 127 | uint64[8] memory H = [ 128 | 0x6a09e667f3bcc908, 129 | 0xbb67ae8584caa73b, 130 | 0x3c6ef372fe94f82b, 131 | 0xa54ff53a5f1d36f1, 132 | 0x510e527fade682d1, 133 | 0x9b05688c2b3e6c1f, 134 | 0x1f83d9abfb41bd6b, 135 | 0x5be0cd19137e2179 136 | ]; 137 | 138 | unchecked { 139 | uint64 T1; 140 | uint64 T2; 141 | 142 | uint64[80] memory W; 143 | FuncVar memory fvar; 144 | 145 | uint64[80] memory K = [ 146 | 0x428a2f98d728ae22, 147 | 0x7137449123ef65cd, 148 | 0xb5c0fbcfec4d3b2f, 149 | 0xe9b5dba58189dbbc, 150 | 0x3956c25bf348b538, 151 | 0x59f111f1b605d019, 152 | 0x923f82a4af194f9b, 153 | 0xab1c5ed5da6d8118, 154 | 0xd807aa98a3030242, 155 | 0x12835b0145706fbe, 156 | 0x243185be4ee4b28c, 157 | 0x550c7dc3d5ffb4e2, 158 | 0x72be5d74f27b896f, 159 | 0x80deb1fe3b1696b1, 160 | 0x9bdc06a725c71235, 161 | 0xc19bf174cf692694, 162 | 0xe49b69c19ef14ad2, 163 | 0xefbe4786384f25e3, 164 | 0x0fc19dc68b8cd5b5, 165 | 0x240ca1cc77ac9c65, 166 | 0x2de92c6f592b0275, 167 | 0x4a7484aa6ea6e483, 168 | 0x5cb0a9dcbd41fbd4, 169 | 0x76f988da831153b5, 170 | 0x983e5152ee66dfab, 171 | 0xa831c66d2db43210, 172 | 0xb00327c898fb213f, 173 | 0xbf597fc7beef0ee4, 174 | 0xc6e00bf33da88fc2, 175 | 0xd5a79147930aa725, 176 | 0x06ca6351e003826f, 177 | 0x142929670a0e6e70, 178 | 0x27b70a8546d22ffc, 179 | 0x2e1b21385c26c926, 180 | 0x4d2c6dfc5ac42aed, 181 | 0x53380d139d95b3df, 182 | 0x650a73548baf63de, 183 | 0x766a0abb3c77b2a8, 184 | 0x81c2c92e47edaee6, 185 | 0x92722c851482353b, 186 | 0xa2bfe8a14cf10364, 187 | 0xa81a664bbc423001, 188 | 0xc24b8b70d0f89791, 189 | 0xc76c51a30654be30, 190 | 0xd192e819d6ef5218, 191 | 0xd69906245565a910, 192 | 0xf40e35855771202a, 193 | 0x106aa07032bbd1b8, 194 | 0x19a4c116b8d2d0c8, 195 | 0x1e376c085141ab53, 196 | 0x2748774cdf8eeb99, 197 | 0x34b0bcb5e19b48a8, 198 | 0x391c0cb3c5c95a63, 199 | 0x4ed8aa4ae3418acb, 200 | 0x5b9cca4f7763e373, 201 | 0x682e6ff3d6b2b8a3, 202 | 0x748f82ee5defb2fc, 203 | 0x78a5636f43172f60, 204 | 0x84c87814a1f0ab72, 205 | 0x8cc702081a6439ec, 206 | 0x90befffa23631e28, 207 | 0xa4506cebde82bde9, 208 | 0xbef9a3f7b2c67915, 209 | 0xc67178f2e372532b, 210 | 0xca273eceea26619c, 211 | 0xd186b8c721c0c207, 212 | 0xeada7dd6cde0eb1e, 213 | 0xf57d4f7fee6ed178, 214 | 0x06f067aa72176fba, 215 | 0x0a637dc5a2c898a6, 216 | 0x113f9804bef90dae, 217 | 0x1b710b35131c471b, 218 | 0x28db77f523047d84, 219 | 0x32caab7b40c72493, 220 | 0x3c9ebe0a15c9bebc, 221 | 0x431d67c49c100d4c, 222 | 0x4cc5d4becb3e42b6, 223 | 0x597f299cfc657e2a, 224 | 0x5fcb6fab3ad6faec, 225 | 0x6c44198c4a475817 226 | ]; 227 | 228 | bytes memory blocks = preprocess(data); 229 | 230 | for (uint256 j = 0; j < blocks.length / 128; j++) { 231 | uint64[16] memory M = cutBlock(blocks, j); 232 | 233 | fvar.a = H[0]; 234 | fvar.b = H[1]; 235 | fvar.c = H[2]; 236 | fvar.d = H[3]; 237 | fvar.e = H[4]; 238 | fvar.f = H[5]; 239 | fvar.g = H[6]; 240 | fvar.h = H[7]; 241 | 242 | for (uint256 i = 0; i < 80; i++) { 243 | if (i < 16) { 244 | W[i] = M[i]; 245 | } else { 246 | W[i] = gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]; 247 | } 248 | 249 | T1 = fvar.h + sigma1(fvar.e) + Ch(fvar.e, fvar.f, fvar.g) + K[i] + W[i]; 250 | T2 = sigma0(fvar.a) + Maj(fvar.a, fvar.b, fvar.c); 251 | 252 | fvar.h = fvar.g; 253 | fvar.g = fvar.f; 254 | fvar.f = fvar.e; 255 | fvar.e = fvar.d + T1; 256 | fvar.d = fvar.c; 257 | fvar.c = fvar.b; 258 | fvar.b = fvar.a; 259 | fvar.a = T1 + T2; 260 | } 261 | 262 | H[0] = H[0] + fvar.a; 263 | H[1] = H[1] + fvar.b; 264 | H[2] = H[2] + fvar.c; 265 | H[3] = H[3] + fvar.d; 266 | H[4] = H[4] + fvar.e; 267 | H[5] = H[5] + fvar.f; 268 | H[6] = H[6] + fvar.g; 269 | H[7] = H[7] + fvar.h; 270 | } 271 | } 272 | 273 | return H; 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /test/FrameVerifier.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console2} from "forge-std/Test.sol"; 5 | import {FrameVerifier} from "../src/FrameVerifier.sol"; 6 | import "../src/Encoder.sol"; 7 | 8 | contract FrameVerifierTest is Test { 9 | function test_EncodeAndVerify() public { 10 | MessageData memory md = MessageData({ 11 | type_: MessageType.MESSAGE_TYPE_FRAME_ACTION, 12 | fid: 64417, 13 | timestamp: 97190733, 14 | network: FarcasterNetwork.FARCASTER_NETWORK_TESTNET, 15 | frame_action_body: FrameActionBody({ 16 | url: hex"68747470733a2f2f6578616d706c652e636f6d", 17 | button_index: 1, 18 | cast_id: CastId({fid: 64417, hash: hex"e9eca527e4d2043b1f77b5b4d847d4f71172116b"}) 19 | }) 20 | }); 21 | assertEq( 22 | MessageDataCodec.encode(md), 23 | // result from hub monorepo 24 | hex"080d10a1f70318cd86ac2e20028201330a1368747470733a2f2f6578616d706c652e636f6d10011a1a08a1f7031214e9eca527e4d2043b1f77b5b4d847d4f71172116b" 25 | ); 26 | 27 | // from hub mono repo 28 | bytes memory sigHex = 29 | hex"17bdafddf9cf7464959a28d57fb5da7c596de4796f663588ea24d804c13ca043f46a546ca474d1b4420cc48e8720d8051786b21a689cdf485f78e51e36a12b05"; 30 | (bytes32 r, bytes32 s) = abi.decode(sigHex, (bytes32, bytes32)); 31 | bytes32 pk = 0x292404752ddd67080bbfe93af4017e51388ebc3c9fb96b8984658155de590b38; 32 | bool ret = FrameVerifier.verifyMessageData({public_key: pk, signature_r: r, signature_s: s, messageData: md}); 33 | assertTrue(ret); 34 | } 35 | } 36 | --------------------------------------------------------------------------------