Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873
Balance 7.5000 ETH
Nonce 1
Code Size 10757 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

10757 bytes
0x60806040526004361061018b5760003560e01c80636c4624c3116100d6578063b3bf91e71161007f578063d0e30db011610059578063d0e30db014610449578063f48ab4e014610451578063f851a440146104595761018b565b8063b3bf91e7146103f3578063b8e9744c14610409578063be831a2e146104295761018b565b80637875a55c116100b05780637875a55c1461039d578063a3155fbb146103b3578063acb99828146103d35761018b565b80636c4624c31461032f5780636d2d6ae01461034f57806370a082311461036f5761018b565b806337da8ec5116101385780634466ec2c116101125780634466ec2c146102b1578063530208f2146102f95780635c975abb146103195761018b565b806337da8ec5146102655780633ccfd60b146102855780633e54ce681461029a5761018b565b8063160bc0ba11610169578063160bc0ba146102055780631e703806146102255780632692c59f146102455761018b565b8063045544431461019057806309d7e8e7146101b9578063158ef93e146101db575b600080fd5b34801561019c57600080fd5b506101a660045481565b6040519081526020015b60405180910390f35b3480156101c557600080fd5b506101d96101d43660046127fe565b610491565b005b3480156101e757600080fd5b506002546101f59060ff1681565b60405190151581526020016101b0565b34801561021157600080fd5b506101d96102203660046127fe565b610546565b34801561023157600080fd5b506101a6610240366004612895565b6106e2565b34801561025157600080fd5b506101d9610260366004612831565b610781565b34801561027157600080fd5b506101a6610280366004612895565b61079d565b34801561029157600080fd5b506101d961083a565b3480156102a657600080fd5b506101a66102a25481565b3480156102bd57600080fd5b506102c66108e0565b6040516101b091908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561030557600080fd5b506101d9610314366004612702565b6109f0565b34801561032557600080fd5b506101a660015481565b34801561033b57600080fd5b506101d961034a36600461286a565b610a3d565b34801561035b57600080fd5b506101d961036a3660046127fe565b610a5f565b34801561037b57600080fd5b506101a661038a3660046126e6565b6102a56020526000908152604090205481565b3480156103a957600080fd5b506101a660035481565b3480156103bf57600080fd5b506101f56103ce366004612831565b61130c565b3480156103df57600080fd5b506101d96103ee366004612702565b611661565b3480156103ff57600080fd5b506101a660055481565b61041c61041736600461272d565b6117ee565b6040516101b091906128d9565b34801561043557600080fd5b506101d9610444366004612849565b61187a565b6101d9611895565b6101d96118f8565b34801561046557600080fd5b50600054610479906001600160a01b031681565b6040516001600160a01b0390911681526020016101b0565b6000546001600160a01b031633146104a857600080fd5b60025460ff161580156104bb5750600754155b61050c5760405162461bcd60e51b815260206004820152601a60248201527f57726f6e6720696e697469616c697a6174696f6e20737461676500000000000060448201526064015b60405180910390fd5b600061051782611911565b9050600061052482611942565b905061052f82611a2b565b61054181600660005b60990201611a82565b505050565b6000546001600160a01b0316331461055d57600080fd5b60025460ff16158015610571575060075415155b6105bd5760405162461bcd60e51b815260206004820152601a60248201527f57726f6e6720696e697469616c697a6174696f6e2073746167650000000000006044820152606401610503565b6002805460ff1916600117905560006105d582611911565b905060006105e282611cf2565b90506105ed82611a2b565b6080810151516106655760405162461bcd60e51b815260206004820152602a60248201527f496e697469616c697a6174696f6e20626c6f636b206d75737420636f6e74616960448201527f6e206e6578745f627073000000000000000000000000000000000000000000006064820152608401610503565b6040818101805180516101d2805467ffffffffffffffff191667ffffffffffffffff928316908117909155602080840151600690815593860151609f5560c087015160009283526102a3825286832055935160e0810151905190921681526102a48452939093209290925560808301510151610541916001610538565b6000601080600154166000148061070357506000546001600160a01b031633145b61070c57600080fd5b67ffffffffffffffff831660009081526102a4602052604090205491508115801561073a57506102a2544210155b801561074857506102a25415155b801561076f57506101d25467ffffffffffffffff8481166801000000000000000090920416145b1561077b576101d65491505b50919050565b6000546001600160a01b0316331461079857600080fd5b600155565b600060108060015416600014806107be57506000546001600160a01b031633145b6107c757600080fd5b67ffffffffffffffff831660009081526102a360205260409020549150811580156107f557506102a2544210155b801561080357506102a25415155b801561082a57506101d25467ffffffffffffffff8481166801000000000000000090920416145b1561077b5750506101d554919050565b600280600154166000148061085957506000546001600160a01b031633145b61086257600080fd5b6102a1546001600160a01b03163314158061088057506102a2544210155b61088957600080fd5b3360009081526102a56020526040902054806108a457600080fd5b3360008181526102a560205260408082208290555183156108fc0291849190818181858888f19350505050158015610541573d6000803e3d6000fd5b61090b6040518060800160405280600081526020016000815260200160008152602001600081525090565b6102a2544210156109a9576101d25467ffffffffffffffff1681526101d35460208201526102a25460408201526101d45460069060ff1661094f576101d154610975565b60036101d1546001018161097357634e487b7160e01b600052601260045260246000fd5b065b6003811061099357634e487b7160e01b600052603260045260246000fd5b60990201600101548160600181815250506109ed565b6102a254156109d1576101d25468010000000000000000900467ffffffffffffffff166109e0565b6101d25467ffffffffffffffff165b67ffffffffffffffff1681525b90565b6000546001600160a01b03163314610a0757600080fd5b6040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610541573d6000803e3d6000fd5b6000546001600160a01b03163314610a5457600080fd5b825491821816189055565b6004806001541660001480610a7e57506000546001600160a01b031633145b610a8757600080fd5b60025460ff16610ad95760405162461bcd60e51b815260206004820152601b60248201527f436f6e7472616374206973206e6f7420696e697469616c697a656400000000006044820152606401610503565b6003543360009081526102a560205260409020541015610b3b5760405162461bcd60e51b815260206004820152601560248201527f42616c616e6365206973206e6f7420656e6f75676800000000000000000000006044820152606401610503565b6000610b4683611911565b90506000610b5382611cf2565b9050610b5e82611a2b565b6102a254421015610bfd576005546101d35401816040015160a0015167ffffffffffffffff161015610bf85760405162461bcd60e51b815260206004820152603060248201527f43616e206f6e6c79207265706c6163652077697468206120737566666963696560448201527f6e746c79206e6577657220626c6f636b000000000000000000000000000000006064820152608401610503565b610cab565b6102a25415610cab576101d2805468010000000000000000810467ffffffffffffffff1667ffffffffffffffff199091161790556101d45460ff1615610c675760036101d15460010181610c6157634e487b7160e01b600052601260045260246000fd5b066101d1555b60006102a28190556101d5546101d2805467ffffffffffffffff90811684526102a360209081526040808620949094556101d654925490911684526102a490529120555b6101d25460408201515167ffffffffffffffff918216911611610d365760405162461bcd60e51b815260206004820152602160248201527f4e657720626c6f636b206d75737420686176652068696768657220686569676860448201527f74000000000000000000000000000000000000000000000000000000000000006064820152608401610503565b600060066101d15460038110610d5c57634e487b7160e01b600052603260045260246000fd5b60990201546040830151602001511415610d7857506000610e47565b600660036101d15460010181610d9e57634e487b7160e01b600052601260045260246000fd5b0660038110610dbd57634e487b7160e01b600052603260045260246000fd5b60990201546040830151602001511415610dd957506001610e47565b60405162461bcd60e51b815260206004820152602260248201527f45706f6368206964206f662074686520626c6f636b206973206e6f742076616c60448201527f69640000000000000000000000000000000000000000000000000000000000006064820152608401610503565b6000600682610e59576101d154610e7f565b60036101d15460010181610e7d57634e487b7160e01b600052601260045260246000fd5b065b60038110610e9d57634e487b7160e01b600052603260045260246000fd5b60990201905080600101548360a00151511015610efc5760405162461bcd60e51b815260206004820152601a60248201527f417070726f76616c206c69737420697320746f6f2073686f72740000000000006044820152606401610503565b600181015460009081905b808214610ff957600084606601600184901c60328110610f3757634e487b7160e01b600052603260045260246000fd5b015490508660a001518381518110610f5f57634e487b7160e01b600052603260045260246000fd5b60200260200101516000015115610f8b578060801c6fffffffffffffffffffffffffffffffff16840193505b81836001019350831415610f9f5750610ff9565b8660a001518381518110610fc357634e487b7160e01b600052603260045260246000fd5b60200260200101516000015115610fed576fffffffffffffffffffffffffffffffff811693909301925b50816001019150610f07565b50508160980154811161104e5760405162461bcd60e51b815260206004820152601160248201527f546f6f2066657720617070726f76616c730000000000000000000000000000006044820152606401610503565b821561112b576080840151516110a65760405162461bcd60e51b815260206004820181905260248201527f4e657874206e6578745f6270732073686f756c64206e6f74206265204e6f6e656044820152606401610503565b836040015160c001518460800151604001511461112b5760405162461bcd60e51b815260206004820152602660248201527f48617368206f6620626c6f636b2070726f64756365727320646f6573206e6f7460448201527f206d6174636800000000000000000000000000000000000000000000000000006064820152608401610503565b604084015180516101d280547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560a0820151166101d35560c08501516101d55560e0908101516101d6558401516101d755600182015460009081905b8082101561123c5760008760a0015183815181106111d057634e487b7160e01b600052603260045260246000fd5b6020026020010151905080600001511561123057826001901b8417935080602001516101d9846064811061121457634e487b7160e01b600052603260045260246000fd5b6002020160008201518160000155602082015181600101559050505b506001909101906111a2565b50506101d88190556101d4805460ff191685158015919091179091556112ce576000600660036101d1546002018161128457634e487b7160e01b600052601260045260246000fd5b06600381106112a357634e487b7160e01b600052603260045260246000fd5b60990201905085604001516040015181600001819055506112cc86608001516020015182611a82565b505b50506102a180547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055505060045442016102a25550505050565b6101d8546000906001831b166113645760405162461bcd60e51b815260206004820152601160248201527f4e6f2073756368207369676e61747572650000000000000000000000000000006044820152606401610503565b6101d45460009060069060ff1661137e576101d1546113a4565b60036101d154600101816113a257634e487b7160e01b600052601260045260246000fd5b065b600381106113c257634e487b7160e01b600052603260045260246000fd5b60990201905060006101d984606481106113ec57634e487b7160e01b600052603260045260246000fd5b6002020190506000806101d7546114a66101d260089054906101000a900467ffffffffffffffff16600201600060088267ff00ff00ff00ff001667ffffffffffffffff16901c60088366ff00ff00ff00ff1667ffffffffffffffff16901b17915060108267ffff0000ffff00001667ffffffffffffffff16901c60108365ffff0000ffff1667ffffffffffffffff16901b17915060208267ffffffffffffffff16901c60208367ffffffffffffffff16901b179050919050565b60405160f89390931b7fff00000000000000000000000000000000000000000000000000000000000000166020840152602183019190915260c01b7fffffffffffffffff0000000000000000000000000000000000000000000000001660418201526000604982015260600160405160208183030381529060405290506000808280602001905181019061153a91906127b3565b915091507f00000000000000000000000088f975d5a1153ea92af66e7c4292576a329c04b66001600160a01b031663ebd1b95186600201896064811061159057634e487b7160e01b600052603260045260246000fd5b01548654600188015460405160e085901b7fffffffff000000000000000000000000000000000000000000000000000000001681526004810193909352602483019190915260448201526064810185905276ffffffffffffffffffffffffffffffffffffffffffffff198416608482015260a40160206040518083038186803b15801561161c57600080fd5b505afa158015611630573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611654919061277b565b955050505050505b919050565b600880600154166000148061168057506000546001600160a01b031633145b61168957600080fd5b6102a25442106117015760405162461bcd60e51b815260206004820152602760248201527f4e6f20626c6f636b2063616e206265206368616c6c656e67656420617420746860448201527f69732074696d65000000000000000000000000000000000000000000000000006064820152608401610503565b61170a8261130c565b156117575760405162461bcd60e51b815260206004820152601f60248201527f43616e2774206368616c6c656e67652076616c6964207369676e6174757265006044820152606401610503565b6003546102a1546001600160a01b031660009081526102a56020526040902054611781919061292c565b6102a1546001600160a01b0390811660009081526102a56020526040902091909155600354908416906108fc906117ba9060029061290c565b6040518115909202916000818181858888f193505050501580156117e2573d6000803e3d6000fd5b505060006102a2555050565b6000546060906001600160a01b0316331461180857600080fd5b600080846001600160a01b03168460405161182391906128bd565b600060405180830381855af49150503d806000811461185e576040519150601f19603f3d011682016040523d82523d6000602084013e611863565b606091505b50915091508161187257600080fd5b949350505050565b6000546001600160a01b0316331461189157600080fd5b9055565b60018054811615806118b157506000546001600160a01b031633145b6118ba57600080fd5b600354341480156118d957503360009081526102a56020526040902054155b6118e257600080fd5b503360009081526102a560205260409020349055565b6000546001600160a01b0316331461190f57600080fd5b565b604080518082019091526000808252602082015260208201815281611934815190565b825101602083015250919050565b6060600061194f8361204b565b63ffffffff1690508067ffffffffffffffff81111561197e57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156119cf57816020015b604080516080810182526000606082018181528252602080830182905292820152825260001990920191018161199c5790505b50915060005b81811015611a24576119e684612087565b838281518110611a0657634e487b7160e01b600052603260045260246000fd5b60200260200101819052508080611a1c90612973565b9150506119d5565b5050919050565b6020810151815114611a7f5760405162461bcd60e51b815260206004820152601960248201527f5061727365206572726f723a20454f49206578706563746564000000000000006044820152606401610503565b50565b81516064811115611b215760405162461bcd60e51b815260206004820152604a60248201527f4974206973206e6f7420657870656374656420686176696e672074686174206d60448201527f616e7920626c6f636b2070726f64756365727320666f72207468652070726f7660648201527f6964656420626c6f636b00000000000000000000000000000000000000000000608482015260a401610503565b6001820181905560005b81811015611b9057838181518110611b5357634e487b7160e01b600052603260045260246000fd5b60200260200101516000015160000151836002018260648110611b8657634e487b7160e01b600052603260045260246000fd5b0155600101611b2b565b506000805b828114611cdc576000858281518110611bbe57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001519050806fffffffffffffffffffffffffffffffff168301925083826001019250821415611c37578060801b6fffffffffffffffffffffffffffffffff191685606601600184901c60328110611c2f57634e487b7160e01b600052603260045260246000fd5b015550611cdc565b6000868381518110611c5957634e487b7160e01b600052603260045260246000fd5b60209081029190910181015101516fffffffffffffffffffffffffffffffff8116948501949091507fffffffffffffffffffffffffffffffff00000000000000000000000000000000608084901b160160668701600185901c60328110611cd057634e487b7160e01b600052603260045260246000fd5b01555050600101611b95565b5060036002820204836098018190555050505050565b611d9760408051610100808201835260008083526020808401829052845161012081018652828152908101829052808501829052606081018290526080810182905260a0810182905260c0810182905260e0810182905291820152909182019081526000602080830182905260408051606080820183528482529281019290925281810192909252910190815260606020820181905260006040830181905291015290565b611da08261211a565b8152611dab8261211a565b6020820152611db982612127565b6040820152611dc78261211a565b6060820152611dd582612207565b60808201526000611de58361204b565b63ffffffff1690508067ffffffffffffffff811115611e1457634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611e6d57816020015b60408051808201825260008082528251808401909352808352602080840191909152810191909152815260200190600190039081611e325790505b5060a083015260005b81811015611ec957611e878461226b565b8360a001518281518110611eab57634e487b7160e01b600052603260045260246000fd5b60200260200101819052508080611ec190612973565b915050611e76565b50600280836040015161010001518460600151604051602001611ef6929190918252602082015260400190565b60408051601f1981840301815290829052611f10916128bd565b602060405180830381855afa158015611f2d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611f50919061279b565b835160408051602081019390935282015260600160408051601f1981840301815290829052611f7e916128bd565b602060405180830381855afa158015611f9b573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190611fbe919061279b565b60c08301819052602080840151604051600293611fe693909101918252602082015260400190565b60408051601f1981840301815290829052612000916128bd565b602060405180830381855afa15801561201d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612040919061279b565b60e083015250919050565b600061208161205b8360046122b8565b60d881901c63ff00ff001662ff00ff60e89290921c9190911617601081811b91901c1790565b92915050565b60408051608081018252600060608201818152825260208201819052918101829052906120b3836122d1565b90506120be836122e7565b6120c783612314565b82526120d28361238c565b6fffffffffffffffffffffffffffffffff16602083015260ff81166001141561210d576120fe836122d1565b60ff161515604083015261077b565b6000604083015250919050565b60006120818260206122b8565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915261217b8260d061243a565b61010082015261218a82612459565b67ffffffffffffffff16815261219f8261211a565b60208201526121ad8261211a565b60408201526121bb8261211a565b60608201526121c98261211a565b60808201526121d782612459565b67ffffffffffffffff1660a08201526121ef8261211a565b60c08201526121fd8261211a565b60e0820152919050565b6040805160608082018352600080835260208301919091529181019190915261222f826124ce565b158015825261165c57815161224383611942565b6020830152825161226090829061225b90829061292c565b61253b565b604083015250919050565b6040805180820182526000808252825180840190935280835260208084019190915281019190915261229c826124ce565b158015825261165c576122ae8261255d565b6020820152919050565b60006122c48383612604565b5081518051910190915290565b60006122de8260016122b8565b60f81c92915050565b60006122f28261204b565b63ffffffff16905061230d818361260490919063ffffffff16565b8151019052565b60408051602081019091526000815261232c826122d1565b60ff161561237c5760405162461bcd60e51b815260206004820152601d60248201527f5061727365206572726f723a20696e76616c6964206b657920747970650000006044820152606401610503565b6123858261211a565b8152919050565b600061208161239c8360106122b8565b6dff000000ff000000ff000000ff00607882901c9081166cff000000ff000000ff000000ff60889390931c92831617601090811b6fff000000ff000000ff000000ff000000929092166eff000000ff000000ff000000ff0000939093169290921790911c17602081811b6fffffffff00000000ffffffff00000000166bffffffff00000000ffffffff9290911c9190911617604081811b91901c1790565b60006124468383612604565b8251612452908361253b565b9392505050565b60006120816124698360086122b8565b66ff000000ff000060c882901c90811667ff000000ff00000060b89390931c92831617601090811c64ff000000ff9290921665ff000000ff00939093169290921790911b17602081811c63ffffffff1691901b6bffffffffffffffff00000000161790565b6000806124da836122d1565b905060018160ff1611156125305760405162461bcd60e51b815260206004820152601960248201527f5061727365206572726f723a20696e76616c696420626f6f6c000000000000006044820152606401610503565b60ff16151592915050565b600060206000838560025afa5b8061255257612548565b505060005192915050565b604080518082019091526000808252602082015261257a826122d1565b60ff16156125f05760405162461bcd60e51b815260206004820152602360248201527f5061727365206572726f723a20696e76616c6964207369676e6174757265207460448201527f79706500000000000000000000000000000000000000000000000000000000006064820152608401610503565b6125f98261211a565b81526122ae8261211a565b602082015182518201111561265b5760405162461bcd60e51b815260206004820152601b60248201527f5061727365206572726f723a20756e657870656374656420454f4900000000006044820152606401610503565b5050565b600082601f83011261266f578081fd5b813567ffffffffffffffff8082111561268a5761268a6129a4565b604051601f8301601f19908116603f011681019082821181831017156126b2576126b26129a4565b816040528381528660208588010111156126ca578485fd5b8360208701602083013792830160200193909352509392505050565b6000602082840312156126f7578081fd5b8135612452816129ba565b60008060408385031215612714578081fd5b823561271f816129ba565b946020939093013593505050565b6000806040838503121561273f578182fd5b823561274a816129ba565b9150602083013567ffffffffffffffff811115612765578182fd5b6127718582860161265f565b9150509250929050565b60006020828403121561278c578081fd5b81518015158114612452578182fd5b6000602082840312156127ac578081fd5b5051919050565b600080604083850312156127c5578182fd5b82519150602083015176ffffffffffffffffffffffffffffffffffffffffffffff19811681146127f3578182fd5b809150509250929050565b60006020828403121561280f578081fd5b813567ffffffffffffffff811115612825578182fd5b6118728482850161265f565b600060208284031215612842578081fd5b5035919050565b6000806040838503121561285b578182fd5b50508035926020909101359150565b60008060006060848603121561287e578081fd5b505081359360208301359350604090920135919050565b6000602082840312156128a6578081fd5b813567ffffffffffffffff81168114612452578182fd5b600082516128cf818460208701612943565b9190910192915050565b60006020825282518060208401526128f8816040850160208701612943565b601f01601f19169190910160400192915050565b60008261292757634e487b7160e01b81526012600452602481fd5b500490565b60008282101561293e5761293e61298e565b500390565b60005b8381101561295e578181015183820152602001612946565b8381111561296d576000848401525b50505050565b60006000198214156129875761298761298e565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611a7f57600080fdfea2646970667358221220c4e6e79813650f87983cecaaecad09dcd9553de5fd09d0482a231f30c6db1fc864736f6c63430008030033

Verified Source Code Partial Match

Compiler: v0.8.3+commit.8d00100c EVM: istanbul Optimization: Yes (1000 runs)
NearBridge.sol 299 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import "./AdminControlled.sol";
import "./INearBridge.sol";
import "./NearDecoder.sol";
import "./Ed25519.sol";

contract NearBridge is INearBridge, AdminControlled {
    using Borsh for Borsh.Data;
    using NearDecoder for Borsh.Data;

    // Assumed to be even and to not exceed 256.
    uint constant MAX_BLOCK_PRODUCERS = 100;

    struct Epoch {
        bytes32 epochId;
        uint numBPs;
        bytes32[MAX_BLOCK_PRODUCERS] keys;
        bytes32[MAX_BLOCK_PRODUCERS / 2] packedStakes;
        uint256 stakeThreshold;
    }

    // Whether the contract was initialized.
    bool public initialized;
    uint256 public lockEthAmount;
    // lockDuration and replaceDuration shouldn't be extremely big, so adding them to an uint64 timestamp should not overflow uint256.
    uint256 public lockDuration;
    // replaceDuration is in nanoseconds, because it is a difference between NEAR timestamps.
    uint256 public replaceDuration;
    Ed25519 immutable edwards;

    Epoch[3] epochs;
    uint curEpoch;
    uint64 curHeight;

    // The most recently added block. May still be in its challenge period, so should not be trusted.
    uint64 untrustedHeight;
    uint256 untrustedTimestamp;
    bool untrustedNextEpoch;
    bytes32 untrustedHash;
    bytes32 untrustedMerkleRoot;
    bytes32 untrustedNextHash;
    uint256 untrustedSignatureSet;
    NearDecoder.Signature[MAX_BLOCK_PRODUCERS] untrustedSignatures;

    // Address of the account which submitted the last block.
    address lastSubmitter;
    // End of challenge period. If zero, untrusted* fields and lastSubmitter are not meaningful.
    uint public lastValidAt;

    mapping(uint64 => bytes32) blockHashes_;
    mapping(uint64 => bytes32) blockMerkleRoots_;
    mapping(address => uint256) public override balanceOf;

    constructor(
        Ed25519 ed,
        uint256 lockEthAmount_,
        uint256 lockDuration_,
        uint256 replaceDuration_,
        address admin_,
        uint256 pausedFlags_
    ) AdminControlled(admin_, pausedFlags_) {
        require(replaceDuration_ > lockDuration_ * 1000000000);
        edwards = ed;
        lockEthAmount = lockEthAmount_;
        lockDuration = lockDuration_;
        replaceDuration = replaceDuration_;
    }

    uint constant UNPAUSE_ALL = 0;
    uint constant PAUSED_DEPOSIT = 1;
    uint constant PAUSED_WITHDRAW = 2;
    uint constant PAUSED_ADD_BLOCK = 4;
    uint constant PAUSED_CHALLENGE = 8;
    uint constant PAUSED_VERIFY = 16;

    function deposit() public payable override pausable(PAUSED_DEPOSIT) {
        require(msg.value == lockEthAmount && balanceOf[msg.sender] == 0);
        balanceOf[msg.sender] = msg.value;
    }

    function withdraw() public override pausable(PAUSED_WITHDRAW) {
        require(msg.sender != lastSubmitter || block.timestamp >= lastValidAt);
        uint amount = balanceOf[msg.sender];
        require(amount != 0);
        balanceOf[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }

    function challenge(address payable receiver, uint signatureIndex) public override pausable(PAUSED_CHALLENGE) {
        require(block.timestamp < lastValidAt, "No block can be challenged at this time");
        require(!checkBlockProducerSignatureInHead(signatureIndex), "Can't challenge valid signature");

        balanceOf[lastSubmitter] = balanceOf[lastSubmitter] - lockEthAmount;
        receiver.transfer(lockEthAmount / 2);
        lastValidAt = 0;
    }

    function checkBlockProducerSignatureInHead(uint signatureIndex) public view override returns (bool) {
        // Shifting by a number >= 256 returns zero.
        require((untrustedSignatureSet & (1 << signatureIndex)) != 0, "No such signature");
        unchecked {
            Epoch storage untrustedEpoch = epochs[untrustedNextEpoch ? (curEpoch + 1) % 3 : curEpoch];
            NearDecoder.Signature storage signature = untrustedSignatures[signatureIndex];
            bytes memory message = abi.encodePacked(
                uint8(0),
                untrustedNextHash,
                Utils.swapBytes8(untrustedHeight + 2),
                bytes23(0)
            );
            (bytes32 arg1, bytes9 arg2) = abi.decode(message, (bytes32, bytes9));
            return edwards.check(untrustedEpoch.keys[signatureIndex], signature.r, signature.s, arg1, arg2);
        }
    }

    // The first part of initialization -- setting the validators of the current epoch.
    function initWithValidators(bytes memory data) public override onlyAdmin {
        require(!initialized && epochs[0].numBPs == 0, "Wrong initialization stage");

        Borsh.Data memory borsh = Borsh.from(data);
        NearDecoder.BlockProducer[] memory initialValidators = borsh.decodeBlockProducers();
        borsh.done();

        setBlockProducers(initialValidators, epochs[0]);
    }

    // The second part of the initialization -- setting the current head.
    function initWithBlock(bytes memory data) public override onlyAdmin {
        require(!initialized && epochs[0].numBPs != 0, "Wrong initialization stage");
        initialized = true;

        Borsh.Data memory borsh = Borsh.from(data);
        NearDecoder.LightClientBlock memory nearBlock = borsh.decodeLightClientBlock();
        borsh.done();

        require(nearBlock.next_bps.some, "Initialization block must contain next_bps");

        curHeight = nearBlock.inner_lite.height;
        epochs[0].epochId = nearBlock.inner_lite.epoch_id;
        epochs[1].epochId = nearBlock.inner_lite.next_epoch_id;
        blockHashes_[nearBlock.inner_lite.height] = nearBlock.hash;
        blockMerkleRoots_[nearBlock.inner_lite.height] = nearBlock.inner_lite.block_merkle_root;
        setBlockProducers(nearBlock.next_bps.blockProducers, epochs[1]);
    }

    struct BridgeState {
        uint currentHeight; // Height of the current confirmed block
        // If there is currently no unconfirmed block, the last three fields are zero.
        uint nextTimestamp; // Timestamp of the current unconfirmed block
        uint nextValidAt; // Timestamp when the current unconfirmed block will be confirmed
        uint numBlockProducers; // Number of block producers for the current unconfirmed block
    }

    function bridgeState() public view returns (BridgeState memory res) {
        if (block.timestamp < lastValidAt) {
            res.currentHeight = curHeight;
            res.nextTimestamp = untrustedTimestamp;
            res.nextValidAt = lastValidAt;
            unchecked {
                res.numBlockProducers = epochs[untrustedNextEpoch ? (curEpoch + 1) % 3 : curEpoch].numBPs;
            }
        } else {
            res.currentHeight = lastValidAt == 0 ? curHeight : untrustedHeight;
        }
    }

    function addLightClientBlock(bytes memory data) public override pausable(PAUSED_ADD_BLOCK) {
        require(initialized, "Contract is not initialized");
        require(balanceOf[msg.sender] >= lockEthAmount, "Balance is not enough");

        Borsh.Data memory borsh = Borsh.from(data);
        NearDecoder.LightClientBlock memory nearBlock = borsh.decodeLightClientBlock();
        borsh.done();

        unchecked {
            // Commit the previous block, or make sure that it is OK to replace it.
            if (block.timestamp < lastValidAt) {
                require(
                    nearBlock.inner_lite.timestamp >= untrustedTimestamp + replaceDuration,
                    "Can only replace with a sufficiently newer block"
                );
            } else if (lastValidAt != 0) {
                curHeight = untrustedHeight;
                if (untrustedNextEpoch) {
                    curEpoch = (curEpoch + 1) % 3;
                }
                lastValidAt = 0;

                blockHashes_[curHeight] = untrustedHash;
                blockMerkleRoots_[curHeight] = untrustedMerkleRoot;
            }

            // Check that the new block's height is greater than the current one's.
            require(nearBlock.inner_lite.height > curHeight, "New block must have higher height");

            // Check that the new block is from the same epoch as the current one, or from the next one.
            bool fromNextEpoch;
            if (nearBlock.inner_lite.epoch_id == epochs[curEpoch].epochId) {
                fromNextEpoch = false;
            } else if (nearBlock.inner_lite.epoch_id == epochs[(curEpoch + 1) % 3].epochId) {
                fromNextEpoch = true;
            } else {
                revert("Epoch id of the block is not valid");
            }

            // Check that the new block is signed by more than 2/3 of the validators.
            Epoch storage thisEpoch = epochs[fromNextEpoch ? (curEpoch + 1) % 3 : curEpoch];
            // Last block in the epoch might contain extra approvals that light client can ignore.
            require(nearBlock.approvals_after_next.length >= thisEpoch.numBPs, "Approval list is too short");
            // The sum of uint128 values cannot overflow.
            uint256 votedFor = 0;
            for ((uint i, uint cnt) = (0, thisEpoch.numBPs); i != cnt; ++i) {
                bytes32 stakes = thisEpoch.packedStakes[i >> 1];
                if (nearBlock.approvals_after_next[i].some) {
                    votedFor += uint128(bytes16(stakes));
                }
                if (++i == cnt) {
                    break;
                }
                if (nearBlock.approvals_after_next[i].some) {
                    votedFor += uint128(uint256(stakes));
                }
            }
            require(votedFor > thisEpoch.stakeThreshold, "Too few approvals");

            // If the block is from the next epoch, make sure that next_bps is supplied and has a correct hash.
            if (fromNextEpoch) {
                require(nearBlock.next_bps.some, "Next next_bps should not be None");
                require(
                    nearBlock.next_bps.hash == nearBlock.inner_lite.next_bp_hash,
                    "Hash of block producers does not match"
                );
            }

            untrustedHeight = nearBlock.inner_lite.height;
            untrustedTimestamp = nearBlock.inner_lite.timestamp;
            untrustedHash = nearBlock.hash;
            untrustedMerkleRoot = nearBlock.inner_lite.block_merkle_root;
            untrustedNextHash = nearBlock.next_hash;

            uint256 signatureSet = 0;
            for ((uint i, uint cnt) = (0, thisEpoch.numBPs); i < cnt; i++) {
                NearDecoder.OptionalSignature memory approval = nearBlock.approvals_after_next[i];
                if (approval.some) {
                    signatureSet |= 1 << i;
                    untrustedSignatures[i] = approval.signature;
                }
            }
            untrustedSignatureSet = signatureSet;
            untrustedNextEpoch = fromNextEpoch;
            if (fromNextEpoch) {
                Epoch storage nextEpoch = epochs[(curEpoch + 2) % 3];
                nextEpoch.epochId = nearBlock.inner_lite.next_epoch_id;
                setBlockProducers(nearBlock.next_bps.blockProducers, nextEpoch);
            }
            lastSubmitter = msg.sender;
            lastValidAt = block.timestamp + lockDuration;
        }
    }

    function setBlockProducers(NearDecoder.BlockProducer[] memory src, Epoch storage epoch) internal {
        uint cnt = src.length;
        require(cnt <= MAX_BLOCK_PRODUCERS, "It is not expected having that many block producers for the provided block");
        epoch.numBPs = cnt;
        unchecked {
            for (uint i = 0; i < cnt; i++) {
                epoch.keys[i] = src[i].publicKey.k;
            }
            uint256 totalStake = 0; // Sum of uint128, can't be too big.
            for (uint i = 0; i != cnt; ++i) {
                uint128 stake1 = src[i].stake;
                totalStake += stake1;
                if (++i == cnt) {
                    epoch.packedStakes[i >> 1] = bytes32(bytes16(stake1));
                    break;
                }
                uint128 stake2 = src[i].stake;
                totalStake += stake2;
                epoch.packedStakes[i >> 1] = bytes32(uint256(bytes32(bytes16(stake1))) + stake2);
            }
            epoch.stakeThreshold = (totalStake * 2) / 3;
        }
    }

    function blockHashes(uint64 height) public view override pausable(PAUSED_VERIFY) returns (bytes32 res) {
        res = blockHashes_[height];
        if (res == 0 && block.timestamp >= lastValidAt && lastValidAt != 0 && height == untrustedHeight) {
            res = untrustedHash;
        }
    }

    function blockMerkleRoots(uint64 height) public view override pausable(PAUSED_VERIFY) returns (bytes32 res) {
        res = blockMerkleRoots_[height];
        if (res == 0 && block.timestamp >= lastValidAt && lastValidAt != 0 && height == untrustedHeight) {
            res = untrustedMerkleRoot;
        }
    }
}
AdminControlled.sol 55 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

contract AdminControlled {
    address public admin;
    uint public paused;

    constructor(address _admin, uint flags) {
        admin = _admin;
        paused = flags;
    }

    modifier onlyAdmin {
        require(msg.sender == admin);
        _;
    }

    modifier pausable(uint flag) {
        require((paused & flag) == 0 || msg.sender == admin);
        _;
    }

    function adminPause(uint flags) public onlyAdmin {
        paused = flags;
    }

    function adminSstore(uint key, uint value) public onlyAdmin {
        assembly {
            sstore(key, value)
        }
    }

    function adminSstoreWithMask(
        uint key,
        uint value,
        uint mask
    ) public onlyAdmin {
        assembly {
            let oldval := sload(key)
            sstore(key, xor(and(xor(value, oldval), mask), oldval))
        }
    }

    function adminSendEth(address payable destination, uint amount) public onlyAdmin {
        destination.transfer(amount);
    }

    function adminReceiveEth() public payable onlyAdmin {}

    function adminDelegatecall(address target, bytes memory data) public payable onlyAdmin returns (bytes memory) {
        (bool success, bytes memory rdata) = target.delegatecall(data);
        require(success);
        return rdata;
    }
}
Borsh.sol 111 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import "./Utils.sol";

library Borsh {
    using Borsh for Data;

    struct Data {
        uint ptr;
        uint end;
    }

    function from(bytes memory data) internal pure returns (Data memory res) {
        uint ptr;
        assembly {
            ptr := data
        }
        unchecked {
            res.ptr = ptr + 32;
            res.end = res.ptr + Utils.readMemory(ptr);
        }
    }

    // This function assumes that length is reasonably small, so that data.ptr + length will not overflow. In the current code, length is always less than 2^32.
    function requireSpace(Data memory data, uint length) internal pure {
        unchecked {
            require(data.ptr + length <= data.end, "Parse error: unexpected EOI");
        }
    }

    function read(Data memory data, uint length) internal pure returns (bytes32 res) {
        data.requireSpace(length);
        res = bytes32(Utils.readMemory(data.ptr));
        unchecked {
            data.ptr += length;
        }
        return res;
    }

    function done(Data memory data) internal pure {
        require(data.ptr == data.end, "Parse error: EOI expected");
    }

    // Same considerations as for requireSpace.
    function peekKeccak256(Data memory data, uint length) internal pure returns (bytes32) {
        data.requireSpace(length);
        return Utils.keccak256Raw(data.ptr, length);
    }

    // Same considerations as for requireSpace.
    function peekSha256(Data memory data, uint length) internal view returns (bytes32) {
        data.requireSpace(length);
        return Utils.sha256Raw(data.ptr, length);
    }

    function decodeU8(Data memory data) internal pure returns (uint8) {
        return uint8(bytes1(data.read(1)));
    }

    function decodeU16(Data memory data) internal pure returns (uint16) {
        return Utils.swapBytes2(uint16(bytes2(data.read(2))));
    }

    function decodeU32(Data memory data) internal pure returns (uint32) {
        return Utils.swapBytes4(uint32(bytes4(data.read(4))));
    }

    function decodeU64(Data memory data) internal pure returns (uint64) {
        return Utils.swapBytes8(uint64(bytes8(data.read(8))));
    }

    function decodeU128(Data memory data) internal pure returns (uint128) {
        return Utils.swapBytes16(uint128(bytes16(data.read(16))));
    }

    function decodeU256(Data memory data) internal pure returns (uint256) {
        return Utils.swapBytes32(uint256(data.read(32)));
    }

    function decodeBytes20(Data memory data) internal pure returns (bytes20) {
        return bytes20(data.read(20));
    }

    function decodeBytes32(Data memory data) internal pure returns (bytes32) {
        return data.read(32);
    }

    function decodeBool(Data memory data) internal pure returns (bool) {
        uint8 res = data.decodeU8();
        require(res <= 1, "Parse error: invalid bool");
        return res != 0;
    }

    function skipBytes(Data memory data) internal pure {
        uint length = data.decodeU32();
        data.requireSpace(length);
        unchecked {
            data.ptr += length;
        }
    }

    function decodeBytes(Data memory data) internal pure returns (bytes memory res) {
        uint length = data.decodeU32();
        data.requireSpace(length);
        res = Utils.memoryToBytes(data.ptr, length);
        unchecked {
            data.ptr += length;
        }
    }
}
Ed25519.sol 1731 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

contract Ed25519 {
    // Computes (v^(2^250-1), v^11) mod p
    function pow22501(uint256 v) private pure returns (uint256 p22501, uint256 p11) {
        p11 = mulmod(v, v, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(
            mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),
            v,
            0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed
        );
        p11 = mulmod(p22501, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(
            mulmod(p11, p11, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed),
            p22501,
            0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed
        );
        uint256 a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        uint256 b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(p22501, p22501, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        b = mulmod(b, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, b, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        a = mulmod(a, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
        p22501 = mulmod(p22501, a, 0x7fffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffed);
    }

    function check(
        bytes32 k,
        bytes32 r,
        bytes32 s,
        bytes32 m1,
        bytes9 m2
    ) public pure returns (bool) {
        unchecked {
            uint256 hh;
            // Step 1: compute SHA-512(R, A, M)
            {
                uint256[5][16] memory kk = [
                    [
                        uint256(0x428a2f98_d728ae22),
                        uint256(0xe49b69c1_9ef14ad2),
                        uint256(0x27b70a85_46d22ffc),
                        uint256(0x19a4c116_b8d2d0c8),
                        uint256(0xca273ece_ea26619c)
                    ],
                    [
                        uint256(0x71374491_23ef65cd),
                        uint256(0xefbe4786_384f25e3),
                        uint256(0x2e1b2138_5c26c926),
                        uint256(0x1e376c08_5141ab53),
                        uint256(0xd186b8c7_21c0c207)
                    ],
                    [
                        uint256(0xb5c0fbcf_ec4d3b2f),
                        uint256(0xfc19dc6_8b8cd5b5),
                        uint256(0x4d2c6dfc_5ac42aed),
                        uint256(0x2748774c_df8eeb99),
                        uint256(0xeada7dd6_cde0eb1e)
                    ],
                    [
                        uint256(0xe9b5dba5_8189dbbc),
                        uint256(0x240ca1cc_77ac9c65),
                        uint256(0x53380d13_9d95b3df),
                        uint256(0x34b0bcb5_e19b48a8),
                        uint256(0xf57d4f7f_ee6ed178)
                    ],
                    [
                        uint256(0x3956c25b_f348b538),
                        uint256(0x2de92c6f_592b0275),
                        uint256(0x650a7354_8baf63de),
                        uint256(0x391c0cb3_c5c95a63),
                        uint256(0x6f067aa_72176fba)
                    ],
                    [
                        uint256(0x59f111f1_b605d019),
                        uint256(0x4a7484aa_6ea6e483),
                        uint256(0x766a0abb_3c77b2a8),
                        uint256(0x4ed8aa4a_e3418acb),
                        uint256(0xa637dc5_a2c898a6)
                    ],
                    [
                        uint256(0x923f82a4_af194f9b),
                        uint256(0x5cb0a9dc_bd41fbd4),
                        uint256(0x81c2c92e_47edaee6),
                        uint256(0x5b9cca4f_7763e373),
                        uint256(0x113f9804_bef90dae)
                    ],
                    [
                        uint256(0xab1c5ed5_da6d8118),
                        uint256(0x76f988da_831153b5),
                        uint256(0x92722c85_1482353b),
                        uint256(0x682e6ff3_d6b2b8a3),
                        uint256(0x1b710b35_131c471b)
                    ],
                    [
                        uint256(0xd807aa98_a3030242),
                        uint256(0x983e5152_ee66dfab),
                        uint256(0xa2bfe8a1_4cf10364),
                        uint256(0x748f82ee_5defb2fc),
                        uint256(0x28db77f5_23047d84)
                    ],
                    [
                        uint256(0x12835b01_45706fbe),
                        uint256(0xa831c66d_2db43210),
                        uint256(0xa81a664b_bc423001),
                        uint256(0x78a5636f_43172f60),
                        uint256(0x32caab7b_40c72493)
                    ],
                    [
                        uint256(0x243185be_4ee4b28c),
                        uint256(0xb00327c8_98fb213f),
                        uint256(0xc24b8b70_d0f89791),
                        uint256(0x84c87814_a1f0ab72),
                        uint256(0x3c9ebe0a_15c9bebc)
                    ],
                    [
                        uint256(0x550c7dc3_d5ffb4e2),
                        uint256(0xbf597fc7_beef0ee4),
                        uint256(0xc76c51a3_0654be30),
                        uint256(0x8cc70208_1a6439ec),
                        uint256(0x431d67c4_9c100d4c)
                    ],
                    [
                        uint256(0x72be5d74_f27b896f),
                        uint256(0xc6e00bf3_3da88fc2),
                        uint256(0xd192e819_d6ef5218),
                        uint256(0x90befffa_23631e28),
                        uint256(0x4cc5d4be_cb3e42b6)
                    ],
                    [
                        uint256(0x80deb1fe_3b1696b1),
                        uint256(0xd5a79147_930aa725),
                        uint256(0xd6990624_5565a910),
                        uint256(0xa4506ceb_de82bde9),
                        uint256(0x597f299c_fc657e2a)
                    ],
                    [
                        uint256(0x9bdc06a7_25c71235),
                        uint256(0x6ca6351_e003826f),
                        uint256(0xf40e3585_5771202a),
                        uint256(0xbef9a3f7_b2c67915),
                        uint256(0x5fcb6fab_3ad6faec)
                    ],
                    [
                        uint256(0xc19bf174_cf692694),
                        uint256(0x14292967_0a0e6e70),
                        uint256(0x106aa070_32bbd1b8),
                        uint256(0xc67178f2_e372532b),
                        uint256(0x6c44198c_4a475817)
                    ]
                ];
                uint256 w0 = (uint256(r) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |
                    ((uint256(r) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) >> 64) |
                    ((uint256(r) & 0xffffffff_ffffffff_00000000_00000000) << 64);
                uint256 w1 = (uint256(k) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |
                    ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) >> 64) |
                    ((uint256(k) & 0xffffffff_ffffffff_00000000_00000000) << 64);
                uint256 w2 = (uint256(m1) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000_ffffffff_ffffffff) |
                    ((uint256(m1) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) >> 64) |
                    ((uint256(m1) & 0xffffffff_ffffffff_00000000_00000000) << 64);
                uint256 w3 = (uint256(bytes32(m2)) &
                    0xffffffff_ffffffff_00000000_00000000_00000000_00000000_00000000_00000000) |
                    ((uint256(bytes32(m2)) & 0xffffffff_ffffffff_00000000_00000000_00000000_00000000) >> 64) |
                    0x800000_00000000_00000000_00000348;
                uint256 a = 0x6a09e667_f3bcc908;
                uint256 b = 0xbb67ae85_84caa73b;
                uint256 c = 0x3c6ef372_fe94f82b;
                uint256 d = 0xa54ff53a_5f1d36f1;
                uint256 e = 0x510e527f_ade682d1;
                uint256 f = 0x9b05688c_2b3e6c1f;
                uint256 g = 0x1f83d9ab_fb41bd6b;
                uint256 h = 0x5be0cd19_137e2179;
                for (uint256 i = 0; ; i++) {
                    // Round 16 * i
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[0][i];
                        temp1 += w0 >> 192;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 1
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[1][i];
                        temp1 += w0 >> 64;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 2
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[2][i];
                        temp1 += w0 >> 128;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 3
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[3][i];
                        temp1 += w0;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 4
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[4][i];
                        temp1 += w1 >> 192;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 5
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[5][i];
                        temp1 += w1 >> 64;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 6
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[6][i];
                        temp1 += w1 >> 128;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 7
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[7][i];
                        temp1 += w1;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 8
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[8][i];
                        temp1 += w2 >> 192;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 9
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[9][i];
                        temp1 += w2 >> 64;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 10
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[10][i];
                        temp1 += w2 >> 128;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 11
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[11][i];
                        temp1 += w2;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 12
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[12][i];
                        temp1 += w3 >> 192;
                        a &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = a | (a << 64);
                            uint256 s0 = (ss >> 28) ^ (ss >> 34) ^ (ss >> 39);
                            uint256 maj = (a & (b | c)) | (b & c);
                            temp2 = s0 + maj;
                        }
                        h = g;
                        g = f;
                        f = e;
                        e = d + temp1;
                        d = c;
                        c = b;
                        b = a;
                        a = temp1 + temp2;
                    }
                    // Round 16 * i + 13
                    {
                        uint256 temp1;
                        uint256 temp2;
                        e &= 0xffffffff_ffffffff;
                        {
                            uint256 ss = e | (e << 64);
                            uint256 s1 = (ss >> 14) ^ (ss >> 18) ^ (ss >> 41);
                            uint256 ch = (e & (f ^ g)) ^ g;
                            temp1 = h + s1 + ch;
                        }
                        temp1 += kk[13][i];
                        temp1 += w3 >> 64;
                        a &= 0xffffffff_ffffffff;
                        {
                   ...

// [truncated — 99829 bytes total]
INearBridge.sol 28 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

interface INearBridge {
    event BlockHashAdded(uint64 indexed height, bytes32 blockHash);

    event BlockHashReverted(uint64 indexed height, bytes32 blockHash);

    function blockHashes(uint64 blockNumber) external view returns (bytes32);

    function blockMerkleRoots(uint64 blockNumber) external view returns (bytes32);

    function balanceOf(address wallet) external view returns (uint256);

    function deposit() external payable;

    function withdraw() external;

    function initWithValidators(bytes calldata initialValidators) external;

    function initWithBlock(bytes calldata data) external;

    function addLightClientBlock(bytes calldata data) external;

    function challenge(address payable receiver, uint256 signatureIndex) external;

    function checkBlockProducerSignatureInHead(uint256 signatureIndex) external view returns (bool);
}
NearDecoder.sol 149 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

import "./Borsh.sol";

library NearDecoder {
    using Borsh for Borsh.Data;
    using NearDecoder for Borsh.Data;

    uint8 constant VALIDATOR_V1 = 0;
    uint8 constant VALIDATOR_V2 = 1;

    struct PublicKey {
        bytes32 k;
    }

    function decodePublicKey(Borsh.Data memory data) internal pure returns (PublicKey memory res) {
        require(data.decodeU8() == 0, "Parse error: invalid key type");
        res.k = data.decodeBytes32();
    }

    struct Signature {
        bytes32 r;
        bytes32 s;
    }

    function decodeSignature(Borsh.Data memory data) internal pure returns (Signature memory res) {
        require(data.decodeU8() == 0, "Parse error: invalid signature type");
        res.r = data.decodeBytes32();
        res.s = data.decodeBytes32();
    }

    struct BlockProducer {
        PublicKey publicKey;
        uint128 stake;
        // Flag indicating if this validator proposed to be a chunk-only producer (i.e. cannot become a block producer).
        bool isChunkOnly;
    }

    function decodeBlockProducer(Borsh.Data memory data) internal pure returns (BlockProducer memory res) {
        uint8 validator_version = data.decodeU8();
        data.skipBytes();
        res.publicKey = data.decodePublicKey();
        res.stake = data.decodeU128();
        if (validator_version == VALIDATOR_V2) {
            res.isChunkOnly = data.decodeU8() != 0;
        } else {
            res.isChunkOnly = false;
        }
    }

    function decodeBlockProducers(Borsh.Data memory data) internal pure returns (BlockProducer[] memory res) {
        uint length = data.decodeU32();
        res = new BlockProducer[](length);
        for (uint i = 0; i < length; i++) {
            res[i] = data.decodeBlockProducer();
        }
    }

    struct OptionalBlockProducers {
        bool some;
        BlockProducer[] blockProducers;
        bytes32 hash; // Additional computable element
    }

    function decodeOptionalBlockProducers(Borsh.Data memory data)
        internal
        view
        returns (OptionalBlockProducers memory res)
    {
        res.some = data.decodeBool();
        if (res.some) {
            uint start = data.ptr;
            res.blockProducers = data.decodeBlockProducers();
            res.hash = Utils.sha256Raw(start, data.ptr - start);
        }
    }

    struct OptionalSignature {
        bool some;
        Signature signature;
    }

    function decodeOptionalSignature(Borsh.Data memory data) internal pure returns (OptionalSignature memory res) {
        res.some = data.decodeBool();
        if (res.some) {
            res.signature = data.decodeSignature();
        }
    }

    struct BlockHeaderInnerLite {
        uint64 height; // Height of this block since the genesis block (height 0).
        bytes32 epoch_id; // Epoch start hash of this block's epoch. Used for retrieving validator information
        bytes32 next_epoch_id;
        bytes32 prev_state_root; // Root hash of the state at the previous block.
        bytes32 outcome_root; // Root of the outcomes of transactions and receipts.
        uint64 timestamp; // Timestamp at which the block was built.
        bytes32 next_bp_hash; // Hash of the next epoch block producers set
        bytes32 block_merkle_root;
        bytes32 hash; // Additional computable element
    }

    function decodeBlockHeaderInnerLite(Borsh.Data memory data)
        internal
        view
        returns (BlockHeaderInnerLite memory res)
    {
        res.hash = data.peekSha256(208);
        res.height = data.decodeU64();
        res.epoch_id = data.decodeBytes32();
        res.next_epoch_id = data.decodeBytes32();
        res.prev_state_root = data.decodeBytes32();
        res.outcome_root = data.decodeBytes32();
        res.timestamp = data.decodeU64();
        res.next_bp_hash = data.decodeBytes32();
        res.block_merkle_root = data.decodeBytes32();
    }

    struct LightClientBlock {
        bytes32 prev_block_hash;
        bytes32 next_block_inner_hash;
        BlockHeaderInnerLite inner_lite;
        bytes32 inner_rest_hash;
        OptionalBlockProducers next_bps;
        OptionalSignature[] approvals_after_next;
        bytes32 hash;
        bytes32 next_hash;
    }

    function decodeLightClientBlock(Borsh.Data memory data) internal view returns (LightClientBlock memory res) {
        res.prev_block_hash = data.decodeBytes32();
        res.next_block_inner_hash = data.decodeBytes32();
        res.inner_lite = data.decodeBlockHeaderInnerLite();
        res.inner_rest_hash = data.decodeBytes32();
        res.next_bps = data.decodeOptionalBlockProducers();

        uint length = data.decodeU32();
        res.approvals_after_next = new OptionalSignature[](length);
        for (uint i = 0; i < length; i++) {
            res.approvals_after_next[i] = data.decodeOptionalSignature();
        }

        res.hash = sha256(
            abi.encodePacked(sha256(abi.encodePacked(res.inner_lite.hash, res.inner_rest_hash)), res.prev_block_hash)
        );

        res.next_hash = sha256(abi.encodePacked(res.next_block_inner_hash, res.hash));
    }
}
Utils.sol 98 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8;

library Utils {
    function swapBytes2(uint16 v) internal pure returns (uint16) {
        return (v << 8) | (v >> 8);
    }

    function swapBytes4(uint32 v) internal pure returns (uint32) {
        v = ((v & 0x00ff00ff) << 8) | ((v & 0xff00ff00) >> 8);
        return (v << 16) | (v >> 16);
    }

    function swapBytes8(uint64 v) internal pure returns (uint64) {
        v = ((v & 0x00ff00ff00ff00ff) << 8) | ((v & 0xff00ff00ff00ff00) >> 8);
        v = ((v & 0x0000ffff0000ffff) << 16) | ((v & 0xffff0000ffff0000) >> 16);
        return (v << 32) | (v >> 32);
    }

    function swapBytes16(uint128 v) internal pure returns (uint128) {
        v = ((v & 0x00ff00ff00ff00ff00ff00ff00ff00ff) << 8) | ((v & 0xff00ff00ff00ff00ff00ff00ff00ff00) >> 8);
        v = ((v & 0x0000ffff0000ffff0000ffff0000ffff) << 16) | ((v & 0xffff0000ffff0000ffff0000ffff0000) >> 16);
        v = ((v & 0x00000000ffffffff00000000ffffffff) << 32) | ((v & 0xffffffff00000000ffffffff00000000) >> 32);
        return (v << 64) | (v >> 64);
    }

    function swapBytes32(uint256 v) internal pure returns (uint256) {
        v =
            ((v & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff) << 8) |
            ((v & 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00) >> 8);
        v =
            ((v & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff) << 16) |
            ((v & 0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000) >> 16);
        v =
            ((v & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff) << 32) |
            ((v & 0xffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000) >> 32);
        v =
            ((v & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff) << 64) |
            ((v & 0xffffffffffffffff0000000000000000ffffffffffffffff0000000000000000) >> 64);
        return (v << 128) | (v >> 128);
    }

    function readMemory(uint ptr) internal pure returns (uint res) {
        assembly {
            res := mload(ptr)
        }
    }

    function writeMemory(uint ptr, uint value) internal pure {
        assembly {
            mstore(ptr, value)
        }
    }

    function memoryToBytes(uint ptr, uint length) internal pure returns (bytes memory res) {
        if (length != 0) {
            assembly {
                // 0x40 is the address of free memory pointer.
                res := mload(0x40)
                let end := add(
                    res,
                    and(add(length, 63), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)
                )
                // end = res + 32 + 32 * ceil(length / 32).
                mstore(0x40, end)
                mstore(res, length)
                let destPtr := add(res, 32)
                // prettier-ignore
                for { } 1 { } {
                    mstore(destPtr, mload(ptr))
                    destPtr := add(destPtr, 32)
                    if eq(destPtr, end) {
                        break
                    }
                    ptr := add(ptr, 32)
                }
            }
        }
    }

    function keccak256Raw(uint ptr, uint length) internal pure returns (bytes32 res) {
        assembly {
            res := keccak256(ptr, length)
        }
    }

    function sha256Raw(uint ptr, uint length) internal view returns (bytes32 res) {
        assembly {
            // 2 is the address of SHA256 precompiled contract.
            // First 64 bytes of memory can be used as scratch space.
            let ret := staticcall(gas(), 2, ptr, length, 0, 32)
            // If the call to SHA256 precompile ran out of gas, burn any gas that remains.
            // prettier-ignore
            for { } iszero(ret) { } { }
            res := mload(0)
        }
    }
}

Read Contract

admin 0xf851a440 → address
balanceOf 0x70a08231 → uint256
blockHashes 0x37da8ec5 → bytes32
blockMerkleRoots 0x1e703806 → bytes32
bridgeState 0x4466ec2c → tuple
checkBlockProducerSignatureInHead 0xa3155fbb → bool
initialized 0x158ef93e → bool
lastValidAt 0x3e54ce68 → uint256
lockDuration 0x04554443 → uint256
lockEthAmount 0x7875a55c → uint256
paused 0x5c975abb → uint256
replaceDuration 0xb3bf91e7 → uint256

Write Contract 12 functions

These functions modify contract state and require a wallet transaction to execute.

addLightClientBlock 0x6d2d6ae0
bytes data
adminDelegatecall 0xb8e9744c
address target
bytes data
returns: bytes
adminPause 0x2692c59f
uint256 flags
adminReceiveEth 0xf48ab4e0
No parameters
adminSendEth 0x530208f2
address destination
uint256 amount
adminSstore 0xbe831a2e
uint256 key
uint256 value
adminSstoreWithMask 0x6c4624c3
uint256 key
uint256 value
uint256 mask
challenge 0xacb99828
address receiver
uint256 signatureIndex
deposit 0xd0e30db0
No parameters
initWithBlock 0x160bc0ba
bytes data
initWithValidators 0x09d7e8e7
bytes data
withdraw 0x3ccfd60b
No parameters

Token Balances (1)

View Transfers →
WETH 0

Recent Transactions

No transactions found for this address